Skip to content

Commit 9d9ba58

Browse files
authored
add custom linker script (#103)
* add custom linker script a custom linker script can be applied by adding the .ld filepath as 2nd argument to mbed_set_post_build * more detailed comment * add if is_standalone for text cases * replace COMMENT in add_custom_command by echo COMMENT is not reliable printed
1 parent 310aac3 commit 9d9ba58

File tree

2 files changed

+89
-5
lines changed

2 files changed

+89
-5
lines changed

tools/cmake/mbed_set_linker_script.cmake

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ function(mbed_setup_linker_script mbed_os_target mbed_baremetal_target target_de
5656
OUTPUT
5757
${LINKER_SCRIPT_PATH}
5858
PRE_LINK
59+
COMMAND
60+
${CMAKE_COMMAND} -E echo "Preprocess linker script: ${RAW_LINKER_SCRIPT_NAME} -> ${LINKER_SCRIPT_NAME}"
5961
COMMAND
6062
${CMAKE_C_COMPILER} @${linker_defs_response_file}
6163
-E -x assembler-with-cpp
@@ -68,23 +70,80 @@ function(mbed_setup_linker_script mbed_os_target mbed_baremetal_target target_de
6870
${target_defines_header}
6971
WORKING_DIRECTORY
7072
${CMAKE_CURRENT_SOURCE_DIR}
71-
COMMENT
72-
"Preprocess linker script: ${RAW_LINKER_SCRIPT_NAME} -> ${LINKER_SCRIPT_NAME}"
7373
VERBATIM
7474
)
7575

76+
7677
# The job to create the linker script gets attached to the mbed-linker-script target,
7778
# which is then added as a dependency of the MCU target. This ensures the linker script will exist
7879
# by the time we need it.
7980
add_custom_target(mbed-linker-script DEPENDS ${LINKER_SCRIPT_PATH} VERBATIM)
8081
foreach(TARGET ${mbed_baremetal_target} ${mbed_os_target})
8182
add_dependencies(${TARGET} mbed-linker-script)
8283

83-
# Add linker flags to the MCU target to pick up the preprocessed linker script
84-
target_link_options(${TARGET}
84+
# When building the Mbed internal tests, the tests get created before the mbed-os target does. So, the normal logic
85+
# in mbed_set_post_build() to set the linker script does not work. So, we need to instead attach the linker script to
86+
# the mbed-os and mbed-baremetal libraries themselves, so it will get picked up automatically.
87+
# This prevents a custom linker script from being used in STANDALONE mode, but we don't need to do that.
88+
set_target_properties(${TARGET} PROPERTIES LINKER_SCRIPT_PATH ${LINKER_SCRIPT_PATH})
89+
90+
# add linker script only for tests
91+
if(MBED_IS_STANDALONE)
92+
target_link_options(${TARGET}
8593
INTERFACE
8694
"-T" "${LINKER_SCRIPT_PATH}"
87-
)
95+
)
96+
endif()
8897
endforeach()
8998

9099
endfunction(mbed_setup_linker_script)
100+
101+
102+
#
103+
# Change the linker script to a custom supplied script instead of the built in.
104+
# this function is called by mbed_set_post_build(target linker_script)
105+
#
106+
# target: CMake target for Mbed OS
107+
# new_linker_script_path: raw linker script
108+
#
109+
function(mbed_set_custom_linker_script target new_linker_script_path)
110+
111+
set(RAW_LINKER_SCRIPT_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${new_linker_script_path})
112+
set(CUSTOM_LINKER_SCRIPT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${target}.link_spript.ld)
113+
114+
# To avoid path limits on Windows, we create a "response file" and set the path to it as a
115+
# global property. We need this solely to pass the compile definitions to GCC's preprocessor,
116+
# so it can expand any macro definitions in the linker script.
117+
get_property(linker_defs_response_file GLOBAL PROPERTY COMPILE_DEFS_RESPONSE_FILE)
118+
119+
get_filename_component(RAW_LINKER_SCRIPT_NAME ${RAW_LINKER_SCRIPT_PATHS} NAME)
120+
get_filename_component(LINKER_SCRIPT_NAME ${CUSTOM_LINKER_SCRIPT_PATH} NAME)
121+
122+
add_custom_command(
123+
TARGET
124+
${target}
125+
PRE_LINK
126+
COMMAND
127+
${CMAKE_COMMAND} -E echo "Preprocess custom linker script: ${RAW_LINKER_SCRIPT_NAME} -> ${LINKER_SCRIPT_NAME}"
128+
COMMAND
129+
${CMAKE_C_COMPILER} @${linker_defs_response_file}
130+
-E -x assembler-with-cpp
131+
-include ${CMAKE_BINARY_DIR}/mbed-os/mbed-target-config.h
132+
-P ${RAW_LINKER_SCRIPT_PATHS}
133+
-o ${CUSTOM_LINKER_SCRIPT_PATH}
134+
DEPENDS
135+
${RAW_LINKER_SCRIPT_PATHS}
136+
${linker_defs_response_file}
137+
${target_defines_header}
138+
WORKING_DIRECTORY
139+
${CMAKE_CURRENT_SOURCE_DIR}
140+
VERBATIM
141+
)
142+
143+
# Add linker flags to the target to pick up the preprocessed linker script
144+
target_link_options(${target}
145+
PRIVATE
146+
"-T" "${CUSTOM_LINKER_SCRIPT_PATH}"
147+
)
148+
149+
endfunction(mbed_set_custom_linker_script)

tools/cmake/mbed_target_functions.cmake

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,32 @@ endfunction()
126126
#
127127
# Set post build operations
128128
#
129+
# target: the affected target
130+
# 2nd arg: optional, linker script path
131+
#
129132
function(mbed_set_post_build target)
133+
# add linker script. Skip for greentea test code, there the linker script is set in mbed_setup_linker_script()
134+
if (NOT MBED_IS_STANDALONE)
135+
if("${ARGN}" STREQUAL "")
136+
if(TARGET mbed-os)
137+
get_target_property(LINKER_SCRIPT_PATH mbed-os LINKER_SCRIPT_PATH)
138+
target_link_options(${target}
139+
PRIVATE
140+
"-T" "${LINKER_SCRIPT_PATH}"
141+
)
142+
elseif(TARGET mbed-baremetal)
143+
get_target_property(LINKER_SCRIPT_PATH mbed-baremetal LINKER_SCRIPT_PATH)
144+
target_link_options(${target}
145+
PRIVATE
146+
"-T" "${LINKER_SCRIPT_PATH}"
147+
)
148+
endif()
149+
else()
150+
message(STATUS "${target} uses custom linker script ${ARGV2}")
151+
mbed_set_custom_linker_script(${target} ${ARGV2})
152+
endif()
153+
endif()
154+
130155
# The mapfile name includes the top-level target name and the
131156
# executable suffix for all toolchains as CMake hardcodes the name of the
132157
# diagnostic output file for some toolchains.

0 commit comments

Comments
 (0)