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 /
signature.asc
Description: This is a digitally signed message part
-- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake