Skip to content

Commit

Permalink
add custom linker script (ARMmbed#103)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
JojoS62 authored Nov 28, 2022
1 parent 310aac3 commit 9d9ba58
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 5 deletions.
69 changes: 64 additions & 5 deletions tools/cmake/mbed_set_linker_script.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ function(mbed_setup_linker_script mbed_os_target mbed_baremetal_target target_de
OUTPUT
${LINKER_SCRIPT_PATH}
PRE_LINK
COMMAND
${CMAKE_COMMAND} -E echo "Preprocess linker script: ${RAW_LINKER_SCRIPT_NAME} -> ${LINKER_SCRIPT_NAME}"
COMMAND
${CMAKE_C_COMPILER} @${linker_defs_response_file}
-E -x assembler-with-cpp
Expand All @@ -68,23 +70,80 @@ function(mbed_setup_linker_script mbed_os_target mbed_baremetal_target target_de
${target_defines_header}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
COMMENT
"Preprocess linker script: ${RAW_LINKER_SCRIPT_NAME} -> ${LINKER_SCRIPT_NAME}"
VERBATIM
)


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

# Add linker flags to the MCU target to pick up the preprocessed linker script
target_link_options(${TARGET}
# When building the Mbed internal tests, the tests get created before the mbed-os target does. So, the normal logic
# in mbed_set_post_build() to set the linker script does not work. So, we need to instead attach the linker script to
# the mbed-os and mbed-baremetal libraries themselves, so it will get picked up automatically.
# This prevents a custom linker script from being used in STANDALONE mode, but we don't need to do that.
set_target_properties(${TARGET} PROPERTIES LINKER_SCRIPT_PATH ${LINKER_SCRIPT_PATH})

# add linker script only for tests
if(MBED_IS_STANDALONE)
target_link_options(${TARGET}
INTERFACE
"-T" "${LINKER_SCRIPT_PATH}"
)
)
endif()
endforeach()

endfunction(mbed_setup_linker_script)


#
# Change the linker script to a custom supplied script instead of the built in.
# this function is called by mbed_set_post_build(target linker_script)
#
# target: CMake target for Mbed OS
# new_linker_script_path: raw linker script
#
function(mbed_set_custom_linker_script target new_linker_script_path)

set(RAW_LINKER_SCRIPT_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${new_linker_script_path})
set(CUSTOM_LINKER_SCRIPT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${target}.link_spript.ld)

# To avoid path limits on Windows, we create a "response file" and set the path to it as a
# global property. We need this solely to pass the compile definitions to GCC's preprocessor,
# so it can expand any macro definitions in the linker script.
get_property(linker_defs_response_file GLOBAL PROPERTY COMPILE_DEFS_RESPONSE_FILE)

get_filename_component(RAW_LINKER_SCRIPT_NAME ${RAW_LINKER_SCRIPT_PATHS} NAME)
get_filename_component(LINKER_SCRIPT_NAME ${CUSTOM_LINKER_SCRIPT_PATH} NAME)

add_custom_command(
TARGET
${target}
PRE_LINK
COMMAND
${CMAKE_COMMAND} -E echo "Preprocess custom linker script: ${RAW_LINKER_SCRIPT_NAME} -> ${LINKER_SCRIPT_NAME}"
COMMAND
${CMAKE_C_COMPILER} @${linker_defs_response_file}
-E -x assembler-with-cpp
-include ${CMAKE_BINARY_DIR}/mbed-os/mbed-target-config.h
-P ${RAW_LINKER_SCRIPT_PATHS}
-o ${CUSTOM_LINKER_SCRIPT_PATH}
DEPENDS
${RAW_LINKER_SCRIPT_PATHS}
${linker_defs_response_file}
${target_defines_header}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)

# Add linker flags to the target to pick up the preprocessed linker script
target_link_options(${target}
PRIVATE
"-T" "${CUSTOM_LINKER_SCRIPT_PATH}"
)

endfunction(mbed_set_custom_linker_script)
25 changes: 25 additions & 0 deletions tools/cmake/mbed_target_functions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,32 @@ endfunction()
#
# Set post build operations
#
# target: the affected target
# 2nd arg: optional, linker script path
#
function(mbed_set_post_build target)
# add linker script. Skip for greentea test code, there the linker script is set in mbed_setup_linker_script()
if (NOT MBED_IS_STANDALONE)
if("${ARGN}" STREQUAL "")
if(TARGET mbed-os)
get_target_property(LINKER_SCRIPT_PATH mbed-os LINKER_SCRIPT_PATH)
target_link_options(${target}
PRIVATE
"-T" "${LINKER_SCRIPT_PATH}"
)
elseif(TARGET mbed-baremetal)
get_target_property(LINKER_SCRIPT_PATH mbed-baremetal LINKER_SCRIPT_PATH)
target_link_options(${target}
PRIVATE
"-T" "${LINKER_SCRIPT_PATH}"
)
endif()
else()
message(STATUS "${target} uses custom linker script ${ARGV2}")
mbed_set_custom_linker_script(${target} ${ARGV2})
endif()
endif()

# The mapfile name includes the top-level target name and the
# executable suffix for all toolchains as CMake hardcodes the name of the
# diagnostic output file for some toolchains.
Expand Down

0 comments on commit 9d9ba58

Please sign in to comment.