semantics of target_link_libraries PRIVATE for a library target - cmake

In the CMake documentation for target_link_libraries, it says:
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
The PUBLIC, PRIVATE and INTERFACE keywords can be used to specify both the link dependencies and the link interface in one command.
Libraries and targets following PUBLIC are linked to, and are made
part of the link interface. Libraries and targets following PRIVATE
are linked to, but are not made part of the link interface. Libraries
following INTERFACE are appended to the link interface and are not
used for linking .
I don't quite understand how this applies to library targets.
Suppose my language is C or C++; that targets lib1 and lib2 are libraries, and that target e1 is an executable. Now, if I write:
target_link_libraries(lib1 PRIVATE lib2)
target_link_libraries(e1 PRIVATE lib1)
Will e1 necessarily be linked against lib2 when I build e1?
Note: If the answer differs depending on whether lib1/lib2 are static or dynamic libraries, please say so.

Will e1 necessarily be linked against lib2 when I build e1?
Yes.
But e1 will not have INCLUDE_DIRECTORIES nor COMPILE_DEFINITIONS that are PUBLIC from lib2.

Related

Creating a executable out of a library in CMake, and linking the library in another library

I am trying to link foo-lib library into another target bar-lib however doing the following results in an error.
(add_executable):
Cannot find source file: foo-lib
How can I create an executable out of a library and the same library can be linked into another target?
add_library(foo-lib STATIC src/foo.cpp)
add_executable(foo-ut foo-lib)
target_include_directories(foo-ut PRIVATE include)
target_link_libraries(foo-ut PUBLIC lib1 lib2)
# second library that links foo-lib
add_library(bar-lib STATIC src/bar.cpp)
add_executable(bar-ut bar-lib)
target_include_directories(bar-ut PRIVATE include)
target_link_libraries(bar-ut PUBLIC foo-lib)
This worked the way I wanted but I am not sure if I should be adding foo.cpp for the bar-ut target
add_executable(bar-ut src/foo.cpp src/bar.cpp)
I'm not going to question the design choices and what you need it for and if it is a good idea in any way. I will just provide you with a "scalable" way of doing this.
As the others pointed out add_executable() requires source files.
Now assuming that the source files that you use to create a static library contain a main() function. Then you can create (out of the same source files) an executable, by passing to the add_executable the same source files as you would to add_library.
As the program grows these would get lengthy, so what you should do is something that is no longer recommended by "CMake best practices" and that is to introduce a SOURCES variable. I.e.:
set(PROJECT_SOURCES source1.cpp source2.cpp source3.cpp)
set(PROJECT_HEADERS header1.h header2.h header3.h)
add_library(foo-lib STATIC ${PROJECT_SOURCES} ${PROJECT_HEADERS})
add_executable(foo-ut ${PROJECT_SOURCES} ${PROJECT_HEADERS}
As your program grows you would just add the respective files into the designated variables. Now as to possible improvements:
fabian mentioned a very good thing which is OBJECT libraries, since you are rebuilding the same files for both the executable and library you could just create an object library and link it. This would make it twice as fast (you only need to compile once).
Since these SOURCES are already once passed to some target, you could just get them from the target's properties via get_target_properties(MY_SOURCES foo-lib SOURCES) this would give you a variable MY_SOURCES that contains sources which are used by the target library.

What happens with target_link_libraries(libstatic libfoo libbar)?

I am bit confused about linking libraries when our target is a static library.
For instance, for an executable it will help linker resolve undefined symbols. But, incase of a static libraries, why would it link at this stage?
Won't linking be done when I will link some executable against libstatic?
Thanks.
In CMake,
target_link_libraries(targetName PUBLIC lib1 lib2)
affects to the linker's argument in two scenarios:
PRIVATE: when the linker is called for the for the executable/library, corresponded to the target targetName.
INTERFACE: when the linker is called for the other executable/library otherTargetName, which is linked with targetName via
target_link_libraries(otherTargetName PUBLIC targetName)
This is known as transitive property of the linking libraries.
You are right that the linker is not called for the static libraries, so in that case the first scenario is eliminated.
But the second scenario remains: When you create the executable (or other shared library) and call
target_link_libraries(otherTargetName PUBLIC libStatic)
then CMake automatically links that executable(or shared library) with everything, to which libStatic is "linked" with target_link_libraries.
Such automation helps in structuring the project:
By calling
target_link_libraries(libStatic PUBLIC lib1 lib2)
you state, that libStatic uses functions defined in lib1 and lib2
By calling
target_link_libraries(otherTargetName PUBLIC libStatic)
you state, that executable/library otherTargetName uses functions from libStatic.
At this stage you don't care about internals of libStatic, whether it is self-contained or depends from some other libraries: CMake will care about this for you.
Note on using PUBLIC keyword in target_link_libraries: while in some cases this is equivalent to omitting the keyword, a modern CMake way is to specify keywords explicitly. See also policy CMP0023.
Other possible keywords are PRIVATE and INTERFACE, each of them selects only a single scenario described above.
Note that transitive linking property is a pure CMake feature and works only when linking to a target. The library file (.a or .lib) itself doesn't contain information about dependent libraries, so linking with a file doesn't trigger transitive linking.

How to share properties across multiple targets in CMake?

I am a bit late in the game of "modern cmake" and trying to catch up. One question after reading target centric paradigm is how to share properties (include, compile options, definitions etc) across multiple targets?
More specifically, my project simply involves a few libraries and multiple executables as targets. They pretty much share the same includes, language features etc. Do I need to repeat it for every target? or just one target is enough for the rest? or any other alternative ways? TIA.
If there are dependencies between targets, then target_include_libraries and other target_ commands will take care of propagating the properties if you use the PUBLIC visibility:
add_library(foo ...)
target_include_directories(foo PUBLIC foo_includes)
add_executable(bar ...)
# foo_includes propagate to bar.
target_link_libraries(bar foo)
If there is no dependency relationship between the targets you can share option via CMake variables:
set(my_includes ...)
add_library(foo ...)
target_include_directories(foo PUBLIC ${my_includes})
add_library(bar ...)
target_include_directories(bar PUBLIC ${my_includes})

Transitive dependencies and OBJECT libraries

A somewhat similar question was asked here, Transitive target_include_directories on OBJECT libraries, but there was no real solution.
If I have a project b that depends on a project a I can build them as follows
add_library(a OBJECT ${a_srcs})
add_library(b OBJECT ${b_srcs})
When I want to build an excutable using I them I can write
add_executable(p ${p_srcs} $<TARGET_OBJECTS:b> $<TARGET_OBJECTS:a>)
Is there any way to not have to specify $<TARGET_OBJECTS:a>? I assume this means telling CMake in some way that there is a dependency. If I was building SHARED libraries rather than OBJECT ones the b project would contain
target_link_libraries(b a)
which creates this dependency, but I can't find some equivalent way for OBJECT libraries.
Insofar as I understand it, in the current setup, no. The add_executable for target p can either
Link against some library (shared or static), or
Merge object sources into itself.
You have chosen (2). The only other option I see here is create a third library c that merges in a and b into a full-blown library (see Usage section at the bottom, which is likely where you were already looking).
When you do that, you could then target_link_libraries(c). The compiled OBJECTs cannot be linked against on their own. You have to merge the sources into either an executable or a library for them to be used.
Your add_executable call could be thought of basically doing add_executable(p ${p_srcs} ${a_srcs} ${b_srcs}), only instead of compiling a_srcs and b_srcs (which has been done previously), just copy in the compiled objects instead of redoing the work. That's a really simple / bad explanation, but that's the general idea.
The best way I have found to do this is to wrap the OBJECT library in an INTERFACE library.
add_library(a-objects OBJECT ${a_srcs})
add_library(b-objects OBJECT ${b_srcs})
add_library(a INTERFACE)
add_library(b INTERFACE)
target_link_libraries(a INTERFACE a-objects)
target_link_libraries(b INTERFACE b-objects)
target_sources(a INTERFACE $<TARGET_OBJECTS:a-objects>)
target_sources(b INTERFACE $<TARGET_OBJECTS:b-objects>)
My rule is to use the OBJECT library to set requirements, but only ever link against the INTERFACE library.
target_link_libraries(b-objects INTERFACE a)
Setting it up this way should allow you to link against both libraries like this:
add_executable(p ${p_srcs})
target_link_libraries(p PRIVATE b)

CMake target_link_libraries Interface Dependencies

I am new to CMake and a bit confused with the PUBLIC, PRIVATE and INTERFACE keywords related to target_link_libraries(). Documentation mentions that they can be used to specify both the link dependencies and the link interface in one command.
What does link dependencies and link interface actually mean?
If you are creating a shared library and your source cpp files #include the headers of another library (Say, QtNetwork for example), but your header files don't include QtNetwork headers, then QtNetwork is a PRIVATE dependency.
If your source files and your headers include the headers of another library, then it is a PUBLIC dependency.
If your header files other than your source files include the headers of another library, then it is an INTERFACE dependency.
Other build properties of PUBLIC and INTERFACE dependencies are propagated to consuming libraries. http://www.cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#transitive-usage-requirements
#steveire accepted answer is great. I just wanted to add a table to quickly see the difference:
.-----------.------------------.----------------.
| | Linked by target | Link interface |
:-----------+------------------+----------------:
| PUBLIC | X | X |
:-----------+------------------+----------------:
| PRIVATE | X | |
:-----------+------------------+----------------:
| INTERFACE | | X |
'-----------'------------------'----------------'
Linked by target: libraries included in target sources (not a dependency for projects linking the library).
Link interface: libraries included in target public headers (dependencies for projects linking the library).
Not my brainchild but this extremely useful explanation helped me understand the situation. The most important part is quoted below for reference:
When A links B as PRIVATE, it is saying that A uses B in its implementation, but B is not used in any part of A's public API. Any
code that makes calls into A would not need to refer directly to
anything from B. An example of this could be a networking library A
which can be built to use one of a number of different SSL
libraries internally (which B represents). A presents a unified
interface for client code which does not reference any of the
internal SSL data structures or functions. Client code would have
no idea what SSL implementation (B) is being used by A, nor does
that client code need to care.
When A links B as INTERFACE, it is saying that A does not use B in its implementation, but B is used in A's public API. Code
that calls into A may need to refer to things from B in order to
make such calls. One example of this is an interface library which
simply forwards calls along to another library but doesn't actually
reference the objects on the way through other than by a pointer or
reference. Another example is where A is defined in CMake as an
interface library, meaning it has no actual implementation itself,
it is effectively just a collection of other libraries (I'm
probably over-simplifying here, but you get the picture).
When A links B as PUBLIC, it is essentially a combination of PRIVATE and INTERFACE. It says that A uses B in its implementation and
B is also used in A's public API.
Consider first what this means for include search paths. If something
links against A, it will also need any include search paths from B if
B is in A's public API. Thus, if A links B either as PUBLIC or
INTERFACE, then any header search paths defined for target B will also
apply to anything that links to A. Any PRIVATE header search path for
B will NOT be carried through to anything that links only to A. The
target_include_directories() command handles this. The situation with
compile flags is analogously handled with target_compile_definitions()
and target_compile_options().
Now consider the situation for the actual libraries involved. If A is
a shared library, then A will have encoded into it a dependency on B.
This information can be inspected with tools like ldd on Linux, otool
on Mac and something like Dependency Walker (a.k.a. depends.exe) on
Windows. If other code links directly to A, then it also will have
encoded into it a dependency on A. It will not, however, have a
dependency on B unless A links B either as PUBLIC or INTERFACE. So far, so
good. If, however, A is a static library, the situation changes.
Static libraries do not carry information about other libraries they
depend on. For this reason, when A links B as PRIVATE and another
target C links A, CMake will still add B to the list of libraries
to be linked for C because parts of B are needed by A, but A itself
doesn't have that dependency encoded into it. So even though B is an
internal implementation detail of A, C still needs B added to the
linker command, which CMake conveniently handles for you.
If you were paying careful attention, you would have noticed that when
A links B as PRIVATE, the include directories of B never propagate
to something linking to A, but if A is a static library, then the
linking of B behaves as though the relationship was PUBLIC. This PRIVATE-becomes-PUBLIC behaviour for static libraries only applies to
the
linking, not to the other dependencies (compiler options/flags and include search paths). The upshot of all this is that if you select
PRIVATE, PUBLIC or INTERFACE based on the explanations in the dot
points above, then CMake will ensure dependencies propagate through to
where they are required, regardless of whether libraries are static or
shared. This does, of course, rely on you the developer not missing
any dependencies or specifying the wrong PRIVATE/PUBLIC/INTERFACE
relationship.
Some answers only said when to use PRIVATE/PUBLIC/INTERFACE, but the affects are ignored. Refer:CMake-Public-Private-Interface
PUBLIC
All the objects following PUBLIC will be used for linking to the current target and providing the interface to the other targets that have dependencies on the current target.
PRIVATE
All the objects following PRIVATE will only be used for linking to the current target.
INTERFACE
All the objects following INTERFACE will only be used for providing the interface to the other targets that have dependencies on the current target.
Other posts already answered what the meaning of PUBLIC/PRIVATE/INTERFACE keywords. I want to add one more to clarify the terms "link dependencies" and "link interface."
Link dependencies :
the list of libraries to be linked by the target.
The target property LINK_LIBRARIES holds this information.
Link interface : the list of libraries to be linked by the target's dependents. The target property INTERFACE_LINK_LIBRARIES holds this information.
Probably the term "link interface" came from the old CMake wording used around LINK_INTERFACE_LIBRARIES properties, which is deprecated in favor of INTERFACE_LINK_LIBRARIES.
See the description of CMP0022, which also uses the term "link interface."
https://cmake.org/cmake/help/latest/policy/CMP0022.html
INTERFACE_LINK_LIBRARIES defines the link interface.