Introduction
FT Jam is an enhanced version of the Jam build tool. This document lists the differences between these two programs. Note that these changes come from the need of real-world cases that can't be compiled correctly with classic Jam's limitations.
Note that FT Jam is, and will always be, fully backwards compatible with the regular Jam tool. It thus can be used as a drop-in replacement for existing Jam users. If you find something that breaks a classic Jamfile when used with FT Jam, please send a copy to the FreeType developers' mailing list so that it can be fixed as soon as possible.
New Built-in Rules
FT Jam has introduced several new built-in rules.
HDRMACRO – Header File Macro Inclusion
Jam is capable of scanning C source files to automatically determine header file dependencies. It does so through the following scheme.
-
First, it looks for preprocessor inclusion directives like
#include "myfile.h"
or#include <myfile.h>
. -
It searches for the corresponding header files according to the values of several Jam variables like SEARCH, LOCATE, etc.
-
When the header file is found, and hasn't been processed yet, it is added to the dependency tree and scanned recursively to determine its own dependencies.
ISO C allows macro expansion to occur in a #include
directive, as long
as the resulting value is a correct header file name. The following is
thus valid, but is not parsed adequately by Jam.
#define MYFILE_H "myfile.h"
#include MYFILE_H
FT Jam can parse such files normally by its HDRMACRO built-in rule whose syntax is
HDRMACRO filename ;
where filename
is the name of a file that contains the definitions
of macros that is used in inclusion directives. When you invoke this
built-in, it does the following automatically.
-
Scan filename for
#define
directives and filter those that do not define a potential filename (e.g., it discards macros with parameters). -
When a potential filename macro is encountered (i.e., when its definition expands to something like
"..."
or<...>
, where...
means ‘anything’), it is recorded in a global dictionary with its value.
Later on, when FT Jam finds a macro inclusion directive, like
#include MYFILE_H
, it searches its macro dictionary to see if it can
expand it. If so, it performs the expansion inline and updates the
dependency tree. Otherwise it simply ignores the line.
Note that you should always use the HDRMACRO built-in before other dependency rules (like Cc or C++), in order to record the macro definitions before header file scanning occurs
SUBST – Regular Expression Replacement
This new built-in must be used as a function and performs regular expression matching and replacement. Its syntax is
RESULT = [ SUBST source pattern replacement ] ;
where source is the source string, pattern is a regular expression pattern that is searched in the source string, and replacement is the replacement for the first pattern match. Of course, RESULT is a variable that contains the match's result.
Note that the character ‘$’ is used as an escape $character, with $1, $2, $3, etc., corresponding to the first matched sub-expression, the second one, the third one, etc.
Here is a small example. The following Jamfile fragment
XX_TGZ = packagename-2.0.2.tar.gz ;
PATTERN = "([A-Za-z][A-Za-a0-9_]*)-(.*)\.tar\.gz" ;
XX_TBZ2 = [ SUBST $(XX_TGZ) "(.*)\.tar\.gz" "$1.tar.bz2" ] ;
XX_TAR = [ SUBST $(XX_TGZ) "(.*)\.gz" "$1" ] ;
XX_NAME = [ SUBST $(XX_TGZ) $(PATTERN) "$1" ] ;
XX_VER = [ SUBST $(XX_TGZ) $(PATTERN) "$2" ] ;
ECHO $XX_TBZ2 ;
ECHO $XX_TAR ;
ECHO $XX_NAME ;
ECHO $XX_VER ;
prints as
packagename-2.0.2.tar.bz2
packagename-2.0.2.tar
packagename
2.0.2
Indirect Rule Invocation
Well, that is not exactly a new built-in, but is sufficiently close to it to deserve this classification.
FT Jam allows you to use macro expansion to determine which rule to invoke in a function call. For example, the following code fragment is not valid in classic Jam but runs with FT Jam:
rule MyFunc
{
return "Boo!" $(<) ;
}
FUNC = MyFunc ;
BOO = [ $(FUNC) "Ahh!" ] ;
ECHO $(BOO) ;
Of course, it prints ‘Boo! Ahh!
’. Note also that during debug output,
the expansion is dumped (e.g., ‘MyFunc’ and not ‘$(FUNC)’).
Note that this rule invocation method must be used carefully, since the whole variable expansion is used to determine which rule to use, including any spaces. The following thus fails.
rule MyFunc
{
return "Boo!" $(<) ;
}
FUNC = MyFunc "Ahh!" ;
BOO = [ $(FUNC) ] ;
ECHO $(BOO) ;
The reason is that there is no rule named ‘MyFunc Ahh!
’.
FAIL_EXPECTED – Action Result Inversion
Do not use this built-in without a very good reason. Its purpose is to invert the result of a given build action.
-
If the action didn't perform correctly (e.g., a file couldn't compile correctly), Jam will consider the target as built anyway and will keep updating dependents.
-
If the action succeeded (e.g., if the same file did compile correctly), Jam will treat it as an error, and stop immediately this branch of the dependency tree (without building dependents).
As you might probably guess, this built-in is only useful in very specific cases (e.g., testing system features as in a configure script). You probably don't need it in your Jamfiles, so better keep your hands off of it.
It is actually an ‘experimental’ feature of FT Jam and could be renamed or modified heavily in the future, so don't rely on it unless you are in close contact with the FT Jam author(s).
Jambase Enhancements
The Jambase is a file containing all default rules and actions used by the Jamfiles. It is written in normal Jam syntax and is compiled within the ‘jam’ executable by default.
New Windows and OS/2 Toolset Selection Scheme
In classic Jam, toolset selection on Windows and OS/2 is performed by setting specific environment variables corresponding to the compiler you want to use.
Variable | Toolset | Value |
BCCROOT | Borland C++ | installation path |
MSVC | Visual C++ 16-bits | installation path |
MSVCNT | Visual C++ 32-bits | installation path |
Note that the first variable in the list that is detected is used by the classic Jambase to determine which toolset to use. This is very annoying when you need to switch frequently between toolsets on the same machine (e.g., you have to unset a variable before setting the previous one, and you have to retype an installation path on each switch).
The FT Jam Jambase provides a more flexible scheme that allows you to switch between toolsets very easily, using one additional level of indirection.
-
When the Jambase is first parsed, it looks for a specific environment variable named
JAM_TOOLSET
. -
When
JAM_TOOLSET
is found, it is used to determine which toolset to use. Its value is the name of another specific environment variable that normally gives the toolset's installation path. -
If it doesn't find
JAM_TOOLSET
, it defaults to the classic Jambase behaviour and looks forBCCROOT
,MSVC
andMSVCNT
(in this order). If none of these variables are defined, it prints a message.
For example, here is how to use the Borland C++ compiler.
set BORLANDC=path\to\borland\install
set JAM_TOOLSET=BORLANDC
jam
And here is how to use the Visual C++ compiler.
set VISUALC=path\to\visualc\install
set JAM_TOOLSET=VISUALC
jam
You can also change the value of JAM_TOOLSET
anytime you want to
switch between the toolsets automatically.
set BORLANDC=path\to\borland\install
set VISUALC=path\to\visualc\install
set JAM_TOOLSET=BORLANDC
jam
jam clean
set JAM_TOOLSET=VISUALC
jam
jam clean
The biggest advantage of this scheme is that you only need to define
toolset-specific variables once, then later use JAM_TOOLSET
to switch
between them. This generally allows you to put all variable definitions
into a batch file and forget about their exact values. When using a
large number of toolsets, this can be really helpful.
New Windows and OS/2 Toolsets Supported
New toolsets have been added to the FT Jam Jambase for Windows and OS/2.
The best way to see them is simply to invoke ‘jam’ when JAM_TOOLSET
isn't defined. This dumps a message containing the list of currently
supported toolsets for your platform.
On Windows, you get output like this.
Jam cannot be run because you didn't indicate which compilation toolset
to use. To do so, follow these simple instructions:
- define one of the following environment variable, with the
appropriate value according to this list:
Variable Toolset Description
BORLANDC Borland C++ BC++ install path
VISUALC Microsoft Visual C++ VC++ install path
VISUALC16 Microsoft Visual C++ 16 bit VC++ 16 bit install
INTELC Intel C/C++ IC++ install path
WATCOM Watcom C/C++ Watcom install path
MINGW MinGW (gcc) MinGW install path
LCC Win32-LCC LCC-Win32 install path
- define the JAM_TOOLSET environment variable with the *name*
of the toolset variable you want to use.
e.g.: set VISUALC=C:Visual6
set JAM_TOOLSET=VISUALC
Here the output on OS/2.
Jam cannot be run because you didn't indicate which compilation toolset
to use. To do so, follow these simple instructions:
- define one of the following environment variable, with the
appropriate value according to this list:
Variable Toolset Description
WATCOM Watcom C/C++ Watcom install path
EMX EMX (gcc) EMX install path
VISUALAGE IBM Visual Age C/C++ VisualAge install path
- define the JAM_TOOLSET environment variable with the *name*
of the toolset variable you want to use.
e.g.: set WATCOM=C:\WATCOM
set JAM_TOOLSET=WATCOM
Other Improvements
FT Jam also provides other important or minor improvements to the original Jam sources.
Runs on Windows 9x
The classic Jam is not capable of running on Windows 95 and 98 systems.
That is mainly because it relies on the Windows NT command line
processor named cmd.exe
, while Win9x systems only come with the
infamous command.com
which isn't capable of returning valid exit
codes for most commands.
FT Jam provides an improved execution backend that is capable of detecting Win9x systems at runtime, and take special measures to deal with their limitation.
To date, we haven't encountered a Jamfile that works on NT and fails on Win9x with FT Jam. Please send these to the FreeType developers' mailing list in case you have one.
Cosmetic Enhancements
There are also some cosmetic enhancements that might be useful.
-
FT Jam prints
updating 1 target updating 2 targets
instead of
updating 1 target(s) updating 2 target(s)
-
Classic Jam ‘wraps’ debug output inelegantly when it is too nested, which can make debugging really hard. This has been fixed in FT Jam
About the Author
David Turner is best known as the author of the open-source FreeType library. He specializes in writing highly portable code for embedded systems.
The source code of FT Jam is stored on the Perforce Public Depot (peek
at //guest/david_turner/jam/src
).