Reputation: 13589
I have been learning Conan for a personal project, and I have a question that I haven't been able to answer from looking at the docs and examples.
There seems to be an awkward lack of interaction between Conan's "profiles" and CMake. What I mean is: There are a number of different build parameters that must be manually kept in sync - running CMake with different parameters than the ones that were chosen during conan install
will result in build errors.
To give a more concrete example, here are two of my configs and how I would use them to build:
$ cat ~/.conan/profiles/gcc_debug
[settings]
os=Linux
os_build=Linux
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=10
compiler.libcxx=libstdc++11
build_type=Debug
[options]
[build_requires]
[env]
$ export CC=/usr/bin/gcc
$ export CXX=/usr/bin/g++
$ conan install ../src --profile gcc_debug
$ cmake ../src -GNinja -DCMAKE_BUILD_TYPE=Debug
$ cmake --build .
$ cat ~/.conan/profiles/clang_cl_release
[settings]
os=Windows
os_build=Windows
arch=x86_64
arch_build=x86_64
compiler=Visual Studio
compiler.version=16
compiler.toolset=ClangCL
build_type=Release
[options]
[build_requires]
[env]
$ conan install ../src --profile clang_cl_release
$ cmake ../src -G"Visual Studio 16 2019" -TClangCL
$ cmake --build . --config=Release
In the first example, I have to repeat gcc
and Debug
.
In the second one, I have to repeat Visual Studio
, 16
, ClangCL
, and Release
.
Having to repeat myself so many times feels smelly, especially when these options are spread out across multiple long-running commands, and forgetting one just option can result in non-obvious error messages. It also seems weird to me that Conan doesn't just enforce (override) the appropriate CMake vars when you call cmake_basic_setup()
; it already knows what values it expects, and blows up if they don't match.
What is the recommended way to handle this?
Upvotes: 3
Views: 3401
Reputation: 10486
Let Conan handle all the gory details in its build
function!
conanfile.py
from conan.tools.cmake import CMake, cmake_layout
...
requires = "fmt/7.1.3" # example requirement
generators = "CMakeToolchain", "CMakeDeps"
...
def layout(self):
cmake_layout(self)
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
...
CMakeLists.txt
cmake_minmum_required(VERSION 3.16)
project(my_project)
find_package(fmt REQUIRED) # Find dependency brought by Conan
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} fmt::fmt)
Terminal:
$ conan install -if build/Release . # Add -pr <profile> here
$ conan build -if build/Release .
You don't have to manually export GCC every time, put it under the [env]
section of your profile:
conan profile update "env.CC=/usr/bin/gcc" gcc_debug
⚠️ This is for Conan v1.X!
conanfile.py
from conans import CMake
...
generators = "cmake"
...
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
...
CMakeLists.txt
cmake_minmum_required(VERSION 3.16)
project(my_project)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
set(CONAN_SYSTEM_INCLUDES ON) # Hide GCC/Clang warnings in third-party libs
conan_basic_setup()
add_executable(${PROJECT_NAME} main.cpp)
conan_target_link_libraries(${PROJECT_NAME})
Terminal:
$ conan install -if build/Release . # Add -pr <profile> here
$ conan build -bf build/Release .
Your default generator can be specified this way (only works with cmake
generator):
conan profile update "env.CONAN_CMAKE_GENERATOR=Ninja" gcc_debug
Upvotes: 2
Reputation: 4677
See recommended conan usage: https://github.com/conan-io/cmake-conan
set(CONAN_PROFILE_NAME ${CMAKE_SYSTEM_NAME}-${CMAKE_GENERATOR})
execute_process(COMMAND ${CONAN_CMD} profile new ${CONAN_PROFILE_NAME} --detect ERROR_QUIET)
conan_cmake_autodetect(settings)
# REPEAT THIS FOR EACH OF YOUR REMOTES
conan_cmake_configure(REQUIRES zlib/1.2.0 GENERATORS cmake_find_package)
conan_cmake_install(PATH_OR_REFERENCE .
BUILD missing
REMOTE conancenter
PROFILE ${CONAN_PROFILE_NAME}
SETTINGS ${settings})
find_package(zlib)
Upvotes: 1
Reputation: 63
Normally you would use Conan to setup all your external libraries and then use them from CMake. You can however do the other way around: Let CMake call Conan to install the external dependencies.
Example code from How to launch conan install from cmake:
cmake_minimum_required(VERSION 2.8)
project(myproject CXX)
# Download automatically, you can also just copy the conan.cmake file
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/master/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake")
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_cmake_run(REQUIRES Catch2/2.6.0@catchorg/stable
BASIC_SETUP)
add_executable(main main.cpp)
target_link_libraries(main ${CONAN_LIBS})
Upvotes: 2
Reputation: 13589
I just started looking into conan build
, which seems promising. I had originally skipped over this because it looked like it only applied to people who were publishing a Conan package, but now I'm thinking it is meant for consumers as well. In fact, this page even explicitly mentions my problem statement:
This
conan build
will use the settings used in theconan install
which have been cached in the localconaninfo.txt
and file in your build folder. This simplifies the process and reduces the errors of mismatches between the installed packages and the current project configuration. [...] Implementing and using the conanfile.pybuild()
method ensures that we always use the same settings both in the installation of requirements and the build of the project, and simplifies calling the build system.
Upvotes: 0