JamPlus manual
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:

  • If $(LOCATE) is set then the target is bound relative to the first directory in $(LOCATE). Only the first element is used for binding.
  • If $(SEARCH) is set then the target is bound to the first directory in $(SEARCH) where the target file already exists.
  • If the $(SEARCH) search fails, the target is bound relative to the current directory anyhow.

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. Note that modifying JAM_COMMAND_LINE_TARGETS will override targets specified on the command-line.
JAM_EXTRA_COMMAND_LINE_OPTIONSAll command-line options that follow on a jam command line invocation.
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

Additionally, JAMSHELLEXT is a variable that can be set to the proper extension of a script accepted by the shell.

JAMSHELL = pwsh.exe -noprofile -executionpolicy bypass -File ;
JAMSHELLEXT = .ps1 ;

Clean up of extra files and directories

After a build has completed, files and directories may be left in the build's destination directories that came from a previous build and are no longer being built. JamPlus' clean up facility can be used to remove the extra files and directories at the end of the build process.

Three variables are used to control the clean up:

CLEAN.VERBOSEPrints out file removals during the clean up phase.
CLEAN.ROOTSThe list of root paths denoted by wildcards to check for extra files to clean up.
CLEAN.KEEP_WILDCARDSExtra wildcards to prevent from being cleaned up.
CLEAN.KEEP_TARGETSExtra targets to prevent from being cleaned up.
CLEAN.NOOPDo not actually perform the removal. Useful with CLEAN.VERBOSE to report what would be cleaned up.

To begin a clean-up, the CLEAN.ROOTS variable must contain one or more wildcard entries specifying the directory locations to be scanned for extra file entries during the clean-up. Wildcards must conform to the format in the :W modifier documentation.

# This ensures subdira/ and subdirb/ are recursively checked for
# extra files that were not generated as part of this build.
CLEAN.ROOTS = subdira/** subdirb/** ;
# Check subdira/ recursively for extra files, but ignore any
# references to junk.txt within the hierarchy. Also check subdirb/
# recursively.
CLEAN.ROOTS = subdira/**@-**/junk.txt subdirb/** ;

All targets that are in the dependency graph for this build are automatically preserved within the CLEAN.ROOTS directories.

If additional files or targets should be preserved and are not specified within the dependency graph, the CLEAN.KEEP_WILDCARDS or CLEAN.KEEP_TARGETS variables should be used.

CLEAN.KEEP_WILDCARDS is a list of wildcard entries specifying inclusions (and even exclusions) of files to be preserved during the clean up process. As with CLEAN.ROOTS, it conforms to the format described in the :W= modifier documentation.

# In the case where Jam itself does not know about generated *.txt
# files within the subdira/ directory structure, preserve any found
# *.txt file for later usage.
CLEAN.KEEP_WILDCARDS += subdira/**.txt ;

CLEAN.KEEP_TARGETS is a list of Jam targets that were not processed as part of the dependency graph for this build.

# junk.txt is a target residing in subdirb, but it has no build
# instructions. We want to preserve it during the clean up, so we add
# it to the CLEAN.KEEP_TARGETS list.
SEARCH on junk.txt = subdirb ;
CLEAN.KEEP_TARGETS += junk.txt ;

By default, directory and file removals happen silently at the end of the build. Set the CLEAN.VERBOSE variable to 1 to print out the removals.

CLEAN.VERBOSE = 1 ;

Set the CLEAN.NOOP variable to 1 to calculate what would be removed during the clean up but not actually perform the clean up.

CLEAN.NOOP = 1 ;