Reputation: 23
Okay, the title is obviously weird. I hope anyone who can define my curiosity cleanly, would edit the title into proper one.
When using CMakeLists.txt, we usually import third-party packages via command find_package()
macro, which looks for proper find_XXX.cmake
script, and then results outputting variables such as XXX_LIBRARIES
, XXX_INCLUDE_DIRECTORIES
, etc.
However, recently I found some instruction guide for add_library()
macro, that can include actual library binaries as its source(?), like this way:
add_library(my_target STATIC IMPORTED foo.lib)
And as I guess, as long as the name my_target
is actually names a target, then we can add another compositions into that target, like any other cmake targets, like below.
target_inlcude_directories(my_target PUBLIC ${PKG_PREFIX}/include)
target_link_directories(my_target PUBLIC ${PKG_PREFIX}/lib)
target_compile_features(my_target PUBLIC std_cxx_17)
If this is possible, then wouldn't this be much cleaner way to describe exported package's compositions, rather than linking and adding those verbose *_LIBS
*_DIRS
variables manually for each? Like below?
add_executable(foo ${MY_SOURCES})
find_package(xxx)
# BEFORE
target_link_directories(foo PRIVATE ${XXX_LINK_DIRECTORIES}) # note: I don't remember what was it exactly.
target_link_libraries(foo PRIVATE ${XXX_LIBRARIES})
target_include_directories(foo PRIVATE ${XXX_INCLUDE_DIRECTORIES})
# AFTER
target_link_libraries(foo PRIVATE xxx::my_target)
Am I thinking something invalid?
Upvotes: 0
Views: 1360
Reputation: 141493
can we avoid using find_package to import other packages?
You can, but it's the tool to be used just for that. find_package()
is basically an include()
with some special options.
wouldn't this be much cleaner way to describe exported package's compositions, rather than linking and adding those verbose *_LIBS *_DIRS variables manually for each? Like below?
It would be and it is used.
cmake
is still ongoing relative big changes in a very short time. I think interface libraries weren't so popular or weren't available some time ago. The only (except some checks, etc) thing find_package
does is it includes a file named FindXXX.cmake
(or other file named differently). Only. It's completely dependent on what's inside the FindXXX.cmake
file what happens.
Newer cmake FindXXX.cmake
does exactly what you propose: they create an INTERFACE IMPORTED
library, for example on my pc:
@/usr/share/cmake-3.20/Modules
$ grep add_library -wr --include='Find*' .
.... a lot of results ....
./FindBoost.cmake: add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
./FindBoost.cmake: add_library(Boost::disable_autolinking INTERFACE IMPORTED)
./FindBoost.cmake: add_library(Boost::dynamic_linking INTERFACE IMPORTED)
./FindThreads.cmake: add_library(Threads::Threads INTERFACE IMPORTED)
./FindHDF5.cmake: add_library(HDF5::HDF5 INTERFACE IMPORTED)
./FindHDF5.cmake: add_library("hdf5::${hdf5_target_name}" INTERFACE IMPORTED)
./FindHDF5.cmake: add_library("hdf5::${hdf5_target_name}" UNKNOWN IMPORTED)
./FindHDF5.cmake: add_library("hdf5::${hdf5_target_name}" INTERFACE IMPORTED)
./FindHDF5.cmake: add_library("hdf5::${hdf5_target_name}" UNKNOWN IMPORTED)
./FindGTest.cmake: add_library(GTest::GTest INTERFACE IMPORTED)
./FindGTest.cmake: add_library(GTest::Main INTERFACE IMPORTED)
./FindGTest.cmake: add_library(GTest::gtest ${GTEST_LIBRARY_TYPE} IMPORTED)
./FindGTest.cmake: add_library(GTest::gtest_main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED)
./FindBZip2.cmake: add_library(BZip2::BZip2 UNKNOWN IMPORTED)
Older or "more standard" (ie. older :) indeed create multiple variables - XXX_LINK_DIRECTORIES
XXX_LIBRARIES
etc. Note that does variable names are not the same everywhere (XXX_LIB
? XXX_INC_DIRS
? etc.) and change depending on which FindXXX.cmake
you call because some developers decided on different names. A lot of documentation was written in the time the find_package
used variables, so it's still visible in documentation, but nowadays interface libraries clearly dominate and what you propose is already used.
Upvotes: 2
Reputation: 82461
Note that the imported library is not set up properly in this case. Configuration scripts (<packageName>Config.cmake
) which are used as fallback for find_package
or if you use the CONFIG
version usually do exactly this: create one or more imported targets for you to use in your project. I strongly recommend using those instead of the *_LIBS
/*_DIRS
variables, if available.
Here's the correct version of importing the library:
add_library(my_target STATIC IMPORTED)
# INTERFACE "visibility" needed here;
# also quote the path concatenation to avoid issues with spaces in PKG_PREFIX
target_include_directories(my_target INTERFACE "${PKG_PREFIX}/include")
target_link_directories(my_target INTERFACE "${PKG_PREFIX}/lib")
# do you really need the linking library to use the C++ 17 standard?
target_compile_features(my_target INTERFACE std_cxx_17)
# you need specify the absolute path to the lib as IMPORTED_LOCATION target property
# you may need to adjust the location according to the exact location of the lib file
#
# variables CMAKE_CURRENT_SOURCE_DIR (if used from CMakeLists.txt) or
# CMAKE_CURRENT_LIST_DIR (if used from a script) may be helpful
#
# requires seperate treatment for different OS; this is not included here
set_target_properties(my_target PROPERTIES IMPORTED_LOCATION "${PKG_PREFIX}/lib/my_target.a")
Note that in this case the library you need to link is my_target
, not xxx::my_target
.
Upvotes: 1