Hm it seems like the defining feature of Bazel is high level "macros" like cc_library() and proto_library() on top of the low level build graph
I looked at the examples and tutorial and it still seems more low level, in that you mention object files and link them?
main_o = compile("src/main.cpp", "build/tut1/src/main.o")
util_o = compile("src/util.cpp", "build/tut1/src/util.o")
link([main_o, util_o], "build/tut1/app")
One reason I like the layering is for build variants -- dbg opt ASAN UBSAN -- something Make does very poorly. IMO you don't want to mention literal object file paths in the build config for this reason.
I use a tree layout like
_build/obj/cxx-asan/frontend.syntax.o
_build/obj/cxx-asan/core/process.o
_build/obj/cxx-ubsan/frontend.syntax.o
_build/obj/cxx-ubsan/core/process.o
and then this is abstracted with the Bazel-like target syntax
//frontend/syntax
//core/process
This works well - you don't have to clean when rebuilding variants, and all the object sharing between test binaries really speeds up the build.
IMO this is 100% essential for writing C++ these days -- all tests should be run with ASAN and UBSAN.
---
I wrote a mini-bazel on top of Ninja with these features:
https://www.oilshell.org/blog/2022/10/garbage-collector.html...
So it's ~1700 lines, though some of that is our own logic, and extra features like computing preprocessed size, which I used to improve compile times.
You get the build macros like asdl_library() generating C++ and Python (the same as proto_library(), a schema language that generates code)
And it also correctly finds dependencies of code generators. So if you change a .py file that is imported by another .py file that is used to generated a C++ header, everything will work. That was one of the trickier bits, with Ninja implicit dependencies.
This build file example mixes low level Ninja n.rule() and n.build() with high level r.cc_library() and so forth. I find this layering really does make it scale better for bigger projects
https://github.com/oilshell/oil/blob/master/asdl/NINJA_subgr...
Some more description - https://lobste.rs/s/qnb7xt/ninja_is_enough_build_system#c_tu...
Comment about Chrome/Android using the same pattern - https://lobste.rs/s/0qc6vp/arcan_0_6_3_i_pty_fool#c_ahqwky
which is explicitly in the Android docs - https://android.googlesource.com/platform/build/bazel/+/7d96...
The main thing my system doesn't have as mentioned is the per-action build sandboxing, which Bazel has OS-specific wrappers for. That's really useful for finding missing deps. Right now it's not a big pain point, since the build will break in a slightly less obvious way if you're missing deps.