cmakelinker

How can I remove a link option from a target in CMake?


We have a CMake project which adds link-options at the top-level via add_link_options. We use them for a lot of static-library-targets. We also have two special targets. Each of those two targets is built separately as an relocatable output module by an tiarmclang LTS2.1.2 TI-compiler. So they are partially linked. And get their final linking into the main-target.

This is achieved by not having the targets implemented with add_library but with add_executable. Now it's important the targets won't use the top-level-link-options since those options would link the relocatable output module in a wrong way which makes problems later on. They should either independently use their own defined link-options and drop the ones from above or at least it shall be possible to remove previous set link-options. The setup is in minimal like this:

#top-level 
add_link_options(
            "-Wl,--reread_libs"
            "-Wl,--ram_model" #should not be used in relocatable target
            "-Wl,-e_vectors" #should not be used in relocatable target
            "-Wl,--diag_suppress=10063"
)

#main-target
add_executable(main-target 
            #some sources here
)

target_link_libraries(main-target PUBLIC
                      relocatable-target
)

target_link_options(main-target PRIVATE
                    #some additional link-options like map-file and so on
)

#relocatable target
add_executable(relocatable-target
            #some sources here
)

set_target_properties(relocatable-target PROPERTIES SUFFIX ".out"
                  ENABLE_EXPORTS on
)

target_link_options(relocatable-target PRIVATE 
#separate link-options here
)

I may remove the problematic link-options from the top-level add_link-options but then the logical relation is the wrong way: the main-target needs to do changes because of a target way below. That's not how it should work.

I thought that since the add_executable signifies: "Hey I am a separate running entity" CMake would automatically not use the top-level-linker-options. Is there a way to do this?

I did not find any solution for this problem. I found some hundreds of lines of CMake-macros for compile-options to achieve something similar but that could not be the solution.


Solution

  • As already mentioned in the comments, it doesn't make sense that you're using add_linker_options for static library targets. From the add_link_options docs:

    Note: This command cannot be used to add options for static library targets, since they do not use a linker. To add archiver or MSVC librarian flags, see the STATIC_LIBRARY_OPTIONS target property.

    But putting that aside for the sake of discussion, to answer the question in general about how to remove linker flags added by add_link_options: The docs of add_link_options says:

    This command can be used to add any link options, but alternative commands exist to add libraries (target_link_libraries() or link_libraries()). See documentation of the directory and target LINK_OPTIONS properties.

    If you look at the docs pointed to for the directory property, you'll see that it says:

    This property holds a semicolon-separated list of options given so far to the add_link_options() command.

    This property is used to initialize the LINK_OPTIONS target property when a target is created, which is used by the generators to set the options for the compiler.

    So you just need to read out the value of your target's LINK_OPTIONS property into a CMake variable, modify the CMake variable to remove that option, and then write the value of the CMake variable back into the target property. For example:

    add_link_options("-foo" "-remove-me" "-bar" "-baz")
    add_library(mytarget SHARED foo.cpp)
    get_target_property(mytarget_LINK_OPTIONS mytarget LINK_OPTIONS)
    message("mytarget_LINK_OPTIONS: ${mytarget_LINK_OPTIONS}") # original value
    list(REMOVE_ITEM mytarget_LINK_OPTIONS "-remove-me")
    message("mytarget_LINK_OPTIONS: ${mytarget_LINK_OPTIONS}") # modified value
    set_target_properties(mytarget PROPERTIES LINK_OPTIONS "${mytarget_LINK_OPTIONS}")
    get_target_property(mytarget_LINK_OPTIONS mytarget LINK_OPTIONS)
    message("mytarget_LINK_OPTIONS: ${mytarget_LINK_OPTIONS}") # written-back value
    

    , which will print the following during configuration:

    mytarget_LINK_OPTIONS: -foo;-remove-me;-bar;-baz
    mytarget_LINK_OPTIONS: -foo;-bar;-baz
    mytarget_LINK_OPTIONS: -foo;-bar;-baz
    

    Another potential option (I have not verified) could be to set a custom target property on those special targets that indicates it doesn't want those link options, and then wrap your special general add_link_options options with a target property generator expression.