boostorg / cmake

CMake support infrastructure Boost submodule
87 stars 26 forks source link

BoostConfig creates targets which are not available when using boost from subdirectory #61

Closed vasil-pashov closed 4 months ago

vasil-pashov commented 4 months ago

Summary

BoostConfig creates additional "Compatibility targets" here. These targets, however, are not created if Boost is added as a subdirectory to an existing project, which leads to link errors.

Context

I'm trying to build OpenVDB with Boost as a dependency. I'm using Cmake's FetchContent with OVERRIDE_FIND_PACKAGE enabled. OpenVDB uses find_package to find Boost and links to Boost::disable_autolinking which is not created when Boost is used as subdirectory.

Repro ```cmake # CMakeLists.txt cmake_minimum_required(VERSION 3.29.2) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) project(my_project) include(FetchContent) set(BUILD_EXAMPLES OFF) FetchContent_Declare( zlib URL https://github.com/madler/zlib/releases/download/v1.3.1/zlib131.zip OVERRIDE_FIND_PACKAGE ) set(BUILD_TESTS OFF) set(BUILD_FUZZERS OFF) set(BUILD_BENCHMARKS OFF) set(BUILD_EXAMPLES OFF) FetchContent_Declare( blosc URL https://github.com/Blosc/c-blosc/archive/refs/tags/v1.21.5.zip OVERRIDE_FIND_PACKAGE ) set(TBB_TEST OFF) set(TBB_INSTALL OFF) FetchContent_Declare( tbb GIT_REPOSITORY https://github.com/oneapi-src/oneTBB GIT_TAG v2021.13.0-rc1 OVERRIDE_FIND_PACKAGE ) FetchContent_Declare( boost URL https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.xz URL_HASH SHA256=2e64e5d79a738d0fa6fb546c6e5c2bd28f88d268a2a080546f74e5ff98f29d0e OVERRIDE_FIND_PACKAGE ) FetchContent_Declare( openvdb URL https://github.com/AcademySoftwareFoundation/openvdb/archive/refs/tags/v11.0.0.zip OVERRIDE_FIND_PACKAGE ) FetchContent_MakeAvailable(zlib blosc tbb boost openvdb) add_library(Blosc::blosc ALIAS blosc_shared) add_library(ZLIB::ZLIB ALIAS zlib) add_executable(my_project main.cpp) ```

Current workaround

I'm adding a boost-extra.cmake file which contains a copy of the code creating the target.

Code ```cmake FetchContent_Declare( boost URL https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.xz URL_HASH SHA256=2e64e5d79a738d0fa6fb546c6e5c2bd28f88d268a2a080546f74e5ff98f29d0e OVERRIDE_FIND_PACKAGE ) file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/boost-extra.cmake [=[ add_library(Boost::boost INTERFACE IMPORTED) set_property(TARGET Boost::boost APPEND PROPERTY INTERFACE_LINK_LIBRARIES Boost::headers) add_library(Boost::diagnostic_definitions INTERFACE IMPORTED) add_library(Boost::disable_autolinking INTERFACE IMPORTED) add_library(Boost::dynamic_linking INTERFACE IMPORTED) if(WIN32) set_property(TARGET Boost::diagnostic_definitions PROPERTY INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC") set_property(TARGET Boost::disable_autolinking PROPERTY INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB") set_property(TARGET Boost::dynamic_linking PROPERTY INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK") endif() ]=] ) ```

I think this pollutes the project and is not much future-proof.

Desired solution

Building from a subdirectory should export the same targets as installing Boost and using find_package.

Environment Details

Boost version: 1.85 OS: Windows 11 CMake version: 3.29.2

pdimov commented 4 months ago

It's easy enough to add Boost::diagnostic_definitions, Boost::disable_autolinking, and Boost::dynamic_linking, but Boost::headers doesn't do anything from a subdirectory.

vasil-pashov commented 4 months ago

Adding Boost::diagnostic_definitions, Boost::disable_autolinking, and Boost::dynamic_linking would solve my issue.

Regarding Boost::headers isn't it just an alias for Boost::boost at least that's what the docs say about it. I think it would be nice to have it as well to cover something like this:

# Top level CMake
FetchContent_Declare(
boost
GIT_REPOSITORY ...
OVERRIDE_FIND_PACKAGTE
)
# Some subdir or another project fetched via FetchContent
find_package(boost REQUIRED)
target_link_libraries(proj PIRVATE Boost::headers)
pdimov commented 4 months ago

Boost::headers and Boost::boost are the targets for header-only libraries. When Boost is installed, all headers go into the same directory, so one only needs a single include path, which these two targets provide.

When using Boost as a subdirectory, though, the library headers are in their respective library directories, so from CMake you have to link to the library targets even when they are header-only.

vasil-pashov commented 4 months ago

Ah, you're right! I've stumbled upon this yesterday and it made me scratch my head. Now I get it. Thanks! In this case do you think it's reasonable to have something like this?

# If boost is a subproject
if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
  add_library(Boost::headers INTERFACE)
  target_include_directories(Boost::headers INTERFACE lib1_headers lib2_headers ...)
endif()
pdimov commented 4 months ago

Maybe, although that's going to add something like 150 include paths, not sure how reasonable that's going to be in practice. :-)

vasil-pashov commented 4 months ago

Yeah, you have a point. In a perfect world find_package and using it from source should behave exactly the same. I'm personally willing to have have large list of include directories (until it makes me hurt) but I understand that you have to think about all other users. Maybe hiding the target behind some flag would be worth it... Anyway having Boost::diagnostic_definitions, Boost::disable_autolinking, and Boost::dynamic_linking would be nice.

pdimov commented 4 months ago

OK, I added support for BOOST_ENABLE_COMPATIBILITY_TARGETS=ON to develop.

vasil-pashov commented 4 months ago

Awesome, thanks. I'm closing this.