diff --git a/subsys/llext/CMakeLists.txt b/subsys/llext/CMakeLists.txt index b129dc7f94314fb..e76bc5944748e81 100644 --- a/subsys/llext/CMakeLists.txt +++ b/subsys/llext/CMakeLists.txt @@ -1,5 +1,84 @@ if(CONFIG_LLEXT) + + # Include all llext kernel sources as a library target zephyr_library() zephyr_library_sources(llext.c llext_export.c buf_loader.c) zephyr_library_sources_ifdef(CONFIG_LLEXT_SHELL shell.c) + + # 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}") + + # 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} ALL + 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() + endif() diff --git a/tests/subsys/llext/CMakeLists.txt b/tests/subsys/llext/CMakeLists.txt index adb199761ddc579..45cea437c330d2d 100644 --- a/tests/subsys/llext/CMakeLists.txt +++ b/tests/subsys/llext/CMakeLists.txt @@ -23,4 +23,4 @@ generate_inc_file_for_target( ${gen_dir}/hello_world.inc ) -add_dependencies(app hello_world) +add_dependencies(app hello_world_llext) diff --git a/tests/subsys/llext/hello_world/CMakeLists.txt b/tests/subsys/llext/hello_world/CMakeLists.txt index 30f0c1a3b3c7b0b..40aad0cd3db8815 100644 --- a/tests/subsys/llext/hello_world/CMakeLists.txt +++ b/tests/subsys/llext/hello_world/CMakeLists.txt @@ -12,34 +12,14 @@ elseif(CONFIG_MODULES AND NOT CONFIG_LLEXT_TEST_HELLO STREQUAL "m") message(FATAL_ERROR "CONFIG_LLEXT_TEST_HELLO must be set to 'm' when CONFIG_MODULES is enabled") else() -# 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_llext + 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()