Skip to content
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-edk: rework, add Python export and more optional information #78727

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

pillo79
Copy link
Collaborator

@pillo79 pillo79 commented Sep 19, 2024

When building several different EDKs, there's currently no way to avoid mistaking one for another. The goal of this PR is to add metadata to a generated EDK so that the target board / SOC / CPU can be retrieved and checked by downstream projects.

An additional Python-compatible output format is provided for projects that do not use CMake or make.

To implement the above, a number of internal refactors with minimal visible effect have been implemented, with the goal of having more maintainable and extendable code:

  • the EDK output commands have been refactored into generic functions that take the target file type as a parameter;
  • flag processing has been made target-agnostic by using placeholders that are expanded in the output functions.

LLEXT EDK documentation has been updated accordingly.

EDIT: updated after review notes.

@pillo79 pillo79 changed the title cmake/llext-edk: internal rework, add Bash export and more optional information llext-edk: add Bash export and more optional information Sep 19, 2024
@pillo79 pillo79 changed the title llext-edk: add Bash export and more optional information llext-edk: rework, add Bash export and more optional information Sep 19, 2024
@pillo79 pillo79 marked this pull request as ready for review September 20, 2024 07:11
@zephyrbot zephyrbot added area: llext Linkable Loadable Extensions area: Build System labels Sep 20, 2024
@pillo79 pillo79 force-pushed the pr-llext-edk-additional-info branch 2 times, most recently from 4c9878b to b77ad56 Compare September 20, 2024 09:44
@pillo79
Copy link
Collaborator Author

pillo79 commented Sep 20, 2024

v2:

  • Fixed a copy-paste error in placeholder expansion.

Copy link
Collaborator

@tejlmand tejlmand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced of two things:

  • Why should we suddenly start exporting a bunch of extra variables ?
    No detailed explanation is given, and the closest I can see seems to be because of informational use. So where does this end ?
    Are we going to maintain a list in top-level CMakeLists of all Zephyr build settings.
  • Exporting to bash.
    Starting to export to specific shells seems like setting a bad precendence.
    We provide CMake and Makefiles, and any downstream build system should be able to cope with those or easily wrap them to set them in their favorite shell instead.

CMakeLists.txt Outdated
Comment on lines 2188 to 2214
# Define variables for the cmake sub-process
foreach(exported_var
APPLICATION_SOURCE_DIR
CONFIG_LLEXT_EDK_NAME
CONFIG_LLEXT_EDK_USERSPACE_ONLY
llext_edk_cflags
llext_edk_file
PROJECT_BINARY_DIR
WEST_TOPDIR
ZEPHYR_BASE
CONFIG_LLEXT_EDK_TARGET_INFO # uses:
ARCH
BOARD
BOARD_REVISION
BOARD_QUALIFIERS
NORMALIZED_BOARD_QUALIFIERS
NORMALIZED_BOARD_TARGET
SOC_NAME
SOC_SERIES
SOC_FAMILY
CONFIG_LLEXT_EDK_TOOLCHAIN_INFO # uses:
CROSS_COMPILE_TARGET
COMPILER
LINKER
)
list(APPEND llext_edk_var_args -D${exported_var}="${${exported_var}}")
endforeach()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is growing out of hands and easily becomes unmaintainable, not to mention putting undesired restrictions on Zephyr build system internals.

For the first part, starting to have a long list of settings being maintained at the toplevel CMakeLsts.txt is not ok.
What started as a small and maintainable list which is called at a time where things are known to be defined, such as: ZEPHYR_BASE, WEST_TOPDIR was acceptable, but a constant growing list for llext is not.

Secondly, exporting Zephyr internals as-is start to mean that Zephyr cannot control this.
Are we starting to promise that we will never rename those variables because they are being exported ?

Although there is no intention of renaming SOC_NAME, SOC_SERIES, BOARD_REVISION, etc. then if this change is accepted, then it sets a precedence that any variable might enter this list.

I know there is a wish for a more controlled and well-defined way of exporting Zephyr internals where names are promised to be stable, especially for CI and IDE integration.
And for that reason work is ongoing to try and establish a common output file for build info.

Perhaps this can be useful for llext to avoid above bloat in CMakeLists.txt.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair points, I will revert this change and simply add the few missing variables I'd like to have exported to the EDK command line.

work is ongoing to try and establish a common output file for build info.

I am also very interested in this. Any pointer is appreciated 🙂

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, it's now opened: #79118

CMakeLists.txt Outdated
Comment on lines 2200 to 2207
BOARD
BOARD_REVISION
BOARD_QUALIFIERS
NORMALIZED_BOARD_QUALIFIERS
NORMALIZED_BOARD_TARGET
SOC_NAME
SOC_SERIES
SOC_FAMILY
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly why are all those details needed ?

Shouldn't it be sufficient to have the board target ?

Or are you starting to replicate the Zephyr build system outside of Zephyr ?
If that's the case, then perhaps integrate to sysbuild is a better choice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order of importance, I'd say:

  • NORMALIZED_BOARD_TARGET is the really interesting bit, as it is extremely specific to each EDK build. Otherwise, the EDK exports no metadata that can correlate itself with a board target.
  • CROSS_COMPILE_TARGET is very useful as well, as it identifies the specific compiler used and whose CFLAGS are exported by the EDK.
  • I have also used ARCH, BOARD, and to a lesser extent SOC_NAME, to logically group different EDKs.

The other variables were added only for "completeness"; sorry for not thinking about the maintenance burden.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • CROSS_COMPILE_TARGET is very useful as well, as it identifies the specific compiler used and whose CFLAGS are exported by the EDK.

and this exactly proves my worries of exporting those fields like this, because not all toolchains set this variable and we make no promises. But suddenly we could need to fix "bugs" because something which is intended for internal use is being exported.

An example of a toolchain where this variable is not defined is LLVM.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I have also used ARCH, BOARD, and to a lesser extent SOC_NAME, to logically group different EDKs.

Be careful on using arch for grouping, because a board could have multiple SoCs of different archs or a multi-core SoC where the cores are of different arch. Of course this depends on which level the arch is place, but Zephyr has just gone through a rework to avoid arch on high level organization 😉

Comment on lines 209 to 226
elseif(target STREQUAL "BASH")
# Bash: export array variables of the form:
#
# var=("value1" "value2" ...)
#
# TIP: use the "${var[@]}" syntax, including quotes, to pass all the
# elements as single arguments to a command in scripts.
set(DASHIMACROS "-imacros\${${install_dir_var}}/")
set(DASHI "-I\${${install_dir_var}}/")
string(CONFIGURE "${var_value}" exp_var_value @ONLY)
# Embedded quotes and backslashes are escaped. Each element of the
# list is wrapped in quotes and is separated by a space.
edk_escape("${exp_var_value}" exp_var_value)
list(JOIN exp_var_value "\" \"" exp_var_value_str)
file(APPEND ${edk_file_${target}} "${var_name}=(\"${exp_var_value_str}\")\n")
endif()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should start exporting to specific shells.
This is a build system, and thus exporting CMake and Makefiles seems ok, but starting to export to bash is going to just bloat our interface.

What about bat files ? fish ? or the favorite shell of some other user ?
If an external build tool is not satisfied with CMake or Makefiles then I would leave it for that tool to have a tool which can read the file and convert to its favorite shell.

Only additional file format I consider acceptable is yaml, because that is a file format Zephyr build system already uses for dumping data, for example in the Zephyr meta file creation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And to think I was about to add Python export as well... 😅 I'm surprised this would be considered "bloat" - it's only for the EDK, it's a few lines of code and it just makes the life easier for simple downstream projects - but I understand.
I'll remove this and use the current CMake export to generate the same script in my project.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised this would be considered "bloat"

when I'm saying bloat then i'm thinking in terms of what we promise externally.
If we provide bash here, should we then also provide this elsewhere, and what about xyz.

And to think I was about to add Python export as well...

had you done it the other way, then a Python might have made it through 😆
because we already use Python a lot, and Python is cross-platform (Linux, Windows, MacOS, etc.), but with Python then a yaml file would have been just as easy / nice to use 😉

Only additional file format I consider acceptable is yaml

Copy link
Collaborator Author

@pillo79 pillo79 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The objective of this PR is to add metadata to an EDK build so that the target board / SOC / CPU can be retrieved and checked by downstream projects. In my case I will require building several different EDKs, and I realized there's no way to avoid mistaking one for another.

I understand your concerns, and will amend the proposal accordingly.

CMakeLists.txt Outdated
Comment on lines 2200 to 2207
BOARD
BOARD_REVISION
BOARD_QUALIFIERS
NORMALIZED_BOARD_QUALIFIERS
NORMALIZED_BOARD_TARGET
SOC_NAME
SOC_SERIES
SOC_FAMILY
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order of importance, I'd say:

  • NORMALIZED_BOARD_TARGET is the really interesting bit, as it is extremely specific to each EDK build. Otherwise, the EDK exports no metadata that can correlate itself with a board target.
  • CROSS_COMPILE_TARGET is very useful as well, as it identifies the specific compiler used and whose CFLAGS are exported by the EDK.
  • I have also used ARCH, BOARD, and to a lesser extent SOC_NAME, to logically group different EDKs.

The other variables were added only for "completeness"; sorry for not thinking about the maintenance burden.

CMakeLists.txt Outdated
Comment on lines 2188 to 2214
# Define variables for the cmake sub-process
foreach(exported_var
APPLICATION_SOURCE_DIR
CONFIG_LLEXT_EDK_NAME
CONFIG_LLEXT_EDK_USERSPACE_ONLY
llext_edk_cflags
llext_edk_file
PROJECT_BINARY_DIR
WEST_TOPDIR
ZEPHYR_BASE
CONFIG_LLEXT_EDK_TARGET_INFO # uses:
ARCH
BOARD
BOARD_REVISION
BOARD_QUALIFIERS
NORMALIZED_BOARD_QUALIFIERS
NORMALIZED_BOARD_TARGET
SOC_NAME
SOC_SERIES
SOC_FAMILY
CONFIG_LLEXT_EDK_TOOLCHAIN_INFO # uses:
CROSS_COMPILE_TARGET
COMPILER
LINKER
)
list(APPEND llext_edk_var_args -D${exported_var}="${${exported_var}}")
endforeach()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair points, I will revert this change and simply add the few missing variables I'd like to have exported to the EDK command line.

work is ongoing to try and establish a common output file for build info.

I am also very interested in this. Any pointer is appreciated 🙂

Comment on lines 209 to 226
elseif(target STREQUAL "BASH")
# Bash: export array variables of the form:
#
# var=("value1" "value2" ...)
#
# TIP: use the "${var[@]}" syntax, including quotes, to pass all the
# elements as single arguments to a command in scripts.
set(DASHIMACROS "-imacros\${${install_dir_var}}/")
set(DASHI "-I\${${install_dir_var}}/")
string(CONFIGURE "${var_value}" exp_var_value @ONLY)
# Embedded quotes and backslashes are escaped. Each element of the
# list is wrapped in quotes and is separated by a space.
edk_escape("${exp_var_value}" exp_var_value)
list(JOIN exp_var_value "\" \"" exp_var_value_str)
file(APPEND ${edk_file_${target}} "${var_name}=(\"${exp_var_value_str}\")\n")
endif()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And to think I was about to add Python export as well... 😅 I'm surprised this would be considered "bloat" - it's only for the EDK, it's a few lines of code and it just makes the life easier for simple downstream projects - but I understand.
I'll remove this and use the current CMake export to generate the same script in my project.

This commit refactors the code that generates the Makefile and CMake
EDK files into functions that accept the file type as an argument.

No functional changes are introduced in this commit.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
teburd
teburd previously approved these changes Sep 20, 2024
Copy link
Collaborator

@teburd teburd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All seems very reasonable, nice!

This commit removes all CMake- or Makefile-specific variables from the
code and instead uses a single list for each type of flag. Where a
difference is needed between the two, a special marker is used.
These markers are replaced later in the target-specific area of the
write functions.

Escaping of problematic characters is also added to the write functions,
to ensure that quotes and backslashes in the flags are properly handled.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This patch adds several variables related to the Zephyr build to the
files generated by the EDK.

The exported information is intended to provide additional context to
the external projects that use the EDK; however since they are Zephyr
internals, there is no guarantee of stability for these variables
or their contents.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This commit adds a new export target for Python code. The exported
variables are formatted as lists of f-strings so the embedded paths
is implicitly expanded at definition time.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
Extend the documentation for the LLEXT EDK to include information about
the target and toolchain information that is now exported by the EDK and
the new output format.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
@pillo79 pillo79 changed the title llext-edk: rework, add Bash export and more optional information llext-edk: rework, add Python export and more optional information Sep 20, 2024
@pillo79
Copy link
Collaborator Author

pillo79 commented Sep 20, 2024

v3, incorporating @tejlmand notes:

  • Bash is now Python 🙂
  • The list of exported variables is static and considerably reduced
  • Both the code and the documentation clearly state the added variables reflect Zephyr internals and no stability guarantees are implied.

@pillo79
Copy link
Collaborator Author

pillo79 commented Sep 26, 2024

@tejlmand can you please revisit this? Thanks!

Comment on lines +224 to +225
list(JOIN exp_var_value "\", f\"" exp_var_value_str)
file(APPEND ${edk_file_${target}} "${var_name} = [f\"${exp_var_value_str}\"]\n")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't look like yaml to me 😉
ref: #78727 (comment)

then a yaml file would have been just as easy / nice to use 😉

Only additional file format I consider acceptable is yaml

remember, yaml can be read directly into Python dict and is much nicer to work with.
We actually have a yaml module in Zephyr CMake now 😄

CMakeLists.txt Outdated
Comment on lines 2188 to 2214
# Define variables for the cmake sub-process
foreach(exported_var
APPLICATION_SOURCE_DIR
CONFIG_LLEXT_EDK_NAME
CONFIG_LLEXT_EDK_USERSPACE_ONLY
llext_edk_cflags
llext_edk_file
PROJECT_BINARY_DIR
WEST_TOPDIR
ZEPHYR_BASE
CONFIG_LLEXT_EDK_TARGET_INFO # uses:
ARCH
BOARD
BOARD_REVISION
BOARD_QUALIFIERS
NORMALIZED_BOARD_QUALIFIERS
NORMALIZED_BOARD_TARGET
SOC_NAME
SOC_SERIES
SOC_FAMILY
CONFIG_LLEXT_EDK_TOOLCHAIN_INFO # uses:
CROSS_COMPILE_TARGET
COMPILER
LINKER
)
list(APPEND llext_edk_var_args -D${exported_var}="${${exported_var}}")
endforeach()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, it's now opened: #79118

@tejlmand
Copy link
Collaborator

v3, incorporating @tejlmand notes:

* Bash is now Python 🙂

* The list of exported variables is static and considerably reduced

* Both the code and the documentation clearly state the added variables reflect Zephyr internals and no stability guarantees are implied.

Thanks, but before going into details again on this one, then I have opened #79118 as promised.

I know we currently still have the CMake and Makefile export, but I was thinking that it could be beneficial to cover the Python export functionality you need by expanding the schema with the extra info by using the according build_info() function where needed.
This will also move knowledge / ever growing list of settings away from top-level CMakeLists.txt and closer to where the vars are actually defined and used (and thus reducing maintenance on those).

Later we can then update CMake / makefile generation to actually use the information from the build info infrastructure instead of having to keep track of this manually, but that I would take ast a later stage.

Please take a look at #79118 in relation to this PR and give your initial thoughts.
😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Build System area: llext Linkable Loadable Extensions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants