Refactor extension splitting to make it more flexible (for SWIG).
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 3 Aug 2003 19:48:29 +0000 (19:48 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 3 Aug 2003 19:48:29 +0000 (19:48 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@758 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Builder.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Tool/gnulink.py
src/engine/SCons/Tool/midl.py
src/engine/SCons/Tool/msvc.py
src/engine/SCons/Tool/msvs.py
src/engine/SCons/Tool/qt.py

index 3f5e4d5b870c5733bc2197c2451b4269bfc593e3..862b65fd257bcfee56279c026f6cb85be914e1b4 100644 (file)
@@ -4901,9 +4901,42 @@ builder with the target.
 
 .IP prefix 
 The prefix that will be prepended to the target file name.
+This may be a simple string,  or a callable object that takes
+a construction environment as its argument
+and returns a prefix.
+
+.ES
+b = Builder("build_it < $SOURCE > $TARGET"
+            prefix = "file-")
+
+def gen_prefix(env):
+    return "file-" + env['PLATFORM'] + '-'
+b = Builder("build_it < $SOURCE > $TARGET"
+            prefix = gen_prefix)
+.EE
 
 .IP suffix
 The suffix that will be appended to the target file name.
+This may be a simple string, or a callable object that takes
+a construction environment as its argument
+and returns a suffix.
+If the suffix is a string, then
+.B scons
+will append a '.' to the beginning of the
+suffix if it's not already there.
+The string returned by callable object
+is untouched and must append its own '.'
+to the beginning if one is desired.
+
+.ES
+b = Builder("build_it < $SOURCE > $TARGET"
+            suffix = "file-"
+
+def gen_suffix(env):
+    return "." + env['PLATFORM'] + "-file"
+b = Builder("build_it < $SOURCE > $TARGET"
+            suffix = gen_suffix)
+.EE
 
 .IP src_suffix
 The expected source file name suffix.
index acf7e8880816e66bb32bbc28383964dc9b636de6..9a1966d17b2d08a4970a2f2030e1321e468c47b7 100644 (file)
@@ -77,6 +77,9 @@ RELEASE 0.XX - XXX
   - Add /TP to the default CXXFLAGS for msvc, so it can compile all
     of the suffixes we use as C++ files.
 
+  - Allow the "prefix" and "suffix" attributes of a Builder to be
+    callable objects that return generated strings.
+
   From Gary Oberbrunner:
 
   - Report the target being built in error messages when building
index 4b6464aa0f59595b6789938ea735a1482a745b63..b7bc1a30c24d6072b4de7117c5ed62db22af7237 100644 (file)
@@ -238,12 +238,6 @@ def _init_nodes(builder, env, overrides, tlist, slist):
         if scanner:
             s.source_scanner = scanner
 
-
-def _adjust_suffix(suff):
-    if suff and not suff[0] in [ '.', '$' ]:
-        return '.' + suff
-    return suff
-
 class EmitterProxy:
     """This is a callable class that can act as a
     Builder emitter.  It holds on to a string that
@@ -322,10 +316,13 @@ class BuilderBase:
     def __cmp__(self, other):
         return cmp(self.__dict__, other.__dict__)
 
+    def splitext(self, path):
+        return SCons.Util.splitext(path)
+
     def _create_nodes(self, env, overrides, target = None, source = None):
         """Create and return lists of target and source nodes.
         """
-        def adjustixes(files, pre, suf):
+        def adjustixes(files, pre, suf, self=self):
             if not files:
                 return []
             ret = []
@@ -339,7 +336,7 @@ class BuilderBase:
                         if fn[:len(pre)] != pre:
                             f = os.path.join(path, pre + fn)
                     # Only append a suffix if the file does not have one.
-                    if suf and not SCons.Util.splitext(f)[1]:
+                    if suf and not self.splitext(f)[1]:
                         if f[-len(suf):] != suf:
                             f = f + suf
                 ret.append(f)
@@ -357,7 +354,7 @@ class BuilderBase:
             if isinstance(s, SCons.Node.Node):
                 s = str(s)
             dir, s = os.path.split(s)
-            target = pre + os.path.splitext(s)[0] + suf
+            target = pre + self.splitext(s)[0] + suf
             if dir:
                 target = [ os.path.join(dir, target) ]
         else:
@@ -410,8 +407,27 @@ class BuilderBase:
 
         return tlist
 
+    def adjust_suffix(self, suff):
+        if suff and not suff[0] in [ '.', '$' ]:
+            return '.' + suff
+        return suff
+
+    def get_prefix(self, env):
+        prefix = self.prefix
+        if callable(prefix):
+            prefix = prefix(env)
+        return env.subst(prefix)
+
+    def get_suffix(self, env):
+        suffix = self.suffix
+        if callable(suffix):
+            suffix = suffix(env)
+        else:
+            suffix = self.adjust_suffix(suffix)
+        return env.subst(suffix)
+
     def src_suffixes(self, env):
-        return map(lambda x, e=env: e.subst(_adjust_suffix(x)),
+        return map(lambda x, s=self, e=env: e.subst(s.adjust_suffix(x)),
                    self.src_suffix)
 
     def set_src_suffix(self, src_suffix):
@@ -428,12 +444,6 @@ class BuilderBase:
             return ''
         return ret[0]
 
-    def get_suffix(self, env):
-        return env.subst(_adjust_suffix(self.suffix))
-
-    def get_prefix(self, env):
-        return env.subst(self.prefix)
-
     def targets(self, node):
         """Return the list of targets for this builder instance.
 
@@ -532,15 +542,15 @@ class MultiStepBuilder(BuilderBase):
         src_suffixes = self.src_suffixes(env)
 
         for snode in slist:
-            path, ext = SCons.Util.splitext(snode.get_abspath())
+            path, ext = self.splitext(snode.get_abspath())
             if sdict.has_key(ext):
                 src_bld = sdict[ext]
                 tgt = apply(src_bld, (env, path, snode), kw)
                 # Only supply the builder with sources it is capable
                 # of building.
                 if SCons.Util.is_List(tgt):
-                    tgt = filter(lambda x, suf=src_suffixes:
-                                 SCons.Util.splitext(SCons.Util.to_String(x))[1] in suf,
+                    tgt = filter(lambda x, self=self, suf=src_suffixes:
+                                 self.splitext(SCons.Util.to_String(x))[1] in suf,
                                  tgt)
                 if not SCons.Util.is_List(tgt):
                     final_sources.append(tgt)
index ded5354f50069fb2bc57662fd3ef290559cda2a2..a7c2f12168623d3827f7ded2a446e1e7a8c9efb5 100644 (file)
@@ -287,6 +287,37 @@ class BuilderTestCase(unittest.TestCase):
         assert not builder.target_factory is FooFactory
         assert builder.source_factory is FooFactory
 
+    def test_splitext(self):
+        """Test the splitext() method attached to a Builder."""
+        b = SCons.Builder.Builder()
+        assert b.splitext('foo') == ('foo','')
+        assert b.splitext('foo.bar') == ('foo','.bar')
+        assert b.splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
+
+        class MyBuilder(SCons.Builder.BuilderBase):
+            def splitext(self, path):
+                return "called splitext()"
+
+        b = MyBuilder()
+        ret = b.splitext('xyz.c')
+        assert ret == "called splitext()", ret
+
+    def test_adjust_suffix(self):
+        """Test how a Builder adjusts file suffixes
+        """
+        b = SCons.Builder.Builder()
+        assert b.adjust_suffix('.foo') == '.foo'
+        assert b.adjust_suffix('foo') == '.foo'
+        assert b.adjust_suffix('$foo') == '$foo'
+
+        class MyBuilder(SCons.Builder.BuilderBase):
+            def adjust_suffix(self, suff):
+                return "called adjust_suffix()"
+
+        b = MyBuilder()
+        ret = b.adjust_suffix('.foo')
+        assert ret == "called adjust_suffix()", ret
+
     def test_prefix(self):
         """Test Builder creation with a specified target prefix
 
@@ -312,6 +343,14 @@ class BuilderTestCase(unittest.TestCase):
         assert tgt.path == os.path.join('lib', 'libtgt5'), \
                 "Target has unexpected name: %s" % tgt.path
 
+        def gen_prefix(env):
+            return "gen_prefix() says " + env['FOO']
+        my_env = Environment(FOO = 'xyzzy')
+        builder = SCons.Builder.Builder(prefix = gen_prefix)
+        assert builder.get_prefix(my_env) == "gen_prefix() says xyzzy"
+        my_env['FOO'] = 'abracadabra'
+        assert builder.get_prefix(my_env) == "gen_prefix() says abracadabra"
+
     def test_src_suffix(self):
         """Test Builder creation with a specified source file suffix
         
@@ -366,6 +405,14 @@ class BuilderTestCase(unittest.TestCase):
         assert tgt.path == 'src5.o', \
                 "Target has unexpected name: %s" % tgt.path
 
+        def gen_suffix(env):
+            return "gen_suffix() says " + env['BAR']
+        my_env = Environment(BAR = 'hocus pocus')
+        builder = SCons.Builder.Builder(suffix = gen_suffix)
+        assert builder.get_suffix(my_env) == "gen_suffix() says hocus pocus", builder.get_suffix(my_env)
+        my_env['BAR'] = 'presto chango'
+        assert builder.get_suffix(my_env) == "gen_suffix() says presto chango"
+
     def test_ListBuilder(self):
         """Testing ListBuilder class."""
         def function2(target, source, env, tlist = [outfile, outfile2], **kw):
index 09519357f7a035091678a72cbdd1563f6e6e13b6..d12a504d7311d8c870885173190581186949eb9e 100644 (file)
@@ -232,12 +232,12 @@ class EntryProxy(SCons.Util.Proxy):
 
     def __get_filebase(self):
         name = self.get().name
-        return SCons.Util.SpecialAttrWrapper(os.path.splitext(name)[0],
+        return SCons.Util.SpecialAttrWrapper(SCons.Util.splitext(name)[0],
                                              name + "_filebase")
 
     def __get_suffix(self):
         name = self.get().name
-        return SCons.Util.SpecialAttrWrapper(os.path.splitext(name)[1],
+        return SCons.Util.SpecialAttrWrapper(SCons.Util.splitext(name)[1],
                                              name + "_suffix")
 
     def __get_file(self):
@@ -248,7 +248,7 @@ class EntryProxy(SCons.Util.Proxy):
         """Return the file's directory and file name, with the
         suffix stripped."""
         entry = self.get()
-        return SCons.Util.SpecialAttrWrapper(os.path.splitext(entry.get_path())[0],
+        return SCons.Util.SpecialAttrWrapper(SCons.Util.splitext(entry.get_path())[0],
                                              entry.name + "_base")
 
     def __get_posix_path(self):
@@ -499,7 +499,7 @@ class Entry(Base):
         return node.get_found_includes(env, scanner, target)
 
     def scanner_key(self):
-        return os.path.splitext(self.name)[1]
+        return SCons.Util.splitext(self.name)[1]
 
     def get_contents(self):
         """Fetch the contents of the entry.
@@ -1154,7 +1154,7 @@ class File(Base):
         return self.dir.root()
 
     def scanner_key(self):
-        return os.path.splitext(self.name)[1]
+        return SCons.Util.splitext(self.name)[1]
 
     def get_contents(self):
         if not self.rexists():
index 4c14383f91b42564286ac4281385e8570d149bd0..0f92b350d914d3146c30b19d8441279041b7889a 100644 (file)
@@ -45,7 +45,7 @@ linkers = ['g++', 'gcc', 'c++', 'cc']
 
 def cxxSource(sources):
     for s in sources:
-        if os.path.splitext(str(s))[1] in cc.CXXSuffixes:
+        if SCons.Util.splitext(str(s))[1] in cc.CXXSuffixes:
             return 1
         if cxxSource(s.sources):
             return 1
index 77769db7a27c86d09a579288b277b7016d9c0dd9..a1f079b27d171484366128d305edd0208c3280d6 100644 (file)
@@ -33,13 +33,15 @@ selection method.
 
 __revision__ = "__REVISION__"
 
+import os.path
+
 import SCons.Defaults
 import SCons.Scanner.IDL
-import os.path
+import SCons.Util
 
 def midl_emitter(target, source, env):
     """Produces a list of outputs from the MIDL compiler"""
-    base, ext = os.path.splitext(str(source[0]))
+    base, ext = SCons.Util.splitext(str(source[0]))
     tlb = base + '.tlb'
     incl = base + '.h'
     interface = base + '_i.c'
index 3d6f3ab43a2ec5841395a4895a0b33f0313d1f88..2c8a004f1dee8d4982ff36ad0bf2355f9269ea57 100644 (file)
@@ -327,13 +327,13 @@ def pch_emitter(target, source, env):
     obj = None
 
     for t in target:
-        if os.path.splitext(str(t))[1] == '.pch':
+        if SCons.Util.splitext(str(t))[1] == '.pch':
             pch = t
-        if os.path.splitext(str(t))[1] == '.obj':
+        if SCons.Util.splitext(str(t))[1] == '.obj':
             obj = t
 
     if not obj:
-        obj = os.path.splitext(str(pch))[0]+'.obj'
+        obj = SCons.Util.splitext(str(pch))[0]+'.obj'
 
     target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work
 
index 1a9a7bbb95a39af602a7cc0f83948b4e633967a4..40361a17ab9defc23384d0ed7422f8c70f2b6606 100644 (file)
@@ -126,7 +126,7 @@ class _DSPGenerator:
         if self.env.has_key('name'):
             self.name = self.env['name']
         else:
-            self.name = os.path.basename(os.path.splitext(self.dspfile)[0])
+            self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
 
         print "Adding '" + self.name + ' - ' + self.config.variant + "' to Visual Studio Project '" + str(dspfile) + "'"
 
@@ -515,7 +515,7 @@ class _DSWGenerator:
         if self.env.has_key('name'):
             self.name = self.env['name']
         else:
-            self.name = os.path.basename(os.path.splitext(self.dspfile)[0])
+            self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
 
     def Build(self):
         pass
@@ -961,19 +961,19 @@ def projectEmitter(target, source, env):
         source = []
 
     # make sure the suffix is correct for the version of MSVS we're running.
-    (base, suff) = os.path.splitext(str(target[0]))
+    (base, suff) = SCons.Util.splitext(str(target[0]))
     suff = env['MSVSPROJECTSUFFIX']
     target[0] = base + suff
 
     dspfile = SCons.Node.FS.default_fs.File(target[0]).srcnode()
-    dswfile = SCons.Node.FS.default_fs.File(os.path.splitext(str(dspfile))[0] + env['MSVSSOLUTIONSUFFIX'])
+    dswfile = SCons.Node.FS.default_fs.File(SCons.Util.splitext(str(dspfile))[0] + env['MSVSSOLUTIONSUFFIX'])
 
     if not source:
         source = [SCons.Script.SConscript.stack[-1].sconscript.srcnode()]
 
     source[0].attributes.sconstruct = SCons.Script.SConscript.stack[0].sconscript
 
-    bdswpath = os.path.splitext(str(target[0]))[0] + env['MSVSSOLUTIONSUFFIX']
+    bdswpath = SCons.Util.splitext(str(target[0]))[0] + env['MSVSSOLUTIONSUFFIX']
     bdswfile = SCons.Node.FS.default_fs.File(bdswpath)
 
     # only make these side effects if they're
index 65e76491186ec4018b6d5e44b608ee79ecf2dc2a..d9f690a08af959e517efe7cc7d3c46511efeaa1e 100644 (file)
@@ -36,8 +36,9 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import os.path
 import re
 
-import SCons.Tool
 import SCons.Defaults
+import SCons.Tool
+import SCons.Util
 
 header_extensions = (".h", ".H", ".hxx", ".hpp", ".hh")
 
@@ -71,17 +72,17 @@ class _Automoc:
         # out_sources contains at least all sources for the Library or Prog
         out_sources = source[:]
         for s in source:
-            prefix, suffix = os.path.splitext(str(s))
+            prefix, suffix = SCons.Util.splitext(str(s))
             # Nodes for header (h) / moc file (moc_cpp) / cpp file (cpp)
             # and ui.h file (ui_h)
             cpp = s.sources[0]
             ui = None
             if cpp.sources != None and len(cpp.sources) > 0:
-                src_src_suffix = os.path.splitext(str(cpp.sources[0]))[1]
+                src_src_suffix = SCons.Util.splitext(str(cpp.sources[0]))[1]
                 if src_src_suffix == env.subst('$QT_UISUFFIX'):
                     ui = cpp.sources[0]
             
-            src_prefix, src_suffix = os.path.splitext(str(cpp.srcnode()))
+            src_prefix, src_suffix = SCons.Util.splitext(str(cpp.srcnode()))
             h=None
             for h_ext in header_extensions:
                 if os.path.exists(src_prefix + h_ext):
@@ -99,7 +100,7 @@ class _Automoc:
             if (h and q_object_search.search(h.get_contents())) or ui:
                 # h file with the Q_OBJECT macro found -> add moc_cpp
                 dir,base = os.path.split(prefix)
-                src_ext = os.path.splitext(str(h))[1]
+                src_ext = SCons.Util.splitext(str(h))[1]
                 moc_cpp = SCons.Node.FS.default_fs.File(os.path.join(dir, 
                     env['QT_MOCNAMEGENERATOR'](base, src_ext, env)))
                 moc_o = self.objBuilder(source=moc_cpp)
@@ -111,7 +112,7 @@ class _Automoc:
                 # cpp file with Q_OBJECT macro found -> add moc
                 # (to be included in cpp)
                 dir,base = os.path.split(prefix)
-                src_ext = os.path.splitext(str(cpp))[1]
+                src_ext = SCons.Util.splitext(str(cpp))[1]
                 moc = SCons.Node.FS.default_fs.File(os.path.join(dir, 
                     env['QT_MOCNAMEGENERATOR'](base, src_ext, env)))
                 self.mocFromCppBld(env, moc, cpp)