Home > Back-end >  Adding a step for building linker script file from template in CMake?
Adding a step for building linker script file from template in CMake?

Time:09-28

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)
  • Related