1

Is there a way to set compile definitions for a linked library target but with different sets of definitions for the library used by each target (compile defs are mutually exclusive for the lib linked with each target)?

Target A > lib with -DDEF_A only
Target B > lib with -DDEF_B only

target_compile_definitions() only allows you to set definitions on a target, but if set on the library target this would be set for both targets.

The only way I can think of doing it is to create a function to add new library targets, so multiple library targets can be defined with different compile definitions.

Nick
  • 3,958
  • 4
  • 32
  • 47
  • Every library target you create in CMake eventually produces **single** library file. When this file is compiled, it could use only a **single set** of compile options. If you want to build libraries with different set of options, you need to create separate targets for them. – Tsyvarev Nov 09 '19 at 13:15

1 Answers1

1

This could work with the simple case you've laid out, assuming lib is another target created within the same CMake build tree. You could use get_target_property() to get the LINK_LIBRARIES property list for TargetA and TargetB. If lib is in the list of first-level link dependencies, then you can add the compile definition to lib.

# Get the list of first-level link dependencies for TargetA and TargetB.
get_target_property(TARGETA_LIBS TargetA LINK_LIBRARIES)
get_target_property(TARGETB_LIBS TargetB LINK_LIBRARIES)

# Loop through the TargetA dependencies.
foreach(LIB ${TARGETA_LIBS})
    # Was the 'lib' library added as a dependency to TargetA?
    if (${LIB} STREQUAL lib)
        # Yes, so add the compile definitions to 'lib'.
        target_compile_definitions(${LIB} PRIVATE DEF_A)
    endif()
endforeach()

# Loop through the TargetB dependencies.
foreach(LIB ${TARGETB_LIBS})
    # Was the 'lib' library added as a dependency to TargetB?
    if (${LIB} STREQUAL lib)
        # Yes, so add the compile definitions to 'lib'.
        target_compile_definitions(${LIB} PRIVATE DEF_B)
    endif()
endforeach()

Note, this only works if lib is a first-level dependency of the target, it does not search dependencies recursively, as shown in this answer. Also, if lib is an interface library, you'll have to get the INTERFACE_LINK_LIBRARIES property instead.


EDIT Based on answer feedback: If the compile definitions DEF_A and DEF_B are mutually exclusive in the lib target. The cleanest approach may be to create a separate lib target, one catered for TargetA and another catered for TargetB. This could look something like this:

set(LIB_SOURCES 
    Class1.cpp
    ...
)

# Create the 'lib' target to link to TargetA.
add_library(lib_forTargetA SHARED ${LIB_SOURCES})
target_compile_definitions(lib_forTargetA PRIVATE DEF_A)

# Create the 'lib' target to link to TargetB.
add_library(lib_forTargetB SHARED ${LIB_SOURCES})
target_compile_definitions(lib_forTargetB PRIVATE DEF_B)
Kevin
  • 16,549
  • 8
  • 60
  • 74
  • But if both TargetA and TargetB link with lib, then this would add both `DEF_A` and `DEF_B` to the lib compile defs? Which is what I am trying to avoid, I do not want lib for target A to have the `DEF_B` definition. Or is `${LIB}` in `${TARGETA_LIBS}` distinct from `${LIB}` in `${TARGETB_LIBS}`? – Nick Nov 09 '19 at 17:04
  • @Nick Yes, both `DEF_A` and `DEF_B` would be compile definitions of `lib` in this case. The requirement for them to be mutually exclusive was not clear from your question post... If that's what you want, you would have give one library preference (if A then not B, or if B then not A) so that only `DEF_A` **or** `DEF_B` is added. The other solution is, as suggested, to create separate targets for each case. – Kevin Nov 09 '19 at 17:20
  • I have updated to make the question clearer. So I think it is best to use a function to create lib targets from the TargetA/B scope. – Nick Nov 09 '19 at 17:30
  • @Nick Agreed. This can still be a pretty simple solution; I've expanded my answer to show what that could look like. Hope this helps! – Kevin Nov 09 '19 at 17:58
  • 1
    Thanks. As the library is a third party library and I wanted to do this in a generic way, I defined a function to create a library target with a given name. This way I can specify whatever compile defs I want on the custom target. – Nick Nov 09 '19 at 19:04