{"id":1133,"date":"2019-07-26T07:23:36","date_gmt":"2019-07-26T06:23:36","guid":{"rendered":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/?p=1133"},"modified":"2019-07-27T23:44:57","modified_gmt":"2019-07-27T22:44:57","slug":"stroll","status":"publish","type":"post","link":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/stroll\/","title":{"rendered":"Stroll: an experimental build system"},"content":{"rendered":"<p>I&#8217;d like to share an experiment in developing a language-agnostic build system\u00a0that does not require the user to specify dependencies between individual build tasks. By &#8220;language-agnostic&#8221; I mean the user does not need to learn a new language or a special file format for describing build tasks &#8212; existing scripts or executable files can be used as build tasks directly without modification.<\/p>\n<p>I call this build system <a href=\"https:\/\/github.com\/snowleopard\/stroll\">Stroll<\/a> because its build algorithm reminds me of strolling through a park where you&#8217;ve never been before, trying to figure out an optimal path to your target destination, and likely going in circles occasionally until you&#8217;ve built up a complete mental map of the park.<\/p>\n<p><!--more--><\/p>\n<h3>Main idea<\/h3>\n<p>Most build systems require the user to specify both <em>build tasks<\/em>\u00a0as well as <em>dependencies<\/em> between the tasks: knowing the dependencies allows the build system to determine which tasks need to be executed when you modify some of the source files. From personal experience, describing dependencies accurately is difficult and is often a source of frustration.<\/p>\n<p>Build tasks and their dependencies are typically described using domain-specific task description languages: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Make_(software)\">Make<\/a> uses makefiles,\u00a0<a href=\"https:\/\/www.bazel.build\/\">Bazel<\/a> uses a Python-inspired\u00a0<a href=\"https:\/\/docs.bazel.build\/versions\/master\/skylark\/language.html\">Starlark<\/a>,\u00a0<a href=\"https:\/\/shakebuild.com\/\">Shake<\/a> uses Haskell, etc. While learning a new\u00a0task description language is not a big deal, translating an existing build system to a new language may take years (or maybe I&#8217;m just slow).<\/p>\n<p>Stroll is different. You use your favourite language(s) to describe build tasks, put them in a directory, and ask Stroll to execute them. Stroll does not look inside the tasks; it treats the tasks as black boxes and finds the dependencies between them by tracking their\u00a0file accesses. This process is not optimal in the sense that a task may fail because its dependency is not ready and, therefore, will need to be built again later, but in the end, Stroll will learn the complete and accurate dependency graph and will store it to speed up future builds.<\/p>\n<p>There is a build system called <a href=\"https:\/\/github.com\/brushtechnology\/fabricate\">Fabricate<\/a> that also tracks file accesses to automatically compute accurate task dependencies, but it requires the user to describe build tasks in a lightweight Python DSL and preschedule them by calling the tasks in the right order, essentially asking the user to do the strolling part themselves. Fabricate is cool and inspired Stroll but I&#8217;d like to explore this corner of the build systems space a bit further.<\/p>\n<h3>Demo<\/h3>\n<p>Stroll is just an experiment and I&#8217;m not sure if the main idea behind it is feasible, but it can already be used to automate some simple collections of build tasks. Let me give you a demo. I&#8217;m using Windows below but the demo works on Linux too.<\/p>\n<p>Consider a simple &#8220;Hello, World!&#8221; program stored in the file <span style=\"color: #000080\">src\/main.c<\/span>:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #bc7a00\">#include &lt;stdio.h&gt;<\/span>\r\n\r\n<span style=\"color: #b00040\">int<\/span> <span style=\"color: #0000ff\">main<\/span>()\r\n{\r\n    printf(<span style=\"color: #ba2121\">\"Hello, World!<\/span><span style=\"color: #bb6622;font-weight: bold\">\\n<\/span><span style=\"color: #ba2121\">\"<\/span>);\r\n    <span style=\"color: #008000;font-weight: bold\">return<\/span> <span style=\"color: #666666\">0<\/span>;\r\n}\r\n<\/pre>\n<\/div>\n<p>We can build an executable <span style=\"color: #000080\">bin\/main.exe<\/span> from it by using the following simple build script <span style=\"color: #000080\">build\/main.bat<\/span>:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #0000ff\">mkdir<\/span> bin\r\n<span style=\"color: #0000ff\">gcc<\/span> src<span style=\"color: #666666\">\/<\/span>main<span style=\"color: #666666\">.<\/span>c <span style=\"color: #666666\">-<\/span>o bin<span style=\"color: #666666\">\/<\/span>main<span style=\"color: #666666\">.<\/span>exe\r\n<\/pre>\n<\/div>\n<p>Let&#8217;s ask Stroll to build our little project:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> stroll build\r\n<span style=\"color: #888888\">Executing build\/main.bat...<\/span>\r\n<span style=\"color: #888888\">Done\r\n<\/span>\r\n<span style=\"color: #000080;font-weight: bold\">$<\/span> bin\/main.exe\r\n<span style=\"color: #888888\">Hello, World!<\/span>\r\n<\/pre>\n<\/div>\n<p>When executing build tasks, Stroll tracks their file accesses and stores the discovered information next to the build scripts, by appending the extension <span style=\"color: #000080\">.stroll<\/span>\u00a0to their names:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;padding: 0.8em;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> cat build\/main.bat.stroll\r\n<span style=\"color: #888888\">exit-code: ExitSuccess<\/span>\r\n<span style=\"color: #888888\">operations:<\/span>\r\n<span style=\"color: #888888\">  bin\/main.exe:<\/span>\r\n<span style=\"color: #888888\">    write: efc851e573be26cf8fe726caf70facf924ccdbae5c4fce241fdbe728b3abde76<\/span>\r\n<span style=\"color: #888888\">  src\/main.c:<\/span>\r\n<span style=\"color: #888888\">    read: bc31bb10c238be7ee34fd86edec0dc99d145f56067b13b82c351608efd38763c<\/span>\r\n<span style=\"color: #888888\">  build\/main.bat:<\/span>\r\n<span style=\"color: #888888\">    read: da9a4390693741b8d52388f18b1c5ccc418531bc3b0a64900890c381a31e7839<\/span>\r\n<\/pre>\n<\/div>\n<p>As you can see, Stroll recorded the exit code of the script, two file reads and one file write, along with the corresponding hashes of file contents.<\/p>\n<p>We can ask Stroll to visualise the discovered dependency graph:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> stroll -g build | dot -Tpng -Gdpi=600 -o graph.png\r\n<\/pre>\n<\/div>\n<p>The flag <span style=\"color: #000080\">-g<\/span> tells Stroll to print out the discovered dependency graph in the <a href=\"https:\/\/en.wikipedia.org\/wiki\/DOT_(graph_description_language)\">DOT format<\/a> that we subsequently convert to the following PNG file:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-1-build-main-bat.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-1-build-main-bat.png\" alt=\"Dependency graph\" width=\"300\" \/><\/a><\/p>\n<p>The green box indicates that the only build task <span style=\"color: #000080\">main<\/span> is up-to-date. This means Stroll will not execute it in the next run unless any of its inputs or outputs change. If we modify <span style=\"color: #000080\">src\/main.c<\/span>\u00a0and regenerate the dependency graph, we can see that the task <span style=\"color: #000080\">main<\/span> is now out-of-date:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-2-modify-main-c.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-2-modify-main-c.png\" alt=\"Dependency graph\" width=\"300\" \/><\/a><\/p>\n<p>The specific dependency that is out-of-date is shown by a dashed edge. Note that Stroll is a <em>self-tracking build system<\/em>, i.e. it tracks changes not only in sources and build artefacts but in build tasks too.<\/p>\n<p>To make the example a bit more interesting, let&#8217;s add\u00a0a library providing a greeting function <span style=\"color: #000080\">greet<\/span>\u00a0in files <span style=\"color: #000080\">src\/lib\/lib.h<\/span> and <span style=\"color: #000080\">src\/lib\/lib.c<\/span>:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> cat src\/lib\/lib.h\r\n<span style=\"color: #888888\">void greet(char *name);<\/span>\r\n\r\n<span style=\"color: #000080;font-weight: bold\">$<\/span> cat src\/lib\/lib.c\r\n<span style=\"color: #888888\">#<\/span>include &lt;stdio.h&gt;\r\n<span style=\"color: #888888\">#<\/span>include &lt;lib.h&gt;\r\n\r\n<span style=\"color: #888888\">void greet(char *name)<\/span>\r\n<span style=\"color: #888888\">{<\/span>\r\n<span style=\"color: #888888\">    printf(\"Hello, %s!\\n\", name);<\/span>\r\n<span style=\"color: #888888\">}<\/span>\r\n<\/pre>\n<\/div>\n<p>To compile the library we will add a new build task\u00a0<span style=\"color: #000080\">build\/lib.bat<\/span>:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #0000ff\">mkdir<\/span> bin<span style=\"color: #666666\">\/<\/span>lib\r\n<span style=\"color: #0000ff\">gcc<\/span> <span style=\"color: #666666\">-Isrc<\/span><span style=\"color: #666666\">\/<\/span>lib <span style=\"color: #666666\">-<\/span>c src<span style=\"color: #666666\">\/<\/span>lib<span style=\"color: #666666\">\/<\/span>lib<span style=\"color: #666666\">.<\/span>c <span style=\"color: #666666\">-<\/span>o bin<span style=\"color: #666666\">\/<\/span>lib<span style=\"color: #666666\">\/<\/span>lib<span style=\"color: #666666\">.<\/span>o\r\n<\/pre>\n<\/div>\n<p>If we look at the dependency graph before running Stroll we&#8217;ll see:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-3-add-lib-bat.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-3-add-lib-bat.png\" alt=\"Dependency graph\" width=\"390\" \/><\/a><\/p>\n<p>The new task <span style=\"color: #000080\">lib<\/span> appeared in the graph but without any dependencies; it is marked as out-of-date because Stroll has never executed it. If we run Stroll now, it will execute both tasks reaching the following state:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-4-build-all.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-4-build-all.png\" alt=\"Dependency graph\" width=\"630\" \/><\/a><\/p>\n<p>The tasks are currently independent and can be built in parallel but let&#8217;s make use of the library by modifying the <span style=\"color: #000080\">main<\/span> source file as follows:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #bc7a00\">#include &lt;lib.h&gt;<\/span>\r\n\r\n<span style=\"color: #b00040\">int<\/span> <span style=\"color: #0000ff\">main<\/span>()\r\n{\r\n    greet(<span style=\"color: #ba2121\">\"World\"<\/span>);\r\n    <span style=\"color: #008000;font-weight: bold\">return<\/span> <span style=\"color: #666666\">0<\/span>;\r\n}\r\n<\/pre>\n<\/div>\n<p>If we run Stroll now, the build will fail:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> stroll build\r\n<span style=\"color: #888888\">Executing build\/main.bat...<\/span>\r\n<span style=\"color: #888888\">Script build\/main.bat has failed.<\/span>\r\n<span style=\"color: #888888\">Done<\/span>\r\n\r\n<span style=\"color: #000080;font-weight: bold\">$<\/span> cat build\/main.bat.stderr\r\n<span style=\"color: #888888\">A subdirectory or file bin already exists.<\/span>\r\n<span style=\"color: #888888\">src\\main.c:2:17: fatal error: lib.h: No such file or directory<\/span>\r\n<span style=\"color: #888888\">compilation terminated.<\/span>\r\n<\/pre>\n<\/div>\n<p>By examining the file <span style=\"color: #000080\">build\/main.bat.stderr<\/span>\u00a0helpfully created by Stroll, we can see that the build failed because we forgot to modify the build script and point\u00a0<span style=\"color: #000080\">gcc<\/span> to our library. An error is visualised by a task with a double border:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-5-build-error.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-5-build-error.png\" alt=\"Dependency graph\" width=\"630\" \/><\/a><\/p>\n<p>Let&#8217;s fix the script <span style=\"color: #000080\">main\/build.bat<\/span>:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #0000ff\">mkdir<\/span> bin\r\n<span style=\"color: #0000ff\">gcc<\/span> <span style=\"color: #666666\">-Isrc<\/span><span style=\"color: #666666\">\/<\/span>lib src<span style=\"color: #666666\">\/<\/span>main<span style=\"color: #666666\">.<\/span>c bin<span style=\"color: #666666\">\/<\/span>lib<span style=\"color: #666666\">\/<\/span>lib<span style=\"color: #666666\">.<\/span>o <span style=\"color: #666666\">-<\/span>o bin<span style=\"color: #666666\">\/<\/span>main<span style=\"color: #666666\">.<\/span>exe\r\n<\/pre>\n<\/div>\n<p>With this fix, Stroll completes successfully and produces the following dependency graph:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-6-fix-error.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-6-fix-error.png\" alt=\"Dependency graph\" width=\"530\" \/><\/a><\/p>\n<p>We can now demonstrate the <em>early cut-off<\/em> feature by adding a comment to the file <span style=\"color: #000080\">src\/lib\/lib.c<\/span>. Before running Stroll let&#8217;s check that this change makes both <span style=\"color: #000080\">lib<\/span> and <span style=\"color: #000080\">main<\/span> out-of-date:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-7-add-comment.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-7-add-comment.png\" alt=\"Dependency graph\" width=\"530\" \/><\/a><\/p>\n<p>As you can see, both tasks are now marked as out-of-date: <span style=\"color: #000080\">lib<\/span>\u2019s direct input has changed, which transitively also affects <span style=\"color: #000080\">main<\/span>. Let&#8217;s Stroll:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> stroll build\r\n<span style=\"color: #888888\">Executing build\/lib.bat...<\/span>\r\n<span style=\"color: #888888\">Done<\/span>\r\n<\/pre>\n<\/div>\n<p>Stroll has rebuilt the library but the file <span style=\"color: #000080\">bin\/lib\/lib.o<\/span> didn&#8217;t change, thus restoring the up-to-date status of the task\u00a0<span style=\"color: #000080\">main<\/span>.<\/p>\n<p>Finally, to clean up after our experiments, let&#8217;s create a new task <span style=\"color: #000080\">clean<\/span> and place it into a different directory: <span style=\"color: #000080\">clean\/clean.bat<\/span>.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> cat clean\/clean.bat\r\n<span style=\"color: #888888\">rm bin\/lib\/lib.o<\/span>\r\n<span style=\"color: #888888\">rm bin\/main.exe<\/span>\r\n\r\n<span style=\"color: #000080;font-weight: bold\">$<\/span> stroll clean\r\n<span style=\"color: #888888\">Executing clean\/clean.bat...<\/span>\r\n<span style=\"color: #888888\">Done<\/span>\r\n<\/pre>\n<\/div>\n<p>The corresponding dependency graph shows two outputs &#8212; the deleted binary files.<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-8-clean.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-8-clean.png\" alt=\"Dependency graph\" width=\"300\" \/><\/a><\/p>\n<p>As you might have noticed, Stroll uses directories as collections of build tasks related to a common build target. To build a target we simply run Stroll in the corresponding directory. If you&#8217;d like to build just a single task from a directory, you can specify the full path, for example:<\/p>\n<div style=\"background: #f8f8f8;overflow: auto;width: auto;padding: 0em;margin: 0em 0em 1em\">\n<pre style=\"margin: 0;line-height: 125%\"><span style=\"color: #000080;font-weight: bold\">$<\/span> stroll build\/lib.bat\r\n<span style=\"color: #888888\">Executing build\/lib.bat...<\/span>\r\n<\/pre>\n<\/div>\n<p>This executes the\u00a0<span style=\"color: #000080\">lib<\/span>\u00a0task (regardless of its current status). Note that the <span style=\"color: #000080\">main<\/span> task is currently out-of-date because <span style=\"color: #000080\">clean<\/span> deleted its output:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-9-build-lib.png\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2019\/07\/stroll-9-build-lib.png\" alt=\"Dependency graph\" width=\"530\" \/><\/a><\/p>\n<p>To complete the build, run <span style=\"color: #000080\">stroll build<\/span>, which will execute only the <span style=\"color: #000080\">main<\/span> task, as desired.<\/p>\n<p><span style=\"color: #000080\"><strong>Challenge:<\/strong> <\/span>Try to orchestrate a situation, where Stroll would execute one of the tasks twice, hence demonstrating that Stroll is not a minimal build system.<\/p>\n<h3>Under the hood<\/h3>\n<p>Stroll is implemented in ~400 lines of Haskell (including comments) and uses the following libraries in addition to the standard ones:<\/p>\n<ul>\n<li><a href=\"http:\/\/hackage.haskell.org\/package\/shake\">Shake<\/a>\u2019s <span style=\"color: #000080\">cmd<\/span> function is used to execute build tasks tracking their file accesses. This relies on Shake&#8217;s support of the <a href=\"https:\/\/github.com\/jacereda\/fsatrace\"><span style=\"color: #000080\">fsatrace<\/span> utility<\/a>.<\/li>\n<li>The algebraic graphs library <a href=\"https:\/\/hackage.haskell.org\/package\/algebraic-graphs\">Alga<\/a> is used for graph construction, traversal and visualisation.<\/li>\n<li>Libraries <a href=\"https:\/\/hackage.haskell.org\/package\/cryptonite\">cryptonite<\/a> and <a href=\"https:\/\/hackage.haskell.org\/package\/yaml\">yaml<\/a> are used for computing file content hashes and serialising\/deserialising YAML files.<\/li>\n<\/ul>\n<p>Many thanks to everyone who contributed to these projects!<\/p>\n<p>You are welcome to <a href=\"https:\/\/github.com\/snowleopard\/stroll\">browse the source code<\/a> of Stroll and\/or play with it, but be warned: it has a few serious limitations (discussed below), and I&#8217;m not sure they will ever be fixed.<\/p>\n<h3>Limitations<\/h3>\n<p>Stroll is fun and I consider it a successful experiment but the current implementation has a few serious limitations:<\/p>\n<ul>\n<li>The <span style=\"color: #000080\">fsatrace<\/span> utility does not track reads from non-existing files, which means Stroll cannot determine that a task is out-of-date because a file that was previously missing has now appeared. Directory scans are not tracked either, that&#8217;s why I didn&#8217;t use a command like <span style=\"color: #000080\">rm -rf bin\/*<\/span> in the <span style=\"color: #000080\">clean<\/span> script. A model of Stroll with ideal tracking that is free from these limitations is available <a href=\"https:\/\/github.com\/snowleopard\/build\/blob\/3cc873c3d30615a60757be1424bef31d892cd0b9\/src\/Build\/Task\/Opaque.hs\">here<\/a>.<\/li>\n<li>Although <span style=\"color: #000080\">fsatrace<\/span> can track file movement, e.g. <span style=\"color: #000080\">mv src dst<\/span>, Stroll does not yet support it and terminates with an error if detected.<\/li>\n<li>The current implementation is completely sequential, i.e. build tasks are executed one by one. It&#8217;s possible to make Stroll parallel, but it&#8217;d require quite a bit of engineering. I might do it someday.<\/li>\n<li>Stroll is not a cloud build system although it&#8217;s possible to make it one by adding shared storage of artefacts keyed by their hashes. For more details see the <a href=\"https:\/\/dl.acm.org\/ft_gateway.cfm?id=3236774\">Build Systems \u00e0 la Carte paper<\/a>.<\/li>\n<\/ul>\n<h3>Final remarks<\/h3>\n<p>One interesting aspect that I haven&#8217;t demonstrated above is how one can mix and match different languages when writing individual build tasks. For example, we could use <a href=\"https:\/\/shakebuild.com\/\">Shake<\/a> for compiling C source files into object files. Note that Shake itself is a build system that maintains its own state, but it still works out just fine: if Shake decides to rebuild only one object file (since others are up-to-date) Stroll can safely remember this decision &#8212; as long as all input files are the same and the Shake&#8217;s database is unchanged, we can assume that the results produced by Shake previously are still valid. This means that even though Stroll&#8217;s task granularity may be quite coarse (e.g. one task for 100 object files), these coarse-grain tasks can benefit from fine-grain incrementality and parallelism supported by other build systems, such as Shake. And if you happen to have two existing build systems written in different languages you don&#8217;t need to rewrite anything: you can <em>compose your legacy build systems simply by placing them into the same directory and using Stroll<\/em>.<\/p>\n<p>Unusually, Stroll can cope with cyclic task descriptions, where a few build tasks form a dependency cycle, as well as with build tasks that generate new build tasks! Stroll simply keeps building until\u00a0reaching a fixed point where all tasks are up-to-date.<\/p>\n<p>Stroll does not fit the modelling approach from the <a href=\"https:\/\/dl.acm.org\/ft_gateway.cfm?id=3236774\">Build Systems \u00e0 la Carte paper<\/a>, where build tasks have statically known outputs: Stroll supports both <em>dynamic inputs and dynamic outputs<\/em>. I conjecture that such build systems cannot be minimal, i.e. they fundamentally require a trial and error approach used by Stroll, where unnecessary work may be performed while discovering the complete dependency graph.<\/p>\n<h3>Acknowledgements<\/h3>\n<p>I&#8217;ve been thinking about this idea for a while and had many illuminating discussions with Ulf Adams, Arseniy Alekseyev, Jeremie Dimino, Georgy Lukyanov, Neil Mitchell, Iman Narasamdya, Simon Peyton Jones,\u00a0 Newton Sanches, Danil Sokolov, and probably others. A few people in this list have been sceptical about the idea, so I do not imply that they endorsed Stroll &#8212; I&#8217;m merely thankful to everyone for their insights.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;d like to share an experiment in developing a language-agnostic build system\u00a0that does not require the user to specify dependencies between individual build tasks. By &#8220;language-agnostic&#8221; I mean the user does not need to learn a new language or a special file format for describing build tasks &#8212; existing scripts or executable files can be &hellip; <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/stroll\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Stroll: an experimental build system<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1174,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,6,3],"tags":[14],"class_list":["post-1133","post","type-post","status-publish","format-standard","hentry","category-algorithms","category-coding","category-thinking","tag-build"],"_links":{"self":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/1133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/users\/1174"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/comments?post=1133"}],"version-history":[{"count":62,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/1133\/revisions"}],"predecessor-version":[{"id":1208,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/1133\/revisions\/1208"}],"wp:attachment":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/media?parent=1133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/categories?post=1133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/tags?post=1133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}