@@ -247,31 +247,38 @@ endfunction()
247247# the static archive further along the line would then supply the registry after
248248# all. Other linkers keep the reference without it.
249249function (executorch_target_link_shared_runtime target_name )
250+ executorch_target_retain_shared_library (${target_name} executorch_shared )
251+ endfunction ()
252+
253+ # Put a shared library on a consumer's link line and keep it there.
254+ #
255+ # A library whose only purpose is to run a static initializer, such as a backend
256+ # or an operator registration library, has no symbol the consumer references
257+ # directly, so the linker is free to drop it from DT_NEEDED. Some linkers do
258+ # exactly that and the initializer never runs, which shows up at runtime as a
259+ # backend or kernel that is missing rather than as a link error.
260+ function (executorch_target_retain_shared_library target_name library_target )
250261 if (NOT EXECUTORCH_BUILD_SHARED)
251262 return ()
252263 endif ()
253264 if (APPLE OR MSVC )
254265 # TARGET_LINKER_FILE rather than TARGET_FILE: on Windows the linker needs
255266 # the import library, not the DLL itself.
256- set (_runtime_flags "SHELL:$<TARGET_LINKER_FILE :executorch_shared >" )
267+ set (_retain_flags "SHELL:$<TARGET_LINKER_FILE :${library_target} >" )
257268 else ()
258- # --no-as-needed keeps the runtime in DT_NEEDED even though no symbol has
259- # been referenced yet at this point on the link line. It is wrapped in
260- # push-state/pop-state rather than closed with an explicit --as-needed so
261- # that whatever policy was in effect before is restored: closing with
262- # --as-needed would leave that in force for everything that follows, and
263- # would drop shared backends whose only purpose is static-init registration.
264- set (_runtime_flags
265- "SHELL:LINKER:--push-state,--no-as-needed $<TARGET_FILE :executorch_shared > LINKER:--pop-state"
269+ # push-state/pop-state rather than closing with an explicit --as-needed:
270+ # that would leave --as-needed in force for everything after it on the line
271+ # and drop the next library that only exists for static-init registration.
272+ set (_retain_flags
273+ "SHELL:LINKER:--push-state,--no-as-needed $<TARGET_FILE :${library_target} > LINKER:--pop-state"
266274 )
267275 endif ()
268- # The generator expression alone does not make the runtime get built first, so
269- # state the build-order dependency explicitly.
270- add_dependencies (${target_name} executorch_shared )
276+ # The generator expression alone does not order the build, so say it outright.
277+ add_dependencies (${target_name} ${library_target} )
271278 set_property (
272279 TARGET ${target_name}
273280 APPEND
274- PROPERTY LINK_OPTIONS "${_runtime_flags } "
281+ PROPERTY LINK_OPTIONS "${_retain_flags } "
275282 )
276283endfunction ()
277284
0 commit comments