# Override the default \`-O3 -DNDEBUG\` Release flags?

**URL:** https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085
**Category:** Usage
**Tags:** os:linux
**Created:** [June 24, 2024, 4:16am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085 "2024-06-24T04:16:55Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![intelfx](https://discourse.cmake.org/user_avatar/discourse.cmake.org/intelfx/32/4692_2.png) [@intelfx](https://discourse.cmake.org/u/intelfx)
#### Post date: [June 24, 2024, 4:16am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/1 "2024-06-24T04:16:56Z")

</div>

Hi,

What is the least-breaking way to override the `-O3 -DNDEBUG` flags automatically set by CMake for Release configurations, without touching any flags that the build system itself might have set in addition?

This question is being asked from a distributor’s standpoint, that is, not the project authors. Many Linux distributions have guidelines for the compilation flags used when building distributed software, and the default-to-`-O3` behavior sometimes contradicts these guidelines. For instance, in Arch Linux [we have a policy of setting `-DCMAKE_BUILD_TYPE=None`](https://wiki.archlinux.org/title/CMake_package_guidelines#CMake_can_automatically_override_the_default_compiler_optimization_flag) due to this concern, but this policy has caused a number of issues due to missing `-DNDEBUG` that is occasionally relied on by various projects.

It is possible to override the flags variables themselves when invoking CMake:

```sh
$ cmake \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=/usr \
  -DCMAKE_C_FLAGS_RELEASE="-O2 -DNDEBUG" \
  -DCMAKE_CXX_FLAGS_RELEASE="-O2 -DNDEBUG" \
  -S . -B build

```

However, this risks overwriting any modifications the project itself might perform on the `CMAKE_(C|CXX)_FLAGS_RELEASE` variables after they were initialized by CMake.

* * *

So, is there any way to tell CMake, in a generic fashion, to use something else instead of `-O3 -DNDEBUG` as the default value for Release compilation flags, without affecting any later modifications to these variables within the project buildsystem?

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [June 25, 2024, 7:19am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/2 "2024-06-25T07:19:38Z")

</div>

> [@intelfx](#):
>
> For instance, in Arch Linux [we have a policy of setting `-DCMAKE_BUILD_TYPE=None`](https://wiki.archlinux.org/title/CMake_package_guidelines#CMake_can_automatically_override_the_default_compiler_optimization_flag) due to this concern, but this policy has caused a number of issues due to missing `-DNDEBUG` that is occasionally relied on by various projects.

Don’t do that. `None` is not generally a valid build type, and it’s not a robust way to get the behavior you want. Instead, pick a configuration that is closest to what you want (likely `Release`) and override the default flags by either:

- Specifying the relevant variables on the `cmake` command line (see below), or
- Specifying the relevant variables in a toolchain file.

Since you want to completely replace the flags the CMake would normally set for you, the variables you want to be setting will be `CMAKE_<LANG>_FLAGS` and `CMAKE_<LANG>_FLAGS_<CONFIG>`. The former is used for all configurations, and the latter is appended after that for just the `<CONFIG>` configuration. The `<LANG>` part will be `C`, `CXX`, `ASM`, and so on depending on what languages you want to override the default flags for.

Command line example:

```auto
cmake -DCMAKE_CXX_FLAGS= "-DCMAKE_CXX_FLAGS_RELEASE=-O2 -DNDEBUG" ...

```

The above sets `CMAKE_CXX_FLAGS` to an empty string and `CMAKE_CXX_FLAGS_RELEASE` to `-O2 -DNDEBUG`. You would want to add more variables for other languages as well.

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [June 25, 2024, 7:26am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/3 "2024-06-25T07:26:33Z")

</div>

Sorry, hit send before responding to the second half of your question. If you want to only change the _defaults_ and still let the project control these flag variables (which they shouldn’t be setting to begin with, but that’s a whole other topic), you can set the `CMAKE_<LANG>_FLAGS_INIT` and `CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variables instead. These are only used on the first run in a build directory, and they are used to initialise the non-INIT variables I mentioned in my previous reply. Again, you can set them either on the command line or in a toolchain file.

For regular users, they should be setting the `..._INIT` variables in toolchain files. This still allows them to override the non-INIT variables if they want to. In your case, you want to explicitly control the exact flags used, so it sounds to me like you should be setting the non-INIT variables. If a project is trying to modify these variables (which used to be common many years ago in the early days of CMake, but is actively discouraged now), then it depends on how they try to do that. They would already be expecting the cache variables to be defined by the time they get a chance to read or modify them (well, technically that is after the first `project()` or `enable_language()` call that enables the language they want to control the flags for). Hopefully they are only setting non-cache variables and they are doing so by appending to the existing values, but you’re really at the mercy of whatever they decide to do.

---

<div class="post-metadata">

### Author: ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)
#### Post date: [June 25, 2024, 7:51am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/4 "2024-06-25T07:51:07Z")

</div>

Another discussion on this topic: [https://gitlab.kitware.com/cmake/cmake/-/issues/21705](https://gitlab.kitware.com/cmake/cmake/-/issues/21705)

regards  
A.

---

<div class="post-metadata">

### Author: ![intelfx](https://discourse.cmake.org/user_avatar/discourse.cmake.org/intelfx/32/4692_2.png) [@intelfx](https://discourse.cmake.org/u/intelfx)
#### Post date: [June 25, 2024, 8:55am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/5 "2024-06-25T08:55:14Z")

</div>

> Don’t do that. `None` is not generally a valid build type, and it’s not a robust way to get the behavior you want.

I agree, but in the absence of any other way to control the CMake default flags this is what at least Arch Linux ended up writing into our guidelines.

> In your case, you want to explicitly control the exact flags used, so it sounds to me like you should be setting the non-INIT variables. If a project is trying to modify these variables (which used to be common many years ago in the early days of CMake, but is actively discouraged now), then it depends on how they try to do that. They would already be expecting the cache variables to be defined by the time they get a chance to read or modify them (well, technically that is after the first `project()` or `enable_language()` call that enables the language they want to control the flags for). Hopefully they are only setting non-cache variables and they are doing so by appending to the existing values, but you’re really at the mercy of whatever they decide to do.

Well, all of this is true. As you correctly note, many free software projects have broken or just sloppily written build systems, and it would be clearly infeasible for us (or any other distribution) to patch or thoroughly review all of them.

This is exactly why my intent/request here is precisely **to behave exactly as vanilla CMake would behave** , except that `-O3` should not be part of the default Release flags.

> If you want to only change the _defaults_ and still let the project control these flag variables (which they shouldn’t be setting to begin with, but that’s a whole other topic), you can set the `CMAKE_<LANG>_FLAGS_INIT` and `CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variables instead. These are only used on the first run in a build directory, and they are used to initialise the non-INIT variables I mentioned in my previous reply. Again, you can set them either on the command line or in a toolchain file.

Unfortunately, this was the first thing I tried. Setting any of the `CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variables on the command line results in CMake default flags being _appended_ to the specified flags. Observe:

```cmake
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.28)
project(hello)

set(CMAKE_CXX_STANDARD 17)

add_executable(hello_cpp main.cpp)
add_executable(hello_c main.c)

```

```auto
$ env CFLAGS="-O2 -g" CXXFLAGS="-O2 -g" \
  cmake \
   -DCMAKE_BUILD_TYPE=Release \
   -DCMAKE_C_FLAGS_RELEASE_INIT="-DNDEBUG" \
   -DCMAKE_CXX_FLAGS_RELEASE_INIT="-DNDEBUG" \
   -S . -B cmake-build-release
-- The C compiler identification is GNU 14.1.1
-- The CXX compiler identification is GNU 14.1.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.4s)
-- Generating done (0.0s)
-- Build files have been written to: /home/intelfx/devel/landfill/hello/cmake-build-release

```

```auto
$ grep -E '(C|CXX)_FLAGS_RELEASE:STRING' cmake-build-release/CMakeCache.txt
CMAKE_CXX_FLAGS_RELEASE:STRING=-DNDEBUG -O3 -DNDEBUG
CMAKE_C_FLAGS_RELEASE:STRING=-DNDEBUG -O3 -DNDEBUG

```

So, the unwanted `-O3` flag still makes it to the resulting CMake cache.

Any other ideas?

---

<div class="post-metadata">

### Author: ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)
#### Post date: [June 25, 2024, 8:58am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/6 "2024-06-25T08:58:47Z")

</div>

What I’ve got in my CMake files:

```cmake
set(CMAKE_CXX_FLAGS_DEBUG "" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "" CACHE STRING "" FORCE)

```

notice the `FORCE` option.

Then I set my compiler options.

---

<div class="post-metadata">

### Author: ![intelfx](https://discourse.cmake.org/user_avatar/discourse.cmake.org/intelfx/32/4692_2.png) [@intelfx](https://discourse.cmake.org/u/intelfx)
#### Post date: [June 25, 2024, 9:03am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/8 "2024-06-25T09:03:23Z")

</div>

This is missing the point. I’m not speaking as a _project author_ here, but as a _distribution maintainer_. This means that I’m not writing my own `CMakeLists.txt` from scratch, but working with an existing build system.

---

<div class="post-metadata">

### Author: ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)
#### Post date: [June 25, 2024, 9:29am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/9 "2024-06-25T09:29:34Z")

</div>

Understand. So I don’t know how to enforce that. In my case, I propose templated CMakeLists, that are enforcing a set of rules (such as these) but I don’t feel it can be an option for you.

Sorry

---

<div class="post-metadata">

### Author: ![intelfx](https://discourse.cmake.org/user_avatar/discourse.cmake.org/intelfx/32/4692_2.png) [@intelfx](https://discourse.cmake.org/u/intelfx)
#### Post date: [June 25, 2024, 9:32am UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/10 "2024-06-25T09:32:12Z")

</div>

Yes, precisely. For a distribution, it is generally not an option to patch (let alone _rewrite_ according to specific strict rules) the build systems of each distributed program — it simply does not scale.

---

<div class="post-metadata">

### Author: ![ebaudrez](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/e8c25b/32.png) [@ebaudrez](https://discourse.cmake.org/u/ebaudrez)
#### Post date: [July 24, 2025, 1:28pm UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/11 "2025-07-24T13:28:26Z")

</div>

I was curious to know if a satisfactory solution was ultimately found (this page turns up as one of the top hits when Googling “cmake default flags”, so I suppose other people may stumble upon it as well).

I tried with a toolchain file, but the “-O3 -DNDEBUG” that seems to be inserted by /usr/share/cmake/Modules/Compiler/GNU.cmake always comes back. I’m a bit out of ideas at this point.

---

<div class="post-metadata">

### Author: ![intelfx](https://discourse.cmake.org/user_avatar/discourse.cmake.org/intelfx/32/4692_2.png) [@intelfx](https://discourse.cmake.org/u/intelfx)
#### Post date: [July 24, 2025, 1:46pm UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/12 "2025-07-24T13:46:11Z")

</div>

I have a half-finished patch against the built-in toolchain module files that introduces a new set or variables to override the “default default” optimization flags for each profile. I’m just not sure if upstream will even want it — these days most people are outright hostile to the idea of introducing new extension points…

---

<div class="post-metadata">

### Author: ![ebaudrez](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/e/e8c25b/32.png) [@ebaudrez](https://discourse.cmake.org/u/ebaudrez)
#### Post date: [July 24, 2025, 2:00pm UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/13 "2025-07-24T14:00:21Z")

</div>

Reading /usr/share/cmake/Modules/Compiler/GNU.cmake, I was a bit surprised to read

`string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")`

I was expecting a `set` instead of an append there, but maybe this is just me misunderstanding the logic. Does your patch change that?

---

<div class="post-metadata">

### Author: ![vito.gamberini](https://discourse.cmake.org/user_avatar/discourse.cmake.org/vito.gamberini/32/4376_2.png) [@vito.gamberini](https://discourse.cmake.org/u/vito.gamberini)
#### Post date: [July 26, 2025, 2:31pm UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/14 "2025-07-26T14:31:13Z")

</div>

I think Arch’s behavior is simply correct. I wouldn’t set the build type to “None” (some projects try to catch that and reset the build type to “Release”), but the correct way to dodge CMake’s choices about the standard build types is to set your own.

My personal choice would be `CMAKE_BUILD_TYPE=ArchRelease` (or `ArchDebug`, etc). And then control the CXX flags as you already are. I use Arch as an example of why projects shouldn’t make assumptions about the build type/config, because it is perfectly legitimate to change it for the purpose of having complete control over the flaglines.

---

<div class="post-metadata">

### Author: ![vito.gamberini](https://discourse.cmake.org/user_avatar/discourse.cmake.org/vito.gamberini/32/4376_2.png) [@vito.gamberini](https://discourse.cmake.org/u/vito.gamberini)
#### Post date: [July 26, 2025, 2:34pm UTC](https://discourse.cmake.org/t/override-the-default-o3-dndebug-release-flags/11085/15 "2025-07-26T14:34:48Z")

</div>

All this to say I don’t think there’s any need to change anything upstream. The blessed way as a packager to exercise complete control over flags, install locations, etc, etc, to tell CMake to buzz off, is to set the build type to your own.
