Orphan Targets
tmake maintains a cache of all targets that have previously been built.
This allows tmake to "know" when rules change such that a previous target
is no longer a target, and thus the old file can be removed. By removing
previous targets, tmake ensures that these files do not interfere with
the new build.
Consider the build.spec:
$ cat build.spec Executable prog main.c a.c b.c $ tmake Cc a.o Cc b.o Cc main.o Link prog Built 4 of 4 target(s) in 0.25 seconds
Now assume that b.c is no longer required:
$ cat build.spec Executable prog main.c a.c $ tmake Clean removing 1 orphan target(s) Link prog Built 1 of 3 target(s) in 0.12 seconds
Note that the orphan target b.o is deleted as it an no longer
be generated by any rule. And now change the name of the program.
$ cat build.spec Executable newprog main.c a.c $ tmake Clean removing 1 orphan target(s) Link newprog Built 1 of 3 target(s) in 0.09 seconds
Now prog is deleted and newprog is created in it's place.
rulebase.default orphan handling
By default, the tmake core will simply delete orphan targets. However it is possible that an accidental rule change could cause files to be deleted unintentionally. For example, if a generated file is replaced with a source file and the source is misidentified as an orphan.
To address this situation rulebase.default
overrides delete-orphan-files to instead move orphans to .trash/.
The deleted orphan can be manually reinstated from .trash/, until tmake clean is run,
at which point all files from .trash/ are deleted.
From rulebase.default:
# This callback is invoked to delete orphans
# This version replaces the builtin version.
# Instead of deleting files immediately, orphans are moved into
# the .trash directory. This directory is only removed via the
# 'clean', 'distclean' or 'clean-orphans' targets.
proc delete-orphan-files {args} {
# Can't create .trash if it doesn't exist and we are root
file-mkdir -rooterr .trash
foreach file $args {
if {[file-type $file] in {file link}} {
set trashfile .trash/[string map {/ _} $file]
# Can't simple use file rename -force in case the files are hard links
file delete $trashfile
file rename $file $trashfile
}
}
}
An example of the importance of removing orphans
Consider the situation where a header file is being generated and used.
$ cat build.spec Generate test.h {} {} { writefile $target {static const char TEST[] = __FILE__;} } PublishIncludes test.h Executable --test tester test.c $ cat test.c #include <stdio.h> #include <test.h> int main(void) { printf("TEST is %s\n", TEST); return 0; } $ tmake test Generate test.h Publish publish/include/test.h Cc test.o Link tester Test objdir/tester TEST is objdir/publish/include/test.h Built 4 of 4 target(s) in 0.41 seconds
Now imagine that we decide that test.h is no longer to be generated but
will be a source file.
$ echo "static const char TEST[] = __FILE__;" >test.h $ cat build.spec Executable --test tester test.c $ tmake -v -v test Clean removing 2 orphan target(s) Cc test.o gcc -Iobjdir/publish/include -I. -Iobjdir -c test.c -o objdir/test.o Link tester gcc -o objdir/tester objdir/test.o Test objdir/tester objdir/tester >@stdout TEST is ./test.h Built 2 of 2 target(s) in 0.39 seconds
Note that because -Iobjdir/publish/include comes before -I., if test.h had not been
removed, the compiler would have used the old, generated test.h instead -- which would
would have led to unintended consequences. By removing files build outputs that are no longer
targets, tmake ensures that this situation cannot occur.
This situation is particularly likely to occur when using ifconfig as targets are modified
dynamically without any changes to the build description. If instead we have:
$ cat build.spec
ifconfig GENTEST {
Generate test.h {} {} {
writefile $target {static const char TEST[] = __FILE__;}
}
PublishIncludes test.h
}
Executable --test tester test.c
Then we can dynamically choose where test.h comes from and tmake will ensure that
a leftover generated file will not compromise the integrity of the build.
$ tmake GENTEST=1 test Generate test.h Publish publish/include/test.h Cc test.o Link tester Test objdir/tester TEST is ./test.h Built 4 of 4 target(s) in 0.16 seconds $ tmake test Clean removing 2 orphan target(s) Cc test.o Link tester Test objdir/tester TEST is ./test.h Built 2 of 2 target(s) in 0.15 seconds
The results of the search are