Skip to content

Commit b7f91f1

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 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 and pass them to the linker using toolchain_linker_add_compiler_options. Signed-off-by: Keith Packard <keithp@keithp.com>
1 parent 055472a commit b7f91f1

File tree

9 files changed

+122
-61
lines changed

9 files changed

+122
-61
lines changed

CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ endif()
247247
# Apply the final optimization flag(s)
248248
zephyr_compile_options($<$<COMPILE_LANGUAGE:C>:${OPTIMIZATION_FLAG}>)
249249
zephyr_compile_options($<$<COMPILE_LANGUAGE:CXX>:${OPTIMIZATION_FLAG}>)
250-
toolchain_linker_add_compiler_options(${OPTIMIZATION_FLAG})
250+
compiler_simple_options(simple_options)
251+
toolchain_linker_add_compiler_options(${OPTIMIZATION_FLAG} ${simple_options})
251252

252253
if(CONFIG_LTO)
253254
zephyr_compile_options($<TARGET_PROPERTY:compiler,optimization_lto>)
@@ -2345,6 +2346,9 @@ add_subdirectory_ifdef(
23452346
cmake/makefile_exports
23462347
)
23472348

2349+
# Ask the compiler to set the lib_include_dir and rt_library properties
2350+
compiler_set_linker_properties()
2351+
23482352
toolchain_linker_finalize()
23492353

23502354
# 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} ${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} ${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: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,12 @@ 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}")

cmake/linker/xt-ld/target.cmake

Lines changed: 4 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}

cmake/modules/FindTargetTools.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ include(${ZEPHYR_BASE}/cmake/bintools/bintools_template.cmake)
106106
include(${TOOLCHAIN_ROOT}/cmake/bintools/${BINTOOLS}/target.cmake OPTIONAL)
107107

108108
include(${TOOLCHAIN_ROOT}/cmake/linker/target_template.cmake)
109+
include(${TOOLCHAIN_ROOT}/cmake/compiler/target_template.cmake)
109110

110111
set(TargetTools_FOUND TRUE)
111112
set(TARGETTOOLS_FOUND TRUE)

0 commit comments

Comments
 (0)