CMake: set_target_properties fails with target defined by generator expression

2.8k views Asked by At

I'm having a problem with the cmake Generator Expression TARGET_NAME_IF_EXISTS. With this CMakeLists.txt:

cmake_minimum_required(VERSION 3.13.0)
option(SLIB_BUILD_STATIC "" ON)
project(slib VERSION 1.0)

add_library(slibObjects OBJECT main.c)
add_library(slib SHARED $<TARGET_OBJECTS:slibObjects>)

if (SLIB_BUILD_STATIC)                  # Can this if() be replaced with a GenExp?
  add_library(slibStatic STATIC $<TARGET_OBJECTS:slibObjects>)
endif()

set_target_properties(
    slib
    $<TARGET_NAME_IF_EXISTS:slibStatic> # This GenExp doesn't get reduced
  PROPERTIES
    VERSION ${SLIB_VERSION}
    SOVERSION ${SLIB_VERSION_MAJOR}
)

I get

CMake Error at CMakeLists.txt:12 (set_target_properties):
  set_target_properties Can not find target to add properties to:
  $<TARGET_NAME_IF_EXISTS:slibStatic>

I expected set_target_properties to reduce to one of these depending on if SLIB_BUILD_STATIC is set:

set_target_properties( slib slibStatic PROPERTIES ...)
set_target_properties( slib PROPERTIES ...)

What am I doing wrong?

1

There are 1 answers

0
Tsyvarev On BEST ANSWER

Generator expressions are NOT a replacement for if command

Generator expressions are usable only for some properties and some variables, so they could be evaluated at the end of configuration stage to a values, which depends from the build type. Such behavior cannot be achieved with plain if because multi-configuration CMake generators (like Visual Studio) read a CMakeLists.txt once but create several configurations.

Generator expressions are usable also for the commands which sets these properties and variables.

Every possible usage of generator expressions is explicitly stated in the documentation for a command/property/variable which supports them.

Documentation for the command set_target_properties doesn't describe usage of generator expressions, so this command simply doesn't support them.

Actually, one can pass to that command a generator expression as a property's value. In that case the command will just assign that value to the corresponded property. It is dependent from the property whether the generator expression will be resolved when evaluate the property after the configuration.

But neither the name of the target not the name of the property cannot be a generator expression.

For conditionally set properties for a target, use plain if:

# Unconditionally set properties for 'slib' target.
set_target_properties(
    slib
  PROPERTIES
    VERSION ${SLIB_VERSION}
    SOVERSION ${SLIB_VERSION_MAJOR}
)
# Set properties for 'slibStatic' target only if this target exist.
if (TARGET slibStatic)
  set_target_properties(
      slibStatic
    PROPERTIES
      VERSION ${SLIB_VERSION}
      SOVERSION ${SLIB_VERSION_MAJOR}
  )
endif()

For avoid copy-pasting of properties' assignment, you could create a variable which contains a list of targets, and then use this variable:

# Variable which contain list of affected targets.
set(targets_for_version_set slib)
# Add target 'slibStatic' to the list only if the target exist

if (TARGET slibStatic)
  list(APPEND targets_for_version_set slibStatic)
endif()
# Now assign properties for all variables in the list
set_target_properties(
    ${targets_for_version_set}
  PROPERTIES
    VERSION ${SLIB_VERSION}
    SOVERSION ${SLIB_VERSION_MAJOR}
)