Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"config-style" cmake find_package unusable in parent scope

Tags:

cmake

I have the following structure

project_root/
    CMakeLists.txt     (A)
    ext/
        CMakeLists.txt (B)
    apps/
        CMakeLists.txt (C)

The setup seems to be the fundamental issue, only when adding this new "config-style" library.

TL;DR: when find_package(foo) in (B) defines foo::foo as the library, how can I make foo::foo available in the parent scope so that target_link_libraries(tgt foo) will work for both (A) and (C)?

  1. List (A) defines my project's options, such as what drivers to compile support for.
  2. add_subdirectory(ext) takes place, and the needed external libraries are found. They are a mixture of add_subdirectory and find_package. List (B) populates lists for extra include directories, libraries, and compile time definitions, making them available to (A) (and subsequently (C)) with

    set(MYPROJ_EXTRA_INC_DIRS "${MYPROJ_EXTRA_INC_DIRS}" PARENT_SCOPE)
    set(MYPROJ_EXTRA_LIBS     "${MYPROJ_EXTRA_LIBS}"     PARENT_SCOPE)
    set(MYPROJ_EXTRA_DEFINES  "${MYPROJ_EXTRA_DEFINES}"  PARENT_SCOPE)
    
  3. List (A) now adds my library, including these extra directories, adding these extra definitions, and ultimately

    target_link_libraries(${MYPROJ_LIB_NAME} ${MYPROJ_EXTRA_LIBS})
    
  4. When the applications are requested to be built, add_subdirectory(apps) takes place, and list (C) defines a simple macro that creates an executable using the specified dependencies. The relevant part

    target_link_libraries(${appName} ${MYPROJ_LIB_NAME} ${MYPROJ_EXTRA_LIBS})
    

This has been working very well for a long time. However, I added support for a new library that uses config-style find_package definitions, and I can't figure out how to use it correctly.

Call this new library dependency foo. It ultimately defines a single foo_LIBRARY which is foo::foo. My understanding was that I would need to do target_link_libraries(tgt foo), which works in list (A) for my library. However, it does not work for the applications, and in the macro I have to do find_package(foo) again for every executable.

Is there a way to use the existing approach (list(APPEND MYPROJ_EXTRA_LIBS <something>)) that does not require running find_package every time?

I've exhausted every reasonable option, and either get that -lfoo is not defined (if I just append foo to the list like I thought I should be), or find_package() is missing for an IMPORTED or ALIAS target. AKA since find_package(foo) happens in (B), by the time we reach (C) this target is not available. I tried making an ALIAS, but the error was then something that amounts to ALIAS cannot be created to an IMPORTED library.

like image 678
svenevs Avatar asked Jan 28 '26 06:01

svenevs


1 Answers

Results of find_package call(both CONFIG and MODULE) are intended be used in the same directory or below. You are just lucky in that simple propagating of variables into PARENT_SCOPE makes results of find_package usable by the parent.

add_subdirectory(ext) takes place, and the needed external libraries are found.

Instead of ext/CMakeLists.txt included with add_subdirectory create CMake file (e.g. external.cmake) for being included via include. Because include command doesn't introduce new variable's scope, its find_package calls works for the main CMakeLists.txt.

Many existed projects process their dependencies in include files.


Another approach would be propagating results of find_package calls from subdirectory to the parent by creating INTERFACE library target which itself uses these results:

add_library(MyLibExtra INTERFACE)
target_link_libraries(MyLibExtra INTERFACE ${MYPROJ_EXTRA_LIBS})
target_include_directories(MyLibExtra INTERFACE ${MYPROJ_EXTRA_INC_DIRS})
target_compile_definitions(MyLibExtra INTERFACE ${MYPROJ_EXTRA_DEFINES})
like image 166
Tsyvarev Avatar answered Jan 30 '26 14:01

Tsyvarev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!