aminya / project_options

A general-purpose CMake library that provides functions that improve the CMake experience following the best practices.
https://aminya.github.io/project_options/
MIT License
352 stars 52 forks source link

Library options are not exported to calling projects #275

Open pmatalon opened 2 months ago

pmatalon commented 2 months ago

I have a header-only library project, and I am using project_options to package it, so that it can be used as a dependency for other projects. The library has numerous options, defined with the cmake functions option or set. What I want is to export those options, so that calling projects can configure them. Here is the skeleton of its CMakeLists.txt, with the options WITH_OPENMP and CHECK_NAN:

project(my_lib LANGUAGES CXX)

(...) 

project_options(
  ENABLE_CACHE
  # ...other arguments
)

add_library(my_lib INTERFACE)
target_link_libraries(my_lib INTERFACE project_options project_warnings)

set(INCLUDE_DIR "include")
target_include_directories(my_lib INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_DIR}>"
                          "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")

# dependencies
set(DEPENDENCIES_CONFIGURED pugixml fmt)
foreach(DEPENDENCY ${DEPENDENCIES_CONFIGURED})
  find_package(${DEPENDENCY} CONFIG REQUIRED)
endforeach()
target_link_system_libraries(my_lib INTERFACE pugixml::pugixml fmt::fmt)

# optional dependency
option(WITH_OPENMP "Enable OpenMP" OFF)
if(${WITH_OPENMP})
  find_package(OpenMP)
  target_link_libraries(my_lib INTERFACE OpenMP::OpenMP_CXX)
  target_compile_definitions(my_lib INTERFACE MYLIB_WITH_OPENMP)
endif()

# another option
option(CHECK_NAN "Check if NaN occur in computations" OFF)
if(CHECK_NAN)
  target_compile_definitions(my_lib INTERFACE MYLIB_CHECK_NAN)
endif()

(...)

# packaging of the project
package_project(
  TARGETS my_lib project_options project_warnings libdeps
  INTERFACE_DEPENDENCIES_CONFIGURED ${DEPENDENCIES_CONFIGURED}
  INTERFACE_INCLUDES ${INCLUDE_DIR}
)

Now, another project has my_lib as a dependency. Here is its CMakeLists.txt:

project(caller_project CXX)
find_package(my_lib CONFIG REQUIRED)
add_executable(caller_project main.cpp)
target_link_libraries(caller_project PRIVATE my_lib::my_lib my_lib::project_options my_lib::project_warnings my_lib::libdeps)

# How do I set the options WITH_OPENMP and CHECK_NAN of `my_lib`?

The compilation of caller_project works fine with this CMakeLists.txt. My problem is that I can't set my_lib's options. I think the options are simply not exported, since I don't see them when I use the ccmake command. (On the other hand, if my_lib's dependencies have options themselves, I can see them in ccmake.) I tried using dynamic_project_options with and without ENABLE_CACHE, but no luck... Thank you for your support.

Upvote & Fund

@aminya is using Polar.sh so you can upvote and help fund this issue. The funding is received once the issue is completed & confirmed by you.

Thank you in advance for helping prioritize & fund our backlog!


Fund with Polar

ClausKlein commented 2 months ago

If you want to change the default config values of a sub project set the options before call FetchContent_MakeAvailable() orfind_package()`! i.e.:

include(FetchContent)

FetchContent_Declare(
    glfw
    GIT_REPOSITORY  https://github.com/glfw/glfw.git
    SOURCE_DIR      "${CMAKE_CURRENT_SOURCE_DIR}/glfw-src"
    GIT_TAG         "master"
    GIT_SHALLOW     TRUE
)
set(GLFW_BUILD_WAYLAND  ON)
set(GLFW_BUILD_X11      OFF)
FetchContent_MakeAvailable(glfw)

or

option(USE_BOOST "build with BOOST support" ON)
if(USE_BOOST)
  option(Boost_DEBUG "find boost at verbose mode" OFF)
  option(Boost_USE_STATIC_LIBS "use static libs only" OFF)
  option(Boost_USE_MULTITHREADED "use -mt libs only" ON)

  find_package(Boost 1.71 CONFIG REQUIRED COMPONENTS atomic chrono filesystem thread unit_test_framework)
  if(Boost_FOUND)
    add_definitions(-DBOOST_ALL_NO_LIB)
    include_directories(include)
  endif()
endif()
pmatalon commented 2 months ago

Thank you for your quick answer. I'll try to clarify my question. The options are in my library project, which uses package_options for the packaging. I configured the CMakeLists.txt so that If an option is activated, other dependencies are included, compilation options are defined, etc. Now, in a caller project, I want to be able to set those options in my library, thus triggering the linking of other dependencies, compile options for my library, etc. Unfortunately, it seems that my library's options are not exported, so the caller project cannot set them. When I use the ccmake command on the caller project, I can see all available options: the options of all dependencies are present, except those of my library.

ClausKlein commented 2 months ago

What do you mean with package_options?

They are not at https://github.com/aminya/project_options?tab=readme-ov-file#readme

ClausKlein commented 2 months ago

see too https://github.com/aminya/project_options/pull/276/files#r1744556217

pmatalon commented 2 months ago

What do you mean with package_options?

They are not at https://github.com/aminya/project_options?tab=readme-ov-file#readme

Sorry, I meant project_options.

pmatalon commented 2 months ago

I have updated the text of the issue to include a more detailed CMakeLists.txt and re-explain the problem.

ClausKlein commented 2 months ago

Your logic is wrong!

An interface library is anheader only implementation. Thefind_package(OpenMP) and the resulting compile_defintions must be done by the user of your exported cmake package!

You need something like this https://github.com/ClausKlein/boost-modules-bench/blob/develop/asio-module/AsioConfig.cmake.in

And this is not supported by project_options.

pmatalon commented 1 month ago

I agree that the config can be done by the user, but the work that must be done if an option is activated may be complicated, and it would simplify the user's job if that work was done for him upon a simple option's activation. Using only standard cmake functions, you indeed need a Config.cmake.in file to do that. project_options does not support it, ok.