Interfaces are VERY GOOD for migrations.
If you decide that you want to stop using some compiler flag, or maybe use a different compiler, or change your python version, or...
You can right a regex to go over all your shell invocations, change them, then test, or you can do something like:
``` def build_thing(name, srcs, hdrs, migration=False): if migration: ...
build_thing( name = "my_lib", srcs = ["my_lib.cc"], hdrs = ["my_lib.h"], ) ```
You can then manually flip that to test stuff, write a script to flip it for every team, sending out a PR (because your targets can have oncalls) and they can land it, and then at the end you can flip the default and manually add a False to the holdouts.
All this stuff gives you the ability to do hard stuff at scale.
They only fully support Javascript. The complex stuff, like defines, C++ toolchain, dynamic libs, etc.. is all out of scope.
That's very unfair to JS devs. We're well aware that other things exist...
...because we're trying to replace them all with JS.
As if all JS developers can be grouped into a single entity with the same thoughts. This sounds a bit like saying "the legions of Makita Tools carpenters think" or "the legions of Volvo truck drivers think".
This means that #ifdef FOO will be evaluate to true _inside the .cc and .h files listed in srcs_, when building this target or dependent targets, but might be something else when downstream targets' object files (.o) are built.
But abstractions are a good thing! They let you separate a system into layers, so that things programmed at a higher layer don't need to know all the details of the lower layers. It's the way we separate interface from implementation.
Let me give an example from Bazel. Suppose you are compiling some C or C++, and you need to define a preprocessor symbol. There are two ways of doing this, "defines" and "local_defines":
You can use "defines" when you have #ifdef statements in headers and "local_defines" when you only test the symbols in your .cc files.I did not have to think about how defines will propagate to the libraries that depend on me, I just specified what I need and the build system handles the rest. I did not have to define my own CXXFLAGS variable and handle concatenating all of the right things together. The lower layer takes care of that.
What Bazel lets you do is create abstraction boundaries within the build system. People can write rules that define a self-contained set of build logic, then other people can use those abstractions without knowing all the details of how they are implemented.
Bazel is not perfect, and I have found myself banging my head against the wall many times. But overall the ability to define abstractions in a build system is, I think, one of the biggest things it gets right.
Disclosure: I work for Google, but not on Bazel.