Skip to content

Commit

Permalink
cmake: move add_llext_target() to llext.cmake
Browse files Browse the repository at this point in the history
The CMake function add_llext_target() is used to wrap the building of an
llext. Move this code to cmake/modules/llext.cmake instead of being in a
subsystem-specific CMakeFile.

The function is moved verbatim except for an additional check for
CONFIG_LLEXT to be enabled (previously it was done at CMakeFile level).

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
  • Loading branch information
pillo79 committed Jan 12, 2024
1 parent 8226c24 commit d435f7b
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 103 deletions.
111 changes: 111 additions & 0 deletions cmake/modules/llext.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# SPDX-License-Identifier: Apache-2.0

include_guard(GLOBAL)

# 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} ALL
COMMENT "Compiling ${output_name}"
DEPENDS ${output_file}
)

# Define arch-specific flags for the supported architectures
if(CONFIG_ARM)
list(PREPEND LLEXT_C_FLAGS "-mlong-calls" "-mthumb")
elseif(CONFIG_XTENSA)
list(PREPEND LLEXT_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs")
else()
message(FATAL_ERROR "add_llext_target: unsupported architecture")
endif()

# 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
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_COMPILE_DEFINITIONS>
)
target_compile_options(${target_name}_lib PRIVATE
${LLEXT_C_FLAGS}
-imacros "${AUTOCONF_H}"
)
target_include_directories(${target_name}_lib PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_INCLUDE_DIRECTORIES>
)
target_include_directories(${target_name}_lib SYSTEM PUBLIC
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
)

# Arch-specific conversion of the object file to an llext
if(CONFIG_ARM)

# No conversion 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>
)

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
add_custom_command(
OUTPUT ${output_file}
BYPRODUCTS ${pre_output_file}
COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS}
-o ${pre_output_file}
$<TARGET_OBJECTS:${target_name}_lib>
COMMAND ${CROSS_COMPILE}strip -R .xt.*
-o ${output_file}
${pre_output_file}
DEPENDS ${target_name}_lib $<TARGET_OBJECTS:${target_name}_lib>
)

endif()
endfunction()
3 changes: 3 additions & 0 deletions cmake/modules/zephyr_default.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ list(APPEND zephyr_cmake_modules dts)
list(APPEND zephyr_cmake_modules kconfig)
list(APPEND zephyr_cmake_modules soc)

# Include rules for building llexts
list(APPEND zephyr_cmake_modules llext)

foreach(component ${SUB_COMPONENTS})
if(NOT ${component} IN_LIST zephyr_cmake_modules)
message(FATAL_ERROR
Expand Down
103 changes: 0 additions & 103 deletions subsys/llext/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,107 +5,4 @@ if(CONFIG_LLEXT)
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}
)

# Define arch-specific flags for the supported architectures
if(CONFIG_ARM)
list(PREPEND LLEXT_C_FLAGS "-mlong-calls" "-mthumb")
elseif(CONFIG_XTENSA)
list(PREPEND LLEXT_C_FLAGS "-shared" "-fPIC" "-nostdlib" "-nodefaultlibs")
else()
message(FATAL_ERROR "add_llext_target: unsupported architecture")
endif()

# 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
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_COMPILE_DEFINITIONS>
)
target_compile_options(${target_name}_lib PRIVATE
${LLEXT_C_FLAGS}
-imacros "${AUTOCONF_H}"
)
target_include_directories(${target_name}_lib PRIVATE
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_INCLUDE_DIRECTORIES>
)
target_include_directories(${target_name}_lib SYSTEM PUBLIC
$<TARGET_PROPERTY:zephyr_interface,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
)

# Arch-specific conversion of the object file to an llext
if(CONFIG_ARM)

# No conversion 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>
)

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
add_custom_command(
OUTPUT ${output_file}
BYPRODUCTS ${pre_output_file}
COMMAND ${CMAKE_C_COMPILER} ${LLEXT_C_FLAGS}
-o ${pre_output_file}
$<TARGET_OBJECTS:${target_name}_lib>
COMMAND ${CROSS_COMPILE}strip -R .xt.*
-o ${output_file}
${pre_output_file}
DEPENDS ${target_name}_lib $<TARGET_OBJECTS:${target_name}_lib>
)

endif()
endfunction()

endif()

0 comments on commit d435f7b

Please sign in to comment.