I hate starting a topic that is so similar to so many others, but I haven’t found a clear explanation of how to get from where I am to where I want to be. I’ve read the Importing and Exporting Guide and all the questions here that were even closely related, and I’m still lost.
I’m currently trying to take some “utility” stuff that I use in every (business, not CMake) project, an package it for general use in the company. Currently, this includes 3 directories, each of which builds a library; some are shared, some are static.
Because I hate copy/pasta, I defined a macro to declare a library such that the specific library really only needs to define its sources (but it’s incomplete). This macro looks like this:
macro( DeclLib target linkage )
set(myTarget ${target})
set(myDepend ${target})
set(myTest ${target}UnitTest)
set(myLinkage ${linkage})
add_library( ${myTarget} ${linkage} )
cmake_path(GET CMAKE_CURRENT_SOURCE_DIR PARENT_PATH target_inc_dir)
message(INFO " for target=${target}"
" linkage=${linkage}"
" source=${CMAKE_CURRENT_SOURCE_DIR}"
" inc=${target_inc_dir}"
)
target_include_directories( ${myTarget} PUBLIC
"$<BUILD_INTERFACE:${target_inc_dir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
file(GLOB target_inc_files
*.hh *.h *.hpp *.cuh)
### THIS IS PROBLEMATIC ... what is the point of FILE_SET exactly?
# target_sources( ${myTarget} INTERFACE
# FILE_SET inc
# TYPE HEADERS
# BASE_DIRS ${target_inc_dir}
# )
install(FILES ${target_inc_files}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(TARGETS ${myTarget}
EXPORT foo
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
endmacro()
If I uncomment out the FILE_SET, I get an error:
install TARGETS target XXX is exported but not all of its interface file
sets are installed
This is on the install(TARGETS...)
line of the macro, called from each library.
Rather than fight with that, I left it commented out.
After all the subdirs are included, I have:
install(EXPORT foo
FILE foo.cmake
NAMESPACE foo::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/foo
)
Now, I have an external dependency issue. One of my libraries provides some wrapper around GoogleTest to make it more suitable for our use. This CMakeLists.txt file includes:
DeclLib(gtestApp SHARED)
# build the library
target_sources( ${myTarget}
PRIVATE
${target_sources}
)
target_include_directories( ${myTarget}
PRIVATE
# this was required or it wouldn't find the "util" include path
$<TARGET_PROPERTY:util,INTERFACE_INCLUDE_DIRECTORIES>
)
target_link_libraries( ${myTarget} INTERFACE
util
gtest
)
(GoogleTest is brought in by FetchContent
in the top-level CMakeLists.txt)
This results in an error:
CMake Error: install(EXPORT "foo" ...) includes target "gtestApp" which requires target "gtest" that is not in any export set.
I don’t want to export gtest; I just want to depend on it. I feel like I’m in a maze of twisty passages, all alike. I’m likely to be eaten by a grue.
First, am I even going in the right direction? Is there a better way to make this available to other projects? My thought is that I’d like for this package to be available using FetchContent
like any other third party thing.