Jam - Cross referencing between directories

Assume the following directory structure.

  • src
  • src/common
  • src/common/tests

Of course, common/tests includes common for testing. Problem is when one wants to include common/tests from common, say, to make tests runnable from common directory. Simply SubIncludeing each other result in infinite recursion, and does not work .

To solve this problem, a guard similar to one used for C/C++ headers can be used. Define SubIncludeOnce in Jamrules as below.

SUBDIRRULES += SubDirRule ;

rule SubDirRule {
    $(SUBDIR)-INC = true ;
}

rule SubIncludeOnce top_tokens {
    local _dir = [ FSubDirPath $(top_tokens) ] ;
    if ! $($(_dir)-INC) { SubInclude $(top_tokens) ; }
}

SUBDIRRULE in this example is a list of rule names which SubDir invokes at the end.

Because the order of Jamfile inclusion differs with jam start directory, one should be careful about modifying global variables like CFLAGS. On the other way, one can use the fact that SUBDIR differs for each directories. Assume the following additional directory structure.

  • src/unittest
  • src/unittest/tests

unittest uses and includes common, but does not want common tests to run for test. For those circumstances, define a rule that determine SUBDIR is below the directory that jam started.

rule FPathSplit path {
    local _i, _tokens ;
    for _i in $(path) {
        local _p ;
        while $(_i) && $(_i) != $(_i:D) {
            _p += $(_i:B)$(_i:S) ;
            _i = $(_i:D) ;
        }
        if $(_i) { _p += $(_i) ; }
        _tokens += [ FReverse $(_p) ] ;
    }
    return $(_tokens) ;
}

rule LocalSubDir {
    local _tokens = [ FPathSplit $(SUBDIR) ] ;
    if $(_tokens[0]) = .. { return ; }
    return Yes ;
}

Use LocalSubDir for the testing rule, say, Check to include only the tests below the starting directory.

Check {
  if ! [ LocalSubDir ] { return ; }
  …
}