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 /

Attachment: 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

Reply via email to