Boost logo

Boost-Build :

From: Daniel Wallin (daniel_at_[hidden])
Date: 2007-05-21 11:18:09


We have a project which declares several features that are used to turn
on and off features in the built library. The targets in the project are
all dependent on targets from another project (Boost), but the features
are project-local - they have no effect on boost. Here's a simple
example of the situation:

A/Jamfile
---------

  lib a : a.cpp ;

B/Jamfile
---------

  import feature : feature;
  feature foo : on off : propagated link-incompatible ;
  use-project /A : ../A ;
  lib b : b.cpp /A//a ;

C/Jamfile
---------

  use-project /B : ../B ;
  lib c : c.cpp /B//b ;

A represents Boost, B is our project and C is another project that
depends on B, for completeness.

When issuing a build request in C:

  bjam foo=off

what happens is <foo>off is propagated to all targets, meaning B is
rebuilt with <foo>off, and then A is rebuilt with <foo>off. This gives:

  A/bin/gcc/debug/foo-off/..
  B/bin/gcc/debug/foo-off/..
  C/bin/gcc/debug/foo-off/..

The problem here is that <foo> isn't relevant for any target in A, so
the rebuild is unnecessary. My proposed solution involves adding another
 attribute to feature; "local". So the above feature-declaration would look:

  feature foo : on off : propagated link-incompatible local ;

Local features are associated with the project in which they are
declared. They are propagated to all build targets, but removed if the
targets project doesn't match the property project. If they do match,
the property is propagated back up through usage-requirements.

When issuing a build request in C, with my changes:

  bjam foo=off

we instead get:

  A/bin/gcc/debug/..
  B/bin/gcc/debug/foo-off/..
  C/bin/gcc/debug/foo-off/..

<foo>off is applied to B, and then propagated up to C, but removed from A.

I have been using the attached path locally with success, but I may very
well have overlooked some problems or better solutions.

-- 
Daniel Wallin
Boost Consulting
www.boost-consulting.com

Index: feature.jam
===================================================================
RCS file: /cvsroot/boost/boost/tools/build/v2/build/feature.jam,v
retrieving revision 1.65
diff -u -r1.65 feature.jam
--- feature.jam 3 Apr 2007 17:10:53 -0000 1.65
+++ feature.jam 21 May 2007 15:06:34 -0000
@@ -31,6 +31,7 @@
       link-incompatible
       subfeature
       order-sensitive
+ local
       ;
 
     .all-features = ;
@@ -143,6 +144,13 @@
         .all-top-features += $(name) ;
     }
     extend $(name) : $(values) ;
+
+ import project ;
+ local c = [ project.current ] ;
+ if $(c) && "local" in $(attributes)
+ {
+ $(name).project = [ project.current ] ;
+ }
 }
 
 # set default value of the given feature, overriding any previous
@@ -199,6 +207,12 @@
     return $($(:E=:G=$(feature)).values) ;
 }
 
+# return the project of the given feature
+rule project ( feature )
+{
+ return $($(feature).project) ;
+}
+
 # returns true iff 'value-string' is a value-string of an implicit feature
 rule is-implicit-value ( value-string )
 {
Index: generators.jam
===================================================================
RCS file: /cvsroot/boost/boost/tools/build/v2/build/generators.jam,v
retrieving revision 1.108
diff -u -r1.108 generators.jam
--- generators.jam 3 Apr 2007 17:10:53 -0000 1.108
+++ generators.jam 21 May 2007 15:06:34 -0000
@@ -429,7 +429,7 @@
         {
             name = [ determine-output-name $(sources) ] ;
         }
-
+
         # Assign an action for each target
         local action = [ action-class ] ;
         local a = [ class.new $(action) $(sources) : $(self.id) :
Index: property-set.jam
===================================================================
RCS file: /cvsroot/boost/boost/tools/build/v2/build/property-set.jam,v
retrieving revision 1.28
diff -u -r1.28 property-set.jam
--- property-set.jam 3 Apr 2007 17:10:53 -0000 1.28
+++ property-set.jam 21 May 2007 15:06:34 -0000
@@ -90,6 +90,11 @@
             {
                 self.link-incompatible += $(p) ;
             }
+
+ if "local" in $(att)
+ {
+ self.locals += $(p) ;
+ }
         }
         
     }
@@ -145,6 +150,12 @@
     {
         return $(self.incidental) ;
     }
+
+ # Returns local features
+ rule locals ( )
+ {
+ return $(self.locals) ;
+ }
     
     rule refine ( ps )
     {
Index: targets.jam
===================================================================
RCS file: /cvsroot/boost/boost/tools/build/v2/build/targets.jam,v
retrieving revision 1.208
diff -u -r1.208 targets.jam
--- targets.jam 29 Dec 2006 08:45:24 -0000 1.208
+++ targets.jam 21 May 2007 15:06:36 -0000
@@ -1172,7 +1172,23 @@
             $(usage-requirements-var) += [ $(result[1]).raw ] ;
         }
     }
-
+
+ # Helper for generate. Returns true if p is associated with the
+ # same project as the target.
+ rule is-property-local-to-project ( p )
+ {
+ if "local" in [ feature.attributes $(p:G) ]
+ {
+ if [ feature.project $(p:G) ] = $(self.project)
+ {
+ return true ;
+ }
+ }
+ else
+ {
+ return true ;
+ }
+ }
     
     # Determines final build properties, generates sources,
     # and calls 'construct'. This method should not be
@@ -1220,8 +1236,16 @@
                       "Usage requirements for $(self.name) are " $(usage-requirements) ;
                 }
 
- rproperties = [ property-set.create $(properties)
- $(usage-requirements) ] ;
+ # First we strip all the locals that doesn't have the
+ # correct project from the property-set. This happens
+ # after the dependent targets are constructed, so
+ # if a local feature is relevant for a dependent target
+ # the feature will get propagated back through
+ # usage-requirements.
+ rproperties = [ property-set.create [
+ sequence.filter is-property-local-to-project :
+ $(properties) ] $(usage-requirements) ] ;
+
                 usage-requirements = [ property-set.create $(usage-requirements) ] ;
                 
                 if [ modules.peek : .debug-building ]
@@ -1236,7 +1260,7 @@
                 # we link to two library which have the same <library> in
                 # usage requirements.
                 source-targets = [ sequence.unique $(source-targets) ] ;
-
+
                 local result =
                   [ construct $(self.name) :
                     $(source-targets) : $(rproperties) ] ;
@@ -1255,6 +1279,12 @@
 
                     local ur = [ compute-usage-requirements $(s) ] ;
                     ur = [ $(ur).add $(gur) ] ;
+
+ # Add local features that either apply to this target
+ # or were propagated back here through usage-requirements
+ # to our usage-requirements.
+ ur = [ $(ur).add-raw [ $(rproperties).locals ] ] ;
+
                     $(s).set-usage-requirements $(ur) ;
                     if [ modules.peek : .debug-building ]
                     {


Boost-Build list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk