@@ -15,25 +15,134 @@ function(__ldgen_add_fragment_files fragment_files)
1515 idf_build_set_property(__LDGEN_FRAGMENT_FILES "${_fragment_files} " APPEND )
1616endfunction ()
1717
18- # __ldgen_add_component
19- #
20- # Generate sections info for specified target to be used in linker script generation
21- function (__ldgen_add_component component_lib)
22- idf_build_set_property(__LDGEN_LIBRARIES "$<TARGET_FILE:${component_lib} >" APPEND )
23- idf_build_set_property(__LDGEN_DEPENDS ${component_lib} APPEND )
24- endfunction ()
25-
2618# __ldgen_process_template
2719#
2820# Passes a linker script template to the linker script generation tool for
29- # processing
21+ # processing. This internal function is called from the public "target_linker_script" function.
22+ # It simply records the template and output file names. The actual linker script generation
23+ # target is created later by the __ldgen_create_target function.
24+ #
3025function (__ldgen_process_template template output )
26+ idf_build_set_property(__LDGEN_TEMPLATES "${template} " APPEND )
27+ idf_build_set_property(__LDGEN_OUTPUTS "${output} " APPEND )
28+ endfunction ()
29+
30+ # __ldgen_get_lib_deps_of_target
31+ #
32+ # Helper function to get the list of libraries that a target depends on,
33+ # recursively, and append it to the out_list. The 'target' argument is
34+ # typically an executable.
35+ #
36+ function (__ldgen_get_lib_deps_of_target target out_list_var)
37+ set (out_list ${${out_list_var} })
38+ if (target IN_LIST out_list)
39+ # This target is already in the list, meaning that it has been
40+ # processed already. Bail out.
41+ return ()
42+ endif ()
43+
44+ # The target is not in the list yet. Add it, and then add all its dependencies.
45+ list (APPEND out_list ${target} )
46+ set (${out_list_var} ${out_list} PARENT_SCOPE)
47+
48+ get_target_property (target_deps ${target} LINK_LIBRARIES )
49+ if (NOT target_deps)
50+ # This target has no dependencies, nothing to do.
51+ return ()
52+ endif ()
53+
54+ foreach (dep ${target_deps} )
55+ if (dep IN_LIST out_list)
56+ # This dependency has already been processed, skip it.
57+ continue ()
58+ endif ()
59+
60+ if (NOT TARGET ${dep} )
61+ # LINK_LIBRARIES may contain various non-library-related linker flags
62+ # (-u, -L, -l, etc.), skip them.
63+ if (dep MATCHES "^-" OR dep MATCHES "^\:\: " )
64+ continue ()
65+ endif ()
66+
67+ # If the dependency is not a target, it may be a library. Add it to the list.
68+ list (APPEND out_list ${dep} )
69+ else ()
70+ # Recursively add the dependencies of this target.
71+ __ldgen_get_lib_deps_of_target(${dep} out_list)
72+ endif ()
73+ endforeach ()
74+
75+ set (${out_list_var} ${out_list} PARENT_SCOPE)
76+ endfunction ()
77+
78+
79+ # __ldgen_create_target
80+ #
81+ # Internal function which creates a custom target for the linker script generation tool.
82+ # This function is called from the public idf_build_executable function.
83+ #
84+ function (__ldgen_create_target exe_target)
3185 idf_build_get_property(idf_target IDF_TARGET)
3286 idf_build_get_property(idf_path IDF_PATH)
87+ idf_build_get_property(templates __LDGEN_TEMPLATES)
88+ idf_build_get_property(outputs __LDGEN_OUTPUTS)
89+
90+ if (NOT templates)
91+ # No templates were passed to ldgen, nothing to do.
92+ return ()
93+ endif ()
94+
95+ list (LENGTH templates num_templates)
96+ if (NOT num_templates EQUAL 1)
97+ # This limitation can be removed, if necessary, by looping over the list of templates
98+ # and creating a target for each one of them.
99+ # However, this is not needed in IDF for now, hence the simpler implementation.
100+ message (FATAL_ERROR "Only one template file can be passed to __ldgen_process, "
101+ "got ${num_templates} : ${templates} " )
102+ endif ()
103+
104+ list (GET templates 0 template)
105+ list (GET outputs 0 output )
106+
107+ # Collect all the libraries that the executable depends on, recursively.
108+ # This is needed to pass the list of libraries to the linker script generator tool.
109+ set (ldgen_libraries)
110+ __ldgen_get_lib_deps_of_target(${exe_target} ldgen_libraries)
111+ list (REMOVE_ITEM ldgen_libraries ${exe_target} )
112+ set (ldgen_deps)
113+ foreach (lib ${ldgen_libraries} )
114+ if (TARGET ${lib} )
115+ get_target_property (lib_type ${lib} TYPE )
116+ if (lib_type STREQUAL "INTERFACE_LIBRARY" )
117+ continue ()
118+ endif ()
119+ list (APPEND ldgen_libraries_expr "$<TARGET_FILE:${lib} >" )
120+ list (APPEND ldgen_deps ${lib} )
121+ else ()
122+ # Here we have two cases:
123+ #
124+ # 1. ${lib} is actually a target, but the target is outside the current scope.
125+ # This is the case for imported library targets (such as those added by
126+ # add_prebuilt_library), since by default imported targets are not
127+ # visible outside the directory where they are defined, unless they are
128+ # marked as GLOBAL.
129+ # This case covers many (but not all) of IDF's prebuilt libraries.
130+ #
131+ # 2. ${lib} is the name of a library, which the linker can find in its built-in
132+ # or specified search paths.
133+ # This is the case for toolchain libraries (m, c, gcc, stdc++) as well
134+ # as for some prebuilt libraries which have been added using `-lname -Lpath`
135+ # style flags.
136+ #
137+ # If we can successfully find the absolute path of each such library, this
138+ # will allow us to pass them to ldgen, enabling us to place functions from
139+ # prebuilt libraries to specific sections in the linker script (IDF-12049)
140+ endif ()
141+ endforeach ()
142+ list (JOIN ldgen_libraries_expr "\n " ldgen_libraries_str)
33143
34144 idf_build_get_property(build_dir BUILD_DIR)
35- idf_build_get_property(ldgen_libraries __LDGEN_LIBRARIES GENERATOR_EXPRESSION)
36- file (GENERATE OUTPUT ${build_dir} /ldgen_libraries.in CONTENT $<JOIN:${ldgen_libraries} ,\n>)
145+ file (WRITE ${build_dir} /ldgen_libraries.in "${ldgen_libraries_str} " )
37146 file (GENERATE OUTPUT ${build_dir} /ldgen_libraries INPUT ${build_dir} /ldgen_libraries.in)
38147
39148 set_property (DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR} "
@@ -42,7 +151,7 @@ function(__ldgen_process_template template output)
42151 "${build_dir} /ldgen_libraries" )
43152
44153 idf_build_get_property(ldgen_fragment_files __LDGEN_FRAGMENT_FILES GENERATOR_EXPRESSION)
45- idf_build_get_property(ldgen_depends __LDGEN_DEPENDS GENERATOR_EXPRESSION)
154+
46155 # Create command to invoke the linker script generator tool.
47156 idf_build_get_property(sdkconfig SDKCONFIG)
48157 idf_build_get_property(root_kconfig __ROOT_KCONFIG)
@@ -69,12 +178,15 @@ function(__ldgen_process_template template output)
69178 --libraries-file "${build_dir} /ldgen_libraries"
70179 --objdump "${CMAKE_OBJDUMP} "
71180 ${ldgen_check}
72- DEPENDS ${template} ${ldgen_fragment_files} ${ldgen_depends } ${SDKCONFIG}
181+ DEPENDS ${template} ${ldgen_fragment_files} ${ldgen_deps } ${SDKCONFIG}
73182 VERBATIM
74183 )
75184
185+ # The executable depends on the output of the ldgen command.
76186 get_filename_component (_name ${output} NAME )
77187 add_custom_target (__ldgen_output_${_name} DEPENDS ${output} )
78- add_dependencies (__idf_build_target __ldgen_output_${_name} )
188+ add_dependencies (${exe_target} __ldgen_output_${_name} )
189+
190+ # Add the output of the ldgen command to the list of link dependencies.
79191 idf_build_set_property(__LINK_DEPENDS ${output} APPEND )
80192endfunction ()
0 commit comments