Built-in Variables

Introduction

This section discusses variables that have special meaning to Jam.

BINDING, SEARCH, and LOCATE Variables

These variables control the binding of file target names to locations in the file system. Generally, $(SEARCH) is used to find existing sources while $(LOCATE) is used to fix the location for built targets.

Rooted (absolute path) file targets are bound as is. Unrooted file target names are also normally bound as is, and thus relative to the current directory, but the settings of $(LOCATE) and $(SEARCH) alter this:

Both $(SEARCH) and $(LOCATE) should be set target-specific and not globally. If they were set globally, jam would use the same paths for all file binding, which is not likely to produce sane results. When writing your own rules, especially ones not built upon those in Jambase, you may need to set $(SEARCH) or $(LOCATE) directly. Almost all of the rules defined in Jambase set $(SEARCH) and $(LOCATE) to sensible values for sources they are looking for and targets they create, respectively.

Header Scanning Variables

The HDRSCAN and HDRPATTERN variables control the default header file scanning. HDRSCAN is an egrep(1) pattern, with ()'s surrounding the file name, used to find file inclusion statements in source files. Jambase uses $(HDRPATTERN) as the pattern for HDRSCAN. HDRRULE is the name of a rule to invoke with the results of the scan: the scanned file is the target, the found files are the sources, the bound name of the target is in the third argument. HDRRULE is run under the influence of the scanned file's target-specific variables. It defaults to the Jambase HdrRule.

Both HDRSCAN and HDRRULE must be set for header file scanning to take place, and they should be set target-specific and not globally. If they were set globally, all files, including executables and libraries, would be scanned for header file include statements.

The scanning for header file inclusions is not exact, but it is at least dynamic, so there is no need to run something like makedepend(GNU) to create a static dependency file. The scanning mechanism errs on the side of inclusion (i.e., it is more likely to return filenames that are not actually used by the compiler than to miss include files) because it can't tell if #include lines are inside #ifdefs or other conditional logic. In Jambase, HdrRule applies the NoCare rule to each header file found during scanning so that if the file isn't present yet doesn't cause the compilation to fail, Jam won't care.

Also, scanning for regular expressions only works where the included file name is literally in the source file. It can't handle languages that allow including files using variable names (as the Jam language itself does).

On Windows, header filenames are, by default, converted to lowercase. This can be prevented by setting a target's HDRDOWNSHIFT variable to false.

Filtering Unwanted Dependencies

When HDRFILTER is set on a target, the rule bearing the name specified in the contents of HDRFILTER is executed with the following signature.

    rule DoHeaderFilter TARGET_NAME : DEPENDENCIES : TARGET_BOUNDNAME
    {
        # Filter any unwanted dependencies.
        DEPENDENCIES -= bob fred ;
        return $(DEPENDENCIES) ;
    }

HDRFILTER can also be used to translate dependency names:

    # Reading our special file format, DEPENDENCIES may come in as $(environment_variable)/filename.
    # Translate it.
    rule DoHeaderFilter TARGET_NAME : DEPENDENCIES : TARGET_BOUNDNAME
    {
        # Filter any unwanted dependencies.
        DEPENDENCIES = $(DEPENDENCIES:A) ;
        return $(DEPENDENCIES) ;
    }

Shelling Processes for Dependencies

When HDRPIPE is set on a target, during the dependency scan for headers, the process command line specified by HDRPIPE is run. Any dependencies written by the process to stdout are run through the normal HDRSCAN regular expression mechanism.

If HDRPIPEFILE is set on the target, the filename specified by HDRPIPEFILE is opened and parsed for dependencies after the HDRPIPE process exits.

Semaphores

At times, it is necessary to synchronize access in a multiprocessor build. The SEMAPHORE variable, when set on a target to be built, does just that. When the given SEMAPHORE value is in use by another target, any targets with the same SEMAPHORE will block until the currently building target is finished and releases the SEMAPHORE lock.

Example: The Visual C++ compiler accesses the same .pdb and .idb files. To prevent that, a SEMAPHORE is used:

    SEMAPHORE on $(objects) = $(LOCATE_TARGET)/$(_VCPDB).pdb ;

Platform Identifier Variables

A number of Jam built-in variables can be used to identify runtime platform:

OSOS identifier string
OSPLATUnderlying architecture, when applicable
MACtrue on MAC platform
NTtrue on NT platform
OS2true on OS2 platform
UNIXtrue on Unix platforms
VMStrue on VMS platform

Jam Version Variables

JAMDATETime and date at jam start-up.
JAMUNAMEOuput of uname(1) command (Unix only)
JAMVERSIONjam version, as reported by jam -v.

Miscellaneous Variables

CWDThe current working directory.
JAM_COMMAND_LINE_TARGETSThe list of all targets passed into Jam on the command line. If no targets were passed, JAM_COMMAND_LINE_TARGETS defaults to all.
JAM_PROCESS_PATHThe path where the Jam executable resides.
PATHDELIM_OLDSTYLEIn JamPlus, the default path separator is a forward slash. If PATHDELIM_OLDSTYLE is set to 1, the default path separator is OS-specific, and the behavior mirrors the original Perforce Jam.

JAMSHELL Variable

When jam executes a rule's action block, it forks and execs a shell, passing the action block as an argument to the shell. The invocation of the shell can be controlled by $(JAMSHELL). The default on Unix is, for example:

JAMSHELL = /bin/sh -c % ;

The % is replaced with the text of the action block.

Jam does not directly support building in parallel across multiple hosts, since that is heavily dependent on the local environment. To build in parallel across multiple hosts, you need to write your own shell that provides access to the multiple hosts. You then reset to reference it.

Just as jam expands a % to be the text of the rule's action block, it expands a ! to be the multi-process slot number. The slot number varies between 1 and the number of concurrent jobs permitted by the -j flag given on the command line. Armed with this, it is possible to write a multiple host shell. For example:

    #!/bin/sh

    # This sample JAMSHELL uses the SunOS on(1) command to execute a
    # command string with an identical environment on another host.

    # Set JAMSHELL = jamshell ! %
    #
    # where jamshell is the name of this shell file.
    #
    # This version handles up to -j6; after that they get executed
    # locally.

    case $1 in
    1|4) on winken sh -c "$2";;
    2|5) on blinken sh -c "$2";;
    3|6) on nod sh -c "$2";;
    *)   eval "$2";;
    esac