1# SPDX-License-Identifier: Apache-2.0
2set_property(TARGET linker PROPERTY devices_start_symbol "_device_list_start")
3
4find_package(GnuLd REQUIRED)
5set(CMAKE_LINKER ${GNULD_LINKER})
6
7set_ifndef(LINKERFLAGPREFIX -Wl)
8
9if((${CMAKE_LINKER} STREQUAL "${CROSS_COMPILE}ld.bfd") OR
10   ${GNULD_LINKER_IS_BFD})
11  # ld.bfd was found so let's explicitly use that for linking, see #32237
12  list(APPEND TOOLCHAIN_LD_FLAGS -fuse-ld=bfd)
13  list(APPEND CMAKE_REQUIRED_FLAGS -fuse-ld=bfd)
14  string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
15endif()
16
17# Run $LINKER_SCRIPT file through the C preprocessor, producing ${linker_script_gen}
18# NOTE: ${linker_script_gen} will be produced at build-time; not at configure-time
19macro(configure_linker_script linker_script_gen linker_pass_define)
20  set(extra_dependencies ${ARGN})
21  set(cmake_linker_script_settings
22      ${PROJECT_BINARY_DIR}/include/generated/ld_script_settings_${linker_pass_define}.cmake
23  )
24
25  if(CONFIG_CMAKE_LINKER_GENERATOR)
26    file(GENERATE OUTPUT ${cmake_linker_script_settings} CONTENT
27         "set(FORMAT \"$<TARGET_PROPERTY:linker,FORMAT>\" CACHE INTERNAL \"\")\n
28          set(ENTRY \"$<TARGET_PROPERTY:linker,ENTRY>\" CACHE INTERNAL \"\")\n
29          set(MEMORY_REGIONS \"$<TARGET_PROPERTY:linker,MEMORY_REGIONS>\" CACHE INTERNAL \"\")\n
30          set(GROUPS \"$<TARGET_PROPERTY:linker,GROUPS>\" CACHE INTERNAL \"\")\n
31          set(SECTIONS \"$<TARGET_PROPERTY:linker,SECTIONS>\" CACHE INTERNAL \"\")\n
32          set(SECTION_SETTINGS \"$<TARGET_PROPERTY:linker,SECTION_SETTINGS>\" CACHE INTERNAL \"\")\n
33          set(SYMBOLS \"$<TARGET_PROPERTY:linker,SYMBOLS>\" CACHE INTERNAL \"\")\n
34         "
35    )
36    add_custom_command(
37      OUTPUT ${linker_script_gen}
38      COMMAND ${CMAKE_COMMAND}
39        -C ${DEVICE_API_LINKER_SECTIONS_CMAKE}
40        -C ${cmake_linker_script_settings}
41        -DPASS="${linker_pass_define}"
42        -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/${linker_script_gen}
43        -P ${ZEPHYR_BASE}/cmake/linker/ld/ld_script.cmake
44      DEPENDS ${DEVICE_API_LD_TARGET}
45    )
46  else()
47    set(template_script_defines ${linker_pass_define})
48    list(TRANSFORM template_script_defines PREPEND "-D")
49
50    # Only Ninja and Makefile generators support DEPFILE.
51    if((CMAKE_GENERATOR STREQUAL "Ninja")
52       OR (CMAKE_GENERATOR MATCHES "Makefiles")
53    )
54      set(linker_script_dep DEPFILE ${PROJECT_BINARY_DIR}/${linker_script_gen}.dep)
55    else()
56      # TODO: How would the linker script dependencies work for non-linker
57      # script generators.
58      message(STATUS "Warning; this generator is not well supported. The
59    Linker script may not be regenerated when it should.")
60      set(linker_script_dep "")
61    endif()
62
63    zephyr_get_include_directories_for_lang(C current_includes)
64    if(DEFINED SOC_LINKER_SCRIPT)
65      cmake_path(GET SOC_LINKER_SCRIPT PARENT_PATH soc_linker_script_includes)
66      set(soc_linker_script_includes -I${soc_linker_script_includes})
67    endif()
68
69    add_custom_command(
70      OUTPUT ${linker_script_gen}
71      DEPENDS
72      ${LINKER_SCRIPT}
73      ${AUTOCONF_H}
74      ${extra_dependencies}
75      # NB: 'linker_script_dep' will use a keyword that ends 'DEPENDS'
76      ${linker_script_dep}
77      COMMAND ${CMAKE_C_COMPILER}
78      -x assembler-with-cpp
79      ${NOSYSDEF_CFLAG}
80      -MD -MF ${linker_script_gen}.dep -MT ${linker_script_gen}
81      -D_LINKER
82      -D_ASMLANGUAGE
83      -D__GCC_LINKER_CMD__
84      -imacros ${AUTOCONF_H}
85      ${current_includes}
86      ${soc_linker_script_includes}
87      ${template_script_defines}
88      -E ${LINKER_SCRIPT}
89      -P # Prevent generation of debug `#line' directives.
90      -o ${linker_script_gen}
91      VERBATIM
92      WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
93      COMMAND_EXPAND_LISTS
94    )
95  endif()
96endmacro()
97
98# Force symbols to be entered in the output file as undefined symbols
99function(toolchain_ld_force_undefined_symbols)
100  foreach(symbol ${ARGN})
101    zephyr_link_libraries(${LINKERFLAGPREFIX},-u,${symbol})
102  endforeach()
103endfunction()
104
105# Link a target to given libraries with toolchain-specific argument order
106#
107# Usage:
108#   toolchain_ld_link_elf(
109#     TARGET_ELF             <target_elf>
110#     OUTPUT_MAP             <output_map_file_of_target>
111#     LIBRARIES_PRE_SCRIPT   [libraries_pre_script]
112#     LINKER_SCRIPT          <linker_script>
113#     LIBRARIES_POST_SCRIPT  [libraries_post_script]
114#     DEPENDENCIES           [dependencies]
115#   )
116function(toolchain_ld_link_elf)
117  cmake_parse_arguments(
118    TOOLCHAIN_LD_LINK_ELF                                     # prefix of output variables
119    ""                                                        # list of names of the boolean arguments
120    "TARGET_ELF;OUTPUT_MAP;LINKER_SCRIPT"                     # list of names of scalar arguments
121    "LIBRARIES_PRE_SCRIPT;LIBRARIES_POST_SCRIPT;DEPENDENCIES" # list of names of list arguments
122    ${ARGN}                                                   # input args to parse
123  )
124
125  target_link_libraries(
126    ${TOOLCHAIN_LD_LINK_ELF_TARGET_ELF}
127    ${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_PRE_SCRIPT}
128    ${TOPT}
129    ${TOOLCHAIN_LD_LINK_ELF_LINKER_SCRIPT}
130    ${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_POST_SCRIPT}
131
132    ${LINKERFLAGPREFIX},-Map=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP}
133    ${LINKERFLAGPREFIX},--whole-archive
134    ${WHOLE_ARCHIVE_LIBS}
135    ${LINKERFLAGPREFIX},--no-whole-archive
136    ${NO_WHOLE_ARCHIVE_LIBS}
137    $<TARGET_OBJECTS:${OFFSETS_LIB}>
138    -L${PROJECT_BINARY_DIR}
139
140    ${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES}
141  )
142endfunction(toolchain_ld_link_elf)
143
144# Function for finalizing link setup after Zephyr configuration has completed.
145#
146# This function will generate the correct CMAKE_C_LINK_EXECUTABLE / CMAKE_CXX_LINK_EXECUTABLE
147# rule to ensure that standard c and runtime libraries are correctly placed
148# and the end of link invocation and doesn't appear in the middle of the link
149# command invocation.
150macro(toolchain_linker_finalize)
151  get_property(zephyr_std_libs TARGET linker PROPERTY lib_include_dir)
152  get_property(link_order TARGET linker PROPERTY link_order_library)
153  foreach(lib ${link_order})
154    get_property(link_flag TARGET linker PROPERTY ${lib}_library)
155    list(APPEND zephyr_std_libs "${link_flag}")
156  endforeach()
157  string(REPLACE ";" " " zephyr_std_libs "${zephyr_std_libs}")
158
159  set(link_libraries "<OBJECTS> -o <TARGET> <LINK_LIBRARIES> ${zephyr_std_libs}")
160  set(common_link "<LINK_FLAGS> ${link_libraries}")
161
162  set(CMAKE_ASM_LINK_EXECUTABLE "<CMAKE_ASM_COMPILER> <FLAGS> <CMAKE_ASM_LINK_FLAGS> ${common_link}")
163  set(CMAKE_C_LINK_EXECUTABLE   "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> ${common_link}")
164
165  set(cpp_link "${common_link}")
166  if(NOT "${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "host")
167    if(CONFIG_CPP_EXCEPTIONS AND LIBGCC_DIR)
168      # When building with C++ Exceptions, it is important that crtbegin and crtend
169      # are linked at specific locations.
170      set(cpp_link "<LINK_FLAGS> ${LIBGCC_DIR}/crtbegin.o ${link_libraries} ${LIBGCC_DIR}/crtend.o")
171    endif()
172  endif()
173  set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> ${cpp_link}")
174endmacro()
175
176# Load toolchain_ld-family macros
177include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_relocation.cmake)
178include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_configure.cmake)
179