10

Specifically with CMake builds, if you don't specify a build type explicitly, the build will use neither Debug nor Release compilation flags.

I was writing my own Makefile for a simple program and realized there is no reason to generate a binary with no flags.
I either want the debug build for development or release build for deployment.
I don't see a use-case for anything else, are there more?

Is this design decision in CMake motivated by an actual practice in software development of creating builds that are neither Debug nor Release or is it a mistake to not specify a default build type in a CMake project in CMakeLists.txt?

6
  • 7
    There is value in builds with full optimizations, but also with debug symbols so that coredumps can be debugged. Of course, some compilers can split the debug symbols into separate files so that they don't bloat the deployed executable. I've also had scenarios where I needed basic optimizations in test builds in order to run tests with acceptable performance. Some release build configurations disable safety checks or asserts, which might be a very bad idea.
    – amon
    Commented Apr 12 at 12:40
  • 1
    The rule of thumb is: the less options the better.
    – freakish
    Commented Apr 12 at 14:46
  • 3
    Isn't the default build mode in CMake RelWithDebInfo? "Release with debug information", rather than "no flags". Commented Apr 12 at 18:02
  • @HolyBlackCat the way I understand it, no. cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html Commented Apr 13 at 15:53
  • Hmm, I stand corrected, I got an empty string on Linux. I could swear I had RelWithDebInfo on MinGW, but can't test it right now. Commented Apr 13 at 16:00

4 Answers 4

20

Yes. Develop build and release build should behave identical, but they don’t always do. So you want to be able to have a build that is as close as possible to a release build, but capable of being run on a developer machine and being debugged.

And once in a while you run this build when your development build seems stable, to find problems that only customers would find.

(What could go wrong between developer and release build? I once saw code with a statement assert(x == 1) but instead the statement was assert(x = 1). The assert didn’t not just miss when x was two, it actually fixed it. And then the release version broke. )

5
  • 3
    My head exploded with the assert(x = 1) example. Great answer! Commented Apr 13 at 23:03
  • 5
    Genius. "- Computer, make sure that x is 1. - Ok."
    – pipe
    Commented Apr 14 at 1:46
  • 1
    It's not foolproof but this error can be prevented with assert(1==x). The compiler will catch 1=x as an error. So I'm in the habit of writing literals on the left whenever possible.
    – nickalh
    Commented Apr 14 at 9:03
  • Also, lint or the appropriate risky code checker for your language should flag that as "Hey, did you really mean this?"
    – nickalh
    Commented Apr 14 at 9:05
  • The assert was in code that was close before release.
    – gnasher729
    Commented Apr 15 at 17:23
7

I either want the debug build for development or release build for deployment. I don't see a use-case for anything else, are there more?

You are right, these two are the most frequently required use cases:

  • a debug build without any optimization but full debug symbols
  • a release build with full optimization and no debug symbols

Others have mentioned certain cases where other combinations of compiler switches may make sense (for example, partially optimizations, optimizations plus debug symbols), but no compilation flags at all may create something arbitrary which is not what you want.

Is this design decision in CMake motivated by an actual practice in software development of creating builds that are neither Debug nor Release or is it a mistake to not specify a default build type in a CMake project in CMakeLists.txt?

The creators of CMake could have made the tool pick a default build configuration when none is specified, but everyone will probably have their own idea what the most useful default is. They could also have made CMake throw an error and stop execution for this case. Or, they could CMake let the decision delegate to the compiler vendor and use whatever the vendor provided as default, when no flags were set. We can only guess why they choose the last alternative, but surely not because it is "actual practice in software development".

However, others have already solved this problem for you: here I found a short article how to make CMake pick your favorite build config according to some simple rule (the example shows how the Debug configuration is chosen when a .git file is present in the source tree, otherwise the Release configuration). I am sure you can modify this script so it will apply to your environment and your idea what the best default build configuration is.

6

Testing, staging, profiling, stripped are just a few of other possible modes.

1

When developing for native Linux applications CMake has been set to use the following configurations for the C99 code base:

  1. release: Which has optimisations enabled and is the configuration deployed. The executables aren't stripped of debug information to aid using addr2line to decode an backtrace reported by a crash (e.g. SIGSEGV) or assertion failure. We chose to leave assertions enabled for release to trap if the code gets into an inconsistent state. The assertions use our own function to control the diagnostic information collected
  2. coverage: To check code coverage when the regression tests are run.
  3. debug: This has no optimisations enabled, to maximise debug visibility. This configuration also enables some GCC sanitizer options to trap some runtime errors. E.g. using an out of range boolean or indexing outside of an array with compile time bounds. Since the sanitizer inserts conditional branches which are only taken on a failure, the sanitizer isn't enabled on the coverage configuration to avoid getting a large number of branches which are reported as not taken.
  4. qac: This doesn't compile an executable, but creates a project for performing static analysis.
  5. win32: This uses mingw32 to cross-compile some utilities for decoding binary log files as Windows executables. This allows the log file decoders to be compiled for both Linux and Windows. Given that the mingw32 cross-compiler has POSIX libraries, it is useful to be able to create command line executables which can be run on Windows and Linux and use POSIX libraries which are available for both operating systems and avoids having to use conditional compilation and call different functions on Linux and Windows, for operations such as reading directories entries.

Regression tests are run using executables built for release, coverage and debug checking the tests pass for all configurations.

Not the answer you're looking for? Browse other questions tagged or ask your own question.