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)?
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)
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})
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.
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})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With