简体   繁体   中英

Linking Boost when using cmake-conan

1 - Initial situation

Problem description

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.

System configuration

  • Ubuntu 20.04.4 LTS
  • cmake version 3.23.2 (via snap)
  • Conan version 1.49.0 (via virtual env)
  • gcc (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0
  • Python 3.8.10

Minimal example

# 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;
}

Configuration & build

$ 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]

Error message

[ 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).

2 - Progress

Building Boost from source, always

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 the all 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)

Configuration snippets

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:

  1. conan_cmake_configure()
  2. conan_cmake_autodetect()
  3. conan_cmake_install()
  4. find_package()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM