conan-io / cmake-conan

CMake wrapper for conan C and C++ package manager

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[develop2] CMAKE_CONFIGURATION_TYPES issue

simonimpey opened this issue · comments

commented

I am having an issue building a project that defines CMAKE_CONFIGURATION_TYPES. Specifically if we look at conan_provide_dependency package_name

macro(conan_provide_dependency package_name)
    get_property(CONAN_INSTALL_SUCCESS GLOBAL PROPERTY CONAN_INSTALL_SUCCESS)
    if(NOT CONAN_INSTALL_SUCCESS)
        find_program(CONAN_COMMAND "conan" REQUIRED)
        conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION)
        conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION})
        message(STATUS "CMake-Conan: first find_package() found. Installing dependencies with Conan")
        conan_profile_detect_default()
        detect_host_profile(${CMAKE_BINARY_DIR}/conan_host_profile)
        if(NOT CMAKE_CONFIGURATION_TYPES)
            message(STATUS "CMake-Conan: Installing single configuration ${CMAKE_BUILD_TYPE}")
            conan_install(-pr ${CMAKE_BINARY_DIR}/conan_host_profile --build=missing -g CMakeDeps)
        else()
            message(STATUS "CMake-Conan: Installing both Debug and Release")
            conan_install(-pr ${CMAKE_BINARY_DIR}/conan_host_profile -s build_type=Release --build=missing -g CMakeDeps)
            conan_install(-pr ${CMAKE_BINARY_DIR}/conan_host_profile -s build_type=Debug --build=missing -g CMakeDeps)
        endif()
    else()
        message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran")
    endif()

    get_property(CONAN_GENERATORS_FOLDER GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
    list(FIND CMAKE_PREFIX_PATH "${CONAN_GENERATORS_FOLDER}" index)
    if(${index} EQUAL -1)
        list(PREPEND CMAKE_PREFIX_PATH "${CONAN_GENERATORS_FOLDER}")
    endif()
    find_package(${ARGN} BYPASS_PROVIDER CMAKE_FIND_ROOT_PATH_BOTH)
endmacro()

If this CMake variable is defined then the macro attempts to call conan_install for both Release and Debug build types.

  1. Should it be Release and Debug or should it be an iteration over the build types defined in CMAKE_CONFIGURATION_TYPES.
  2. More importantly, each such call set the global variable $CONAN_GENERATORS_FOLDER. This is subsequently used later in the macro to update the CMAKE_PREFIX_PATH. Due to the overrwriting this variable will always, I think, take the value set by the last call to conan_install, in this case Debug.

The problem that results from this occurs when attempting to make a Release build of a project that defines CMAKE_CONFIGURATION_TYPES. The Conan install completes successfully but the resulting build files do not contain the correct include or link directories/files. I believe this is due to the miss-match between the build type (Release) and the Conan generators selected (Debug), although I could be completely wrong :)

Should some form of mapping be maintained between build type and generator folder that can be used to look up the correct generator folder? I'm afraid I'm not enough of an expert on how CMake multi-config generators work to know the correct answer here.

commented

Hi @simonimpey

I think that yes, it might make sense to iterate the CMAKE_CONFIGURATION_TYPES for the conan install

For the second question, probably not. Conan layout() should be aware of this, and multi-config systems will get the same generators_folder for all configurations (this is why it is multi-config)

commented

Hi @memsharded

I will try and clarify my issue with some selected output...

I am attempting to make a release build of a project that defines the variable CMAKE_CONFIGURATION_TYPES. Due to the second point I have raised above first the release install is run followed by the debug install. As such the variable CONAN_GENERATORS_FOLDER is set to the debug folder, see below:

cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=/****/builddeploy/Linux/../../Conan.cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ /****/builddeploy/Linux/../..
.
.
.
-- CMake-Conan: conan install /**** -of=/****/Linux/x64/Release/conan -pr;/****/Linux/x64/Release/conan_host_profile;-s;build_type=Debug;--build=missing;-g;CMakeDeps

======== Input profiles ========
Profile host:
[settings]
arch=x86_64
build_type=Release
compiler=clang
compiler.cppstd=20
compiler.libcxx=libstdc++
compiler.version=16
os=Linux
[conf]
tools.cmake.cmaketoolchain:generator=Ninja

Profile build:
[settings]
arch=x86_64
build_type=Release
compiler=clang
compiler.cppstd=gnu17
compiler.libcxx=libstdc++
compiler.version=16
os=Linux
[conf]
.
.
.
Install finished successfully
-- CMake-Conan: CONAN_GENERATORS_FOLDER=/****/Linux/x64/Release/conan/build/Release/generators
-- CMake-Conan: CONANFILE=/****/conanfile.py
-- CMake-Conan: conan install /*** -of=/****/Linux/x64/Release/conan -pr;/****/Linux/x64/Release/conan_host_profile;-s;build_type=Debug;--build=missing;-g;CMakeDeps

======== Input profiles ========
Profile host:
[settings]
arch=x86_64
build_type=Debug
compiler=clang
compiler.cppstd=20
compiler.libcxx=libstdc++
compiler.version=16
os=Linux
[conf]
tools.cmake.cmaketoolchain:generator=Ninja

Profile build:
[settings]
arch=x86_64
build_type=Release
compiler=clang
compiler.cppstd=gnu17
compiler.libcxx=libstdc++
compiler.version=16
os=Linux
[conf]
.
.
.
Install finished successfully
-- CMake-Conan: CONAN_GENERATORS_FOLDER=/****/Linux/x64/Release/conan/build/Debug/generators
-- CMake-Conan: CONANFILE=/****/conanfile.py

Later during the find_package process we can see in the CMake trace output the following types of statements:

/****/Linux/x64/Release/conan/build/Debug/generators/fmt-Target-debug.cmake(15):  set_property(TARGET fmt_DEPS_TARGET PROPERTY INTERFACE_LINK_LIBRARIES $<$<CONFIG:Debug>:${fmt_FRAMEWORKS_FOUND_DEBUG}> $<$<CONFIG:Debug>:${fmt_SYSTEM_LIBS_DEBUG}> $<$<CONFIG:Debug>:> APPEND )

Here it is clear to see that because we have picked up the debug generator we are using CMake generator expressions that are dependent on the build type being debug. As a result of this the CMake targets produced do not include the required target_include_directories, target_link_libraries, etc expressions.

This may simply be a case of me calling things the wrong way...

@simonimpey Can you please share your CMakeLists.txt and the full command and console output. GitHub allows you to upload txt files which would be very helpful.

Its unclear what you are doing so it wont be possible to reproduce that error you are having :)

commented

@simonimpey Can you please share your CMakeLists.txt and the full command and console output. GitHub allows you to upload txt files which would be very helpful.

Its unclear what you are doing so it wont be possible to reproduce that error you are having :)

No but I will try and put together a minimal repro that I can share...

commented

I think that such use is not covered by CMake, not really a Conan (or a cmake-conan) thing. From https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html, we see:

Specifies the available build types (configurations) on multi-config generators (e.g. Visual Studio, Xcode, or Ninja Multi-Config) as a semicolon-separated list. Typical entries include Debug, Release, RelWithDebInfo and MinSizeRel, but custom build types can also be defined.

That is, the definition of CMAKE_CONFIGURATION_TYPES should only be done if the generator is multi-config, but you are using the Ninja generator, not the Ninja Multi-Config one. If you use the Ninja Multi-Config generator, then Conan will already do the right thing regarding the generators folder. Am I missing something?

commented

I think that such use is not covered by CMake, not really a Conan (or a cmake-conan) thing. From https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html, we see:

Specifies the available build types (configurations) on multi-config generators (e.g. Visual Studio, Xcode, or Ninja Multi-Config) as a semicolon-separated list. Typical entries include Debug, Release, RelWithDebInfo and MinSizeRel, but custom build types can also be defined.

That is, the definition of CMAKE_CONFIGURATION_TYPES should only be done if the generator is multi-config, but you are using the Ninja generator, not the Ninja Multi-Config one. If you use the Ninja Multi-Config generator, then Conan will already do the right thing regarding the generators folder. Am I missing something?

You are quite correct, I had wrongly assumed that CMAKE_CONFIGURATION_TYPES would be ignored by single target generators.

Many thanks.

commented

You are quite correct, I had wrongly assumed that CMAKE_CONFIGURATION_TYPES would be ignored by single target generators.

The truth is that the documentation is not fully clear, and if the variable is defined, but not used, it might be ignored, or maybe depending on the policies, it might just throw a warning, not that evident. But following the CMake behavior that doesn't define the variable at all for single-config generators, I understand that the users CMakeLists.txt should follow such behavior too.