summaryrefslogtreecommitdiff
path: root/Help/prop_tgt/INTERFACE_LINK_LIBRARIES_DIRECT.rst
blob: 6243bb1481f5a96d490d362bb13380df4028c7bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
INTERFACE_LINK_LIBRARIES_DIRECT
-------------------------------

.. versionadded:: 3.24

List of libraries that consumers of this library should treat
as direct link dependencies.

This target property may be set to *include* items in a dependent
target's final set of direct link dependencies.  See the
:prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE` target property
to exclude items.

The initial set of a dependent target's direct link dependencies is
specified by its :prop_tgt:`LINK_LIBRARIES` target property.  Indirect
link dependencies are specified by the transitive closure of the direct
link dependencies' :prop_tgt:`INTERFACE_LINK_LIBRARIES` properties.
Any link dependency may specify additional direct link dependencies
using the ``INTERFACE_LINK_LIBRARIES_DIRECT`` target property.
The set of direct link dependencies is then filtered to exclude items named
by any dependency's :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE`
target property.

.. |INTERFACE_PROPERTY_LINK_DIRECT| replace:: ``INTERFACE_LINK_LIBRARIES_DIRECT``
.. include:: INTERFACE_LINK_LIBRARIES_DIRECT.txt

Direct Link Dependencies as Usage Requirements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``INTERFACE_LINK_LIBRARIES_DIRECT`` and
``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE`` target properties
are :ref:`usage requirements <Target Usage Requirements>`.
Their effects propagate to dependent targets transitively, and can
therefore affect the direct link dependencies of every target in a
chain of dependent libraries.  Whenever some library target ``X`` links
to another library target ``Y`` whose direct or transitive usage
requirements contain ``INTERFACE_LINK_LIBRARIES_DIRECT`` or
``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE``, the properties may affect
``X``'s list of direct link dependencies:

* If ``X`` is a shared library or executable, its dependencies are linked.
  They also affect the usage requirements with which ``X``'s sources are
  compiled.

* If ``X`` is a static library or object library, it does not actually
  link, so its dependencies at most affect the usage requirements with
  which ``X``'s sources are compiled.

The properties may also affect the list of direct link dependencies
on ``X``'s dependents:

* If ``X`` links ``Y`` publicly:

  .. code-block:: cmake

    target_link_libraries(X PUBLIC Y)

  then ``Y`` is placed in ``X``'s :prop_tgt:`INTERFACE_LINK_LIBRARIES`,
  so ``Y``'s usage requirements, including ``INTERFACE_LINK_LIBRARIES_DIRECT``,
  ``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE``, and the usage requirements
  declared by the direct link dependencies they add, are propagated to
  ``X``'s dependents.

* If ``X`` is a static library or object library, and links ``Y`` privately:

  .. code-block:: cmake

    target_link_libraries(X PRIVATE Y)

  then ``$<LINK_ONLY:Y>`` is placed in ``X``'s
  :prop_tgt:`INTERFACE_LINK_LIBRARIES`.  ``Y``'s linking requirements,
  including ``INTERFACE_LINK_LIBRARIES_DIRECT``,
  ``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE``, and the transitive link
  dependencies declared by the direct link dependencies they add, are
  propagated to ``X``'s dependents.  However, ``Y``'s non-linking
  usage requirements are blocked by the :genex:`LINK_ONLY` generator
  expression, and are not propagated to ``X``'s dependents.

* If ``X`` is a shared library or executable, and links ``Y`` privately:

  .. code-block:: cmake

    target_link_libraries(X PRIVATE Y)

  then ``Y`` is not placed in ``X``'s :prop_tgt:`INTERFACE_LINK_LIBRARIES`,
  so ``Y``'s usage requirements, even ``INTERFACE_LINK_LIBRARIES_DIRECT``
  and ``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE``, are not propagated to
  ``X``'s dependents.

* In all cases, the content of ``X``'s :prop_tgt:`INTERFACE_LINK_LIBRARIES`
  is not affected by ``Y``'s ``INTERFACE_LINK_LIBRARIES_DIRECT`` or
  ``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE``.

One may limit the effects of ``INTERFACE_LINK_LIBRARIES_DIRECT`` and
``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE`` to a subset of dependent
targets by using the :genex:`TARGET_PROPERTY` generator expression.
For example, to limit the effects to executable targets, use an
entry of the form::

  "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:...>"

Similarly, to limit the effects to specific targets, use an entry
of the form::

  "$<$<BOOL:$<TARGET_PROPERTY:USE_IT>>:...>"

This entry will only affect targets that set their ``USE_IT``
target property to a true value.

Direct Link Dependency Ordering
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The list of direct link dependencies for a target is computed from an
initial ordered list in its :prop_tgt:`LINK_LIBRARIES` target property.
For each item, additional direct link dependencies are discovered from
its direct and transitive ``INTERFACE_LINK_LIBRARIES_DIRECT`` usage
requirements.  Each discovered item is injected before the item that
specified it.  However, a discovered item is added at most once,
and only if it did not appear anywhere in the initial list.
This gives :prop_tgt:`LINK_LIBRARIES` control over ordering of
those direct link dependencies that it explicitly specifies.

Once all direct link dependencies have been collected, items named by
all of their :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE`
usage requirements are removed from the final list.  This does not
affect the order of the items that remain.

Example: Static Plugins
^^^^^^^^^^^^^^^^^^^^^^^

Consider a static library ``Foo`` that provides a static plugin
``FooPlugin`` to consuming application executables, where the
implementation of the plugin depends on ``Foo`` and other things.
In this case, the application should link to ``FooPlugin`` directly,
before ``Foo``.  However, the application author only knows about ``Foo``.
We can express this as follows:

.. code-block:: cmake

  # Core library used by other components.
  add_library(Core STATIC core.cpp)

  # Foo is a static library for use by applications.
  # Implementation of Foo depends on Core.
  add_library(Foo STATIC foo.cpp foo_plugin_helper.cpp)
  target_link_libraries(Foo PRIVATE Core)

  # Extra parts of Foo for use by its static plugins.
  # Implementation of Foo's extra parts depends on both Core and Foo.
  add_library(FooExtras STATIC foo_extras.cpp)
  target_link_libraries(FooExtras PRIVATE Core Foo)

  # The Foo library has an associated static plugin
  # that should be linked into the final executable.
  # Implementation of the plugin depends on Core, Foo, and FooExtras.
  add_library(FooPlugin STATIC foo_plugin.cpp)
  target_link_libraries(FooPlugin PRIVATE Core Foo FooExtras)

  # An app that links Foo should link Foo's plugin directly.
  set_property(TARGET Foo PROPERTY INTERFACE_LINK_LIBRARIES_DIRECT FooPlugin)

  # An app does not need to link Foo directly because the plugin links it.
  set_property(TARGET Foo PROPERTY INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE Foo)

An application ``app`` only needs to specify that it links to ``Foo``:

.. code-block:: cmake

  add_executable(app main.cpp)
  target_link_libraries(app PRIVATE Foo)

The ``INTERFACE_LINK_LIBRARIES_DIRECT`` target property on ``Foo`` tells
CMake to pretend that ``app`` also links directly to ``FooPlugin``.
The ``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE`` target property on ``Foo``
tells CMake to pretend that ``app`` did *not* link directly to ``Foo``.
Instead, ``Foo`` will be linked as a dependency of ``FooPlugin``.  The
final link line for ``app`` will link the libraries in the following
order:

* ``FooPlugin`` as a direct link dependency of ``app``
  (via ``Foo``'s usage requirements).
* ``FooExtras`` as a dependency of ``FooPlugin``.
* ``Foo`` as a dependency of ``FooPlugin`` and ``FooExtras``.
* ``Core`` as a dependency of ``FooPlugin``, ``FooExtras``, and ``Foo``.

Note that without the ``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE`` target
property, ``Foo`` would be linked twice: once as a direct dependency
of ``app``, and once as a dependency of ``FooPlugin``.

Example: Opt-In Static Plugins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In the above `Example: Static Plugins`_, the ``app`` executable specifies
that it links directly to ``Foo``.  In a real application, there might
be an intermediate library:

.. code-block:: cmake

  add_library(app_impl STATIC app_impl.cpp)
  target_link_libraries(app_impl PRIVATE Foo)

  add_executable(app main.cpp)
  target_link_libraries(app PRIVATE app_impl)

In this case we do not want ``Foo``'s ``INTERFACE_LINK_LIBRARIES_DIRECT``
and ``INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE`` target properties to affect
the direct dependencies of ``app_impl``.  To avoid this, we can revise
the property values to make their effects opt-in:

.. code-block:: cmake

  # An app that links Foo should link Foo's plugin directly.
  set_property(TARGET Foo PROPERTY INTERFACE_LINK_LIBRARIES_DIRECT
    "$<$<BOOL:$<TARGET_PROPERTY:FOO_STATIC_PLUGINS>>:FooPlugin>"
  )

  # An app does not need to link Foo directly because the plugin links it.
  set_property(TARGET Foo PROPERTY INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE
    "$<$<BOOL:$<TARGET_PROPERTY:FOO_STATIC_PLUGINS>>:Foo>"
  )

Now, the ``app`` executable can opt-in to get ``Foo``'s plugin(s):

.. code-block:: cmake

  set_property(TARGET app PROPERTY FOO_STATIC_PLUGINS 1)

The final link line for ``app`` will now link the libraries in the following
order:

* ``FooPlugin`` as a direct link dependency of ``app``
  (via ``Foo``'s usage requirements).
* ``app_impl`` as a direct link dependency of ``app``.
* ``FooExtras`` as a dependency of ``FooPlugin``.
* ``Foo`` as a dependency of ``app_impl``, ``FooPlugin``, and ``FooExtras``.
* ``Core`` as a dependency of ``FooPlugin``, ``FooExtras``, and ``Foo``.