[CMake] Private dependencies of static libraries exported as targets
Ivan Shapovalov
intelfx at intelfx.name
Mon Aug 15 21:32:33 EDT 2016
Hello,
So I'm trying to learn how to do CMake in a modern way. If I understand
correctly, the "modern way" is to use IMPORTED targets.
Preamble
--------
I have a project which builds a library `foo`. This library can be
built as static or shared, depending on value of BUILD_SHARED_LIBS. My
CMakeLists.txt does not perform any special handling of either case.
It links to a library `bar`, which is an implementation detail, i. e.
clients of `foo` do not need to know that I use `bar`. Hence I make it
a PRIVATE dependency (let's assume that authors of Bar also try to do
modern CMake and package their library using IMPORTED targets):
# somewhere in BarConfig.cmake
add_library(bar STATIC IMPORTED ...)
set_target_properties(bar PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${_IMPORT_PREFIX}/include
IMPORTED_LOCATION ${_IMPORT_PREFIX}/lib/libfoo.a)
# somewhere in my CMakeLists.txt
find_package(Bar)
add_library(foo ... EXPORT FooTargets)
target_include_directories(foo ...)
target_link_libraries(foo PRIVATE bar)
install(TARGETS foo DESTINATION lib)
install(EXPORT FooTargets DESTINATION lib/cmake/Foo)
# this file does find_package(Bar) and includes FooTargets.cmake
configure_file(FooConfig.cmake.in FooConfig.cmake @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake DESTINATION lib/cmake/Foo)
Problem
-------
If library `foo` is built as shared, then everything is fine because:
- if library `bar` is built as static, then its code is simply added
to library `foo` at link time => everything OK
- if library `bar` is built as shared, then the runtime linker will
recursively load it when library `foo` is loaded => everything OK
But, if library `foo` is built as static, then its clients suddenly
become required to link to `bar` as well, and this information is not
recorded anywhere!
Possible Solution #1
--------------------
I could wrap `target_link_libraries()` into a function which says
PRIVATE or PUBLIC dependent on whether we are building a SHARED or
STATIC library respectively:
function(foo_target_link_private_library target library)
if(BUILD_SHARED_LIBS)
target_link_libraries(${target} PRIVATE ${library})
else
target_link_libraries(${target} PUBLIC ${library})
endfunction()
But this feels like a hack and adds include path bloat: the clients of
`foo` will never need `bar`'s include pathes, even if `bar` is static.
I could imagine creating fake targets like `bar_for_static` and copying
there `bar`'s IMPORTED_LOCATION and INTERFACE_LINK_FLAGS but not
INTERFACE_INCLUDE_DIRECTORIES (and then link to `bar_for_static` in
`foo`'s interface), but this is even more gross.
Is there anything less hackish or more idiomatic?
Thanks,
--
Ivan Shapovalov / intelfx /
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://public.kitware.com/pipermail/cmake/attachments/20160816/871cbb9a/attachment.sig>
More information about the CMake
mailing list