1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-26 04:00:43 +03:00

Redrafted most of Chapter 3 of inbuild

This commit is contained in:
Graham Nelson 2020-03-30 00:30:20 +01:00
parent e76d02da6e
commit 123b9c166e
20 changed files with 957 additions and 430 deletions

View file

@ -1,6 +1,6 @@
# Inform 7
v10.1.0-alpha.1+6Q30 'Krypton' (29 March 2020)
v10.1.0-alpha.1+6Q31 'Krypton' (30 March 2020)
## About Inform 7

View file

@ -1,3 +1,3 @@
Prerelease: alpha.1
Build Date: 29 March 2020
Build Number: 6Q30
Build Date: 30 March 2020
Build Number: 6Q31

View file

@ -91,7 +91,7 @@ stored here.
<p class="inwebparagraph"></p>
<p class="endnote">The structure inbuild_copy is accessed in 1/ic, 2/nst, 3/bg, 3/bs2, 3/is, 3/is2, 3/is3, 3/is4, 4/km, 4/em, 4/lm, 4/pbm, 4/pfm, 4/tm, 4/pm, 5/kts, 5/es, 5/ed, 5/ed2, 5/ec, 5/ps, 5/ls, 6/hdn, 6/inc and here.</p>
<p class="endnote">The structure inbuild_copy is accessed in 1/ic, 2/nst, 3/bg, 3/ib, 3/bs2, 3/is, 3/is2, 3/is3, 3/is4, 4/km, 4/em, 4/lm, 4/pbm, 4/pfm, 4/tm, 4/pm, 5/kts, 5/es, 5/ed, 5/ed2, 5/ec, 5/ps, 5/ls, 6/hdn, 6/inc and here.</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>Copies are created by the managers for the respective genres, usually when
claiming. If you are a manager, do not call this...
@ -196,7 +196,7 @@ for later reporting. These are stored in a list.
<p class="inwebparagraph"></p>
<p class="endnote">The function Copies::write_copy is used in 3/bg (<a href="3-bg.html#SP1">&#167;1</a>).</p>
<p class="endnote">The function Copies::write_copy is used in 3/bg (<a href="3-bg.html#SP5">&#167;5</a>, <a href="3-bg.html#SP6">&#167;6</a>, <a href="3-bg.html#SP8_1">&#167;8.1</a>).</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Reading source text. </b></p>
@ -279,12 +279,12 @@ its main task: building an Inform project.
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Copies::build</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">inbuild_copy</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">BM</span><span class="plain">) {</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain"> = </span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;vertex</span><span class="plain">;</span>
<span class="identifier">VMETHOD_CALL</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;genre</span><span class="plain">, </span><span class="constant">GENRE_BUILDING_SOON_MTID</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">, &amp;</span><span class="identifier">V</span><span class="plain">);</span>
<span class="functiontext">Graphs::build</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="functiontext">IncrementalBuild::build</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Copies::rebuild</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">inbuild_copy</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">BM</span><span class="plain">) {</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain"> = </span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;vertex</span><span class="plain">;</span>
<span class="identifier">VMETHOD_CALL</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;genre</span><span class="plain">, </span><span class="constant">GENRE_BUILDING_SOON_MTID</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">, &amp;</span><span class="identifier">V</span><span class="plain">);</span>
<span class="functiontext">Graphs::rebuild</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="functiontext">IncrementalBuild::rebuild</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
@ -365,7 +365,7 @@ its main task: building an Inform project.
<p class="inwebparagraph"></p>
<p class="endnote">The function Copies::copy_to is used in 3/bg (<a href="3-bg.html#SP1">&#167;1</a>).</p>
<p class="endnote">The function Copies::copy_to is used in 3/bg (<a href="3-bg.html#SP8_1">&#167;8.1</a>).</p>
<p class="endnote">The function Copies::overwrite_error is used in 4/km (<a href="4-km.html#SP6">&#167;6</a>), 4/em (<a href="4-em.html#SP8">&#167;8</a>), 4/lm (<a href="4-lm.html#SP7">&#167;7</a>), 4/tm (<a href="4-tm.html#SP6">&#167;6</a>), 4/pm (<a href="4-pm.html#SP7">&#167;7</a>).</p>

View file

@ -121,7 +121,7 @@ nest depends only on its genre.
<p class="inwebparagraph"></p>
<p class="endnote">The function Genres::stored_in_nests is used in 3/bg (<a href="3-bg.html#SP1">&#167;1</a>).</p>
<p class="endnote">The function Genres::stored_in_nests is used in 3/bg (<a href="3-bg.html#SP8">&#167;8</a>).</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>The requirements parser needs to identify genres by name, so:
</p>

View file

@ -282,7 +282,7 @@ empty text is legal here, and produces an unlimited requirement.
<p class="inwebparagraph"></p>
<p class="endnote">The function Requirements::write is used in 3/bg (<a href="3-bg.html#SP1">&#167;1</a>).</p>
<p class="endnote">The function Requirements::write is used in 3/bg (<a href="3-bg.html#SP5">&#167;5</a>).</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Meeting requirements. </b>Finally, we actually use these intricacies for something. Given an edition,
we return <code class="display"><span class="extract">TRUE</span></code> if it meets the requirements and <code class="display"><span class="extract">FALSE</span></code> if it does not.

View file

@ -225,7 +225,7 @@ begins at the start of the text, after a hyphen, or after a bracket. Thus
<p class="inwebparagraph"></p>
<p class="endnote">The function Works::write is used in 2/edt (<a href="2-edt.html#SP1">&#167;1</a>), 3/bg (<a href="3-bg.html#SP1">&#167;1</a>).</p>
<p class="endnote">The function Works::write is used in 2/edt (<a href="2-edt.html#SP1">&#167;1</a>), 3/bg (<a href="3-bg.html#SP6">&#167;6</a>, <a href="3-bg.html#SP7">&#167;7</a>).</p>
<p class="endnote">The function Works::write_to_HTML_file is used in <a href="#SP6">&#167;6</a>, 5/ed (<a href="5-ed.html#SP19_2">&#167;19.2</a>), 5/ed2 (<a href="5-ed2.html#SP3_2_1">&#167;3.2.1</a>).</p>

View file

@ -57,45 +57,69 @@
<main role="main">
<!--Weave of '3/bg' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../compiler.html">Compiler Modules</a></li><li><a href="index.html">inbuild</a></li><li><a href="index.html#3">Chapter 3: Incremental Builds</a></li><li><b>Build Graphs</b></li></ul><p class="purpose">Graphs in which vertices correspond to files or copies, and arrows to dependencies between them.</p>
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../compiler.html">Compiler Modules</a></li><li><a href="index.html">inbuild</a></li><li><a href="index.html#3">Chapter 3: Incremental Builds</a></li><li><b>Build Graphs</b></li></ul><p class="purpose">Graphs in which vertices correspond to files or copies, and edges to dependencies between them.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Build graphs</a></li></ul><hr class="tocbar">
<ul class="toc"><li><a href="#SP1">&#167;1. Build graphs</a></li><li><a href="#SP2">&#167;2. Creation</a></li><li><a href="#SP5">&#167;5. Writing</a></li><li><a href="#SP8">&#167;8. Archiving</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Build graphs. </b>These are directed acyclic graphs which show what depends on what in the
building process. If an arrow leads from A to B, then B must be built before
A can be built.
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Build graphs. </b>See the Inbuild manual for an introduction to the build graph. Properly
speaking, it is a directed acyclic multigraph which us usually disconnected.
</p>
<p class="inwebparagraph">There can be two sorts of vertex in such a graph: copy vertices, each of which
belongs to a single copy, and internal vertices, each of which represents
a different file inside the copy.
<p class="inwebparagraph">There are two colours of edge: build edges and use edges. A build edge between
A and B means that B must exist and be up-to-date before A can be built.
A use edge between A and B means that B must exist and be up-to-date before
A can be used.
</p>
<p class="inwebparagraph">There are three colours of vertex: copy, file and requirement. Copy vertices
correspond to copies which the user does have; requirement vertices to copies
which she doesn't have; and file vertices to unmanaged plain files in
the build process. For example, if an Inform project says it wants to include
an extension which isn't anywhere to be seen, then the project itself is a
copy vertex, as are the Standard Rules extension, the CommandParserKit kit,
and such; the missing extension is represneted by a requirement vertex; and
the story file which the project would compile to, if only it could be
compiled, is a file vertex.
</p>
<pre class="definitions">
<span class="definitionkeyword">enum</span> <span class="constant">COPY_VERTEX</span><span class="definitionkeyword"> from </span><span class="constant">1</span>
<span class="definitionkeyword">enum</span> <span class="constant">REQUIREMENT_VERTEX</span>
<span class="definitionkeyword">enum</span> <span class="constant">FILE_VERTEX</span>
<span class="definitionkeyword">enum</span> <span class="constant">GHOST_VERTEX</span>
<span class="definitionkeyword">enum</span> <span class="constant">REQUIREMENT_VERTEX</span>
</pre>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">build_vertex</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">type</span><span class="plain">; </span> <span class="comment">one of the <code class="display"><span class="extract">*_VERTEX</span></code> values above</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">linked_list</span><span class="plain"> *</span><span class="identifier">build_edges</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">build_vertex</span></code></span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">linked_list</span><span class="plain"> *</span><span class="identifier">use_edges</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">build_vertex</span></code></span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">inbuild_copy</span><span class="plain"> *</span><span class="identifier">buildable_if_copy</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">filename</span><span class="plain"> *</span><span class="identifier">buildable_if_internal_file</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">inbuild_requirement</span><span class="plain"> *</span><span class="identifier">findable</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">annotation</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">source_file</span><span class="plain"> *</span><span class="identifier">read_as</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">linked_list</span><span class="plain"> *</span><span class="identifier">build_edges</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">build_vertex</span></code></span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">linked_list</span><span class="plain"> *</span><span class="identifier">use_edges</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">build_vertex</span></code></span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">last_described_in_generation</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">build_result</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">last_built_in_generation</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">always_build_this</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">build_script</span><span class="plain"> *</span><span class="identifier">script</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">last_described</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">built</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">force_this</span><span class="plain">;</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">build_vertex</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure build_vertex is accessed in 3/ib, 3/bs2, 3/is, 3/is3, 3/is4, 4/em, 5/ed, 5/ps, 6/inc and here.</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. Creation. </b>First, the three colours of vertex.
</p>
<pre class="display">
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="functiontext">Graphs::file_vertex</span><span class="plain">(</span><span class="identifier">filename</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">) {</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain">);</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain"> = </span><span class="constant">FILE_VERTEX</span><span class="plain">;</span>
@ -106,9 +130,10 @@ a different file inside the copy.
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;script</span><span class="plain"> = </span><span class="functiontext">BuildScripts::new</span><span class="plain">();</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;annotation</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;read_as</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_described</span><span class="plain"> = 0;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;built</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;force_this</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_described_in_generation</span><span class="plain"> = 0;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_result</span><span class="plain"> = </span><span class="identifier">NOT_APPLICABLE</span><span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_built_in_generation</span><span class="plain"> = -1;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;always_build_this</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">;</span>
<span class="plain">}</span>
@ -129,14 +154,22 @@ a different file inside the copy.
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain"> = </span><span class="identifier">R</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="functiontext">Graphs::ghost_vertex</span><span class="plain">(</span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">) {</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain"> = </span><span class="functiontext">Graphs::file_vertex</span><span class="plain">(</span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain"> = </span><span class="constant">GHOST_VERTEX</span><span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;annotation</span><span class="plain"> = </span><span class="identifier">Str::duplicate</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">;</span>
<span class="plain">}</span>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::file_vertex is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 5/ps (<a href="5-ps.html#SP1">&#167;1</a>, <a href="5-ps.html#SP3">&#167;3</a>).</p>
<p class="endnote">The function Graphs::copy_vertex is used in 4/km (<a href="4-km.html#SP7">&#167;7</a>), 4/em (<a href="4-em.html#SP9">&#167;9</a>), 4/lm (<a href="4-lm.html#SP8">&#167;8</a>), 4/pbm (<a href="4-pbm.html#SP7">&#167;7</a>), 4/pfm (<a href="4-pfm.html#SP7">&#167;7</a>), 4/tm (<a href="4-tm.html#SP7">&#167;7</a>), 4/pm (<a href="4-pm.html#SP8">&#167;8</a>).</p>
<p class="endnote">The function Graphs::req_vertex is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 6/inc (<a href="6-inc.html#SP6_1">&#167;6.1</a>).</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>Next, the two colours of edge. Note that between A and B there can be
at most one edge of each colour.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::need_this_to_build</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">from</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">to</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"no from"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"no to"</span><span class="plain">);</span>
@ -144,8 +177,6 @@ a different file inside the copy.
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain"> == </span><span class="identifier">to</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="comment">Graphs::describe(STDOUT, from, FALSE); PRINT(" needs ");</span>
<span class="comment">Graphs::describe(STDOUT, to, FALSE); PRINT("\n");</span>
<span class="identifier">ADD_TO_LINKED_LIST</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">);</span>
<span class="plain">}</span>
@ -158,25 +189,52 @@ a different file inside the copy.
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain"> == </span><span class="identifier">to</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="identifier">ADD_TO_LINKED_LIST</span><span class="plain">(</span><span class="identifier">to</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">-</span><span class="element">&gt;use_edges</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">description_round</span><span class="plain"> = 1;</span>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::need_this_to_build is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 5/ps (<a href="5-ps.html#SP3">&#167;3</a>), 6/inc (<a href="6-inc.html#SP1_1">&#167;1.1</a>, <a href="6-inc.html#SP6_1">&#167;6.1</a>).</p>
<p class="endnote">The function Graphs::need_this_to_use is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 5/ps (<a href="5-ps.html#SP3">&#167;3</a>), 6/inc (<a href="6-inc.html#SP1_1">&#167;1.1</a>).</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>The script attached to a vertex is a list of instructions for how to build
the resource it refers to. Some vertices have no instructions provided, so:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Graphs::can_be_built</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">BuildScripts::script_length</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;script</span><span class="plain">) &gt; 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::can_be_built is used in 3/ib (<a href="3-ib.html#SP7_1">&#167;7.1</a>).</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Writing. </b>This is a suitably indented printout of the graph as seen from a given
vertex: it's used by the Inbuild command <code class="display"><span class="extract">-graph</span></code>.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">no_desc_generations</span><span class="plain"> = 1;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::describe</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">recurse</span><span class="plain">) {</span>
<span class="functiontext">Graphs::describe_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 0, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">recurse</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="constant">NOT_A_GB</span><span class="plain">, </span><span class="identifier">description_round</span><span class="plain">++);</span>
<span class="functiontext">Graphs::describe_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 0, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">recurse</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NOT_APPLICABLE</span><span class="plain">, </span><span class="identifier">no_desc_generations</span><span class="plain">++);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::describe_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">,</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">recurse</span><span class="plain">, </span><span class="identifier">pathname</span><span class="plain"> *</span><span class="identifier">stem</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">which</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">description_round</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">recurse</span><span class="plain">, </span><span class="identifier">pathname</span><span class="plain"> *</span><span class="identifier">stem</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">following_build_edge</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">description_round</span><span class="plain">) {</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">depth</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" "</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">which</span><span class="plain"> == </span><span class="constant">BUILD_GB</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"--build-&gt; "</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">which</span><span class="plain"> == </span><span class="constant">USE_GB</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"--use---&gt; "</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">following_build_edge</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"--build-&gt; "</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">following_build_edge</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"--use---&gt; "</span><span class="plain">);</span>
<span class="functiontext">Graphs::describe_vertex</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" "</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_described</span><span class="plain"> == </span><span class="identifier">description_round</span><span class="plain">) { </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"q.v.\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">; }</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">);</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">COPY_VERTEX</span><span class="plain">: </span><span class="functiontext">Copies::write_copy</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_copy</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">REQUIREMENT_VERTEX</span><span class="plain">: </span><span class="functiontext">Requirements::write</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">FILE_VERTEX</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%f"</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_internal_file</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">GHOST_VERTEX</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"(%S)"</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;annotation</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="string">"%p"</span><span class="plain">, </span><span class="identifier">stem</span><span class="plain">);</span>
@ -187,6 +245,8 @@ a different file inside the copy.
<span class="plain">}</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_described_in_generation</span><span class="plain"> == </span><span class="identifier">description_round</span><span class="plain">) { </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" q.v.\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">; }</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_described_in_generation</span><span class="plain"> = </span><span class="identifier">description_round</span><span class="plain">;</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">recurse</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_copy</span><span class="plain">) </span><span class="identifier">stem</span><span class="plain"> = </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_copy</span><span class="plain">-</span><span class="element">&gt;location_if_path</span><span class="plain">;</span>
@ -194,9 +254,9 @@ a different file inside the copy.
<span class="identifier">stem</span><span class="plain"> = </span><span class="identifier">Filenames::get_path_to</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_internal_file</span><span class="plain">);</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">)</span>
<span class="functiontext">Graphs::describe_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">stem</span><span class="plain">, </span><span class="constant">BUILD_GB</span><span class="plain">, </span><span class="identifier">description_round</span><span class="plain">);</span>
<span class="functiontext">Graphs::describe_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">stem</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">description_round</span><span class="plain">);</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;use_edges</span><span class="plain">)</span>
<span class="functiontext">Graphs::describe_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">stem</span><span class="plain">, </span><span class="constant">USE_GB</span><span class="plain">, </span><span class="identifier">description_round</span><span class="plain">);</span>
<span class="functiontext">Graphs::describe_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">stem</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">description_round</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
@ -206,15 +266,29 @@ a different file inside the copy.
<span class="reserved">case</span><span class="plain"> </span><span class="constant">COPY_VERTEX</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"[c%d]"</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-&gt;</span><span class="identifier">allocation_id</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">REQUIREMENT_VERTEX</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"[r%d]"</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-&gt;</span><span class="identifier">allocation_id</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">FILE_VERTEX</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"[f%d]"</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-&gt;</span><span class="identifier">allocation_id</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">GHOST_VERTEX</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"[g%d]"</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-&gt;</span><span class="identifier">allocation_id</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::describe is used in 2/cps (<a href="2-cps.html#SP11">&#167;11</a>), 3/ib (<a href="3-ib.html#SP7">&#167;7</a>, <a href="3-ib.html#SP7_1_3">&#167;7.1.3</a>).</p>
<p class="endnote">The function Graphs::describe_r appears nowhere else.</p>
<p class="endnote">The function Graphs::describe_vertex appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>A similar but slightly different recursion for <code class="display"><span class="extract">-build-needs</span></code> and <code class="display"><span class="extract">-use-needs</span></code>.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::show_needs</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">uses_only</span><span class="plain">) {</span>
<span class="functiontext">Graphs::show_needs_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, 0, 0, </span><span class="identifier">uses_only</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::show_needs_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">true_depth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">uses_only</span><span class="plain">) {</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::show_needs_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">,</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">true_depth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">uses_only</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain"> == </span><span class="constant">COPY_VERTEX</span><span class="plain">) {</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">depth</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" "</span><span class="plain">);</span>
<span class="reserved">inbuild_copy</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain"> = </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_copy</span><span class="plain">;</span>
@ -227,7 +301,8 @@ a different file inside the copy.
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"missing %S: "</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;genre</span><span class="plain">-</span><span class="element">&gt;genre_name</span><span class="plain">);</span>
<span class="functiontext">Works::write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VersionNumberRanges::is_any_range</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;version_range</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", need version in range "</span><span class="plain">); </span><span class="identifier">VersionNumberRanges::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;version_range</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", need version in range "</span><span class="plain">);</span>
<span class="identifier">VersionNumberRanges::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;version_range</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", any version will do"</span><span class="plain">);</span>
<span class="plain">}</span>
@ -243,18 +318,32 @@ a different file inside the copy.
<span class="functiontext">Graphs::show_needs_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">, </span><span class="identifier">true_depth</span><span class="plain">+1, </span><span class="identifier">uses_only</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::show_needs is used in 2/cps (<a href="2-cps.html#SP11">&#167;11</a>).</p>
<p class="endnote">The function Graphs::show_needs_r appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>And for <code class="display"><span class="extract">-build-missing</span></code> and <code class="display"><span class="extract">-use-missing</span></code>.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Graphs::show_missing</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">uses_only</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Graphs::show_missing_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, 0, </span><span class="identifier">uses_only</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Graphs::show_missing_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">true_depth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">uses_only</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Graphs::show_missing_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">,</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">true_depth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">uses_only</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N</span><span class="plain"> = 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain"> == </span><span class="constant">REQUIREMENT_VERTEX</span><span class="plain">) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"missing %S: "</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;genre</span><span class="plain">-</span><span class="element">&gt;genre_name</span><span class="plain">);</span>
<span class="functiontext">Works::write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VersionNumberRanges::is_any_range</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;version_range</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", need version in range "</span><span class="plain">); </span><span class="identifier">VersionNumberRanges::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;version_range</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", need version in range "</span><span class="plain">);</span>
<span class="identifier">VersionNumberRanges::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;findable</span><span class="plain">-</span><span class="element">&gt;version_range</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", any version will do"</span><span class="plain">);</span>
<span class="plain">}</span>
@ -271,35 +360,37 @@ a different file inside the copy.
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">N</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::archive</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">inbuild_nest</span><span class="plain"> *</span><span class="identifier">N</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">BM</span><span class="plain">) {</span>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::show_missing is used in 2/cps (<a href="2-cps.html#SP11">&#167;11</a>, <a href="2-cps.html#SP12">&#167;12</a>).</p>
<p class="endnote">The function Graphs::show_missing_r appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. Archiving. </b>This isn't simply a matter of printing out, of course, but very similar code
handles <code class="display"><span class="extract">-archive</span></code> and <code class="display"><span class="extract">-archive-to N</span></code>.
</p>
<p class="inwebparagraph">Note that the English language definition, which lives in the internal nest,
cannot be read from any other nest &mdash; so we won't archive it.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::archive</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">inbuild_nest</span><span class="plain"> *</span><span class="identifier">N</span><span class="plain">,</span>
<span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">BM</span><span class="plain">) {</span>
<span class="functiontext">Graphs::archive_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, 0, </span><span class="identifier">N</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::archive_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">true_depth</span><span class="plain">, </span><span class="reserved">inbuild_nest</span><span class="plain"> *</span><span class="identifier">N</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">BM</span><span class="plain">) {</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Graphs::archive_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">true_depth</span><span class="plain">, </span><span class="reserved">inbuild_nest</span><span class="plain"> *</span><span class="identifier">N</span><span class="plain">,</span>
<span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">BM</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain"> == </span><span class="constant">COPY_VERTEX</span><span class="plain">) {</span>
<span class="reserved">inbuild_copy</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain"> = </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_copy</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Genres::stored_in_nests</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;genre</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">((</span><span class="identifier">Str::ne</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;title</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"English"</span><span class="plain">)) ||</span>
<span class="plain">(</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;author_name</span><span class="plain">) &gt; 0))) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%S: "</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;genre</span><span class="plain">-</span><span class="element">&gt;genre_name</span><span class="plain">);</span>
<span class="functiontext">Copies::write_copy</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">);</span>
<span class="identifier">pathname</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;location_if_path</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;location_if_file</span><span class="plain">) </span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">Filenames::get_path_to</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;location_if_file</span><span class="plain">);</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">);</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">, </span><span class="string">"%p/"</span><span class="plain">, </span><span class="identifier">N</span><span class="plain">-</span><span class="element">&gt;location</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">, </span><span class="string">"%p/"</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::prefix_eq</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">, </span><span class="identifier">nl</span><span class="plain">, </span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">))) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" -- already there\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" -- archiving\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="functiontext">Copies::copy_to</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="identifier">N</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">(</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;author_name</span><span class="plain">) &gt; 0)))</span>
&lt;<span class="cwebmacro">Archive a single copy</span> <span class="cwebmacronumber">8.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">)</span>
@ -309,187 +400,47 @@ a different file inside the copy.
<span class="functiontext">Graphs::archive_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">true_depth</span><span class="plain">+1, </span><span class="identifier">N</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">Graphs::timestamp_for</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain"> = (</span><span class="identifier">time_t</span><span class="plain">) 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_internal_file</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> </span><span class="identifier">transcoded_pathname</span><span class="plain">[4*</span><span class="identifier">MAX_FILENAME_LENGTH</span><span class="plain">];</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">FN</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">FN</span><span class="plain">, </span><span class="string">"%f"</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_internal_file</span><span class="plain">);</span>
<span class="identifier">Str::copy_to_locale_string</span><span class="plain">(</span><span class="identifier">transcoded_pathname</span><span class="plain">, </span><span class="identifier">FN</span><span class="plain">, 4*</span><span class="identifier">MAX_FILENAME_LENGTH</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">FN</span><span class="plain">);</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">stat</span><span class="plain"> </span><span class="identifier">filestat</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">stat</span><span class="plain">(</span><span class="identifier">transcoded_pathname</span><span class="plain">, &amp;</span><span class="identifier">filestat</span><span class="plain">) != -1) </span><span class="identifier">latest</span><span class="plain"> = </span><span class="identifier">filestat</span><span class="plain">.</span><span class="identifier">st_mtime</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">latest</span><span class="plain"> = </span><span class="functiontext">Graphs::time_of_most_recent_ingredient</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">Graphs::time_of_most_recent_ingredient</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain"> = (</span><span class="identifier">time_t</span><span class="plain">) 0;</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">inner</span><span class="plain"> = </span><span class="functiontext">Graphs::timestamp_for</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">latest</span><span class="plain"> == (</span><span class="identifier">time_t</span><span class="plain">) 0) || (</span><span class="identifier">difftime</span><span class="plain">(</span><span class="identifier">inner</span><span class="plain">, </span><span class="identifier">latest</span><span class="plain">) &gt; 0))</span>
<span class="identifier">latest</span><span class="plain"> = </span><span class="identifier">inner</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">Graphs::time_of_most_recent_used_resource</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain"> = (</span><span class="identifier">time_t</span><span class="plain">) 0;</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;use_edges</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">inner</span><span class="plain"> = </span><span class="functiontext">Graphs::timestamp_for</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">latest</span><span class="plain"> == (</span><span class="identifier">time_t</span><span class="plain">) 0) || (</span><span class="identifier">difftime</span><span class="plain">(</span><span class="identifier">inner</span><span class="plain">, </span><span class="identifier">latest</span><span class="plain">) &gt; 0))</span>
<span class="identifier">latest</span><span class="plain"> = </span><span class="identifier">inner</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::file_vertex is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 5/ps (<a href="5-ps.html#SP1">&#167;1</a>, <a href="5-ps.html#SP3">&#167;3</a>).</p>
<p class="endnote">The function Graphs::copy_vertex is used in 4/km (<a href="4-km.html#SP7">&#167;7</a>), 4/em (<a href="4-em.html#SP9">&#167;9</a>), 4/lm (<a href="4-lm.html#SP8">&#167;8</a>), 4/pbm (<a href="4-pbm.html#SP7">&#167;7</a>), 4/pfm (<a href="4-pfm.html#SP7">&#167;7</a>), 4/tm (<a href="4-tm.html#SP7">&#167;7</a>), 4/pm (<a href="4-pm.html#SP8">&#167;8</a>).</p>
<p class="endnote">The function Graphs::req_vertex is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 6/inc (<a href="6-inc.html#SP6_1">&#167;6.1</a>).</p>
<p class="endnote">The function Graphs::ghost_vertex is used in 5/ps (<a href="5-ps.html#SP3">&#167;3</a>).</p>
<p class="endnote">The function Graphs::need_this_to_build is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 5/ps (<a href="5-ps.html#SP3">&#167;3</a>), 6/inc (<a href="6-inc.html#SP1_1">&#167;1.1</a>, <a href="6-inc.html#SP6_1">&#167;6.1</a>).</p>
<p class="endnote">The function Graphs::need_this_to_use is used in 5/kts (<a href="5-kts.html#SP2">&#167;2</a>), 5/ps (<a href="5-ps.html#SP3">&#167;3</a>), 6/inc (<a href="6-inc.html#SP1_1">&#167;1.1</a>).</p>
<p class="endnote">The function Graphs::describe is used in <a href="#SP2">&#167;2</a>, 2/cps (<a href="2-cps.html#SP11">&#167;11</a>).</p>
<p class="endnote">The function Graphs::describe_r appears nowhere else.</p>
<p class="endnote">The function Graphs::describe_vertex appears nowhere else.</p>
<p class="endnote">The function Graphs::show_needs is used in 2/cps (<a href="2-cps.html#SP11">&#167;11</a>).</p>
<p class="endnote">The function Graphs::show_needs_r appears nowhere else.</p>
<p class="endnote">The function Graphs::show_missing is used in 2/cps (<a href="2-cps.html#SP11">&#167;11</a>, <a href="2-cps.html#SP12">&#167;12</a>).</p>
<p class="endnote">The function Graphs::show_missing_r appears nowhere else.</p>
<p class="endnote">The function Graphs::archive is used in 2/cps (<a href="2-cps.html#SP12">&#167;12</a>).</p>
<p class="endnote">The function Graphs::archive_r appears nowhere else.</p>
<p class="endnote">The function Graphs::timestamp_for is used in <a href="#SP2_1">&#167;2.1</a>.</p>
<p class="endnote">The function Graphs::time_of_most_recent_ingredient is used in <a href="#SP2_1">&#167;2.1</a>.</p>
<p class="endnote">The function Graphs::time_of_most_recent_used_resource is used in <a href="#SP2_1">&#167;2.1</a>.</p>
<p class="endnote">The structure build_vertex is accessed in 3/bs2, 3/is, 3/is3, 3/is4, 4/em, 5/ed, 5/ps, 6/inc and here.</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b></p>
<p class="inwebparagraph"><a id="SP8_1"></a><b>&#167;8.1. </b>The most delicate thing here is that we don't want to archive something
to <code class="display"><span class="extract">N</span></code> if it's already there; but that is difficult to detect.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">NOT_A_GB</span><span class="plain"> 0</span>
<span class="definitionkeyword">define</span> <span class="constant">BUILD_GB</span><span class="plain"> 1</span>
<span class="definitionkeyword">define</span> <span class="constant">FORCE_GB</span><span class="plain"> 2</span>
<span class="definitionkeyword">define</span> <span class="constant">USE_GB</span><span class="plain"> 4</span>
</pre>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Graphs::build</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">meth</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">changes</span><span class="plain"> = 0;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Graphs::build_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="constant">BUILD_GB</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">, &amp;</span><span class="identifier">changes</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Graphs::rebuild</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">meth</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">changes</span><span class="plain"> = 0;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Graphs::build_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="constant">BUILD_GB</span><span class="plain"> + </span><span class="constant">FORCE_GB</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">, &amp;</span><span class="identifier">changes</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">trace_ibg</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Graphs::build_r</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">gb</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">meth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> *</span><span class="identifier">changes</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="string">"Visit: "</span><span class="plain">); </span><span class="functiontext">Graphs::describe</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;built</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">changes_so_far</span><span class="plain"> = *</span><span class="identifier">changes</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">STREAM_INDENT</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">); }</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain">)</span>
<span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">Graphs::build_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">gb</span><span class="plain"> | </span><span class="constant">USE_GB</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">, </span><span class="identifier">changes</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">USE_GB</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;use_edges</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain">)</span>
<span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">Graphs::build_r</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">gb</span><span class="plain"> &amp; (</span><span class="constant">BUILD_GB</span><span class="plain"> + </span><span class="constant">FORCE_GB</span><span class="plain">), </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">, </span><span class="identifier">changes</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">STREAM_OUTDENT</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">FORCE_GB</span><span class="plain">) || (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;force_this</span><span class="plain">)) </span><span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain"> == </span><span class="constant">GHOST_VERTEX</span><span class="plain">) &amp;&amp; (*</span><span class="identifier">changes</span><span class="plain"> &gt; </span><span class="identifier">changes_so_far</span><span class="plain">)) </span><span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span>&lt;<span class="cwebmacro">Decide based on timestamps</span> <span class="cwebmacronumber">2.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">needs_building</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">BuildScripts::script_length</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;script</span><span class="plain">) &gt; 0)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="string">"Build: "</span><span class="plain">); </span><span class="functiontext">Graphs::describe</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">); }</span>
<span class="plain">(*</span><span class="identifier">changes</span><span class="plain">)++;</span>
<span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">BuildScripts::execute</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;script</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="string">"No Build\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); }</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;built</span><span class="plain"> = </span><span class="identifier">rv</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Graphs::build is used in 2/cps (<a href="2-cps.html#SP10">&#167;10</a>).</p>
<p class="endnote">The function Graphs::rebuild is used in 2/cps (<a href="2-cps.html#SP10">&#167;10</a>).</p>
<p class="endnote">The function Graphs::build_r appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP2_1"></a><b>&#167;2.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Decide based on timestamps</span> <span class="cwebmacronumber">2.1</span>&gt; =
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Archive a single copy</span> <span class="cwebmacronumber">8.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">last_built_at</span><span class="plain"> = </span><span class="functiontext">Graphs::timestamp_for</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="string">"Last built at: %08x\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">last_built_at</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">last_built_at</span><span class="plain"> == (</span><span class="identifier">time_t</span><span class="plain">) 0)</span>
<span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">time_of_most_recent</span><span class="plain"> = </span><span class="functiontext">Graphs::time_of_most_recent_ingredient</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">time_of_most_recent</span><span class="plain"> != (</span><span class="identifier">time_t</span><span class="plain">) 0) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="string">"Most recent: %08x\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">time_of_most_recent</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">difftime</span><span class="plain">(</span><span class="identifier">time_of_most_recent</span><span class="plain">, </span><span class="identifier">last_built_at</span><span class="plain">) &gt; 0)</span>
<span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">USE_GB</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">time_of_most_recent_used</span><span class="plain"> = </span><span class="functiontext">Graphs::time_of_most_recent_used_resource</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">time_of_most_recent_used</span><span class="plain"> != (</span><span class="identifier">time_t</span><span class="plain">) 0) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">STDOUT</span><span class="plain">, </span><span class="string">"Most recent use: %08x\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">time_of_most_recent_used</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">difftime</span><span class="plain">(</span><span class="identifier">time_of_most_recent_used</span><span class="plain">, </span><span class="identifier">last_built_at</span><span class="plain">) &gt; 0)</span>
<span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%S: "</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;edition</span><span class="plain">-</span><span class="element">&gt;work</span><span class="plain">-</span><span class="element">&gt;genre</span><span class="plain">-</span><span class="element">&gt;genre_name</span><span class="plain">);</span>
<span class="functiontext">Copies::write_copy</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">);</span>
<span class="identifier">pathname</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;location_if_path</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;location_if_file</span><span class="plain">) </span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">Filenames::get_path_to</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">-</span><span class="element">&gt;location_if_file</span><span class="plain">);</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">);</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">, </span><span class="string">"%p/"</span><span class="plain">, </span><span class="identifier">N</span><span class="plain">-</span><span class="element">&gt;location</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">, </span><span class="string">"%p/"</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::prefix_eq</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">, </span><span class="identifier">nl</span><span class="plain">, </span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">))) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" -- already there\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" -- archiving\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="functiontext">Copies::copy_to</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="identifier">N</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">BM</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">nl</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">cl</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP2">&#167;2</a>.</p>
<p class="endnote">This code is used in <a href="#SP8">&#167;8</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><i>(This section begins Chapter 3: Incremental Builds.)</i></li><li><a href="3-bm.html">Continue with 'Build Methodology'</a></li></ul><hr class="tocbar">

View file

@ -122,7 +122,7 @@
<p class="endnote">The structure build_methodology is accessed in 3/bs2, 3/is, 3/is2, 3/is3, 3/is4, 4/km, 4/em, 4/lm, 4/tm, 4/pm and here.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="3-bg.html">Back to 'Build Graphs'</a></li><li><a href="3-bs.html">Continue with 'Build Scripts'</a></li></ul><hr class="tocbar">
<ul class="toc"><li><a href="3-bg.html">Back to 'Build Graphs'</a></li><li><a href="3-ib.html">Continue with 'Incremental Building'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>

View file

@ -1,7 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>3/bm</title>
<title>3/ib</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
@ -104,20 +104,20 @@
<p class="inwebparagraph"></p>
<p class="endnote">The function BuildScripts::new is used in 3/bg (<a href="3-bg.html#SP1">&#167;1</a>).</p>
<p class="endnote">The function BuildScripts::new is used in 3/bg (<a href="3-bg.html#SP2">&#167;2</a>).</p>
<p class="endnote">The function BuildScripts::script_length is used in 3/bg (<a href="3-bg.html#SP2">&#167;2</a>).</p>
<p class="endnote">The function BuildScripts::script_length is used in 3/bg (<a href="3-bg.html#SP4">&#167;4</a>).</p>
<p class="endnote">The function BuildScripts::add_step is used in 3/bs2 (<a href="3-bs2.html#SP4">&#167;4</a>).</p>
<p class="endnote">The function BuildScripts::concatenate appears nowhere else.</p>
<p class="endnote">The function BuildScripts::execute is used in 3/bg (<a href="3-bg.html#SP2">&#167;2</a>).</p>
<p class="endnote">The function BuildScripts::execute is used in 3/ib (<a href="3-ib.html#SP7_1_3">&#167;7.1.3</a>).</p>
<p class="endnote">The structure build_script is private to this section.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="3-bm.html">Back to 'Build Methodology'</a></li><li><a href="3-bs2.html">Continue with 'Build Steps'</a></li></ul><hr class="tocbar">
<ul class="toc"><li><a href="3-ib.html">Back to 'Incremental Building'</a></li><li><a href="3-bs2.html">Continue with 'Build Steps'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>

View file

@ -0,0 +1,413 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>3/bm</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<nav role="navigation">
<h1><a href="../webs.html">Sources</a></h1>
<ul>
<li><a href="../compiler.html"><b>compiler tools</b></a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul>
<h2>Compiler Webs</h2>
<ul>
<li><a href="../inbuild/index.html">inbuild</a></li>
<li><a href="../inform7/index.html">inform7</a></li>
<li><a href="../inter/index.html">inter</a></li>
</ul>
<h2>Inbuild Modules</h2>
<ul>
<li><a href="../inbuild-module/index.html">inbuild</a></li>
<li><a href="../arch-module/index.html">arch</a></li>
<li><a href="../words-module/index.html">words</a></li>
<li><a href="../syntax-module/index.html">syntax</a></li>
<li><a href="../html-module/index.html">html</a></li>
</ul>
<h2>Inform7 Modules</h2>
<ul>
<li><a href="../core-module/index.html">core</a></li>
<li><a href="../problems-module/index.html">problems</a></li>
<li><a href="../inflections-module/index.html">inflections</a></li>
<li><a href="../linguistics-module/index.html">linguistics</a></li>
<li><a href="../kinds-module/index.html">kinds</a></li>
<li><a href="../if-module/index.html">if</a></li>
<li><a href="../multimedia-module/index.html">multimedia</a></li>
<li><a href="../index-module/index.html">index</a></li>
</ul>
<h2>Inter Modules</h2>
<ul>
<li><a href="../inter-module/index.html">inter</a></li>
<li><a href="../building-module/index.html">building</a></li>
<li><a href="../codegen-module/index.html">codegen</a></li>
</ul>
<h2>Foundation</h2>
<ul>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of '3/ib' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../compiler.html">Compiler Modules</a></li><li><a href="index.html">inbuild</a></li><li><a href="index.html#3">Chapter 3: Incremental Builds</a></li><li><b>Incremental Building</b></li></ul><p class="purpose">Deciding what is the least possible amount which needs to be built, in what order, to arrive at a working version of a copy.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Timestamps</a></li><li><a href="#SP5">&#167;5. Build process</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Timestamps. </b>We want to assign a timestamp to every vertex in the graph, whose meaning is
that what it represents has been up-to-date since that time.
</p>
<p class="inwebparagraph">For a file vertex, we take that from the file system's timestamp. For a
copy vertex, we do the same for a copy which is a single file (such as an
extension), but for a copy which is a directory containing a composite of
resources, there's no good way to know. (Perhaps we could scan the files
in it recursively, but then we have to worry about hidden files, symlinks,
and all of that.) Instead, we use the build graph itself to decide; for
example, the timestamp for a kit is the most recent timestamp of any of its
binary Inter files, because those are its build-dependencies.
</p>
<pre class="display">
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::timestamp</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">) {</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;type</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">FILE_VERTEX</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">Filenames::timestamp</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_internal_file</span><span class="plain">);</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">COPY_VERTEX</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_copy</span><span class="plain">-</span><span class="element">&gt;location_if_file</span><span class="plain">)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">Filenames::timestamp</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;buildable_if_copy</span><span class="plain">-</span><span class="element">&gt;location_if_file</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::time_of_latest_build_dependency</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="reserved">default</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">Platform::never_time</span><span class="plain">();</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function IncrementalBuild::timestamp is used in <a href="#SP3">&#167;3</a>, <a href="#SP4">&#167;4</a>, <a href="#SP7_1_3_1">&#167;7.1.3.1</a>.</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>The following compares two times: it returns 1 if <code class="display"><span class="extract">t1</span></code> is later, -1 if
<code class="display"><span class="extract">t2</span></code> is later, and 0 if they are identical.
</p>
<p class="inwebparagraph">Note that we never apply the C standard library function <code class="display"><span class="extract">difftime</span></code> in
the case of the never-time, which we consider to be before all other times.
(On most platforms it will be the C epoch of 1970, and <code class="display"><span class="extract">difftime</span></code> alone
would be fine, but we're being careful.)
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::timecmp</span><span class="plain">(</span><span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">t1</span><span class="plain">, </span><span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">t2</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">t1</span><span class="plain"> == </span><span class="identifier">Platform::never_time</span><span class="plain">()) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">t2</span><span class="plain"> == </span><span class="identifier">Platform::never_time</span><span class="plain">()) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">return</span><span class="plain"> -1;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">t2</span><span class="plain"> == </span><span class="identifier">Platform::never_time</span><span class="plain">()) {</span>
<span class="reserved">return</span><span class="plain"> 1;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">t1</span><span class="plain"> == </span><span class="identifier">t2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">difftime</span><span class="plain">(</span><span class="identifier">t1</span><span class="plain">, </span><span class="identifier">t2</span><span class="plain">) &gt; 0) </span><span class="reserved">return</span><span class="plain"> 1;</span>
<span class="reserved">return</span><span class="plain"> -1;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function IncrementalBuild::timecmp is used in <a href="#SP3">&#167;3</a>, <a href="#SP4">&#167;4</a>, <a href="#SP7_1_3_1">&#167;7.1.3.1</a>.</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>We then take the latest timestamp of any build dependency:
</p>
<pre class="display">
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::time_of_latest_build_dependency</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain"> = </span><span class="identifier">Platform::never_time</span><span class="plain">();</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">t</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::timestamp</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">IncrementalBuild::timecmp</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">, </span><span class="identifier">latest</span><span class="plain">) &gt; 0) </span><span class="identifier">latest</span><span class="plain"> = </span><span class="identifier">t</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function IncrementalBuild::time_of_latest_build_dependency is used in <a href="#SP1">&#167;1</a>, <a href="#SP7_1_3_1">&#167;7.1.3.1</a>.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>And of any use dependency:
</p>
<pre class="display">
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::time_of_latest_use_dependency</span><span class="plain">(</span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain"> = </span><span class="identifier">Platform::never_time</span><span class="plain">();</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;use_edges</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">t</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::timestamp</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">IncrementalBuild::timecmp</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">, </span><span class="identifier">latest</span><span class="plain">) &gt; 0) </span><span class="identifier">latest</span><span class="plain"> = </span><span class="identifier">t</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">latest</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function IncrementalBuild::time_of_latest_use_dependency is used in <a href="#SP7_1_3_1">&#167;7.1.3.1</a>.</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Build process. </b>This is a recursive process, beginning at the node representing what we want
to build. As we recurse, we pass a bitmap of the following:
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">BUILD_DEPENDENCIES_MATTER_GB</span><span class="plain"> 1 </span> <span class="comment">We will need all your build dependencies too</span>
<span class="definitionkeyword">define</span> <span class="constant">USE_DEPENDENCIES_MATTER_GB</span><span class="plain"> 2 </span> <span class="comment">We will need all your use dependencies too</span>
<span class="definitionkeyword">define</span> <span class="constant">IGNORE_TIMESTAMPS_GB</span><span class="plain"> 4 </span> <span class="comment">Don't be incremental: trust nothing, rebuild everything</span>
</pre>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::build</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">meth</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::begin_recursion</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">,</span>
<span class="constant">BUILD_DEPENDENCIES_MATTER_GB</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::rebuild</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">meth</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::begin_recursion</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">,</span>
<span class="constant">BUILD_DEPENDENCIES_MATTER_GB</span><span class="plain"> + </span><span class="constant">IGNORE_TIMESTAMPS_GB</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function IncrementalBuild::build is used in 2/cps (<a href="2-cps.html#SP10">&#167;10</a>).</p>
<p class="endnote">The function IncrementalBuild::rebuild is used in 2/cps (<a href="2-cps.html#SP10">&#167;10</a>).</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>This is called when Inbuild's <code class="display"><span class="extract">-trace</span></code> switch is set at the command line.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">trace_ibg</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::enable_trace</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">trace_ibg</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function IncrementalBuild::enable_trace appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>We want to be very sure that this recursion does not lock up, or perform
unnecessary work by performing the same node twice. To do this we apply the
<code class="display"><span class="extract">built</span></code> flag to a node when it has been built; but to make this is not left
over from last time around, we only regard it when the <code class="display"><span class="extract">last_built_in_generation</span></code> count
for the node is set to the current "generation", a unique number incremented
for each time we recurse.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">no_build_generations</span><span class="plain"> = 0;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::begin_recursion</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">gb</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">,</span>
<span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">meth</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">changes</span><span class="plain"> = 0;</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">trace</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace_ibg</span><span class="plain">) </span><span class="identifier">trace</span><span class="plain"> = </span><span class="identifier">STDOUT</span><span class="plain">;</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"Incremental build %d:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">no_build_generations</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::recurse</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">trace</span><span class="plain">, </span><span class="identifier">gb</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">, &amp;</span><span class="identifier">changes</span><span class="plain">, </span><span class="identifier">no_build_generations</span><span class="plain">++);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"%d change(s)\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">changes</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">IncrementalBuild::recurse</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">trace</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">gb</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain">,</span>
<span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">meth</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> *</span><span class="identifier">changes</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">generation</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) {</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"Visit %c%c%c: "</span><span class="plain">,</span>
<span class="plain">(</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">BUILD_DEPENDENCIES_MATTER_GB</span><span class="plain">)?</span><span class="character">'b'</span><span class="plain">:</span><span class="character">'.'</span><span class="plain">,</span>
<span class="plain">(</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">USE_DEPENDENCIES_MATTER_GB</span><span class="plain">)?</span><span class="character">'u'</span><span class="plain">:</span><span class="character">'.'</span><span class="plain">,</span>
<span class="plain">(</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">IGNORE_TIMESTAMPS_GB</span><span class="plain">)?</span><span class="character">'i'</span><span class="plain">:</span><span class="character">'.'</span><span class="plain">);</span>
<span class="functiontext">Graphs::describe</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_built_in_generation</span><span class="plain"> == </span><span class="identifier">generation</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_result</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Build this node if necessary, setting rv to its success or failure</span> <span class="cwebmacronumber">7.1</span>&gt;<span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_result</span><span class="plain"> = </span><span class="identifier">rv</span><span class="plain">;</span>
<span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;last_built_in_generation</span><span class="plain"> = </span><span class="identifier">generation</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function IncrementalBuild::begin_recursion is used in <a href="#SP5">&#167;5</a>.</p>
<p class="endnote">The function IncrementalBuild::recurse is used in <a href="#SP7_1_1">&#167;7.1.1</a>, <a href="#SP7_1_2">&#167;7.1.2</a>.</p>
<p class="inwebparagraph"><a id="SP7_1"></a><b>&#167;7.1. </b>In everything which follows, <code class="display"><span class="extract">rv</span></code> (prosaically, this stands only for "return
value") remains <code class="display"><span class="extract">TRUE</span></code> until the first active step fails, at which point no
other active steps are ever taken, nor are any recursions made. In effect,
the first failure halts the process.
</p>
<p class="inwebparagraph">We are recursing depth-first, that is, we build the things needed to build
<code class="display"><span class="extract">V</span></code> before we build <code class="display"><span class="extract">V</span></code> itself.
</p>
<p class="inwebparagraph">A point of difference between this algorithm and <code class="display"><span class="extract">make</span></code> is that we do not
halt with an error if a node has no way to be built. This is because the
graphs are here are built by Inbuild itself, not by a possibly erroneous
makefile whose author has forgotten something and whose intentions are not
clear. Here, if a node has no build script attached, it must be because it
needs no action taken.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Build this node if necessary, setting rv to its success or failure</span> <span class="cwebmacronumber">7.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) </span><span class="identifier">STREAM_INDENT</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">BUILD_DEPENDENCIES_MATTER_GB</span><span class="plain">) </span>&lt;<span class="cwebmacro">Build the build dependencies of the node</span> <span class="cwebmacronumber">7.1.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">USE_DEPENDENCIES_MATTER_GB</span><span class="plain">) </span>&lt;<span class="cwebmacro">Build the use dependencies of the node</span> <span class="cwebmacronumber">7.1.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) </span><span class="identifier">STREAM_OUTDENT</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">rv</span><span class="plain">) &amp;&amp; (</span><span class="functiontext">Graphs::can_be_built</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">))) </span>&lt;<span class="cwebmacro">Build the node itself, if necessary</span> <span class="cwebmacronumber">7.1.3</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP7_1_1"></a><b>&#167;7.1.1. </b>Suppose V needs W (for whatever reason), and that W can only be used with X.
It follows that we will have to build X as well as W, since the process of
building V is itself a use of W, and therefore of X. So we always enable the
<code class="display"><span class="extract">USE_DEPENDENCIES_MATTER_GB</span></code> bit when recursing through an edge.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Build the build dependencies of the node</span> <span class="cwebmacronumber">7.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;build_edges</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain">)</span>
<span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::recurse</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">trace</span><span class="plain">,</span>
<span class="identifier">gb</span><span class="plain"> | </span><span class="constant">USE_DEPENDENCIES_MATTER_GB</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">, </span><span class="identifier">changes</span><span class="plain">, </span><span class="identifier">generation</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7_1">&#167;7.1</a>.</p>
<p class="inwebparagraph"><a id="SP7_1_2"></a><b>&#167;7.1.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Build the use dependencies of the node</span> <span class="cwebmacronumber">7.1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">build_vertex</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;use_edges</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain">)</span>
<span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::recurse</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">trace</span><span class="plain">,</span>
<span class="identifier">gb</span><span class="plain"> | </span><span class="constant">USE_DEPENDENCIES_MATTER_GB</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">, </span><span class="identifier">changes</span><span class="plain">, </span><span class="identifier">generation</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7_1">&#167;7.1</a>.</p>
<p class="inwebparagraph"><a id="SP7_1_3"></a><b>&#167;7.1.3. </b>Now for the node <code class="display"><span class="extract">V</span></code> itself.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Build the node itself, if necessary</span> <span class="cwebmacronumber">7.1.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">IGNORE_TIMESTAMPS_GB</span><span class="plain">) || (</span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;always_build_this</span><span class="plain">)) </span><span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span>&lt;<span class="cwebmacro">Decide based on timestamps</span> <span class="cwebmacronumber">7.1.3.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">needs_building</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"Build: "</span><span class="plain">); </span><span class="functiontext">Graphs::describe</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">); }</span>
<span class="plain">(*</span><span class="identifier">changes</span><span class="plain">)++;</span>
<span class="identifier">rv</span><span class="plain"> = </span><span class="functiontext">BuildScripts::execute</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">-</span><span class="element">&gt;script</span><span class="plain">, </span><span class="identifier">meth</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"No build\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); }</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7_1">&#167;7.1</a>.</p>
<p class="inwebparagraph"><a id="SP7_1_3_1"></a><b>&#167;7.1.3.1. </b>This is where the incremental promise is finally kept. If the timestamp of
<code class="display"><span class="extract">V</span></code> is definitely before later than that of everything it depends on, then
it would be redundant to recreate it.
</p>
<p class="inwebparagraph">Note that equal timestamps force rebuilding. File timestamping is quite coarse
on some systems, so equal timeatamps might only mean that the two files were
created during the same second.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Decide based on timestamps</span> <span class="cwebmacronumber">7.1.3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">last_up_to_date_at</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::timestamp</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">last_up_to_date_at</span><span class="plain"> == </span><span class="identifier">Platform::never_time</span><span class="plain">())</span>
<span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"Last built at: %08x\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">last_up_to_date_at</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">BUILD_DEPENDENCIES_MATTER_GB</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">t</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::time_of_latest_build_dependency</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"Most recent build dependency: %08x\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">t</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">IncrementalBuild::timecmp</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">, </span><span class="identifier">last_up_to_date_at</span><span class="plain">) &gt;= 0)</span>
<span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">gb</span><span class="plain"> &amp; </span><span class="constant">USE_DEPENDENCIES_MATTER_GB</span><span class="plain">) {</span>
<span class="identifier">time_t</span><span class="plain"> </span><span class="identifier">t</span><span class="plain"> = </span><span class="functiontext">IncrementalBuild::time_of_latest_use_dependency</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">trace</span><span class="plain">) { </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">trace</span><span class="plain">, </span><span class="string">"Most recent use dependency: %08x\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">t</span><span class="plain">); }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">IncrementalBuild::timecmp</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">, </span><span class="identifier">last_up_to_date_at</span><span class="plain">) &gt;= 0)</span>
<span class="identifier">needs_building</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7_1_3">&#167;7.1.3</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="3-bm.html">Back to 'Build Methodology'</a></li><li><a href="3-bs.html">Continue with 'Build Scripts'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>
</html>

View file

@ -92,7 +92,7 @@ in the dictionary after each successful use of that extension.
<p class="inwebparagraph"></p>
<p class="endnote">The structure extension_dictionary_entry is accessed in 3/bg and here.</p>
<p class="endnote">The structure extension_dictionary_entry is accessed in 3/bg, 3/ib and here.</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>Clashes occur if, say, two extensions define "chopper" as a kind
of vehicle (for instance, meaning a helicopter in one and a motorcycle

View file

@ -389,7 +389,6 @@ may be multiple sentences, which we need to count up.
<span class="identifier">pathname</span><span class="plain"> *</span><span class="identifier">build_folder</span><span class="plain"> = </span><span class="functiontext">Projects::build_pathname</span><span class="plain">(</span><span class="identifier">project</span><span class="plain">);</span>
<span class="identifier">filename</span><span class="plain"> *</span><span class="identifier">inf_F</span><span class="plain"> = </span><span class="identifier">Filenames::in_folder</span><span class="plain">(</span><span class="identifier">build_folder</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"auto.inf"</span><span class="plain">);</span>
<span class="comment">build_vertex *inter_V = Graphs::ghost_vertex(I"binary inter in memory");</span>
<span class="reserved">build_vertex</span><span class="plain"> *</span><span class="identifier">inter_V</span><span class="plain"> = </span><span class="functiontext">Graphs::file_vertex</span><span class="plain">(</span><span class="identifier">inf_F</span><span class="plain">);</span>
<span class="functiontext">Graphs::need_this_to_build</span><span class="plain">(</span><span class="identifier">inter_V</span><span class="plain">, </span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;as_copy</span><span class="plain">-</span><span class="element">&gt;vertex</span><span class="plain">);</span>
<span class="functiontext">BuildSteps::attach</span><span class="plain">(</span><span class="identifier">inter_V</span><span class="plain">, </span><span class="identifier">compile_using_inform7_skill</span><span class="plain">,</span>
@ -414,16 +413,14 @@ may be multiple sentences, which we need to count up.
<span class="identifier">filename</span><span class="plain"> *</span><span class="identifier">blorbed_F</span><span class="plain"> = </span><span class="identifier">Filenames::in_folder</span><span class="plain">(</span><span class="identifier">build_folder</span><span class="plain">, </span><span class="identifier">story_file_leafname2</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">story_file_leafname2</span><span class="plain">);</span>
<span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;blorbed_vertex</span><span class="plain"> = </span><span class="functiontext">Graphs::file_vertex</span><span class="plain">(</span><span class="identifier">blorbed_F</span><span class="plain">);</span>
<span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;blorbed_vertex</span><span class="plain">-</span><span class="element">&gt;force_this</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;blorbed_vertex</span><span class="plain">-</span><span class="element">&gt;always_build_this</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="functiontext">Graphs::need_this_to_build</span><span class="plain">(</span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;blorbed_vertex</span><span class="plain">, </span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;unblorbed_vertex</span><span class="plain">);</span>
<span class="functiontext">BuildSteps::attach</span><span class="plain">(</span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;blorbed_vertex</span><span class="plain">, </span><span class="identifier">package_using_inblorb_skill</span><span class="plain">,</span>
<span class="functiontext">Inbuild::nest_list</span><span class="plain">(), </span><span class="identifier">releasing</span><span class="plain">, </span><span class="identifier">VM</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;as_copy</span><span class="plain">);</span>
<span class="comment">inter_V-&gt;force_this = TRUE;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">compile_only</span><span class="plain">) {</span>
<span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;chosen_build_target</span><span class="plain"> = </span><span class="identifier">inf_V</span><span class="plain">;</span>
<span class="identifier">inf_V</span><span class="plain">-</span><span class="element">&gt;force_this</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="identifier">inf_V</span><span class="plain">-</span><span class="element">&gt;always_build_this</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">releasing</span><span class="plain">) </span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;chosen_build_target</span><span class="plain"> = </span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;blorbed_vertex</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;chosen_build_target</span><span class="plain"> = </span><span class="identifier">project</span><span class="plain">-</span><span class="element">&gt;unblorbed_vertex</span><span class="plain">;</span>
<span class="plain">}</span>

View file

@ -112,12 +112,16 @@
<ul class="sectionlist">
<li>
<p><a href="3-bg.html"><spon class="sectiontitle">Build Graphs</span></a> -
<span class="purpose">Graphs in which vertices correspond to files or copies, and arrows to dependencies between them.</span></p>
<span class="purpose">Graphs in which vertices correspond to files or copies, and edges to dependencies between them.</span></p>
</li>
<li>
<p><a href="3-bm.html"><spon class="sectiontitle">Build Methodology</span></a> -
<span class="purpose">Whether to run tasks internally in some merged tool, or run via the shell, or simply trace to the standard output what we think ought to be done.</span></p>
</li>
<li>
<p><a href="3-ib.html"><spon class="sectiontitle">Incremental Building</span></a> -
<span class="purpose">Deciding what is the least possible amount which needs to be built, in what order, to arrive at a working version of a copy.</span></p>
</li>
<li>
<p><a href="3-bs.html"><spon class="sectiontitle">Build Scripts</span></a> -
<span class="purpose">Scripts are nothing more than list of build steps.</span></p>

View file

@ -192,7 +192,7 @@ that we want to start work now.
<span class="reserved">build_methodology</span><span class="plain"> *</span><span class="identifier">BM</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">path_to_tools</span><span class="plain">) </span><span class="identifier">BM</span><span class="plain"> = </span><span class="functiontext">BuildMethodology::new</span><span class="plain">(</span><span class="identifier">path_to_tools</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">, </span><span class="identifier">use</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">BM</span><span class="plain"> = </span><span class="functiontext">BuildMethodology::new</span><span class="plain">(</span><span class="functiontext">Pathnames::up</span><span class="plain">(</span><span class="identifier">path_to_inbuild</span><span class="plain">), </span><span class="constant">TRUE</span><span class="plain">, </span><span class="identifier">use</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">build_trace_mode</span><span class="plain">) </span><span class="identifier">trace_ibg</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">build_trace_mode</span><span class="plain">) </span><span class="functiontext">IncrementalBuild::enable_trace</span><span class="plain">();</span>
<span class="reserved">linked_list</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain"> = </span><span class="functiontext">Main::list_of_targets</span><span class="plain">();</span>
<span class="reserved">inbuild_copy</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="reserved">inbuild_copy</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">)</span>

View file

@ -93,7 +93,7 @@ that we want to start work now.
build_methodology *BM;
if (path_to_tools) BM = BuildMethodology::new(path_to_tools, FALSE, use);
else BM = BuildMethodology::new(Pathnames::up(path_to_inbuild), TRUE, use);
if (build_trace_mode) trace_ibg = TRUE;
if (build_trace_mode) IncrementalBuild::enable_trace();
linked_list *L = Main::list_of_targets();
inbuild_copy *C;
LOOP_OVER_LINKED_LIST(C, inbuild_copy, L)

View file

@ -154,12 +154,12 @@ its main task: building an Inform project.
void Copies::build(OUTPUT_STREAM, inbuild_copy *C, build_methodology *BM) {
build_vertex *V = C->vertex;
VMETHOD_CALL(C->edition->work->genre, GENRE_BUILDING_SOON_MTID, C, &V);
Graphs::build(OUT, V, BM);
IncrementalBuild::build(OUT, V, BM);
}
void Copies::rebuild(OUTPUT_STREAM, inbuild_copy *C, build_methodology *BM) {
build_vertex *V = C->vertex;
VMETHOD_CALL(C->edition->work->genre, GENRE_BUILDING_SOON_MTID, C, &V);
Graphs::rebuild(OUT, V, BM);
IncrementalBuild::rebuild(OUT, V, BM);
}
@ Now in quick succession |-graph|, |-build-needs|, |-use-needs|, |-build-missing|,

View file

@ -1,39 +1,56 @@
[Graphs::] Build Graphs.
Graphs in which vertices correspond to files or copies, and arrows to
Graphs in which vertices correspond to files or copies, and edges to
dependencies between them.
@h Build graphs.
These are directed acyclic graphs which show what depends on what in the
building process. If an arrow leads from A to B, then B must be built before
A can be built.
See the Inbuild manual for an introduction to the build graph. Properly
speaking, it is a directed acyclic multigraph which us usually disconnected.
There can be two sorts of vertex in such a graph: copy vertices, each of which
belongs to a single copy, and internal vertices, each of which represents
a different file inside the copy.
There are two colours of edge: build edges and use edges. A build edge between
A and B means that B must exist and be up-to-date before A can be built.
A use edge between A and B means that B must exist and be up-to-date before
A can be used.
There are three colours of vertex: copy, file and requirement. Copy vertices
correspond to copies which the user does have; requirement vertices to copies
which she doesn't have; and file vertices to unmanaged plain files in
the build process. For example, if an Inform project says it wants to include
an extension which isn't anywhere to be seen, then the project itself is a
copy vertex, as are the Standard Rules extension, the CommandParserKit kit,
and such; the missing extension is represneted by a requirement vertex; and
the story file which the project would compile to, if only it could be
compiled, is a file vertex.
@e COPY_VERTEX from 1
@e REQUIREMENT_VERTEX
@e FILE_VERTEX
@e GHOST_VERTEX
@e REQUIREMENT_VERTEX
=
typedef struct build_vertex {
int type; /* one of the |*_VERTEX| values above */
struct linked_list *build_edges; /* of |build_vertex| */
struct linked_list *use_edges; /* of |build_vertex| */
struct inbuild_copy *buildable_if_copy;
struct filename *buildable_if_internal_file;
struct inbuild_requirement *findable;
struct text_stream *annotation;
struct source_file *read_as;
struct linked_list *build_edges; /* of |build_vertex| */
struct linked_list *use_edges; /* of |build_vertex| */
int last_described_in_generation;
int build_result;
int last_built_in_generation;
int always_build_this;
struct build_script *script;
int last_described;
int built;
int force_this;
MEMORY_MANAGEMENT
} build_vertex;
@h Creation.
First, the three colours of vertex.
=
build_vertex *Graphs::file_vertex(filename *F) {
build_vertex *V = CREATE(build_vertex);
V->type = FILE_VERTEX;
@ -44,9 +61,10 @@ build_vertex *Graphs::file_vertex(filename *F) {
V->script = BuildScripts::new();
V->annotation = NULL;
V->read_as = NULL;
V->last_described = 0;
V->built = FALSE;
V->force_this = FALSE;
V->last_described_in_generation = 0;
V->build_result = NOT_APPLICABLE;
V->last_built_in_generation = -1;
V->always_build_this = FALSE;
return V;
}
@ -68,13 +86,10 @@ build_vertex *Graphs::req_vertex(inbuild_requirement *R) {
return V;
}
build_vertex *Graphs::ghost_vertex(text_stream *S) {
build_vertex *V = Graphs::file_vertex(NULL);
V->type = GHOST_VERTEX;
V->annotation = Str::duplicate(S);
return V;
}
@ Next, the two colours of edge. Note that between A and B there can be
at most one edge of each colour.
=
void Graphs::need_this_to_build(build_vertex *from, build_vertex *to) {
if (from == NULL) internal_error("no from");
if (to == NULL) internal_error("no to");
@ -82,8 +97,6 @@ void Graphs::need_this_to_build(build_vertex *from, build_vertex *to) {
build_vertex *V;
LOOP_OVER_LINKED_LIST(V, build_vertex, from->build_edges)
if (V == to) return;
// Graphs::describe(STDOUT, from, FALSE); PRINT(" needs ");
// Graphs::describe(STDOUT, to, FALSE); PRINT("\n");
ADD_TO_LINKED_LIST(to, build_vertex, from->build_edges);
}
@ -97,24 +110,36 @@ void Graphs::need_this_to_use(build_vertex *from, build_vertex *to) {
ADD_TO_LINKED_LIST(to, build_vertex, from->use_edges);
}
int description_round = 1;
@ The script attached to a vertex is a list of instructions for how to build
the resource it refers to. Some vertices have no instructions provided, so:
=
int Graphs::can_be_built(build_vertex *V) {
if (BuildScripts::script_length(V->script) > 0) return TRUE;
return FALSE;
}
@h Writing.
This is a suitably indented printout of the graph as seen from a given
vertex: it's used by the Inbuild command |-graph|.
=
int no_desc_generations = 1;
void Graphs::describe(OUTPUT_STREAM, build_vertex *V, int recurse) {
Graphs::describe_r(OUT, 0, V, recurse, NULL, NOT_A_GB, description_round++);
Graphs::describe_r(OUT, 0, V, recurse, NULL, NOT_APPLICABLE, no_desc_generations++);
}
void Graphs::describe_r(OUTPUT_STREAM, int depth, build_vertex *V,
int recurse, pathname *stem, int which, int description_round) {
int recurse, pathname *stem, int following_build_edge, int description_round) {
for (int i=0; i<depth; i++) WRITE(" ");
if (which == BUILD_GB) WRITE("--build-> ");
if (which == USE_GB) WRITE("--use---> ");
if (following_build_edge == TRUE) WRITE("--build-> ");
if (following_build_edge == FALSE) WRITE("--use---> ");
Graphs::describe_vertex(OUT, V);
WRITE(" ");
if (V->last_described == description_round) { WRITE("q.v.\n"); return; }
TEMPORARY_TEXT(T);
switch (V->type) {
case COPY_VERTEX: Copies::write_copy(T, V->buildable_if_copy); break;
case REQUIREMENT_VERTEX: Requirements::write(T, V->findable); break;
case FILE_VERTEX: WRITE("%f", V->buildable_if_internal_file); break;
case GHOST_VERTEX: WRITE("(%S)", V->annotation); break;
}
TEMPORARY_TEXT(S);
WRITE_TO(S, "%p", stem);
@ -125,6 +150,8 @@ void Graphs::describe_r(OUTPUT_STREAM, int depth, build_vertex *V,
}
DISCARD_TEXT(S);
DISCARD_TEXT(T);
if (V->last_described_in_generation == description_round) { WRITE(" q.v.\n"); return; }
V->last_described_in_generation = description_round;
WRITE("\n");
if (recurse) {
if (V->buildable_if_copy) stem = V->buildable_if_copy->location_if_path;
@ -132,9 +159,9 @@ void Graphs::describe_r(OUTPUT_STREAM, int depth, build_vertex *V,
stem = Filenames::get_path_to(V->buildable_if_internal_file);
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges)
Graphs::describe_r(OUT, depth+1, W, TRUE, stem, BUILD_GB, description_round);
Graphs::describe_r(OUT, depth+1, W, TRUE, stem, TRUE, description_round);
LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges)
Graphs::describe_r(OUT, depth+1, W, TRUE, stem, USE_GB, description_round);
Graphs::describe_r(OUT, depth+1, W, TRUE, stem, FALSE, description_round);
}
}
@ -144,15 +171,18 @@ void Graphs::describe_vertex(OUTPUT_STREAM, build_vertex *V) {
case COPY_VERTEX: WRITE("[c%d]", V->allocation_id); break;
case REQUIREMENT_VERTEX: WRITE("[r%d]", V->allocation_id); break;
case FILE_VERTEX: WRITE("[f%d]", V->allocation_id); break;
case GHOST_VERTEX: WRITE("[g%d]", V->allocation_id); break;
}
}
@ A similar but slightly different recursion for |-build-needs| and |-use-needs|.
=
void Graphs::show_needs(OUTPUT_STREAM, build_vertex *V, int uses_only) {
Graphs::show_needs_r(OUT, V, 0, 0, uses_only);
}
void Graphs::show_needs_r(OUTPUT_STREAM, build_vertex *V, int depth, int true_depth, int uses_only) {
void Graphs::show_needs_r(OUTPUT_STREAM, build_vertex *V,
int depth, int true_depth, int uses_only) {
if (V->type == COPY_VERTEX) {
for (int i=0; i<depth; i++) WRITE(" ");
inbuild_copy *C = V->buildable_if_copy;
@ -165,7 +195,8 @@ void Graphs::show_needs_r(OUTPUT_STREAM, build_vertex *V, int depth, int true_de
WRITE("missing %S: ", V->findable->work->genre->genre_name);
Works::write(OUT, V->findable->work);
if (VersionNumberRanges::is_any_range(V->findable->version_range) == FALSE) {
WRITE(", need version in range "); VersionNumberRanges::write_range(OUT, V->findable->version_range);
WRITE(", need version in range ");
VersionNumberRanges::write_range(OUT, V->findable->version_range);
} else {
WRITE(", any version will do");
}
@ -182,17 +213,22 @@ void Graphs::show_needs_r(OUTPUT_STREAM, build_vertex *V, int depth, int true_de
}
}
@ And for |-build-missing| and |-use-missing|.
=
int Graphs::show_missing(OUTPUT_STREAM, build_vertex *V, int uses_only) {
return Graphs::show_missing_r(OUT, V, 0, uses_only);
}
int Graphs::show_missing_r(OUTPUT_STREAM, build_vertex *V, int true_depth, int uses_only) {
int Graphs::show_missing_r(OUTPUT_STREAM, build_vertex *V,
int true_depth, int uses_only) {
int N = 0;
if (V->type == REQUIREMENT_VERTEX) {
WRITE("missing %S: ", V->findable->work->genre->genre_name);
Works::write(OUT, V->findable->work);
if (VersionNumberRanges::is_any_range(V->findable->version_range) == FALSE) {
WRITE(", need version in range "); VersionNumberRanges::write_range(OUT, V->findable->version_range);
WRITE(", need version in range ");
VersionNumberRanges::write_range(OUT, V->findable->version_range);
} else {
WRITE(", any version will do");
}
@ -210,34 +246,27 @@ int Graphs::show_missing_r(OUTPUT_STREAM, build_vertex *V, int true_depth, int u
return N;
}
void Graphs::archive(OUTPUT_STREAM, build_vertex *V, inbuild_nest *N, build_methodology *BM) {
@h Archiving.
This isn't simply a matter of printing out, of course, but very similar code
handles |-archive| and |-archive-to N|.
Note that the English language definition, which lives in the internal nest,
cannot be read from any other nest -- so we won't archive it.
=
void Graphs::archive(OUTPUT_STREAM, build_vertex *V, inbuild_nest *N,
build_methodology *BM) {
Graphs::archive_r(OUT, V, 0, N, BM);
}
void Graphs::archive_r(OUTPUT_STREAM, build_vertex *V, int true_depth, inbuild_nest *N, build_methodology *BM) {
void Graphs::archive_r(OUTPUT_STREAM, build_vertex *V, int true_depth, inbuild_nest *N,
build_methodology *BM) {
if (V->type == COPY_VERTEX) {
inbuild_copy *C = V->buildable_if_copy;
if ((Genres::stored_in_nests(C->edition->work->genre)) &&
((Str::ne(C->edition->work->title, I"English")) ||
(Str::len(C->edition->work->author_name) > 0))) {
WRITE("%S: ", C->edition->work->genre->genre_name);
Copies::write_copy(OUT, C);
pathname *P = C->location_if_path;
if (C->location_if_file) P = Filenames::get_path_to(C->location_if_file);
TEMPORARY_TEXT(nl);
TEMPORARY_TEXT(cl);
WRITE_TO(nl, "%p/", N->location);
WRITE_TO(cl, "%p/", P);
if (Str::prefix_eq(cl, nl, Str::len(nl))) {
WRITE(" -- already there\n");
} else {
WRITE(" -- archiving\n");
Copies::copy_to(C, N, TRUE, BM);
}
DISCARD_TEXT(nl);
DISCARD_TEXT(cl);
}
(Str::len(C->edition->work->author_name) > 0)))
@<Archive a single copy@>;
}
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges)
@ -248,120 +277,24 @@ void Graphs::archive_r(OUTPUT_STREAM, build_vertex *V, int true_depth, inbuild_n
}
}
time_t Graphs::timestamp_for(build_vertex *V) {
time_t latest = (time_t) 0;
@ The most delicate thing here is that we don't want to archive something
to |N| if it's already there; but that is difficult to detect.
if (V->buildable_if_internal_file) {
char transcoded_pathname[4*MAX_FILENAME_LENGTH];
TEMPORARY_TEXT(FN);
WRITE_TO(FN, "%f", V->buildable_if_internal_file);
Str::copy_to_locale_string(transcoded_pathname, FN, 4*MAX_FILENAME_LENGTH);
DISCARD_TEXT(FN);
struct stat filestat;
if (stat(transcoded_pathname, &filestat) != -1) latest = filestat.st_mtime;
@<Archive a single copy@> =
WRITE("%S: ", C->edition->work->genre->genre_name);
Copies::write_copy(OUT, C);
pathname *P = C->location_if_path;
if (C->location_if_file) P = Filenames::get_path_to(C->location_if_file);
TEMPORARY_TEXT(nl);
TEMPORARY_TEXT(cl);
WRITE_TO(nl, "%p/", N->location);
WRITE_TO(cl, "%p/", P);
if (Str::prefix_eq(cl, nl, Str::len(nl))) {
WRITE(" -- already there\n");
} else {
latest = Graphs::time_of_most_recent_ingredient(V);
}
return latest;
}
time_t Graphs::time_of_most_recent_ingredient(build_vertex *V) {
time_t latest = (time_t) 0;
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges) {
time_t inner = Graphs::timestamp_for(W);
if ((latest == (time_t) 0) || (difftime(inner, latest) > 0))
latest = inner;
}
return latest;
}
time_t Graphs::time_of_most_recent_used_resource(build_vertex *V) {
time_t latest = (time_t) 0;
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges) {
time_t inner = Graphs::timestamp_for(W);
if ((latest == (time_t) 0) || (difftime(inner, latest) > 0))
latest = inner;
}
return latest;
}
@
@d NOT_A_GB 0
@d BUILD_GB 1
@d FORCE_GB 2
@d USE_GB 4
=
int Graphs::build(OUTPUT_STREAM, build_vertex *V, build_methodology *meth) {
int changes = 0;
return Graphs::build_r(OUT, BUILD_GB, V, meth, &changes);
}
int Graphs::rebuild(OUTPUT_STREAM, build_vertex *V, build_methodology *meth) {
int changes = 0;
return Graphs::build_r(OUT, BUILD_GB + FORCE_GB, V, meth, &changes);
}
int trace_ibg = FALSE;
int Graphs::build_r(OUTPUT_STREAM, int gb, build_vertex *V, build_methodology *meth, int *changes) {
if (trace_ibg) { WRITE_TO(STDOUT, "Visit: "); Graphs::describe(STDOUT, V, FALSE); }
if (V->built) return TRUE;
int changes_so_far = *changes;
if (trace_ibg) { STREAM_INDENT(STDOUT); }
int rv = TRUE;
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges)
if (rv)
rv = Graphs::build_r(OUT, gb | USE_GB, W, meth, changes);
if (gb & USE_GB)
LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges)
if (rv)
rv = Graphs::build_r(OUT, gb & (BUILD_GB + FORCE_GB), W, meth, changes);
if (trace_ibg) { STREAM_OUTDENT(STDOUT); }
if (rv) {
int needs_building = FALSE;
if ((gb & FORCE_GB) || (V->force_this)) needs_building = TRUE;
else if ((V->type == GHOST_VERTEX) && (*changes > changes_so_far)) needs_building = TRUE;
else @<Decide based on timestamps@>;
if ((needs_building) && (BuildScripts::script_length(V->script) > 0)) {
if (trace_ibg) { WRITE_TO(STDOUT, "Build: "); Graphs::describe(STDOUT, V, FALSE); }
(*changes)++;
rv = BuildScripts::execute(V, V->script, meth);
} else {
if (trace_ibg) { WRITE_TO(STDOUT, "No Build\n"); }
}
}
V->built = rv;
return rv;
}
@<Decide based on timestamps@> =
time_t last_built_at = Graphs::timestamp_for(V);
if (trace_ibg) { WRITE_TO(STDOUT, "Last built at: %08x\n", last_built_at); }
if (last_built_at == (time_t) 0)
needs_building = TRUE;
else {
time_t time_of_most_recent = Graphs::time_of_most_recent_ingredient(V);
if (time_of_most_recent != (time_t) 0) {
if (trace_ibg) { WRITE_TO(STDOUT, "Most recent: %08x\n", time_of_most_recent); }
if (difftime(time_of_most_recent, last_built_at) > 0)
needs_building = TRUE;
}
if (gb & USE_GB) {
time_t time_of_most_recent_used = Graphs::time_of_most_recent_used_resource(V);
if (time_of_most_recent_used != (time_t) 0) {
if (trace_ibg) { WRITE_TO(STDOUT, "Most recent use: %08x\n", time_of_most_recent_used); }
if (difftime(time_of_most_recent_used, last_built_at) > 0)
needs_building = TRUE;
}
}
WRITE(" -- archiving\n");
Copies::copy_to(C, N, TRUE, BM);
}
DISCARD_TEXT(nl);
DISCARD_TEXT(cl);

View file

@ -0,0 +1,231 @@
[IncrementalBuild::] Incremental Building.
Deciding what is the least possible amount which needs to be built, in what
order, to arrive at a working version of a copy.
@h Timestamps.
We want to assign a timestamp to every vertex in the graph, whose meaning is
that what it represents has been up-to-date since that time.
For a file vertex, we take that from the file system's timestamp. For a
copy vertex, we do the same for a copy which is a single file (such as an
extension), but for a copy which is a directory containing a composite of
resources, there's no good way to know. (Perhaps we could scan the files
in it recursively, but then we have to worry about hidden files, symlinks,
and all of that.) Instead, we use the build graph itself to decide; for
example, the timestamp for a kit is the most recent timestamp of any of its
binary Inter files, because those are its build-dependencies.
=
time_t IncrementalBuild::timestamp(build_vertex *V) {
switch (V->type) {
case FILE_VERTEX:
return Filenames::timestamp(V->buildable_if_internal_file);
case COPY_VERTEX:
if (V->buildable_if_copy->location_if_file)
return Filenames::timestamp(V->buildable_if_copy->location_if_file);
return IncrementalBuild::time_of_latest_build_dependency(V);
default:
return Platform::never_time();
}
}
@ The following compares two times: it returns 1 if |t1| is later, -1 if
|t2| is later, and 0 if they are identical.
Note that we never apply the C standard library function |difftime| in
the case of the never-time, which we consider to be before all other times.
(On most platforms it will be the C epoch of 1970, and |difftime| alone
would be fine, but we're being careful.)
=
int IncrementalBuild::timecmp(time_t t1, time_t t2) {
if (t1 == Platform::never_time()) {
if (t2 == Platform::never_time()) return 0;
return -1;
}
if (t2 == Platform::never_time()) {
return 1;
}
if (t1 == t2) return 0;
if (difftime(t1, t2) > 0) return 1;
return -1;
}
@ We then take the latest timestamp of any build dependency:
=
time_t IncrementalBuild::time_of_latest_build_dependency(build_vertex *V) {
time_t latest = Platform::never_time();
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges) {
time_t t = IncrementalBuild::timestamp(W);
if (IncrementalBuild::timecmp(t, latest) > 0) latest = t;
}
return latest;
}
@ And of any use dependency:
=
time_t IncrementalBuild::time_of_latest_use_dependency(build_vertex *V) {
time_t latest = Platform::never_time();
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges) {
time_t t = IncrementalBuild::timestamp(W);
if (IncrementalBuild::timecmp(t, latest) > 0) latest = t;
}
return latest;
}
@h Build process.
This is a recursive process, beginning at the node representing what we want
to build. As we recurse, we pass a bitmap of the following:
@d BUILD_DEPENDENCIES_MATTER_GB 1 /* We will need all your build dependencies too */
@d USE_DEPENDENCIES_MATTER_GB 2 /* We will need all your use dependencies too */
@d IGNORE_TIMESTAMPS_GB 4 /* Don't be incremental: trust nothing, rebuild everything */
=
int IncrementalBuild::build(OUTPUT_STREAM, build_vertex *V, build_methodology *meth) {
return IncrementalBuild::begin_recursion(OUT,
BUILD_DEPENDENCIES_MATTER_GB, V, meth);
}
int IncrementalBuild::rebuild(OUTPUT_STREAM, build_vertex *V, build_methodology *meth) {
return IncrementalBuild::begin_recursion(OUT,
BUILD_DEPENDENCIES_MATTER_GB + IGNORE_TIMESTAMPS_GB, V, meth);
}
@ This is called when Inbuild's |-trace| switch is set at the command line.
=
int trace_ibg = FALSE;
void IncrementalBuild::enable_trace(void) {
trace_ibg = TRUE;
}
@ We want to be very sure that this recursion does not lock up, or perform
unnecessary work by performing the same node twice. To do this we apply the
|built| flag to a node when it has been built; but to make this is not left
over from last time around, we only regard it when the |last_built_in_generation| count
for the node is set to the current "generation", a unique number incremented
for each time we recurse.
=
int no_build_generations = 0;
int IncrementalBuild::begin_recursion(OUTPUT_STREAM, int gb, build_vertex *V,
build_methodology *meth) {
int changes = 0;
text_stream *trace = NULL;
if (trace_ibg) trace = STDOUT;
WRITE_TO(trace, "Incremental build %d:\n", no_build_generations);
int rv = IncrementalBuild::recurse(OUT, trace, gb, V, meth, &changes, no_build_generations++);
WRITE_TO(trace, "%d change(s)\n", changes);
return rv;
}
int IncrementalBuild::recurse(OUTPUT_STREAM, text_stream *trace, int gb, build_vertex *V,
build_methodology *meth, int *changes, int generation) {
if (trace) {
WRITE_TO(trace, "Visit %c%c%c: ",
(gb & BUILD_DEPENDENCIES_MATTER_GB)?'b':'.',
(gb & USE_DEPENDENCIES_MATTER_GB)?'u':'.',
(gb & IGNORE_TIMESTAMPS_GB)?'i':'.');
Graphs::describe(trace, V, FALSE);
}
if (V->last_built_in_generation == generation) return V->build_result;
int rv = TRUE;
@<Build this node if necessary, setting rv to its success or failure@>;
V->build_result = rv;
V->last_built_in_generation = generation;
return rv;
}
@ In everything which follows, |rv| (prosaically, this stands only for "return
value") remains |TRUE| until the first active step fails, at which point no
other active steps are ever taken, nor are any recursions made. In effect,
the first failure halts the process.
We are recursing depth-first, that is, we build the things needed to build
|V| before we build |V| itself.
A point of difference between this algorithm and |make| is that we do not
halt with an error if a node has no way to be built. This is because the
graphs are here are built by Inbuild itself, not by a possibly erroneous
makefile whose author has forgotten something and whose intentions are not
clear. Here, if a node has no build script attached, it must be because it
needs no action taken.
@<Build this node if necessary, setting rv to its success or failure@> =
if (trace) STREAM_INDENT(trace);
if (gb & BUILD_DEPENDENCIES_MATTER_GB) @<Build the build dependencies of the node@>;
if (gb & USE_DEPENDENCIES_MATTER_GB) @<Build the use dependencies of the node@>;
if (trace) STREAM_OUTDENT(trace);
if ((rv) && (Graphs::can_be_built(V))) @<Build the node itself, if necessary@>;
@ Suppose V needs W (for whatever reason), and that W can only be used with X.
It follows that we will have to build X as well as W, since the process of
building V is itself a use of W, and therefore of X. So we always enable the
|USE_DEPENDENCIES_MATTER_GB| bit when recursing through an edge.
@<Build the build dependencies of the node@> =
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->build_edges)
if (rv)
rv = IncrementalBuild::recurse(OUT, trace,
gb | USE_DEPENDENCIES_MATTER_GB, W, meth, changes, generation);
@<Build the use dependencies of the node@> =
build_vertex *W;
LOOP_OVER_LINKED_LIST(W, build_vertex, V->use_edges)
if (rv)
rv = IncrementalBuild::recurse(OUT, trace,
gb | USE_DEPENDENCIES_MATTER_GB, W, meth, changes, generation);
@ Now for the node |V| itself.
@<Build the node itself, if necessary@> =
int needs_building = FALSE;
if ((gb & IGNORE_TIMESTAMPS_GB) || (V->always_build_this)) needs_building = TRUE;
else @<Decide based on timestamps@>;
if (needs_building) {
if (trace) { WRITE_TO(trace, "Build: "); Graphs::describe(trace, V, FALSE); }
(*changes)++;
rv = BuildScripts::execute(V, V->script, meth);
} else {
if (trace) { WRITE_TO(trace, "No build\n"); }
}
@ This is where the incremental promise is finally kept. If the timestamp of
|V| is definitely before later than that of everything it depends on, then
it would be redundant to recreate it.
Note that equal timestamps force rebuilding. File timestamping is quite coarse
on some systems, so equal timeatamps might only mean that the two files were
created during the same second.
@<Decide based on timestamps@> =
time_t last_up_to_date_at = IncrementalBuild::timestamp(V);
if (last_up_to_date_at == Platform::never_time())
needs_building = TRUE;
else {
if (trace) { WRITE_TO(trace, "Last built at: %08x\n", last_up_to_date_at); }
if (gb & BUILD_DEPENDENCIES_MATTER_GB) {
time_t t = IncrementalBuild::time_of_latest_build_dependency(V);
if (trace) { WRITE_TO(trace, "Most recent build dependency: %08x\n", t); }
if (IncrementalBuild::timecmp(t, last_up_to_date_at) >= 0)
needs_building = TRUE;
}
if (gb & USE_DEPENDENCIES_MATTER_GB) {
time_t t = IncrementalBuild::time_of_latest_use_dependency(V);
if (trace) { WRITE_TO(trace, "Most recent use dependency: %08x\n", t); }
if (IncrementalBuild::timecmp(t, last_up_to_date_at) >= 0)
needs_building = TRUE;
}
}

View file

@ -262,7 +262,6 @@ void Projects::construct_build_target(inform_project *project, target_vm *VM,
pathname *build_folder = Projects::build_pathname(project);
filename *inf_F = Filenames::in_folder(build_folder, I"auto.inf");
// build_vertex *inter_V = Graphs::ghost_vertex(I"binary inter in memory");
build_vertex *inter_V = Graphs::file_vertex(inf_F);
Graphs::need_this_to_build(inter_V, project->as_copy->vertex);
BuildSteps::attach(inter_V, compile_using_inform7_skill,
@ -287,16 +286,14 @@ void Projects::construct_build_target(inform_project *project, target_vm *VM,
filename *blorbed_F = Filenames::in_folder(build_folder, story_file_leafname2);
DISCARD_TEXT(story_file_leafname2);
project->blorbed_vertex = Graphs::file_vertex(blorbed_F);
project->blorbed_vertex->force_this = TRUE;
project->blorbed_vertex->always_build_this = TRUE;
Graphs::need_this_to_build(project->blorbed_vertex, project->unblorbed_vertex);
BuildSteps::attach(project->blorbed_vertex, package_using_inblorb_skill,
Inbuild::nest_list(), releasing, VM, NULL, project->as_copy);
// inter_V->force_this = TRUE;
if (compile_only) {
project->chosen_build_target = inf_V;
inf_V->force_this = TRUE;
inf_V->always_build_this = TRUE;
} else if (releasing) project->chosen_build_target = project->blorbed_vertex;
else project->chosen_build_target = project->unblorbed_vertex;
}

View file

@ -20,6 +20,7 @@ Chapter 2: Conceptual Framework
Chapter 3: Incremental Builds
Build Graphs
Build Methodology
Incremental Building
Build Scripts
Build Steps
Inter Skill