4 ms·
"Build is the first stage of execution" resonates with me too. It follows that build systems should be written in terms of real, encapsulated APIs that separat
by haberman 2y ago
"Build is the first stage of execution" resonates with me too.
It follows that build systems should be written in terms of real, encapsulated APIs that separate interface from implementation.
Make-like build systems are like programming in assembly language: there is no structure that isolates one build step from another. Make offers no way of creating a "local variable" -- an intermediate file that is hidden from any other build step. The filesystem is like memory: as long as you can figure out the filename (address) somehow, you can read and write whatever you want.
Even if you can declare that one build step depends on another, there's usually nothing that prevents a step from reading (or even writing!) files from other build steps that it did not declare a dependency on.
What you want is a build system that lets you define real APIs, with truly private state. For example, cc_library() in Bazel (cxx_library() in Buck2) lets you define a C++ library in terms of the srcs/hdrs/etc, but you don't know how it will be implemented. Other rules and targets can consume the outputs of cc_library(), but only the files that are publicly exposed in the returned providers.
This model brings true encapsulation to build systems, which makes it much more feasible to change implementation details without breaking users.
- necovek 2y agoIt's basically impossible to program with no side effects in any general purpose language, and providing a build system language likely requires side-effect rich APIs too (to write files, call external tools, etc). Which is to say that you can perfectly well implement a "clean" build setup with make, and provide an "interface" for parts of the system to tie into. Files and directories are as good an input/output interface as any other, and you can do some simple safeguards with permissions on directories and files. To create a local, intermediate file with make, you create a file in TMPDIR (eg with mktemp or tempfile) and remove it at the end, setting the permissions the way you want for any nested steps not to be able to access it.