llext: use CMake shared library support on Xtensa

This change reworks the Xtensa support in llext to use CMake's native
shared library support, instead of manually running "gcc -shared".

This change minimizes the differences in llext handling by defining
appropriate CMake targets for the different architectures.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This commit is contained in:
Luca Burelli 2024-01-22 18:12:21 +01:00 committed by Carles Cufí
parent f61b003b07
commit 1e47c64266
2 changed files with 68 additions and 40 deletions

View file

@ -17,5 +17,4 @@ set(LLEXT_APPEND_FLAGS
-fPIC
-nostdlib
-nodefaultlibs
-shared
)

View file

@ -5099,6 +5099,12 @@ endmacro()
# loadable extensions (llexts).
#
# Usage:
# add_llext_target(<target_name>
# OUTPUT <output_file>
# SOURCES <source_file>
# )
#
# Add a custom target that compiles a single source file to a .llext file.
#
# Output and source files must be specified using the OUTPUT and SOURCES
@ -5112,6 +5118,14 @@ endmacro()
# The C_FLAGS argument can be used to pass additional compiler flags to the
# compilation of this particular llext.
#
# The following custom properties of <target_name> are defined and can be
# retrieved using the get_target_property() function:
#
# - lib_target Target name for the source compilation and/or link step.
# - lib_output The binary file resulting from compilation and/or
# linking steps.
# - pkg_output The final .llext file.
#
# Example usage:
# add_llext_target(hello_world
# OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext
@ -5131,10 +5145,8 @@ function(add_llext_target target_name)
message(FATAL_ERROR "add_llext_target: CONFIG_LLEXT must be enabled")
endif()
# Output file must be provided
if(NOT LLEXT_OUTPUT)
message(FATAL_ERROR "add_llext_target: OUTPUT argument must be provided")
endif()
# Source and output files must be provided
zephyr_check_arguments_required_all("add_llext_target" LLEXT OUTPUT SOURCES)
# Source list length must currently be 1
list(LENGTH LLEXT_SOURCES source_count)
@ -5142,15 +5154,8 @@ function(add_llext_target target_name)
message(FATAL_ERROR "add_llext_target: only one source file is supported")
endif()
set(output_file ${LLEXT_OUTPUT})
set(llext_pkg_output ${LLEXT_OUTPUT})
set(source_file ${LLEXT_SOURCES})
get_filename_component(output_name ${output_file} NAME)
# Add user-visible target and dependency
add_custom_target(${target_name}
COMMENT "Compiling ${output_name}"
DEPENDS ${output_file}
)
# Convert the LLEXT_REMOVE_FLAGS list to a regular expression, and use it to
# filter out these flags from the Zephyr target settings
@ -5166,62 +5171,86 @@ function(add_llext_target target_name)
"$<FILTER:${zephyr_flags},EXCLUDE,${llext_remove_flags_regexp}>"
)
# Compile the source file to an object file using current Zephyr settings
# but a different set of flags
add_library(${target_name}_lib OBJECT ${source_file})
target_compile_definitions(${target_name}_lib PRIVATE
# Compile the source file using current Zephyr settings but a different
# set of flags.
# This is currently arch-specific since the ARM loader for .llext files
# expects object file format, while the Xtensa one uses shared libraries.
set(llext_lib_target ${target_name}_llext_lib)
if(CONFIG_ARM)
# Create an object library to compile the source file
add_library(${llext_lib_target} OBJECT ${source_file})
set(llext_lib_output $<TARGET_OBJECTS:${llext_lib_target}>)
elseif(CONFIG_XTENSA)
# Create a shared library
add_library(${llext_lib_target} SHARED ${source_file})
set(llext_lib_output $<TARGET_FILE:${llext_lib_target}>)
# Add the llext flags to the linking step as well
target_link_options(${llext_lib_target} PRIVATE
${LLEXT_APPEND_FLAGS}
)
endif()
target_compile_definitions(${llext_lib_target} PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_COMPILE_DEFINITIONS>
)
target_compile_options(${target_name}_lib PRIVATE
target_compile_options(${llext_lib_target} PRIVATE
${zephyr_filtered_flags}
${LLEXT_APPEND_FLAGS}
${LLEXT_C_FLAGS}
)
target_include_directories(${target_name}_lib PRIVATE
target_include_directories(${llext_lib_target} PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_INCLUDE_DIRECTORIES>
)
target_include_directories(${target_name}_lib SYSTEM PUBLIC
target_include_directories(${llext_lib_target} SYSTEM PUBLIC
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
)
add_dependencies(${target_name}_lib
add_dependencies(${llext_lib_target}
zephyr_interface
zephyr_generated_headers
)
# Arch-specific conversion of the object file to an llext
# Arch-specific packaging of the built binary file into an .llext file
if(CONFIG_ARM)
# No conversion required, simply copy the object file
# No packaging required, simply copy the object file
add_custom_command(
OUTPUT ${output_file}
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:${target_name}_lib> ${output_file}
DEPENDS ${target_name}_lib $<TARGET_OBJECTS:${target_name}_lib>
OUTPUT ${llext_pkg_output}
COMMAND ${CMAKE_COMMAND} -E copy ${llext_lib_output} ${llext_pkg_output}
DEPENDS ${llext_lib_target} ${llext_lib_output}
)
elseif(CONFIG_XTENSA)
# Generate an intermediate file name
get_filename_component(output_dir ${output_file} DIRECTORY)
get_filename_component(output_name_we ${output_file} NAME_WE)
set(pre_output_file ${output_dir}/${output_name_we}.pre.llext)
# Need to convert the object file to a shared library, then strip some sections
# Need to strip the shared library of some sections
add_custom_command(
OUTPUT ${output_file}
BYPRODUCTS ${pre_output_file}
COMMAND ${CMAKE_C_COMPILER} ${LLEXT_APPEND_FLAGS}
-o ${pre_output_file}
$<TARGET_OBJECTS:${target_name}_lib>
OUTPUT ${llext_pkg_output}
COMMAND $<TARGET_PROPERTY:bintools,strip_command>
$<TARGET_PROPERTY:bintools,strip_flag>
$<TARGET_PROPERTY:bintools,strip_flag_remove_section>.xt.*
$<TARGET_PROPERTY:bintools,strip_flag_infile>${pre_output_file}
$<TARGET_PROPERTY:bintools,strip_flag_outfile>${output_file}
$<TARGET_PROPERTY:bintools,strip_flag_infile>${llext_lib_output}
$<TARGET_PROPERTY:bintools,strip_flag_outfile>${llext_pkg_output}
$<TARGET_PROPERTY:bintools,strip_flag_final>
DEPENDS ${target_name}_lib $<TARGET_OBJECTS:${target_name}_lib>
DEPENDS ${llext_lib_target} ${llext_lib_output}
)
else()
message(FATAL_ERROR "add_llext_target: unsupported architecture")
endif()
# Add user-visible target and dependency, and fill in properties
get_filename_component(output_name ${llext_pkg_output} NAME)
add_custom_target(${target_name}
COMMENT "Generating ${output_name}"
DEPENDS ${llext_pkg_output}
)
set_target_properties(${target_name} PROPERTIES
lib_target ${llext_lib_target}
lib_output ${llext_lib_output}
pkg_output ${llext_pkg_output}
)
endfunction()