Building for multiple configurations: Release, Debug, Static and Shared

Important

In this example, we will retrieve the CMake Conan package from a Conan repository with packages compatible with Conan 2.0. To run this example successfully you should add this remote to your Conan configuration (if did not already do it) doing: conan remote add conanv2 https://conanv2beta.jfrog.io/artifactory/api/conan/conan --index 0

Please, first clone the sources to recreate this project. You can find them in the examples2.0 repository in GitHub:

$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/consuming_packages/different_configurations

So far, we built a simple CMake project that depended on the zlib library and learned about tool_requires, a special type or requirements for build-tools like CMake. In both cases, we did not specify anywhere that we wanted to build the application in Release or Debug mode, or if we wanted to link against static or shared libraries. That is because Conan, if not instructed otherwise, will use a default configuration declared in the ‘default profile’. This default profile was created in the first example when we run the conan profile detect command. Conan stores this file in the /profiles folder, located in the Conan user home. You can check the contents of your default profile by running the conan config home command to get the location of the Conan user home and then showing the contents of the default profile in the /profiles folder:

$ conan config home
Current Conan home: /Users/tutorial_user/.conan2

# output the file contents
$ cat /Users/tutorial_user/.conan2/profiles/default
[settings]
os=Macos
arch=x86_64
compiler=apple-clang
compiler.version=13.0
compiler.libcxx=libc++
compiler.cppstd=gnu98
build_type=Release
[options]
[tool_requires]
[env]

As you can see, the profile has different sections. The [settings] section is the one that has information about things like the operating system, architecture, compiler, and build configuration. When you call a Conan command setting the --profile argument, Conan will take all the information from the profile and apply it to the packages you want to build or install. If you don’t specify that argument it’s equivalent to call it with --profile=default. These two commands will behave the same:

$ conan install . --build=missing
$ conan install . --build=missing --profile=default

You can store different profiles and use them to build for different settings. For example, to use a build_type=Debug, or adding a tool_requires to all the packages you build with that profile. One example of a debug profile could be:

<conan home>/profiles/debug
[settings]
os=Macos
arch=x86_64
compiler=apple-clang
compiler.version=13.0
compiler.libcxx=libc++
compiler.cppstd=gnu98
build_type=Debug

Modifying settings: use Debug configuration for the application and its dependencies

Using profiles is not the only way to set the configuration you want to use. You can also override the profile settings in the Conan command using the --settings argument. For example, you can build the project from the previous examples in Debug configuration instead of Release.

Before building, please check that we modified the source code from the previous example to show the build configuration the sources were built with:

#include <stdlib.h>
...

int main(void) {
    ...
    #ifdef NDEBUG
    printf("Release configuration!\n");
    #else
    printf("Debug configuration!\n");
    #endif

    return EXIT_SUCCESS;
}

Now let’s build our project for Debug configuration:

$ conan install . --output-folder=build --build=missing --settings=build_type=Debug

As we explained above, this is the equivalent of having debug profile and running these command using the --profile=debug argument instead of the --settings=build_type=Debug argument.

This conan install command will check if we already installed the required libraries (Zlib) in Debug configuration and install them otherwise. It will also set the build configuration in the conan_toolchain.cmake toolchain that the CMakeToolchain generator creates so that when we build the application it’s built in Debug configuration. Now build your project as you did in the previous examples and check in the output how it was built in Debug configuration:

Windows
# assuming Visual Studio 15 2017 is your VS version and that it matches your default profile
$ cd build
$ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
$ cmake --build . --config Debug
$ Debug\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.2.11
Debug configuration!
Linux, macOS
$ cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug
$ cmake --build .
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.2.11
Debug configuration!

Modifying options: linking the application dependencies as shared libraries

So far, we have been linking Zlib statically in our application. That’s because in the Zlib’s Conan package there’s an attribute set to build in that mode by default. We can change from static to shared linking by setting the shared option to True using the --options argument. To do so, please run:

Windows
$ conan install . --output-folder=build --build=missing --options=zlib/1.2.11:shared=True

Doing this, Conan will install the Zlib shared libraries, generate the files to build with them and, also the necessary files to locate those dynamic libraries when running the application. Let’s build the application again after configuring it to link Zlib as a shared library:

Windows
$ cd build
# assuming Visual Studio 15 2017 is your VS version and that it matches your default profile
$ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
$ cmake --build . --config Release
...
[100%] Built target compressor
Linux, Macos
$ cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
...
[100%] Built target compressor

Now, if you try to run the compiled executable you will see an error because the executable can’t find the shared libraries for Zlib that we just installed.

Windows
$ Release\compressor.exe
(on a pop-up window) The code execution cannot proceed because zlib1.dll was not found. Reinstalling the program may fix this problem.
Linux, Macos
$ ./compressor
./compressor: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

This is because shared libraries (.dll in windows, .dylib in OSX and .so in Linux), are loaded at runtime. That means that the application executable needs to know where are the required shared libraries when it runs. On Windows, the dynamic linker will search in the same directory then in the PATH directories. On OSX, it will search in the directories declared in DYLD_LIBRARY_PATH as on Linux will use the LD_LIBRARY_PATH.

Conan provides a mechanism to define those variables and make it possible, for executables, to find and load these shared libraries. This mechanism is the VirtualRunEnv generator. If you check the output folder you will see that Conan generated a new file called conanrun.sh/bat. This is the result of automatically invoking that VirtualRunEnv generator when we activated the shared option when doing the conan install. This generated script will set the PATH, LD_LIBRARY_PATH, DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH environment variables so that executables can find the shared libraries.

Activate the virtual environment, and run the executables again:

Windows
$ conanrun.bat
$ Release\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
...
Linux, macOS
$ source conanrun.sh
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
...

Just as in the previous example with the VirtualBuildEnv generator, when we run the conanrun.sh/bat script a deactivation script called deactivate_conanrun.sh/bat is created to restore the environment. Source or run it to do so:

Windows
$ deactivate_conanrun.bat
Linux, macOS
$ source deactivate_conanrun.sh

Difference between settings and options

You may have noticed that for changing between Debug and Release configuration we used a Conan setting, but when we set shared mode for our executable we used a Conan option. Please, note the difference between settings and options:

  • settings are typically a project-wide configuration defined by the client machine. Things like the operating system, compiler or build configuration that will be common to several Conan packages and would not make sense to define one default value for only one of them. For example, it doesn’t make sense for a Conan package to declare “Visual Studio” as a default compiler because that is something defined by the end consumer, and unlikely to make sense if they are working in Linux.
  • options are intended for package-specific configuration that can be set to a default value in the recipe. For example, one package can define that its default linkage is static, and this is the linkage that should be used if consumers don’t specify otherwise.

Read more

  • Installing configurations with conan config install
  • VS Multi-config
  • Example about how settings and options influence the package id
  • Cross-compiling using –profile:build and –profile:host
  • Using patterns for settings and options