views:

81

answers:

1

I have a project which uses OMake for its build system, and I am trying to handle a rather tough corner case.

I have some definition files and a tool which can take these definition files and create GraphViz files. There are two problems, though:

  • Each definition file can produce multiple graphs, and the list of graphs it can produce is encoded in the file. My dump tool does have a -list option which lists all the graphs a definition file will produce.
  • This dump tool is built in the source tree.
  • I want this list available in the OMakefile so I can use other rules to convert the DOT files to SVG, and have a phony target depend on all the SVGs (goal: a single build command which builds SVG descriptions of all my graphs).

If I only had the first problem, it would be easy - I would run the tool to build a list, and then use that list to build a target which invokes the dumper to output the GraphViz files. However, I am rather stuck on forcing the dump tool to be built before it is needed.

If this were make, I would just run make recursively to build the dump tool. OMake does not allow recursive invocation, however, and the build function is only usable from osh.

Any suggestions for a good solution to this problem?

A: 

Okay, here is my proposal. First, here is a quick generator made in bash, that can take a "--list" argument that creates an omake variable to contain the list of things to do. The generator is called "generator.txt", as we are going to "make" it by renaming it into a .sh.

#!/bin/bash

if [ "$1" = "--list" ]; then
    echo -e 'FILES[] = \n\ta\n\tb\n\tc'
else
    echo 1 > a.dot
    echo 2 > b.dot
    echo 3 > c.dot
fi

Then, the OMakefile itself:

.INCLUDE: rules : generator.txt
    cp generator.txt generator.sh
    chmod 755 generator.sh  
    ./generator.sh
    ./generator.sh --list > rules

DOTS[] =
    $(addsuffix .dot, $(FILES))

SVGS[] =
    $(addsuffix .svg, $(FILES))

# rule to turn a .dot into a .svg
%.svg: %.dot
    cp $*.dot $*.svg

.DEFAULT: $(SVGS)

.PHONY: clean
clean:
    rm -f generator.sh a.* b.* c.* rules

The trick here is to generate the "rules" file from generator.txt, to be included in the OMakefile. Whenever generator.txt (the source for our generator) changes, we recreate (build) the generator, run it (creating files a.dot, b.dot, c.dot), and finally run it with --list to generate our FILE[] variable containing the list of files to generate.

Then, it becomes trivial to generate the DOTS and SVGS variables, and the rule that turns a dot into an svg. The default target depends on the list of svgs, which is going to build everything in order.

The problem with this approach is that building the generator is quite coarse as we must have the "INCLUDE" dependencies list being real files. Nevertheless, this should at least perform operations in the correct order.

Notice how modifying generator.txt (for example, adding another .dot to be generated, or changing the how the contents of a .dot will be generated) correctly forces the regeneration of generator.sh, and then of any generated file which would have been modified.

EDIT

I think the main problem is that omake expects to be able to generate the entire dependencies graph before starting to do any work. As such, it cannot work on some dependencies to build the generator, then generate more dependencies to work on its output.

I suppose there are ways to work around:

  • The first one is to have the generator built as part of the .INCLUDE directive, as I described first, which is a hassle because you have to put all the generator build process into that directive.

  • The second one would be to lose some flexibility, and work on one input to one output, for example having the generator generate only one file with all the concatenated inputs. As you know that you will have only one file, you can set dependencies easily.

  • The third one, which would be my favorite, is to have a 2 phase build system. In a sub directory, you have an OMakefile that generates the generator and outputs the files. In an other subdirectory, you have another OMakefile, that reads the contents of the first directory to generate the list of files to process, then runs the transformation. Then, in the main directory, a bash script calls omake in the first directory, then in the second. This hopefully should mean that you can generate everything with a single command, but also that a rebuild would be minimal: the first omake will only regenerate files if the inputs have changed, and the second omake will only transform the changed or new files.

small_duck
Thanks. I tried a similar solution with INCLUDE. However, my generator program is itself a nontrivial OCaml program. I did not realize that INCLUDE deps must be real files, and tried to use my program as dependency; this did not work (the program failed to build). Due to OMake's lack of support for recursive builds, I don't see a straightforward way to utilize this solution. Any suggestions in that vein?
Michael E