Find file
Fetching contributors…
Cannot retrieve contributors at this time
933 lines (718 sloc) 41.8 KB
STU(1) University of Koblenz-Landau STU(1)
stu - Build automation
stu [ -f FILENAME ] [ OPTION ]... [ TARGET ]...
Stu is a tool for build automation. Like Make, it is used to call
other programs in order to build files. Stu has two features that set
it apart from Make: (1) dynamic dependencies: The dependencies of a
target can be themselves computed by a command. When '[FILENAME]' (a
filename currounded by angle brackets) is used as a dependency, Stu
will build the file FILENAME and read dependencies from it. (2) Param‐
eters: Names of files (and transient targets) can contain parameters
written using dollar syntax. For example, a rule with a target file‐
name 'list.$name' will be used to build any file matching the pattern
'list.*', and the parameter $name can be used in names of dependencies
and in the build command. Targets may contain any number of parame‐
In general, Stu is very much like Make: Instead of a 'Makefile', one
uses a file named 'main.stu', which is read by Stu. Also like Make, Stu
will build the first target it finds, except if given an explicit tar‐
get to built. Stu is designed to follow the conventions of Make, of
the shell, and of Unix and POSIX in general. As an example, the
options -f and -k have the same meaning in Stu as they do in Make.
Rules for building files are read from the file 'main.stu', from a file
passed by the -f option, or using the -F option.
Names of targets to build passed on the command line follow a simpli‐
fied Stu syntax, in which the only special characters are the transient
target marker '@', and brackets '[]'. All other characters are inter‐
preted as part of filenames. When the -J option is used, arguments
passed on the command line are interpreted as filenames without Stu
Read targets from FILENAME, which must contain \0-separated
filenames. No Stu syntax is processed.
-a Treat all trivial dependencies, which are declared with the -t
flag or option, as non-trivial.
Pass a target filename, without Stu syntax. This option only
allows file targets to be specified, not transient targets.
Pass a target using full Stu syntax. The given expression is
parsed as if it was given as one or more dependencies in a Stu
file. As a result, flags -p, -o and -t, brackets, parentheses
and other Stu syntax elements can be used, and spaces separate
filenames. This is not equivalent to passing a string as an
argument to Stu outside of options, because -C supports full Stu
syntax, while arguments supports only a reduced syntax (see
-d Debug mode. Show internal information about the Stu algorithm
on standard error output. All printed output lines begin with
the string 'DEBUG ', i.e. the word DEBUG followed by two spa‐
-E Explain error messages. Only some error messages have explana‐
Read the given file instead of the default 'main.stu'. If the
name of a directory is passed, the file 'main.stu' in the given
directory is read. If '-' is passed, read standard input. The
-f option can be used multiple times.
Pass rules in full Stu syntax.
-g Treat all optional dependencies (declared with the -o flag) as
-h Output a short help and exit.
-i Interactive mode. I.e., put the jobs run into the foreground.
Must not be used in conjunction with -j N when N > 1. By
default, jobs are run in the background, meaning they can't read
standard input, will not get any terminal signals, and pressing
Ctrl-C will stop Stu as a whole. Using this option, each job is
run in the foreground, and therefore they can read standard
input, will get terminal signals such as SIGINT (after Ctrl-C)
and end-of-stdin (after Ctrl-D). Thus, when -i is used, press‐
ing Ctrl-C will only interrupt the currently running job, and if
the -k option is used, Stu will continue with the next job.
When Ctrl-Z is pressed, Stu will interrupt the currently running
job, and ask the user to press ENTER to continue, or press Ctrl-
C/Ctrl-Z to interrupt or suspend Stu itself. -i does not work
when Stu does not run in a terminal.
-j K Run K jobs in parallel. K must be a positive integer. The
default value is one, meaning that Stu does not start jobs in
parallel. When running jobs in parallel and the -k option is
not used, a single job that fails will make Stu abort all other
running jobs and terminate. Thus, the -j option is often used
in conjunction with the -k option. The parameter K is manda‐
tory. This option works like the corresponding option in GNU
Make, but note that in GNU Make, the argument is optional.
-J Parse all arguments to Stu as filenames, disabling all Stu syn‐
tax that is otherwise used. Intended when Stu is used with
tools such as xargs(1) or similar. The -J option itself does
not take an argument; it only changes the way arguments outside
of options are interpreted.
-k Keep going. Do not stop running when an error occurs. Instead,
try to build as much as possible. This option is equivalent to
that of Make.
-K Don't delete partially built files when a command fails or when
Stu is interrupted. By default, Stu will delete the target of a
command after the command fails or is interrupted, when the file
is newer than it was before starting the command. This option
disables that behavior. Note that with this option, a subse‐
quent invocation of Stu may lead to the partially built file
being erroneously considered up to date.
Specify the order in which jobs are run. When ORDER is 'dfs'
(the default), Stu traverses the dependency graph in a depth-
first fashion, in a way similar to Make. When ORDER is 'random',
the order in which jobs are run is randomized within each tar‐
Run jobs in pseudorandom order, seeded by the given string.
Read targets from FILENAME, which must contain newline-separated
filenames. No Stu syntax is processed.
Pass the given file as an optional dependency, i.e., build it
only if it already exists and is out of date.
Pass the given file as a persistent dependency, i.e., build the
file but ignore its timestamp.
-P Print the set of rules to standard output and exit. Note that
Make has a -p option to print the rules, but does not exit. The
output format is not specified.
-q Question mode. Do not execute any commands. Instead, determine
whether the given targets are up to date. The exit status is 0
when all given targets (or the default target) are up to date, 1
when not, and 4 on errors.
-s Silent mode. Suppress messages on standard output: messages
about which commands are run, a message when the build is suc‐
cessful, and a message when there is nothing to be done. Error
messages are not suppressed. This option is comparable to the
same option in Make.
-V Output the version number of Stu and exit.
-x Call the shell using the -x option, i.e., each individual shell
command is output to standard error output individually, instead
of outputting a full command at once on standard output. In the
output, each command is prefixed by the value of '$PS4'.
-y Disable color in output. By default, Stu checks whether error
output and standard error output are TTYs and whether $TERM is
defined and not 'dumb' and if they are, uses ANSI escape
sequences to color code messages.
-Y Enable color output unconditionally.
-z Output runtime statistics about child processes on standard out‐
put when finished. Does not include the runtime of the Stu
process itself. Includes the runtime of all child and grand‐
child processes, and so on. Does not include the runtime of
children or grandchildren that have not been waited for (which
only happens when Stu is interrupted by a signal.)
A simple rule looks as follows:
results.txt: data.txt compute {
./compute <data.txt >results.txt
The colon may be omitted when there are no dependencies:
A { echo la la la >A }
Here is an example of a rule containing three parameters. Stu will use
pattern matching to match the target pattern to a given filename:
data-$dataset.txt analyse-$method
./analyse-$method \
-m $measure \
-f data-$dataset.txt \
-o plot.$dataset.$method.$measure.eps
Here is an example of a dynamic dependency. The target 'compute' (a C
program) must be rebuild whenever its source code files are modified.
Since the set of source code files is large and may be changed by
changing the source code itself, we use the file 'compute.c.dep' to
contain the list of dependencies. The file 'compute.c.dep' will then
be built by Stu like any file, and its content parsed for the actual
compute: [compute.c.dep] {
gcc -c compute.c -o compute
$name.c.dep: $name.c compute-dep {
./compute-dep-c "$name.c" >"$name.c.dep"
Parameters can also use the syntax ${...}.
Syntax can be on multiple lines; whitespace is not significant. No
backslashes are needed at line ends:
do-stuff >output.txt;
A rule may be entirely given on a single line:
system-info: { uname -a >system-info }
The following rule uses single quotes to declare filenames that include
parentheses and quotes:
'((': 'aaa\"bbb' {
./bla -f
Multiple parametrized rules may match a target. In that case Stu uses
the one that is the least parametrized, as defined by the subset rela‐
tion on the set of characters that are in parameters. When building
'X.txt' in this example, only the second rule is called:
$name.txt: { echo "$name" is the best >"$name.txt" }
X.txt: { echo X sucks >X.txt }
All commands are echoed by Stu. Thus, you can output debugging infor‐
mation (or any type of information) using shell comments. There is no
need for the @echo construct of Make.
A: {
# This may take a while...
compute-stuff >A
Persistent dependencies: In the following example, the directory
'data' is a persistent dependency, i.e. 'data' is only built when it
does not exist, but it is never re-built. A persistent dependency is
indicated by the -p flag. This is useful for directories, whose time‐
stamps change when files are created/removed in them.
data/file: -p data {
echo Hello >data/file
data: { mkdir data }
Optional dependencies can be declared with the -o flag. An optional
dependency will never be built if it does not already exist. If it
already exists, then its own rule is used (and its date checked) to
decide whether it should be rebuilt.
target: -o input {
if [ -r input ] ; then
cp input target
echo Hello >target
Trivial dependencies are denoted with the -t flag. They denote a
dependency that should never cause a target to be rebuilt, but if the
target is rebuilt for another reason, then they are treated like normal
dependencies. Trivial dependencies are typically used for configura‐
tion, i.e., for the setting up configuration of application. Trivial
dependencies are not allowed if the rule has no command.
target: -t input;
Variable dependency: the content of variables can come from files. In
the following example, the C flags are stored in the file 'CFLAGS', and
used in the compilation command using the $[CFLAGS] dependency.
compute: compute.c $[CFLAGS]
gcc $CFLAGS compute -o compute.c
CFLAGS: { echo -Wall -Werror >CFLAGS }
Variable dependencies may be declared as persistent as in $[-p X] and
as trivial as in $[-t X] but not as optional using the -oflag. By
default, the name of the variable set is the same as the filename.
Another variable name can be used in the following way:
Transient targets are marked with '@'. They are used for targets such
as '@clean' that do an action without building a file, and for lists of
files that depend on other targets, but don't have a command associated
with them. They are also used instead of variables that would other‐
wise contain a list of filenames.
Here is a transient target that cleans up the directory:
@clean: { rm -Rf *.o *~ }
Here a transient target is used as a shortcut to a longer name:
@build.$name: dat/build.$name.txt;
Here a transient target is used as a list of files. Multiple targets
can depend on it, to effectively depend on the individual files:
@headers: a.h b.h c.h;
x: x.c @headers {
cc x.c -o x
y: y.c @headers {
cc y.c -o y
Like a makefile, a Stu file consists of rules. In Stu, the order of
rules is not important, except for the fact that the first rule is used
by default if no rule is given explicitly. Comments are written with
'#' like in Make or in the shell.
The basic syntax is similar to that of make, but does not rely on
mandatory whitespace. Instead of tabs, the commands are enclosed in
curly braces.
Stu syntax supports two types of objects: file targets and transient
targets. Files are any file in the file system, and are always refer‐
enced by their filename. Transient targets have names beginning with
the '@' symbol and do not correspond to files, but can have dependen‐
cies and commands.
A rule for a file in Stu has the following syntax:
The target is a filename. DEPENDENCY ... are depencies. COMMAND is a
command which is passed to the shell for building. Stu will always
execute the whole command block using a single call to the shell. This
is different than Make, which calls each line individually. This means
that you can for instance define a variable on one line and use it on
the next.
Stu uses the -e option when calling the shell; this means that any
failing command will make the whole target fail.
The standard input is redirected from /dev/null, except when an
explicit input redirection is specified using '<'. Thus, commands exe‐
cuted from within Stu cannot read from standard input, except when the
-i option is used. Stu starts each job in its own process group, whose
process group ID is equal to its process ID. This allows Stu to kill
all (direct and indirect) child processes of jobs, by using kill(2) to
terminate all processes in the corresponding process group.
When the command of a file is replaced by a semicolon, this means that
the file is always built together with its dependencies:
In this example, the file TARGET is assumed to be up to date whenever
all dependencies are up to date. This can be used when two files are
built by a single command. As a special case, writing the name of a
file followed by semicolon tells Stu that the file must always exist,
and is always up to date; Stu will then report an error if the file
does not exist:
For a transient, the same syntax is used as for a file:
If a transient target includes a command, Stu will have no way of
remembering that the command was executed, and the command will be exe‐
cuted again on the next invocation of Stu, even if the previous invoca‐
tion was successful. Therefore, commands for transient targets will
typically output build progress information, or perform actions that do
not fit well the build system paradigm, such as removing or deploying
built files.
Rules can have multiple targets, in which case the command must build
all the targets that are files. If one of the targets is a transient
target, this effectively creates an alias for the file targets.
TARGET... [ : DEPENDENCY ... ] ;
The operator '>' can be used in front of the target name to indicate
that the output of the command should be redirected into the target
file. As an example, the following code creates the file 'HEADERS'
containing the output of the given 'echo' command:
>HEADERS { echo *.h }
For a file target, content can be specified directly using the '='
The content is stripped of empty lines and common whitespace at the
beginning of lines, and written into the file.
Using the equal sign with a file name creates a copy rule, i.e., the
given file is copied with the 'cp' command:
TARGET = [ -p | -o ] SOURCE;
By default, Stu will use '/bin/cp' to perform the copy. This can be
changed by setting the variable $STU_CP. If source ends in a slash
(outside of any parameter value), then Stu will look for a file with
the same basename as TARGET in the directory SOURCE. If the persistent
flag -p is used, the timestamp of the source file is not verifying,
only its existence. If the optional flag -o is used, it is not an
error if the target exists and not the source: in that case the target
is considered up to date. Both flags must not be used simultaenously.
A dependency can be one of the following:
NAME A file dependency
The target depends on the file with the name NAME. Stu will make sure
that the file NAME is up to date before the target itself can be up to
@NAME A transient dependency
A transient target. They represent a distinct namespace from files,
and thus their command do not create files.
-p NAME A persistent dependency
Stu will only check whether the dependency exists, but not its modifi‐
cation time. This is mostly useful for directories, as the modifica‐
tion time of directories is updated whenever files are added or removed
in the directory.
-o NAME An optional dependency
Optional dependencies are never built if they don't exist. If they
exist, they are treated like normal dependencies and their date is
taken into account for determining whether the target has to be
A dependency cannot be declared as persistent and optional at the same
time, as that would imply that its command is never executed.
-t NAME A trivial dependency
A trivial dependency will never cause the target to be rebuilt. How‐
ever, if the target is rebuilt for another reason, then the trivial
dependency will be rebuilt itself. This is mostly useful for configu‐
ration files that are generated automatically, including the case of
files containing the flags used to invoke compilers and other programs.
'[' ['-n' | '-0'] NAME ']' A dynamic dependency
Stu will ensure the file named NAME exists, and then parse it as con‐
taining further dependencies of the target. The fact that NAME needs
to be rebuild does not imply that the target has to be rebuilt. The
flag .BR -n makes interpret the content of the file as a newline-sepa‐
rated list of filenames. Analogously, the -0 flag can be used when the
file contains \0-separated filenames. If no flag is used, the file is
parsed in full Stu syntax.
'[' @NAME ']' A dynamic transient target
Brackets can also be used around a transient dependency name. In that
case, all dependencies of the given transient targets will be consid‐
ered dynamic dependencies.
$[NAME] A variable dependency
The file NAME is ensured to be up to date, and the content of the file
NAME is used as the value of the variable $NAME when the target's com‐
mand is executed.
<NAME An input dependency
The dependency is a file which will be used as standard input for the
( ... )
Groups of dependencies can be enclosed on parentheses. Parentheses may
not contain variable dependencies (i.e., something like The flags -p
and -o can be applied to a group of dependencies given in parentheses:
-p ( ... )
-o ( ... )
The flags -p and -o can be applied to dynamic dependencies:
-p [ ... ]
-o [ ... ]
in which case all resulting dynamic dependencies will be flagged as
optional or persistent.
Both parentheses and brackets may be nested:
((A)) # Equivalent to A
[[A]] # Read out dependencies from all files given in the file 'A'.
Any file or transient target may include parameters. Parameters are
noted using the '$' character and are given a name. Stu will match the
pattern to any file or transient target it needs to build. Parameters
can appear in dependencies and in commands any number of times
(included not appearing in them). In a target name, a parameter can
only appear once. The following example contains the parameter $name:
list.$name: data.$name $
./compute-list -n "$name"
Parameters within a single target name must be separated by at least
one character, as otherwise Stu would not be able to determine how to
split up a chain of characters into two parameters. Names of parame‐
ters cannot be empty.
A file or transient target name may match more than one rule. If that
is the case, then Stu will use the rule that dominates all other match‐
ing rules. A rule A is defined to dominate another rule B if for every
character in the target filename there is inside a parameter in rule A,
it is also inside a parameter in rule B, and at least one character is
in a parameter is rule B but not in rule B. It is an error when there
is no single matching rule that dominates all other matching rules.
In the following example, the first rule dominates the other rules for
the file named 'a.b.c':
a.$x.c: ... { ... }
a.$x: ... { ... }
$x.c: ... { ... }
In the following example, no rule dominates the others for the filename
'a.b.c', so Stu will report an error:
$x.b.c: ... { ... }
a.$x.c: ... { ... }
a.b.$x: ... { ... }
Directives in Stu are introduced by '%' and serve a similar purpose to
the C preprocessor. The token '%' must be followed by the directive
name. There may be any amount of whitespace (including none) between
'%' and the name of the directive.
File inclusion is done using the '%include' directive. This can be put
at any place in the input file, and will temporarily continue tokeniza‐
tion in another file. The filename does not have to be quoted, except
if it contains special characters, just like any other filename in Stu.
If a directory is given after include (with or without an ending
slash), the file 'main.stu' within that directory is read.
% include a.stu
% include "b.stu"
% include 'c.stu'
% include data/
To declare which version of Stu a script is written for, use the '%ver‐
sion' directive:
% version 2.3
% version 2.3.4
Both variants will allow the script to be executed only with a version
of Stu of the correct major version number (2 in this example), and
whose minor version (and patch level) have at least the given values.
There may be multiple '%version' directives; each one is then checked
separately. In particular, it is possible to place a version directive
in each source file. This treatment of version numbers follows seman‐
tic versionning ( The version directive will not prevent
usage of Stu features that were not present in the specified version.
Unquoted filenames in Stu may contain the following ASCII characters:
[a-z] [A-Z] [0-9] _ ^ ` + - . ~ /
and all non-ASCII characters. Filenames containing other characters
must be quoted by either single or double quotes. The characters -, +
and ~ are not allowed as the first character of a name if they are not
The following characters have special meaning in Stu and cannot be used
in unquoted filenames:
# Comment (until the end of the line)
% Directive (followed by directive name and arguments)
' Quote; without escape sequences
" Quote; with escape sequences
: Separator for rule definition
; For rules without command, end of variable declaration
- Prefix character for flag, followed by a single character
$ Parameter
@ Transient target marker
> Output redirection
< Input redirection
= Assignment rule, copy rule, named variable
{ } Command
( ) List
[ ] Dynamic dependency
Comments introduced by '#' go until the end of the line. Commands
starting with '{' go until the matching '}', taking into account shell
syntax, i.e., the command itself may contain more braces. All other
characters are individual tokens and may or may not be separated from
other tokens by whitespace.
Quoting in Stu is similar to quoting in the shell. Quoted or unquoted
names which are not separated by whitespace are interpreted as a single
Single quotes may contain any character except single quotes and the
NUL character '\0'. Backslashes and newline characters always have
their literal meaning inside single quotes.
Inside double quotes, backslashes, double quotes and the dollar sign
must be escaped by a backslash. Other C-like escape sequences are
supported, too. To be precise, the following escape sequences are pos‐
sible: \" \\ \$ \a \b \f \n \r \t \v. Dollars in double quotes intro‐
duce parameter names in the same way as outside quotes. Double quotes
may also contain unescaped newline characters. The NUL character '\0'
is not allowed inside double quotes.
Spacing rules: The lack of whitespace between tokens is an error
under certain conditions. Specifically: Whitespace must appear before
opening parentheses and brackets, and after closing parenthesis and
brackets, when the parenthesis or bracket in question would otherwise
be touching either a name token, or another parenthesis or bracket
"from outside". I.e., the following combinations are errors:
)( )[ ]( ][ )A ]A A( A[
In these examples, 'A' stands for any name, including quoted names
using whitespace, except when this would create a new token, which is
only the case for name tokens.
The following characters are reserved for future extension:
* \ & | ! ? ,
The syntax of a Stu file is given in the following Yacc-like notation.
This is the syntax after processing of directives, which are introduced
with '%'.
rule_list: rule*
rule: ('@' NAME | ['>'] NAME)+ [':' expression_list]
('{' COMMAND '}' | ';')
NAME '=' '{' CONTENT '}'
NAME '=' ('-p' | '-o')* NAME ';'
expression_list: expression*
expression: '(' expression_list ')'
'[' expression_list ']'
flag expression
redirect_dep: ['<'] bare_dep
bare_dep: ['@'] NAME
variable_dep: '$' '[' flag* ['<'] NAME ']'
flag: '-p' | '-o' | '-t' | '-n'
Stu files read via the -f option or as the default Stu file, as well as
the argument to the -F option must contain a 'rule_list'. A file
included by brackets (a dynamic dependency) and arguments to the -C
option must contain an 'expression_list'.
Cycles in the dependency graph are not allowed. As an example, the fol‐
lowing results in an error:
A: B { ... }
B: A { ... }
Cycles are considered at the rule level, i.e., cycles such as the fol‐
lowing are also flagged as an error, even though there is no cycle on
the filename level. In the following example, it is not possible to
build the file 'a.gz.gz' from the file 'a', even though it would not
result in a cycle, but since both files 'a.gz' and 'a.gz.gz' use the
same parametrized rule, this is not allowed:
$name.gz: $name { gzip -k $name }
Cycles are possible in dynamic dependencies, where they are allowed and
ignored. For instance, the following examples will correctly build the
file 'A', after having built 'B' and 'C':
A: [B] { echo CORRECT >A }
B: { echo [C] >B }
C: { echo [B] >C }
Symlinks are treated transparently by Stu. In other words, Stu will
always consider the timestamp of the linked-to file. A symlink to a
non-existing file will be treated as a non-existing file.
Stu uses jobs control: Each job is put into its own process group.
All jobs are put into the background, except when the option -i is
used. When -i is not used, the standard input of all jobs is redi‐
rected from /dev/null.
0 Everything was built successfully or was up to date already.
1 Build error. These indicate errors in the commands invoked and
files read by Stu. Example: a child process produced an error,
or a dependency was not found and no rule was given for it.
When using the -q option, the exit status is 1 when the given
targets are not up to date.
2 Logical error. These indicate errors in the usage of Stu.
Examples are syntax errors in Stu sources and cycles in the
dependency graph.
3 Both build and logical errors were encountered (when using the
-k option).
4 An error occurred that made Stu abort execution immediately,
regardless of whether the -k option was used.
STU_CP If set, Stu calls the 'cp' program from the given location
instead of '/bin/cp'. The given version of 'cp' must support
the syntax 'cp -- "$fileA" "$fileB"'.
Contains options to be set on every run of Stu. All letters
except for those in EQswxyYz are ignored. Options passed on the
command line apply after those passed using this variable.
If set, Stu calls the shell from the given location instead of
'/bin/sh'. The given shell must support the -e and -c options.
This is mainly useful on systems where '/bin/sh' is not a POSIX
Stu sets this variable to '1' in all child processes. In order
to avoid recursive invocation of Stu, Stu will fail on startup
when the variable is set. To circumvent this, unset the vari‐
able. Recursive Stu is as harmful as recursive Make.
TERM Used to determine whether to use color output. This variable
must be set to a value different from 'dumb', and isatty(3) must
return 1 for color to be enabled.
When received, Stu will output a list of currently running jobs
on standard output, and statistics about runtime, in a similar
way to the -z option. The reported runtimes include only jobs
that have already terminated, and exclude currently running
jobs. Multiple SIGUSR1 signals sent in succession may result in
output only printed once.
The Stu language is unique to this implementation, and the man page
serves as the reference for its syntax.
Stu follows Semantic Versioning ( The major version number
is increased when backward-incompatible changes are made. The minor
version number is increased when features are added. The patch level is
increased for other changes.
This section contains more advanced examples of Stu usage.
The following declaration tells Stu that the file 'config.h' must
exist, and will allow Stu to give more meaningful error messages if the
file is not found.
Input and output redirection can be used to write commands that invoke
a filter such as sed, awk or tr. The following example will build the
'A' containing the string 'HELLO':
>A: <B { tr a-z A-Z }
>B { echo hello }
Variable dependencies may be included indirectly through transient tar‐
gets without commands, and through dynamic dependencies. In the fol‐
lowing example, the variable $V will be passed through to the commands
for the targets A and B:
V: { echo Hello >V }
@x: $[V];
y: { echo '$[V]' >y }
A: @x { echo $V >A }
B: [y] { echo $V >B }
Trivial dependencies are often combined with variable dependencies to
implement flags, for instance to a compiler, as in the following exam‐
ple. This will make sure that a change in the file 'VERSION' will not
lead to a recompilation of the program, but if 'program.c' is modified
and 'program' is rebuilt, then 'CFLAGS' will also be rebuilt.
VERSION; # Contains the version number; updated by hand
program: program.c $[-t CFLAGS] { gcc $CFLAGS program.c -o program
Copy rules are often used to copy a file from another directory into
the current directory. If both files have the same name, the name of
the source file can be omitted.
# Copy the file bsd/config.h to the current directory. The slash
# the end of the directory name is not necessary, but provides a
# useful hint to the reader.
config.h = bsd/;
Optional copy rules can be used in projects in which certain files will
be available for some developers, but not others:
# The file 'config.h' is delivered with this project. For users
# having the /usr/share/project/ directory, the file will always be
# updated from there by Stu. For users who don't, the file
# delivered with the project is always used.
config.h = -o /usr/share/project/;
The -C option allows to pass any dependency in Stu syntax, and there‐
fore can be used in some advanced use cases:
stu -C '-o X' # Re-build file 'X' only if it already exists
stu -C '[X]' # Build all files given in file 'X'
To check whether Stu is compatible with a particular version of the Stu
# Make sure Stu is compatible with the given version
if stu -C '%version 2.7' ; then
echo "Your Stu is compatible with version 2.7"
The -F option allows to define rules on the command line, e.g.:
# Same as GNU's 'cp -u A B'
stu -F 'B=A;'
You can also use -F to use Stu as a replacement for 'test':
# Check that the file 'A' exists; similar to [ -e A ]
if stu -c A ; then
echo "The file 'A' exists"
# The same, but works also when there is a file 'main.stu' present
# that should be ignored
if stu -F 'A;' ...
You can use Stu to just execute something, like a poor man's shell:
stu -F '@all{ echo Hello World }'
(of course, you can also type that directly or use 'sh -c', etc.)
Using the -i option, Stu commands can read from their standard input.
For instance, the following will read a line from the user and use it.
This cannot be used in conjunction with the -j option (except for -j1).
>config.h: {
echo >&2 "Please enter the value of COUNT"
read -r count
echo "#define COUNT $count"
Filenames in Stu are literal. Stu does not recognize it when two dif‐
ferent names refer to the same file.
The argument to the -j option (number of jobs to run in parallel) is
mandatory, as opposed to the behavior of GNU Make, where no argument
means to run as many jobs in parallel as possible.
Rule-level recursion is not allowed. This excludes a recursive parsing
of C-like dependencies. Rule-level recursion would be easy to enable,
but would open up problems related to infinite loops, which would
require Stu to have a maximal recursion depth.
When the command fails and its target is a directory, Stu cannot remove
the directory as it does for regular files.
Changing a command within a Stu file will not make the target to be
rebuilt. This can be seen as both a feature or a bug. Also, all
changes in a file will lead to rebuilds of other files, even if the
changes are trivial, e.g., when only whitespace was changed in C source
code. Furthermore, touching a file without changing the contents will
also lead to a rebuild, although it is not needed. Both limitations
could be removed by using fingerprints instead of modification times.
All timestamps have only one-second resolution, except when the Linux-
only USE_MTIM option is set on compilation. (Which it is by default on
Using optional dependencies may make a second invocation of Stu not
output 'Targets are up to date', as the optional dependency may have
been created by subsequent targets.
Written by Jérôme Kunegis <>, with contributions
and help by Jun Sun, Aaron McDaid, Heinrich Hartmann, and Holger Heinz.
make(1), cook(1)
stu-2.4.38 October 2016 STU(1)