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

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}")

Related

How to set value by code to a CACHE variable defined by 3d party CMake?

In my project, the CMakeLists includes other cmake files from a library and those dependencies need some cache variables to be configured by user values.
It is all working well if I define those values from the command line with the cmake command:
-DTHIRDPARTY_FRAMEWORK_ROOT="$thirdpartyFrameworkPath"
But can I define (= hardcode) such values in my own CMakeLists file?
To avoid my own users to do it when they configure my project (some values of the 3d party configuration are constant in my project), and make my own cmake interface simpler.
I tried to simply set the variable with a value, but it is both defined and used in the included cmake so it gets overwritten with their default value just before being used.
Using set(... FORCE) seems to work but it does not look clean to me, and might lead to confusing errors if they rename or change the type of the variables on their side. It also forces me to add a type and a doc string because of the set(... CACHE ...) syntax.
Is there a better way to do this?
Setting CACHE INTERNAL variable is a proper way for hardcode a parameter of the inner project in the outer one:
set(THIRDPARTY_FRAMEWORK_ROOT CACHE INTERNAL "Hardcoded root for 'thirdparty'" <value>)
INTERNAL type makes sure that this setting will overwrite the option (FORCE doesn't need) and makes sure that the option won't be shown for a "normal" user.
Since the parameter is not intended to be changed by a user, its real type is meaningless, so there is no needs for it to coincide with the one set in the inner project.
As for description, you could set it to be empty (the parameter is not shown to the normal user, remember?). Alternatively, in the description you could explain why do you set the variable in the outer project. So an "advanced" user will see your description.

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.

How do I make Meson object constant?

As explained here, I like to create file objects in subdirs, and library / executables in the top-level file. However, since all the variables end up in global scope, two subdir files could accidentally use the same variable names. For example:
# Top-level meson.build
subdir('src/abc')
subdir('src/def')
# src/abc/meson.build
my_files=files('1.c','2.c')
# src/def/meson.build
my_files=files('3.c','4.c')
I want meson to throw an error when src/def/meson.build tries to assign a value to my_files. Is this possible in Meson 0.50?
Reassigning variables is rather legitimate operation in meson, so it looks as it is not possible to generate error in standard way. One way of avoiding this problem is following some naming rules e.g. according to folders/sub-folders' names (abc_files, def_files in your case).
But if you really need to have variables with the same name and make sure they are not reassigned, you can use is_variable() function which returns true if variable with given name has been assigned. So, place the following assert before each assignment:
assert(not is_variable('my_files'), 'my_files already assigned!!!')
my_files=files('3.c','4.c')

What is the purpose of the TARGET_NAME generator expression?

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).

find_library() only finds the path of the first library name

I am referring the official doc to use find_library() and my cmake version is 3.9.1.
In short, my find_library() only deals with the first library name and ignore the rest.
For example, when I do something like,
find_library (var NAMES libname1 libname2 PATHS libpath)
var will only get the full path-name of library libname1 not the counterpart of libname2. Both the libraries are placed correctly in libpath. In fact, if I reverse the order as NAMES libname2 libname1, var will only get the full path-name of library libname2
Any suggestion?
The find_librarycommand finds a library by trying the NAMES one after another. So the NAMES are synonyms for the library (e.g. libjpg libjpeg). After the first match it saves the path to the library in the variable var. You need to use two find_library calls to accomplish what you are after.