I am trying to have the following CMake project working: the idea is to use cmake-conan to have cmake handle the conan install step (sparing the user the need to set up the profile etc).
However it fails to link to Boost.
# CMakelist.txt
cmake_minimum_required(VERSION 3.23.2)
# project name and language
project(MYAPP LANGUAGES CXX)
# we default to Release build type if DCMAKE_BUILD_TYPE not provided
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "C++ flags, Debug configuration: ${CMAKE_CXX_FLAGS_DEBUG}")
message(STATUS "C++ flags, Release configuration: ${CMAKE_CXX_FLAGS_RELEASE}")
message(STATUS "C++ flags, Release configuration with Debug info: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
message(STATUS "C++ flags, minimal Release configuration: ${CMAKE_CXX_FLAGS_MINSIZEREL}")
# Use modern C++ with support for concepts and mp-units
set(CMAKE_CXX_STANDARD 20)
# Prevent use of non-portable compiler extensions
set(CMAKE_CXX_EXTENSIONS OFF)
# This makes C++20 a requirement and prevents a "decay" to C++98 when the compiler does not support C++20.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Tell find_package() to first search using Config mode before falling back to Module mode (for conan)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
set(Boost_DEBUG ON)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
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/0.18.1/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake"
TLS_VERIFY ON)
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_cmake_configure(
REQUIRES
boost/1.79.0
GENERATORS
cmake_find_package
)
# By default, Conan only searches for packages from the two central repositories
# hosted and moderated by **Conan.io** staff: `conan-center` and `conan-transit`.
# We will need packages that are not hosted by these official repositories.
# The [Bincrafters](https://bincrafters.github.io/2017/06/06/using-bincrafters-conan-repository/)
# community posts new packages/versions every week in a separate Conan repository.
conan_add_remote(NAME bincrafters
URL https://bincrafters.jfrog.io/artifactory/api/conan/public-conan)
# Detect settings like OS and architecture
# I think it also detects CMake settings like gcc, gcc-version; cppstd, build_type etc
conan_cmake_autodetect(settings)
# Since GCC >= 5, the compiler is likely to be using the new CXX11 ABI by default (libstdc++11)
# See https://docs.conan.io/en/latest/howtos/manage_gcc_abi.html
conan_cmake_install(PATH_OR_REFERENCE .
BUILD missing
REMOTE conancenter bincrafters
SETTINGS
${settings}
compiler.libcxx=libstdc++11
)
find_package(Boost 1.79 REQUIRED COMPONENTS program_options REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app Boost::boost)
# We need C++ 20 activated with the concepts library
target_compile_features(my_app PUBLIC cxx_std_20)
// main.cpp
#include <boost/program_options.hpp>
namespace bpo = boost::program_options;
int main(int argc, char* argv[])
{
bpo::variables_map vm;
bool verbose = false;
return 0;
}
$ mkdir build && cd build
$ cmake -D CMAKE_BUILD_TYPE=Release \
-D CMAKE_C_COMPILER=/usr/bin/gcc-10 \
-D CMAKE_CXX_COMPILER=/usr/bin/g++-10 \
..
$ cmake --build .
The Conan profile defined on the fly during the configuration step (cmake ..
) is the following:
Configuration:
[settings]
arch=x86_64
arch_build=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=20
compiler.libcxx=libstdc++11
compiler.version=10
os=Linux
os_build=Linux
[options]
[build_requires]
[env]
CC=[/usr/bin/gcc-10]
CXX=[/usr/bin/g++-10]
[conf]
[ 50%] Building CXX object CMakeFiles/my_app.dir/main.cpp.o
[100%] Linking CXX executable my_app
/usr/bin/ld: CMakeFiles/my_app.dir/main.cpp.o: in function `main':
main.cpp:(.text.startup+0x24): undefined reference to `boost::program_options::variables_map::variables_map()'
/usr/bin/ld: main.cpp:(.text.startup+0x33): undefined reference to `vtable for boost::program_options::variables_map'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/my_app.dir/build.make:97: my_app] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/my_app.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
I have looked around for now two days and I could not find any lead (although I learned a lot).
Accordind the discussion in the comments, I updated the CMake file to ask for dependencies to be built from source. The conan.io/cmake-conan README documentation states that replacing the BUILD missing
by BUILD all
should work:
BUILD
(if this parameter takes theall
value, Conan will build everything from source)
So I tried it, removing the bincrafters reference and even trying to downgrade the Boost version to 1.77, or cleaning the conan cache with conan remove "*" -s -b -f
. But I still end with the exact same linking error.
cmake_minimum_required(VERSION 3.23.2)
# project name and language
project(MYAPP LANGUAGES CXX)
# we default to Release build type if DCMAKE_BUILD_TYPE not provided
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
# Use modern C++ with support for concepts and mp-units
set(CMAKE_CXX_STANDARD 20)
# Prevent use of non-portable compiler extensions
set(CMAKE_CXX_EXTENSIONS OFF)
# This makes C++20 a requirement and prevents a "decay" to C++98 when the compiler does not support C++20.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Tell find_package() to first search using Config mode before falling back to Module mode (for conan)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
set(Boost_DEBUG ON)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
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/0.18.1/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake"
TLS_VERIFY ON)
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_cmake_configure(
REQUIRES
boost/1.77.0
GENERATORS
cmake_find_package
)
# Detect settings like OS and architecture
# I think it also detects CMake settings like gcc, gcc-version; cppstd, build_type etc
conan_cmake_autodetect(settings)
# Since GCC >= 5, the compiler is likely to be using the new CXX11 ABI by default (libstdc++11)
# See https://docs.conan.io/en/latest/howtos/manage_gcc_abi.html
# The BUILD all option builds all dependencies from source every time
conan_cmake_install(PATH_OR_REFERENCE .
BUILD all
REMOTE conancenter
SETTINGS
${settings}
compiler.libcxx=libstdc++11
)
find_package(Boost 1.77 REQUIRED COMPONENTS program_options REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app Boost::boost)
During the configuration, I receive suspicious/intriguing outputs. I am not knowledgeable enough to know if they could be part of the solution, so here they are:
/home/becheler/.conan/data/libbacktrace/cci.20210118/_/_/build/19729b9559f3ae196cad45cb2b97468ccb75dcd1/source_subfolder/missing: Unknown `--is-lightweight' option
Try `/home/becheler/.conan/data/libbacktrace/cci.20210118/_/_/build/19729b9559f3ae196cad45cb2b97468ccb75dcd1/source_subfolder/missing --help' for more information
configure: WARNING: 'missing' script is too old or missing
Libraries have been installed in:
/home/becheler/.conan/data/libbacktrace/cci.20210118/_/_/package/19729b9559f3ae196cad45cb2b97468ccb75dcd1/lib
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,-rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'
notice: [python-cfg] Details of this Python configuration:
notice: [python-cfg] interpreter command: "python"
notice: [python-cfg] include path: "/home/becheler/dev/virtual_environments/conan-env/include/python3.8"
notice: [python-cfg] library path: "/home/becheler/dev/virtual_environments/conan-env/lib/python3.8/config" "/home/becheler/dev/virtual_environments/conan-env/lib"
notice: [python-cfg] Checking for NumPy...
notice: [python-cfg] running command 'python -c "import sys; sys.stderr = sys.stdout; import numpy; print(numpy.get_include())"'
notice: [python-cfg] NumPy disabled. Reason:
notice: [python-cfg] python -c "import sys; sys.stderr = sys.stdout; import numpy; print(numpy.get_include())" aborted with
notice: [python-cfg] Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
And maybe the most relevant concerns the components spelling:
- Conan: Using autogenerated FindBoost.cmake
-- Conan: Component 'program_options' found in package 'Boost'
... // ~~~~~~~~ A BIT LATER ~~~~~~~~~~~~~~~~~
-- Library boost_program_options found /home/becheler/.conan/data/boost/1.77.0/_/_/package/f54880bb9f17d8cef9b4d28f5cf70e057f105ac1/lib/libboost_program_options.a
-- Found: /home/becheler/.conan/data/boost/1.77.0/_/_/package/f54880bb9f17d8cef9b4d28f5cf70e057f105ac1/lib/libboost_program_options.a
... // ~~~~~~~~ A BIT LATER AGAIN ~~~~~~~~~~~~~~~~~
-- Library boost_program_options found /home/becheler/.conan/data/boost/1.77.0/_/_/package/f54880bb9f17d8cef9b4d28f5cf70e057f105ac1/lib/libboost_program_options.a
-- Found: /home/becheler/.conan/data/boost/1.77.0/_/_/package/f54880bb9f17d8cef9b4d28f5cf70e057f105ac1/lib/libboost_program_options.a
The solution to have a successful build was to change the default generator from Ninja to CMake, that is replacing GENERATORS cmake_find_package
by GENERATORS cmake
in the call the conan_cmake_configure
. I have no idea why!
Here is the successful CMake file:
cmake_minimum_required(VERSION 3.23.2)
# project name and language
project(MYAPP LANGUAGES CXX)
# we default to Release build type if DCMAKE_BUILD_TYPE not provided
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "C++ flags, Debug configuration: ${CMAKE_CXX_FLAGS_DEBUG}")
message(STATUS "C++ flags, Release configuration: ${CMAKE_CXX_FLAGS_RELEASE}")
message(STATUS "C++ flags, Release configuration with Debug info: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
message(STATUS "C++ flags, minimal Release configuration: ${CMAKE_CXX_FLAGS_MINSIZEREL}")
# Use modern C++ with support for concepts and mp-units
set(CMAKE_CXX_STANDARD 20)
# Prevent use of non-portable compiler extensions
set(CMAKE_CXX_EXTENSIONS OFF)
# This makes C++20 a requirement and prevents a "decay" to C++98 when the compiler does not support C++20.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Tell find_package() to first search using Config mode before falling back to Module mode (for conan)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
set(Boost_DEBUG ON)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
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/0.18.1/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake"
TLS_VERIFY ON)
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_cmake_configure(
REQUIRES
boost/1.77.0
GENERATORS
cmake
)
# Detect settings like OS and architecture
# I think it also detects CMake settings like gcc, gcc-version; cppstd, build_type etc
conan_cmake_autodetect(settings)
# Since GCC >= 5, the compiler is likely to be using the new CXX11 ABI by default (libstdc++11)
# See https://docs.conan.io/en/latest/howtos/manage_gcc_abi.html
# The BUILD all option builds all dependencies from source every time
conan_cmake_install(PATH_OR_REFERENCE .
BUILD all
REMOTE conancenter
SETTINGS
${settings}
compiler.libcxx=libstdc++11
compiler.cppstd=20
)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
# find_package(Boost 1.77 REQUIRED COMPONENTS program_options REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app CONAN_PKG::boost)
# We need C++ 20 activated with the concepts library
# target_compile_features(my_app PUBLIC cxx_std_20)
And then:
$ mkdir build && cd build
$ cmake -D CMAKE_BUILD_TYPE=Release \
-D CMAKE_C_COMPILER=/usr/bin/gcc-10 \
-D CMAKE_CXX_COMPILER=/usr/bin/g++-10 \
..
$ cmake --build .
The price to pay is that we get a bit far from the Conan 2.0 way of doing things, that is calling:
conan_cmake_configure()
conan_cmake_autodetect()
conan_cmake_install()
find_package()