Table of Contents

NAME

build - build and maintain programs and other systems

SYNOPSIS

build [-n] [-v] [-t] [-d] [-f buildfile] target...

DESCRIPTION

Build is designed to perform the same tasks as make, but to be much simpler, cleaner and easier to use, and to overcome some of make's shortcomings.

This manual entry describes Version 2 of build, which is a stand-alone program based on the Elk Scheme interpreter. Unlike previous versions, it does not use make(1).

USAGE

If the -f option is given, build looks for a file of that name to execute. If a directory is named, build looks for a file called "Buildfile" in that directory. If no -f option is given, build looks for a file called "Buildfile" in the current directory.

The target names may be file names or the names of variables defined in the buildfile. Any relative pathnames are interpreted with respect to the directory containing the buildfile.

If no target name is specified, the last program or module declared in the buildfile is built.

OPTIONS

-f filename
Execute the buildfile filename or filename/Buildfile. Defaults to "Buildfile" in the current directory.

-n
Print commands, but do not execute them.

-v
Verbose. Normally a short description of what is about to be done is printed; this option causes the full commands to be displayed as well.

-t
Trace. Prints a message after each significant operation is performed while executing buildfiles. Useful for tracking down bugs in a buildfile. In conjunction with -v, prints full pathnames (normally only the last component is printed).

-d
Debug. Causes a very long and detailed commentary to be displayed, including among other things the reasons why targets are being built.

PREREQUISITES

Although not strictly necessary, some acquaintance with the programming language Scheme is helpful, particularly when writing extensions to build.

BUILDFILE

A buildfile consists of a sequence of Scheme expressions. Build provides a number of facilities in the form of Scheme functions and macros.

Comments
Comments are introduced by a semicolon. Everything from the semicolon to the end of the line is ignored.

Build Functions
A build function is used to specify that one or more target files are to be built from a set of input files. The arguments to the build function are pathnames, or lists of pathnames, of input files. The build function returns the pathname of the target, or a list of pathnames if there is more than one target.

Relative pathnames are expanded to full pathnames at the earliest opportunity. Build maintains a current directory for this purpose that is prepended to any relative pathname before its use by a build function. Likewise, a build function always returns the full pathname of its targets. (See also "Current Directory" below.)

The following predefined build functions are provided:

(program program-name object-file...)

Links the specified object files to form the named executable program. Returns the pathname of the program.

(c source-file...)

Compiles the specified C source files and returns a list of the pathnames of the resulting object files.

(library library-name object-file...)

Links the specified object files to form the named library. The library name is interpreted as if for the "-l" option of the C compiler; e.g. the library name "foo" results in a library called "libfoo.a". The full pathname of the library is returned.

(install-in directory file...)

Copies the given files to the given directory, and returns a list of the pathnames of the resulting files.

Variables
Variables are maintained and used with the standard Scheme mechanisms. Variables should be declared before use with define; thereafter set! should be used to alter their values.

(define variable value)

Declares a variable and assigns it the given initial value.

(set! variable value)

Assigns the given value to a previously defined variable.

Predefined Variables
The following predefined variables have special uses:

include-path-list
List of directories that the C preprocessor should search for include files.

c-flags
A flag or list of flags to pass to the C compiler when compiling ".c" files or linking ".o" files.

c-define-list
List of preprocessor symbol definitions to be passed to the C preprocessor. Each definition is of the form "name=value".

c-compiler
Program to use for compiling C source files. Default "cc".

library-path-list
List of directories that the linker should search for libraries.

library-list
List of libraries that should be searched when linking programs. The library names are turned into "-l" options to the linker; e.g. the library name "foo" results in the library file "libfoo.a" being linked.

linker-flags
A flag or list of flags to pass to the linker, in addition to the c-flags.

linker

Name of the program to use for linking programs. Default "cc".

archiver
Name of the program to use for creating libraries. Default "ar".

ranlib
Name of the program to use for indexing library files. Default "ranlib".

arch The current machine architecture, as returned by arch(1).

default-target
If no target is specified on the command line, the last value assigned to this variable in the top-level buildfile is used. It is set by the module and program build functions.

cwd The pathname of the current directory. This variable should not be set; see "Current Directory" below.

Modules
A module is a collection of targets that can be referred to by name elsewhere in the buildfile. A module is declared with the module macro:

(module name expr...)

The module name is defined as a variable and assigned a list of results from evaluating the expressions in the module body.

Current Directory
The current directory can be changed using the in macro:

(in directory expr...)

The expressions are evaluated with the current directory bound to the directory. If directory is a relative pathname, it is interpreted in the context of the old current directory. The old current directory is restored after executing the expressions.

Scope Rules
All user-defined variables, and values assigned to predefined variables by the user, are local to the buildfile in which they occur. Variables may be made visible to other buildfiles using the export macro: (export form...)

Each form may be the name of a variable to export, or an expression evaluating to a variable name or list of variable names.

A variable need not be defined before being exported. The value exported is the value the variable has after the whole buildfile has been executed.

A buildfile can refer to another buildfile using the import function:

(import buildfile...)

Each of the named buildfiles is loaded (if not already loaded) and the bindings of all variables it exports are made visible in the current buildfile. During execution of the imported buildfile, the current directory is bound to the directory in which that buildfile resides.

The buildfile name may name a directory, in which case the file "Buildfile" in that directory is executed.

If the buildfile name is a relative pathname, a search is made up the directory hierarchy from the current directory looking for a file of the given name, or a directory of the given name containing a file "Buildfile".

The return value of import is a list of the names of variables exported by the imported buildfiles. Thus one may write

(export (import buildfile...))

to import a buildfile and re-export all of the imported variables.

EXAMPLES

Build a program "hello" from "hello.c":
(program "hello"
(c "hello.c"))
)

Build a program from two source files and an object file:

(program "foo"
(c "foo.c" "blarg.c")
"flump.o"
)

A subdirectory "mylibdir" contains the sources for building a library, which is then used as a component in building a program. Mylibdir has its own buildfile for building the library:

;

;
File "mylibdir/Buildfile" ; (export my-library-module) (module my-library-module (library "mylib" (c "first.c" "second.c" "third.c") ) )

;
;
File "Buildfile" ; (import "mylibdir") (program "myprog" (c "mymain.c" "myother.c") my-library-module )

UTILITY FUNCTIONS

Build provides a number of predefined functions. Ones of general usefulness are listed here; more specialised ones are listed in the section Build Function Utilities below.

Variable Manipulation Functions
The following functions are provided for manipulating predefined variables:

(include-path directory...)

Prepends the specified pathnames to the include-path-list variable.

(c-define definition...)

Prepends the specified definitions to the c-define-list variable.

(library-path directory...)

Prepends the specified pathnames to the library-path-list variable.

(use-library library...)

Prepends the specified library names to the library-list variable.

Pathname Manipulation Functions
The following functions are provided for manipulating pathnames and lists of pathnames.

(prepend-dir directory pathname)

Prepends the directory to the pathname (which must be relative), inserting a slash if necessary.

(path pathname-component...)

Concatenates the given pathname components, inserting slashes as necessary, to form a single pathname.

(full-path pathname-component...)

The given pathname components are concatenated using path. If the resulting pathname is relative, the current directory is prepended to yield a full pathname.

(full-paths pathname-list)

Expands each pathname to a full pathname and returns a list of the results.

EXTENDING BUILD

The primary means of extending build is by writing new build functions. A build function is an ordinary Scheme function that obeys certain rules. For those not familiar with Scheme, a brief description of how to define a function is given here. For further information, consult the references in the SEE ALSO section.

Defining Functions
A function is defined using define as follows:

(define (name formal-param...) expr...)

The value returned by the function is that of the last expression. A call of the function would look like:

(name expr...)

A function accepting a variable number of parameters can be defined by separating the last formal parameter from the preceding ones by a dot, for example:

(define (my-func arg1 arg2 . rest-of-args) expr...
)

defines my-func as accepting two or more parameters. When called, arg1 and arg2 are bound to the first two parameters, and rest-of-args is bound to a list of the remaining parameters.

Exporting Functions
Function names are variables, and are subject to the same scope rules as other variables. Therefore, function names that are to be visible outside the buildfile must be exported.

Defining Build Functions
The rules that a build function must obey are:

(1) Any parameters that are pathnames must be expanded to full pathnames before being used.

(2) In place of any pathname parameter, the build function must accept a list of pathnames, or any hierarchy of lists of pathnames.

(3) The build function must specify a rule that indicates how to make the target from the files given as parameters (see below).

(4) The build function must return the full pathname of the target that it builds, or a list of full pathnames if it builds more than one target.

To assist in defining build functions, the define-buildfunction macro is provided:

(define-build-function (name formal-param...) (declaration...)
expr...
)

Each declaration is one of:

(path formal-param...)
(paths formal-param...)

Before the expressions in the body of the function are evaluated, the formal parameters are preprocessed as follows:

Each formal parameter appearing in a path declaration is assumed to be a filename, and is expanded to a full pathname (using full-path below).

Each formal parameter appearing in a paths declaration is assumed to be a filename or hierarchical list of filenames, and is standardised (using standardise below).

There is also another form of define-build-function described below under "Implicit Parameters".

Build Function Utilities
The following utility functions are provided to assist build functions.

(flatten-list list)

The list may be a single item or a hierarchy of lists of items. Returns a single-level list. If list is a single item (not a list), the result is a list containing that item.

(standardise list)

This is equivalent to (full-paths (flatten-list list)). It should rarely be needed, as the paths declaration of define-build-function performs the same task.

(filename-directory pathname)

Returns all except the last component of pathname. (Note: no check is made whether the pathname names a directory or a file. Given the name of a directory, the result will be the name of the directory containing that directory.)

(filename-nondirectory pathname)

Returns the last component of pathname).

(remove-suffix pathname)

Returns pathname with its dot-suffix, if any, removed (including the dot).

(replace-suffix pathname new-suffix)

Removes any existing dot-suffix from pathname, and then apppends new-suffix. (Note: the new-suffix should include a dot, if one is required.)

(trace format argument...)

If -t is specified, print a tracing message to stderr. The format string specifies how to interpret the arguments. Metacharacters that may be used in the format include:

~s
Print the next argument as a Scheme object.

~a
Like ~s but doesn't print quotes around strings.

~%
Print a newline character.

For more information on format strings, see the references.

Unless -v is also specified, any pathnames in the arguments are abbreviated to their last components. If -t is not specified, trace produces no output.

Specifying Rules
A rule is specified in a build function using the rule function:

(rule target-pathname dependencies command...)

The target-pathname is the name of the target being made. The dependencies is a list of pathnames of files that the target depends on. Each command is a command for execution by sh(1). Whenever the target is out of date, each command is executed in turn.

Two special characters may be prepended to a command. If the command begins with `#', it is treated as a comment and printed, but is not executed. If it starts with `@', the command is executed but not printed (unless the -v option was given). Otherwise, the command is both printed and executed.

Two functions are provided to assist in the construction of commands for rule:

(description argument...)

Standardises the arguments (using standardise), concatenates them with blanks between, and prepends a `#' character.

(command argument...)

Standardises the arguments (using standardise), concatenates them with blanks between, and prepends an `@' character.

Implicit Parameters
Some build functions use the values of global variables to specify options that rarely change -- for example, the c function uses c-flags and c-compiler. Such variables effectively constitute implicit parameters to the functions which use them.

Because build is lexically scoped, such implicit parameters require special treatment, as the following illustration shows. Suppose the c function and the c-flags variable were defined in a buildfile foo and exported. Further suppose that the buildfile blarg imports foo, and changes the value of c-flags.

If the c function were simply to refer to the global c-flags directly, the change to c-flags would not be seen by the c function, because c refers to c-flags variable in the environment of foo, not blarg.

Instead, we want the reference to c-flags in the c function to refer to the value of the c-flags variable in the environment from which c is called, rather than the one in which it was defined. In effect, we want dynamic rather than lexical scoping.

In order to support dynamic scoping where required, definebuild-function has an alternative form allowing the declaration of implicit parameters:

(define-build-function
(name (implicit-param...) explicit-param...) (declaration...)
expr...
)

This form of define-build-function defines two things: a macro called name and a function called name* (the same name with an asterisk appended).

The macro is called as:

(name actual-param...)

The macro expands to a call of the function as follows:

(name* implicit-param... actual-param...)

That is, the values of variables in the environment of the call with the same names as the implicit parameters are passed to the function as extra parameters. Within the function, they may be referred to by name in the same way as ordinary parameters.

When exporting a build function declared with implicit parameters, both the macro name and function name should be exported, that is:

(export name name*)

Examples
Here is an example of a build function for building a target from a set of input files using the m4(1) macro processor. (define-build-function (m4 output-file . input-files) ((paths input-files)
(path output-file))
(rule output-file input-files
(description "Creating" output-file "using m4") (command "m4" input-files ">" output-file) )
output-file
)

Here is a complete package for compiling and linking Pascal programs. It could be placed in a separate buildfile and accessed from other buildfiles using import.

Use is made here of some facilities of the Scheme language not described here. See the references for more information.

;----------------------------------------------;

;
Package for building Pascal programs ; ;----------------------------------------------

(export pascal pascal*
pascal-program
pascal-flags pascal-linker-flags
pascal-compiler pascal-linker)

;

;
Default values ; (define pascal-flags `()) (define pascal-linker-flags `()) (define pascal-compiler "pc") (define pascal-linker "pc")

;
;
Compile pascal sources to .o files ; (define-build-function ;
(pascal
; Build function name (pascal-compiler pascal-flags
include-path-list)
; Implicit parameters
. source-files)
; Explicit parameters ;
((paths source-files))
; Declarations ;
;
Helper function for pascal (private) ; (define (do-pascal-source-file source-file) (let ((object-file (replace-suffix source-file ".o")))

(rule object-file source-file
(description "Compiling" source-file) (command pascal-compiler pascal-flags include-path-list source-file "-o" object-file) )
object-file
)
)
;
;
Body of pascal function ; (let ((result (map do-pascal-source-file source-files))) (trace "Done pascal ~s~%" source-files) result) )

;
;
Link pascal object files into an executable program ; (define-build-function ;
(pascal-program
; Build function name (pascal-linker pascal-flags
pascal-linker-flags
; Implicit params library-path-list library-list)
program-name . object-files)
; Explicit params ;
((path program-name)
; Declarations (paths object-files)) ; (rule program-name object-files (description "Linking" program-name) (command pascal-linker pascal-flags pascal-linker-flags object-files library-path-list library-list "-o" program-name) ) (set! default-target program-name) (trace "Done pascal-program ~s~%" program-name) program-name ) ;----------------- End of Pascal package ----------------------

ENVIRONMENT

By default, build reads a file called .buildrc in the user's home directory on startup. This file may contain arbitrary Scheme expressions; typically it is used to specify sitedependent settings such as pathname translations (see below).

The environment variable BUILD_STARTUP may be used to specify an alternative startup file.

Pathname Translation
In a network environment, symbolic links are often used to give the appearance of a uniform file system structure across machines. However, build determines the name of the current directory by following the .. links up the directory hierarchy. This can lead to inconsistent names for the same file being stored in the state file, resulting in unnecessary rebuilding. It can also confuse debuggers that rely on the names of source files embedded in object files. To solve this problem, the translate function can be used to specify pathname prefix transformations:

(translate old-prefix new-prefix)

This declares that directory names beginning with old-prefix should be changed to have new-prefix instead. For example,

(translate "/export/foobar" "/usr")

would cause "/export/foobar/blarg/somefile" to be turned into "/usr/blarg/somefile".

Translation specifications are usually placed in the .buildrc file, and are applied sequentially in the order declared to each directory pathname generated by build.

Note that pathname translations are only applied to directory names that build calculates (using getwd(3)), not to pathnames explicitly written into a buildfile (which are under user control and assumed to be correct).

FILES

Buildfile
Default initial buildfile.

*/.build.state
Build keeps hidden dependency information about each target in a file called .build.state in the directory in which the target resides.

*/.build.dependency
Temporary file created in the directory of a target while building the target to collect hidden dependency information.

~/.buildrc
Default startup file.

BUGS

When things go wrong, the error messages are Scheme error messages.

Analysing large networks of buildfiles is slow.

Full interpretation of the -d output requires arcane knowledge.

None of this would be necessary if make were part of the filesystem.

AUTHOR

Greg Ewing, University of Canterbury

SEE ALSO

make(1)
Reference Manual for the Elk Extension Language Interpreter The Revised Revised Revised Report on SCHEME


Table of Contents