-
Notifications
You must be signed in to change notification settings - Fork 6.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
llext: additional CMake harmonizations #67997
llext: additional CMake harmonizations #67997
Conversation
@lyakh I believe you could use something like this:
which results in the following command being run:
|
@pillo79 some list-conversion missing? |
6873e7d
to
101a21b
Compare
cmake/modules/extensions.cmake
Outdated
# OUTPUT <output_file> | ||
# SOURCES <source_file> | ||
# [C_FLAGS <flags> ...] | ||
# [POSTPROC_CMD <cmd> [POSTPROC_ARGS <args> ...]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not fond of this, let's split the functions.
add_llext_target()
creates the target and accepts source files, similar to CMake's add_custom_target / add_library.
But we should consider which one add_llext_target()
resembles. With this PR I'm starting to think it probably more resembles add_library than custom_target.
Therefore I believe that instead of having POSTPROC_CMD
then we should be have a function which resembles add_custom_command(TARGET <target> PRE_/POST_BUILD)
.
As I see, we need finer granularity, so an idea could be:
add_llext_command(TARGET <llext_target>
[ PRE_BUILD | PRE_STRIP | POST_BUILD | <other> ] # Choose what is appropriate in this context
COMMAND ....
)
That will also allow to gradually build the target and extra steps based on various other setting and not having to know everything from start.
Like:
add_llext_target(...)
if(<something>)
add_llext_command(...)
endif()
Note: should we consider to rename add_llext_target()
to add_llext_library()
to make it more clear that we actually produce a lib.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The product is an llext, not necessarily a library, it could be a partially linked elf representing a whole application to load, so I think adding the term library is a misrepresentation in this case. If shorter and closer to add _library is needed, then abbreviating to add_llext is fine, its a target to build.
The rest makes good sense to me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The product is an llext, not necessarily a library, it could be a partially linked elf representing a whole application to load, so I think adding the term library is a misrepresentation in this case.
and yet the term lib
is used all over the place in this PR:
zephyr/cmake/modules/extensions.cmake
Line 5172 in 37f60ed
set(llext_lib_target ${target_name}_llext_lib) |
zephyr/cmake/modules/extensions.cmake
Line 5177 in 37f60ed
set(llext_lib_output $<TARGET_OBJECTS:${llext_lib_target}>) |
zephyr/cmake/modules/extensions.cmake
Line 5195 in 37f60ed
target_compile_definitions(${llext_lib_target} PRIVATE |
etc.
cmake/modules/extensions.cmake
Outdated
# add_llext_target(<target_name> | ||
# OUTPUT <output_file> | ||
# SOURCES <source_file> | ||
# [C_FLAGS <flags> ...] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's have a dedicate function for C_FLAGS
, perhaps llext_compile_options(<target> <options>)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For testing convenience and coverage, could you add some dummy post-processing in one of the samples or tests?
Hi, I was able to use this for building an SOF LLEXT binary and it worked well! So you can add my "Tested-by" to your PR if that's something commonly done in Zephyr. But I did have to add |
( DNM since I can't have this reviewed by the release window closing ) |
101a21b
to
1032c24
Compare
@tejlmand @teburd @lyakh I should have addressed all concerns. The function added to customize llext build steps is now exactly like add_llext_command(
TARGET llext_target
PRE_BUILD | PRE_PACK | POST_BUILD
COMMAND ...
)
The |
@lyakh your use case is also better supported now, since:
I would rewrite the above example as: # Generate the llext target
add_llext_target(hello_world
OUTPUT ${llext_bin_file}
SOURCES ${llext_src_file}
)
# Get internal file and target names
get_target_property(link_target hello_world LinkTarget)
get_target_property(linked_file hello_world LinkedFile)
get_target_property(postproc_file hello_world PostProcFile)
# Add the custom command using the above variables
add_llext_command(
TARGET hello_world
PRE_PACK
COMMAND echo ${linked_file} ${postproc_file} ${CMAKE_C_COMPILER} --
$<TARGET_PROPERTY:${link_target},COMPILE_FLAGS>
$<TARGET_PROPERTY:${link_target},LINK_FLAGS>
$<TARGET_PROPERTY:${link_target},LINK_OPTIONS>
$<TARGET_OBJECTS:${link_target}>
) |
add_llext_target
21b29c3
to
2500c59
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New update addressing (I hope) all open points:
- The global property change is now addressed at its root, by defining a custom Zephyr
SYSTEM_NAME
, to properly shadow the original dynamic libs override inGeneric.cmake
. - Reworked
llext_proc_target
's custom command so its contents and logic is unambiguous. - Made the
PRE_BUILD
custom step fail on ARM, since it has no linking step and there is no way to properly implement a workaround for it. - Additional function comments explaining expected behavior of the custom commands.
@tejlmand please let me know your feedback.
cmake/modules/extensions.cmake
Outdated
elseif(CONFIG_XTENSA) | ||
|
||
# Ensure shared library support is enabled | ||
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finally found it! 🥳
It's getting cleared in upstream Generic.cmake, a file which CMake loads as the "system name" set here:
zephyr/cmake/modules/FindTargetTools.cmake
Lines 36 to 43 in 4045975
# https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/CrossCompiling: | |
# CMAKE_SYSTEM_NAME : this one is mandatory, it is the name of the target | |
# system, i.e. the same as CMAKE_SYSTEM_NAME would have if CMake would run | |
# on the target system. Typical examples are "Linux" and "Windows". This | |
# variable is used for constructing the file names of the platform files | |
# like Linux.cmake or Windows-gcc.cmake. If your target is an embedded | |
# system without OS set CMAKE_SYSTEM_NAME to "Generic". | |
set(CMAKE_SYSTEM_NAME Generic) |
So this is part of upstream CMake, and not modifiable per se.
I addressed it by doing set (CMAKE_SYSTEM_NAME Zephyr)
in FindTargetTools.cmake
and providing a simple Platform/Zephyr.cmake
that reuses Generic, but enables dynamic linking support when LLEXT is enabled.
I just noticed by chance that a (probably small) conflict appeared in |
When CONFIG_LLEXT is enabled, the Zephyr platform needs to enable dynamic library support. This is done by setting the `TARGET_SUPPORTS_SHARED_LIBS` property to `TRUE` in the global property scope. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
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>
Remove the C_FLAGS argument from add_llext_target() and add a set of functions to configure the compilation and linking of an llext using the same API of the target_* functions. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This patch adds support for custom commands to be executed during the build of an llext target. The commands can be executed at different points in the build process: - PRE_BUILD: Before the llext code is linked. - POST_BUILD: After the llext code is built, but before packaging it in an .llext file. - POST_PKG: After the llext file has been created. Note that PRE_BUILD is not supported for ARM targets, as in that case object files are used directly and there is no actual linking step. The commands can be added using the new add_llext_command() function. An example usage of it, along with some target properties, is added to the hello_world test case. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2500c59
to
cf0b25e
Compare
Thanks. Yes, the sample code needs to be included inside the new |
@tejlmand any further feedback? There is other work depending on this |
@tejlmand arguably this is an LLEXT set of changes so I've re-assigned to myself, if this is wrong please do correct it |
Review is stale with several weeks given to update and comments seem to have been addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# the build. The command will be executed at the specified build step and | ||
# can refer to <target>'s properties for build-specific details. | ||
# | ||
# The differrent build steps are: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor typo in comment. Obviously not blocking. Do not force-push and lose approvals ONLY for this.
@marc-hb It is my goal and wish to first establish a PR CI chain for both Zephyr twister and SOF LLEXT use-case. After that I'll gladly continue with my attempt to move over SOF LLEXT cmake code to this new base. I tried it before and it worked well, but we have changed a couple of things since then, so, need to try again. Will work with @pillo79 if any new requirements arise. Yes, I definitely agree that switching over to using these functions would be a good improvement! |
…roduction of cmake/modules/Platform/Zephyr.cmake This commit reverts a breaking change in CMAKE_SYSTEM_NAME introduced by zephyrproject-rtos#67997 (changing it from "Zephyr" back to "Generic") and removes the file `cmake/modules/Platform/Zephyr`. Both changes in the aforementioned PR were only introduced to ultimately modify the value of the global CMake property TARGET_SUPPORTS_SHARED_LIBS for the special case of building for Xtensa with LLEXT. The modification of CMAKE_SYSTEM_NAME is considered a breaking change because it has the potential to alter the build of any non-trivial project that previously checked for the "Generic" system identifier as corresponding to Zephyr - for example by doing `if (CMAKE_SYSTEM_NAME STREQUAL "Generic")`. Such builds may now break in many ways including silently when there is no `else()` clause with a `message()` to alert the user that a whole configuration block had been skipped. In essesnce, that CMAKE_SYSTEM_NAME modification was only introduced in order to have CMake to load `cmake/modules/Platform/Zephyr.cmake` which in turn adjusted the value of TARGET_SUPPORTS_SHARED_LIBS. But the use of a CMake platform file like this is ineffective for non-trivial projects where one or more top level CMake `project()` calls may happen before the first call to `find_package(Zephyr)` because in such cases CMAKE_MODULE_PATH will not have been modified yet to contain the path to <Zephyr_ROOT>/cmake/modules and thus no platform file will be include by CMake. This patch moves the conditional override of TARGET_SUPPORTS_SHARED_LIBS into the `kernel.cmake` module which is known to be the first call to `project()` that enables any language and thus the one that must come before any artifact target can be defined. Signed-off-by: Nicolas Lebedenco <nicolas@lebedenco.net>
…roduction of cmake/modules/Platform/Zephyr.cmake This commit reverts a breaking change in CMAKE_SYSTEM_NAME introduced by zephyrproject-rtos#67997 (changing it from "Zephyr" back to "Generic") and removes the file `cmake/modules/Platform/Zephyr`. Both changes in the aforementioned PR were only introduced to ultimately modify the value of the global CMake property TARGET_SUPPORTS_SHARED_LIBS for the special case of building for Xtensa with LLEXT. The modification of CMAKE_SYSTEM_NAME is considered a breaking change because it has the potential to alter the build of any non-trivial project that previously checked for the "Generic" system identifier as corresponding to Zephyr - for example by doing `if (CMAKE_SYSTEM_NAME STREQUAL "Generic")`. Such builds may now break in many ways including silently when there is no `else()` clause with a `message()` to alert the user that a whole configuration block had been skipped. In essence, that CMAKE_SYSTEM_NAME modification was only introduced in order to have CMake to load `cmake/modules/Platform/Zephyr.cmake` which in turn adjusted the value of TARGET_SUPPORTS_SHARED_LIBS. But the use of a CMake platform file like this is ineffective for non-trivial projects where one or more top level CMake `project()` calls may happen before the first call to `find_package(Zephyr)` because in such cases CMAKE_MODULE_PATH will not have been modified yet to contain the path to <Zephyr_ROOT>/cmake/modules and thus no platform file will be include by CMake. This patch moves the conditional override of TARGET_SUPPORTS_SHARED_LIBS into the `kernel.cmake` module which is known to be the first call to `project()` that enables any language and thus the one that must come before any artifact target can be defined. Signed-off-by: Nicolas Lebedenco <nicolas@lebedenco.net>
This PR reworks
add_llext_target
to more cleanly mimic existing CMake machinery, and support adding custom commands to the extension building stages (as turned out to be useful in this SOF PR).The
C_FLAGS
argument toadd_llext_target
has been removed. Flags, defines, paths and similar configuration options can now be set using functions that mimic CMake'starget_
* API.Custom build steps can be requested via the new
add_llext_command
function, that shares the API withadd_custom_command
:Intermediate file or target names are exported via properties on the main target and can be accessed via the
get_target_property()
function:-
lib_target
: Target name for the compilation and/or link step.-
lib_output
: Name of the binary file resulting from compilation and/or linking steps.-
pkg_input
: Name of the binary file to be used as input to the packaging stage.-
pkg_output
: Name of the final llext file.The phase options have natural meanings:
PRE_BUILD
runs after compilation, but before any linking step takes place (as CMake); might uselib_target
to get additional variables.POST_BUILD
runs after all code-related compile/link stages have been executed (as CMake), but before packaging; this is expected to createpkg_input
by processing the contents oflib_output
.POST_PKG
is a new stage after the packaging in .llext is complete; might access the contents of the filepkg_output
.