Page 1 of 1

In search of a good build system for C++

Posted: Thu May 03, 2018 9:53 am UTC
by raudorn
Lately I've been writing a lot of C++ code scattered across both existing and newly created projects and so far I find compiling and building things in C++ to be a check on the con side of a pro-con-analysis of C++. Does anyone have recommendations on how to build projects?

Here's an unordered list of things that are nice to have in a build system:
  • Automatic inclusion of new .cpp and .hpp (or .h) files into pool of compiled files
  • Makes #include statements just work
  • Works on most systems without having to install an outrageous amount of dependencies (for the build system anyway)
  • Makes inclusion of external libraries (outside the project folder) easy
  • Allows division of code into internal libraries for faster compilation (only recompile what changed)
  • If there is any boilerplate at all, makes it clear what is necessary
  • Effort to configure the build of a project scales with the amount of features used, not with the amount of code to compile, especially with nested folders

I have tried mostly cmake and scons so far. The latter feels like a version of the former that makes some things more convenient, but isn't all that different. cmake meanwhile is definitely a step up from writing Makefiles manually, but it's a far cry from things like Rust's crates. I feel like I could do anything I need with cmake, but it does not make things easy.
There are probably solutions for any problem I might encounter, but these do not feel like clean programming practices. For example, automatically including new code files requires writing some recursive globing-loop inside cmake's description language, which of course I didn't write myself and instead copy from other projects. If that is the best solution, why isn't this part of cmake itself?!

Re: In search of a good build system for C++

Posted: Thu May 03, 2018 12:30 pm UTC
by Tub
If your build system is as simple as "compile every single file in this directory into an executable", then a simple Makefile will do. See here, for example. This has minimal dependencies, but isn't easily portable to toolchains that don't use gcc/clang's command line syntax.

For example, automatically including new code files requires writing some recursive globing-loop inside cmake's description language, which of course I didn't write myself and instead copy from other projects. If that is the best solution, why isn't this part of cmake itself?!

file(GLOB_RECURSE ...) ?

CMake does not recommend using globs to enumerate files though, because it cannot detect added files automatically. You'll end up manually re-running cmake on every new file, or you'll waste time by running cmake on every compile. Globbing inside the makefile is faster and more reliable.

Re: In search of a good build system for C++

Posted: Thu May 03, 2018 9:47 pm UTC
by raudorn
Tub wrote:If your build system is as simple as "compile every single file in this directory into an executable", then a simple Makefile will do. See here, for example. This has minimal dependencies, but isn't easily portable to toolchains that don't use gcc/clang's command line syntax.

For some small projects, yes. The main thing I'm currently working on requires more functionality however. I honestly don't really understand how it works, except that it uses cmake and needs a CMakeLists file in every subdirectory, which is a lot of duplicated code, but at least this allows splitting of the code into sort-of internal libraries.

Tub wrote:file(GLOB_RECURSE ...) ?

CMake does not recommend using globs to enumerate files though, because it cannot detect added files automatically. You'll end up manually re-running cmake on every new file, or you'll waste time by running cmake on every compile. Globbing inside the makefile is faster and more reliable.

Ah, yeah, that's what I meant. It's still necessary to run cmake again when new files are added, but at least the new files don't have to be registered in the CMakeLists files.

Re: In search of a good build system for C++

Posted: Thu May 03, 2018 10:20 pm UTC
by Soupspoon
Can't you script something to autogenerate all the CMakeLists stuff for you? A shell-script (or a .bat¹, as I didn't see anything to narrow down what OS this was under, at first look at your posts), or a .pl or .py one, could go in there to interrogate all makeable files/etc in a directory and format them into the midst of a config, and bookended by the invariable stuff.

Or maybe your next compiled project could be to develop a utility/wizard/app to do this, if you're happier with just sticking with C++ rather than having to pick up a script dialect you're not currently familiar with… If you can't find one already made, maybe you could even fill a much needed development niche (if you've got time to 'support' other people with need for somethinf similar and yet with varying requirements.


Just an idea, maybe.a bit left-field, and not totally sure I picked up on all of your nuanced needs.


¹ Although it's a more awkward to use "FOR /D IN …" and "FOR /F IN …", with tokens and variable expansion modifiers you can do most of what you could do trivially in a (foo)sh shell.

Re: In search of a good build system for C++

Posted: Fri May 04, 2018 10:36 am UTC
by raudorn
Soupspoon wrote:Can't you script something to autogenerate all the CMakeLists stuff for you?

In theory, sure, that's possible. A build system is "just" a layer wrapped around the compiler to make it a bit more convenient to tell the compiler what and how to compile. However I don't think cmake is missing any functionality I need. It's more that it is not as easy to use as I would like it to be. A build system is supposed to take some work off the developer's shoulder, not add to it.

Re: In search of a good build system for C++

Posted: Sun May 13, 2018 8:17 am UTC
by Link
Going by what I've read, if you're already comfortable with CMake, there's basically zero reason to switch to anything else. Personally, though, I still love the bog-standard Autotools (especially in combination with autogen.sh). Going through your list:

Automatic inclusion of new .cpp and .hpp (or .h) files into pool of compiled files
This one is a bit of a problem with Autotools because it's not at all obvious how new files should be compiled. A real project will typically have many binaries and libraries with complex interdependencies, and figuring out which source file belongs to which parts is a highly nontrivial task. This is not something Autotools does for you by default, but in my opinion also isn't something a build system should do. Even so, a few lines of m4 should cover simple cases; there may already be something in the Autoconf archive.

Makes #include statements just work
As long as you don't do outrageous stuff, sure.

Works on most systems without having to install an outrageous amount of dependencies (for the build system anyway)
Most *NIX-like systems already have them out of the box. There are lots of dependencies, but they're all small -- that's the UNIX philosophy at work. It's pretty easy to set up on most OSes, AFAIK.

Makes inclusion of external libraries (outside the project folder) easy
pkg-config!

Allows division of code into internal libraries for faster compilation (only recompile what changed)
Yup, out of the box.

If there is any boilerplate at all, makes it clear what is necessary
I'm not sure understand exactly what you mean by this, but this sounds like more of a task for a separate script or an IDE than it does for a build system. Tip for GCC users: -Wl,--as-needed tries to minimise the linking of unnecessary code.

Effort to configure the build of a project scales with the amount of features used, not with the amount of code to compile, especially with nested folders
Mostly true. Typically adding new source files requires adding them to the appropriate SOURCES directives in Makefile.am, and adding subdirectories requires adding a SUBDIRS directive to the parent Makefile.am and a new trivial Makefile.am to the subdir itself, but those are all one-time overhead. The actual operation time of autoconf and configure depends mostly on the complexity of configure.ac, which typically does not depend directly on the size of the source code.