--install . behaviour differs from --build . --target install

I configure a project via:

cmake -S …/ -B . -DCMAKE_BUILD_TYPE=None -DCMAKE_INSTALL_PREFIX=/tmp/prefix -G ‘Unix Makefiles’

In CMakeLists,txt there is call to install(export):

install(EXPORT ${PROJECT_NAME}Targets
NAMESPACE pkg::
DESTINATION “${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}”
)

Now when I build/install via:
cmake --build . --config Release --target install

(note the redundant --config which should be ignored because of single file generator)

I see 2 files:
pkgTargets.cmake pkgTargets-none.cmake

The 2nd file corresponds to the CMAKE_BUILD_TYPE I used to configure.

Now if I clean everything and try the same with:
cmake --build . --config Release
cmake --install . --config Release

I only see:
pkgTargets.cmake

There -none.cmake file has not been created?

I also tested without the redundant --config Release and it works as expected eg
cmake build .
cmake install .

And tested with --config None and this also works as expected.
cmake --build . --config None
cmake --install . --config None

I would actually expect both of these --config options to be ignored?

Why do you set an invalid build type?

What makes you think None is an invalid build type?

The default supported build types are:

bash-5.2$ cmake -LA . | egrep '(CXX_FLAGS|BUILD_TYPE)'
CMAKE_BUILD_TYPE:STRING=
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
bash-5.2$ 

Is that command contextual? When I run in my build folder:

cmake -LA . | egrep '(CXX_FLAGS|BUILD_TYPE)'
Generated with config types: 
Generated with build type: None
CMAKE_BUILD_TYPE:STRING=None
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
CMAKE_CXX_FLAGS_NONE:STRING=
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG

Which is the reason I am using None.

I don’t want any of the flags appended that these other build types include.

Quote from docs:

The default value is often an empty string, but this is usually not desirable and one of the other standard build types is usually more appropriate.

I don’t want any of the flags appended that these other build types include.

You may use -D CMAKE_CONFIGURATION_TYPES=None

You may use -D CMAKE_CONFIGURATION_TYPES=None
Interesting - I will test that

For a single config generator, I thought setting configuration was “ignored”

Have you ever seen: https://wiki.archlinux.org/title/CMake_package_guidelines

This is where I got the inspiration for CMAKE_BUILD_TYPES=None

with -D CMAKE_CONFIGURATION_TYPES=None none of the erroneous flags are added to the compile commands which looks promising, and if I do

cmake --install .

I get a pkgTargets-noconfig.cmake which looks correct

But if I specify any value for --config eg.

cmake --install . --config None
or
cmake --install . --config Release

the -noconfig file is not generated, similar to the previous observation

In this particular instance there is no difference in setting -D CMAKE_CONFIGURATION_TYPES=None or just not setting it at all

Both you end up with a noconfig export file

  • which cmake version are you using?
  • on which OS?
  • try same with Ninja generator please

Setting CMAKE_BUILD_TYPE to None is incorrect. You are saying you want to use a custom build type that is literally called None. Since you define no variables for this custom None build type, it may coincidentally behave similar to CMAKE_BUILD_TYPE being unset or set to an empty string, but there may be corner cases where that isn’t so. The output you showed earlier with this value None is really just trying to tell you that CMAKE_BUILD_TYPE holds an empty string.

Setting CMAKE_CONFIGURATION_TYPES for a single config generator should be meaningless, don’t do it.

If you truly want the effect of getting CMAKE_CXX_FLAGS but none of the other CMAKE_CXX_FLAGS_<CONFIG> flags, then setting CMAKE_BUILD_TYPE to an empty string would achieve that. But as the docs say, that is almost never what a developer wants. I would question the use case where you don’t want any configuration, but you haven’t given any detail why you want that specific behavior. If you were using a multi-config generator, you don’t have the choice of an empty configuration. Being able to use one for single configuration generators is a bit of an anomaly.

We build many 3rd party dependencies that already have cmake builds, but we use bazel with a bazel cmake wrapper. We have also defined our own custom bazel gcc toolchain, and we would prefer that to be the source of truth for for our optimisation flags, rather than cmake adding in it’s own defaults depending on what CMAKE_BUILD_TYPE is set to.

And yes, the upstream projects themselves may have logic on CMAKE_BUILD_TYPE as well, but many don’t, but we could patch this logic out.

That is why I was looking to see what the arch project does, and a colleague also linked the gentoo project and their cmake wrapper.

So until now we’ve just been setting CMAKE_BUILD_TYPE to None and this has for the most part worked, but I am open to better guidance on how to handle this requirement.

cmake version 3.22.1
Ubuntu 22.04.5 LTS

The clearest approach to what you are trying to achieve would probably be to define your own custom config. Give it a name that makes clear what the custom config represents, don’t use None. If you don’t define the config-specific variables CMAKE_CXX_FLAGS_<CONFIG>, they default to empty, and that sounds like what you’re wanting. This will be essentially the same as using None like you are now, but without the confusion and potential corner cases where None might be taken to mean something special (I don’t recall where I’ve seen that, better just to avoid the problem by using a better name).

One down side of using a custom config though is when you install your project, you’re installing that config, not Debug or Release. If consumers are making assumptions about what configurations a target is provided in, they may have trouble dealing with your custom configuration.

An alternative would be to overwrite flag variables like CMAKE_CXX_FLAGS_RELEASE, discarding the default contents and setting them to whatever flags want to enforce. But some projects then modify that value, which projects shouldn’t do, but it is unfortunately still common. Even then, projects can also add flags in other (legitimate) ways, so you may have a hard time truly enforcing a consistent set of flags across all projects.

Craig, thanks so much for responding with ideas on different approaches.

One down side of using a custom config though is when you install your project, you’re installing that config

This seems related to my observation: Building with CMAKE_BUILD_TYPE=None and installing with --config Release resulted in no MyLibraryTargets-<config>.cmake file being generated.

If consumers are making assumptions about what configurations a target is provided in, they may have trouble dealing with your custom configuration

I assume you mean the assumptions the library authors themselves make within their custom CMake. We can limit this somewhat by controlling the build/install types/configs on both sides, but yes its another potential source of errors.