CMake Link.txt generated during CMake configuration does not contain any link flags or source files when using riscv toolchain

I have 2 source files, one is C (cstart.c) and another is assembly (startup.S) using which i am trying to make an riscv executable.

Here is how my CMakeLists.txt Looks Like

=========================================================================
cmake_minimum_required(VERSION 3.22.1)
set(CMAKE_TRY_COMPILE_TARGET_TYPE “STATIC_LIBRARY”)
set(CMAKE_TOOLCHAIN_FILE “/workspaces/risc_v/riscv_toolchain.cmake”)
project(riscv_training_lab C ASM)

message(STATUS “CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}”)
message(STATUS “CMAKE_CROSSCOMPILING: ${CMAKE_CROSSCOMPILING}”)

add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cstart.o
COMMAND ${CMAKE_ASM_COMPILER} -c -g -O0 -ffreestanding -march=rv64i -mabi=lp64 -mcmodel=medany -o ${CMAKE_CURRENT_BINARY_DIR}/cstart.o ${CMAKE_CURRENT_SOURCE_DIR}/cstart.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/cstart.c
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/startup.o
COMMAND ${CMAKE_ASM_COMPILER} -c -g -O0 -ffreestanding -march=rv64i -mabi=lp64 -mcmodel=medany -o ${CMAKE_CURRENT_BINARY_DIR}/startup.o ${CMAKE_CURRENT_SOURCE_DIR}/startup.S
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/startup.S

)

SET(OBJS
${CMAKE_CURRENT_BINARY_DIR}/cstart.o
${CMAKE_CURRENT_BINARY_DIR}/startup.o
)

add_executable(data_stack ${OBJS})
set_target_properties(data_stack PROPERTIES LINKER_LANGUAGE C)

=========================================================================

Here is how my toolchain file, which i am referring in above mentioned CMakeLists.txt looks like

========================================================================
set(CMAKE_SYSTEM_NAME Generic)

set(CMAKE_SYSTEM_PROCESSOR riscv64)

set(RISCV_TOOLCHAIN_ROOT “/opt/riscv/freestanding/multilib”)

set(CMAKE_C_COMPILER_TARGET riscv64-unknown-elf)

set(CMAKE_CXX_COMPILER_TARGET riscv64-unknown-elf)

set(CMAKE_C_COMPILER ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-gcc)

set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})

set(CMAKE_CXX_COMPILER ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-g++)

set(CMAKE_STRIP ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-strip)

set(CMAKE_AR ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-gcc-ar)

set(CMAKE_RANLIB ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-ranlib)

set(CMAKE_ADDR2LINE ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-addr2line)

set(CMAKE_NM ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-nm)

set(CMAKE_LINKER ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-ld)

set(CMAKE_OBJCOPY ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-objcopy)

set(CMAKE_OBJDUMP ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-objdump)

set(CMAKE_READELF ${RISCV_TOOLCHAIN_ROOT}/bin/riscv64-unknown-elf-readelf)

set(CMAKE_LINKER ${CMAKE_C_COMPILER})

set(CMAKE_C_LINK_EXECUTABLE ${CMAKE_C_COMPILER})

set(CMAKE_CROSSCOMPILING TRUE)

========================================================================

When i run cmake command, the CMake link.txt file so generated doe snot show any source files. Here is how the contents of link.txt looks like

=================================================
/opt/riscv/freestanding/multilib/bin/riscv64-unknown-elf-gcc

=================================================

I don’t see this issue when i dont use any toolchain. So if i use following CMakeLists.txt, i see link,txt showing source files

=========================================================================
cmake_minimum_required(VERSION 3.22.1)

project(riscv_training_lab C ASM)

add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cstart.o
COMMAND ${CMAKE_ASM_COMPILER} -c -g -O0 -ffreestanding -march=rv64i -mabi=lp64 -mcmodel=medany -o ${CMAKE_CURRENT_BINARY_DIR}/cstart.o ${CMAKE_CURRENT_SOURCE_DIR}/cstart.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/cstart.c
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/startup.o
COMMAND ${CMAKE_ASM_COMPILER} -c -g -O0 -ffreestanding -march=rv64i -mabi=lp64 -mcmodel=medany -o ${CMAKE_CURRENT_BINARY_DIR}/startup.o ${CMAKE_CURRENT_SOURCE_DIR}/startup.S
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/startup.S
)

SET(OBJS
${CMAKE_CURRENT_BINARY_DIR}/cstart.o
${CMAKE_CURRENT_BINARY_DIR}/startup.o
)

add_executable(data_stack ${OBJS})
set_target_properties(data_stack PROPERTIES LINKER_LANGUAGE C)

=========================================================================

Now the contents of link.txt shown all input and output files

=================================================
/usr/bin/cc cstart.o startup.o -o data_stack

=================================================

Can you please suggest what wrong is happening when i am using riscv toolchain

Does not do what you think it does - it’s a rule how to build link command line

This is what i see for CMAKE_C_LINK_EXECUTABLE,

======================================================================
The value of CMAKE_C_LINK_EXECUTABLE typically includes placeholders that CMake replaces with specific values during generation:

  • <CMAKE_C_COMPILER>: The C compiler being used.
  • <CMAKE_C_LINK_FLAGS>: Linker flags automatically determined by CMake based on the build type and target properties.
  • <LINK_FLAGS>: Linker flags specified explicitly by the user (e.g., through target_link_options).
  • <OBJECTS>: The object files to be linked.
  • <TARGET>: The name of the executable target.
  • Other placeholders for specific options or paths.

Usage and Modification:

While CMAKE_C_LINK_EXECUTABLE can be modified, it’s generally best to avoid directly setting this variable unless absolutely necessary for highly specialized scenarios like custom toolchain integration or specific build system modifications.

Instead of directly manipulating CMAKE_C_LINK_EXECUTABLE, it is recommended to use standard CMake commands and properties for controlling the linking process, such as:

  • target_link_libraries(): To link executables with libraries.
  • target_link_options(): To add specific linker flags to a target.
  • CMAKE_C_FLAGS and CMAKE_C_FLAGS_<BUILD_TYPE>: To add compiler/linker flags globally or for specific build types.
  • Toolchain files: For cross-compilation environments, toolchain files are the appropriate place to define or override tool-specific variables like CMAKE_C_LINK_EXECUTABLE.
    =========================================================================

are you suggesting that i should get rid of this from my toolchain file to solve this problem??

I am suggesting, that you have set it to ${CMAKE_C_COMPILER} which is set to /opt/riscv/freestanding/multilib/bin/riscv64-unknown-elf-gcc which contains no placeholders at all so this is the only thing that will end up as linker command (as you clearly discovered)

Since it seems you do not actually want to modify the linker command, just don’t set this variable.
BTW: You also set CMAKE_LINKER two times to different values…

You use CMake like a Makefile but all the custom commands are not needed. Just use the built-in ASM language support.