In a more general sense, it's just very handy to be able to access all the expansion modes of the generator from user genexes, for flexibility. Otherwise there are things that the generator can do that the user cannot observe or interact with, which forces the user to reimplement the behavior, usually incorrectly.
I ran into this issue trying to work around issue #22057. It was hard to debug because I couldn't even use file(GENERATE)
to expand and dump properties to a file to look at.
Most do, but there are flags that come from target properties are the issue.
I know add_custom_command
is not designed for compilation. But there are situations (like mine) where you need to do a larger custom build process that wants to use the compile flags.
I see your point. But if CMake supports add_custom_command
, CMake clearly support constructing custom commands, so being able to generate reasonably complete compile and link things in special ways seems like a good thing. Maybe my approach isn't good though. Maybe a way to collect the needed information and ways to reprocess it in build environment independent ways would be more appropriate. Then a developer could make a conscious choice of how to construct command lines in cases where CMake doesn't actually do it (like VS and Xcode).
How is add_custom_command
handled in VS and Xcode?
This is now also a problem for $<DEVICE_LINK:>
and $<HOST_LINK:>
. Maybe we could have a genex similar to $<TARGET_GENEX_EVAL:tgt,expr>
that executes it's argument in a specific "link context" that can be specified as either DEVICE
or HOST
. A similar approach might be useful for other context sensitive genexes like $<INSTALL_INTERFACE:...>
. Not being able to expand flexibly in file(GENERATE)
makes it hard to debug generator expressions. Currently, if something contains $<HOST_LINK:...>
it is impossible to dump the expansion (as far as I can tell). And $<HOST_LINK:...>
is added to LINK_OPTIONS
by FindMPI.cmake
(when CUDA is available) so it can pop up even if the developer does not know they are using it.
To configure "sub-builds" that do not use CMake, the build system needs to extract the compiler and link options used by CMake and pass them to the sub-build. This is currently extremely tricky and (I think) impossible in a fully general way. I propose a few generator expressions that would extract information from the generation process (and even the generator itself), so that a CMake build script could use file(GENERATE)
or a custom command to pass the information to the sub-build in a principled and general way.
I propose the following genexes. Each expands to a cmake list, to avoid space safety issues.
$<TARGET_COMPILE_COMMAND:target,source_file>
: the compiler command with no options, e.g., gcc
or ccache;gcc
$<TARGET_COMPILE_OPTIONS:target,source_file>
: the command-line arguments to the compiler, including -D
, -o
, and input file names. E.g., -std=c++17;-fPIC;-pipe;-I;/usr/local/include;-O3;-DNDEBUG;src/source.cpp;-o;build/source.cpp.o
.$<TARGET_LINK_COMMAND:target>
: the linker command with no options, e.g., ld
or gcc
.$<TARGET_LINK_OPTIONS:target>
: the command line arguments to the linker. E.g., -fPIC;-Wl,-O2;-shared;-Wl,-soname,liblib.so;-o;liblib.so;build/source.cpp.o;-Wl,-rpath,/usr/local/lib;-ldl;-pthread
.I would love to split the _OPTIONS
expressions into _FLAGS
, _INPUTS
, and _OUTPUTS
, but I suspect that may not be possible in all cases since flags and inputs/outputs may need to be interspersed because argument order matters. I would also be happy with other splits of the command lines into different components. My only real requirement is that it should be possible reconstruct the compile/link command line used by the build system, precisely enough to have the same semantics. And this reconstruction should be possible in genexes without too much pain/fragility, so no special regexs, but I'm fine with needing $<JOIN:>
or something like that. The LINKER:
and SHELL:
magics should already be expanded since this is a command line.
These genexes should be usable in file(GENERATE)
and add_custom_command()
. I am assuming that the required shell and linker information is available at generation time since the generator obviously needs it to generate the build files. The genexes take a target as an argument, so they shouldn't need a target context.
There is one challenge though: With the advent of $<HOST_LINK:>
and $<DEVICE_LINK:>
, there may need to be an additional argument to specify which link operation we are talking about here. An optional DEVICE
or HOST
argument after the target seems like an easy solution.
compile_commands.json
provides similar information for compilation (but not linking). However, it is not "space safe" since it uses strings to represent command lines. Also it is harder to use since an external program would need to find the information it needed in the JSON file.
#15449 (https://cmake.org/Bug/view.php?id=15449) proposes a genex to get information about a target in a detailed way that could be used to construct most of a compile or link command. However, that proposal does not provide any way to construct a command line appropriate for the current build. #12435 proposes a similar (all be it more specific) genex with the same inability to build a command line in a fully general way.
I need to run a setuptools build as part of a CMake build. So I need to construct the compile and link commands and arguments needed so that that CMake configuration is used by setuptools compilations and that the setuptools builds can access CMake compiled build dependencies.
The implementation I have so far is at: https://github.com/KatanaGraph/katana/blob/6e8438703f9740dba688b67bfe8642e3f3da2917/cmake/Modules/KatanaPythonSetupSubdirectory.cmake#L77-L141
If this proposal were implemented I would instead create a dummy python module target with the correct dependencies and use these genexes to extract the information I needed into a JSON or even Python source file that contained exactly the information I needed. This would avoid the fragility of the current approach.
This issue originates from a discussion: https://discourse.cmake.org/t/generating-linker-command-line-arguments-to-a-file/3117