Neal Kruis
Neal Kruis

Reputation: 2287

In CMake, is there a way to set properties on all targets that a given target has a link dependency on?

In CMake, we can set target properties as either PRIVATE, PUBLIC, or INTERFACE. Both PUBLIC and INTERFACE properties are inherited by any targets that depend on the current target. However, unless I'm missing something, there doesn't seem to be an easy way to define a property that must propagate in the other direction (i.e., inherited by dependencies of the current target).

Most linkers/compilers require that all linked targets have the same value for certain properties (e.g., the exception handling model). If we want to change one of these properties for an executable it requires that it be set on all of its dependencies. Often these dependencies are submodules in our code where we can't modify their CMakeLists.txt files for our specific use-case. This leaves us with two options:

  1. Set a global property (e.g., CMAKE_CXX_FLAGS or add_compile_options) that propagates to all targets in any subdirectories regardless of whether they are dependencies or not.
  2. Explicitly set the properties on each dependent target using target_compile_options. This gets excessive and repetitive depending on the number of dependencies.

It would be nice if there was a functionality that would pass properties down only to dependency targets without having to specify them all individually. Does anyone know how to do this?

Upvotes: 1

Views: 1613

Answers (1)

starball
starball

Reputation: 50364

For the case of compiler flags that must be consistent for an entire program (including parts that are dynamically linked), such as MSVC's exception handling model, I think the set-something-global approach is suitable. To me, it seems pragmatic and slightly more robust than adding flags to each third-party target one-by-one (ie. what if you forget to handle to one? or what if third-party targets are added or removed in a new version? it seems like a ripe opportunity for human error).

Setting the environment variable [CMAKE_<LANG>_FLAGS] is a good start. You may need to do more if you are building external projects via ExternalProject.

A word of caution for such settings like the exception handling model: You might be tempted to hardcode this global setting inthe CMake files for your project. If your project is used by people other than just you or your company, and especially if its main component is a library and not an executable, it's good practice not to do that. Don't take away your user's ability to choose something like this (unless for some reason your library requires a certain exception handling model, in which case I would still leave this global setting up to them to set, provide documentation stating this, and look into emitting a CMake warning if a user doesn't comply). Instead, use a feature like CMake presets, or only set it if the project is the top-level project

An intersting side note: CMake currently globally "hard-codes" /EHsc for MSVC builds by default. Here's the ticket discussing this

Upvotes: 1

Related Questions