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:
parent
f61b003b07
commit
1e47c64266
2 changed files with 68 additions and 40 deletions
|
@ -17,5 +17,4 @@ set(LLEXT_APPEND_FLAGS
|
||||||
-fPIC
|
-fPIC
|
||||||
-nostdlib
|
-nostdlib
|
||||||
-nodefaultlibs
|
-nodefaultlibs
|
||||||
-shared
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -5099,6 +5099,12 @@ endmacro()
|
||||||
# loadable extensions (llexts).
|
# 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.
|
# 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
|
# 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
|
# The C_FLAGS argument can be used to pass additional compiler flags to the
|
||||||
# compilation of this particular llext.
|
# 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:
|
# Example usage:
|
||||||
# add_llext_target(hello_world
|
# add_llext_target(hello_world
|
||||||
# OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext
|
# 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")
|
message(FATAL_ERROR "add_llext_target: CONFIG_LLEXT must be enabled")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Output file must be provided
|
# Source and output files must be provided
|
||||||
if(NOT LLEXT_OUTPUT)
|
zephyr_check_arguments_required_all("add_llext_target" LLEXT OUTPUT SOURCES)
|
||||||
message(FATAL_ERROR "add_llext_target: OUTPUT argument must be provided")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Source list length must currently be 1
|
# Source list length must currently be 1
|
||||||
list(LENGTH LLEXT_SOURCES source_count)
|
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")
|
message(FATAL_ERROR "add_llext_target: only one source file is supported")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(output_file ${LLEXT_OUTPUT})
|
set(llext_pkg_output ${LLEXT_OUTPUT})
|
||||||
set(source_file ${LLEXT_SOURCES})
|
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
|
# Convert the LLEXT_REMOVE_FLAGS list to a regular expression, and use it to
|
||||||
# filter out these flags from the Zephyr target settings
|
# 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}>"
|
"$<FILTER:${zephyr_flags},EXCLUDE,${llext_remove_flags_regexp}>"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Compile the source file to an object file using current Zephyr settings
|
# Compile the source file using current Zephyr settings but a different
|
||||||
# but a different set of flags
|
# set of flags.
|
||||||
add_library(${target_name}_lib OBJECT ${source_file})
|
# This is currently arch-specific since the ARM loader for .llext files
|
||||||
target_compile_definitions(${target_name}_lib PRIVATE
|
# 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_PROPERTY:zephyr_interface,INTERFACE_COMPILE_DEFINITIONS>
|
||||||
)
|
)
|
||||||
target_compile_options(${target_name}_lib PRIVATE
|
target_compile_options(${llext_lib_target} PRIVATE
|
||||||
${zephyr_filtered_flags}
|
${zephyr_filtered_flags}
|
||||||
${LLEXT_APPEND_FLAGS}
|
${LLEXT_APPEND_FLAGS}
|
||||||
${LLEXT_C_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_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>
|
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
|
||||||
)
|
)
|
||||||
add_dependencies(${target_name}_lib
|
add_dependencies(${llext_lib_target}
|
||||||
zephyr_interface
|
zephyr_interface
|
||||||
zephyr_generated_headers
|
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)
|
if(CONFIG_ARM)
|
||||||
|
|
||||||
# No conversion required, simply copy the object file
|
# No packaging required, simply copy the object file
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${output_file}
|
OUTPUT ${llext_pkg_output}
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:${target_name}_lib> ${output_file}
|
COMMAND ${CMAKE_COMMAND} -E copy ${llext_lib_output} ${llext_pkg_output}
|
||||||
DEPENDS ${target_name}_lib $<TARGET_OBJECTS:${target_name}_lib>
|
DEPENDS ${llext_lib_target} ${llext_lib_output}
|
||||||
)
|
)
|
||||||
|
|
||||||
elseif(CONFIG_XTENSA)
|
elseif(CONFIG_XTENSA)
|
||||||
|
|
||||||
# Generate an intermediate file name
|
# Need to strip the shared library of some sections
|
||||||
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
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${output_file}
|
OUTPUT ${llext_pkg_output}
|
||||||
BYPRODUCTS ${pre_output_file}
|
|
||||||
COMMAND ${CMAKE_C_COMPILER} ${LLEXT_APPEND_FLAGS}
|
|
||||||
-o ${pre_output_file}
|
|
||||||
$<TARGET_OBJECTS:${target_name}_lib>
|
|
||||||
COMMAND $<TARGET_PROPERTY:bintools,strip_command>
|
COMMAND $<TARGET_PROPERTY:bintools,strip_command>
|
||||||
$<TARGET_PROPERTY:bintools,strip_flag>
|
$<TARGET_PROPERTY:bintools,strip_flag>
|
||||||
$<TARGET_PROPERTY:bintools,strip_flag_remove_section>.xt.*
|
$<TARGET_PROPERTY:bintools,strip_flag_remove_section>.xt.*
|
||||||
$<TARGET_PROPERTY:bintools,strip_flag_infile>${pre_output_file}
|
$<TARGET_PROPERTY:bintools,strip_flag_infile>${llext_lib_output}
|
||||||
$<TARGET_PROPERTY:bintools,strip_flag_outfile>${output_file}
|
$<TARGET_PROPERTY:bintools,strip_flag_outfile>${llext_pkg_output}
|
||||||
$<TARGET_PROPERTY:bintools,strip_flag_final>
|
$<TARGET_PROPERTY:bintools,strip_flag_final>
|
||||||
DEPENDS ${target_name}_lib $<TARGET_OBJECTS:${target_name}_lib>
|
DEPENDS ${llext_lib_target} ${llext_lib_output}
|
||||||
)
|
)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "add_llext_target: unsupported architecture")
|
message(FATAL_ERROR "add_llext_target: unsupported architecture")
|
||||||
endif()
|
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()
|
endfunction()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue