tup [--debug-sql] [--debug-fuse] [SECONDARY_COMMAND] [ARGS]
Tup is a file-based build system. You should use tup if you are
developing software which needs to be translated from input files (written
by you) into a different output format. For example, if you are writing a C
program, you could use tup to determine which files need to be recompiled,
archived, and linked based on a dependency graph.
Tup has no domain specific knowledge. You must tell tup how to
build your program, such as by saying that all .c files are converted to .o
files by using gcc. This is done by writing one or more Tupfiles.
You can do all of your development with just 'tup', along with
writing Tupfiles. See also the INI FILE, OPTIONS FILES and
TUPFILES sections below.
- tup [<output_1> ...
<output_n>]
- Updates the set of outputs based on the dependency graph and the current
state of the filesystem. If no outputs are specified then the whole
project is updated. This is what you run every time you make changes to
your software to bring it up-to-date. You can run this anywhere in the tup
hierarchy, and it will always update the requested output. By default, the
list of files that are changed are determined by scanning the filesystem
and checking modification times. For very large projects this may be slow,
but you can skip the scanning time by running the file monitor (see
SECONDARY COMMANDS for a description of the monitor).
- -jN
- Temporarily override the updater.num_jobs option to 'N'. This will run up
to N jobs in parallel, subject to the constraints of the DAG. Eg: 'tup
-j2' will run up to two jobs in parallel, whereas 'tup' will run up to
updater.num_jobs in parallel. See the option secondary command below.
- --verbose
- Causes tup to display the full command string instead of just the
pretty-printed string for commands that use the ^ TEXT^ prefix.
- --quiet
- Temporarily override the display.quiet option to '1'. See the option
secondary command below.
- -k
- --keep-going
- Temporarily override the updater.keep_going option to '1'. See the option
secondary command below.
- --no-keep-going
- Temporarily override the updater.keep_going option to '0'. See the option
secondary command below.
- --no-scan
- Do not scan the project for changed files. This is for internal tup
testing only, and should not be used during normal development.
- --no-environ-check
- Do not check for updates to the environment variables exported to
sub-processes. Instead, the environment variables will be used from the
database. This is used by the monitor in autoupdate/autoparse mode so that
the most recent environment variables are used, rather than the settings
when the monitor was initialized.
- -d
- Output debug log to screen.
- --debug-run
- Output the :-rules generated by a run-script. See the 'run ./script args'
feature in the TUPFILES section. --debug-logging Save some debug
output and build graphs in .tup/log. Graphs are rotated on each invocation
with --debug-logging.
These commands are used to modify the behavior of tup or look at
its internals. You probably won't need these very often. Secondary commands
are invoked as:
tup [--debug-sql] [--debug-fuse] SECONDARY_COMMAND
[SECONDARY_COMMAND_ARGS]
- init
[directory]
- Creates a '.tup' directory in the specified directory and initializes the
tup database. If a directory name is unspecified, it defaults to creating
'.tup' in the current directory. This defines the top of your project, as
viewed by tup. Everything in the current directory and its subdirectories
are known as the "tup hierarchy".
If you want to avoid having to run 'tup init' every time you
clone your repository to a new location, you can instead create an empty
file called 'Tupfile.ini' in the project root. If 'tup' is run without
the '.tup' directory present, it will automatically create one for you
as a sibling of the Tupfile.ini file, as if you had run 'tup init' in
that directory.. If there are multiple Tupfile.ini files in parent
paths, the one highest up the tree will be chosen.
- --no-sync
- Sets the 'db.sync' option of the project to '0'. By default the 'db.sync'
option will be set to '1'. This flag is mostly used for test cases, but
you could also use this in any environment where you want to script tup
and use no synchronization by default.
- refactor
- ref
- The refactor command can be used to help refactor Tupfiles. This will
cause tup to run through the parsing phase, but not execute any commands.
If any Tupfiles that are parsed result in changes to the database, these
are reported as errors. For example, we may have the following simple
Tupfile:
: foreach *.c |> gcc -c %f -o %o -Wall |> %B.o
After an initial 'tup', we decide that we want to move the
-Wall to a variable called CFLAGS. The Tupfile now looks like:
CFLAGS = -Wall
: foreach *.c |> gcc -c %f -o %o $(CFLAGS) |> %B.o
Running 'tup refactor' will cause tup to parse the Tupfile,
and if we made any mistakes, an error message will be displayed. The
Tupfiles can then be modified to fix those errors, and keep running 'tup
refactor' until all Tupfiles are parsed successfully.
Errors are reported for adding or removing any of the
following: commands, inputs that are generated files, outputs, the
.gitignore directive, input or output <groups>, and directory
level dependencies. Otherwise, you are able to move any strings out to
$-variables, !-macros, and the like, so long as the end-result of the
set of :-rules is the same.
- monitor
- *LINUX ONLY* Starts the inotify-based file monitor. The monitor must scan
the filesystem once and initialize watches on each directory. Then when
you make changes to the files, the monitor will see them and write them
directly into the database. With the monitor running, 'tup' does not need
to do the initial scan, and can start constructing the build graph
immediately. The "Scanning filesystem..." time from 'tup' is
approximately equal to the time you would save by running the monitor.
When the monitor is running, a 'tup' with no file changes should only take
a few milliseconds (on my machines I get about 2 or 3ms when everything is
in the disk cache). If you restart your computer, you will need to restart
the monitor. The following arguments can be given on the command line. Any
additional arguments not handled by the monitor will be passed along to
the updater if either monitor.autoupdate or monitor.autoparse are enabled.
For example, you could run the monitor as 'tup monitor -f -a -j2' to run
the monitor in the foreground, and automatically update with 2 jobs when
changes are detected. See also the option secondary command below.
- -d
- Enable debugging of the monitor process.
- -f
- --foreground
- Temporarily override the monitor.foreground option to 1. The monitor will
run in the foreground (don't daemonize).
- -b
- --background
- Temporarily override the monitor.foreground option to 0. The monitor will
run in the background (daemonize).
- -a
- --autoupdate
- Temporarily override the monitor.autoupdate option to 1. This will
automatically run an update when file changes are detected.
- -n
- --no-autoupdate
- Temporarily override the monitor.autoupdate option to 0. This will prevent
the monitor from automatically running an update when file changes are
detected.
- --autoparse
- Temporarily override the monitor.autoparse option to 1. This will
automatically run the parser when file changes are detected.
- --no-autoparse
- Temporarily override the monitor.autoparse option to 0. This will prevent
the monitor from automatically running the parser when file changes are
detected.
- stop
- Kills the monitor if it is running. Basically it saves you the trouble of
looking up the PID and killing it that way.
- variant foo.config
[bar.config] [...]
- For each argument, this command creates a variant directory with
tup.config symlinked to the specified config file. For example, if a
directory contained several variant configurations, one could easily
create a variant for each config file:
$ ls configs/
bar.config
foo.config
$ tup variant configs/*.config
tup: Added variant 'build-bar' using config file 'configs/bar.config'
tup: Added variant 'build-foo' using config file 'configs/foo.config'
This is equivalent to the following:
$ mkdir build-bar
$ ln -s ../configs/bar.config build-bar/tup.config
$ mkdir build-foo
$ ln -s ../configs/foo.config build-foo/tup.config
For projects that commonly use several variants, the files in
the configs/ directory could be checked in to source control. Each
developer would run the 'tup variant' after 'tup init' during the
initial checkout of the software. Variants can also be created manually
by making a build directory and creating a tup.config file in it (see
the VARIANTS section). This command merely helps save some steps, so
that you don't have to make each build directory and tup.config symlink
manually.
- dbconfig
- Displays the current tup database configuration. These are internal values
used by tup.
- options
- Displays all of the current tup options, as well as where they originated.
For details on all of the available options and how to set
them, see the OPTIONS FILES section below.
- graph [--dirs] [--ghosts]
[--env] [--combine] [--stickies] [<output_1> ...
<output_n>]
- Prints out a graphviz .dot format graph of the tup database to stdout. By
default it only displays the parts of the graph that have changes. If you
provide additional arguments, they are assumed to be files that you want
to graph. This operates directly on the tup database, so unless you are
running the file monitor you may want to run 'tup scan' first. This is
generally used for debugging tup -- you may or may not find it helpful for
trying to look at the structure of your program.
- --dirs
- Temporarily override the graph.dirs option to '1'. This will show the
directory nodes and Tupfiles.
- --ghosts
- Temporarily override the graph.ghosts option to '1'. This will show ghost
nodes (files that a command tried to access, but don't actually
exist).
- --env
- Temporarily override the graph.environment option to '1'. This will show
the environment variables, such as PATH.
- todo [<output_1> ...
<output_n>]
- Prints out the next steps in the tup process that will execute when
updating the given outputs. If no outputs are specified then it prints the
steps needed to update the whole project. Similar to the 'upd' command,
'todo' will automatically scan the project for file changes if a file
monitor is not running.
- --no-scan
- Do not scan the project for changed files. This is for internal tup
testing only, and should not be used during normal development.
- --verbose
- Causes tup to display the full command string instead of just the
pretty-printed string for commands that use the ^ TEXT^ prefix.
- generate [--config
config-file] script.sh (or script.bat on Windows)
- The generate command will parse all Tupfiles and create a shell script
that can build the program without running in a tup environment. The
expected usage is in continuous integration environments that aren't
compatible with tup's dependency checking (eg: if FUSE is not supported).
On Windows, if the script filename has a ".bat" extension, then
the output will be a batch script instead of a shell script. For example:
git clone ... myproj
cd myproj
tup generate build.sh
./build.sh
# Copy out build artifacts / logs here
git clean -f -x -d
The shell script does not work incrementally, so it is effectively a
one-time use. You will need to clean up the tree before the next 'tup
generate' and script invocation. This does not support variants, however
the top-level tup.config file is used to define the configuration
variables. Optionally, a separate configuration file can be passed in with
the --config argument.
- varsed
- The varsed command is used as a subprogram in a Tupfile; you would not run
it manually at the command-line. It is used to read one file, and replace
any variable references and write the output to a second file. Variable
references are of the form @VARIABLE@, and are replaced with the
corresponding value of the @-variable. For example, if foo.txt contains:
The architecture is set to @ARCH@
And you have a :-rule in a Tupfile like so:
: foo.txt |> tup varsed %f %o |> foo-out.txt
Then on an update, the output file will be identical to the input file,
except the string @ARCH@ will be replaced with whatever CONFIG_ARCH is set
to in tup.config. The varsed command automatically adds the dependency
from CONFIG_ARCH to the particular command node that used it (so if
CONFIG_ARCH changes, the output file will be updated with the new
value).
- scan
- You shouldn't ever need to run this, unless you want to make the database
reflect the filesystem before running 'tup graph'. Scan is called
automatically by 'upd' if the monitor isn't running.
- upd
- Legacy secondary command. Calling 'tup upd' is equivalent to simply
calling 'tup'.
The tup command can be run from anywhere in the source tree. It
uses the information from all Tupfiles (see the TUPFILES section) as
well as it's own dynamic database, which is maintained in the .tup directory
located at the root of the project. The .tup directory can be created
manually with the 'tup init' command, or you can have it run automatically
by adding an empty Tupfile.ini file at the root of the project's version
control repository.
The contents of the Tupfile.ini file are ignored.
Tup allows for a variety of configuration files. These files
affect the behavior of tup as a program, but not tup as a build system. That
is to say, changing any of these options should not affect the end result of
a successful build, but may affect how tup gets there (e.g. how many compile
jobs to run in parallel).
The options are read in the following precedence order:
command-line overrides (eg: -j flag passed to 'tup')
.tup/options file
~/.tupoptions file
/etc/tup/options file
tup's compiled in defaults
For Windows, the options files are read in as follows:
command-line overrides
.tup/options file
tup.ini in the Application Data path (usually C:\ProgramData\tup\tup.ini)
tup's compiled in defaults
For an exact list of paths on your platform, type 'tup
options'.
All files use the same .ini-style syntax. A section header is
enclosed in square brackets, like so:
[updater]
The section header is followed by one or more variable
definitions, of the form 'variable = value'. Comments start with a
semi-colon and continue to the end of the line. The variable definitions can
all be set to integers. For boolean flags, "true"/"yes"
and "false"/"no" are synonyms for 1 and 0, respectively.
For example, if you have a .tup/options file that contains:
[updater]
num_jobs = 2
keep_going = true
Then 'tup' will default to 2 jobs, and have the updater.keep_going
flag set. The options listed below are of the form 'section.variable', so to
set 'db.sync' you would need a '[db]' section followed by 'sync = 0', for
example. The defaults listed here are the compiled-in defaults.
- db.sync (default
'1')
- Set to '1' if the SQLite synchronous feature is enabled. When enabled, the
database is properly synchronized to the disk in a way that it is always
consistent. When disabled, it will run faster since writes are left in the
disk cache for a time before being written out. However, if your computer
crashes before everything is written out, the tup database may become
corrupted. See http://www.sqlite.org/pragma.html for more
information.
- updater.num_jobs
(defaults to the number of processors on the system )
- Set to the maximum number of commands tup will run simultaneously. The
default is dynamically determined to be the number of processors on the
system. If updater.num_jobs is greater than 1, commands will be run in
parallel only if they are independent. See also the -j option.
- updater.keep_going
(default '0')
- Set to '1' to keep building as much as possible even if errors are
encountered. Anything dependent on a failed command will not be executed,
but other independent commands will be. The default is '0', which will
cause tup to stop after the first failed command. See also the -k
option.
- updater.full_deps
(defaults to '0')
- Set to '1' to track dependencies on files outside of the tup hierarchy.
The default is '0', which only tracks dependencies within the tup
hierarchy. For example, if you want all C files to be re-compiled when gcc
is updated on your system, you should set this to '1'. In Linux and OSX,
using full dependencies requires that the tup binary is suid as root so
that it can run sub-processes in a chroot environment. Alternatively on
Linux, if your kernel supports user namespaces, then you don't need to
make the binary suid. Note that if this value is set to '1' from '0', tup
will rebuild the entire project. Disabling this option when it was
previously enabled does not require a full rebuild, but does take some
time since the nodes representing external files are cleared out. NOTE:
This does not currently work with ccache or other programs that may write
to external files due to issues with locking. This may be fixed in the
future.
- updater.warnings
(defaults to '1')
- Set to '0' to disable warnings about writing to hidden files. Tup doesn't
track files that are hidden. If a sub-process writes to a hidden file,
then by default tup will display a warning that this file was created. By
disabling this option, those warnings are not displayed. Hidden filenames
(or directories) include: ., .., .tup, .git, .hg, .bzr, .svn.
- display.color
(default 'auto')
- Set to 'never' to disable ANSI escape codes for colored output, or
'always' to always use ANSI escape codes for colored output. The default
is 'auto', which displays uses colored output if stdout is connected to a
tty, and uses no colors otherwise (ie: if stdout is redirected to a
file).
- display.width
(defaults to the terminal width)
- Set to any number 10 or larger to force a fixed width for the progress
bar. This is assumed to be the total width, some of which is used for
spacing, brackets, and the percentage complete. If this value is less than
10, the progress bar is disabled.
- display.progress
(defaults to '1' if stdout is a TTY)
- Set to '1' to enable the progress bar, or '0' to turn it off. By default
it is enabled if stdout is a TTY, and disabled if stdout is not a
TTY.
- display.job_numbers
(default '1')
- Set to '0' to avoid displaying the "N) " string before the
results of a job. The default is to display this number.
- display.job_time
(default '1')
- Set to '0' to avoid displaying the runtime of a job along with the
results. The default is to display the runtime. Note that the runtime
displayed includes the time that tup takes to save the dependencies.
Therefore, this runtime will likely be larger than the runtime when
executing the same job manually in the shell.
- display.quiet
(default '0')
- Set to '1' to prevent tup from displaying most output. Tup will still
display a banner and output from any job that writes to stdout/stderr, or
any job that returns a non-zero exit code. The progress bar is still
displayed; see also display.progress for really quiet output.
- monitor.autoupdate
(default '0')
- Set to '1' to automatically rebuild if a file change is detected. This
only has an effect if the monitor is running. The default is '0', which
means you have to type 'tup' when you are ready to update.
- monitor.autoparse
(default '0')
- Set to '1' to automatically run the parser if a file change is detected.
This is similar to monitor.autoupdate, except the update stops after the
parser stage - no commands are run until you manually type 'tup'. This
only has an effect if the monitor is running. Note that if both autoupdate
and autoparse are set, then autoupdate takes precedence.
- monitor.foreground
(default '0')
- Set to '1' to run the monitor in the foreground, so control will not
return to the terminal until the monitor is stopped (either by ctrl-C in
the controlling terminal, or running 'tup stop' in another terminal). The
default is '0', which means the monitor will run in the background.
- graph.dirs
(default '0')
- Set to '1' and the 'tup graph' command will show the directory nodes and
their ownership links. Tupfiles are also displayed, since they point to
directory nodes. By default directories and Tupfiles are not shown since
they can clutter the graph in some cases, and are not always useful.
- graph.ghosts
(default '0')
- Set to '1' to show ghost nodes. Some commands may try to read from many
files that don't exist, causing ghost nodes to be created. By default,
ghosts are not shown to make the graph easier to understand.
- graph.environment
(default '0')
- Set to '1' to show the environment nodes (such as PATH) and their
dependencies. By default the environment variables are not shown since
nearly everything will depend on PATH.
- graph.combine
(default '0')
- Set to '1' to try to combine similar nodes in the graph. For example,
instead of showing 10 separate compilation commands that all have one .c
file input and one .o file output, this will combine them into one command
to more easily see the whole structure of the graph. By default all nodes
are shown separately.
You must create a file called "Tupfile" anywhere in the
tup hierarchy that you want to create an output file based on the input
files. The input files can be anywhere else in the tup hierarchy, but the
output file(s) must be written in the same directory as the Tupfile.
- : [foreach] [inputs] [ | order-only inputs] |> command |>
[outputs] [ | extra outputs] [<group>] [{bin}]
- The :-rules are the primary means of creating commands, and are denoted by
the fact that the ':' character appears in the first column of the
Tupfile. The syntax is supposed to look somewhat like a pipeline, in that
the input files on the left go into the command in the middle, and the
output files come out on the right.
- foreach
- This is either the actual string "foreach", or it is empty. The
distinction is in how many commands are generated when there are multiple
input files. If "foreach" is specified, one command is created
for each file in the inputs section. If it is not specified, one command
is created containing all of the files in the inputs section. For example,
the following Tupfiles are equivalent:
# Tupfile 1
: foo.c |> gcc -c foo.c -o foo.o |> foo.o
: bar.c |> gcc -c bar.c -o bar.o |> bar.o
# Tupfile 2
: foreach foo.c bar.c |> gcc -c %f -o %o |> %B.o
Additionally, using "foreach" allows the use of the "%e"
flag (see below).
- inputs
- The input files for the command. An input file can be anywhere in the tup
hierarchy, and is specified relative to the current directory. Input files
affect the %-flags (see below). Wildcarding is supported within a
directory by using the SQLite glob function. The special glob characters
are '*', '?', and '[]'. For example, "*.c" would match any .c
file, "fo?.c" would match any 3-character .c file that has 'f'
and 'o' as the first two characters, and "fo[xyz].c" would match
fox.c, foy.c, and foz.c. Globbing does not match directories, so
"src/*.c" will work, but "*/*.c" will not.
- order-only
inputs
- These are also used as inputs for the command, but will not appear in any
of the %-flags. They are separated from regular inputs by use of the '|'
character. In effect, these can be used to specify additional inputs to a
command that shouldn't appear on the command line. Globbing is supported
as in the inputs section. For example, one use for them is to specify
auto-generated header dependencies:
: |> echo "#define FOO 3" > %o |> foo.h
: foreach foo.c bar.c | foo.h |> gcc -c %f -o %o |> %B.o
This will add the foo.h dependency to the gcc commands for foo.c and bar.c,
so tup will know to generate the header before trying to compile. The
foreach command will iterate over the regular inputs (here, foo.c and
bar.c), not the order-only inputs (foo.h). If you forget to add such a
dependency, tup will report an error when the command is executed. Note
that the foo.h dependency is only listed here because it is created by
another command -- normal headers do not need to be specified.
- command
- The command string that will be passed to the system(3) call by tup. This
command is allowed to read from any file specified as an input or
order-only input, as well as any other file in the tup hierarchy that is
not the output of another command. In other words, a command cannot read
from another command's output unless it is specified as an input. This
restriction is what allows tup to be parallel safe. Additionally, the
command must write to all of the output files specified by the
"outputs" section, if any.
- When executed, the command's file accesses are monitored by tup to ensure
that they conform to these rules. Any files opened for reading that were
generated from another command but not specified as inputs are reported as
errors. Similarly, any files opened for writing that are not specified as
outputs are reported as errors. All files opened for reading are recorded
as dependencies to the command. If any of these files change, tup will
re-execute the command during the next update. Note that if an input
listed in the Tupfile changes, it does not necessarily cause the command
to re-execute, unless the command actually read from that input during the
prior execution. Inputs listed in the Tupfile only enforce ordering among
the commands, while file accesses during execution determine when commands
are re-executed.
- A command string can begin with the special sequence ^ TEXT^, which
will tell tup to only print "TEXT" instead of the whole command
string when the command is being executed. This saves the effort of using
echo to pretty-print a long command. The short-display behavior can be
overridden by passing the --verbose flag to tup, which will cause tup to
display the actual command string instead of "TEXT". The space
after the first '^' is significant. Any characters immediately after the
first '^' are treated as flags. See the ^-flags section below for details.
For example, this command will print "CC foo.c" when executing
system(gcc -c foo.c -o foo.o) :
: foo.c |> ^ CC %f^ gcc -c %f -o %o |> foo.o
- A command string can also begin with the special character '!', in which
case the !-macro specified will be substituted in for the actual command.
See the !-macro definition later. Commands can also be blank, which is
useful to put all the input files in a {bin} for a later rule.
- outputs
- The outputs section specifies the files that will be written to by the
command. Only one command can write to a specific file, but a single
command can output multiple files (such as how a bison command will output
both a .c and .h file). The output can use any %-flags except %o. Once a
file is specified in an output section, it is put into the tup database.
Any following rules can use that file as an input, even if it doesn't
exist in the filesystem yet.
- The extra-outputs section is similar to the order-only inputs section. It
is separated from the regular outputs by the '|' character. The
extra-outputs behave exactly as regular outputs, except they do not appear
in the %o flag. These can be used if a command generates files whose names
do not actually appear in the command line. If there is exactly one output
specified by the rule, the extra-outputs section can use the %O flag to
represent the basename of the output. This can be useful in extra-outputs
for !-macros.
- <group>
- Output files can be grouped into global groups by specifying a
<group> after the outputs but before a bin. Groups allow for
order-only dependencies between folders. Note that groups are directory
specific, however, so when referring to a group you must specify the path
to where it is assigned. For example, if a main project depends on the
output from several submodules you can structure Tup like so to make sure
the submodules are built before the main project:
#./submodules/sm1/Tupfile
: foo.c |> gcc -c %f -o %o |> %B.o ../<submodgroup>
#./submodules/sm2/Tupfile
: bar.c |> gcc -c %f -o %o |> %B.o ../<submodgroup>
#./project/Tupfile
: baz.c | ../submodules/<submodgroup> |> gcc -c %f -o %o |> %B.o
Notice how groups are directory specific and the path is specified outside
of the <>. By specifying the <submodgroup> as an order-only
input Tup will build the submodules before attempting to build the entire
project.
- {bin}
- Outputs can be grouped into a bin using the "{bin}" syntax. A
later rule can use "{bin}" as an input to use all of the files
in that bin. For example, the foreach rule will put each .o file in the
objs bin, which is used as an input in the linker rule:
: foreach *.c |> gcc -c %f -o %o |> %B.o {objs}
: {objs} |> gcc %f -o %o |> program
- In this case one could use *.o as the input instead, but sometimes it is
useful to separate outputs into groups even though they have the same
extension (such as if one directory creates multiple binaries, using *.o
wouldn't be correct). If a {bin} is specified in the output section of
multiple rules, the bin will be the union of all the outputs. You can't
remove things from a bin, and the bin disappears after the current Tupfile
is parsed.
- ^-flags
- In a command string that uses the ^ TEXT^ sequence, flag characters
can be placed immediately after the ^ until the first space character or
closing caret. For example:
: foo.c |> ^c CC %f^ gcc --coverage %f -o %o |> foo | foo.gcno
: bar.c |> ^c^ gcc --coverage %f -o %o |> bar | bar.gcno
In the foo.c case, the command requires namespaces (or suid) and will
display "CC foo.c". In the bar.c case, the command requires
namespaces (or suid) and the "gcc --coverage bar.c -o bar"
string is displayed. These are the supported flag characters:
- b
- The 'b' flag causes the command to be run via "/usr/bin/env bash -e
-o pipefail -c <command>" instead of the default "/bin/sh
-e -c <command>". In addition to allowing bash extensions in
the :-rule, "-o pipefail" dictates that "the return value
of a pipeline is the value of the last (rightmost) command to exit with a
non-zero status, or zero if all commands in the pipeline exit
successfully."
- c
- The 'c' flag causes the command to fail if tup does not support user
namespaces (on Linux) or is not suid root. In these cases, tup runs in a
degraded mode where the fake working directories are visible in the
sub-processes, and some dependencies may be missed. If these degraded
behaviors will break your a particular command in your build, add the 'c'
flag so that users know they need to add the suid bit or upgrade their
kernel. This flag is ignored on Windows.
- o
- The 'o' flag causes the command to compare the new outputs against the
outputs from the previous run. Any outputs that are the same will not
cause dependent commands in the DAG to be executed. For example, adding
this flag to a compilation command will skip the linking step if the
object file is the same from the last time it ran. The 'o' flag is
incompatible with the 't' flag.
- t
- The 't' flag causes the command's outputs to be transient. The outputs may
be used as inputs to other commands, but after all dependent commands are
executed, the transient outputs will be deleted from the filesystem. This
can be used to save space if there are many stages of processing that each
produce large outputs, but only the final output needs to be kept. The 't'
flag is incompatible with the 'o' flag.
An example where the 't' flag can make sense in a build
pipeline is if there are large assets that go through multiple stages of
processing. For example, a large audio or video file that has stages of
effects applied, each as a separate step in the Tupfile.
In contrast, the 't' flag does *not* make sense for object
files in a C program, even though those could theoretically be deleted
after the final executable is linked. If the object files were marked
transient in this case, a change to any of the input C files would
require *all* object files to be rebuilt in order to produce the
executable, instead of only the single file that was changed.
- %-flags
- Within a command string or output string, the following %-flags may also
be used to substitute values from the inputs or outputs.
- %%
- Expands to a single "%" character in the command string. This
should be used when you want the percent character to be interpreted by
the command itself rather than by tup's parser.
- %f
- The filename from the "inputs" section. This includes the path
and extension. This is most useful in a command, since it lists each input
file name with the path relative to the current directory. For example,
"src/foo.c" would be copied exactly as
"src/foo.c"
- %b
- Like %f, but is just the basename of the file. The directory part is
stripped off. For example, "src/foo.c" would become
"foo.c"
- %B
- Like %b, but strips the extension. This is most useful in converting an
input file into an output file of the same name but with a different
extension, since the output file needs to be in the same directory. For
example, "src/foo.c" would become "foo"
- %e
- The file extension of the current file when used in a foreach rule. This
can be used for variables that can have different values based on the
suffix of the file. For example, you could set certain flags for assembly
(.S) files that are different from .c files, and then use a construct like
$(CFLAGS_%e) to reference the CFLAGS_S or CFLAGS_c variable depending on
what type of file is being compiled. For example, "src/foo.c"
would become "c", while "src/foo.S" would become
"S"
- %o
- The name of the output file(s). It is useful in a command so that the
filename passed to a command will always match what tup thinks the output
is. This only works in the "command" section, not in the
"outputs" section.
- %O
- The name of the output file without the extension. This only works in the
extra-outputs section if there is exactly one output file specified. A
use-case for this is if you have a !-macro that generates files not
specified on the command line, but are based off of the output that is
named. For example, if a linker creates a map file by taking the specified
output "foo.so", removing the ".so" and adding
".map", then you may want a !-macro like so:
!ldmap = |> ld ... -o %o |> | %O.map
: foo1.o foo2.o |> !ldmap |> foo.so
- %d
- The name of the lowest level of the directory. For example, in
foo/bar/Tupfile, this would be the string "bar". One case where
this can be useful is in naming libraries based on the directory they are
in, such as with the following !-macro:
!ar = |> ar crs %o %f |> lib%d.a
Using this macro in foo/bar/Tupfile would then create foo/bar/libbar.a
- %g
- The string that a glob operator matched. For example with the files
a_text.txt and b_text.txt, the rule:
: foreach *_text.txt |> foo %f |> %g_binary.bin
will output the filenames a_binary.bin and b_binary.bin. Only the first glob
expanded will be substituted in for %g. %g is only valid when there is a
single input file or foreach is used.
- %<group>
- All of the files in "group". For example:
#./submodules/sm1/Tupfile
: foo.c |> gcc -c %f -o %o |> %B.o ../<submodgroup>
#./submodules/sm2/Tupfile
: bar.c |> gcc -c %f -o %o |> %B.o ../<submodgroup>
#./project/Tupfile
: ../submodules/<submodgroup> |> echo '%f' > %o |> submodules_f.txt
: ../submodules/<submodgroup> |> echo '%<submodgroup>' > %o |> submodules_group.txt
will produce "../submodules/<submodgroup>" in
submodules_f.txt, but "../submodules/sm1/foo.o
../submodules/sm2/bar.o" in submodules_group.txt. If the input
contains multiple groups with the same name but different directories,
%<group> will be expanded to all of the files in each listed
group.
- var = value
- var := value
- Set the $-variable "var" to the value on the right-hand side.
Both forms are the same, and are allowed to more easily support converting
old Makefiles. The $-variable "var" can later be referenced by
using "$(var)". Variables referenced here are always expanded
immediately. As such, setting a variable to have a %-flag does not make
sense, because a %-flag is only valid in a :-rule. The syntax $(var_%e) is
allowed in a :-rule. Variable references do not nest, so something like
$(var1_$(var2)) does not make sense. You also cannot pass variable
definitions in the command line or through the environment. Any reference
to a variable that has not had its value set returns an empty string.
CFLAGS = -Dfoo
: bar.c |> cc $(CFLAGS) $(other) -o %o -c %f |> %B.o
will generate the command "cc -Dfoo -o bar.o -c bar.c" when
run.
Any $-variable that begins with the string "CONFIG_" is
automatically converted to the @-variable of the same name minus the
"CONFIG_" prefix. In other words, $(CONFIG_FOO) and @(FOO) are
interchangeable. Attempting to assign a value to a CONFIG_ variable in a
Tupfile results in an error, since these can only be set in the tup.config
file.
Note that you may see a syntax using back-ticks when setting
variables, such as:
CFLAGS += `pkg-config fuse3 --cflags`
Tup does not do any special processing for back-ticks, so the pkg-config command
is not actually executed when the variable is set in this example. Instead,
this is passed verbatim to any place that uses it. Therefore if a command
later references $(CFLAGS), it will contain the string `pkg-config fuse3
--cflags`, so it will be parsed by the shell.
- var += value
- Append "value" to the end of the current value of
"var". If "var" has not been set, this is equivalent
to a regular '=' statement. If "var" already has a value, a
space is appended to the $-variable before the new value is appended.
- $(TUP_CWD)
- The special $-variable TUP_CWD is always set to the path relative to the
Tupfile currently parsed. It can change value when including a file in a
different directory. For example, if you "include ../foo.tup",
then TUP_CWD will be set to ".." when parsing foo.tup. This lets
foo.tup specify flags like "CFLAGS += -I$(TUP_CWD)", and CFLAGS
will always have the -I directory where foo.tup is located, no matter if
it was included as "../foo.tup" or "../../foo.tup" or
"subdir/foo.tup". For an alternative to $(TUP_CWD) when
referring to files, see the section on &-variables below.
No other special $-variables exist yet, but to be on the safe side
you should assume that all variables named TUP_* are reserved.
- &var = file
- &var := file
- &var += file
- p.PD 1 Set the &-variable to refer to the given file or directory. The
file must be a normal file, not a generated file (an output from a
:-rule). &-variables are used to refer to files in a similar way as
$(TUP_CWD), except that instead of storing the relative path to the file,
&-variables store tup's internal ID of the file. This means that the
relative path to the file is determined when the &-variable is used,
rather than when the variable is assigned as is the case with $(TUP_CWD).
&-variables can only be used in the following locations: :-rule
inputs, :-rule order-only inputs, :-rule commands, include lines, and
run-script lines, and they are later be referenced by using
"&(var)".
# Tuprules.tup
&libdir = src/lib
!cc = |> cc -I&(libdir) -c %f -o %o |> %B.o
# src/lib/Tupfile
: foreach *.c |> !cc |>
: *.o |> ar crs %o %f |> libstuff.a
# src/lib/test/Tupfile
: test_stuff.c |> !cc |>
: test_stuff.o &(libdir)/libstuff.a |> cc -o %o %f |> test_stuff
# src/Tupfile
: main.c |> !cc |> main.o
: main.o &(libdir)/libstuff.a |> cc -o %o %f |> main_app
will generate the following build.sh commands (via "tup generate
build.sh"):
cd src/lib
cc -I. -c lib1.c -o lib1.o
cc -I. -c lib2.c -o lib2.o
ar crs libstuff.a lib1.o lib2.o
cd test
cc -I.. -c test_stuff.c -o test_stuff.o
cc -o test_stuff test_stuff.o ../libstuff.a
cd ../..
cc -Ilib -c main.c -o main.o
cc -o main_app main.o lib/libstuff.a
- ifeq
(lval,rval)
- Evaluates the 'lval' and 'rval' parameters (ie: substitutes all
$-variables and @-variables), and does a string comparison to see if they
match. If so, all lines between the 'ifeq' and following 'endif' statement
are processed; otherwise, they are ignored. Note that no whitespace is
pruned for the values - all text between the '(' and ',' comprise 'lval',
and all text between the ',' and ')' comprise 'rval'. This means that ifeq
(foo, foo) is false, while ifeq (foo,foo) is true. This is for
compatibility with Makefile if statements.
ifeq (@(FOO),y)
CFLAGS += -DFOO
else
CFLAGS += -g
endif
- ifneq
(lval,rval)
- Same as 'ifeq', but with the logic inverted.
- ifdef
VARIABLE
- Tests of the @-variable named VARIABLE is defined at all in tup.config. If
so, all lines between the 'ifdef' and following 'endif' statement are
processed; otherwise, they are ignored. For example, suppose tup.config
contains:
CONFIG_FOO=n
Then 'ifdef FOO' will evaluate to true. If tup.config doesn't exist, or does
not set CONFIG_FOO in any way, then 'ifdef FOO' will be false.
- ifndef
VARIABLE
- Same as 'ifdef', but with the logic inverted.
- else
- Toggles the true/false-ness of the previous if-statement.
- endif
- Ends the previous ifeq/ifdef/ifndef. Note that only 8 levels of nesting
if-statements is supported.
- error
[message]
- Causes tup to stop parsing and fail, printing message to the user
as explanation.
- !macro = [inputs] | [order-only inputs] |> command |>
[outputs]
- Set the !-macro to the given command string. This syntax is very similar
to the :-rule, since a !-macro is basically a macro for those rules. The
!-macro is not expanded until it is used in the command string of a
:-rule. As such, the primary use of the !-macro is to have a place to
store command strings with %-flags that may be re-used. For example, we
could have a !cc macro in a top-level Tuprules.tup file like so:
!cc = |> ^ CC %f^ gcc -c %f -o %o |>
A Tupfile could then do as follows:
include_rules
: foreach *.c |> !cc |> %B.o
You will only want to specify the output parameter in either the !-macro or
the :-rule that uses it, but not both. If you specify any inputs in the
!-macro, they would usually be order-only inputs. For example, if you have
a !cc rule where you are using a compiler that has been generated by tup,
you can list the compiler file in the order-only list of the !-macro. The
compiler file will then become an input dependency for any :-rule that
uses the macro.
- include
file
- Reads the specified file and continues parsing almost as if that file was
pasted inline in the current Tupfile. Only regular files are allowed to be
included -- attempting to include a generated file is an error. Any
include statements that occur in the included file will be parsed relative
to the included file's directory.
- include_rules
- Reads in Tuprules.tup files up the directory chain. The first Tuprules.tup
file is read at the top of the tup hierarchy, followed by the next
subdirectory, and so on through to the Tuprules.tup file in the current
directory. In this way, the top-level Tuprules.tup file can specify
general variable settings, and subsequent subdirectories can override them
with more specific settings. You would generally specify include_rules as
the first line in the Tupfile. The name is a bit of a misnomer, since you
would typically use Tuprules.tup to define variables rather than
:-rules.
- run ./script
args
- Runs an external script with the given arguments to generate :-rules. This
is an advanced feature that can be used when the standard Tupfile syntax
is too simplistic for a complex program. The script is expected to write
the :-rules to stdout. No other Tupfile commands are allowed - for
example, the script cannot create $-variables or !-macros, but it can
output :-rules that use those features. As a simple example, consider if a
command must be executed 5 times, but there are no input files to use
tup's foreach keyword. An external script called 'build.sh' could be
written as follows:
#! /bin/sh -e
for i in `seq 1 5`; do
echo ": |> echo $i > %o |> $i.txt"
done
A Tupfile can then be used to get these rules:
run ./build.sh
Tup will then treat this as if a Tupfile was written with 5 lines like so:
: |> echo 1 > %o |> 1.txt
: |> echo 2 > %o |> 2.txt
: |> echo 3 > %o |> 3.txt
: |> echo 4 > %o |> 4.txt
: |> echo 5 > %o |> 5.txt
Since the Tupfile-parsing stage is watched for dependencies, any files that
this script accesses within the tup hierarchy will cause the Tupfile to be
re-parsed. There are some limitations, however. First, the readdir() call
is instrumented to return the list of files that would be accessible at
that time that the run-script starts executing. This means the files that
you see in 'ls' on the command-line may be different from the files that
your script sees when it is parsed. Tup essentially pretends that the
generated files don't exist until it parses a :-rule that lists it as an
output. Note that any :-rules executed by the run-script itself are not
parsed until the script executes successfully. Second, due to some
structural limitations in tup, the script cannot readdir() on any
directory other than the directory of the Tupfile. In other words, a
script can do 'for i in *.c', but not 'for i in sub/*.c'. The
'--debug-run' flag can be passed to 'tup' in order to show the list of
:-rules that tup receives from the script. Due to the readdir()
instrumentation, this may be different than the script's output when it is
run manually from the command-line.
- preload
directory
- By default, a run-script can only use a readdir() (ie: use a wild-card) on
the current directory. To specify a list of other allowable wild-card
directories, use the preload keyword. For example, if a run script needs
to look at *.c and src/*.c, the src directory needs to be preloaded:
preload src
run ./build.sh *.c src/*.c
- export
VARIABLE
- The export directive adds the environment variable VARIABLE to the export
list for future :-rules and run-scripts. The value for the variable comes
from tup's environment, not from the Tupfile itself. Generally this means
you will need to set the variable in your shell if you want to change the
value used by commands and scripts. By default only PATH is exported.
Windows additionally exports several variables suitable for building with
the Visual Studio compiler suite. Tup will check the exported environment
variables to see if they have changed values between updates, and
re-execute any commands that that use those environment variables. Note
that this means if PATH is changed, all commands will run again. For
example:
: |> command1 ... |>
export FOO
: |> command2 ... |>
Tup will save the current value of FOO and pass it to the
environment when executing command2. If FOO has a different value during
the next update, then command2 will execute again with the new value in
the environment. In this example, command1 will not have FOO in its
environment and will not re-execute when its value changes.
Note that the FOO above is passed to the environment; it is
not provided as an internal variable within tup. Thus, given the
following:
export FOO
: |> echo myFOO=$(FOO) envFOO=${FOO} > %o |> foo.txt
when run as "$ FOO=silly tup" would result in the contents of the
foo.txt file being "myFOO= envFOO=silly". If the "export
FOO" was removed from the Tupfile, the contents of the file would be
"myFOO= envFOO=" because tup does not propagate environment
variables unless they are explicitly exported. This helps preserve
repeatable and deterministic builds.
If you wish to export a variable to a specific value rather
than get the value from the environment, you can do that in your shell
instead of through tup. For example, in Linux you can do:
: |> FOO=value command ... |>
This usage will not create a dependency on the environment
variable FOO, since it is controlled through the Tupfile.
- .gitignore
- Tells tup to automatically generate a .gitignore file in the current
directory which contains a list of the output files that are generated by
tup. This can be useful if you are using git, since the set of files
generated by tup matches exactly the set of files that you want git to
ignore. If you are using Tuprules.tup files, you may just want to specify
.gitignore in the top-level Tuprules.tup, and then have every other
Tupfile use include_rules to pick up the .gitignore definition. In this
way you never have to maintain the .gitignore files manually. Note that
you may wish to ignore other files not created by tup, such as temporary
files created by your editor. In this case case you will want to setup a
global gitignore file using a command like 'git config --global
core.excludesfile ~/.gitignore', and then setup ~/.gitignore with your
personal list. For other cases, you can also simply add any custom ignore
rules above the "##### TUP GITIGNORE #####" line.
- #
- At the beginning of a line, a '#' character signifies a comment. A comment
line is ignored by the parser. The comment can have leading whitespaces
that is also ignored. If there is any non-whitespace before a '#'
character, then the line is not a comment. It also means that if a
previous line ended with '\' (line wrap) then '#' is interpreted as a
regular symbol.
Variable expansion in tup is immediate in every case except for
!-macros. That is, if you see a :-rule or variable declaration, you can
substitute the current values for the variables. The !-macros are only
parsed when they used in a :-rule. In that case, the actual :-rule is a sort
of a union between the :-rule as written and the current value of the
!-macro.
When tup parses a Tupfile, it makes a single pass through the
file, parsing a line at a time. At the end of the Tupfile, all variable,
!-macro, and {bin} definitions are discarded. The only lingering effects of
parsing a Tupfile are the command nodes and dependencies that now exist in
the tup database. Additionally, a .gitignore file may have been created if
requested by the Tupfile.
@-variables are special variables in tup. They are used as
configuration variables, and can be read by Tupfiles or used by the varsed
command. Commands are able to read them too, but the program executed by the
command has to have direct knowledge of the variables. @-variables are
specified in the tup.config file at the top of the tup hierarchy or in a
variant directory. For example, tup.config may contain:
CONFIG_FOO=y
A Tupfile may then read the @-variable like so:
srcs-@(FOO) += foo.c
srcs-y += bar.c
: foreach $(srcs-y) |> gcc -c %f -o %o |> %B.o
In this example, if CONFIG_FOO is set to 'y', then the foo.c file
will be included in the input list and therefore compiled. If CONFIG_FOO is
unspecified or set to some other value, foo.c will not be included.
The @-variables can be used similar to $-variables, with the
following distinctions: 1) @-variables are read-only in Tupfiles, and 2)
@-variables are in the DAG, which means reading from them creates a
dependency from the @-variable to the Tupfile. Therefore any Tupfile that
reads @(FOO) like the above example will be reparsed if the value of
CONFIG_FOO in tup.config changes.
The reason for prefixing with "CONFIG_" in the
tup.config file is to maintain compatibility with kconfig, which can be used
to generate this file.
Note that the syntax for tup.config is fairly strict. For a
statement like "CONFIG_FOO=y", tup will create an @-variable using
the string starting after "CONFIG_", and up to the '=' sign. The
value is everything immediately after the '=' sign until the newline, but if
there is a surrounding pair of quotes, they are stripped. In this example,
it would set "FOO" to "y". Note that if instead the line
were "CONFIG_FOO = y", then the variable "FOO " would be
set to " y".
In tup.config, comments are determined by a '#' character in the
first column. These are ignored, unless the comment is of the form:
# CONFIG_FOO is not set
In this case, the @-variable "FOO" is explicitly set to "n".
- @(TUP_PLATFORM)
- TUP_PLATFORM is a special @-variable. If CONFIG_TUP_PLATFORM is not set in
the tup.config file, it has a default value according to the platform that
tup itself was compiled in. Currently the default value is one of
"linux", "solaris", "macosx",
"win32", "freebsd" or "netbsd".
- @(TUP_ARCH)
- TUP_ARCH is another special @-variable. If CONFIG_TUP_ARCH is not set in
the tup.config file, it has a default value according to the processor
architecture that tup itself was compiled in. Currently the default value
is one of "i386", "x86_64", "powerpc",
"powerpc64", "ia64", "alpha",
"sparc", "arm64", or "arm".
Tup supports variants, which allow you to build your project
multiple times with different configurations. Perhaps the most common case
is to build a release and a debug configuration with different compiler
flags, though any number of variants can be used to support whatever
configurations you like. Each variant is built in its own directory distinct
from each other and from the source tree. When building with variants, the
in-tree build is disabled. To create a variant, make a new directory at the
top of the tup hierarchy and create a "tup.config" file there. For
example:
$ mkdir build-default
$ touch build-default/tup.config
$ tup
Here we created a directory called "build-default" and
made an empty tup.config inside. Note that the build directory must be at
the same level as the ".tup" directory. Upon updating, tup will
parse all of the Tupfiles using the configuration file we created, and place
all build products within subdirectories of build-default that mirror the
source tree. We could then create another variant like so:
$ mkdir build-debug
$ echo "CONFIG_MYPROJ_DEBUG=y" > build-debug/tup.config
$ tup
This time all Tupfiles will be parsed with @(MYPROJ_DEBUG) set to
"y", and all build products will be placed in the build-debug
directory. Note that setting @(MYPROJ_DEBUG) only has any effect if the
variable is actually used in a Tupfile (perhaps by adding debug flags to the
compiler command-line).
Running "tup" will update all variants. For example,
updating after modifying a C file that is used in all configurations will
cause it to be re-compiled for each variant. As with any command that is
executed, this is done in parallel subject to the constraints of the DAG and
the number of jobs specified. To build a single variant (or subset of
variants), specify the build directory as the target to "tup",
just like with any partial update. For example:
$ tup build-default
To delete a variant, just wipe out the build directory:
$ rm -rf build-debug
If you build with variants, it is recommended that you always have
a default variant that contains an empty tup.config file. This helps check
that your software is always able to be built by simply checking it out and
doing 'tup init; tup' without relying on a specific configuration.
When using in-tree builds, the resulting build outputs may rely on
run-time files, placed in the source tree and not being processed by tup.
Tup allows such files to be copied verbatim in the variant build directory
by providing a built-in macro "!tup_preserve":
:foreach *.png |> !tup_preserve |>
Either a symbolic link or a copy of the source file will be
created, depending on the OS and file system being used.
Parsing a :-rule may be a little confusing at first. You may find
it easy to think of the Tupfile as a shell script with additional
input/output annotations for the commands. As an example, consider this
Tupfile:
WARNINGS += -W
WARNINGS += -Wall
CFLAGS = $(WARNINGS) -O2
CFLAGS_foo.c = -DFOO
: |> echo '#define BAR 3' > %o |> foo.h
: foreach *.c | foo.h |> gcc -c %f -o %o $(CFLAGS) $(CFLAGS_%f) |> %B.o
: *.o |> gcc %f -o %o |> program
Tup begins parsing this Tupfile with an empty $-variable set. The
first "WARNINGS += -W" line will set the WARNINGS variable to
"-W". The second line will append, so WARNINGS will be set to
"-W -Wall". The third line references this value, so CFLAGS will
now equal "-W -Wall -O2". The fourth line sets a new variable,
called CFLAGS_foo.c, and set it to -DFOO". The first rule will create a
new node "foo.h" in the database, along with the corresponding
command to create it. Note this file won't exist in the filesystem until the
command is actually executed after all Tupfiles are parsed.
The foreach :-rule will generate a command to compile each file.
First tup will parse the input section, and use the glob operation on the
database since a '*' is present. This glob matches foo.c and bar.c. Since it
is a foreach rule, tup will run through the rule first using the input
"foo.c", and again using the input "bar.c". The output
pattern is parsed on each pass, followed by the command string.
On the foo.c pass, the output pattern "%B.o" is parsed,
which will equal "foo.o". Now the command string is parsed,
replacing "foo.c" for "%f" and "foo.o" for
"%o". The $-variables are then expanded, so $(CFLAGS) becomes
"-W -Wall -O2", and $(CFLAGS_foo.c)" becomes
"-DFOO". The final command string written to the database is
"gcc -c foo.c -o foo.o -W -Wall -O2 -DFOO". An output link is
written to the foo.o file, and input links are written from foo.c and foo.h
(the order-only input).
On the second pass through the foreach rule, the only difference
is "bar.c" is the input. Therefore the output pattern becomes
"bar.o", and the final command string becomes "gcc -c bar.c
-o bar.o -W -Wall -O2 " since $(CFLAGS_bar.c) was unspecified.
For more examples with corresponding DAGs, see
http://gittup.org/tup/examples.html
Tup is a little bit different from other build systems. It uses a
well-defined graph structure that is maintained in a separate database. A
set of algorithms to operate on this graph were developed in order to handle
cases such as modifying an existing file, creating or deleting files,
changing command lines, etc. These algorithms are very efficient - in
particular, for the case where a project is already built and one or more
existing files are modified, tup is optimal among file-based build systems.
For other cases, tup is at least very fast, but optimality has not been
proved.
The primary reason for the graph database is to allow the tup
update algorithm to easily access the information it needs. As a very useful
side-effect of the well-defined database structure, tup can determine when a
generated file is no longer needed. What this means is there is no clean
target. Nor is there a need to do a "fresh checkout" and build
your software from scratch. Any number of iterations of updates always
produces the same output as it would if everything was built anew. Should
you find otherwise, you've likely found a bug in tup (not your Tupfiles), in
which case you should notify the mailing list (see CONTACT).
For more information on the theory behind tup, see
http://gittup.org/tup/build_system_rules_and_algorithms.pdf
tup-users@googlegroups.com