Buck: A high-performance build tool
buckbuild.com
buckbuild.com
Uber is migrating from Buck to Bazel, for instance.
At Uber, the Java stack is still sort of ok w/ Buck (because Buck handles some things better there), so they're taking a wait-and-see approach until the Bazel ecosystem catches up w/ Buck on the concerns they care about. But long term, we are envisioning implementing a company-wide monorepo, and that sort of entails having a unified build system.
Pants - https://www.pantsbuild.org/index.html
Please.Build - https://please.build/
Closely related, but functioning bit different:
Gn - https://gn.googlesource.com/gn/ (targets ninja). Used by Chromium, Fuchsia, and others
Soong - https://android.googlesource.com/platform/build/+/master/REA... (targeting Kati?)
Kubeflow Pipeline (for ML) - https://www.kubeflow.org/docs/pipelines/pipelines-overview/
Tekton Pipeline - https://github.com/tektoncd/pipeline
TF Extended - https://www.tensorflow.org/tfx
Currently we marketing it for C++ but it can be used for any language that is supported by Buck.
Here a couple key points:
- Buck and Bazel are very similar.
- Buck currently models C++ projects better [1].
- Buck leverages remote caches currently better than Bazel [3] - Bazel is very easy to install
- Bazels "toolchains" make it very easy to onboard newcomers (to any project and language) but also ensure the build will run as expected.
- Bazel is less opinionated and more extensible than Buck.
In fact Bazel is so powerful that you can have Buildfiles that download a package manager and use it to resolve more dependencies. This is great to get things off the ground, but makes things less composable because the package manager won't see the whole dependency graph. As a result you might get version conflicts somewhere down the line.
To summarize: I think having a very opinionated build-system is easier to reason and scales usually better.
Communities with very opinionated packaging and build-systems are proving this by having orders of magnitude more packages that eg. the highly fragmented C++ community where configuration is prefered over convention.
> Have you considered offering support in Bazel for your package manager?
Yes we did. As soon as this feature [1] is implemented we will have a 1:1 mapping for C++ Buck Projects and Bazel. Then after a small (automated) refactoring of our Buckaroo packages, you should be able to build any package from the Buckaroo ecosystem with either Buck or Bazel.
Btw. The cppslack community is attempting to create a feature matrix of various build-systems here [2]
[1] https://github.com/bazelbuild/bazel/issues/7568
[2] https://docs.google.com/document/d/1y5ZD8ETyGtxCmtT9dIMDTnWw...
To me the biggest added value of Bazel is the remote (build and test) execution (which will get a nice performance boost from https://github.com/bazelbuild/bazel/issues/6862 in Bazel 0.25; also mentioned in [3]).
(Your [3] doesn't compare Bazel and Buck, only Bazel with remote caching and without it, so it's not clear from it that Buck leverages caches better than Bazel).
And one nit, Bazel doesn't allow you to download anything in the loading, analysis, or execution phases ("the BUILD files"), those are completely hermetic, sandboxed, and reproducible (when compilers are). The package manager integrations happen when resolving external repositories ("the WORKSPACE file"), where non-hermetic behavior is allowed and is used e.g. to autoconfigure C++ toolchain, or download npm packages.
Here is what I would like to achieve in own projects:
1. Work on a NodeJS project A that can locally install NPM packages based on packages.json.
2. Have another Python or Go project that build depends on project B.
3. The build tool allows the dependencies pulled either from artifact repository or use checked out version locally.
This build system focuses on the WHAT to build vs HOW to build, which will be driven by project's own build tool, e.g. ant, npm, maven, etc.
I am considering creating my own simple build tool which is inspired by the Amazon's own tooling.
BTW, does not anyone know if I am allowed to develop my own tooling inspired on company's internal tooling? Obviously it won't be exactly the same but taken with lots of inspirational values.
Here is more details on the Amazon's build tool: https://gist.github.com/terabyte/15a2d3d407285b8b5a0a7964dd6...
- Support for thousands of related and unrelated codebases in the same repo, with a nuanced understanding of dependencies so that all "dirty" objects, and no others, are rebuilt/retested for each change.
- Hermetic builds to weed out undeclared dependencies.
- Support for remote build cache / remote build workers.
- Understanding of many unrelated languages.
I can't imagine GNU Make being reasonable in this kind of use case. What would you choose?
Now they have to maintain a fork instead. What's worse is they likely wont know how it works in a year's time, imagine in a few years when they need him to update the library.
Sometimes it's better to buy a library than to waste resources reinventing someone else's tried and tested wheel.
I, for one, applaud the effort. Maybe someday we can finally relegate CMake to the dustbin of history.
However there are still some differences: Buck is much more opinionated than Bazel. Buck models slightly better C++ projects[1] and currently it's remote cache is more efficient[2].
Bazel is more extensible and offers also remote execution. Bazel has a bigger community and it's roadmap is public.
There has been more than 350 C++ [4] libraries been ported to Buck for the Buckaroo Package Manager[3].
There are also technical details that manifest in some odd ways but are not significant. There is a nice paper by Simon Peyton Jones (creator of haskell) and others that goes into the design details [5]
[1] https://github.com/bazelbuild/bazel/issues/7568
[2] https://github.com/bazelbuild/bazel/issues/7664
[3] https://github.com/LoopPerfect/buckaroo
[4] https://github.com/buckaroo-pm
[5] https://www.microsoft.com/en-us/research/uploads/prod/2018/0...
Happy to go more into detail if desired
I haven't worked with Buck myself, but colleagues who evaluated it for JS have expressed concerns with lack of support/ecosystem there as well. In comparison, there are various Bazel rulesets for JS/Typescript, and I've had some pretty good experience w/ implementing rules myself. The Starlark docs are good.
Another thing going for Bazel is its ability to embed external codebases into a build system. This mechanism allows rules to be shared among repositories in a reusable fashion.
https://redo.readthedocs.io/en/latest/
Very different, never used it, but very interesting nonetheless.
However, it doesn’t do things buck and Bazel do such as making sure only declared files are indeed used, or tracking compiler and toolset versions on its own.
At least one of these new-fangled tools gets at least one part right. The salient point is now of course whether Buck considers the correct set of dependencies as well as negative dependencies.
Or do I misunderstand something here?
it's understandable why programmers have opinions about aesthetics regarding their IDE, language, or framework of choice, but what is there to be opinionated about with a build system?
I think you're saying this because your idea of a "build system" is a very simple set of sequential steps from known source code input files to an output binary.
The differing opinions come in when the "build system" includes various contradictory philosophies of how to configure and specify the building of complex software.
Different opinions on:
- syntax : should build config be XML, or JSON, or YAML, or custom syntax? E.g. Ant and Maven used XML but Gradle does not
- dependencies search: should build system implicitly find and add relevant dependencies? Or should programmer explicitly specify each one?
- reproducible builds (version pinning) vs auto-updated dependencies.
- should the build system be "smart" about cross-platform differences? If yes, you end up with complicated build tools like GNU Autoconf "configure" bash script, or CMake's complex syntax.
- should build system do optimization and bundling tasks that's not strictly limited to "compile" steps? Some Javascript build tools try to eliminate redundant or unused js code to make downloads smaller.
- etc, etc.
I also recommend reading the blog post "So you want to write a package manager"[1] to get an idea of how complicated a build system can get. The title says "package manager" but much of the material is also about build systems.
The bottom line is that reasonable people can disagree on the priorities and therefore, you can't create The One & Only Build System to End All Other Build Systems.
[1] https://medium.com/@sdboyer/so-you-want-to-write-a-package-m...
It’s great that Timmy thinks an obscure extension of YAML is the best way to define build configs, but all the rest of the engineers use JSON, so that is what we use.
Perhaps because the incumbent/popular build systems are far from being the best solution for the job, particularly when compared with build systems available for other technologies.
For instance, in C and C++ land the incumbents are still hand-written Makefiles, autotools, or cmake, which leave much to be desired.
- system requirements
- convention vs configuration
- flexibility vs predefined paths
- tradeoff features vs their complexity (parallelism, caching, ...)
- level of integration with specific other tooling (VCS, languages, package managers, ...)
Consider this makefile rule:
foo.a: $(patsubst %.c,%.o,$(wildcard *.c))
Now, the foo.a target will be considered as stale if any of timestamps of it's dependencies is newer than foo.a
But what if you remove a .c file?
As build systems like make don't capture a fingerprint of the names of the inputs of a built (let alone the hash of their contents) it's very hard for them to deal with that case correctly.
Correctness is important otherwise your trust in the incremental builds quicky erodes and you start doing clean builds all the times you get an error, just in case.
The blog post [0] also contains arguments against checksums: Sometimes building a target has side effects. Checksumming every output after building it is somewhat slow. Checksumming every input file before building is very slow.
What matters is keeping track of the actual dependencies and Redo does indeed save that knowledge in a database that gets consulted between runs.
Last year I learned about .PRECIOUS and it was awful
Bazel does ecosystem and language agnostic distributed builds with both GCP and self-hosted solutions.
Here's a demonstration of building the Angular project remotely: https://youtu.be/lDyIc2Abkwg?t=593