Interesting question, Harris. Since Make has served me well enough all
these years, I haven't had much reason to look at Meson or Ninja. I don't
like dependencies, even build dependencies, that don't bring something
substantial to the table. Make is a standard development tool with
multiple, independent implementations, and so, in practice, it's not
really a dependency. Like, say, a text editor, it's safe to simply assume
it's present alongside a compiler, even on Windows. I include Make in
w64devkit after all, so there's really no excuse not to have it on hand
when building my software.
I was aware of Ninja due to it being an output option for CMake, though
I've never used that feature. It's written in C++, which is reasonable
enough for me to consider it. Though Ninja is low level in the same way
Make is low level, so it's not bringing anything new to the table. It
claims to be faster, though that won't apply to the way I build software,
where Make already consumes less than 0.01% of the total build time (full
build), and only a couple of milliseconds when there's nothing to do. The
website says you're not really supposed to write Ninja build files by
hand, and it's intended to be generated by yet another build dependency
(CMake, Meson, etc.). So I see no benefits versus Make, just the cost of
an extra dependency and an unconventional build interface.
When I've run into projects using Meson, my reaction has always been to
roll my eyes and bypass Meson, manually invoking the compiler on the
source files. These projects have always been simple enough that they
don't even need much of a build system, let alone an esoteric one.
Looking more closely at Meson now, I see its written in Python. This is an
inappropriate implementation language for a build system, and more than
enough reason enough for me to never touch it. A build system ought to be
written in a systems language. If I depend on Meson, then I also
transitively depend on a full Python interpreter and package system (to
install Meson) since the Python community has yet to solve distribution /
delivery. Fortunately Meson doesn't have further Python dependencies of
its own, so at least it's not nearly as bad as it could be.
Trying it out some existing Meson builds listed on their site, I see it
makes a common mistake with CMake: The output build scripts contains
absolute paths to the project itself. A consequence is that I can't mix
tools with different views of the file system. For example, tools running
in Cygwin or Msys2 see different paths than native Windows tools, so they
may be confused when invoked by Meson or CMake builds from the other
system. This was at one point a deal-breaker for me with CMake. Though it
seems Meson uses relative paths more than CMake, so maybe in practice it's
not an issue.
The only build system I've ever liked more than plain old Makefiles is "go
build". Unfortunately it's too late for C and C++ to have something like
that — the ecosystem has been fragmented into incompatible ways of doing
things for far too long.
> Looking more closely at Meson now, I see its written in Python. This
> is an inappropriate implementation language for a build system, and
> more than enough reason enough for me to never touch it.
For what it's worth you're not the only one to feel that way. There is a
C implementation of meson on sourcehut that seems to be actively
developed: https://sr.ht/~lattis/muon/
Obviously that doesn't change the value proposition of why you'd use
meson instead of make, but it does help cut an unnecessary python
dependency.
Harry
Good review. I hadn't realized that Meson was written in Python. I
generally agree with the points you make in your email, but I also
feel that Make has a few deficiencies... having a separate build
directory and source directory, for example, is more difficult than it
should be, and supporting the cross platform use case more or less
requires you to have more than one makefile (in fact if memory serves,
you made the same point in one of your articles on makefiles).
... I'm not sure I'm bothered enough by Make's deficiencies to write
my own build system, though :)
Harris
> There is a C implementation on sourcehut
Thanks, Harry, I wasn't aware of this. That's more reasonable, and it's
healthier in the long term for Meson to have multiple implementations.
> having a separate build directory and source directory
Yup, Make is far from perfect, and it doesn't make this easy. As is the
case for most GNU Make extensions, its VPATH extension is too poorly
designed to improve this situation even for GNU Make.
When I've had projects grow large enough enough that maintaining a
Makefile becomes difficult, and I still care about incremental builds, I
hand-write a shell script to drive GCC -MM -MT over the source files,
automatically handling the header dependencies, and covering cases like
out-of-source builds since I can brute force the rules (vs. relying on
Make's limited inference rule matching). That script is essentially doing
the same work as CMake or Meson, but at a fraction of the cost and with
more flexibility.
None of my open source projects have ever become complex enough to warrant
that treatment, so I can't point to any of my real world examples, but I
put together an example for Enchive just now:
https://gist.github.com/skeeto/b07bbfbf8ec7d4075685e8e9f0a7a888
I check in the generated Makefile so that the actual build doesn't depend
on the script or GCC in particular. (Also, running "gcc -MM" on Windows is
painfully slow due to Windows' poor file system performance, so I like to
avoid it.)
> supporting the cross platform use case more or less requires you to have > more than one makefile
Sticking to GCC or Clang, I can cover all platforms with a single Makefile
since the compiler interface is essentially the same across all supported
platforms. A past obstacle has been relying on unix utilities (esp. rm),
which may not be present on Windows even alongside GCC and Make. This was
a major part of my motivation for w64devkit, serving as a reliable,
standard build environment on Windows without lugging Cygwin or Msys2.
In my w64devkit guide from March, I mentioned my convention of using an
EXE Make variable to automatically append an extension to the linked
targets. This covers both the cross-compilation and w64devkit cases.
I *do* use a separate "NMakefile" for interfacing with MSVC tooling, where
I follow cl's unconventional (even for Windows) interface and only use
Windows utilities (as painful as that is). See my "asteroids-demo" for an
example. This is where something like CMake or Meson might have an
advantage, covering both GCC/Clang and MSVC/clang-cl from a single build
configuration. However, like before, I know how to use MSVC, and I'd
rather do it myself and have full control even if I have to maintain a
separate Makefile.
My best solution for dealing with arbitrary, weird platforms is having an
amalgamation build that concatenates all source files into a single source
file / translation unit. Then, just as with SQLite, you don't need any
build system: Simply invoke the compiler directly on the single source
file. Enchive works like this, which is how I support all platforms and
compilers from a single build definition. This is also a major feature of
unity builds, though those have the additional cost of lacking fast
incremental builds during development. Amalgamation is the subject of a
whole new article I've been intending to write for awhile, but haven't
gotten around to it yet.