blob: eae96259d245dcc57e7046d6079dae4899cf471b [file] [log] [blame]
Building extensions
###################
The LLEXT subsystem allows for the creation of extensions that can be loaded
into a running Zephyr application. When building these extensions, it's very
often useful to have access to the headers and compiler flags used by the main
Zephyr application.
The easiest path to achieve this is to build the extension as part of the
Zephyr application, using the `native Zephyr CMake features
<llext_build_native_>`_. This will result in a single build providing both the
main Zephyr application and the extension(s), which will all automatically be
built with the same parameters.
In some cases, involving the full Zephyr build system may not be feasible or
convenient; maybe the extension is built using a different compiler suite or as
part of a different project altogether. In this case, the extension developer
needs to export the headers and compiler flags used by the main Zephyr
application. This can be done using the `LLEXT Extension Development Kit
<llext_build_edk_>`_.
.. _llext_build_native:
Using the Zephyr CMake features
*******************************
The Zephyr build system provides a set of features that can be used to build
extensions as part of the Zephyr application. This is the simplest way to build
extensions, as it requires minimal additions to an application build system.
Building the extension
----------------------
An extension can be defined in the app's ``CMakeLists.txt`` by invoking the
``add_llext_target`` function, providing the target name, the output and the
source files. Usage is similar to the standard ``add_custom_target`` CMake
function:
.. code-block:: cmake
add_llext_target(
<target_name>
OUTPUT <ext_file.llext>
SOURCES <src1> [<src2>...]
)
where:
- ``<target_name>`` is the name of the final CMake target that will result in
the LLEXT binary being created;
- ``<ext_file.llext>`` is the name of the output file that will contain the
packaged extension;
- ``<src1> [<src2>...]`` is the list of source files that will be compiled to
create the extension.
The exact steps of the extension building process depend on the currently
selected :ref:`ELF object format <llext_kconfig_type>`.
The following custom properties of ``<target_name>`` are defined and can be
retrieved using the ``get_target_property()`` CMake function:
``lib_target``
Target name for the source compilation and/or link step.
``lib_output``
The binary file resulting from compilation and/or linking steps.
``pkg_input``
The file to be used as input for the packaging step.
``pkg_output``
The final extension file name.
Tweaking the build process
--------------------------
The following CMake functions can be used to modify the build system behavior
during the extension build process to a fine degree. Each of the below
functions takes the LLEXT target name as its first argument; it is otherwise
functionally equivalent to the common Zephyr ``target_*`` version.
* ``llext_compile_definitions``
* ``llext_compile_features``
* ``llext_compile_options``
* ``llext_include_directories``
* ``llext_link_options``
Custom build steps
------------------
The ``add_llext_command`` CMake function can be used to add custom build steps
that will be executed during the extension build process. The command will be
run at the specified build step and can refer to the properties of the target
for build-specific details.
The function signature is:
.. code-block:: cmake
add_llext_command(
TARGET <target_name>
[PRE_BUILD | POST_BUILD | POST_PKG]
COMMAND <command> [args...]
)
The different build steps are:
``PRE_BUILD``
Before the extension code is linked, if the architecture uses dynamic
libraries. This step can access ``lib_target`` and its own properties.
``POST_BUILD``
After the extension code is built, but before packaging it in an ``.llext``
file. This step is expected to create a :file:`pkg_input` file by reading the
contents of :file:`lib_output`.
``POST_PKG``
After the extension output file has been created. The command can operate
on the final llext file :file:`pkg_output`.
Anything else after ``COMMAND`` will be passed to ``add_custom_command()`` as-is
(including multiple commands and other options).
.. _llext_build_edk:
LLEXT Extension Development Kit (EDK)
*************************************
When building extensions as a standalone project, outside of the main Zephyr
build system, it's important to have access to the same set of generated
headers and compiler flags used by the main Zephyr application, since they have
a direct impact on how Zephyr headers are interpreted and the extension is
compiled in general.
This can be achieved by asking Zephyr to generate an Extension Development Kit
(EDK) from the build artifacts of the main Zephyr application, by running the
following command which uses the ``llext-edk`` target:
.. code-block:: shell
west build -t llext-edk
The generated EDK can be found in the build directory under the ``zephyr``
directory. It's a tarball that contains the headers and compile flags needed
to build extensions. The extension developer can then include the headers
and use the compile flags in their build system to build the extension.
Compile flags
-------------
The EDK includes the convenience files ``cmake.cflags`` (for CMake-based
projects) and ``Makefile.cflags`` (for Make-based ones), which define a set of
variables that contain the compile flags needed by the project. The full list
of flags needed to build an extension is provided by ``LLEXT_CFLAGS``. Also
provided is a more granular set of flags that can be used in support of
different use cases, such as when building mocks for unit tests:
``LLEXT_INCLUDE_CFLAGS``
Compiler flags to add directories containing non-autogenerated headers
to the compiler's include search paths.
``LLEXT_GENERATED_INCLUDE_CFLAGS``
Compiler flags to add directories containing autogenerated headers to
the compiler's include search paths.
``LLEXT_ALL_INCLUDE_CFLAGS``
Compiler flags to add all directories containing headers used in the
build to the compiler's include search paths. This is a combination of
``LLEXT_INCLUDE_CFLAGS`` and ``LLEXT_GENERATED_INCLUDE_CFLAGS``.
``LLEXT_GENERATED_IMACROS_CFLAGS``
Compiler flags for autogenerated headers that must be included in the
build via ``-imacros``.
``LLEXT_BASE_CFLAGS``
Other compiler flags that control code generation for the target CPU.
None of these flags are included in the above lists.
``LLEXT_CFLAGS``
All flags required to build an extension. This is a combination of
``LLEXT_ALL_INCLUDE_CFLAGS``, ``LLEXT_GENERATED_IMACROS_CFLAGS`` and
``LLEXT_BASE_CFLAGS``.
.. _llext_kconfig_edk:
LLEXT EDK Kconfig options
-------------------------
The LLEXT EDK can be configured using the following Kconfig options:
:kconfig:option:`CONFIG_LLEXT_EDK_NAME`
The name of the generated EDK tarball.
:kconfig:option:`CONFIG_LLEXT_EDK_USERSPACE_ONLY`
If set, the EDK will include headers that do not contain code to route
syscalls to the kernel. This is useful when building extensions that will
run exclusively in user mode.
EDK Sample
----------
Refer to :zephyr:code-sample:`llext-edk` for an example of how to use the
LLEXT EDK.