Skip to content

Commit 19cc9f0

Browse files
committed
cmake: Delay computation of linker paths until needed
With inclusion of the optimization flag into the multilib selection process, we cannot compute the compiler library path when the compiler's target.cmake is processed as LINKER_OPTIMIZATION_FLAG is not computed until much later. Instead, add a function (compiler_file_path) which can be used to locate the appropriate crtbegin.o and crtend.o files. Delay computation of lib_include_dir and rt_library until after all compiler flags have been computed by adding compiler_set_linker_properties and calling that just before toolchain_linker_finalize is invoked. Place default implementations of both of these functions in a new file, cmake/compiler/target_template.cmake, where we assume the compiler works like gcc or clang and handlers the --print-file-name and --print-libgcc-file-name options. Compilers needing alternate implementations can override these functions in their target.cmake files. These implementations require that no generator expressions are necessary for the compiler to compute the right library paths. This mechanism is also used to take any additional compiler options by adding a new (optional) linker function, toolchain_linker_add_compiler_options, which maps compiler options to equivalent linker options, discarding any that aren't applicable. Signed-off-by: Keith Packard <[email protected]>
1 parent df71a35 commit 19cc9f0

File tree

11 files changed

+156
-60
lines changed

11 files changed

+156
-60
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,8 @@ zephyr_compile_options($<$<COMPILE_LANGUAGE:ASM>:${ASM_OPTIMIZATION_FLAG}>)
307307
zephyr_compile_options($<$<COMPILE_LANGUAGE:C>:${COMPILER_OPTIMIZATION_FLAG}>)
308308
zephyr_compile_options($<$<COMPILE_LANGUAGE:CXX>:${COMPILER_OPTIMIZATION_FLAG}>)
309309
add_link_options(${LINKER_OPTIMIZATION_FLAG})
310+
compiler_simple_options(simple_options)
311+
toolchain_linker_add_compiler_options(${simple_options})
310312

311313
if(CONFIG_LTO)
312314
zephyr_compile_options($<TARGET_PROPERTY:compiler,optimization_lto>)
@@ -2401,6 +2403,9 @@ add_subdirectory_ifdef(
24012403
cmake/makefile_exports
24022404
)
24032405

2406+
# Ask the compiler to set the lib_include_dir and rt_library properties
2407+
compiler_set_linker_properties()
2408+
24042409
toolchain_linker_finalize()
24052410

24062411
# export build information

cmake/compiler/clang/target.cmake

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -100,21 +100,6 @@ if(NOT "${ARCH}" STREQUAL "posix")
100100
endif()
101101
endif()
102102

103-
# This libgcc code is partially duplicated in compiler/*/target.cmake
104-
execute_process(
105-
COMMAND ${CMAKE_C_COMPILER} ${clang_target_flag} ${TOOLCHAIN_C_FLAGS}
106-
--print-libgcc-file-name
107-
OUTPUT_VARIABLE RTLIB_FILE_NAME
108-
OUTPUT_STRIP_TRAILING_WHITESPACE
109-
)
110-
111-
get_filename_component(RTLIB_DIR ${RTLIB_FILE_NAME} DIRECTORY)
112-
get_filename_component(RTLIB_NAME_WITH_PREFIX ${RTLIB_FILE_NAME} NAME_WLE)
113-
string(REPLACE lib "" RTLIB_NAME ${RTLIB_NAME_WITH_PREFIX})
114-
115-
set_property(TARGET linker PROPERTY lib_include_dir "-L${RTLIB_DIR}")
116-
set_property(TARGET linker PROPERTY rt_library "-l${RTLIB_NAME}")
117-
118103
list(APPEND CMAKE_REQUIRED_FLAGS -nostartfiles -nostdlib ${isystem_include_flags})
119104
string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
120105

cmake/compiler/gcc/target.cmake

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,21 +98,6 @@ if(SYSROOT_DIR)
9898
set(LIBC_LIBRARY_DIR "\"${SYSROOT_DIR}\"/lib/${NEWLIB_DIR}")
9999
endif()
100100

101-
# This libgcc code is partially duplicated in compiler/*/target.cmake
102-
execute_process(
103-
COMMAND ${CMAKE_C_COMPILER} ${TOOLCHAIN_C_FLAGS} --print-libgcc-file-name
104-
OUTPUT_VARIABLE LIBGCC_FILE_NAME
105-
OUTPUT_STRIP_TRAILING_WHITESPACE
106-
)
107-
108-
assert_exists(LIBGCC_FILE_NAME)
109-
110-
get_filename_component(LIBGCC_DIR ${LIBGCC_FILE_NAME} DIRECTORY)
111-
112-
assert_exists(LIBGCC_DIR)
113-
114-
set_linker_property(PROPERTY lib_include_dir "-L\"${LIBGCC_DIR}\"")
115-
116101
# For CMake to be able to test if a compiler flag is supported by the
117102
# toolchain we need to give CMake the necessary flags to compile and
118103
# link a dummy C file.

cmake/compiler/icx/target.cmake

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,6 @@ else()
4545
list(APPEND TOOLCHAIN_C_FLAGS "-m32")
4646
endif()
4747

48-
49-
# This libgcc code is partially duplicated in compiler/*/target.cmake
50-
execute_process(
51-
COMMAND ${CMAKE_C_COMPILER} ${TOOLCHAIN_C_FLAGS} --print-libgcc-file-name
52-
OUTPUT_VARIABLE LIBGCC_FILE_NAME
53-
OUTPUT_STRIP_TRAILING_WHITESPACE
54-
)
55-
56-
get_filename_component(LIBGCC_DIR ${LIBGCC_FILE_NAME} DIRECTORY)
57-
58-
list(APPEND LIB_INCLUDE_DIR "-L\"${LIBGCC_DIR}\"")
59-
if(LIBGCC_DIR)
60-
list(APPEND TOOLCHAIN_LIBS gcc)
61-
endif()
62-
6348
set(CMAKE_REQUIRED_FLAGS -nostartfiles -nostdlib ${isystem_include_flags})
6449
string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
6550

cmake/compiler/target_template.cmake

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
#
3+
# Copyright (c) 2025, Nordic Semiconductor ASA
4+
5+
# Template file for optional Zephyr compiler functions.
6+
#
7+
# This file will define optional compiler functions for toolchains that are not
8+
# defining these functions themselves.
9+
10+
# Extract all of the compiler options which don't involve generator
11+
# expressions. We hope that none of the flags required to compute compiler
12+
# support library paths depend upon those.
13+
14+
function(compiler_simple_options simple_options_out)
15+
16+
get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS)
17+
18+
set(simple_options "")
19+
20+
foreach(flag ${flags})
21+
22+
# Include this flag if GENEX_STRIP has no effect,
23+
# otherwise skip the whole thing
24+
25+
string(GENEX_STRIP "${flag}" sflag)
26+
if(flag STREQUAL sflag)
27+
if(flag MATCHES "^SHELL:[ ]*(.*)")
28+
separate_arguments(flag UNIX_COMMAND ${CMAKE_MATCH_1})
29+
endif()
30+
list(APPEND simple_options ${flag})
31+
endif()
32+
33+
endforeach()
34+
35+
set(${simple_options_out} "${simple_options}" PARENT_SCOPE)
36+
endfunction()
37+
38+
if(NOT COMMAND compiler_file_path)
39+
40+
# Search for filename in default compiler library path using the
41+
# --print-file-name option which is common to gcc and clang. If the
42+
# file is not found, filepath_out will be set to an empty string.
43+
#
44+
# This only works if none of the compiler flags used to compute
45+
# the library path involve generator expressions as we cannot
46+
# evaluate those in this function.
47+
#
48+
# Compilers needing a different implementation should provide this
49+
# function in their target.cmake file
50+
51+
function(compiler_file_path filename filepath_out)
52+
53+
compiler_simple_options(simple_options)
54+
55+
execute_process(
56+
COMMAND ${CMAKE_C_COMPILER} ${TOOLCHAIN_C_FLAGS} ${COMPILER_OPTIMIZATION_FLAG} ${simple_options}
57+
--print-file-name ${filename}
58+
OUTPUT_VARIABLE filepath
59+
OUTPUT_STRIP_TRAILING_WHITESPACE
60+
)
61+
if(${filepath} STREQUAL ${filename})
62+
set(filepath "")
63+
endif()
64+
set(${filepath_out} "${filepath}" PARENT_SCOPE)
65+
endfunction()
66+
67+
endif()
68+
69+
if(NOT COMMAND compiler_set_linker_properties)
70+
71+
# Set the lib_include_dir and rt_library linker properties
72+
# by searching for the runtime library in the compiler default
73+
# library search path. If no runtime library is found, these
74+
# properties will remain unset
75+
#
76+
# Compilers needing a different implementation should provide this
77+
# function in their target.cmake file
78+
79+
function(compiler_set_linker_properties)
80+
81+
compiler_simple_options(simple_options)
82+
83+
# Compute complete path to the runtime library using the
84+
# --print-libgcc-file-name compiler flag
85+
execute_process(
86+
COMMAND ${CMAKE_C_COMPILER} ${TOOLCHAIN_C_FLAGS} ${COMPILER_OPTIMIZATION_FLAG} ${simple_options}
87+
--print-libgcc-file-name
88+
OUTPUT_VARIABLE library_path
89+
OUTPUT_STRIP_TRAILING_WHITESPACE
90+
)
91+
92+
# Compute the library directory name
93+
94+
get_filename_component(library_dir ${library_path} DIRECTORY)
95+
set_linker_property(PROPERTY lib_include_dir "-L${library_dir}")
96+
97+
# Compute the linker option for this library
98+
99+
get_filename_component(library_basename ${library_path} NAME_WLE)
100+
101+
# Remove the leading 'lib' prefix to leave a value suitable for use with
102+
# the linker -l flag
103+
string(REPLACE lib "" library_name ${library_basename})
104+
105+
set_linker_property(PROPERTY rt_library "-l${library_name}")
106+
endfunction()
107+
108+
endif()

cmake/compiler/xcc/target.cmake

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,6 @@ foreach(file_name include/stddef.h include-fixed/limits.h)
5555
endif()
5656
endforeach()
5757

58-
# This libgcc code is partially duplicated in compiler/*/target.cmake
59-
execute_process(
60-
COMMAND ${CMAKE_C_COMPILER} ${TOOLCHAIN_C_FLAGS} --print-libgcc-file-name
61-
OUTPUT_VARIABLE LIBGCC_FILE_NAME
62-
OUTPUT_STRIP_TRAILING_WHITESPACE
63-
)
64-
65-
get_filename_component(LIBGCC_DIR ${LIBGCC_FILE_NAME} DIRECTORY)
66-
67-
list(APPEND LIB_INCLUDE_DIR "-L\"${LIBGCC_DIR}\"")
68-
6958
# For CMake to be able to test if a compiler flag is supported by the
7059
# toolchain we need to give CMake the necessary flags to compile and
7160
# link a dummy C file.

cmake/linker/ld/target.cmake

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,25 @@ macro(toolchain_linker_finalize)
159159

160160
set(cpp_link "${common_link}")
161161
if(NOT "${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "host")
162-
if(CONFIG_CPP_EXCEPTIONS AND LIBGCC_DIR)
162+
compiler_file_path(crtbegin.o CRTBEGIN_PATH)
163+
compiler_file_path(crtend.o CRTEND_PATH)
164+
if(CONFIG_CPP_EXCEPTIONS AND CRTBEGIN_PATH AND CRTEND_PATH)
163165
# When building with C++ Exceptions, it is important that crtbegin and crtend
164166
# are linked at specific locations.
165-
set(cpp_link "<LINK_FLAGS> ${LIBGCC_DIR}/crtbegin.o ${link_libraries} ${LIBGCC_DIR}/crtend.o")
167+
set(cpp_link "<LINK_FLAGS> ${CRTBEGIN_PATH} ${link_libraries} ${CRTEND_PATH}")
166168
endif()
167169
endif()
168170
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> ${cpp_link}")
169171
endmacro()
170172

173+
# Function to map compiler flags into suitable linker flags
174+
# When using the compiler driver to run the linker, just pass
175+
# them all through
176+
177+
function(toolchain_linker_add_compiler_options)
178+
add_link_options(${ARGV})
179+
endfunction()
180+
171181
# Load toolchain_ld-family macros
172182
include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_relocation.cmake)
173183
include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_configure.cmake)

cmake/linker/lld/target.cmake

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ macro(toolchain_linker_finalize)
128128
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> ${common_link}")
129129
endmacro()
130130

131+
# Function to map compiler flags into suitable linker flags
132+
# When using the compiler driver to run the linker, just pass
133+
# them all through
134+
135+
function(toolchain_linker_add_compiler_options)
136+
add_link_options(${ARGV})
137+
endfunction()
138+
131139
# Load toolchain_ld-family macros
132140
include(${ZEPHYR_BASE}/cmake/linker/ld/target_relocation.cmake)
133141
include(${ZEPHYR_BASE}/cmake/linker/ld/target_configure.cmake)

cmake/linker/target_template.cmake

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,13 @@ if(NOT COMMAND toolchain_linker_finalize)
1111
macro(toolchain_linker_finalize)
1212
endmacro()
1313
endif()
14+
15+
if(NOT COMMAND toolchain_linker_add_compiler_options)
16+
17+
# If the linker doesn't provide a method for mapping compiler options
18+
# to linker options, then assume we can't. This matters when the linker
19+
# is using additional flags when computing toolchain library paths.
20+
21+
function(toolchain_linker_add_compiler_options)
22+
endfunction()
23+
endif()

cmake/linker/xt-ld/target.cmake

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ find_program(CMAKE_LINKER xt-ld ${LD_SEARCH_PATH})
1111

1212
set_ifndef(LINKERFLAGPREFIX -Wl)
1313

14-
if(CONFIG_CPP_EXCEPTIONS)
14+
compiler_file_path(crtbegin.o CRTBEGIN_PATH)
15+
compiler_file_path(crtend.o CRTEND_PATH)
16+
if(CONFIG_CPP_EXCEPTIONS AND CRTBEGIN_PATH AND CRTEND_PATH)
1517
# When building with C++ Exceptions, it is important that crtbegin and crtend
1618
# are linked at specific locations.
1719
# The location is so important that we cannot let this be controlled by normal
1820
# link libraries, instead we must control the link command specifically as
1921
# part of toolchain.
2022
set(CMAKE_CXX_LINK_EXECUTABLE
21-
"<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> ${LIBGCC_DIR}/crtbegin.o <OBJECTS> -o <TARGET> <LINK_LIBRARIES> ${LIBGCC_DIR}/crtend.o")
23+
"<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> ${CRTBEGIN_PATH} <OBJECTS> -o <TARGET> <LINK_LIBRARIES> ${CRTEND_PATH}")
2224
endif()
2325

2426
# Run $LINKER_SCRIPT file through the C preprocessor, producing ${linker_script_gen}
@@ -156,6 +158,14 @@ macro(toolchain_linker_finalize)
156158
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> ${common_link}")
157159
endmacro()
158160

161+
# Function to map compiler flags into suitable linker flags
162+
# When using the compiler driver to run the linker, just pass
163+
# them all through
164+
165+
function(toolchain_linker_add_compiler_options)
166+
add_link_options(${ARGV})
167+
endfunction()
168+
159169
# xt-ld is Xtensa's own version of binutils' ld.
160170
# So we can reuse most of the ld configurations.
161171
include(${ZEPHYR_BASE}/cmake/linker/ld/target_relocation.cmake)

0 commit comments

Comments
 (0)