Controlling build order (for auto-generated code) with Boost.Build (bbv2 / bjam)

251 views Asked by At

I am using an external tool to generate source code for an application at work. The tool takes a directory tree full of JSON files and generates C++ and some other utility files. I have been able to set up a rule and a target that will re-run the generator when the source has changed, but I am struggling to determine how to control build order.

Because I have no straightforward way to generate a list of the C++/H files that will be produced by the code generator (since it is determined by runtime configuration), I don't see any alternative but to run the generator and then do a GLOB of all files in the output directory.

When I set the source (JSON) files up as a dependency of my executable, Boost.Build does run the generator when things have changed, however, it computes the dependencies of my executable before running the code generator, and so does not rebuild the right things (for example, if new files were generated, or header files were changed, their dependencies are not recompiled) because that check is performed before the code generator runs and so the GLOB takes the current (out of date) generated files, and not the new ones.

I get around this by invoking b2 twice, first with a target that generates the code, and again so that the newly generated code is properly GLOBbed and my executable rebuilt. This works, but I'd really rather have a way of specifying "run the code generator, if necessary, then GLOB any files in the output directory and determine what needs to be rebuilt". I have not been successful in finding the right terms to search -- bbv2 has its own concept of "generators" that make it tricky to find exactly what I'm looking for, and I haven't found a good source of examples.

My rules look something like this, I'm afraid I cannot be more specific. This is for a generator that takes files of type *.foo and *.bar and creates a bunch of CPP files and also one .baz file, which I use to determine if it's up-to-date.

type.register FOO : foo ;
type.register BAR : bar ;

type.register BAZ : baz ;

generators.register-composing fileset2baz : FOO BAR : BAZ ;
rule fileset2baz ( target : sources * : properties * )
{
   # I actually have a switch here based on OS type, but it is not germane to this example
   codegen $(target) : $(sources) : $(properties) ;
}
actions codegen
{
    ./run-the-code-generator
}

# take the fileset and a target object, and invoke the generator
rule fileset ( fileset : target )
{
    local FILES = [ path.glob-tree $(fileset) : *.foo *.bar ] ;
    local target_baz = $(fileset:B).baz;
    baz $(target_baz) : $(FILES) ;
    return $(target_baz) ;
}

.... then in my main project, I have something like:

alias cg : [ fileset $(PATH_TO_FILESET) : $(OUTPUT_DIR) ] ;
lib CodeGen : [ GLOB $(OUTPUT_DIR) : *.cpp *.c ] : : : <include>$(OUTPUT_DIR);

If I make the fileset a source of CodeGen, then it evaluates whether it needs to be rebuilt in parallel with whether the output files need to be rebuilt. I am looking for a way to force the cg to run (if necessary) and only after, globbing the files in $(OUTPUT_DIR).

0

There are 0 answers