Boost logo

Boost-Build :

From: Vladimir Prus (ghost_at_[hidden])
Date: 2008-04-06 00:56:09


On Saturday 05 April 2008 23:28:53 Peter Schueller wrote:
> On Sat, Apr 5, 2008 at 3:27 PM, Vladimir Prus <ghost_at_[hidden]> wrote:
> > On Saturday 05 April 2008 11:36:26 Peter Schueller wrote:
> ...
> > > I am using two standard generators to create a client and a server
> > > version of gsoap code. I have to distinguish between server and client
> > > and so I use a property as requirement. If I forget to add this
> > > property to the Jamfile, both of the generators will be pruned and I
> > > will only get the message "target could not be constructed".
> > >
> > > The generators are registered the following way:
> > >
> > > 12 generators.register-standard gsoap.soapcpp2 :
> > > 13 WSDL_H : H(%SoapStub) H(%SoapH) CPP(%SoapC) CPP(%SoapClient) :
> > > 14 <gsoap.usage>client ;
> > > 15
> > > 16 generators.register-standard gsoap.soapcpp2 :
> > > 17 WSDL_H : H(%SoapStub) H(%SoapH) CPP(%SoapC) CPP(%SoapServer) :
> > > 18 <gsoap.usage>server ;
> > >
> > > Is it possible to do something like
> > > >generators.register-standard gsoap.error.usage : WSDL_H : CPP :
> > > <gsoap.usage>"" ;
> > > which only applies the rule gsoap.error.usage if the property
> > > gsoap.usage is not given and a CPP needs to be created from a WSDL_H?
> > >
> > > If I do as above I get a generator ambiguity for targets which have
> > > the property set correctly to either server or client.
> >
> > You can use the generators.override rule to specify that whenever
> > a "real" generator and the "error" generator appear to be viable, the "error"
> > generator loses. See the definition (and comment) in generators.jam.
> >
> > I suppose you plan to emit an error message from your generator's Jam code?
>
> Yes, this is/was my plan. I looked into the override documentation and
> it works fine, and now I finally understand how the whale sample
> works! :)
>
> This is the interesting part of the error message code:
> 48 # Register generator for error message if no <gsoap.usage> was given.
> 49 generators.register-standard gsoap.error.usage : : CPP ;
> 50
> 51 # Let the non-error message generators win over the error message generator
> 52 # -> this way whenever <gsoap.usage> is given, the error message
> is not created.
> 53 generators.override gsoap.soapcpp2 : gsoap.error.usage ;
> 54
> 55 # If this generator is selected, we can output the error message
> and immediately
> 56 # exit, this exit happens before anything is built.
> 57 rule error.usage ( target : source * : properties * )
> 58 {
> 59 EXIT "Error: you need to specify <gsoap.usage>client or
> <gsoap.usage>server"
> 60 "for correctly generating from" $(source) "via soapcpp2" ;
> 61 }

Oh, I think it would be slightly better to have a custom generator
class that would issue the error in the 'run' method, as opposed
to what you have above, because that would produce an error
earlier, without creating a fake CPP target that will produce
an error when actually built. But that's a minor detail.

>
> But I found another possibility: If I do not define the property as
> "free" but as "incidental", Boost.Build will use the first value as a
> default and I could create a rule depending on this property value, so
> I do no longer need the override. Is this a better solution than the
> override with the "free" property?

Oh, I don't think 'free' feature is very good idea -- because Boost.Build
does not use free features to decide on target paths, so you cannot
have one file built with two values of a free feature. I assumed you
have a non-free optional feature.

> feature.feature gsoap.usage : not_given server client : incidental ;
>
> At the moment I am looking into the next problem because if I build
> two applications, one a server and one a client, I get an error
> message because the client part creates some files and the server part
> creates some files, and the intersection is not empty:
>
> /usr/share/boost-build/build/virtual-target.jam:976: in
> virtual-target.register-actual-name from module virtual-targeterror:
> Duplicate name of actual target: <pbin/gcc-3.4/debug>fpSoapC.o
> error: previous virtual target { gcc%gcc.compile.c++-fpSoapC.o.OBJ {
> gsoap%gsoap.soapcpp2-fpSoapC.cpp.CPP { gsoap%gsoap.wsdl2h-fp.h.WSDL_H
> { ../interface/fp.wsdl.WSDL } } } }
> error: created from ./testclient
> error: another virtual target { gcc%gcc.compile.c++-fpSoapC.o.OBJ {
> gsoap%gsoap.soapcpp2-fpSoapC.cpp.CPP { gsoap%gsoap.wsdl2h-fp.h.WSDL_H
> { ../interface/fp.wsdl.WSDL } } } }
> error: created from ./dualcallclient
> error: added properties: <gsoap.usage>server
> error: removed properties: <gsoap.usage>client
> /usr/share/boost-build/build/virtual-target.jam:450: in
> actualize-no-scanner from module object(file-target)@275
>
> I tried to solve this problem as described in the FAQ but it is not so
> easy as it seems, as these two lines still generate the same named OBJ
> files in intermediate steps:
>
> 31 lib client_soap : ../interface/fp.wsdl : <gsoap.usage>client ;
> 32 lib server_soap : ../interface/fp.wsdl : <gsoap.usage>server ;
>
> I think I need to use the property to adjust the names (or the paths?)
> of the generated files. I found the following in the documentation
> which seems incorrect to me:
>
> "Non-incidental features are assumed to affect build products, so the
> files for targets whose build specification differs in non-incidental
> features are placed in different directories as described in "target
> paths" below. [ where? ]".
>
> A "free" feature is not "incidental" so the files should be generated
> in separate directories, but as <include> is also free I don't think
> the documentation is correct in this case.

Well, "free" features don't affect paths, either. I think you have
two solutions:

1. Just define your feature as non-free -- either:

        feature.feature gsoap.usage : not_given server client : incidental ;

as you have above, or:

        feature.feature gsoap.usage : server client : incidental optional ;

This will add the feature to the target paths. I'd recommend the second approach
as it will not add the feature to paths of all targets -- but only to those where
<gsoap.usage> is explicitly specified.

2. If you know for sure that CPP files created with different value of the
feature are identical, and always will be, you have to remove the feature
from the property set associate with the CPP file.

The example generator has this code:

                # Produce one output, using just copy.
                local a = [ new action $(sources[1])
                  : common.copy : $(property-set) ] ;
                local t = [ new file-target $(name) : CPP : $(project)
                  : $(a) ] ;

which can be modifier as follows:

        local raw = [ $(property-set).raw ] ;
        local stripped = [ property.change $(raw) : <gsoap.usage> ] ;
        local a = [ new actions $(sources[1]) : common.copy :
                        [ property-set.create $(stripped) ] ;
        local t = [ new file-target $(name) : CPP : $(project)
                  : $(a) ] ;

In this case, the gsoap.usage property won't be associated with the
target and the call to virtual-target.register will no longer complain
that two different targets are associated with the same filename.

Note: the above is untested, so some *details* might be wrong. It should
work overall.

HTH,
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