STU(1) STU STU(1) NAME stu - Build automation SYNOPSIS stu [ -f FILENAME ] [ OPTION ]... [ TARGET ]... DESCRIPTION Stu is a tool for build automation. Like Make, it is used to call other programs in order to build files. Stu has three features that work in conjunction to allow contructs impossible to realize in Make: (1) Dynamic dependencies: The dependencies of a target can be them‐ selves 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) Parameters: Names of files (and transient targets) can contain parameters written using dol‐ lar syntax. For example, a rule with a target filename '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 parameters. (3) Concatena‐ tion: Stu allows expressions such as list.[FILENAME] and list.(a b c) to construct a list of files following a certain pattern. At its core, 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 op‐ tions -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 -F. Names of targets to build passed on the command line outside of options follow a simplified Stu syntax, in which the only special characters are the transient target marker '@', brackets '[]', and flags starting with a dash '-'. All other characters are interpreted as part of file‐ names; this includes all spaces. The parentheses '()' are not parsed as Stu syntax, because the shell's braces '{}' can be used instead. When -J is used, arguments passed on the command line are interpreted as filenames without Stu syntax. The syntax of arguments outside of options and without using the -J is subject to change with new features in Stu -- to pass filenames portably, use the -c option when passing individual filenames, or -J when passing multiple filenames, e.g. via xargs(1). To pass targets in full stu syntax portably, use the -C op‐ tion. OPTIONS -0 FILENAME Read targets from FILENAME, which must contain \0-separated filenames. No Stu syntax is processed. This option is also suitable in all cases where a file contains only the name of a single file, since filenames do not contain the \0 character. Using this option is equivalent to using the [-0 FILENAME] syn‐ tax. -a Treat all trivial dependencies, which are declared with the -t flag or option, as non-trivial. -c FILENAME Pass a target filename, without Stu syntax. This option only allows file targets to be specified, not transient targets. -C EXPRESSION 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 script. 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 ar‐ gument to Stu outside of options, because -C supports full Stu syntax, while arguments supports only a reduced syntax (see above). -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‐ ces. The output is otherwise not standardized and is subject to change, in particular with internal changes to the algorithms used. -E Explain error messages. For certain errors, an additional ex‐ planation is written on standard error output. Only some error messages have explanations. -f FILENAME 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. -F RULES Pass rules in full Stu syntax. -g Treat all optional dependencies (declared with the -o flag) as non-optional. -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. Without this option, jobs are run in the background, meaning they can't read standard input (they get /dev/null instead), 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, pressing Ctrl-C will only in‐ terrupt 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. When -i is used, Stu must be run in a terminal. -I Print a list of all buildable file targets and exit. Prints one file pattern per line. The patterns are glob pattern suitable for use in the shell. Use quoting for all characters that need quoting in the shell. Can be used to populate files such as ".gitgignore", but care should be taken due to the quoting syn‐ tax and Git's special handling of names that start or end with a slash. -j K Run K jobs in parallel. K must be a positive integer. Without this option, jobs are not run in parallel, which is equivalent to using the -j 1 setting. 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 mandatory. This option works like the corresponding option in GNU Make, but note that in GNU Make, the argument is op‐ tional. -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 be‐ ing erroneously considered up to date. -m ORDER 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 most Make implementations. When ORDER is 'random', the order in which jobs are run is ran‐ domized within each target. -M STRING Run jobs in pseudorandom order, seeded by the given string. -n FILENAME Read targets from FILENAME, which must contain newline-separated filenames. No Stu syntax is processed. Using this option is equivalent to using the [-n FILENAME] syntax. -o FILENAME Pass the given file as an optional dependency, i.e., build it only if it already exists and is out of date. -p FILENAME Pass the given file as a persistent dependency, i.e., build the file but ignore its timestamp. -P Print the set of rules 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 targets are up to date. The exit status is 0 when all given targets (or the default target) are up to date, and 1 when not. The exit status may still be 2 or 4 on encountering logical or fatal errors. The options -k and -j are ignored. -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 se‐ quences 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.) Stu options are parsed with getopt(3) and therefore options must precede arguments. Options following arguments may be supported on some platforms. OVERVIEW A simple rule looks as follows: results.txt: data.txt compute { ./compute --input data.txt --output results.txt } The colon may be omitted when there are no dependencies: data.csv { ./generate --output data.csv } Here is an example of a rule containing three parameters. Stu will use pattern matching to match the target pattern to a given filename: plot.$dataset.$method.$measure.eps: 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 dependencies: 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: output.txt: a.data b.data c.data d.data e.data f.data g.data h.data i.data j.data k.data l.data m.data { 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 a colon: '((': '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 } 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 al‐ ready exists, then its own rule is used (and its date checked) to de‐ cide whether it should be rebuilt. target: -o input { if [ -r input ] ; then cp input target else echo Hello >target fi } Trivial dependencies are denoted with the -t flag. They denote a de‐ pendency 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 don't even cause a target to be re‐ built if they don't exist. Trivial dependencies are typically used for configuration, 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 -o flag. By de‐ fault, the name of the variable set is the same as the filename. An‐ other variable name can be used in the following way: $[NAME = FILENAME] If multiple variable dependencies have the same name, it is unspecified which one is used. If a variable dependencies has the same name as a parameter, it overrides the parameter. 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 } FEATURES Like a makefile, a Stu script 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: [>] TARGET [ : DEPENDENCY ... ] { COMMAND } The target is a filename. DEPENDENCY ... are depencies. COMMAND is a command which is passed to the shell for building. Stu will always ex‐ ecute 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 ex‐ plicit 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: TARGET [ : DEPENDENCY ... ] ; 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: TARGET ; For a transient, the same syntax is used as for a file: @TARGET [ : DEPENDENCY ... ] { COMMAND } @TARGET [ : DEPENDENCY ... ] ; If a transient target includes a command, Stu will have no way of re‐ membering 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 ... ] { COMMAND } 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 rule 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 '=' op‐ erator: TARGET = { CONTENT ... } The content is stripped of empty lines and common whitespace at the be‐ ginning 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 verified, 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 con‐ sidered 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 date. @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 ex‐ ist, they are treated like normal dependencies and their date is taken into account for determining whether the target has to be rebuilt. 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 de‐ pendency will be rebuilt itself. This is mostly useful for configura‐ tion 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 -n makes Stu 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, or when the file contains the name of exactly one file. 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. Output redirection < Input redirection = Assignment rule; copy rule; named variable ( ) List [ ] Dynamic dependency { } Command 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 name. Outside of quotes, the backslash can be used to escape any char‐ acter. Backslash-newline sequences are ignored. All other characters can be preceded by a backslash to retain their literal meaning as part of a name. 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. There is no \0 escape sequence, as names of files and transients cannot contain the NUL byte. Spacing rules: The lack of whitespace between tokens represents con‐ catenation under certain conditions. Specifically: To separate depen‐ dencies, whitespace must appear before opening parentheses and brack‐ ets, 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 represent concatenation: )( )[ ]( ][ )A ]A A( A[ In this list, '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: * & | ! ? , SYNTAX The syntax of a Stu script is given in the following Yacc-like nota‐ tion. This is the syntax after processing of directives, which are in‐ troduced with '%'. rule_list: rule* rule: ('@' NAME | ['>'] NAME)+ [':' expression_list] ('{' COMMAND '}' | ';') NAME '=' '{' CONTENT '}' NAME '=' ('-p' | '-o')* NAME ';' expression_list: expression* {1} expression: unit_expression* {2} flag expression variable_dep unit_expression: '(' expression_list ')' '[' expression_list ']' redirect_dep redirect_dep: ['<'] bare_dep bare_dep: ['@'] NAME variable_dep: '$' '[' flag* ['<'] NAME ']' flag: '-p' | '-o' | '-t' | '-n' | '-0' {1} with intervening whitespace {2} without intervening whitespace Stu scripts read via the -f option or as the default Stu script (main.stu), 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'. Argu‐ ments passed outside of options on the command line must contain an 'expression_list', but a simplified syntax is used in which only the charaters '[]-@' are recognized, and that only in positions where they make sense; in all other cases, characters are interpreted as part of filenames -- this is also valid for whitespace. SEMANTICS 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 job 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 redirected from /dev/null. If a command fails, Stu will remove any of its target files, if they have been already touched by the command. If the failing command did not touch a target file, that existing target file is not removed. This behavior is necessary to avoid the case that a commands partially creates a target file, then fails, and then a subsequent invocation of Stu sees the new file and considers it as up to date, even though it was only partially created. Thus, commands in Stu do not need to make sure they delete any output files when they fail. This behavior is equivalent to that in Make. EXIT STATUS 0 Success. Everything was built successfully, or was already up to date. 1 Build error. This indicates 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. This indicates errors in the usage of Stu. Ex‐ amples are syntax errors in Stu scripts, cycles in the depen‐ dency graph and certain erroneous options on the command line. 3 Both build and logical errors were encountered (when using the -k option). 4 Fatal error. An error occurred that made Stu abort execution immediately, regardless of whether the -k option was used. This includes system errors from which Stu cannot recover (such as out-of-memory conditions), as well as errors on the Stu command line that make Stu fail immediately. ENVIRONMENT STU_CP If set, Stu calls the 'cp' program from the given location in‐ stead of '/bin/cp'. The given version of 'cp' must support the syntax 'cp -- "$fileA" "$fileB"'. STU_OPTIONS Contains options to be set on every run of Stu. Only the op‐ tions EQswxyYz can be set this way. The variable should contain only these characters, dashes, and whitespace; other characters produce an error. Options passed on the command line apply af‐ ter those passed using this variable. STU_SHELL 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 shell. Stu ignores the $SHELL variable, like Make does, as that variable is only intended to set the user's interactive shell. STU_STATUS Stu sets this variable to '1' in all child processes. In order to avoid recursive invocation of Stu, Stu will fail with a fatal error (exit status 4) on startup when the variable is set. To circumvent this, unset the variable. Recursive Stu is as harm‐ ful 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. (Alternatively, color can be controlled by the -y and -Y options.) SIGNALS SIGUSR1 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 rapid succession may re‐ sult in output only printed once. CONFORMING TO The Stu language is unique to this implementation, and the man page serves as the reference for its syntax. Stu follows Semantic Versioning (semver.org). 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. EXAMPLES The basic example of a rule in Stu is: program: program.c config.h { cc -c program.c -o program } The following declaration tells Stu that the file 'config.h' must ex‐ ist, and will allow Stu to give more meaningful error messages if the file is not found. config.h; 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 file 'A' containing the string 'HELLO': >A: 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 >CFLAGS: $[VERSION] { echo -g -Wall -D VERSION=$VERSION ; } 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 at # 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/; Parentheses can be used in a similar way to braces in the shell, to construct a list of filenames following a pattern: @headers: (config data list).h; This will make @headers depend on the files config.h, data.h, and list.h. This can be combined with brackets in the following way: @headers: [NAMES].h; 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 syntax: # Make sure Stu is compatible with the given version if stu -s -C '%version 2.7' ; then echo "Your Stu is compatible with version 2.7" fi 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" fi # 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 '@main{ 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" } BUGS There is no way to change the used shell from within a Stu script. The only way to do it is with the $STU_SHELL environment variable. 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. For arguments passed on the command line outside of options, brackets [] can be used for dynamic dependencies, but parentheses () cannot. Instead, the shell's braces {} must be used, or the option -C. 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 re‐ quire Stu to have a maximal recursion depth. When a 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 script 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 Linux.) 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. Commands enclosed in braces { ... } are parsed using shell syntax, up to one exception: a closing brace is detected everywhere in unqotued environments, not only when standing alone as the first word of a com‐ mand. E.g., the command { echo Hello } is a valid command for Stu, while it would be an error for the shell, as the closing } would be in‐ terpreted as a second argument to 'echo'. In error messages, the column numbers are based on the number of bytes, and do not take into account multibyte characters or combining charac‐ ters, etc. Thus, the placement of error messages may be wrong within the line in certain editors or GUIs. When an error occurs with a concatenated file or transient name, Stu only outputs the location of the name as a whole, and does not point to the source of the individual components of the concatenation. This can lead to confusing error backtraces. AUTHOR Written by Jérôme Kunegis at the University of Na‐ mur, Belgium, as well as at the University of Koblenz-Landau, Germany, with contributions and help by Jun Sun, Aaron McDaid, Heinrich Hart‐ mann, Holger Heinz, and others. Our thanks go to the many early testers and users of Stu, who have helped us fix many bugs, and iden‐ tify many different use cases and usage patterns. SEE ALSO cook(1), gpl(7), make(1), sh(1) stu-2.7.82 July 2023 STU(1)