A triple is set with --target or a target field in the toolchain block, and
everything derived from it follows: platform, arch and the conditionals built
on them come from the triple rather than uname, so a build file can branch on
the platform it is building for instead of the one it is running on.
Tools are taken from the triple prefix when a matching toolchain is installed
(x86_64-w64-mingw32-gcc, -ar, -ranlib) and otherwise the host compiler is
invoked with --target, which covers clang without a prefixed toolchain. An
explicit cc, cxx, ar or ranlib in the build file always wins over the derived
one. --sysroot adds --sysroot to both the compile and link lines.
Each triple gets its own build directory and probe cache under builddir, so a
host tree and a cross tree do not invalidate each other and neither reruns the
other's checks. Probes never execute what they compile, sizeof included, so the
configure stage needed no changes to work against a foreign target.
Executables and shared libraries now take the extension the target platform
uses. Without that the graph expected bin/app while mingw wrote bin/app.exe,
and the link step repeated on every build.
Verified against x86_64-w64-mingw32, which produces a PE32+ binary, and
aarch64-linux-gnu through clang, which produces AArch64 objects.
Ctrl-C killed meowc and left every compiler it had spawned running, still
holding CPU and still about to write into the build directory. There were no
signal handlers at all.
SIGINT and SIGTERM now cancel the same way a build failure does, and the run
returns cleanly so the cache is still written and the exit status is 130. A
second signal falls through to the default handler, so an unresponsive child
cannot trap the user.
Signalling a single pid was not enough: a compiler driver spawns its own
children, and those were reparented to init and survived. Each action is now
placed in its own process group with setsid, and cancellation signals the group,
which also makes the existing failure path reach grandchildren. Unix.wait is
retried on EINTR so a signal arriving mid-wait is not fatal.
Only new spawns were held back after a failure, so every action already running
was allowed to finish even though its output would be discarded. The scheduler
now sends SIGTERM to the remaining children on the first failure, and reports
them separately rather than counting a process it killed as a failure of its
own. Partial outputs are removed and their cache entries dropped, so the next
run starts clean.
Under -k the existing behaviour is kept, since keeping going is the point.
On a graph with three six-second generators alongside one translation unit that
fails immediately, -j4 now returns in 0.12 s rather than 6.03 s.
The default job limit read /proc/cpuinfo and silently fell back to four
anywhere that file is absent, so macOS and the BSDs ran at a fraction of the
available parallelism. Falls back to getconf _NPROCESSORS_ONLN before the
constant.
A header included by fourteen translation units was hashed once per dependent,
and every built action hashed its inputs twice: once to decide it was stale and
again to store the new key. Digests are now memoised for the run, and the
scheduler drops the entries for an action's outputs and depfile once it
finishes, so a freshly written file is never read from the memo.
Records on a throwaway Xvfb display at fixed geometry, drives the session with
xdotool, and quantises through a per-clip palette so the terminal's colours
survive instead of dithering.
Nine targets: two translation units generated from scene files, a C++
consumer, a shared object built from the same sources as the archives, and an
optional zlib dependency.
Checks each node's key at the moment it becomes ready rather than up front,
because an input may have been produced by a node that ran seconds earlier.
This is what gives early cutoff.
Digests every input plus the exact argument vector into one key, persisted
under the build directory. Staleness becomes a content question rather than a
timestamp comparison.
Indexes producers by output path, so a generator and the compile consuming its
output are connected without being declared. Detects duplicate producers and
reports dependency cycles by path.
Expands variables top to bottom, runs checks as they are reached and evaluates
conditionals against results already established. Written order is the
semantics, not an implementation detail.