Commits

Anonymous committed 9adbdb4

Use the prefix and suffix arguments in the Builder base class.

  • Participants
  • Parent commits ef4fbe9

Comments (0)

Files changed (4)

doc/design/engine.sgml

 
 	<programlisting>
 	WebPage = Builder(command = 'htmlgen $HTMLGENFLAGS $sources > $target',
-	                input_suffix = '.in',
-	                output_suffix = '.html')
+	                  suffix = '.html',
+	                  src_suffix = '.in')
 	</programlisting>
 
   <para>
 	        return 1
 
 	OtherBuilder1 = Builder(function = update,
-	                input_suffix = ['.in', '.input'])
+	                        src_suffix = ['.in', '.input'])
 	</programlisting>
 
    <para>
 	        return 1
 
 	OtherBuilder2 = Builder(function = update_arg,
-	                function_arg = 'xyzzy',
-	                input_suffix = ['.in', '.input'])
+	                        function_arg = 'xyzzy',
+	                        src_suffix = ['.in', '.input'])
 	</programlisting>
 
   <para>
 
 	<programlisting>
 	WebPage = Builder(command = 'htmlgen $HTMLGENFLAGS $sources > $target',
-	                input_suffix = '.in',
-	                output_suffix = '.html')
+	                  suffix = '.html',
+	                  src_suffix = '.in')
 	env = Environment(BUILDERS = ['WebPage'])
 	env.WebPage(target = 'foo.html', source = 'foo.in')
 	# Builds 'bar.html' on UNIX, 'bar.htm' on Windows NT:
 
   <para>
 
-   A &Builder; object may optionally be initialized with a list of
-   the expected suffixes of input files for this object.  It may also
-   be initialized with an output suffix for the files that this
-   &Builder; object builds.  These arguments are used in automatic
-   dependency analysis and in generating output file names that don't
-   have suffixes supplied explicitly.
+   A &Builder; object may optionally be initialized with a list of:
+
+  </para>
+
+   <itemizedlist>
+     <listitem>
+     <para>
+
+       the prefix of the target file (e.g., 'lib' for libraries)
+
+     </para>
+     </listitem>
+
+     <listitem>
+     <para>
+
+       the suffix of the target file (e.g., '.a' for libraries)
+
+     </para>
+     </listitem>
+
+     <listitem>
+     <para>
+
+       the expected suffixes of the input files
+       (e.g., '.o' for object files)
+
+     </para>
+     </listitem>
+   </itemizedlist>
+
+   <para>
+
+    These arguments are used in automatic
+    dependency analysis and to generate output file names that don't
+    have suffixes supplied explicitly.
 
   </para>
  </section>
 
 	<programlisting>
 	build = Builder(function = my_build)
-	build_out = build.Copy(output_suffix = '.out')
+	build_out = build.Copy(suffix = '.out')
 	</programlisting>
 
   <para>
 <REMARK>
 Do we even need this anymore?
 Now that the individual builders
-have specified <literal>input_suffix</literal>
-and <literal>output_suffix</literal> values,
+have specified <literal>suffix</literal>
+and <literal>src_suffix</literal> values,
 all of the information we need to support
 the &MakeBuilder; builder is right there in the environment.
 I think this is a holdover from before I
 <REMARK>
 If the &BUILDERMAP; proves unnecessary,
 we could/should get rid of this one, too,
-by adding a parallel <literal>input_suffix</literal>
+by adding a parallel <literal>src_suffix</literal>
 argument to the &Scanner; factory...
 Comments?
 </REMARK>

src/engine/SCons/Builder.py

 
 
 
-class Builder:
+def Builder(**kw):
+    """A factory for builder objects."""
+    if kw.has_key('builders'):
+        return apply(MultiStepBuilder, (), kw)
+    else:
+        return apply(BuilderBase, (), kw)
+
+
+
+class BuilderBase:
     """Base class for Builders, objects that create output
     nodes (files) from input nodes (files).
     """
 
     def __init__(self,	name = None,
 			action = None,
-			input_suffix = None,
-			output_suffix = None,
+			prefix = None,
+			suffix = None,
+			src_suffix = None,
 			node_factory = SCons.Node.FS.default_fs.File):
 	self.name = name
 	self.action = Action(action)
-	self.insuffix = input_suffix
-	self.outsuffix = output_suffix
+	self.prefix = prefix
+	self.suffix = suffix
+	self.src_suffix = src_suffix
 	self.node_factory = node_factory
-	if not self.insuffix is None and self.insuffix[0] != '.':
-	    self.insuffix = '.' + self.insuffix
-	if not self.outsuffix is None and self.outsuffix[0] != '.':
-	    self.outsuffix = '.' + self.outsuffix
+	if not self.suffix is None and self.suffix[0] != '.':
+	    self.suffix = '.' + self.suffix
+	if not self.src_suffix is None and self.src_suffix[0] != '.':
+	    self.src_suffix = '.' + self.src_suffix
 
     def __cmp__(self, other):
 	return cmp(self.__dict__, other.__dict__)
 
     def __call__(self, env, target = None, source = None):
-	tlist = scons_str2nodes(target, self.node_factory)
-	slist = scons_str2nodes(source, self.node_factory)
+	def adjustixes(files, pre, suf):
+	    ret = []
+	    if not type(files) is type([]):
+	        files = [files]
+	    for f in files:
+		if type(f) == type(""):
+		    if pre and f[:len(pre)] != pre:
+		        f = pre + f
+		    if suf:
+		        if f[-len(suf):] != suf:
+		            f = f + suf
+		ret.append(f)
+	    return ret
+	    
+
+	tlist = scons_str2nodes(adjustixes(target, self.prefix, self.suffix),
+                                self.node_factory)
+	slist = scons_str2nodes(adjustixes(source, None, self.src_suffix),
+                                self.node_factory)
 	for t in tlist:
 	    t.builder_set(self)
 	    t.env_set(env)
 class BuilderProxy:
     """This base class serves as a proxy to a builder object,
     exposing the same interface, but just forwarding calls to
-    the underlying object."""
+    the underlying object.  Use it for subclass Builders that
+    need to wrap or decorate another Builder class."""
     def __init__(self, builder):
         self.subject = builder
 
         assert 'subject' in self.__dict__.keys(), \
                "You must call __init__() on the BuilderProxy base."
         return getattr(self.subject, name)
-    
-class TargetNamingBuilder(BuilderProxy):
-    """This is a simple Builder Proxy that decorates the names
-    of a Builder's targets prior to passing them to the underlying
-    Builder.  You can use this to simplify the syntax of a target
-    file.  For instance, you might want to call a Library builder
-    with a target of "foo" and expect to get "libfoo.a" back."""
 
-    def __init__(self, builder, prefix='', suffix=''):
-        """
-        builder - The underlying Builder object
-        
-        prefix - text to prepend to target names (may contain
-        environment variables)
-
-        suffix - text to append to target names (may contain
-        environment variables)
-        """
-        BuilderProxy.__init__(self, builder)
-        self.prefix=prefix
-        self.suffix=suffix
-
-    def __call__(self, env, target = None, source = None):
-        tlist = scons_str2nodes(target, self.subject.node_factory)
-        tlist_decorated = []
-        for tnode in tlist:
-            path, fn = os.path.split(tnode.path)
-            tlist_decorated.append(self.subject.
-                                   node_factory(os.path.join(path,
-                                                             env.subst(self.prefix) +
-                                                             fn +
-                                                             env.subst(self.suffix))))
-        return self.subject.__call__(env, target=tlist_decorated, source=source)
-
-class MultiStepBuilder(Builder):
+class MultiStepBuilder(BuilderBase):
     """This is a builder subclass that can build targets in
     multiple steps according to the suffixes of the source files.
     Given one or more "subordinate" builders in its constructor,
     this class will apply those builders to any files matching
-    the builder's input_suffix, using a file of the same name
-    as the source, but with input_suffix changed to output_suffix.
+    the builder's src_suffix, using a file of the same name
+    as the source, but with src_suffix changed to suffix.
     The targets of these builders then become sources for this
     builder.
     """
     def __init__(self,  name = None,
 			action = None,
-			input_suffix = None,
-			output_suffix = None,
+			prefix = None,
+			suffix = None,
+			src_suffix = None,
                         node_factory = SCons.Node.FS.default_fs.File,
                         builders = []):
-        Builder.__init__(self, name, action, input_suffix, output_suffix,
-                         node_factory)
+        BuilderBase.__init__(self, name, action, prefix, suffix, src_suffix,
+                             node_factory)
         self.builder_dict = {}
         for bld in builders:
-            if bld.insuffix and bld.outsuffix:
-                self.builder_dict[bld.insuffix] = bld
+            if bld.suffix and bld.src_suffix:
+                self.builder_dict[bld.src_suffix] = bld
 
     def __call__(self, env, target = None, source = None):
         slist = scons_str2nodes(source, self.node_factory)
             if self.builder_dict.has_key(ext):
                 bld = self.builder_dict[ext]
                 tgt = bld(env,
-                          target=[ path+bld.outsuffix, ],
+                          target=[ path+bld.suffix, ],
                           source=snode)
                 if not type(tgt) is types.ListType:
                     final_sources.append(tgt)
                     final_sources.extend(tgt)
             else:
                 final_sources.append(snode)
-        return Builder.__call__(self, env, target=target,
-                                source=final_sources)
+        return BuilderBase.__call__(self, env, target=target,
+                                    source=final_sources)
 
 print_actions = 1;
 execute_actions = 1;

src/engine/SCons/BuilderTests.py

     def test__call__(self):
 	"""Test calling a builder to establish source dependencies
 	"""
-	env = Environment()
 	class Node:
 	    def __init__(self, name):
 		self.name = name
 		self.sources = []
 		self.derived = 0
+	    def __str__(self):
+	        return self.name
 	    def builder_set(self, builder):
 		self.builder = builder
 	    def env_set(self, env):
     def test_cmp(self):
 	"""Test simple comparisons of Builder objects
 	"""
-	b1 = SCons.Builder.Builder(input_suffix = '.o')
-	b2 = SCons.Builder.Builder(input_suffix = '.o')
+	b1 = SCons.Builder.Builder(src_suffix = '.o')
+	b2 = SCons.Builder.Builder(src_suffix = '.o')
 	assert b1 == b2
-	b3 = SCons.Builder.Builder(input_suffix = '.x')
+	b3 = SCons.Builder.Builder(src_suffix = '.x')
 	assert b1 != b3
 	assert b2 != b3
 
 	c = test.read(outfile, 'r')
 	assert c == "act.py: syzygy\nfunction2\nclass2a\nclass2b\n", c
 
-    def test_insuffix(self):
-	"""Test Builder creation with a specified input suffix
-	
-	Make sure that the '.' separator is appended to the
-	beginning if it isn't already present.
-	"""
-	builder = SCons.Builder.Builder(input_suffix = '.c')
-	assert builder.insuffix == '.c'
-	builder = SCons.Builder.Builder(input_suffix = 'c')
-	assert builder.insuffix == '.c'
-
     def test_name(self):
 	"""Test Builder creation with a specified name
 	"""
 	builder = SCons.Builder.Builder(node_factory = FooFactory)
 	assert builder.node_factory is FooFactory
 
-    def test_outsuffix(self):
-	"""Test Builder creation with a specified output suffix
+    def test_prefix(self):
+	"""Test Builder creation with a specified target prefix
+
+	Make sure that there is no '.' separator appended.
+	"""
+	builder = SCons.Builder.Builder(prefix = 'lib.')
+	assert builder.prefix == 'lib.'
+	builder = SCons.Builder.Builder(prefix = 'lib')
+	assert builder.prefix == 'lib'
+	tgt = builder(env, target = 'tgt1', source = 'src1')
+	assert tgt.path == 'libtgt1', \
+	        "Target has unexpected name: %s" % tgt[0].path
+
+    def test_src_suffix(self):
+	"""Test Builder creation with a specified source file suffix
+	
+	Make sure that the '.' separator is appended to the
+	beginning if it isn't already present.
+	"""
+	builder = SCons.Builder.Builder(src_suffix = '.c')
+	assert builder.src_suffix == '.c'
+	builder = SCons.Builder.Builder(src_suffix = 'c')
+	assert builder.src_suffix == '.c'
+	tgt = builder(env, target = 'tgt2', source = 'src2')
+	assert tgt.sources[0].path == 'src2.c', \
+	        "Source has unexpected name: %s" % tgt.sources[0].path
+
+    def test_suffix(self):
+	"""Test Builder creation with a specified target suffix
 
 	Make sure that the '.' separator is appended to the
 	beginning if it isn't already present.
 	"""
-	builder = SCons.Builder.Builder(input_suffix = '.o')
-	assert builder.insuffix == '.o'
-	builder = SCons.Builder.Builder(input_suffix = 'o')
-	assert builder.insuffix == '.o'
-
-    def test_TargetNamingBuilder(self):
-        """Testing the TargetNamingBuilder class."""
-        builder = SCons.Builder.Builder(action='foo')
-        proxy = SCons.Builder.TargetNamingBuilder(builder=builder,
-                                                  prefix='foo',
-                                                  suffix='bar')
-        tgt = proxy(env, target='baz', source='bleh')
-        assert tgt.path == 'foobazbar', \
-               "Target has unexpected name: %s" % tgt[0].path
-        assert tgt.builder == builder
+	builder = SCons.Builder.Builder(suffix = '.o')
+	assert builder.suffix == '.o'
+	builder = SCons.Builder.Builder(suffix = 'o')
+	assert builder.suffix == '.o'
+	tgt = builder(env, target = 'tgt3', source = 'src3')
+	assert tgt.path == 'tgt3.o', \
+	        "Target has unexpected name: %s" % tgt[0].path
 
     def test_MultiStepBuilder(self):
         """Testing MultiStepBuilder class."""
         builder1 = SCons.Builder.Builder(action='foo',
-                                        input_suffix='.bar',
-                                        output_suffix='.foo')
+                                        src_suffix='.bar',
+                                        suffix='.foo')
         builder2 = SCons.Builder.MultiStepBuilder(action='foo',
                                                   builders = [ builder1 ])
         tgt = builder2(env, target='baz', source='test.bar test2.foo test3.txt')

src/engine/SCons/Defaults.py

 
 Object = SCons.Builder.Builder(name = 'Object',
                                action = 'cc -c -o $target $sources',
-                               input_suffix='.c',
-                               output_suffix='.o')
-Program = SCons.Builder.MultiStepBuilder(name = 'Program',
-                                         action = 'cc -o $target $sources',
-                                         builders = [ Object ])
-Library = SCons.Builder.MultiStepBuilder(name = 'Library',
-                                         action = 'ar r $target $sources\nranlib $target',
-                                         builders = [ Object ])
-  
-Library = SCons.Builder.TargetNamingBuilder(builder = Library,
-                                            prefix='lib',
-                                            suffix='.a')
+                               src_suffix='.c',
+                               suffix='.o')
+
+Program = SCons.Builder.Builder(name = 'Program',
+                                action = 'cc -o $target $sources',
+                                builders = [ Object ])
+
+Library = SCons.Builder.Builder(name = 'Library',
+                                action = 'ar r $target $sources\nranlib $target',
+                                prefix = 'lib',
+                                suffix = '.a',
+                                builders = [ Object ])
 
 Builders = [Object, Program, Library]