That changes drastically if your codebase contains a lot of C++ and your SW model doesn't quite match the way Bazel tries to push you into. For instance doing any of the following things will quickly turn into a nightmare when using the Bazel C++ rules:
* dynamically linking libraries
* using a containerized approach for library includes (so transitive relative include paths)
* using different toolchains and cross compiling
* interfacing with thirdparty libraries
We are talking seasoned build engineers ending up frustrated after literally months of trying to achieve something that is easy as pie in CMake.
In addition there is still no real IDE support. The CLion plugin is permanently broken and lags behind versions. No real VSCode support. Using custom rules makes this even worse, to the point where CLion will refuse to sync and not having a way to produce a compilation database json.
There are so many bugs open on those projects and no progress or answers. I can not recommend Bazel if C++ or C is what you care about.
But it's not the same as CMake. A properly set up Bazel project gives you so much more: organization-wide incremental builds, build cache and build farm. Also, actual full hermeticity of builds (no, taking ambient deps from a Docker container doesn't replace that).
Comparing CMake to Bazel is like comparing some barely-working bash scripts on a single box to a kubernetes deployment. Maybe you're okay with just bash scripts, but some of us aren't, and that's where Bazel comes in.
E.g. Google's protobuf libraries [1] can be built with Bazel, and they depend heavily on system headers outside the repository, e.g. <iostream> and <stdio.h> and lots more. If those headers subsequently change, Bazel will not pick up on this and will not know to rebuild the parts of the build that depend on them.
To reproduce: run `bazel build -c opt //:protoc_lib` and then put random garbage in your /usr/include/stdio.h and /usr/include/c++/<version>/iostream and then rerun the bazel command -- it will not know to invalidate the build cache. If you `bazel clean` and then build again, you'll get different results.
Bazel does a lot of really nice things and I can believe that within a google3-like environment (where the source code never references a system header?), it effectively provides hermetic builds, but in practice as used outside Google (or even in Google's public OSS releases) it doesn't seem to really match this description or enforce a hermetic seal. What am I missing?
All the complex things that Bazel brings into the game (distributed builds and caches primarily) simply don't have any value when the main task that you're trying to make faster is not done well.
I would much rather like to see more tooling that does these things but builds upon layers of battle-tested existing software.
I think this is something that's slowly, but surely, changing. There's a lot of adoption of Bazel from some big players out there (Uber, Bloomberg, etc). The Blaze team @ Google has also started incorporating outside OSS maintainers into their OSS software (specifically rules_python).
Things are improving. Many of the things you've addressed (third party libraries, cross compiling, dynamically linking things) have been talked about by many people in Bazel's slack. It might not be flawless currently but Bazel's abstractions of how builds work are cool, RBE/caching is amazing for large projects, and a single build system with the promise of gracefully handling "every" language is something our field has been needing for some time.
In 3 to 10 years I can imagine being able to start writing code and never think about which language some library I want to use is written in, which package manager and toolchain I need to use to build everything, how to package my code to be deployable in production, how to setup unit tests, how to get autocompltions and docs and everything in my IDE, etc. The answer could just be "bazel, a language server, an IDE that speaks lsp".
1. Set up sccache backing server (I use docker redis) 2. Export sccache config. Set SCCACHE_REDIS to a Redis url in format redis://[:<passwd>@]<hostname>[:port][/<db>]
Set CMAKE_<LANG>_COMPILER_LAUNCHER (cc, cxx) to sccache.
Starting a new project with it, so it can help you do things the "right way" is a much more attractive proposition.
That said, the IDE/tooling situation for Bazel was disappointing to me in the Java world too. It definitely lags and is incomplete.
And while Nix has an insane learning curve, figuring out how to extend Bazel (and consequently build one's own Python plugin) was a nightmare. The documentation was unhelpful/incomplete and the codebase was incomprehensible and poorly organized, with inheritance sprinkled on everything for its own sake (which is to say, par for the course for Java apps).
I know... "Don't look a gift horse in the mouth! / Don't complain about open source software!" Fair enough, but I don't have to use it, and I'm free to caution others not to as well.
We've been using Bazel not just to build and test our Go apps, but to build docker images, compile proto files, even deploy to k8s. It's really versatile and the developers only need to know one tool to build and test the whole environment.
Haven't run a bazel clean in... 6 months maybe?
The multi-language really is a killer feature when the project inevitably becomes polyglot, such as when doing protobuf/gRPC or using CGo.
Of course Bazel is far from perfect, in fact sometimes you may be better off running your own rules instead of the official ones in some cases, but IMO it makes a pretty decent build system for putting all of your code in one place.
On the other hand, it’s one of those Google things where if you haven’t seen it in action in a functional configuration it’s hard to explain why it’s actually nice. And sadly I feel unsatisfied with the Node.JS rules for example, which is probably how a lot of people will first experience Bazel (since I believe Angular supports Bazel this way.)
Bazel also come with a query tool that makes it easy to tell what other targets your package depends on. Go also has such a tool, but again it's limited to Go dependencies.
I believe Uber has been using bazel for awhile now, and probably were invested in it well before the Go module cache was a thing, so Bazel's build cache is an important optimization.
As the blog post notes, Makefiles are the usual weapon of choice for Go projects of any sufficient complexity, but these are quickly outgrown.
That said, I do agree with other posters that Bazel + go feels like nobody's priority. I use gopls and love it very much, but it doesn't understand how to ask Bazel where files are to analyze. A bug has been open for years, lots of people saying "I'll put it on my OKRs this quarter", and it's just not getting done. I am close to just fixing it myself.
But I have a feeling that this happens to everyone. I have worked on other Bazel projects and they all have detailed setup instructions; for example, Envoy uses Bazel but somehow shells out to cmake, so you have to have the right version of cmake, the right version of clang, etc. to produce a build. To me that defeats the purpose of using Bazel; Bazel should build the toolchain and all dependencies for you, otherwise what's the point? All you should need is Bazel and the source code. But that is not how people are using it. I don't know what the canonical successful Bazel project is, but I haven't found one yet.
I am currently working on a Typescript/Go project with gRPC/Web and will see if Bazel gets me that "one command full build" dream. I am somewhat motivated to make it work, but I have a feeling that there will be warts that makes me regret it. I used Bazel (well, the internal version) when I was at Google and every time I used it it was a joy. Incremental builds where you edited one file and wanted to run the tests were very fast, and builds where you modified some core library and wanted to see the impact across all the affected projects were also fast (easy to use 100s of CPU hours in just a few minutes of wall clock time).
Ultimately I think Bazel is the right approach, but I think to be successful you have to commit to having one engineer work on tooling full time. At your startup, probably not feasible. At Uber, probably very feasible.
(Going off topic, I would love to see what other people are doing for polyglot projects, because I feel like everything is a polyglot project these days. I have never seen a setup I liked -- install one program, check out the code, have a guaranteed working build that is bit-identical to the production image. The fact that nobody does this scares me deeply. But that's where we seem to be as a field.
I am also interested in seeing people's templates for projects. For example, I would like to do a C++ microcontroller project, and want to see how people are building those. I need clangd support, I need to use libraries, and everything I've seen is "hack together a makefile and cross your fingers". It just scares me.)
Uber reinvented a ton of technology because of the idea that off-the-shelf solutions wouldn’t work at “Uber scale”. However, there was very little accountability for whether the in-house solutions were necessary, and working on these tools would get you promoted. So for every “Uber scale” problem that a team actually solved, there were a couple other projects that were just half-baked alternatives to the off-the-shelf software that they should be using.
It turns out that “Uber scale” is not really that large, despite the name. But engineers kept repeating “Uber scale” and building infrastructure.
The same problem occurs at the larger tech companies like Google, Facebook, Microsoft, Amazon, and Apple, but in different ways and to different degrees. And to a large extent, engineers are copying what other companies do, and bringing ideas from one company to another when they hang out after work or switch jobs. For example, you can bet that these companies mostly have their own containerization and scheduling systems, many of which are undoubtedly not competitive with Docker or K8s in 2020, but K8s only goes back to 2014 and all these companies are older. I’m sure Borg and Tupperware are great if you work at Google or Facebook but I’m also sure that they’re missing a bunch of tooling that you’re used to. Same thing with build systems. Bazel, Buck, Pants, Please, and that Frankensteined system that Chrome uses are all copies of each other but Bazel is the only one with a decent size community and ecosystem, as far as I can tell.
Uber is absolutely not on the scale of those companies, and most of the time they should probably be using off-the-shelf solutions when they become available.
As a company, you have to invest immense resources in evolving the infrastructure and it is a never-ending task: the more capacity you build, the more your organization will grow in ways that tax that capacity. The goal posts are ever-receding.
As an individual developer, all that fancy distributed infrastructure becomes a barrier that must be laboriously overcome at every step. Your expectations about what constitutes a "fast" operation get gradually distorted. Working on "small" side-projects (a few thousand files or less) feels effortless in comparison.
Not to say you shouldn't seek out the "big tech" experience; just that it is not all roses.
One companies boring tool is another companies favourite hyped third-party tech tool. (Until it doesn't work for them)
Just like Kubernetes, Bazel is not a silver bullet. But if you get all your ducks in a row, switching over is a gamechanger and will help you out even at the smallest scale.
Having spent the last few weeks of my life converting our build system to Bazel I guarantee you it's far from what I would consider cool. It's more of a necessary evil because the alternatives are even worse.
FANG such as FB and Google has some big monorepos, and you can try that if you are interested.
That's a weird way to put it. Bazel is the open source variant of what Google uses for its monorepo, which is several orders of magnitude larger and arguably more complex.
That Google had to come up with Bazel for themselves only supports that point. It isn't obvious whether it'd then be applicable to other existing cases without customization
Lots of knobs that vary here tho, such as where one draws the line between configuration & customization
I have been tinkering with a few ideas to make the existing tooling work with Bazel, but the effort is larger than I had originally expected.
https://github.com/earthly/earthly
Disclaimer: I am Earthly's creator.
I work on a project with a Go backend and a React frontend, and having to update all those React dependencies myself is what keeps me from moving to a system like Bazel.
I have not seen metris or blogs that prove this "uptick in build efficiency" or an increase productivity.
While I do like the idea behind bazel, I hate repeating deps in things like "go_repository" with gazelle.
No go_repository duplication.
Monorepos are not efficient. They are easier to manage when a team is small but as the team grows and you have more and more deliverables with separate versioning you are introducing control structures in your automation. Complexity explodes!
Anyway, all this does matter if you don't make any profit :)
The complexity exists whether it's a monorepo or many separate repos. A monorepo lets you encode that complexity as versioned code in your build system. Separate repos encode it across people's heads, wikis and who knows what else. Hiding complexity doesn't mean it doesn't exist, just that it will bite you 10 times as hard eventually.
If you need to build N libraries and M executables then you are going to have N+M targets (assuming building for one arch only) whether you use a monorepo or not... Either way you are going to issue N+M build commands.
Also, in bazel you can do
bazel build //...
to do a full build of all targets in a workspace. If they are not doing this but instead passing each target name individually then that probably means that they are only building a subset of everything, and even that subset is too much to pass in a single command line invocation. I'll grant you that it seems excessive to have that many targets, but again I don't see having so many targets as an explicit issue of the monorepo.