In cmake how do you use TARGET in file(GENERATE ... TARGET ...) - cmake

Docs imply that the TARGET option (new with 3.19) can be used for the generator expressions, however in the input how do you use the value input in the TARGET option?
$<TARGET_FILE:???>
tried a few things including ..., '' and just $<TARGET_FILE>. But always get Error evaluating generator expression:
--Docs
TARGET <target>
New in version 3.19.
Specify which target to use when evaluating generator expressions that require a target for evaluation (e.g. $<COMPILE_FEATURES:...>, $<TARGET_PROPERTY:prop>).
--Release notes
The file(GENERATE) command gained a new TARGET keyword to support resolving target-dependent generator expressions.

Related

Detect presence of generator expressions in CMake

The use case for the following problem is macro packages which are deployed, so the input is entirely user defined.
Consider the following minimal example:
function(foo)
cmake_parse_arguments(FOO "" "POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH" "" ${ARGN})
# Chosen as an example for a necessary step which doesn't have a generator expression equivalent
get_filename_component(
ABSOLUTE_PATH
"${FOO_POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH}"
REALPATH
BASE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}"
)
# Compatible with generator expressions by itself
add_custom_command(
OUTPUT
${MY_OUTPUT}
COMMAND
${MY_TOOL}
${ABSOLUTE_PATH}
)
endfunction()
add_custom_command itself supports generator expressions, but the need to go via get_filename_component to handle one class of input (relative paths, for brevity in calling code), and the use of that intermediate step being impossible for the other class of input (build type dependent generator expressions, which get scrambled by get_filename_component) clashes.
get_filename_component effectively can't be used whenever POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH had contained any genex components. get_filename_component has no generator expression equivalent either, so substitution of that logic isn't possible.
Is there a robust way to detect the presence of valid generator expressions in a CMake variable, so it can be used as a signal not to attempt any non-genex transformations on that input?
You could use command string(GENEX_STRIP) which strips generator expressions from the string, and compare its result with original string:
string(GENEX_STRIP "${FOO_POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH}" no_genex)
if(FOO_POSSIBLY_RELATIVE_POSSIBLY_GENEX_PATH STREQUAL no_genex)
# The string doesn't contain generator expressions.
# It is safe to use e.g. 'get_filename_component'
else()
# The string contains generator expressions.
# This case requires special handling.
endif()

Refer to the property of a target in generator expression of custom target

CMake version: 3.16.2
I'm trying to write a custom target for CMake, which allows me to get some properties from a known target.
I have this code:
add_custom_target(target_printer
COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:known_target, BINARY_DIR>"
)
On the configuration step, I faced the next problem:
Error evaluating generator expression:
$<TARGET_PROPERTY:known_target, BINARY_DIR>
Property name not supported.
Any suggestions?
When using generator expressions to retrieve one of the properties of a CMake target, CMake first verifies that the requested property is valid. During this verification, CMake will check to see if the provided property BINARY_DIR is a well-formed CMake property via regular expressions. It is a valid property, but the verification fails because of the extra space provided next to the property name. Generator expressions have very specific syntax (relevant example here), and in this case, spaces are not permitted surrounding the property name BINARY_DIR. Try removing the extra space before BINARY_DIR:
add_custom_target(target_printer
COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:known_target,BINARY_DIR>"
)

CMake add_custom_command OUTPUT support for build/configuration type

I want add_custom_command() to produce a different output depending on whether I'm building for Debug or Release (with a support for Visual Studio multi-configuration builds).
Essentially, I want to achieve something like:
add_custom_command(
OUTPUT $<IF:$<CONFIG:Debug>, file_to_generate_in_debug, file_to_generate_in_release>
COMMAND something.exe
...
)
Unfortunately, the generator expressions are not supported for the OUTPUT argument.
How should I do it using Modern CMake?
To make it more concrete, I'm trying to run windeployqt.exe to and my output should be either Qt5Core.dll or Qt5Cored.dll depending on the actual build configuration (which could either be known at Configure-time (e.g. for Ninja) or at Generate-time (e.g. for Visual Studio)).
Create as many add_custom_command as different OUTPUT you need to produce.
# A command which can be applied for Debug configuration(s)
add_custom_command(
OUTPUT file_to_generate_in_debug
COMMAND something.exe
...
)
# A command which can be applied for Release configuration(s)
add_custom_command(
OUTPUT file_to_generate_in_release
COMMAND something.exe
...
)
Only that instance will be active in a specific configuration which OUTPUT is used as DEPENDS in (other) add_custom_command/add_custom_target. Unlike to OUTPUT, DEPENDS clause supports generator expressions.
# This will chose a command suitable for configuration
add_custom_target(MY_GEN_LIB
DEPENDS $<IF:$<CONFIG:Debug>, file_to_generate_in_debug, file_to_generate_in_release>
)
If some other target needs your configuration-dependent output file, then you may adjust target-level dependencies:
# Depends from the target which produces required file
add_dependencies(other_target MY_GEN_LIB)
This will work even if the other target is an IMPORTED one.

CMake generator expression is not being evaluated

Due to the following warning:
CMake Error at test/CMakeLists.txt:29 (get_target_property):
The LOCATION property may not be read from target "my_exe". Use the
target name directly with add_custom_command, or use the generator
expression $<TARGET_FILE>, as appropriate.
which is the result from lines like this:
get_target_property(my_exe_path my_exe LOCATION)
Like recommended in the docs, I tried to use a generator expression like this:
add_executable(my_exe_path main.cpp)
message("path to executable: $<TARGET_FILE:my_exe_path>")
But TARGET_FILE is not being evaluated
path to executable: $<TARGET_FILE:my_exe>
I'm using CMake 3.4 and added cmake_minimum_required(VERSION 3.4) to my CMakeLists.txt so what am I doing wrong?
Here is a quick and easy way to print the value of a generator expression:
add_custom_target(print
${CMAKE_COMMAND} -E echo $<1:hello> $<0:world>
)
In this example, if you run cmake . and then make print, you will see "hello" (without the quotation marks) in the output.
However, if you just use message($<1:hello> $<0:world>), you will see "$<1:hello> $<0:world>" as output (again, without the quotation marks).
While generator expression is stored at configuration stage (when corresponded CMake command is executed),
evaluation of generator expressions is performed at build stage.
This is why message() command prints generator expression in non-dereferenced form: value denoted by the generator expression is not known at this stage.
Moreover, CMake never dereferences generator expressions by itself. Instead, it generates appropriate string in the build file, which is then interpreted by build utility (make, Visual Studio, etc.).
Note, that not every CMake command accepts generator expressions. Each possible usage of generator expressions is explicitely described in documentation for specific command. Moreover, different CMake command flows or different options have different policy about using of generator expressions.
For example, command flow
add_test(NAME <name> COMMAND <executable>)
accepts generator expressions for COMMAND option,
but command flow
add_test(<name> <executable>)
doesn't!
Another example of policies difference:
install(DIRECTORY <dir> DESTINATION <dest>)
In this command flow generator expressions are allowed for DESTINATION, but not for DIRECTORY option.
Again, read documentation carefully.

CMake generator expression is not evaluated

I cannot understand what I'm doing wrong.
I'm always getting the string "$<TARGET_FILE:tgt1>" instead of the path to the library.
I've created the dummy project.
Here is my root CMakeLists.txt
cmake_minimum_required (VERSION 3.0) # also tried 2.8 with the same result
set(PROJECT_NAME CMP0026)
add_subdirectory(src)
set(TGT_PATH $<TARGET_FILE:tgt1>)
message(STATUS "${TGT_PATH}")
Here is my src/CMakeLists.txt
add_library(tgt1 a.c)
File a.c is created and is empty
I've tried the following generators: Visual Studio 2013 Win64, Ninja and MingW Makefile. I've used Android toolchain for the last two, downloaded from here
I expect that the last message(STATUS command would print full path to the library. However, all variants print the string $<TARGET_FILE:tgt1>.
Generator expressions are not evaluated at configure time (when CMake is parsing CMakeLists, executing commands like add_target() or message() etc.). At this time, a generator expression is just a literal string - the character $ followed by <, then T, then ...
Evaluation of generator expressions happens at generate time (that's why they are called "generator expressions"). Generate time occurs after all CMake code is parsed and processed, and CMake is starting to act on the data therein to produce buildsystem files. Only then does it have all the information necessary to evaluate generator expressions.
So you can only really use generator expressions for things which occur at generate time or later (such as build time). A contrived example would be this:
add_custom_target(
GenexDemo
COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:tgt1>"
VERBATIM
)
At configure time, CMake will record the literal string $<TARGET_FILE:tgt1> as the argument of COMMAND. Then at generate time (when the location of tgt1 is known for each configuration and guaranteed not to change any more), it will substitute it for the generator expression.