diff --git a/cmake/compiler/gcc/target_xtensa.cmake b/cmake/compiler/gcc/target_xtensa.cmake index 177830427db..5321204c2df 100644 --- a/cmake/compiler/gcc/target_xtensa.cmake +++ b/cmake/compiler/gcc/target_xtensa.cmake @@ -17,5 +17,4 @@ set(LLEXT_APPEND_FLAGS -fPIC -nostdlib -nodefaultlibs - -shared ) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 1444229047f..8a3b065821a 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -5099,6 +5099,12 @@ endmacro() # loadable extensions (llexts). # +# Usage: +# add_llext_target( +# OUTPUT +# SOURCES +# ) +# # 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 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) "$" ) - # 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 $) + + elseif(CONFIG_XTENSA) + + # Create a shared library + add_library(${llext_lib_target} SHARED ${source_file}) + set(llext_lib_output $) + + # 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_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_include_directories(${target_name}_lib SYSTEM PUBLIC + target_include_directories(${llext_lib_target} SYSTEM PUBLIC $ ) - 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 $ ${output_file} - DEPENDS ${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} - $ + OUTPUT ${llext_pkg_output} COMMAND $ $ $.xt.* - $${pre_output_file} - $${output_file} + $${llext_lib_output} + $${llext_pkg_output} $ - DEPENDS ${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()