Reputation: 1745
I'm trying to use FetchContent
CMake helper to automate building required dependencies in case they are not installed/available through find_package
, but hitting a wall at how to handle exporting the build targets.
My own project e.g. needs TinyXML2 as a dependency:
## TinyXML2
find_package(tinyxml2 QUIET)
if (${tinyxml2_FOUND})
message(STATUS "tinyxml2 FOUND!(${tinyxml2_LIBRARIES})")
echo_all_cmake_variable_values()
else()
message(STATUS "tinyxml2 NOT FOUND, fetching from source!")
FetchContent_Declare(tinyxml2
GIT_REPOSITORY https://github.com/leethomason/TinyXML2
GIT_TAG 9.0.0
)
FetchContent_MakeAvailable(tinyxml2)
set(tinyxml2_LIBRARIES tinyxml2)
endif()
Which is then used to link the project targets:
# ...
target_link_libraries(${PROJECT_NAME} PUBLIC ${Boost_LIBRARIES}
pthread
${tinyxml2_LIBRARIES})
And the linked target is then exported:
# ...
export(EXPORT ${PROJECT_NAME}Targets
FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake
NAMESPACE ${PROJECT_NAME}::)
The issue is that, when fetching from source, the export step fails:
CMake Error in src/myproject/CMakeLists.txt:
export called with target "myproject" which requires target "tinyxml2" that
is not in any export set.
Is there a way to also auto-export tinyxml2
as a required dependency?
Upvotes: 10
Views: 3176
Reputation: 19936
Is there a way to also auto-export
tinyxml2
as a required dependency?
Not as of CMake 3.23 (pre-release).
When you use FetchContent, it's as if you wrote the "third-party" code yourself. CMake has no idea that it's external. This is called "vendoring" code.
Because you aren't going through find_package
, you will need to install()
"your" target like any other dependency that you will export. It will export into your namespace, too, to avoid conflicts with other copies of tinyxml2
that might be floating around.
I also find this tedious, which is why I shy away from FetchContent
for anything that might be installed or exported and use proper source-based package management tools like vcpkg instead. Such tools let you use find_package
to locate your dependencies, which is (imo) what you should be doing 100% of the time, anyway.
Also, your code is wrong (see my top level comment). Here's a more correct version (I would just say find_package(tinyxml2 REQUIRED)
, personally).
## TinyXML2
find_package(tinyxml2 QUIET)
if (NOT tinyxml2_FOUND)
message(STATUS "tinyxml2 NOT FOUND, fetching from source!")
FetchContent_Declare(tinyxml2
GIT_REPOSITORY https://github.com/leethomason/TinyXML2
GIT_TAG 9.0.0
)
FetchContent_MakeAvailable(tinyxml2)
install(
TARGETS tinyxml2
EXPORT ${PROJECT_NAME}Targets
# More arguments as necessary...
)
endif ()
# ... usage ...
target_link_libraries(${PROJECT_NAME} PUBLIC ${Boost_LIBRARIES}
pthread
tinyxml2::tinyxml2)
This is less typing than going through a variable, too.
Upvotes: 8