Transitive dependencies and OBJECT libraries - cmake

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)

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.

How can I make `target_link_libraries` dependencies transitive from OBJECT libraries in cmake?

If I specify a dependency chain of OBJECT libraries in CMake, only the target_link_libraries dependencies of the very last one is used in the target executable.
Minimal Example:
main depends on objB, which depends on objA.
Both objA and objB are OBJECT libraries in CMake.
I would expect main to link with both object files. It doesn't.
cmake_minimum_required(VERSION 3.13)
project(transitive-object-library-link-issue VERSION 1.0.0 LANGUAGES C)
add_library(objA OBJECT a.c)
add_library(objB OBJECT b.c)
target_link_libraries(objB PUBLIC objA)
# Should link with 'a.o', since 'objA' is "linked" by 'objB'
add_executable(main main.c)
target_link_libraries(main objB)
Note: A working set of files are available at https://github.com/scraimer/cmake-transitive-object-library-link-issue
If I change objA to a non-OBJECT library, the problem is eliminated by getting rid of the chain of OBJECT library dependencies. In other words, change the line
add_library(objA OBJECT a.c)
To be:
add_library(objA a.c)
So it's something specific to OBJECT libraries. How should I be specifying the dependencies to make main link with objA? (Without having to specify objA in every executable target that uses objB)
Object library targets are not real libraries, they are simply a collection of objects, but they are not really linked together until they are used to build a real target like an executable or shared/static library. Citing the linked documentation:
add_library(<name> OBJECT <src>...)
Creates an Object Library. An object library compiles source files but does not archive or link their object files into a library.
In despite of that, you can apply a target_link_library() command to an object library, but only to specify dependencies of their sources on other libraries. The linked documentation explains your problem:
The object library’s usage requirements are propagated transitively [...], but its object files are not.
Object Libraries may “link” to other object libraries to get usage requirements, but since they do not have a link step nothing is done with their object files.
So, the transitive propagation affects only to compile definitions and dependencies of other real libraries, not the objects themselves.
One solution is to define an INTERFACE library for each OBJECT library. Dependencies of interface libraries are transitive.
# Defines an object library named ${T}_obj,
# interface library named ${T} linked to it,
# and sets ${varname} to ${T}_obj.
macro(add_object varname T)
add_library(${T}_obj OBJECT ${ARGN})
add_library(${T} INTERFACE)
target_link_libraries(${T} INTERFACE ${T}_obj $<TARGET_OBJECTS:${T}_obj>)
set(${varname} ${T}_obj)
endmacro(add_object)
Usage
add_object(T a a.c)
add_object(T b b.c) # sets T to b_obj
target_link_libraries(${T} a)
This stems from another issue with OBJECT libraries: duplication of object code. As Brad King explains:
we'd need to be careful to de-duplicate use of [example item's] object files
If transitive propagation was the default, you could accidentally cause the linker to try linking multiple copies of the same code, thus dooming your project to be non-compilable by CMake.
That is a good enough reason not to allow transitive dependencies of OBJECT libraries. It's tricky, so best avoided. So much so that it's mentioned as a Good Practice in his excellent book "Professional CMake: A Practical Guide":
If a target uses something from a library, it should always link directly to that library. Even if the
library is already a link dependency of something else the target links to, do not rely on an indirect
link dependency for something a target uses directly.
He also added in another issue:
he transitive nature of object libraries is not the same as regular libraries. The build-system manual words it like this:
The link (or archiving) step of those other targets will use the object files from object libraries that are directly linked.
The key part of that is the "directly linked". In your example, main gets the objects from b because it links directly to b, but because it does not link directly to a, it does not get a's objects, even though b links to a.
The reason for this is related to problems where deep transivity can result in object files being added multiple times, which will cause an error. This particular aspect has come up a few times in the issue tracker, but I don't have the issue numbers at hand (you can probably search for them and track down the various discussions).
So the solution seems to be to avoid relying on target_link_library for OBJECT libraries. There are two ways: First is to simply not use OBJECT libraries. Second is to explicitly specify objects to link in the hierarchy, as proposed by Hiroshi Miura:
add_library(a OBJECT a.c)
add_library(b OBJECT b.c)
target_sources(b PUBLIC $<TARGET_OBJECTS:a>)
add_executable(main main.c)
target_sources(main PRIVATE $<TARGET_OBJECTS:b>)
This is explicit, but doesn't even solve the problem I have! I suspect this also might run into duplication issues due to diamond patterns, but I haven't tested that.
Maybe over the next few months I'll figure out a better solution using generator expressions based on the LINK_LIBRARIES property of the objA. Not sure how to do that, though.

How to create a wrapper library without exposing the underlying library being used?

Using Cmake I would like to know how to create a wrapper library and let the users link their application with this library only. Users don't need to specify the original library in their linker flags.
For instance, I create a wrapper library for libwebsockets, named libcustomws.
add_library(customws main.c)
target_link_libraries(customws websockets)
I would like user (with no libwebsockets installed) to be able to do:
add_executable(user_app user_app.c)
target_link_libraries(user_app customws pthread)
Wrapper libraries without any additional code from within your project can best be implemented with small INTERFACE library targets with the IMPORTED tag. Example for your scenario:
add_library(customws INTERFACE IMPORTED)
target_include_directories(customws
INTERFACE
/some/include/path)
target_link_libraries(customws
INTERFACE
websockets)
This way, targets that use this library can just
add_executable(user_app user_app.c)
target_link_libraries(user_app customws pthread)
and get the usage requirements from the target customws, in this case an include directory and a linked library (websockets) are propagated through customws. This can be a good thing, as it might encapsulate implementation details of the dependency (different flags for different platforms etc.).
If you like to automatically link to compiled code (that is part of your project), this can be easily done by adding a small intermediate OBJECT library, e.g.
add_libraray(customwsenhanced
OBJECT
someCode.c)
target_link_library(customwsenhanced
PUBLIC
customws)
Depending on whether someCode.c depends on the usage requirements of customws, the target_link_library for customwsenhanced could also use INTERFACE propagation. Now, a client application can go with
add_executable(user_app user_app.c)
target_link_libraries(user_app customwsenhanced pthread)
and will get both the compiled object code of someCode.c as well as flags etc. from customws.

"config-style" cmake find_package unusable in parent scope

I have the following structure
project_root/
CMakeLists.txt (A)
ext/
CMakeLists.txt (B)
apps/
CMakeLists.txt (C)
The setup seems to be the fundamental issue, only when adding this new "config-style" library.
TL;DR: when find_package(foo) in (B) defines foo::foo as the library, how can I make foo::foo available in the parent scope so that target_link_libraries(tgt foo) will work for both (A) and (C)?
List (A) defines my project's options, such as what drivers to compile support for.
add_subdirectory(ext) takes place, and the needed external libraries are found. They are a mixture of add_subdirectory and find_package. List (B) populates lists for extra include directories, libraries, and compile time definitions, making them available to (A) (and subsequently (C)) with
set(MYPROJ_EXTRA_INC_DIRS "${MYPROJ_EXTRA_INC_DIRS}" PARENT_SCOPE)
set(MYPROJ_EXTRA_LIBS "${MYPROJ_EXTRA_LIBS}" PARENT_SCOPE)
set(MYPROJ_EXTRA_DEFINES "${MYPROJ_EXTRA_DEFINES}" PARENT_SCOPE)
List (A) now adds my library, including these extra directories, adding these extra definitions, and ultimately
target_link_libraries(${MYPROJ_LIB_NAME} ${MYPROJ_EXTRA_LIBS})
When the applications are requested to be built, add_subdirectory(apps) takes place, and list (C) defines a simple macro that creates an executable using the specified dependencies. The relevant part
target_link_libraries(${appName} ${MYPROJ_LIB_NAME} ${MYPROJ_EXTRA_LIBS})
This has been working very well for a long time. However, I added support for a new library that uses config-style find_package definitions, and I can't figure out how to use it correctly.
Call this new library dependency foo. It ultimately defines a single foo_LIBRARY which is foo::foo. My understanding was that I would need to do target_link_libraries(tgt foo), which works in list (A) for my library. However, it does not work for the applications, and in the macro I have to do find_package(foo) again for every executable.
Is there a way to use the existing approach (list(APPEND MYPROJ_EXTRA_LIBS <something>)) that does not require running find_package every time?
I've exhausted every reasonable option, and either get that -lfoo is not defined (if I just append foo to the list like I thought I should be), or find_package() is missing for an IMPORTED or ALIAS target. AKA since find_package(foo) happens in (B), by the time we reach (C) this target is not available. I tried making an ALIAS, but the error was then something that amounts to ALIAS cannot be created to an IMPORTED library.
Results of find_package call(both CONFIG and MODULE) are intended be used in the same directory or below. You are just lucky in that simple propagating of variables into PARENT_SCOPE makes results of find_package usable by the parent.
add_subdirectory(ext) takes place, and the needed external libraries are found.
Instead of ext/CMakeLists.txt included with add_subdirectory create CMake file (e.g. external.cmake) for being included via include. Because include command doesn't introduce new variable's scope, its find_package calls works for the main CMakeLists.txt.
Many existed projects process their dependencies in include files.
Another approach would be propagating results of find_package calls from subdirectory to the parent by creating INTERFACE library target which itself uses these results:
add_library(MyLibExtra INTERFACE)
target_link_libraries(MyLibExtra INTERFACE ${MYPROJ_EXTRA_LIBS})
target_include_directories(MyLibExtra INTERFACE ${MYPROJ_EXTRA_INC_DIRS})
target_compile_definitions(MyLibExtra INTERFACE ${MYPROJ_EXTRA_DEFINES})

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.