diff --git a/tools/cmake/mbed_set_linker_script.cmake b/tools/cmake/mbed_set_linker_script.cmake index a313e0c..8355f3b 100644 --- a/tools/cmake/mbed_set_linker_script.cmake +++ b/tools/cmake/mbed_set_linker_script.cmake @@ -56,6 +56,8 @@ 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 @@ -68,11 +70,10 @@ ${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. @@ -80,11 +81,69 @@ 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) diff --git a/tools/cmake/mbed_target_functions.cmake b/tools/cmake/mbed_target_functions.cmake index 77e0678..1e861f0 100644 --- a/tools/cmake/mbed_target_functions.cmake +++ b/tools/cmake/mbed_target_functions.cmake @@ -126,7 +126,32 @@ # # 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.