Skip to content

Commit

Permalink
llext: use CMake shared library support on Xtensa
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
pillo79 committed Mar 11, 2024
1 parent aa87ed5 commit 37f60ed
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 36 deletions.
1 change: 0 additions & 1 deletion cmake/compiler/gcc/target_xtensa.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ set(LLEXT_APPEND_FLAGS
-fPIC
-nostdlib
-nodefaultlibs
-shared
)
91 changes: 56 additions & 35 deletions cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -5142,15 +5148,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
Expand All @@ -5166,62 +5165,84 @@ 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)

# Ensure shared library support is enabled
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS true)

# 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
get_filename_component(output_name ${llext_pkg_output} NAME)
add_custom_target(${target_name}
COMMENT "Generating ${output_name}"
DEPENDS ${llext_pkg_output}
)
endfunction()

0 comments on commit 37f60ed

Please sign in to comment.