<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Dag on Aayush Bajaj's Augmenting Infrastructure</title><link>https://abaj.ai/tags/dag/</link><description>Recent content in Dag on Aayush Bajaj's Augmenting Infrastructure</description><generator>Hugo</generator><language>en</language><copyright>© 2026 Aayush Bajaj</copyright><lastBuildDate>Fri, 10 Jul 2026 08:20:16 +1000</lastBuildDate><atom:link href="https://abaj.ai/tags/dag/index.xml" rel="self" type="application/rss+xml"/><item><title>Build Systems</title><link>https://abaj.ai/wiki/se/implementation/build-systems/</link><pubDate>Thu, 09 Jul 2026 21:02:56 +1000</pubDate><guid>https://abaj.ai/wiki/se/implementation/build-systems/</guid><description>&lt;p>every build system — make, ninja, bazel, cargo, even npm scripts pretending otherwise — is the same machine: a directed acyclic graph of files and commands, plus a policy for deciding which part of the graph is stale. everything else is syntax.&lt;/p>
&lt;h2 id="the-model-a-dag-of-targets">the model: a dag of targets&lt;a href="#the-model-a-dag-of-targets" class="post-heading__anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>a &lt;strong>target&lt;/strong> is a file the build can produce; a &lt;strong>rule&lt;/strong> says how (a command) and from what (its &lt;strong>dependencies&lt;/strong>).&lt;/li>
&lt;li>dependencies point from outputs to inputs; because outputs of one rule are inputs to another, the whole thing is a dag — a cycle would mean &amp;ldquo;to build a you must first build a&amp;rdquo;.&lt;/li>
&lt;li>a build is then two steps:
&lt;ol>
&lt;li>&lt;strong>mark dirty&lt;/strong>: a target is dirty if it is missing, if any dependency is dirty, or if the staleness policy (timestamps or hashes, below) says an input changed. dirtiness propagates along edges — one flipped source poisons its whole downstream cone.&lt;/li>
&lt;li>&lt;strong>evaluate in topological order&lt;/strong>: run each dirty target&amp;rsquo;s command after all its dependencies are up to date (Cormen, Thomas H. and Leiserson, Charles E. and Rivest, Ronald L. and Stein, Clifford, 2009). independent dirty targets can run in parallel (&lt;code>-j8&lt;/code>) — the dag &lt;em>is&lt;/em> the parallelism plan, which is why builds are embarrassingly parallel until the link step serialises everything.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>the entire correctness contract: &lt;strong>the graph must be complete&lt;/strong>. every undeclared dependency is a future &amp;ldquo;works after &lt;code>make clean&lt;/code>&amp;rdquo; bug — the build system faithfully skips rebuilding things it was never told could change.&lt;/li>
&lt;/ul>
&lt;figure class="tikz-figure lateximage">
 &lt;script type="text/tikz"
 >
 
\usepackage{xcolor}
\usetikzlibrary{positioning,calc,arrows.meta}
\begin{document}
\begin{tikzpicture}[font=\small, >={Stealth[length=4pt]},
 src/.style={draw, rounded corners=1pt, fill=blue!12, minimum width=1.7cm, minimum height=0.65cm, font=\ttfamily\scriptsize},
 ok/.style={draw, rounded corners=1pt, fill=green!15, minimum width=1.7cm, minimum height=0.65cm, font=\ttfamily\scriptsize},
 bad/.style={draw, thick, rounded corners=1pt, fill=red!15, minimum width=1.7cm, minimum height=0.65cm, font=\ttfamily\scriptsize}]
\node[src] (mainc) at (0,0) {main.c};
\node[bad] (greeth) at (0,-1.4) {greet.h *};
\node[src] (greetc) at (0,-2.8) {greet.c};
\node[bad] (maino) at (3.6,-0.7) {main.o};
\node[bad] (greeto) at (3.6,-2.1) {greet.o};
\node[bad] (app) at (7.0,-1.4) {app};
\draw[->] (mainc) -- (maino);
\draw[->, red!70!black, thick] (greeth) -- (maino);
\draw[->, red!70!black, thick] (greeth) -- (greeto);
\draw[->] (greetc) -- (greeto);
\draw[->, red!70!black, thick] (maino) -- (app);
\draw[->, red!70!black, thick] (greeto) -- (app);
\node[font=\scriptsize, gray, align=left] at (3.6,-3.4) {* edited: dirtiness flows with the arrows};
\node[font=\scriptsize] at (0,0.75) {sources};
\node[font=\scriptsize] at (3.6,0.75) {objects};
\node[font=\scriptsize] at (7.0,0.75) {binary};
\end{tikzpicture}
\end{document}

 &lt;/script>
 &lt;figcaption>dirty-node propagation: editing greet.h dirties every target downstream of it (red); main.c and its untouched cone stay cached. the build re-runs exactly the red commands, in topological order.&lt;/figcaption>
&lt;/figure>

&lt;h2 id="make-the-actual-semantics">make: the actual semantics&lt;a href="#make-the-actual-semantics" class="post-heading__anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;p>make&amp;rsquo;s whole rebuild rule fits in one sentence: &lt;strong>a target is rebuilt if it does not exist, or if any prerequisite&amp;rsquo;s mtime is newer than the target&amp;rsquo;s mtime.&lt;/strong> everything else is macro expansion.&lt;/p></description></item></channel></rss>