How to query whether a target is an INTERFACE library in CMake - cmake

In modern CMake one can specify a library as INTERFACE: it does not produce build output, but it can have properties associated to it, although not all properties can be set (for instance the FOLDER property is not supported). Say I have a generic CMake macro setting properties for a generic library target, is there a way to tell that the input target is an interface library, so that I can skip the unsupported properties only for that target?

You query the TYPE property of target....
get_target_property(type target TYPE)
if (${type} STREQUAL "INTERFACE_LIBRARY")

Related

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.

What are legal items in the INTERFACE_LINK_LIBRARIES property?

My expectations are, that the items in the target property INTERFACE_LINK_LIBRARIES are other targets. However when I use on Linux for the official Threads package.
find_package(Threads)
get_property(libs TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES)
libs ist set to -lpthread, which seems to be a linker flag, not a target.
Is this correct?
That property is populated by the command target_link_libraries(), and its documentation lists what can be specified:
A library target name
A full path to a library file
A plain library name
A link flag
Keywords debug, optimized, or general
Therefore, link flags are allowed here, even if discouraged by the CMake documentation.

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)

Is all of a static library included in a final product after linking?

Suppose I create an iOS application. I include a static library. I create an object of a class that is defined and implemented in static library. This object doesn't use other classes defined in the library. Will all of the static library be present in the application I build? The idea is that much of the static library contains unused code and wouldn't need to be present.
I believe there a flags that help determine the behavior -- if someone can spell out how this works, I sure would appreciate it.
A static library is an archive of object files. If you link against a static library libfoo.a then
the linker by default will link into your final executable all and only those object files in libfoo.a
that are required to provide definitions for the public symbols that are referenced by the program.
More specifically, if the linker finds the library requested (via the option -lfoo) at a given
point in the commandline sequence of object files and libraries to be linked, then it will
extract from the archive and link into the executable each object file in the archive that provides
a definition for any symbol that remains undefined up to that point in the linkage.
In so doing, definitions of unused public symbols may be redundantly linked into
your program, but only if they are found in an object file (whether free-standing or a member of
a library) that is not completely redundant.
If you do not want to tolerate even those potential redundancies, then a combination of
compiler and linker options can eliminate them: see this answer

How to tell whether a given target is a library or executable?

The built-in function install(TARGETS ...) installs library targets to another location than executable targets. I want to do something similar. Given a list of target names, I want to add all library targets among them to a list variable and all runtime targets to another variable.
I couldn't found a list of CMake's default target properties, but I guess add_library() and add_executable() add a property that can be used for this kind of distinction.
How to tell whether a given target is a library or executable (or even something else)?
According to documentation, TYPE property can be used for distinguish standard CMake target types:
It will be one of STATIC_LIBRARY, MODULE_LIBRARY, SHARED_LIBRARY, EXECUTABLE or one of the internal target types.
Example:
get_target_property(target_type <target> TYPE)
if (target_type STREQUAL "EXECUTABLE")
# Process executable target
endif ()