Basically, before linking is performed, I would like to convert a GCC linker script template file into a final linker script, as discussed in Can I use Preprocessor Directives in .ld file - and I'd like that step to be performed by Cmake.
I guess my problem is similar to the discussion in add_custom_command is not generating a target ; but I still cannot see how to solve it. Here is a minimal example, where I'm faking with an empty .ld linker script template file; first, let's create the files using bash
:
mkdir /tmp/cmake_test && cd /tmp/cmake_test
touch my_linkerscript_template.ld
cat > main.c <<'EOF'
#include <stdio.h>
const char greeting[] = "hello world";
int main() {
printf("%s!\n", greeting);
return 0;
}
EOF
cat > CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.13)
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
project(foobar C)
message("PROJECT_NAME is '${PROJECT_NAME}'")
add_executable(${PROJECT_NAME}
main.c
)
add_compile_options(-Wall
)
target_link_options(${PROJECT_NAME} PRIVATE
"LINKER:--script=${CMAKE_SOURCE_DIR}/my_linkerscript.ld"
)
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/my_linkerscript.ld
DEPENDS ${CMAKE_SOURCE_DIR}/my_linkerscript_template.ld
COMMAND bash ARGS -c "gcc -E -x c -CC -I/usr/include my_linkerscript_template.ld | grep -v '^#' > my_linkerscript.ld"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "build my_linkerscript_template.ld into my_linkerscript.ld (${CMAKE_CURRENT_SOURCE_DIR})"
VERBATIM
)
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_DEPENDS "${CMAKE_SOURCE_DIR}/my_linkerscript.ld")
EOF
Note that my_linkerscript.ld
is not created above; as I'd intend to put my_linkerscript_template.ld
in git, and then have the final my_linkerscript.ld
generated on demand.
If in this case, I do:
mkdir /tmp/cmake_test/build && cd /tmp/cmake_test/build
cmake ../ -DCMAKE_BUILD_TYPE=Debug
make
I get:
$ make
make[2]: *** No rule to make target 'D:/msys64/tmp/cmake_test/my_linkerscript.ld', needed by 'foobar.exe'. Stop.
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/foobar.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
$ grep -r linkerscript .
./CMakeFiles/foobar.dir/build.make:foobar.exe: D:/msys64/tmp/cmake_test/my_linkerscript.ld
./CMakeFiles/foobar.dir/build.make: /D/msys64/mingw64/bin/cc.exe -g -Wl,--script=D:/msys64/tmp/cmake_test/my_linkerscript.ld -Wl,--whole-archive CMakeFiles/foobar.dir/objects.a -Wl,--no-whole-archive -o foobar.exe -Wl,--out-implib,libfoobar.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
So, I did get a dependency on my_linkerscript.ld
; and it did get added to linker options - but there is no build step generated by the add_custom_command
.
How can I have generate the proper dependencies, so that when my_linkerscript.ld
is needed for linking but it does not exist, then commands (that are given in add_custom_command
above) are run, to generate this file from the template?
CodePudding user response:
Output of add_custom_command
needs to be "consumed" by some target, otherwise the custom command has no effect.
The property LINK_DEPENDS
does NOT provide a consumer, so you need to create consumer target by yourself:
# ... in addition to your code
# Create a consumer target for the linker script.
# So previous `add_custom_command` will have an effect.
add_custom_target(my_linkerscript
DEPENDS ${CMAKE_SOURCE_DIR}/my_linkerscript.ld)
# Make executable to depend on that target.
# So, the check whether to relink the executable will be performed
# after possible rebuilding the linker script.
add_dependencies(${PROJECT_NAME} my_linkerscript)