3

How do I remove libraries added with link_libraries()?

Yes, I know I should use target_link_libraries(). I can`t because I must link a library to every future target. See this. The library is CMake built. This should be invisible to the C++/CMake developer. He should not have to worry about this lib. Example:

add_library(link-to-all a.cpp)
link_libraries(link-to-all)
add_executable(e1 e1.cpp) # with link-to-all
add_executable(e2 e2.cpp) # with link-to-all
unlink_libraries(link-to-all) #does not exist!
add_executable(e3 e3.cpp) # without link-to-all
# all further targets link without link-to-all!

In my case link-to-all is a library with implementation for coverage checking functions. It is enabled depending on a configuration option and should be implicitly used for all coming targets. Coverage analysis may be disabled for specific targets, so I want to be able to disable it.

The coverage is enabled by prepending CMAKE_<LANG>_COMPILE_OBJECT and disabled by removing the prefix. Afaik this cannot be done target specific, only global for coming targets. So unlink_libraries() would be a function that i can call symmetrically.

function(enable_coverage)
   prepend_compiler();
   link_libraries(cov);
   # alternative with loosing target information/dependency
   # prepend_system_libs(<path>/libcov.a)
endfunction()
function(disable_coverage)
   reset_compiler();
   unlink_libraries(cov);
   # reset_system_libs()
endfunction()

I could use CMAKE_<LANG>_STANDARD_LIBRARIES, (and also remove it there) but I would need the LOCATION of the library (generator expression: TARGET) in there. But I would also lose the interfaces of link-to-all. Also, that would probably remove the build dependencies.

kuga
  • 1,483
  • 1
  • 17
  • 38
  • 1
    Related: https://stackoverflow.com/questions/49599673/cmake-remove-added-libraries – Kevin Oct 01 '19 at 16:26
  • 1
    I would instead make requirements explicit everywhere. Implicit linking to a library to be linked to all but one is error prone, more complicated than linking directly and lead to error like this. – Guillaume Racicot Oct 01 '19 at 19:17
  • [It seems](https://github.com/Kitware/CMake/blob/master/Source/cmLinkLibrariesCommand.cxx) that `link_libraries` affects of further targets via `LINK_LIBRARIES` property, so [reference](https://stackoverflow.com/questions/49599673/cmake-remove-added-libraries) provided by squareskittles could help in this case too. – Tsyvarev Oct 01 '19 at 22:02
  • @kuga Thank you for clarifying your problem. If your `link-to-all` library is included based on a configuration option, why not just use a [`BOOL`](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#logical-operators) generator expression based on the setting of the configuration option, to conditionally include the library in the `link_libraries()` call. No need for an if-statement.. – Kevin Oct 02 '19 at 12:01
  • @squareskittles Thanks for this advice. While it does not work the way you propose (its not bases on configuration option), it may work another way. Will try something next week. – kuga Oct 02 '19 at 12:57

2 Answers2

5

While I agree with @Guillaume, I'll combine the suggestions into an answer, as the linked answer is not very clear. As @Tsyvarev confirmed in the CMake source, the link_libraries() call sets the LINK_LIBRARIES target property; the target_link_libraries() call does the same. While your executable e3 will initially be set to link with all libraries, you can remove one (or multiple) libraries from the list using a combination of get_target_property() and set_property(). Here is an example to demonstrate how:

# Library to be linked to all targets.
add_library(link-to-all a.cpp)
# Library to be linked to (almost) all targets.
add_library(link-to-almost-all b.cpp)

link_libraries(link-to-all link-to-almost-all)
# Gets our link-everywhere libraries. Oops!
add_executable(e3 test.cpp)

# Get the LINK_LIBRARIES property for this target.
get_target_property(E3_LINKED_LIBS e3 LINK_LIBRARIES)
message("Libraries linked to e3: ${E3_LINKED_LIBS}")

# Remove one item from the list, and overwrite the previous LINK_LIBRARIES property for e3.
list(REMOVE_ITEM E3_LINKED_LIBS link-to-almost-all)
set_property(TARGET e3 PROPERTY LINK_LIBRARIES ${E3_LINKED_LIBS})

# Verify only one library is now linked.
get_target_property(E3_LINKED_LIBS_NEW e3 LINK_LIBRARIES)
message("Libraries linked to e3: ${E3_LINKED_LIBS_NEW}")

The messages printed here confirm the library was removed from the LINK_LIBRARIES target property for e3:

Libraries linked to e3: link-to-all;link-to-almost-all
Libraries linked to e3: link-to-all
Kevin
  • 16,549
  • 8
  • 60
  • 74
  • I should have asked more clearly. link-to-all should be removed from all coming libraries (implicitly!). Will edit the question. – kuga Oct 02 '19 at 07:01
  • If found the property `_COMPILER_LAUNCHER`. With this property i can use your suggestion. Thanks. Answer accepted. – kuga Oct 08 '19 at 13:43
1

As an additonal answer I repeat what I commented on squarekittles answer (for future reference):

You should use the target property <LANG>_COMPILER_LAUNCHER instead of CMAKE_<LANG>_COMPILE_OBJECT. It can be set on target base.

kuga
  • 1,483
  • 1
  • 17
  • 38