docs icon indicating copy to clipboard operation
docs copied to clipboard

How to use conan with CMake to generate multi-config Visual Studio Solution Files?

Open RochaStratovan opened this issue 2 years ago • 5 comments

What is your question?

Hello,

We have a sizeable C/C++ code base that uses CMake to generate multi-config solution files for Windows, as well as single config make file for Linux. Our company is split pretty evenly between Linux and Windows developers.

We would like to use Conan for package management and integration with GitLab. I've worked through the examples, and I'm stuck on one issue. How do I use Conan with CMake to generate a multi-configuration Visual Studio solution file that allows me to select any of the configurations and compile?

Here is the problem I noticed. I worked through the tutorial's Build a simple CMake project using Conan demo.

Following the instructions, I created a Visual Studio solution file that would compile when using the command line cmake --build . --config Release or the Visual Studio IDE set to Release.

I noticed the VS IDE still had the selector for Debug and RelWithDebInfo, so I tried compiling Debug, and it failed saying it couldn't find zlib.h file. I used the VS IDE and quickly saw that the extra include paths and link libraries for Debug weren't set.

This makes sense, because I only configured Release, but I cannot find any documentation that explains how to get it to work with both Release and Debug at the same time.

I found the tutorial page "Building for multiple configurations: Release, Debug, Static and Shared", but this page explains how to change configuration, essentially meaning a separate solution file per configuration.

How can I use conan to to install the desired dependencies: Release and Debug and then run cmake to use the installed Release and Debug dependencies?

Have you read the CONTRIBUTING guide?

  • [X] I've read the CONTRIBUTING guide

RochaStratovan avatar Jan 19 '24 23:01 RochaStratovan

I continued to play around with this and I found that the following steps appear to do what I want:

conan install . --output-folder=build --build=missing --settings=build_type=Release
conan install . --output-folder=build --build=missing --settings=build_type=Debug
conan install . --output-folder=build --build=missing --settings=build_type=RelWithDebInfo
cd build
cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake

However, I don't see this actually documentation that approves or sanctions this, but I recall wording in the introduction that I interpreted to say, "if it's not documented, it can be broken at any time by a new release."

RochaStratovan avatar Jan 20 '24 00:01 RochaStratovan

Hi @RochaStratovan

Your steps are completely correct. We try to describe about configurations in https://docs.conan.io/2/tutorial/consuming_packages/different_configurations.html, but it is true that it is not that explicit this for Visual Studio multi-configuration projects

In other parts like https://docs.conan.io/2/examples/tools/cmake/cmake_toolchain/build_project_cmake_presets.html#examples-tools-cmake-toolchain-build-project-presets it describes

We can call conan install to install both Release and Debug configurations. Conan will generate a conan_toolchain.cmake at the corresponding generators folder:

$ conan install . $ conan install . -s build_type=Debug

To install both configurations first

I am moving this ticket to the docs repo to try to improve this, thanks for the feedback!

memsharded avatar Jan 20 '24 12:01 memsharded

@memsharded should conan tell cmake to only generate the configurations that have been conan installed? E.g., by setting CMAKE_CONFIGURATION_TYPES or similar in the toolchain file.

I was stumped for a while trying the get the debug configuration to build when only Release had been conan installed (I didn't realise release was the conan default).

I'm also curious to know why conan install doesn't overwrite the previous build type, I couldn't see any file in build that looks like it keeps infomation relating to the previous installed configurations.

parched avatar Feb 26 '25 02:02 parched

This I've tried, does it make sense? Should something like this be added by default?

    def generate(self):
        tc = CMakeToolchain(self)

        # This stops extra configurations from being generated
        # See https://github.com/conan-io/docs/issues/3517
        if tc.is_multi_configuration:
            configuration_types = set([self.settings.get_safe("build_type")])

            preset_path = Path(self.generators_folder) / "CMakePresets.json"
            if preset_path.exists():
                preset = json.loads(preset_path.read_text())
                # Conan generated presets should have only 1 configurePreset, no more
                cache_variables = preset["configurePresets"][0]["cacheVariables"]
                if existing := cache_variables.get("CMAKE_CONFIGURATION_TYPES"):
                    configuration_types.update(existing.split(";"))

            tc.cache_variables["CMAKE_CONFIGURATION_TYPES"] = ";".join(
                sorted(configuration_types)
            )
        tc.generate()

And to answer my question as to why is doesn't overwrite the previous build type, it looks like actually reads in the previous toolchain file and updates individual variables.

parched avatar Feb 26 '25 03:02 parched

Hi @parched

Thanks for the feedback.

The

$ conan install .
$ conan install . -s build_type=Debug

Are mostly to install the different dependencies binaries, but is not that connected to the way they are consumed. You might have only Debug type in the consumer, and want to use sometimes the Release dependencies and other the Debug dependencies (this might be possible only in Linux, but not Windows)

The build type of the consumer can be explicitly defined with:

$ conan install . -s build_type=Release -s "&:build_type=Debug"
$ conan install . -s build_type=Debug

Also, modern CMake > 3.27 doesnt need explicit mapping of Configuration types, so users are free to pick what they want. The new CMakeConfigDeps generator in https://docs.conan.io/2/incubating.html does a step further and allows this automatic CMake mapping of configuration types for crossed configurations (consumer in Debug, dependencies in Release).

The recommendation would be then to not modify CMAKE_CONFIGURATION_TYPES, and Conan doesn't have plans to do it either. In the current version, explicit installation of build_types for dependencies and the current consumer is recommended, in the future the new CMakeConfigDeps generator will further simplify this.

memsharded avatar Feb 26 '25 10:02 memsharded