Boost logo

Boost-Build :

From: Vladimir Prus (ghost_at_[hidden])
Date: 2006-03-13 04:20:04


Hi Daniel,

> First off, please note that the test case zip file I provided previously in
> the message thread demonstrates the desired output if you edit the Jamroot
> to switch around the two imports according to the comments. You can then
> run bjam or bjam <atarget> and see what I'm expecting as output. I started
> this whole thread because it seemed bad to me that having the imports one
> way caused it to work perfectly (AFAICT), but having them reversed caused
> ambiguity errors.

Ah, sorry for not specifically replying to this issue. I believe it's a bug,
but bug in the sense that reversing the imports mistakenly does not report
the ambiguity. In other words, ambiguity should be always reported.

> > 1. What are new types of sources type you need in your project, what
> > are extensions for those types.
>
> I have two new source types:
> CSCONFIG with the extension ini
> and
> CUSTOMERINFO for which I do not specify a source extension because the only
> possible source file of that type is named "defaultcustomerinfo.cpp".
> I rely on a cast to try to make BB understand that this one particular CPP
> file is in fact a CUSTOMERINFO file. There is no other file that I would
> ever want to be considered a CUSTOMERINFO file, source or target.
>
> > 2. What are the transformations between those types. For each
> > transformation, state:
> > - which source types it takes, and what number of each type
> > - what is the output
>
> I have two potential transformation actions for CSCONFIG.
> CSCONFIG.merge -- if the target is another csconfig ini and the sources are
> two csconfig.ini, then this action merges them together.
> CSCONFIG.transform -- if the target is a cpp, and the source is a single
> csconfig ini, then this action will transform the ini into the desired cpp.
> In my actual code, the tool is compiled into an executable by BB and passed
> in as a <built-tool> feature and dependency. In the testcase, I represented
> the transform action as just a straight echo of the ini file for
> simplicity's sake.
>
> I have one possible transformation action for CUSTOMERINFO.
> CUSTOMERINFO.transform -- The only possible target should be a normal cpp
> file that can then be used in further targets to be transformed into an obj
> and eventually into an exe or lib. The only possible source should be a
> single file, "defaultcustomerinfo.cpp" which I use the [cast] rule on to
> make it appear to BB as a CUSTOMERINFO source instead of a normal CPP. The
> action uses sed to replace a string in the file with the name of the
> customer so that our code knows the customer for which it was built.

So, you have two generated files, file
   
   customerconfig.cpp

produces from ini files, and another

   customerinfo.cpp produces from defaultcustomerinfo.cpp

right?

> The cpp generated by CSCONFIG.transform should just be a normal cpp. I
> would never want CUSTOMERINFO.transform to touch it.
>
> > 3. Please specify overall sequence of transformation you want.
>
> csconfig csconfig-merged.ini : csconfig-defaults.ini
> csconfig-<acustomer>.ini ;
> -- this should invoke the CSCONFIG.merge action to concatenate the two
> source ini's into a single merged.ini.

Ok, this one I do understand.

> cpp customercsconfig.cpp : csconfig-merged.ini ;
> -- this should invoke the CSCONFIG.transform action to convert the ini
> into a normal cpp file, able to be used in lib or exe targets.

Ok.

> # Note the cast arguments might not be perfect here, I'm just typing them
> from memory
> cpp customerinfo.cpp : [ cast _ customerinfo : defaultcustomerinfo.cpp ] ;
> -- this should invoke the CUSTOMERINFO.transform action to run the
> source through sed generating a normal cpp able to be used in lib or exe
> targets.

Ok, so, in real life this action takes CPP files and produces CPP file, and
your CUSTOMERINFO type is just a technical trick here.

Let's go though the process necessary to define right generators. First, you
need to define generators that have the right types in sources and targets,
so that they can do the desired tranformation. Second, you need to exlcude
transformations you don't want.

Seems like 'csconfig.merge' gives no problem so I'll ignore it. Then, we have
two straigh-forward generator. (Recall, I'm not using CUSTOMERINFO type for
now, because that's artifical type you've introduced). The generators are:

   csconfig.transform is INI -> CPP
   customerinfo.transform is CPP -> CPP

Now, when you write
 
   cpp csconfig-customer.cpp
       : # sources
          csconfig-base.ini
      ;

Boost.Build will find all generator invocation sequences from INI to CPP,
subject to restriction that no generator can be invoked twice. This gives:

   (1) INI -> CPP
   (2) INI -> CPP -> CPP

and it's an ambiguity. The possible solution is to make CPP -> CPP generator
run only when explicitly needed. For example:

1. Add 'run' method to customerinfo-generator, and implement it like this:

   rule run ( project name ? : property-set : sources * : multiple ? )
   {
       if ! $(sources[2]) || [ $(sources[1]).type ] = CPP
       {
            # call base generator
       }
   }

This way, customerinfo.transform will only work if you pass a CPP file to it,
if you pass INI file it won't try to convert it to CPP.

2. You can make customerinfo-generator demand a very specific source type, and
use cast. Basically, that's what you tried to did, but you should not derive
CUSTOMERINFO from CPP. If you do, then sequence (2) above will still be
found, because CUSTOMERINFO types inherits all generators for from type CPP.

You can also use two methods I've suggested before:

1. If the generator should be invoked only when some property, say <customer>
is in build properties, use this:

  generators.override csconfig.transform : customerinfo.transform ;
  
  generators.register [ new customerinfo-generator customerinfo.transform :
       CUSTOMERINFO : CUSTOMERINFO : <customer> ] ;

This way, the customerinfo.transform generator won't be used unless there's
<customer> in the properties. Or you can use:

  generators.register [ new customerinfo-generator customerinfo.transform :
       CUSTOMERINFO : CUSTOMERINFO : <allow>customerinfo.transform ] ;

and add <allow>customerinfo.transform to requirements if you want this
generator to run. The <allow> property is the standard one. You can use a
helper rule to automatically add this property when declaring targets:

   rule customerinfo-transformed ( name : sources * : requirements * .. )
   {
        customerinfo $(name)
           : $(sources)
           : $(requirements) <allow>customerinfo.transform
           .........
   }

2. You can change customerinfo.transform signature:

   type.register CUSTOMERINFO_TRANSFORMED : : CUSTOMERINFO ;
   generators.register [ new customerinfo-generator customerinfo.transform :
       CUSTOMERINFO : CUSTOMERINFO : <allow>customerinfo.transform ] ;

and again use 'customerinfo-transformed' rule when you need to transform
customer info.

I don't know which method is best for you, but all should work.

Speakinga about imports order -- that's still a bug in Boost.Build, I'll see
into it.

- Volodya


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