Problems to export Debug configuration with cmake when using multiconfig generators

I am trying to export some targets I have in a project, and I’ve been using the install command for that. I need to export and install both Debug and Release configurations since I need to export some of the targets to clients that will use them in development and need to do debugging. However I can’t get the my_export-debug.cmake no matter what I do.

What I’m doing is basically the pseudo-code bellow:

install(TARGETS ${my_targets} EXPORT my_export CONFIGURATIONS Debug;Release Runtime DESTINATION ${CMAKE_INSTALL_LIBDIR} CONFIGURATIONS Debug;Release ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} CONFIGURATIONS Debug;Release)

install(EXPORT my_export DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake CONFIGURATIONS Debug;Release)

However, once I install I only get the my_export.cmake and my_export-release.cmake files, and when I try to use them in the installation the Debug version does not work (since there are no Debug imported targets, only the release ones).

In the my_export.cmake I see the code

file(GLOB _cmake_config_files “${CMAKECURRENTLISTDIR}/myexport−∗.cmake”)
foreach(_cmake_config_file IN LISTS _cmake_config_files)
include(“${_cmake_config_file}”)
endforeach()

so if I had the my_export-debug.cmake file I would have the debug exported targets. Why is this happening and how can I export debug targets?

Keywords in install(TARGETS) are case-sensitive. You’ve used Runtime where I think you need RUNTIME. I also recommend formatting your calls with indenting to help you more easily see errors like this. For example:

install(TARGETS ${my_targets}
    EXPORT my_export
    CONFIGURATIONS Debug;Release
    Runtime
        DESTINATION ${CMAKE_INSTALL_LIBDIR}
        CONFIGURATIONS Debug;Release
    ARCHIVE
        DESTINATION ${CMAKE_INSTALL_LIBDIR}
        CONFIGURATIONS Debug;Release
)

When laid out this way, we can see that Runtime stands out as a bit strange. We can also see that the first CONFIGURATIONS isn’t really needed, since we have it in each of the other sections already. But you probably don’t need any of the CONFIGURATIONS lines at all, since you will really just install the configurations you want to control the configurations that are installed. All the keywords here are doing is limiting what gets installed for specific configurations when those configurations are installed. They don’t control which configurations will be installed.

The next thing to check is whether the file names of your target’s binaries are actually different between Debug and Release. You probably want to be setting CMAKE_DEBUG_POSTFIX to something like _d or _debug so that your debug binaries have a different name.

Then you would need to install both Debug and Release. For example:

cmake --install path/to/build/dir --prefix some/staging/area --config Debug
cmake --install path/to/build/dir --prefix some/staging/area --config Release

See what the some/staging/area contains after doing both of those commands.

While we’re here, your install(EXPORT) command also contains a subtle bug:

install(EXPORT my_export
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake   # <---- Not one of the default search paths
    CONFIGURATIONS Debug;Release
)

You need to put the name of the package at the end of the path you’ve provided. Take a careful look at the default paths mentioned in the docs: https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure

Not sure if you intended it, but the DESTINATION for your RUNTIME looks wrong too. It would normally be ${CMAKE_INSTALL_BINDIR}. But if you’re using a more recent CMake version, you can probably leave it out anyway, since the defaults are actually what you want here. I think all you really need is just this:

include(GNUInstallDirs)
install(TARGETS ${my_targets} EXPORT my_export)

The targets are dynamic libraries, so I’m putting both their .lib and .dll files in the lib folder and using the bin folder only for executables. That was not the problem. Turns out the issue was that I was installing both release and debug artifacts to the same locations. I solved it with the $ generator expression. My new install TARGETS command became

install(TARGETS ${my_targets} EXPORT my_export CONFIGURATIONS Debug;Release Runtime DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<LOWER_CASE:$> CONFIGURATIONS Debug;Release ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<LOWER_CASE:$> CONFIGURATIONS Debug;Release)

and when I run cmake install two times with the correct --config arguments it works as expected.

I am using RUNTIME in my actual code, it was just a typo when making the pseudocode. That was not the issue. I’ve described the actual issue and solution below as a reply to one of your comments.

Does it work if you do:

cmake --install . --config Release
cmake --install . --config Debug