I am trying to build a project using Haiku Jam. (The code for the project is available online at https://github.com/Andromeda-OS/LLVM. I recommend at least looking at the directory names in that project so that you know what components I am referring to below.)
I am trying to (re)build the llvm-tblgen utility. llvm-tblgen
has a link-time dependency on libLLVMSupport and libLLVMTableGen. If I add a Jam DEPENDS
statement so that llvm-tblgen
requires that libLLVMSupport
be built first, Jam does not build llvm-tblgen
at all. Jam outputs don't know how to make ./bin/llvm-tblgen/llvm-tblgen
, and gives me no other useful diagnostics, even when running at high verbosity levels.
If I remove every dependency command from llvm-tblgen
, then and only then does Jam compile the file. However, if libLLVMSupport.a
is not present, linker errors will result as Jam was not told to compile libLLVMSupport
first. However, if I tell Jam to build libLLVMSupport
first, then llvm-tblgen
will not be built at all! Any pointers?
To analyze problems like this you can use:
This prints the make tree. The error is printed while processing the make tree, so you see it right where Jam encounters it and can easily track back the dependencies that lead to it. In this case "Intrinsics.gen" has the non-existent dependency and grep reveals the following line in "include/llvm/Jamfile":
So, if you're jamming in the top directory, the latter dependency expands to "./bin/llvm-tblgen/llvm-tblgen". Since target names in Jam are just literal strings -- there's no matching for possible paths happing -- this does not match the target "llvm-tblgen" you define in "bin/llvm-tblgen/Jamfile".
The solution is: Never use target names with path components, just use the file name. If two different targets have the file name, add grist to one or both of them (e.g. "foo" and "foo") to make them unique again. If
SEARCH
orLOCATE
is properly set on the target -- which almost all standard rules do -- Jam will automatically resolve the target name to the matching path (aka bind the target) when used in actions. For instance your TableGen rule should rather look like:"llvm-tblgen" is now passed as a target to the actions and thus automatically bound to the correct path.
You can simplify "include/llvm/Jamfile":
Usually one adds the subdirectory grist to source files (using
[ FGristFiles Intrinsics.td ]
in this case), so clashes with equally named source files in other directories are avoided preemptively. If you use the TableGen rule elsewhere as well, you may also want to move the aboveMakeLocate
andSEARCH
there as well. Instead of settingTABLEGEN_FLAGS
here, I would make that a third parameter of TableGen and set the variable there, so the rule becomes even more convenient to use.A few other things I noted:
return $(results:BS) ;
. The string/path operations are applied to each element of a list, so there's no need to do that manually.LinkLibraries $(1) : lib$(3).a ;
instead of the "for" loop. The rule establishes the dependencies and adds the libraries to the link line (with their path instead of "-L... -l...").