Gentoo Linux Jam Guide Colonel Paneek This document explains the Jam build system to a first-time user. 0.1 2005-09-04 Introduction
What is Jam?

Jam is a software build tool. It is an alternative the the GNU make tools. Jam was written by Perforce Software and has been released as open source.

Jam includes an interpreted procedural language to define the rules and actions processed by Jam. The Jam language is case sensitive. Jam uses these rules (from a Jamfile or a group of Jamfiles) to define how Jam should build a set of targets, which can be object files, libraries, or executables.

Jam's features include automatically generating C & C++ header dependencies, eliminating the necessity to declare header or object files in the Jamfile.

Prerequisites

While no prior knowledge of Jam is assumed, a basic understanding of the C++ language and the GNU toolchain and a working knoledge of the bash shell is reccomended.

Installing Jam

First of all Jam needs to be installed on your system.

# emerge dev-util/jam
Hello World

The next step is to create a small set of files to test the build process.

Create the source file
#include <iostream>

using namespace std;

int main (int argc, char *argv[]) {

	cout << "hello world" << endl;
}
Create the Jamfile In a Jamfile the semicolons are tokens and must be separated by whitespace.
C++ = g++ ;
LINK = $(C++) ;

Main hello : hello.cc ;
Make, test, and remove the executable
$ jam
...found 11 target(s)...
...updating 2 target(s)...
Link hello 
Chmod1 hello 
...updated 2 target(s)...
$ ./hello
hello world
$ jam clean
...found 1 target(s)...
...updating 1 target(s)...
Clean clean 
...updated 1 target(s)...

You can remove the object and executable files by typing jam clean.

Linking user-built object files
Create the header file
#ifndef _MYTOOLS_
#define _MYTOOLS_

#include <string>

namespace std {

	void whatever (string s);
}

#endif
Create the source file
#include <iostream>
#include "mytools.h"

using namespace std;

void std::whatever (string s) {

	cout << "whatever [" << s << ']' << endl;
}
Modify hello.cc

The new header file needs to be included, and the procedure whatever needs to be called by main.

#include <iostream>
#include "mytools.h"

using namespace std;

int main (int argc, char *argv[]) {

	cout << "hello world" << endl;
	whatever ("test");
}
Modify the Jamfile

The file mytools.cc needs to be added to the main dependency list.

C++ = g++ ;
LINK = $(C++) ;

Main hello : hello.cc mytools.cc ;

The executable may now be built as normal.

Linking pre-compiled libraries
Modify the source file

The header file math.h should be included along with the other headers. To test the library the arctangent of 1 is calculated.

#include <iostream>
#include <math.h>
#include "mytools.h"

using namespace std;

void whatever (string s) {

	cout << "whatever [" << s << ']' << endl;
	cout << "atan (1.0) = " << atan (1.0) << endl;
}
Modify the Jamfile

The math library libm needs to be added to library list.

C++ = g++ ;
LINK = $(C++) ;

LINKLIBS += -lm ;

Main hello : hello.cc mytools.cc ;
Examine the build command

Run Jam with the -an flags to see how the math library is added to the build command.

$ jam -an
...found 29 target(s)...
...updating 3 target(s)...
C++ hello.o 

g++ -c -o hello.o -O   hello.cc

C++ mytools.o 

g++ -c -o mytools.o -O   mytools.cc

Link hello 

g++  -o hello  hello.o mytools.o  -lm 

Chmod1 hello 

chmod 711 hello

...updated 3 target(s)...
Directories
Overview

Two rules, SubDir and SubInclude, are used, along with shared variables, to manage subdirectories.

The SubDir rule identifies the directory which contains a Jamfile. At the root of the tree containing Jamfiles there should be a Jamrules file, which contains any default rules for the Jamfiles. A side effect of the SubDir rule is that the Jamrules file is read. The Jamrules file is only ever read once, at the first occurance of the SubDir rule. The SubDir rule should preceed any rules which refer to the contents of the directory.

The SubInclude rule causes another Jamfile to be read in. Typically the Jamfile in the root directory (where the Jamrules file is) will contain a SubInclude rule for each subdirectory one level down. Multiple levels of subdirectories may be managed by writing SubInclude rules for a particular directory in the Jamfile of the parent directory, rather that putting all of the SubInclude rules in the Jamfile in the root directory.

An environment variable should be used to define the root of the directory tree which contains Jamfiles. In this guide the variable JAMR is used. A Jamrules file (which contains variables shared by the individual Jamfiles) should be present in the JAMR root directory.

Example The environment variable may be included within the .bash_profile file in your home directory.
export JAMR=~/jam

An example directory structure may be set up with the following commands:

$ mkdir $JAMR
$ cd $JAMR
$ mkdir main tools

The files mytools.h & mytools.cc should go into the tools directory. The file hello.c should go into the main directory.

The Jamfile in the JAMR directory should be as follows:

SubDir JAMR ;
SubInclude JAMR tools ;
SubInclude JAMR main ;

The Jamrules file belongs in the JAMR directory. Here are the rules for variables which are commonly referenced by the individual Jamfiles. The Jam language assigns values to strings in a fashion similar to that of the bash shell. Here the string variable TOOLS is set to the path of the tools subdirectory.

Echo "Parsing Jamrules" ;

C++ = g++ ;
LINK = $(C++) ;
TOOLS = $(JAMR)/tools ;

The Jamfile in the tools subdirectory uses the Objects rule to specify that only the compilation of the object file is desired.

SubDir JAMR tools ;

Objects mytools.cc ;

The Jamfile in the main directory refers to the tools directory for a dependecy. The HDRS variable is a list of directories that the compiler will search for header files, and must include the tools subdirectory in this case.

SubDir JAMR main ;

HDRS += $(TOOLS) ;

Main hello : hello.cc $(TOOLS)/mytools.cc ;
Other languages
Overview

Jam is not exclusively for C and C++ programs. It can be used to build executables for any language, so long as the appropriate rules and actions are defined.

Example

This new rule defines build dependencies and ensures that the output file will be removed when jam clean is invoked.

rule MakeHtml {

	Depends $(<) : $(>) ;
	Depends all : $(<) ;
	Clean clean : $(<) ;
}

The action has reduced whitespace so that the build command appears in Jam's output the same way as Jam's built-in build commands do.

actions MakeHtml {
xsltproc --novalid demo.xsl $(>) >$(<) ;
}

A rule that references the dependencies must be invoked before Jam will attempt to build anything.

MakeHtml demo.html : demo.xml ;