4 ms·
this is from 2012 and some of the points haven't aged well (see blaze/bazel)
by sabujp 6y ago
this is from 2012 and some of the points haven't aged well (see blaze/bazel)
- RealityVoid 6y agoNot familiar with bazel. Can you expand a bit?
- klodolph 6y agoThere are a few things which are either enforced directly by Bazel (i.e., Bazel takes an opinion on how build systems should work and gives an error if you try to make it work otherwise). There are also a few assumptions which are now harmless, because Bazel will either check that your assumptions are correct, or make the build work as if those assumptions hold. For example, "Build graphs are acyclic." Bazel enforces this. "Every build step updates at least one file." If your build step doesn't produce output, Bazel will complain. "It's possible to tell the compiler which file to write its output to." "It's possible to tell the compiler which directory to write its output to." Bazel does this with sandboxes.
- carlmr 6y agoWhich ones and why? Is blaze/bazel free of all these falsehoods. Did it manage to make new mistakes?
- sabujp 6y agoI'm no blaze/bazel expert (hopefully someone will add their own thoughts), but: 1. build graphs are trees/acyclic : bazel enforces this, no cyclic dependencies allowed 2. Compilers will always modify the timestamps on every file they are expected to output : if a write happens why not update mtime? nanosecond precision, what year is it? 3. It's possible to tell the compiler which file to write its output to : makes no sense to me, we expect our compilers to be writing to the correct files in the correct directories. 4. It's possible to predict in advance which files the compiler will update : yes it is, this is how caching works again see (1) 5. It's possible to determine the dependencies of a target without building it : yes yes it's completely possible given (1) 6. Detecting changes via file hashes is never the right thing : Bazel i think uses a combination of hashes and stamps, but why would using hashes not work 99.99999999999999998% of the time? 7. Non-experts can reliably write portable shell script : lol, experts can't reliably write portable shell scripts either 8. Your build tool is a great opportunity to invent a whole new language: or just coopt pieces of one (python: starlark, skylark) 9. Said language does not need to be a full-featured programming language : yes, it doesn't (again .bzl files) 10. Said language should be based on textual expansion : not sure what the alternative to textual expansion (parsing?) is 11. Adding an Nth layer of textual expansion will fix the problems of the preceding N-1 layers : again how is this different from parsing
- deleted 6y ago[deleted]
- tzs 6y agoOT: when did HN start wrapping long lines in indented text?
- SilasX 6y agoIt's not because the lines are long but because they're prefixed by four spaces (and for anyone reading, please don't do that unless it's actual code).
- tzs 6y agoIt's wrapping lines prefixed with two spaces now. The comment I just posted a couple minutes ago with indented shell input and output definitely used two spaces and it is wrapping on my phone and on my desktop if I narrow the window enough.
- tzs 6y ago> 2. Compilers will always modify the timestamps on every file they are expected to output : if a write happens why not update mtime? nanosecond precision, what year is it? It has nanosecond precision, but on most systems it does not have nanosecond resolution. $ touch a1; sleep .0001; touch a2; stat a1 a2 | grep Modify: Modify: 2020-07-18 21:37:56.421487075 +0000 Modify: 2020-07-18 21:37:56.421487075 +0000 $ touch a1; sleep .0001; touch a2; stat a1 a2 | grep Modify: Modify: 2020-07-18 21:37:57.397502229 +0000 Modify: 2020-07-18 21:37:57.397502229 +0000 $ touch a1; sleep .0001; touch a2; stat a1 a2 | grep Modify: Modify: 2020-07-18 21:37:58.273515840 +0000 Modify: 2020-07-18 21:37:58.277515902 +0000 $ touch a1; sleep .0001; touch a2; stat a1 a2 | grep Modify: Modify: 2020-07-18 21:41:00.736348218 +0000 Modify: 2020-07-18 21:41:00.736348218 +0000 $ touch a1; sleep .0001; touch a2; stat a1 a2 | grep Modify: Modify: 2020-07-18 21:41:01.708363288 +0000 Modify: 2020-07-18 21:41:01.708363288 +0000 $ touch a1; sleep .0001; touch a2; stat a1 a2 | grep Modify: Modify: 2020-07-18 21:41:02.504375653 +0000 Modify: 2020-07-18 21:41:02.508375715 +0000 Note that the difference is either 0 or 0.004000062. This is on a Debian 9 system running on an Amazon Lightsail instance with an ext4 filesystem. Here's a quick and dirty script to play with this: C=0 R=0 while : do R=$((R+1)) touch a1; sleep $1; touch a2 T1=$(stat a1 | grep Modify | sed -e 's/.*://' | sed -e 's/ .*//') T2=$(stat a2 | grep Modify | sed -e 's/.*://' | sed -e 's/ .*//') if [ $T1 != $T2 ]; then dc <<HERE 20k $T2 $T1 - p HERE C=$((C+1)) if [ $C -eq 100 ]; then echo "$R runs" exit 0 fi fi done Output on the above system: $ bash t.sh 0.001 | sort | uniq -c 4 .004000061 83 .004000062 13 .004000063 1 222 runs and on a VMWare Fusion VM running Debian 8 on my Mac: $ bash t.sh 0.001 | sort | uniq -c 29 .003999599 44 .003999600 27 .003999601 1 323 runs
- gravypod 6y agoThese are some of my personal opinions from using, and violently advocating for, bazel: > Build graphs are trees. Build graphs are acyclic. Bazel uses some tricks/magic to hide outputs of build rules from other build rules. Bazel also prevents cyclic dependencies (A depends on B which depends on A). > Compilers will always modify the timestamps on every file they are expected to output. Source files a target depends on will be hashed. The operations applied to the files will also be hashed. > It's possible to determine the dependencies of a target without building it. Bazel forces people to explicitly define all deps that the source code uses. It uses sandboxing to hide unspecified deps from the source code. All of the definition of these rules is defined statically-ish (if you ignore WORKSPACE which technically applies to Blaze). > Targets do not depend on the rules used to build them. Bazel hashes the operations the rules will perform. > Targets depend on every rule in the whole build system. Bazel understands the full DAG and knows what each target depends on and what depends on each target. > Detecting changes via file hashes is always the right thing. Detecting changes via file hashes is never the right thing. It's a tradeoff that someone has to decide. Neither is right or wrong. Using a file content+metadata hash allows you gauntness that the build is always correct. > It's possible to narrow down the set of possibly-updated files to a small hand-enumerated set. As long as you use file hashing and are explicit about your inputs and outputs of every build rule, you can. > Nobody will ever want to rebuild a subset of the available dirty targets. You can build a specific target and it's deps at any time. Unrelated dependency trees are ignored. > stat is slow on modern filesystems. Anything is slow given a large enough scale. Any syscall is slow once you have millions of source files. > Non-experts can reliably write portable shell script. In bazel people interact with higher level rules. You don't need to write shell scripts unless you're implementing something that requires shell scripts. If you'd like you can also use an output of a target as a tool to do further compiling. For example: build protoc then use protoc to compile protos into libraries. Every build step updates at most one file. Every build step updates at least one file. It's possible to tell the compiler which file to write its output to. It's possible to tell the compiler which directory to write its output to. It's possible to predict in advance which files the compiler will update. > Your build tool is a great opportunity to invent a whole new language. Said language does not need to be a full-featured programming language. In particular, said language does not need a module system more sophisticated than #include. Said language should be based on textual expansion. Adding an Nth layer of textual expansion will fix the problems of the preceding N-1 layers. It is a great opportunity to implement a domain specific language as "building software" is a domain that we would like to define programs for. Bazel uses skylark, it's a "fully featured" programming language in that there's loops, conditionals, functions (called "macros"), and a module-ish system ("load()"). It does not operate on textual expansion. > It's totally OK to spend over four hours calculating how much of a 25-minute build you should do. Bazel's target analysis takes a while but for my scale of code base it doesn't take hours, it takes seconds. If you have a huge codebase then these "wasted" seconds would be earned back by it's effective caching and remote build execution. > All the code you will ever need to compile is written in precisely one language. Bazel is multilingual. > Everything lives in a single repository. What is a "repository"? It's really a file system. What is a file system? A fancy kv store. Could you build a KV store that could return the values for every key that is a file in your source tree? Probably. Bazel is built around a monorepo design but you could just as easily clone libraries into shared folders and executre bazel from above your project. You could also use remote repository rules. IMO you're better off just vendoring any source code you're writing in a folder in your repo so you can guarantee old versions of things are around when you need them and you never have a leftpad incident. > Files only ever get updated with timestamps by a single machine. Version control systems will always update the timestamp on a file. Version control systems will never update the timestamp on a file. Version control systems will never change the time to one earlier than the previous timestamp. File contents are check so this is not as much of an issue. > Programmers don't want a system for writing build scripts; they want a system for writing systems that write build scripts. I think people don't want systems like this because they've been burned. I've used a lot of makefile generators and they're all a really poor caching system. You essentially make cache invalidation part of your dev flow. AS a developer I don't want to think about that. I want to ask something to build me something and have it know when it needs to reload build definitions or code. I also don't want to care about what specific "gcc" or "javac" commands are being run. I need to be able to go down to that level but 99% of the time I just need to say "Turn a.c, b.c, and c.c into foobar.bin". As for what bazel is really bad at, these all still apply: > People will only want to build software on Linux. People will only want to build software on a Unix derivative. Nobody will want to build software on Windows. People will only want to build software on Windows. Bazel support in windows is shaky. Bazel itself works but many tools (rules_docker) do not work. One place bazel would be really amazing for, in my opinion, is the game development industry. You have massive source trees, very complex packaging steps, you often have tools that are used as a compiler further in the compilation process (asset packets), you can benefit from shared build clusters, etc. > Single-character magic variables are a good idea in a language that most programmers will rarely use. Not the same but make-like variable substitution exists and it's a bit of a pain: https://docs.bazel.build/versions/master/be/make-variables.html https://docs.bazel.build/versions/master/be/make-variables.h... > System libraries and globally-installed tools never change. Version numbers of system libraries and globally-installed tools only ever increase. Bazel is mostly hermetic except for extremely strange things. Build toolchains that are "expected" to be in the host bleed in and effect a lot of things. It's a really gross side effect of certain things and can cause some nasty bugs. And for some new rules that bazel sins with: 1. People are ok with running builds on hosts of separate architectures to build their software for different architectures Cross compiling in bazel is extremely painful. 2. IDE integration doesn't matter. A lot of people who use bazel don't really care about how well, or how poorly, it integrates with an IDE. As such a lot of the open source world around bazel's IDE integrations are lack luster. Getting things like gRPC working in bazel with auto-completions for multiple languages is nearly impossible. 3. Everyone wants 100% reproducible builds. Many people do not want reproducible builds. That may sound shocking to some but a lot of other tools depend on non-reproducible elements of a build chain. For instance: when using bazel to build a docker container it sets the container's creation timestamp to the unix epoch. Because of this I cannot use Gitlab's registry cleanup script as it'll wipe all images since they're all over N days old. 4. All of the compilers I want to use during my build are installed on my host system. Docker was probably the most amazing improvement in build/tooling workflow in recent years. If I want to build something with docker all I need is docker. If bazel to make this workflow the same it could take over the world. If there was a single place to configure something like this: toolchains( arm: { c: "gcc:10.1.0" } x86: { c: "icc:....." } ) And if the default was that for any language not specified, it would either not be available or would be easily buildable from source as long as you have a C compiler. I don't know if this is the best way to represent this concept but I have no idea why I have to even be concerned what version my host OS ships of gcc. I also don't know why I have to care if my host system is x86 but I want to build a binary for arm. Either use cross compiling features of the compiler or spin up a VM and run the build using native tooling in there. I shouldn't have to manually do that.
- dmoy 6y agoYea y'all can pry blaze from my cold, dead hands. It may have its own problems, but working on a team that compiles things in like 10-15 different languages (c++, c#, go, java, javascript, typescript, lisp, haskell, blaze itself (whatever they call it now... skylark?), python, swift, kotlin, soon rust, a couple flavors of sql, etc), it saves us a lot of hassle.
- yegle 6y agoStarlark, because reasons.
- amelius 6y agoBazel is cute but doesn't solve the real problem that if one changes only a single line in a C file in general it is wasteful to recompile that file from scratch.