Generator expressions to get compiler and linker command lines for a specific target/source file
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.
Proposal
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
orccache;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
orgcc
. -
$<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.
Related Features/Issues
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.
A Specific Use Case
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