What is the purpose of the TARGET_NAME generator expression? - cmake

In the CMake documentation describing generator expressions there is this paragraph:
$<TARGET_NAME:...>
Marks ... as being the name of a target. This is required if exporting targets to multiple dependent export sets. The ... must be a literal name of a target- it may not contain generator expressions.
I am trying to understand the highlighted part.
First I want to see if I understand correctly the notion of dependent export sets. If target B depends on target A and if export set EXP_A contains target A and export set EXP_B contains target B, then the export set EXP_B is dependent on the export set EXP_A. Is this correct?
Why is $<TARGET_NAME:...> "required if exporting targets to multiple dependent export sets"?

I'm not sure what they mean by "multiple dependent export sets". I looked at their test suite and couldn't find anything like that. It's confusing to me, too.
However, I can give you an example where $<TARGET_NAME:...> actually does something. Consider:
cmake_minimum_required(VERSION 3.20)
project(test)
add_library(define_a INTERFACE)
target_compile_definitions(define_a INTERFACE A)
add_library(define_a_tgt INTERFACE)
target_compile_definitions(define_a_tgt INTERFACE "A_TGT=\"$<TARGET_NAME:define_a>\"")
include(GNUInstallDirs)
install(TARGETS define_a define_a_tgt EXPORT test)
install(
EXPORT test
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/test
FILE test-config.cmake
NAMESPACE test::
)
Here, we have two silly INTERFACE libraries. The first, define_a, simply propagates -DA to the target linking to it. The second, define_a_tgt adds a definition of A_TGT such that it is equal to the string containing the name of the target define_a.
In the build interface, this will expand to simply define_a, but after exporting it, CMake will replace $<TARGET_NAME:define_a> with test::define_a (on account of the NAMESPACE argument to install(EXPORT)).
This is a bit contrived, but it does show an instance where CMake is not already aware that a target is being named (it transforms target_link_libraries targets automatically, without this genex). Another instance is inside other generator expressions (even in target_link_libraries).

Related

Why the use of generator expression to link object library?

I understand the purpose of object libraries, but why does linking it to a target need to involve a generator expression?
add_library(myObjects OBJECT a.cpp b.cpp)
add_library(mainLib ${other_srcs} $<TARGET_OBJECTS:myObjects>) # Why not "PRIVATE myObjects" just like other files and targets?
From my understanding, generator expressions are useful for evaluating things available only during generation phase. Why would it be the case that object libraries, which are simply collection of object files, and their location not be known during the configuration phase?
In addition to what #Alex Reinking has already said, the location of the object file may itself depend on the configuration, e.g. with the "Ninja Multi-Config" generator the object files of a target t are located in <build-dir>/t/CMakeFiles/t.dir/<config>/<path-of-source-file-relative-to-dir-in-which-target-is-defined>/<src-file-name>.o
So you're exactly in the situation that you only know the location at generation time, hence the need for a generator expression.
add_library(mainLib ${other_srcs} $<TARGET_OBJECTS:myObjects>) # Why not "myObjects" just like other files and targets?
So:
add_library(mainLib ${other_srcs} myObjects)
Because that would try to find a file named myObjects and compile it. The file has no extensions, so cmake will exit because the file does not exists and he doesn't know how to compile it anyway.
If you meant:
add_library(mainLib ${other_srcs})
target_link_libraries(mainLib PUBLIC myObjects)
The link_libraries dependency on object libraries did not work in older cmake when OBJECT libraries were introduced.
The documentation on object libraries explicitly mentions the form add_library(... $<TARGET_OBJECTS:...) and notes that since cmkae 3.12 target_link_libraries may be used with object libraries.
Why would it be the case that object libraries, which are simply collection of object files, and their location not be known during the configuration phase?
Simple: the target_sources command may be used to add sources (and therefore objects) to a target at any point. If a variable were expanded immediately, one would miss objects that were added later.
In multi-config builds, it is also unknown at configuration time whether you refer to the Debug or Release objects.
Imagine that add_library(target a.cpp b.cpp) created a variable named target_OBJECTS containing /path/to/a.o;/path/to/b.o. Then the following sequence demonstrates the problem:
add_library(target a.cpp b.cpp)
add_executable(main main.cpp ${target_OBJECTS}) # (1)
# ... later ...
target_sources(target PRIVATE c.cpp)
# ... later ...
add_executable(utility util.cpp ${target_OBJECTS}) # (2)
Now how would (2) know about /path/to/c.o? You could have target_sources update that variable, but now a single object library has dependents that see different subsets of it. That's horribly confusing. Moreover, (1) wouldn't see c.o, which is maybe what's desired in this example, but that's not always true. Maybe your code is just organized to define custom commands to create generated sources later.
Making this imperative, rather than declarative like $<TARGET_OBJECTS:target>, imposes structure on CMake code akin to requiring targets in a Makefile to be topologically sorted. It also changes the meaning from "the object files for this target" to "the object files for this target at this point in CMake execution time", which is strictly more complicated to reason about while not offering any expressive advantage.
If you replace this code with the CMake 3.12+ object library linking support, it looks even more vexing:
add_library(target a.cpp b.cpp)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE target) # (1)
# ... later ...
target_sources(target PRIVATE c.cpp)
# ... later ...
add_executable(utility util.cpp)
target_link_libraries(utility PRIVATE target) # (2)
Now, looking at either call to target_link_libraries(... target), one would reasonably expect the same objects to be added.

Can I get the original target name from an alias target?

If I create an alias target in CMake like
add_library(my::foo ALIAS my_foo)
is there any way to query the name of the underlying target name from the alias target?
My use case:
A shared C++ codebase with several independent modules. The root folder of this codebase contains a CMakeList.txt to be added via add_subdirectory to the project using it. According to our convention e.g. my_foo will always be located in a subfolder named my_foo. Furthermore, my_foo will be exported as alias target my::foo and used as such in the project. Note that my_foo is always an INTERFACE target, so I cannot set any custom properties on it.
We use conan to manage third party library dependencies. All modules that have such dependencies contain a conanfile.txt
For convenience I want to write a function (located in the shared codebase's root CMakeList) that takes a list of module targets the project wants to use and scans all of them for conanfiles and sets up the dependencies for those used. I want to be able to pass my::foo as argument to that function but derive my_foo from that argument inside the function to get the corresponding folder name to scan for the conanfile
Any other suggestions that solve the problem according to my use case are welcome as well!
An alias target has a special property, where it store name of the original target: ALIASED_TARGET.
get_target_property(my_foo_original my::foo ALIASED_TARGET)
message(STATUS "Alias my::foo refers to the target ${my_foo_original}")

Distinguish two functions with the same name

I want to use multiple external CMake files in my project. Unfortunately two different files use the same CMake function name foo. I don't want to modify these external files.
Is there a way to call one specific function or will CMake error out? Would it help if one of the functions has a named parameter, i.e., foo(a b c …) and foo(DESTINATION a b c …)?
New function's definition replaces the previous one with the same name. So access to the previous function is lost.
If different functions (but with the same name) are used in different subprojects, you may try to build one subproject as ExternalProject, so function's collision wouldn't occure.
In CMake any function definitions contains the only piece of information for the caller - minimal number of parameters which should be passed to the function. By using this information it is impossible to resolve function's overloading, if it would be implemented.

How to use condition in cmake generator expression

I would like to compile a library as shared or static based on other variable eg:
add_library(MyLibrary $<$<IF:${BUILD_SHARED_LIBS},SHARED,STATIC> ${SOURCES})
For clarity I expect this to be equivalent with the following:
if(BUILD_SHARED_LIBS)
add_library(MyLibrary SHARED ${SOURCES})
elseif()
add_library(MyLibrary STATIC ${SOURCES})
endif()
AFAIK, you cannot do that with generator expressions (no way to query that aspect according to doc), since BUILD_SHARED_LIBS is there for exactly that reason; to allow you to select its value during configuration (using the -D command line option). This will work only if you do not set the library type explicitly as in your code, but like this
add_library(MyLibrary ${SOURCES})
Actually, that is the recommended practice. If you need to influence its value in association with some other condition, you can override it with the usual if()/else() logic, making sure that you print at least an informative message() for the user.
However, an even better approach would be to push those decisions to the user (via options) and check for the illegal combinations, issuing a message(FATAL_ERROR). Even if that condition is determined automatically, this is still a tactic that has merit.

Can we export a function made available through a static library

I have a static library say "A.lib" which contains a function int foo(). I have another dll say "B.dll" which consumes A.lib and uses the function foo() and also exports some other functions. Is it possible to export the function int foo() (imported from A.lib) from B.dll so that it can be consumed in a third dll say "C.dll".
I want to know whether it is possible or not, I dont want workarounds like making A.lib available to the C.dll. Also, I am not concerned if this is a bad design or not.
Thanks very much for your patience to read this through.
I had the same requirement - just found a different solution:
Assuming that A.lib has an A.h (that is consumed by source files used to build B.dll e.g. assuming that A.h contains prototypes for functions contained in A.lib), just add the following in A.h:
#pragma comment(linker, "/export:_foo")
This will instruct the linker to export foo() when building B.dll. Note the leading underscore - it is there because that's the true name of the symbol for foo() contained in A.lib (use dumpbin /symbols A.lib | findstr foo to see it). In my example foo() was using the __cdecl calling convention, but if you use __stdcall() or compile as C++, you'll get different name decoration, so you'll have to adjust the #pragma statement above as a result.
It doesn't matter if A.h gets included by many source files in B.dll - the linker doesn't complain if the exact same definition is made multiple times.
One "advantage" to this approach is that you don't even have to use the __declspec(dllexport) specifier on foo() in A.lib ...
Yes, it's possible but any code example is language dependent.
(for example in C you may simply export a function with the same name and C.dll will see it)