When I find the time I hope to write bindings for netlink for prolog, so that I can declaratively create and configure network namespaces. Complete declarative system configuration using prolog would be a dream come true.
What is steep is the technical know-hows:
1. When things don't work as expected. For example, while it worked flawlessly with languages that it natively support such as Java, that wasn't the case for other languages such as Javascript or Python.
2. When you have to do something advanced such as building custom Bazel rule. You'll need to understand Bazel internals and unfortunately the documentation isn't very intuitive and also somewhat sparse.
Very telling: "common c++ use cases" https://docs.bazel.build/versions/4.2.2/cpp-use-cases.html includes pulling googletest source from the web and linking a random shared object blob. Zero mentions of pkg-config.
> pkg-config in my experience is less reproducible
But this is what I mean, you only want full reproducibility in a "corporate" environment. In a FOSS desktop environment you often specifically want to use whatever the system has.
Compared to other things in Bazel maybe, sure. But if you're just building Go binaries you don't need Bazel. The standard Go tooling is beyond sufficient: it's hard to beat.
I second GP's assessment that Bazel is pretty developer-hostile if you are not Google or have Google's resources to maintain Google's build systems.
Case in point: get Bazel to consume system libraries or vended/third-party dependencies in a C++ project. This is a pretty basic usecase, but it was left as an afterthought in Bazel, and it's an uphill battle just to get Bazel to work with them.
I don't doubt that Bazel can be usable if your entire world is locked tight in repos you control and were all forced to migrate to Bazel. It's the same thing with GYP, another developer-hostile build system spawned there. However, that is not how the world outside of Google works.
The only way I see Bazel become relevant and usable for non-Google/FANG-size orgs is if a higher level build system like CMake supports generating Bazel code, so that all these shortcomings are brushed under the proverbial rug. However, if we get to that, are we really using Bazel, or is Bazel relegated to an implementation detail?
I teach Bazel and help companies adopt it. I’ve noticed that a high percentage of those using Bazel have one or more xooglers on their team.
> I teach Bazel and help companies adopt it.
The very fact that this occupation exists pushes me away from Bazel, having never used it. Makefiles are horrible, but they are well documented and I've been able to google my way out of every problem that I've either run into, inadvertently caused, or had to debug from somebody else's mess (it's always a mess).I don't actually want a better build tool. I want a tool that I spend as little time as possible thinking about.
That might be fine in an enterprise setting where the user likely has a mentor or support contract to turn to. But it's not what I want at home.
It's that it requires a lot of boilerplate and has a very rigid nested structure... which compounds boilerplate, unless you venture into custom plugins/build rules.
Some of the basic ideas are absolutely right, e.g. separating the resolution of dependencies from the build, and purity, but it's just soooo much boilerplate.
But IMHO Bazel's fundamental flaw is that it tries to be a one size fits all solution that's supposed to work for all languages and ecosystems. That pretty much guarantees that it will have more need for boilerplate/configuration, be less performant, have more bugs, and at the end of the day just offer a worse user experience than a build system that applies all of Bazel's underlying ideas/techniques while being designed solely for a single language/ecosystem and more deeply integrated into it.
I think the eventual best case scenario for Bazel is a jack of all trades, master of none, but in its current state, for most of the languages/ecosystems it claims to support, it would be way too generous to even call it a jack of the trade in terms of overall UX.
Git emerged decades after other version control systems were first invented, and found a neat abstraction that covered the space.
That's why I have such hope for the BSalC paper and what can emerge from it.
One thing redo is missing for me is support for building things in a different directory. It's a nice-to-have feature but it's difficult to envision how such a redo would work. Really overlays actually solve this problem, although a fuse based overlayfs would also be nice (so you can use it without needing to escalate privileges).
Bazel does not put outputs in random folders, it puts them in folders that are a deterministic mapping from the build target plus relative path to the thing being built in the source directory. It is well-suited if you have a huge amount of source code with things being output, but one among many speed bumps when getting started.
1. I convert all paths to abspaths;
2. All intermediate products go into a temp dir;
3. All recipes are functions;
4. The set of objects are defined by a “find . -name ‘…’” for C sources;
5. Every C file depends on every header file in the repo;
6. Use ccache; and,
7. Deterministic build.
My big work project is ~20mm loc, including ~65 FW images (embedded OSes). Incremental compilation is ~300ms. Clean rebuilds are 30-40s; scratch builds are 8m. (All of this on ~4 year old MBP.)
Obviously, there are some design tricks to get raw compilation speed up — naive C++ only compiles at ~3kloc/s; it’s possible to get that up to 100kloc/s.
So change in single header file always becomes a full build? Do you use pimpl or other tricks to avoid frequent changes to h-files, otherwise class members usually end up in the headers for simplicity and to avoid incomplete type problems on non-pointers unfortunately. Was this C or C++?
What's the difference between a clean rebuild and a scratch build?
Unless I am mistaken, the author of https://cr.yp.to/redo.html never implemented the idea. He has since used only the Bourne shell and standard UNIX utilties as a build system instead of make. For example, consider the "do" script in this project: https://nacl.cr.yp.to
The "do" script was written circa 2011. The idea for "redo" was published circa 2003. The idea for "make" dates back to 1976. GNU Make was written around 1989. For the avoidance of doubt, I am not suggesting any of these build system ideas or implementations are better or worse than the others. That is for the reader to decide. I am only pointing out which one is the most recent, or most modern, if we use the word "modern" according to its dictionary definition.
Also, any "make" program for C should automatically detect dependencies between files because this information is present in the code and it doesn't make sense to duplicate it.
$ cat Makefile
CFLAGS := -MD -MP
hello: hello.o x.o y.o
-include *.d
$ echo '#include "x.h"' > x.c
$ echo '#include "y.h"' > y.c
$ touch x.h y.h
$ echo 'int main(void) {}' > hello.c
$ make
cc -MD -MP -c -o hello.o hello.c
cc -MD -MP -c -o x.o x.c
cc -MD -MP -c -o y.o y.c
cc hello.o x.o y.o -o hello
$ touch x.h
$ make
cc -MD -MP -c -o x.o x.c
cc hello.o x.o y.o -o hello* http://jdebp.uk./FGA/introduction-to-redo.html#CompilerDefic...
https://www.gnu.org/software/make/manual/html_node/Remaking-...
https://stackoverflow.com/questions/2131213/can-you-make-val...
This requires that either you implement or shell out to a C/C++ parser as part of the dependency resolution step (which has to happen prior to the actual compilation). This will slow down your compilation a lot unless you're able to parse C/C++ as fast as your make/bazel/whatever language.
Unfortunately, current C and C++ compilers do not emit all of the information that they possess internally, only less than half of it (the positive information about files found, not the larger amount of negative information about non-existent files that were searched and would change the build if they were to exist).
You have a.cc that depends on b.cc, but some tool generates b.cc, so it may not exist (but `b.do` does). If I invoke `a.do` to compile `a.cc`, and don't directly declare b.cc as a dependency in the .do file, the theoretical compiler will resolve that it depends on b.cc, and note that that doesn't exist, and then what?
In the bazel world, since you define the dependency graph explicitly before invoking any compiler, you can't run into this issue, but in situations where you need to get dep info from the compiler...what happens with stuff like this?
But why should all of these features be tackled by a single piece of software? Especially seeing how Make, in itself, has proven wildly insufficient already... what, 30 years ago, when GNU autotools came onto the scene?
More specifically, why do you find combinations such as meson + ninja, or CMake + ninja, or even CMake + make as superior to just-Make?
I haven't tried all the alternative combinations because, ultimately, I only have so much time and interest, and their learning curve is significant.
Make is really a complicated combination of these components:
- a dependency definition language with in-place evaluation and half-assed wildcards
- A functional language with extremely limited datatypes (effectively just space-separated strings)
- a clunky macro system
- A "distributed" topological execution engine (did you know Make can coordinate job slots across recursive executions of Make? It's impressive! And shouldn't have to exist!) [1]
All the alternative build systems wisely choose to tackle only some of these features. Redo is interesting in that it's a minimal system that leans on existing Unix tools to fill the gaps, but I can't say I'm impressed with using Shell as the scripting language, though it is arguably more useful than Make's home-grown language that too few people know. Edit: actually, redo's doesn't enforce Shell, it can be any executable. That's more interesting, maybe (flexibility also introduces complexity!)
The most interesting development in this space is the paper "Build Systems A La Carte" [2] by Mokhov, Mitchell, & Peyton Jones, who did a great job of breaking down build systems to their fundamental concepts, and along the way found one particular point of the design space that wasn't fulfilled (Table 2, p79:16). Unfortunately, I fear it'll be some years before something production-ready emerges from that research, (and I'm sure I'll be grumpy about some of their implementation details anyhow! Build systems do not a happy developer make)
[1] https://www.gnu.org/software/make/manual/html_node/Job-Slots...
[2] https://www.microsoft.com/en-us/research/uploads/prod/2018/0...