XMAKE(1)

NAME
xmake - portable make utility

SYNOPSIS
xmake [ -v ] [ -f xmakefile ] [ -d[#] ] [ -n ] [ -D sym[=data] ] label1 ... labelN

-v print version and exit. If xmake doesn't know what version it is, someone forgot to re-make and re-install it with itself.

-f specify different default file

-d[#] turn on debugging

-n dry run - do not execute commands lists

-Dsym[=data] specify additional symbols to call cpp with, also sets the EXTDEFS variable

DESCRIPTION

XMake is a make utility. It is not compatible with other makes, but provides extended functionality over most standard makes. Whereas most other makes have confusing rulesets and do not support many-to-many dependancy specifications, XMake has relatively few (basically no) rulesets and allows you to easily specify many:many dependancies. This gives XMake the flexibility to deal with complex project hierarchies very simply. Despite the fact that there are no built-in rulesets, an XMakefile is often no more complex then a normal Makefile. XMake incorporates the following major features:

The ability to specify one-to-many, and many-to-one dependancies

The ability to apply a single command list to many one-to-one dependancies (typically lots of object files depending on lots of source files can be dealt with in a single line).

The ability to embed shell commands (e.g. find, ls, whatever...) in variable and other definitions.

The ability to generate wildcard template conversions on the fly. For example, you can list the source files and generate the object files and all associated dependancies from the source file list.

Runs the C preprocessor, allowing you to use #if/#else/#endif and, if need be, use preprocessor macros. The main purpose is to support the #include directive and allow operating system and compiler auto-detect.

Maintains special 'dependancy' variables %(left) and %(right) which may used in command sequences.

Allows variables to be .set inside a command sequence, where the .set directive is executed when/if the command sequence is executed... useful when dealing with side effect issues.

Understands delayed-expansion variable specifications. A normal variable specification is something like $(NAME) or %(NAME), whereas a delayed-expansion variable specification is something like ${NAME}. This allows you to set up global variables whos contents are based on other variables which have not yet been initialized. The variable is fully resolved when used in a dependancy or executed as part of a command list.

By default, XMake attempts to access the XMakefile in the current directory. This can be overriden with the -f option.

DIRECTIVES AND VARIABLE SPECIFICATIONS

Directives must start in column 1. XMake understands the following directives:

.set varname contents

Set the contents of the specified variable

.beg / .end

Applicable only within a command sequence, allows blank lines to be inserted without terminating a command sequence.

Variables may be referenced in any one of several ways:

$(varname)
$(varname?wildmatch)
$(varname?wildmatch:wildreplace)
$(varname:wildmatch)
$(varname:wildmatch:wildreplace)
%(special)
%(special:wildmatch)
%(special:wildmatch:wildreplace)

The $() variable form references a .set variable, while the %() variable form references a special dependancy variable. Dependancy variables only work within command sequences. Currently %(left) and %(right) are defined. %(left) represents the left hand side of the dependancy, while %(right) represents the right hand side.

The optional wildmatch and wildreplace elements allow you to dynamically restrict transform the elements contained within the variable. For example, if a variable contains a mix of .c and .h files, you can extract just the .c files with $(VARNAME:*.c) . Transformations are accomplished with a third element. Each '*' or '?' in the match side is represented by %1 to %N on the replace side. You can also use '*' and '?' on the replace side, which sequentially represent %1 ... %N. The most common transformation is something like this:

 .set SRCS include.c list.c main.c subs.c
 .set OBJS $(SRCS:"*.c":"$(OD)/*.o")

DEPENDANCIES

XMake allows you to specify dependancies in a manner simliar to make. However, XMake extends the facility to allow many one-to-one dependancies to be specified on a single line, as well as other combinations. The format for a dependancy is:

d1 d2 ... dn : s1 s2 ... sn [ : a1 a2 a3 ... aX ]
d1 : s1 s2 ... sn [ : a1 a2 a3 ... aX ]
d1 d2 .. dn : [ : s1 a2 a3 ... aX ]

In the first form, each dN is dependant on the associated sN and ALL of the a1-aX elemnts.

In the second form, a single d1 depends on ALL of the s1-sN and a1-aX elements.

In the third form, each destination dN depends on ALL of the a1-aX elements, and there are no 's' elements listed at all.

Note that the a1..aX elements are optional. You may also specify a dependancy with no right hand side elements at all. This will cause the execution list for the left hand side to be run if the left hand side is ever depended upon from a higher level.

The right hand side is not required to represent a real file if its label is used on the left hand side of another dependancy. However, if it does represent a real file, then the 'return code' will be based on a time-stamp comparison even if the sub-dependancies of the right hand side themselves are out of date and cause commands to run. The best example of this is the PROTOS dependancy shown below:
$(OBJS):: $(PROTOS)

$(OBJS):: defs.h

$(OBJS): $(SRCS)
    cc $(CFLAGS) %(right) -o %(left) -c

$(PROTOS): $(OD)/$(XMKPROTO) $(SRCS)
    $(OD)/$(XMKPROTO) -o %(left) %(right:"*.c")

In this example, the object modules are dependant on the prototype file being up-to-date (as well as defs.h). However, the prototype file is updated by xmkproto if any of the source files change. xmkproto is smart enough to not touch the prototype file if it determines that none of the prototypes have changed. Even though the PROTOS:SRCS dependancy is run, the OBJS:PROTOS dependancy will not be run if the prototypes file was not actually modified.

INCLUDE PATHS

XMake automatically includes the following directories when it runs CPP on your XMakefile:
The . directory
The .. directory
Your $HOME/.xmk directory
/usr/local/share/xmk
/usr/share/xmk

This allows you to configure XMake in a global system, with local overrides. Most XMakefiles will not need any of these directories. The most useful is the . and .. directories, which allow you to setup hierarchical XMakefile.inc files which are recursively included.

CONCEPTS

It is extremely easy to construct XMakefile's that use a single file or directory list to compile an entire project. Once you have learned how to use the wildcard match-and-replace capabilities, you will wonder how you could have lived without it before. Amoung other things, these functions allow you to mix multiple file extensions in a single variable, such as SRCS, yet apply a different ruleset to each extension.

FILES

XMakefile    default xmake control file
$HOME/.xmk    In include path for cpp
/usr/local/share/xmk    In include path for cpp
/usr/share/xmk    In include path for cpp