llext: define add_llext_target() for llext compilation

This patch defines a generic function that encapsulates all the
architecture-specific machinery needed to compile llexts from source
files. Current tests are updated to use this function.

Output and source files must be specified using the OUTPUT and SOURCES
arguments. Only one source file is currently supported.

Arch-specific flags will be added automatically. The C_FLAGS argument
can be used to pass additional compiler flags to the compilation of
the source file.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This commit is contained in:
Luca Burelli 2024-01-12 11:06:28 +01:00 committed by Henrik Brix Andersen
commit 0747cd3358
2 changed files with 97 additions and 27 deletions

View file

@ -34,6 +34,7 @@ include(CheckCXXCompilerFlag)
# 5. Zephyr linker functions
# 5.1. zephyr_linker*
# 6 Function helper macros
# 7 Linkable loadable extensions (llext)
########################################################
# 1. Zephyr-aware extensions
@ -4792,3 +4793,92 @@ macro(zephyr_check_flags_exclusive function prefix)
)
endif()
endmacro()
########################################################
# 7. Linkable loadable extensions (llext)
########################################################
#
# These functions simplify the creation and management of linkable
# loadable extensions (llexts).
#
# 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
# arguments. Only one source file is currently supported.
#
# Arch-specific flags will be added automatically. The C_FLAGS argument
# can be used to pass additional compiler flags to the compilation of
# the source file.
#
# Example usage:
# add_llext_target(hello_world
# OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext
# SOURCES ${PROJECT_SOURCE_DIR}/src/llext/hello_world.c
# C_FLAGS -Werror
# )
# will compile the source file src/llext/hello_world.c to a file
# ${PROJECT_BINARY_DIR}/hello_world.llext, adding -Werror to the compilation.
#
function(add_llext_target target_name)
set(single_args OUTPUT)
set(multi_args SOURCES;C_FLAGS)
cmake_parse_arguments(PARSE_ARGV 1 LLEXT "${options}" "${single_args}" "${multi_args}")
# Check that the llext subsystem is enabled for this build
if (NOT CONFIG_LLEXT)
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 list length must currently be 1
list(LENGTH LLEXT_SOURCES source_count)
if(NOT source_count EQUAL 1)
message(FATAL_ERROR "add_llext_target: only one source file is supported")
endif()
set(output_file ${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}
)
# Compile the source file to an .llext file
if(CONFIG_ARM)
list(PREPEND LLEXT_C_FLAGS "-mlong-calls" "-mthumb")
add_custom_command(OUTPUT ${output_file}
COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS} -c
-I ${ZEPHYR_BASE}/include
-imacros ${AUTOCONF_H}
-o ${output_file}
${source_file}
DEPENDS ${source_file}
)
elseif(CONFIG_XTENSA)
list(PREPEND LLEXT_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs")
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)
add_custom_command(OUTPUT ${output_file}
COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS}
-I ${ZEPHYR_BASE}/include
-imacros ${AUTOCONF_H}
-o ${pre_output_file}
${source_file}
COMMAND ${CROSS_COMPILE}strip -R .xt.*
-o ${output_file}
${pre_output_file}
DEPENDS ${source_file}
)
else()
message(FATAL_ERROR "add_llext_target: unsupported architecture")
endif()
endfunction()

View file

@ -7,34 +7,14 @@ project(hello_world)
if(NOT CONFIG_MODULES OR CONFIG_LLEXT_TEST_HELLO STREQUAL "m")
# TODO check which architecture is being used
if(CONFIG_ARM)
set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb")
set(llext_src_file ${PROJECT_SOURCE_DIR}/hello_world.c)
set(llext_bin_file ${PROJECT_BINARY_DIR}/hello_world.llext)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext
COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c
-I ${PROJECT_SOURCE_DIR}/../../../../include
-imacros${PROJECT_BINARY_DIR}/../zephyr/include/generated/autoconf.h
-o ${PROJECT_BINARY_DIR}/hello_world.llext
${PROJECT_SOURCE_DIR}/hello_world.c
)
elseif(CONFIG_XTENSA)
set(CMAKE_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs")
add_llext_target(hello_world
OUTPUT ${llext_bin_file}
SOURCES ${llext_src_file}
)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext
COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS}
-I ${PROJECT_SOURCE_DIR}/../../../../include
-imacros${PROJECT_BINARY_DIR}/../zephyr/include/generated/autoconf.h
-o ${PROJECT_BINARY_DIR}/hello_world.pre.llext
${PROJECT_SOURCE_DIR}/hello_world.c
COMMAND ${CROSS_COMPILE}strip -R .xt.*
-o ${PROJECT_BINARY_DIR}/hello_world.llext
${PROJECT_BINARY_DIR}/hello_world.pre.llext
)
endif()
set(HELLO_WORLD_LLEXT ${PROJECT_BINARY_DIR}/hello_world.llext PARENT_SCOPE)
add_custom_target(hello_world DEPENDS ${PROJECT_BINARY_DIR}/hello_world.llext)
set(HELLO_WORLD_LLEXT ${llext_bin_file} PARENT_SCOPE)
endif()