develop/modules.html · develop/modules.rst 공식 원문 ↗

Zephyr 3.7.0 · Develop · Modules

모듈(외부 프로젝트)

외부 codebase를 Zephyr 모듈로 받아들이고 검증하며 build에 통합하는 전체 수명주기를 설명합니다.

Official pathdevelop/modules.html
Source filedevelop/modules.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

본문 기준: Zephyr 3.7.0 LTS3 · 이후 유지보수 패치는 별도입니다.

Part 1

요약·해설

모듈과 West project의 차이, repository·upstream·license·CI 정책, zephyr/module.yml schema, CMake·Kconfig·Sysbuild 통합, dependency·binary blob·Twister·제출 절차를 한 문서에서 연결합니다.

Governance

TSC · owner · CI · license

Integration

module.yml · CMake · Kconfig

Workflow

West · Sysbuild · pull request

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 CE4F1BFE0D39A3AA7BA327E70E2CA1FF2E431A0B2ED78DA2D16B87AD26313F90
.. _modules:

Modules (External projects)
############################

Zephyr relies on the source code of several externally maintained projects in
order to avoid reinventing the wheel and to reuse as much well-established,
mature code as possible when it makes sense. In the context of Zephyr's build
system those are called *modules*. These modules must be integrated with the
Zephyr build system, as described in more detail in other sections on
this page.

To be classified as a candidate for being included in the default list of
modules, an external project is required to have its own life-cycle outside
the Zephyr Project, that is, reside in its own repository, and have its own
contribution and maintenance workflow and release process. Zephyr modules
should not contain code that is written exclusively for Zephyr. Instead,
such code should be contributed to the main zephyr tree.

Modules to be included in the default manifest of the Zephyr project need to
provide functionality or features endorsed and approved by the project Technical
Steering Committee and should comply with the
:ref:`module licensing requirements<modules_licensing>` and
:ref:`contribution guidelines<modules_contributing>`. They should also have a
Zephyr developer that is committed to maintain the module codebase.

Zephyr depends on several categories of modules, including but not limited to:

- Debugger integration
- Silicon vendor Hardware Abstraction Layers (HALs)
- Cryptography libraries
- File Systems
- Inter-Process Communication (IPC) libraries

Additionally, in some cases modules (particularly vendor HALs) can contain
references to optional :ref:`binary blobs <bin-blobs>`.

This page summarizes a list of policies and best practices which aim at
better organizing the workflow in Zephyr modules.

.. _modules-vs-projects:

Modules vs west projects
************************

Zephyr modules, described in this page, are not the same as :ref:`west projects
<west-workspace>`. In fact, modules :ref:`do not require west
<modules_without_west>` at all. However, when using modules :ref:`with west
<modules_using_west>`, then the build system uses west in order to find modules.

In summary:

Modules are repositories that contain a :file:`zephyr/module.yml` file, so that
the Zephyr build system can pull in the source code from the repository.
:ref:`West projects <west-manifests-projects>` are entries in the `projects:`
section in the :file:`west.yml` manifest file.
West projects are often also modules, but not always. There are west projects
that are not included in the final firmware image (eg. tools) and thus do not
need to be modules.
Modules are found by the Zephyr build system either via :ref:`west itself
<modules_using_west>`, or via the :ref:`ZEPHYR_MODULES CMake variable
<modules_without_west>`.

The contents of this page only apply to modules, and not to west projects in
general (unless they are a module themselves).

Module Repositories
*******************

* All modules included in the default manifest shall be hosted in repositories
  under the zephyrproject-rtos GitHub organization.

* The module repository codebase shall include a *module.yml* file in a
  :file:`zephyr/` folder at the root of the repository.

* Module repository names should follow the convention of using lowercase
  letters and dashes instead of underscores. This rule will apply to all
  new module repositories, except for repositories that are directly
  tracking external projects (hosted in Git repositories); such modules
  may be named as their external project counterparts.

  .. note::

     Existing module repositories that do not conform to the above convention
     do not need to be renamed to comply with the above convention.

* Module repositories names should be explicitly set in the :file:`zephyr/module.yml` file.

* Modules should use "zephyr" as the default name for the repository main
  branch. Branches for specific purposes, for example, a module branch for
  an LTS Zephyr version, shall have names starting with the 'zephyr\_' prefix.

* If the module has an external (upstream) project repository, the module
  repository should preserve the upstream repository folder structure.

  .. note::

     It is not required in module repositories to maintain a 'master'
     branch mirroring the master branch of the external repository. It
     is not recommended as this may generate confusion around the module's
     main branch, which should be 'zephyr'.

* Modules should expose all provided header files with an include pathname
  beginning with the module-name.  (E.g., mcuboot should expose its
  ``bootutil/bootutil.h`` as "mcuboot/bootutil/bootutil.h".)

.. _modules_synchronization:

Synchronizing with upstream
===========================

It is preferred to synchronize a module repository with the latest stable
release of the corresponding external project. It is permitted, however, to
update a Zephyr module repository with the latest development branch tip,
if this is required to get important updates in the module codebase. When
synchronizing a module with upstream it is mandatory to document the
rationale for performing the particular update.

Requirements for allowed practices
----------------------------------

Changes to the main branch of a module repository, including synchronization
with upstream code base, may only be applied via pull requests. These pull
requests shall be *verifiable* by Zephyr CI and *mergeable* (e.g. with the
*Rebase and merge*, or *Create a merge commit* option using Github UI). This
ensures that the incoming changes are always **reviewable**, and the
*downstream* module repository history is incremental (that is, existing
commits, tags, etc. are always preserved). This policy also allows to run
Zephyr CI, git lint, identity, and license checks directly on the set of
changes that are to be brought into the module repository.

.. note::

     Force-pushing to a module's main branch is not allowed.

Allowed practices
-----------------

The following practices conform to the above requirements and should be
followed in all modules repositories. It is up to the module code owner
to select the preferred synchronization practice, however, it is required
that the selected practice is consistently followed in the respective
module repository.

**Updating modules with a diff from upstream:**
Upstream changes brought as a single *snapshot* commit (manual diff) in a
pull request against the module's main branch, which may be merged using
the *Rebase & merge* operation. This approach is simple and
should be applicable to all modules with the downside of suppressing the
upstream history in the module repository.

  .. note::

     The above practice is the only allowed practice in modules where
     the external project is not hosted in an upstream Git repository.

The commit message is expected to identify the upstream project URL, the
version to which the module is updated (upstream version, tag, commit SHA,
if applicable, etc.), and the reason for the doing the update.

**Updating modules by merging the upstream branch:**
Upstream changes brought in by performing a Git merge of the intended upstream
branch (e.g. main branch, latest release branch, etc.) submitting the result in
pull request against the module main branch, and merging the pull request using
the *Create a merge commit* operation.
This approach is applicable to modules with an upstream project Git repository.
The main advantages of this approach is that the upstream repository history
(that is, the original commit SHAs) is preserved in the module repository. The
downside of this approach is that two additional merge commits are generated in
the downstream main branch.


Contributing to Zephyr modules
******************************

.. _modules_contributing:


Individual Roles & Responsibilities
===================================

To facilitate management of Zephyr module repositories, the following
individual roles are defined.

**Administrator:** Each Zephyr module shall have an administrator
who is responsible for managing access to the module repository,
for example, for adding individuals as Collaborators in the repository
at the request of the module owner. Module administrators are
members of the Administrators team, that is a group of project
members with admin rights to module GitHub repositories.

**Module owner:** Each module shall have a module code owner. Module
owners will have the overall responsibility of the contents of a
Zephyr module repository. In particular, a module owner will:

* coordinate code reviewing in the module repository
* be the default assignee in pull-requests against the repository's
  main branch
* request additional collaborators to be added to the repository, as
  they see fit
* regularly synchronize the module repository with its upstream
  counterpart following the policies described in
  :ref:`modules_synchronization`
* be aware of security vulnerability issues in the external project
  and update the module repository to include security fixes, as
  soon as the fixes are available in the upstream code base
* list any known security vulnerability issues, present in the
  module codebase, in Zephyr release notes.


  .. note::

     Module owners are not required to be Zephyr
     :ref:`Maintainers <project_roles>`.

**Merger:** The Zephyr Release Engineering team has the right and the
responsibility to merge approved pull requests in the main branch of a
module repository.


Maintaining the module codebase
===============================

Updates in the zephyr main tree, for example, in public Zephyr APIs,
may require patching a module's codebase. The responsibility for keeping
the module codebase up to date is shared between the **contributor** of
such updates in Zephyr and the module **owner**. In particular:

* the contributor of the original changes in Zephyr is required to submit
  the corresponding changes that are required in module repositories, to
  ensure that Zephyr CI on the pull request with the original changes, as
  well as the module integration testing are successful.

* the module owner has the overall responsibility for synchronizing
  and testing the module codebase with the zephyr main tree.
  This includes occasional advanced testing of the module's codebase
  in addition to the testing performed by Zephyr's CI.
  The module owner is required to fix issues in the module's codebase that
  have not been caught by Zephyr pull request CI runs.


.. _modules_changes:

Contributing changes to modules
===============================

Submitting and merging changes directly to a module's codebase, that is,
before they have been merged in the corresponding external project
repository, should be limited to:

* changes required due to updates in the zephyr main tree
* urgent changes that should not wait to be merged in the external project
  first, such as fixes to security vulnerabilities.

Non-trivial changes to a module's codebase, including changes in the module
design or functionality should be discouraged, if the module has an upstream
project repository. In that case, such changes shall be submitted to the
upstream project, directly.

:ref:`Submitting changes to modules <submitting_new_modules>` describes in
detail the process of contributing changes to module repositories.

Contribution guidelines
-----------------------

Contributing to Zephyr modules shall follow the generic project
:ref:`Contribution guidelines <contribute_guidelines>`.

**Pull Requests:** may be merged with minimum of 2 approvals, including
an approval by the PR assignee. In addition to this, pull requests in module
repositories may only be merged if the introduced changes are verified
with Zephyr CI tools, as described in more detail in other sections on
this page.

The merging of pull requests in the main branch of a module
repository must be coupled with the corresponding manifest
file update in the zephyr main tree.

**Issue Reporting:** `GitHub issues`_ are intentionally disabled in module
repositories, in
favor of a centralized policy for issue reporting. Tickets concerning, for
example, bugs or enhancements in modules shall be opened in the main
zephyr repository. Issues should be appropriately labeled using GitHub
labels corresponding to each module, where applicable.

  .. note::

     It is allowed to file bug reports for zephyr modules to track
     the corresponding upstream project bugs in Zephyr. These bug reports
     shall not affect the
     :ref:`Release Quality Criteria<release_quality_criteria>`.


.. _modules_licensing:

Licensing requirements and policies
***********************************

All source files in a module's codebase shall include a license header,
unless the module repository has **main license file** that covers source
files that do not include license headers.

Main license files shall be added in the module's codebase by Zephyr
developers, only if they exist as part of the external project,
and they contain a permissive OSI-compliant license. Main license files
should preferably contain the full license text instead of including an
SPDX license identifier. If multiple main license files are present it
shall be made clear which license applies to each source file in a module's
codebase.

Individual license headers in module source files supersede the main license.

Any new content to be added in a module repository will require to have
license coverage.

  .. note::

     Zephyr recommends conveying module licensing via individual license
     headers and main license files. This not a hard requirement; should
     an external project have its own practice of conveying how licensing
     applies in the module's codebase (for example, by having a single or
     multiple main license files), this practice may be accepted by and
     be referred to in the Zephyr module, as long as licensing requirements,
     for example OSI compliance, are satisfied.

License policies
================

When creating a module repository a developer shall:

* import the main license files, if they exist in the external project, and
* document (for example in the module README or .yml file) the default license
  that covers the module's codebase.

License checks
--------------

License checks (via CI tools) shall be enabled on every pull request that
adds new content in module repositories.


Documentation requirements
**************************

All Zephyr module repositories shall include an .rst file documenting:

* the scope and the purpose of the module
* how the module integrates with Zephyr
* the owner of the module repository
* synchronization information with the external project (commit, SHA, version etc.)
* licensing information as described in :ref:`modules_licensing`.

The file shall be required for the inclusion of the module and the contained
information should be kept up to date.


Testing requirements
********************

All Zephyr modules should provide some level of **integration** testing,
ensuring that the integration with Zephyr works correctly.
Integration tests:

* may be in the form of a minimal set of samples and tests that reside
  in the zephyr main tree
* should verify basic usage of the module (configuration,
  functional APIs, etc.) that is integrated with Zephyr.
* shall be built and executed (for example in QEMU) as part of
  twister runs in pull requests that introduce changes in module
  repositories.

  .. note::

     New modules, that are candidates for being included in the Zephyr
     default manifest, shall provide some level of integration testing.

  .. note::

     Vendor HALs are implicitly tested via Zephyr tests built or executed
     on target platforms, so they do not need to provide integration tests.

The purpose of integration testing is not to provide functional verification
of the module; this should be part of the testing framework of the external
project.

Certain external projects provide test suites that reside in the upstream
testing infrastructure but are written explicitly for Zephyr. These tests
may (but are not required to) be part of the Zephyr test framework.

Deprecating and removing modules
*********************************

Modules may be deprecated for reasons including, but not limited to:

* Lack of maintainership in the module
* Licensing changes in the external project
* Codebase becoming obsolete

The module information shall indicate whether a module is
deprecated and the build system shall issue a warning
when trying to build Zephyr using a deprecated module.

Deprecated modules may be removed from the Zephyr default manifest
after 2 Zephyr releases.

  .. note::

     Repositories of removed modules shall remain accessible via their
     original URL, as they are required by older Zephyr versions.


Integrate modules in Zephyr build system
****************************************

The build system variable :makevar:`ZEPHYR_MODULES` is a `CMake list`_ of
absolute paths to the directories containing Zephyr modules. These modules
contain :file:`CMakeLists.txt` and :file:`Kconfig` files describing how to
build and configure them, respectively. Module :file:`CMakeLists.txt` files are
added to the build using CMake's `add_subdirectory()`_ command, and the
:file:`Kconfig` files are included in the build's Kconfig menu tree.

If you have :ref:`west <west>` installed, you don't need to worry about how
this variable is defined unless you are adding a new module. The build system
knows how to use west to set :makevar:`ZEPHYR_MODULES`. You can add additional
modules to this list by setting the :makevar:`EXTRA_ZEPHYR_MODULES` CMake
variable or by adding a :makevar:`EXTRA_ZEPHYR_MODULES` line to ``.zephyrrc``
(See the section on :ref:`env_vars` for more details). This can be
useful if you want to keep the list of modules found with west and also add
your own.

.. note::
   If the module ``FOO`` is provided by :ref:`west <west>` but also given with
   ``-DEXTRA_ZEPHYR_MODULES=/<path>/foo`` then the module given by the command
   line variable :makevar:`EXTRA_ZEPHYR_MODULES` will take precedence.
   This allows you to use a custom version of ``FOO`` when building and still
   use other Zephyr modules provided by :ref:`west <west>`.
   This can for example be useful for special test purposes.

If you want to permanently add modules to the zephyr workspace and you are
using zephyr as your manifest repository, you can also add a west manifest file
into the :zephyr_file:`submanifests` directory. See
:zephyr_file:`submanifests/README.txt` for more details.

See :ref:`west-basics` for more on west workspaces.

Finally, you can also specify the list of modules yourself in various ways, or
not use modules at all if your application doesn't need them.

.. _module-yml:

Module yaml file description
****************************

A module can be described using a file named :file:`zephyr/module.yml`.
The format of :file:`zephyr/module.yml` is described in the following:

Module name
===========

Each Zephyr module is given a name by which it can be referred to in the build
system.

The name should be specified in the :file:`zephyr/module.yml` file. This will
ensure the module name is not changeable through user-defined directory names
or ``west`` manifest files:

.. code-block:: yaml

   name: <name>

In CMake the location of the Zephyr module can then be referred to using the
CMake variable ``ZEPHYR_<MODULE_NAME>_MODULE_DIR`` and the variable
``ZEPHYR_<MODULE_NAME>_CMAKE_DIR`` holds the location of the directory
containing the module's :file:`CMakeLists.txt` file.

.. note::
   When used for CMake and Kconfig variables, all letters in module names are
   converted to uppercase and all non-alphanumeric characters are converted
   to underscores (_).
   As example, the module ``foo-bar`` must be referred to as
   ``ZEPHYR_FOO_BAR_MODULE_DIR`` in CMake and Kconfig.

Here is an example for the Zephyr module ``foo``:

.. code-block:: yaml

   name: foo

.. note::
   If the ``name`` field is not specified then the Zephyr module name will be
   set to the name of the module folder.
   As example, the Zephyr module located in :file:`<workspace>/modules/bar` will
   use ``bar`` as its module name if nothing is specified in
   :file:`zephyr/module.yml`.

Module integration files (in-module)
====================================

Inclusion of build files, :file:`CMakeLists.txt` and :file:`Kconfig`, can be
described as:

.. code-block:: yaml

   build:
     cmake: <cmake-directory>
     kconfig: <directory>/Kconfig

The ``cmake: <cmake-directory>`` part specifies that
:file:`<cmake-directory>` contains the :file:`CMakeLists.txt` to use. The
``kconfig: <directory>/Kconfig`` part specifies the Kconfig file to use.
Neither is required: ``cmake`` defaults to ``zephyr``, and ``kconfig``
defaults to ``zephyr/Kconfig``.

Here is an example :file:`module.yml` file referring to
:file:`CMakeLists.txt` and :file:`Kconfig` files in the root directory of the
module:

.. code-block:: yaml

   build:
     cmake: .
     kconfig: Kconfig

.. _sysbuild_module_integration:

Sysbuild integration
====================

:ref:`Sysbuild<sysbuild>` is the Zephyr build system that allows for building
multiple images as part of a single application, the sysbuild build process
can be extended externally with modules as needed, for example to add custom
build steps or add additional targets to a build. Inclusion of
sysbuild-specific build files, :file:`CMakeLists.txt` and :file:`Kconfig`, can
be described as:

.. code-block:: yaml

   build:
     sysbuild-cmake: <cmake-directory>
     sysbuild-kconfig: <directory>/Kconfig

The ``sysbuild-cmake: <cmake-directory>`` part specifies that
:file:`<cmake-directory>` contains the :file:`CMakeLists.txt` to use. The
``sysbuild-kconfig: <directory>/Kconfig`` part specifies the Kconfig file to
use.

Here is an example :file:`module.yml` file referring to
:file:`CMakeLists.txt` and :file:`Kconfig` files in the `sysbuild` directory of
the module:

.. code-block:: yaml

   build:
     sysbuild-cmake: sysbuild
     sysbuild-kconfig: sysbuild/Kconfig

The module description file :file:`zephyr/module.yml` can also be used to
specify that the build files, :file:`CMakeLists.txt` and :file:`Kconfig`, are
located in a :ref:`modules_module_ext_root`.

Build files located in a ``MODULE_EXT_ROOT`` can be described as:

.. code-block:: yaml

   build:
     sysbuild-cmake-ext: True
     sysbuild-kconfig-ext: True

This allows control of the build inclusion to be described externally to the
Zephyr module.

.. _modules-vulnerability-monitoring:

Vulnerability monitoring
========================

The module description file :file:`zephyr/module.yml` can be used to improve vulnerability monitoring.

If your module needs to track vulnerabilities using an external reference
(e.g your module is forked from another repository), you can use the ``security`` section.
It contains the field ``external-references`` that contains a list of references that needs to
be monitored for your module. The supported formats are:

- CPE (Common Platform Enumeration)
- PURL (Package URL)

.. code-block:: yaml

   security:
     external-references:
       - <module-related-cpe>
       - <an-other-module-related-cpe>
       - <module-related-purl>

A real life example for `mbedTLS` module could look like this:

.. code-block:: yaml

   security:
     external-references:
       - cpe:2.3:a:arm:mbed_tls:3.5.2:*:*:*:*:*:*:*
       - pkg:github/Mbed-TLS/[email protected]

.. note::
   CPE field must follow the CPE 2.3 schema provided by `NVD
   <https://csrc.nist.gov/projects/security-content-automation-protocol/specifications/cpe>`_.
   PURL field must follow the PURL specification provided by `Github
   <https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst>`_.


Build system integration
========================

When a module has a :file:`module.yml` file, it will automatically be included into
the Zephyr build system. The path to the module is then accessible through Kconfig
and CMake variables.

Zephyr modules
--------------

In both Kconfig and CMake, the variable ``ZEPHYR_<MODULE_NAME>_MODULE_DIR``
contains the absolute path to the module.

In CMake, ``ZEPHYR_<MODULE_NAME>_CMAKE_DIR`` contains the
absolute path to the directory containing the :file:`CMakeLists.txt` file that
is included into CMake build system. This variable's value is empty if the
module.yml file does not specify a CMakeLists.txt.

To read these variables for a Zephyr module named ``foo``:

- In CMake: use ``${ZEPHYR_FOO_MODULE_DIR}`` for the module's top level directory, and ``${ZEPHYR_FOO_CMAKE_DIR}`` for the directory containing its :file:`CMakeLists.txt`
- In Kconfig: use ``$(ZEPHYR_FOO_MODULE_DIR)`` for the module's top level directory

Notice how a lowercase module name ``foo`` is capitalized to ``FOO``
in both CMake and Kconfig.

These variables can also be used to test whether a given module exists.
For example, to verify that ``foo`` is the name of a Zephyr module:

.. code-block:: cmake

  if(ZEPHYR_FOO_MODULE_DIR)
    # Do something if FOO exists.
  endif()

In Kconfig, the variable may be used to find additional files to include.
For example, to include the file :file:`some/Kconfig` in module ``foo``:

.. code-block:: kconfig

  source "$(ZEPHYR_FOO_MODULE_DIR)/some/Kconfig"

During CMake processing of each Zephyr module, the following variables are
also available:

- the current module's name: ``${ZEPHYR_CURRENT_MODULE_NAME}``
- the current module's top level directory: ``${ZEPHYR_CURRENT_MODULE_DIR}``
- the current module's :file:`CMakeLists.txt` directory: ``${ZEPHYR_CURRENT_CMAKE_DIR}``

This removes the need for a Zephyr module to know its own name during CMake
processing. The module can source additional CMake files using these ``CURRENT``
variables. For example:

.. code-block:: cmake

  include(${ZEPHYR_CURRENT_MODULE_DIR}/cmake/code.cmake)

It is possible to append values to a Zephyr `CMake list`_ variable from the module's first
CMakeLists.txt file.
To do so, append the value to the list and then set the list in the PARENT_SCOPE
of the CMakeLists.txt file. For example, to append ``bar`` to the ``FOO_LIST`` variable in the
Zephyr CMakeLists.txt scope:

.. code-block:: cmake

  list(APPEND FOO_LIST bar)
  set(FOO_LIST ${FOO_LIST} PARENT_SCOPE)

An example of a Zephyr list where this is useful is when adding additional
directories to the ``SYSCALL_INCLUDE_DIRS`` list.

Sysbuild modules
----------------

In both Kconfig and CMake, the variable ``SYSBUILD_CURRENT_MODULE_DIR``
contains the absolute path to the sysbuild module. In CMake,
``SYSBUILD_CURRENT_CMAKE_DIR`` contains the absolute path to the directory
containing the :file:`CMakeLists.txt` file that is included into CMake build
system. This variable's value is empty if the module.yml file does not specify
a CMakeLists.txt.

To read these variables for a sysbuild module:

- In CMake: use ``${SYSBUILD_CURRENT_MODULE_DIR}`` for the module's top level
  directory, and ``${SYSBUILD_CURRENT_CMAKE_DIR}`` for the directory containing
  its :file:`CMakeLists.txt`
- In Kconfig: use ``$(SYSBUILD_CURRENT_MODULE_DIR)`` for the module's top level
  directory

In Kconfig, the variable may be used to find additional files to include.
For example, to include the file :file:`some/Kconfig`:

.. code-block:: kconfig

  source "$(SYSBUILD_CURRENT_MODULE_DIR)/some/Kconfig"

The module can source additional CMake files using these variables. For
example:

.. code-block:: cmake

  include(${SYSBUILD_CURRENT_MODULE_DIR}/cmake/code.cmake)

It is possible to append values to a Zephyr `CMake list`_ variable from the
module's first CMakeLists.txt file.
To do so, append the value to the list and then set the list in the
PARENT_SCOPE of the CMakeLists.txt file. For example, to append ``bar`` to the
``FOO_LIST`` variable in the Zephyr CMakeLists.txt scope:

.. code-block:: cmake

  list(APPEND FOO_LIST bar)
  set(FOO_LIST ${FOO_LIST} PARENT_SCOPE)

Sysbuild modules hooks
----------------------

Sysbuild provides an infrastructure which allows a sysbuild module to define
a function which will be invoked by sysbuild at a pre-defined point in the
CMake flow.

Functions invoked by sysbuild:

- ``<module-name>_pre_cmake(IMAGES <images>)``: This function is called for each
  sysbuild module before CMake configure is invoked for all images.
- ``<module-name>_post_cmake(IMAGES <images>)``: This function is called for each
  sysbuild module after CMake configure has completed for all images.
- ``<module-name>_pre_domains(IMAGES <images>)``: This function is called for each
  sysbuild module before domains yaml is created by sysbuild.
- ``<module-name>_post_domains(IMAGES <images>)``: This function is called for each
  sysbuild module after domains yaml has been created by sysbuild.

arguments passed from sysbuild to the function defined by a module:

- ``<images>`` is the list of Zephyr images that will be created by the build system.

If a module ``foo`` want to provide a post CMake configure function, then the
module's sysbuild :file:`CMakeLists.txt` file must define function ``foo_post_cmake()``.

To facilitate naming of functions, the module name is provided by sysbuild CMake
through the ``SYSBUILD_CURRENT_MODULE_NAME`` CMake variable when loading the
module's sysbuild :file:`CMakeLists.txt` file.

Example of how the ``foo`` sysbuild module can define ``foo_post_cmake()``:

.. code-block:: cmake

   function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake)
     cmake_parse_arguments(POST_CMAKE "" "" "IMAGES" ${ARGN})

     message("Invoking ${CMAKE_CURRENT_FUNCTION}. Images: ${POST_CMAKE_IMAGES}")
   endfunction()

Zephyr module dependencies
==========================

A Zephyr module may be dependent on other Zephyr modules to be present in order
to function correctly. Or it might be that a given Zephyr module must be
processed after another Zephyr module, due to dependencies of certain CMake
targets.

Such a dependency can be described using the ``depends`` field.

.. code-block:: yaml

   build:
     depends:
       - <module>

Here is an example for the Zephyr module ``foo`` that is dependent on the Zephyr
module ``bar`` to be present in the build system:

.. code-block:: yaml

   name: foo
   build:
     depends:
       - bar

This example will ensure that ``bar`` is present when ``foo`` is included into
the build system, and it will also ensure that ``bar`` is processed before
``foo``.

.. _modules_module_ext_root:

Module integration files (external)
===================================

Module integration files can be located externally to the Zephyr module itself.
The ``MODULE_EXT_ROOT`` variable holds a list of roots containing integration
files located externally to Zephyr modules.

Module integration files in Zephyr
----------------------------------

The Zephyr repository contain :file:`CMakeLists.txt` and :file:`Kconfig` build
files for certain known Zephyr modules.

Those files are located under

.. code-block:: none

   <ZEPHYR_BASE>
   └── modules
       └── <module_name>
           ├── CMakeLists.txt
           └── Kconfig

Module integration files in a custom location
---------------------------------------------

You can create a similar ``MODULE_EXT_ROOT`` for additional modules, and make
those modules known to Zephyr build system.

Create a ``MODULE_EXT_ROOT`` with the following structure

.. code-block:: none

   <MODULE_EXT_ROOT>
   └── modules
       ├── modules.cmake
       └── <module_name>
           ├── CMakeLists.txt
           └── Kconfig

and then build your application by specifying ``-DMODULE_EXT_ROOT`` parameter to
the CMake build system. The ``MODULE_EXT_ROOT`` accepts a `CMake list`_ of roots as
argument.

A Zephyr module can automatically be added to the ``MODULE_EXT_ROOT``
list using the module description file :file:`zephyr/module.yml`, see
:ref:`modules_build_settings`.

.. note::

   ``ZEPHYR_BASE`` is always added as a ``MODULE_EXT_ROOT`` with the lowest
   priority.
   This allows you to overrule any integration files under
   ``<ZEPHYR_BASE>/modules/<module_name>`` with your own implementation your own
   ``MODULE_EXT_ROOT``.

The :file:`modules.cmake` file must contain the logic that specifies the
integration files for Zephyr modules via specifically named CMake variables.

To include a module's CMake file, set the variable ``ZEPHYR_<MODULE_NAME>_CMAKE_DIR``
to the path containing the CMake file.

To include a module's Kconfig file, set the variable ``ZEPHYR_<MODULE_NAME>_KCONFIG``
to the path to the Kconfig file.

The following is an example on how to add support the ``FOO`` module.

Create the following structure

.. code-block:: none

   <MODULE_EXT_ROOT>
   └── modules
       ├── modules.cmake
       └── foo
           ├── CMakeLists.txt
           └── Kconfig

and inside the :file:`modules.cmake` file, add the following content

.. code-block:: cmake

   set(ZEPHYR_FOO_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR}/foo)
   set(ZEPHYR_FOO_KCONFIG   ${CMAKE_CURRENT_LIST_DIR}/foo/Kconfig)

Module integration files (zephyr/module.yml)
--------------------------------------------

The module description file :file:`zephyr/module.yml` can be used to specify
that the build files, :file:`CMakeLists.txt` and :file:`Kconfig`, are located
in a :ref:`modules_module_ext_root`.

Build files located in a ``MODULE_EXT_ROOT`` can be described as:

.. code-block:: yaml

   build:
     cmake-ext: True
     kconfig-ext: True

This allows control of the build inclusion to be described externally to the
Zephyr module.

The Zephyr repository itself is always added as a Zephyr module ext root.

.. _modules_build_settings:

Build settings
==============

It is possible to specify additional build settings that must be used when
including the module into the build system.

All ``root`` settings are relative to the root of the module.

Build settings supported in the :file:`module.yml` file are:

- ``board_root``: Contains additional boards that are available to the build
  system. Additional boards must be located in a :file:`<board_root>/boards`
  folder.
- ``dts_root``: Contains additional dts files related to the architecture/soc
  families. Additional dts files must be located in a :file:`<dts_root>/dts`
  folder.
- ``snippet_root``: Contains additional snippets that are available for use.
  These snippets must be defined in :file:`snippet.yml` files underneath the
  :file:`<snippet_root>/snippets` folder. For example, if you have
  ``snippet_root: foo``, then you should place your module's
  :file:`snippet.yml` files in :file:`<your-module>/foo/snippets` or any
  nested subdirectory.
- ``soc_root``: Contains additional SoCs that are available to the build
  system. Additional SoCs must be located in a :file:`<soc_root>/soc` folder.
- ``arch_root``: Contains additional architectures that are available to the
  build system. Additional architectures must be located in a
  :file:`<arch_root>/arch` folder.
- ``module_ext_root``: Contains :file:`CMakeLists.txt` and :file:`Kconfig` files
  for Zephyr modules, see also :ref:`modules_module_ext_root`.
- ``sca_root``: Contains additional :ref:`SCA <sca>` tool implementations
  available to the build system. Each tool must be located in
  :file:`<sca_root>/sca/<tool>` folder. The folder must contain a
  :file:`sca.cmake`.

Example of a :file:`module.yaml` file containing additional roots, and the
corresponding file system layout.

.. code-block:: yaml

   build:
     settings:
       board_root: .
       dts_root: .
       soc_root: .
       arch_root: .
       module_ext_root: .


requires the following folder structure:

.. code-block:: none

   <zephyr-module-root>
   ├── arch
   ├── boards
   ├── dts
   ├── modules
   └── soc

Twister (Test Runner)
=====================

To execute both tests and samples available in modules, the Zephyr test runner
(twister) should be pointed to the directories containing those samples and
tests. This can be done by specifying the path to both samples and tests in the
:file:`zephyr/module.yml` file.  Additionally, if a module defines out of tree
boards, the module file can point twister to the path where those files
are maintained in the module. For example:


.. code-block:: yaml

    build:
      cmake: .
    samples:
      - samples
    tests:
      - tests
    boards:
      - boards

.. _modules-bin-blobs:

Binary Blobs
============

Zephyr supports fetching and using :ref:`binary blobs <bin-blobs>`, and their
metadata is contained entirely in :file:`zephyr/module.yml`. This is because
a binary blob must always be associated with a Zephyr module, and thus the
blob metadata belongs in the module's description itself.

Binary blobs are fetched using :ref:`west blobs <west-blobs>`.  If ``west`` is
:ref:`not used <modules_without_west>`, they must be downloaded and
verified manually.

The ``blobs`` section in :file:`zephyr/module.yml` consists of a sequence of
maps, each of which has the following entries:

- ``path``: The path to the binary blob, relative to the :file:`zephyr/blobs/`
  folder in the module repository
- ``sha256``: `SHA-256 <https://en.wikipedia.org/wiki/SHA-2>`_ checksum of the
  binary blob file
- ``type``: The :ref:`type of binary blob <bin-blobs-types>`. Currently limited
  to ``img`` or ``lib``
- ``version``: A version string
- ``license-path``: Path to the license file for this blob, relative to the root
  of the module repository
- ``url``: URL that identifies the location the blob will be fetched from, as
  well as the fetching scheme to use
- ``description``: Human-readable description of the binary blob
- ``doc-url``: A URL pointing to the location of the official documentation for
  this blob

Module Inclusion
================

.. _modules_using_west:

Using West
----------

If west is installed and :makevar:`ZEPHYR_MODULES` is not already set, the
build system finds all the modules in your :term:`west installation` and uses
those. It does this by running :ref:`west list <west-built-in-misc>` to get
the paths of all the projects in the installation, then filters the results to
just those projects which have the necessary module metadata files.

Each project in the ``west list`` output is tested like this:

- If the project contains a file named :file:`zephyr/module.yml`, then the
  content of that file will be used to determine which files should be added
  to the build, as described in the previous section.

- Otherwise (i.e. if the project has no :file:`zephyr/module.yml`), the
  build system looks for :file:`zephyr/CMakeLists.txt` and
  :file:`zephyr/Kconfig` files in the project. If both are present, the project
  is considered a module, and those files will be added to the build.

- If neither of those checks succeed, the project is not considered a module,
  and is not added to :makevar:`ZEPHYR_MODULES`.

.. _modules_without_west:

Without West
------------

If you don't have west installed or don't want the build system to use it to
find Zephyr modules, you can set :makevar:`ZEPHYR_MODULES` yourself using one
of the following options. Each of the directories in the list must contain
either a :file:`zephyr/module.yml` file or the files
:file:`zephyr/CMakeLists.txt` and :file:`Kconfig`, as described in the previous
section.

#. At the CMake command line, like this:

   .. code-block:: console

      cmake -DZEPHYR_MODULES=<path-to-module1>[;<path-to-module2>[...]] ...

#. At the top of your application's top level :file:`CMakeLists.txt`, like this:

   .. code-block:: cmake

      set(ZEPHYR_MODULES <path-to-module1> <path-to-module2> [...])
      find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

   If you choose this option, make sure to set the variable **before**  calling
   ``find_package(Zephyr ...)``, as shown above.

#. In a separate CMake script which is pre-loaded to populate the CMake cache,
   like this:

   .. code-block:: cmake

      # Put this in a file with a name like "zephyr-modules.cmake"
      set(ZEPHYR_MODULES <path-to-module1> <path-to-module2>
        CACHE STRING "pre-cached modules")

   You can tell the build system to use this file by adding ``-C
   zephyr-modules.cmake`` to your CMake command line.

Not using modules
-----------------

If you don't have west installed and don't specify :makevar:`ZEPHYR_MODULES`
yourself, then no additional modules are added to the build. You will still be
able to build any applications that don't require code or Kconfig options
defined in an external repository.

Submitting changes to modules
******************************

When submitting new or making changes to existing modules the main repository
Zephyr needs a reference to the changes to be able to verify the changes. In the
main tree this is done using revisions. For code that is already merged and part
of the tree we use the commit hash, a tag, or a branch name. For pull requests
however, we require specifying the pull request number in the revision field to
allow building the zephyr main tree with the changes submitted to the
module.

To avoid merging changes to master with pull request information, the pull
request should be marked as ``DNM`` (Do Not Merge) or preferably a draft pull
request to make sure it is not merged by mistake and to allow for the module to
be merged first and be assigned a permanent commit hash. Drafts reduce noise by
not automatically notifying anyone until marked as "Ready for review".
Once the module is
merged, the revision will need to be changed either by the submitter or by the
maintainer to the commit hash of the module which reflects the changes.

Note that multiple and dependent changes to different modules can be submitted
using exactly the same process. In this case you will change multiple entries of
all modules that have a pull request against them.

.. _submitting_new_modules:

Process for submitting a new module
===================================

Please follow the process in :ref:`external-src-process` and obtain the TSC
approval to integrate the external source code as a module

If the request is approved, a new repository will
created by the project team and initialized with basic information that would
allow submitting code to the module project following the project contribution
guidelines.

If a module is maintained as a fork of another project on Github, the Zephyr
module related files and changes in relation to upstream need to be maintained
in a special branch named ``zephyr``.

Maintainers from the Zephyr project will create the repository and initialize
it. You will be added as a collaborator in the new repository.  Submit the
module content (code) to the new repository following the guidelines described
:ref:`here <modules_using_west>`, and then add a new entry to the
:zephyr_file:`west.yml` with the following information:

   .. code-block:: console

        - name: <name of repository>
          path: <path to where the repository should be cloned>
          revision: <ref pointer to module pull request>


For example, to add *my_module* to the manifest:

.. code-block:: console

    - name: my_module
      path: modules/lib/my_module
      revision: pull/23/head


Where 23 in the example above indicated the pull request number submitted to the
*my_module* repository. Once the module changes are reviewed and merged, the
revision needs to be changed to the commit hash from the module repository.

.. _changes_to_existing_module:

Process for submitting changes to existing modules
==================================================

#. Submit the changes using a pull request to an existing repository following
   the :ref:`contribution guidelines <contribute_guidelines>` and
   :ref:`expectations <contributor-expectations>`.
#. Submit a pull request changing the entry referencing the module into the
   :zephyr_file:`west.yml` of the main Zephyr tree with the following
   information:

   .. code-block:: console

        - name: <name of repository>
          path: <path to where the repository should be cloned>
          revision: <ref pointer to module pull request>


For example, to add *my_module* to the manifest:

.. code-block:: console

    - name: my_module
      path: modules/lib/my_module
      revision: pull/23/head

Where 23 in the example above indicated the pull request number submitted to the
*my_module* repository. Once the module changes are reviewed and merged, the
revision needs to be changed to the commit hash from the module repository.



.. _CMake list: https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#lists
.. _add_subdirectory(): https://cmake.org/cmake/help/latest/command/add_subdirectory.html
.. _GitHub issues: https://github.com/zephyrproject-rtos/zephyr/issues

Part 3

한국어 전문 번역

모듈(외부 프로젝트)

Zephyr는 바퀴를 다시 발명하지 않고, 합리적인 경우 이미 검증되고 성숙한 코드를 최대한 재사용하기 위해 외부에서 유지 관리되는 여러 프로젝트의 source code에 의존합니다. Zephyr build system에서는 이러한 프로젝트를 모듈이라고 부릅니다. 모듈은 이 페이지의 다른 절에서 자세히 설명하는 방식으로 Zephyr build system과 통합해야 합니다.

외부 프로젝트가 기본 모듈 목록에 포함될 후보가 되려면 Zephyr Project 밖에서 독자적인 수명주기를 가져야 합니다. 즉, 자체 repository에 있고 자체 contribution·maintenance workflow와 release process가 있어야 합니다. Zephyr 전용으로 작성된 code는 모듈에 두지 말고 주 Zephyr tree에 기여해야 합니다.

Zephyr 기본 manifest에 포함할 모듈은 Project Technical Steering Committee가 지지하고 승인한 기능을 제공해야 하고, 모듈 라이선스 요구 사항과 기여 지침을 준수해야 합니다. 또한 모듈 codebase를 유지하겠다고 약속한 Zephyr developer가 있어야 합니다.

Zephyr가 의존하는 모듈 범주에는 다음 항목 등이 있습니다.

  • Debugger 통합
  • Silicon vendor Hardware Abstraction Layer(HAL)
  • Cryptography library
  • File system
  • Inter-Process Communication(IPC) library

일부 경우, 특히 vendor HAL 모듈에는 선택적 binary blob 참조가 포함될 수도 있습니다.

이 페이지는 Zephyr 모듈의 workflow를 더 체계적으로 구성하기 위한 정책과 권장 실무를 정리합니다.

모듈과 West 프로젝트의 차이

이 페이지에서 설명하는 Zephyr 모듈은 West project와 같지 않습니다. 모듈은 West를 전혀 요구하지 않습니다. 다만 West와 함께 모듈을 사용할 때는 build system이 West를 사용해 모듈을 찾습니다.

정리하면 다음과 같습니다.

모듈은 zephyr/module.yml file을 포함하는 repository이며, Zephyr build system이 repository의 source code를 가져올 수 있게 합니다. West project는 west.yml manifest file의 projects: section에 있는 entry입니다. West project가 모듈인 경우가 많지만 항상 그런 것은 아닙니다. 예를 들어 tool처럼 최종 firmware image에 포함되지 않아 모듈일 필요가 없는 West project도 있습니다.

Zephyr build system은 West 자체 또는 ZEPHYR_MODULES CMake variable을 통해 모듈을 찾습니다.

이 페이지의 내용은 모듈에만 적용되며, West project 자체가 모듈인 경우를 제외하면 일반적인 West project에는 적용되지 않습니다.

모듈 Repository

  • 기본 manifest에 포함되는 모든 모듈은 zephyrproject-rtos GitHub organization 아래 repository에 host해야 합니다.
  • 모듈 repository codebase에는 repository root의 zephyr/ folder 안에 module.yml file이 있어야 합니다.
  • 모듈 repository 이름은 underscore 대신 lowercase letter와 dash를 사용하는 관례를 따라야 합니다. 이 규칙은 새 모듈 repository에 적용됩니다. 다만 외부 Git repository를 직접 추적하는 프로젝트는 외부 프로젝트와 같은 이름을 사용할 수 있습니다.
  • 모듈 repository 이름은 zephyr/module.yml file에 명시적으로 설정해야 합니다.
  • 모듈은 repository main branch의 기본 이름으로 zephyr를 사용해야 합니다. LTS Zephyr version용 모듈 branch처럼 특정 목적의 branch는 zephyr_ prefix로 시작해야 합니다.
  • 모듈에 외부 upstream project repository가 있다면 upstream repository folder 구조를 보존해야 합니다.
  • 모듈은 제공하는 모든 header file을 module-name으로 시작하는 include pathname으로 노출해야 합니다. 예를 들어 mcuboot의 bootutil/bootutil.h는 mcuboot/bootutil/bootutil.h로 노출해야 합니다.

Upstream과 동기화

모듈 repository는 해당 외부 프로젝트의 최신 stable release와 동기화하는 것이 좋습니다. 다만 모듈 codebase의 중요한 update를 얻는 데 필요하면 최신 development branch tip으로 갱신할 수 있습니다. Upstream과 동기화할 때는 해당 update를 수행한 근거를 반드시 문서화해야 합니다.

허용되는 실무의 요구 사항

Upstream codebase와의 동기화를 포함해 모듈 repository main branch에 적용하는 변경은 pull request로만 적용할 수 있습니다. Pull request는 Zephyr CI가 검증할 수 있고 GitHub UI의 Rebase and merge 또는 Create a merge commit 등으로 merge할 수 있어야 합니다. 그러면 들어오는 변경을 항상 검토할 수 있고 downstream 모듈 repository history가 점진적으로 유지되어 기존 commit·tag 등이 보존됩니다. 또한 Zephyr CI, git lint, identity, license check를 모듈에 들어올 변경 집합에 직접 실행할 수 있습니다.

허용되는 실무

다음 방법은 위 요구 사항을 충족하며 모든 모듈 repository에서 따라야 합니다. 모듈 code owner가 동기화 방법을 선택할 수 있지만, 선택한 방법은 해당 repository에서 일관되게 사용해야 합니다.

Upstream diff로 모듈 갱신: upstream 변경을 하나의 snapshot commit(manual diff)으로 만들어 모듈 main branch 대상 pull request에 넣고 Rebase & merge로 merge할 수 있습니다. 단순하고 모든 모듈에 적용할 수 있지만 모듈 repository에서 upstream history가 사라진다는 단점이 있습니다.

Commit message에는 upstream project URL, 갱신한 version(upstream version, tag, commit SHA 등)과 갱신 이유를 적어야 합니다.

Upstream branch를 merge해 모듈 갱신: 대상 upstream branch(main, 최신 release branch 등)를 Git merge하고 그 결과를 모듈 main branch 대상 pull request로 제출한 뒤 Create a merge commit으로 merge합니다. Upstream Git repository가 있는 모듈에 적용할 수 있습니다. 원래 commit SHA를 포함한 upstream history가 모듈 repository에 보존되는 장점이 있지만 downstream main branch에 merge commit이 두 개 추가됩니다.

Zephyr 모듈에 기여

개별 역할과 책임

Zephyr 모듈 repository 관리를 돕기 위해 다음 역할을 정의합니다.

Administrator: 각 Zephyr 모듈에는 repository 접근을 관리할 administrator가 있어야 합니다. 예를 들어 module owner의 요청에 따라 개인을 repository collaborator로 추가합니다. Module administrator는 모듈 GitHub repository에 admin 권한을 가진 project member 집단인 Administrators team의 member입니다.

Module owner: 각 모듈에는 module code owner가 있어야 하며 Zephyr 모듈 repository 내용에 대한 전반적인 책임을 집니다. 특히 다음을 수행합니다.

  • 모듈 repository의 code review 조정
  • Repository main branch 대상 pull request의 기본 assignee 역할
  • 필요하다고 판단하면 추가 collaborator 등록 요청
  • 동기화 정책에 따라 upstream counterpart와 repository를 정기적으로 동기화
  • 외부 프로젝트의 security vulnerability를 파악하고 upstream에 fix가 제공되는 즉시 모듈 repository에 반영
  • 모듈 codebase에 있는 알려진 security vulnerability를 Zephyr release note에 기록

Merger: Zephyr Release Engineering team은 모듈 repository main branch의 승인된 pull request를 merge할 권리와 책임을 가집니다.

모듈 codebase 유지 관리

공개 Zephyr API 변경 같은 Zephyr main tree update 때문에 모듈 codebase를 patch해야 할 수 있습니다. 책임은 Zephyr 변경의 contributor와 module owner가 함께 집니다.

  • Zephyr 원래 변경의 contributor는 모듈 repository에 필요한 대응 변경도 제출해야 합니다. 원래 변경 pull request의 Zephyr CI와 모듈 integration test가 성공하도록 해야 합니다.
  • Module owner는 모듈 codebase를 Zephyr main tree와 동기화하고 test할 전반적인 책임을 집니다. Zephyr CI 외의 고급 test를 필요할 때 수행하고 pull request CI가 잡지 못한 모듈 문제를 수정해야 합니다.

모듈 변경에 기여

대응 외부 프로젝트 repository에 먼저 merge되기 전에 모듈 codebase에 직접 변경을 제출하고 merge하는 경우는 다음으로 제한해야 합니다.

  • Zephyr main tree update 때문에 필요한 변경
  • Security vulnerability fix처럼 외부 프로젝트 merge를 기다릴 수 없는 긴급 변경

모듈에 upstream project repository가 있다면 설계나 기능 변경을 포함한 사소하지 않은 codebase 변경은 피해야 하며 upstream project에 직접 제출해야 합니다.

모듈 변경 제출 절에서 모듈 repository에 기여하는 절차를 자세히 설명합니다.

기여 지침

Zephyr 모듈 기여는 project의 일반 Contribution guideline을 따라야 합니다.

Pull request: PR assignee의 승인을 포함해 최소 2개 승인을 받으면 merge할 수 있습니다. 또한 이 페이지에서 설명하는 Zephyr CI tool로 변경을 검증한 경우에만 merge할 수 있습니다.

모듈 repository main branch의 pull request merge는 Zephyr main tree의 해당 manifest file update와 함께 이루어져야 합니다.

Issue 보고: 모듈 repository에서는 중앙 집중식 issue reporting 정책을 위해 GitHub issue를 의도적으로 비활성화합니다. 모듈 bug나 enhancement ticket은 주 Zephyr repository에 열고, 가능한 경우 각 모듈에 대응하는 GitHub label을 지정해야 합니다.

라이선스 요구 사항과 정책

모듈 repository에 license header가 없는 source file을 포괄하는 main license file이 없다면 모든 source file에 license header가 있어야 합니다.

Main license file은 외부 프로젝트에 실제로 존재하고 permissive OSI-compliant license를 담은 경우에만 Zephyr developer가 모듈 codebase에 추가해야 합니다. SPDX license identifier만 두기보다 전체 license text를 포함하는 것이 좋습니다. Main license file이 여러 개라면 각 source file에 어느 license가 적용되는지 명확해야 합니다.

모듈 source file의 개별 license header는 main license보다 우선합니다.

모듈 repository에 추가하는 모든 새 content는 license 적용 범위에 들어가야 합니다.

라이선스 정책

모듈 repository를 만들 때 developer는 다음을 수행해야 합니다.

  • 외부 프로젝트에 main license file이 있다면 import
  • 모듈 codebase를 포괄하는 기본 license를 module README 또는 .yml file 등에 문서화

라이선스 검사

모듈 repository에 새 content를 추가하는 모든 pull request에서 CI tool을 통한 license check를 활성화해야 합니다.

문서 요구 사항

모든 Zephyr 모듈 repository에는 다음 내용을 문서화하는 .rst file이 있어야 합니다.

  • 모듈의 범위와 목적
  • 모듈이 Zephyr와 통합되는 방식
  • 모듈 repository owner
  • 외부 프로젝트와의 동기화 정보(commit, SHA, version 등)
  • 모듈 라이선스에서 설명한 license 정보

이 file은 모듈 포함의 필수 조건이며 내용은 최신 상태로 유지해야 합니다.

테스트 요구 사항

모든 Zephyr 모듈은 Zephyr와의 통합이 올바르게 동작하는지 보장하는 일정 수준의 integration test를 제공해야 합니다.

Integration test는 다음 요구를 따릅니다.

  • Zephyr main tree에 있는 최소한의 sample과 test 집합 형태일 수 있습니다.
  • Zephyr와 통합된 모듈의 기본 사용(configuration, functional API 등)을 검증해야 합니다.
  • 모듈 repository 변경을 도입하는 pull request의 Twister run에서 build하고 QEMU 등으로 실행해야 합니다.

Integration test의 목적은 모듈 자체의 기능 검증이 아닙니다. 기능 검증은 외부 프로젝트의 test framework에서 수행해야 합니다.

일부 외부 프로젝트는 upstream test infrastructure 안에 있지만 Zephyr용으로 명시적으로 작성한 test suite를 제공합니다. 이러한 test는 Zephyr test framework에 포함될 수 있지만 필수는 아닙니다.

모듈 사용 중단과 제거

다음과 같은 이유로 모듈을 deprecated할 수 있습니다.

  • 모듈 maintainer 부족
  • 외부 프로젝트의 license 변경
  • Codebase의 노후화

모듈 정보는 deprecated 상태를 표시해야 하고, deprecated 모듈로 Zephyr를 build하려 하면 build system이 warning을 출력해야 합니다.

Deprecated 모듈은 Zephyr release 두 번이 지난 뒤 기본 manifest에서 제거할 수 있습니다.

Zephyr build system에 모듈 통합

ZEPHYR_MODULES build system variable은 Zephyr 모듈 directory의 absolute path를 담는 CMake list입니다. 모듈의 CMakeLists.txt와 Kconfig는 각각 build 방법과 configuration 방법을 설명합니다. Module CMakeLists.txt는 CMake add_subdirectory()로 build에 추가되고 Kconfig file은 build의 Kconfig menu tree에 포함됩니다.

West가 설치되어 있으면 새 모듈을 추가하는 경우를 제외하고 이 variable 정의를 직접 다룰 필요가 없습니다. Build system이 West를 통해 ZEPHYR_MODULES를 설정합니다. EXTRA_ZEPHYR_MODULES CMake variable 또는 .zephyrrc의 같은 이름 항목으로 모듈을 더 추가할 수 있습니다. 이는 West가 찾은 모듈을 유지하면서 자체 모듈을 추가할 때 유용합니다.

Zephyr를 manifest repository로 사용하면서 workspace에 모듈을 영구 추가하려면 submanifests directory에 West manifest file을 추가할 수도 있습니다. 자세한 내용은 submanifests/README.txt를 참조하십시오.

West workspace 기초에서 자세한 내용을 확인할 수 있습니다.

마지막으로 모듈 목록을 여러 방법으로 직접 지정하거나 application에 필요하지 않다면 모듈을 전혀 사용하지 않을 수 있습니다.

Module YAML file 설명

zephyr/module.yml file로 모듈을 설명할 수 있습니다. 형식은 다음 절에서 정의합니다.

모듈 이름

각 Zephyr 모듈에는 build system에서 참조할 이름이 부여됩니다.

zephyr/module.yml에 이름을 지정하면 user-defined directory name이나 West manifest file 때문에 모듈 이름이 바뀌지 않습니다.

name: <name>

CMake에서는 ZEPHYR_<MODULE_NAME>_MODULE_DIR로 Zephyr module 위치를 참조하고 ZEPHYR_<MODULE_NAME>_CMAKE_DIR로 모듈 CMakeLists.txt가 있는 directory를 참조할 수 있습니다.

foo 모듈의 예:

name: foo

모듈 내부 통합 file

CMakeLists.txt와 Kconfig build file 포함 방법은 다음과 같이 설명합니다.

build:
  cmake: <cmake-directory>
  kconfig: <directory>/Kconfig

cmake: <cmake-directory>는 사용할 CMakeLists.txt가 있는 directory를 지정하고 kconfig: <directory>/Kconfig는 사용할 Kconfig file을 지정합니다. 둘 다 필수는 아닙니다. cmake 기본값은 zephyr, kconfig 기본값은 zephyr/Kconfig입니다.

모듈 root의 CMakeLists.txt와 Kconfig를 참조하는 예:

build:
  cmake: .
  kconfig: Kconfig

Sysbuild 통합

Sysbuild는 하나의 application에서 여러 image를 build할 수 있는 Zephyr build system입니다. Custom build step이나 추가 target이 필요할 때 module로 sysbuild process를 확장할 수 있습니다. Sysbuild 전용 CMakeLists.txt와 Kconfig 포함은 다음과 같이 설명합니다.

build:
  sysbuild-cmake: <cmake-directory>
  sysbuild-kconfig: <directory>/Kconfig

sysbuild-cmake: <cmake-directory>는 CMakeLists.txt directory를, sysbuild-kconfig: <directory>/Kconfig는 Kconfig file을 지정합니다.

모듈의 sysbuild directory를 참조하는 예:

build:
  sysbuild-cmake: sysbuild
  sysbuild-kconfig: sysbuild/Kconfig

zephyr/module.yml은 build file이 외부 MODULE_EXT_ROOT에 있음을 지정할 수도 있습니다.

build:
  sysbuild-cmake-ext: True
  sysbuild-kconfig-ext: True

이를 통해 build 포함 제어를 Zephyr module 밖에서 설명할 수 있습니다.

Vulnerability monitoring

zephyr/module.yml로 vulnerability monitoring을 개선할 수 있습니다.

모듈이 다른 repository에서 fork되어 외부 참조로 vulnerability를 추적해야 한다면 security section을 사용할 수 있습니다. external-references field에는 모니터링할 참조 목록을 넣습니다. 지원 형식:

  • CPE(Common Platform Enumeration)
  • PURL(Package URL)
security:
  external-references:
    - <module-related-cpe>
    - <an-other-module-related-cpe>
    - <module-related-purl>

mbedTLS 모듈의 실제 형태 예:

security:
  external-references:
    - cpe:2.3:a:arm:mbed_tls:3.5.2:*:*:*:*:*:*:*
    - pkg:github/Mbed-TLS/[email protected]

Build system 통합

module.yml이 있는 모듈은 Zephyr build system에 자동으로 포함됩니다. 모듈 path는 Kconfig와 CMake variable로 접근할 수 있습니다.

Zephyr 모듈

Kconfig와 CMake 모두에서 ZEPHYR_<MODULE_NAME>_MODULE_DIR는 module absolute path를 담습니다.

ZEPHYR_<MODULE_NAME>_CMAKE_DIR는 포함된 CMakeLists.txt가 있는 directory의 absolute path입니다. module.yml이 CMakeLists.txt를 지정하지 않으면 값이 비어 있습니다.

foo 모듈에서 이 variable을 읽는 방법:

  • CMake: module root는 ${ZEPHYR_FOO_MODULE_DIR}, CMakeLists.txt directory는 ${ZEPHYR_FOO_CMAKE_DIR}
  • Kconfig: module root는 $(ZEPHYR_FOO_MODULE_DIR)

Lowercase 이름 foo가 CMake와 Kconfig에서 FOO로 바뀌는 점에 유의하십시오.

이 variable로 모듈 존재 여부도 검사할 수 있습니다.

if(ZEPHYR_FOO_MODULE_DIR)
  # Do something if FOO exists.
endif()

Kconfig에서는 variable을 사용해 추가 include file을 찾을 수 있습니다.

source "$(ZEPHYR_FOO_MODULE_DIR)/some/Kconfig"

각 Zephyr module의 CMake processing 중에는 다음 variable도 사용할 수 있습니다.

  • 현재 모듈 이름: ${ZEPHYR_CURRENT_MODULE_NAME}
  • 현재 모듈 top-level directory: ${ZEPHYR_CURRENT_MODULE_DIR}
  • 현재 모듈 CMakeLists.txt directory: ${ZEPHYR_CURRENT_CMAKE_DIR}

이 CURRENT variable을 사용하면 모듈이 CMake processing 중 자체 이름을 알 필요가 없습니다.

include(${ZEPHYR_CURRENT_MODULE_DIR}/cmake/code.cmake)

모듈의 첫 CMakeLists.txt에서 Zephyr CMake list variable에 값을 추가할 수 있습니다. 값을 append한 뒤 CMakeLists.txt의 PARENT_SCOPE에 list를 설정합니다. FOO_LIST에 bar를 추가하는 예:

list(APPEND FOO_LIST bar)
set(FOO_LIST ${FOO_LIST} PARENT_SCOPE)

SYSCALL_INCLUDE_DIRS에 추가 directory를 넣을 때 유용합니다.

Sysbuild 모듈

SYSBUILD_CURRENT_MODULE_DIR는 Kconfig와 CMake에서 sysbuild module absolute path를 담습니다. CMake의 SYSBUILD_CURRENT_CMAKE_DIR는 build system에 포함된 CMakeLists.txt directory absolute path이며 module.yml이 CMakeLists.txt를 지정하지 않으면 비어 있습니다.

Sysbuild module에서 읽는 방법:

  • CMake: module root는 ${SYSBUILD_CURRENT_MODULE_DIR}, CMakeLists.txt directory는 ${SYSBUILD_CURRENT_CMAKE_DIR}
  • Kconfig: module root는 $(SYSBUILD_CURRENT_MODULE_DIR)

Kconfig에서 추가 file을 include하는 예:

source "$(SYSBUILD_CURRENT_MODULE_DIR)/some/Kconfig"

CMake에서 추가 file을 include하는 예:

include(${SYSBUILD_CURRENT_MODULE_DIR}/cmake/code.cmake)

첫 CMakeLists.txt에서 list에 값을 append하고 PARENT_SCOPE에 설정하는 예:

list(APPEND FOO_LIST bar)
set(FOO_LIST ${FOO_LIST} PARENT_SCOPE)

Sysbuild 모듈 hook

Sysbuild는 module이 CMake flow의 미리 정의된 지점에서 호출될 function을 정의할 수 있는 infrastructure를 제공합니다.

Sysbuild가 호출하는 function:

  • <module-name>_pre_cmake(IMAGES <images>): 모든 image의 CMake configure 전에 각 module마다 호출
  • <module-name>_post_cmake(IMAGES <images>): 모든 image의 CMake configure가 끝난 뒤 각 module마다 호출
  • <module-name>_pre_domains(IMAGES <images>): Sysbuild가 domains YAML을 만들기 전에 호출
  • <module-name>_post_domains(IMAGES <images>): Sysbuild가 domains YAML을 만든 뒤 호출

Sysbuild가 module function에 전달하는 argument:

  • <images>: build system이 생성할 Zephyr image 목록

foo module이 post-CMake configure function을 제공하려면 sysbuild CMakeLists.txt에서 foo_post_cmake()를 정의해야 합니다. Function 이름 작성을 돕기 위해 sysbuild는 module CMakeLists.txt를 load할 때 SYSBUILD_CURRENT_MODULE_NAME variable로 module name을 제공합니다.

function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake)
  cmake_parse_arguments(POST_CMAKE "" "" "IMAGES" ${ARGN})

  message("Invoking ${CMAKE_CURRENT_FUNCTION}. Images: ${POST_CMAKE_IMAGES}")
endfunction()

Zephyr 모듈 dependency

Zephyr 모듈이 올바르게 동작하려면 다른 모듈이 있어야 하거나 특정 CMake target dependency 때문에 다른 모듈보다 뒤에 처리되어야 할 수 있습니다.

depends field로 dependency를 설명합니다.

build:
  depends:
    - <module>

bar에 의존하는 foo 모듈의 예:

name: foo
build:
  depends:
    - bar

이 예는 foo를 build system에 포함할 때 bar가 존재하고, bar를 foo보다 먼저 처리하도록 보장합니다.

외부 모듈 통합 file

모듈 통합 file은 Zephyr module 자체 밖에 둘 수 있습니다. MODULE_EXT_ROOT variable은 외부 통합 file을 담은 root 목록입니다.

Zephyr 내부의 모듈 통합 file

Zephyr repository에는 알려진 일부 Zephyr 모듈의 CMakeLists.txt와 Kconfig build file이 있습니다.

File 위치:

<ZEPHYR_BASE>
└── modules
    └── <module_name>
        ├── CMakeLists.txt
        └── Kconfig

Custom 위치의 모듈 통합 file

추가 모듈을 위한 유사한 MODULE_EXT_ROOT를 만들어 Zephyr build system에 알릴 수 있습니다.

다음 구조로 MODULE_EXT_ROOT를 만듭니다.

<MODULE_EXT_ROOT>
└── modules
    ├── modules.cmake
    └── <module_name>
        ├── CMakeLists.txt
        └── Kconfig

-DMODULE_EXT_ROOT parameter를 CMake build system에 지정해 application을 build합니다. MODULE_EXT_ROOT는 root의 CMake list를 받습니다.

zephyr/module.yml로 Zephyr module을 MODULE_EXT_ROOT 목록에 자동 추가할 수도 있습니다.

modules.cmake에는 특정 이름의 CMake variable로 Zephyr module integration file을 지정하는 logic이 있어야 합니다.

CMake file을 포함하려면 ZEPHYR_<MODULE_NAME>_CMAKE_DIR를 CMake file directory로 설정하고, Kconfig file을 포함하려면 ZEPHYR_<MODULE_NAME>_KCONFIG를 Kconfig file path로 설정합니다.

FOO 모듈 지원을 추가하는 예:

<MODULE_EXT_ROOT>
└── modules
    ├── modules.cmake
    └── foo
        ├── CMakeLists.txt
        └── Kconfig

modules.cmake 내용:

set(ZEPHYR_FOO_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR}/foo)
set(ZEPHYR_FOO_KCONFIG   ${CMAKE_CURRENT_LIST_DIR}/foo/Kconfig)

zephyr/module.yml 기반 모듈 통합 file

zephyr/module.yml은 CMakeLists.txt와 Kconfig가 MODULE_EXT_ROOT에 있음을 지정할 수 있습니다.

build:
  cmake-ext: True
  kconfig-ext: True

이를 통해 build 포함 제어를 Zephyr module 밖에서 설명할 수 있습니다. Zephyr repository 자체는 항상 Zephyr module ext root로 추가됩니다.

Build 설정

모듈을 build system에 포함할 때 사용해야 하는 추가 build 설정을 지정할 수 있습니다. 모든 root 설정은 module root 기준 상대 경로입니다.

module.yml이 지원하는 build setting:

  • board_root: 추가 board를 포함합니다. Board는 <board_root>/boards folder에 있어야 합니다.
  • dts_root: architecture/SoC family 관련 추가 DTS file을 포함합니다. <dts_root>/dts folder에 있어야 합니다.
  • snippet_root: 사용할 추가 snippet을 포함합니다. <snippet_root>/snippets 아래 snippet.yml에 정의해야 합니다. 예를 들어 snippet_root: foo이면 <your-module>/foo/snippets 또는 하위 directory에 둡니다.
  • soc_root: 추가 SoC를 포함하며 <soc_root>/soc folder에 있어야 합니다.
  • arch_root: 추가 architecture를 포함하며 <arch_root>/arch folder에 있어야 합니다.
  • module_ext_root: Zephyr module의 CMakeLists.txt와 Kconfig를 포함합니다.
  • sca_root: build system에서 사용할 추가 SCA tool 구현을 포함합니다. 각 tool은 <sca_root>/sca/<tool> folder에 있고 sca.cmake를 포함해야 합니다.

추가 root를 포함하는 module.yaml 예:

build:
  settings:
    board_root: .
    dts_root: .
    soc_root: .
    arch_root: .
    module_ext_root: .

필요한 folder 구조:

<zephyr-module-root>
├── arch
├── boards
├── dts
├── modules
└── soc

Twister(Test Runner)

모듈의 test와 sample을 모두 실행하려면 Zephyr test runner(Twister)에 해당 directory path를 알려야 합니다. module이 out-of-tree board를 정의하면 board 유지 경로도 지정할 수 있습니다.

build:
  cmake: .
samples:
  - samples
tests:
  - tests
boards:
  - boards

Binary Blob

Zephyr는 binary blob fetch와 사용을 지원하며 metadata는 전부 zephyr/module.yml에 둡니다. Binary blob은 항상 Zephyr module과 연결되므로 metadata도 module description에 속합니다.

Binary blob은 west blobs로 가져옵니다. West를 사용하지 않으면 수동으로 download하고 검증해야 합니다.

zephyr/module.yml의 blobs section은 map sequence이며 각 map은 다음 entry를 가집니다.

  • path: module repository의 zephyr/blobs/ folder 기준 binary blob 상대 path
  • sha256: binary blob file의 SHA-256 checksum
  • type: binary blob type. 현재 img 또는 lib만 지원
  • version: version string
  • license-path: module root 기준 blob license file path
  • url: blob fetch 위치와 fetch scheme을 나타내는 URL
  • description: 사람이 읽는 binary blob 설명
  • doc-url: blob 공식 문서 위치 URL

모듈 포함

West 사용

West가 설치되어 있고 ZEPHYR_MODULES가 아직 설정되지 않았다면 build system은 West installation의 모든 모듈을 찾아 사용합니다. west list로 project path를 얻은 다음 module metadata file이 있는 project만 남깁니다.

West list 결과의 각 project를 다음 순서로 검사합니다.

  • zephyr/module.yml이 있으면 그 내용으로 이전 절에서 설명한 build 추가 file을 결정합니다.
  • module.yml이 없으면 zephyr/CMakeLists.txt와 zephyr/Kconfig를 찾습니다. 둘 다 있으면 모듈로 보고 build에 추가합니다.
  • 두 검사 모두 실패하면 모듈로 보지 않고 ZEPHYR_MODULES에 추가하지 않습니다.

West 없이 사용

West가 없거나 build system이 모듈 검색에 West를 사용하지 않게 하려면 ZEPHYR_MODULES를 직접 설정합니다. 목록의 각 directory는 zephyr/module.yml 또는 zephyr/CMakeLists.txt와 Kconfig를 포함해야 합니다.

  1. CMake command line에서 지정:
    cmake -DZEPHYR_MODULES=<path-to-module1>[;<path-to-module2>[...]] ...
  2. Application top-level CMakeLists.txt의 맨 위에서 지정:
    set(ZEPHYR_MODULES <path-to-module1> <path-to-module2> [...])
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    이 방법은 위와 같이 find_package(Zephyr ...) 호출 전에 variable을 설정해야 합니다.
  3. CMake cache를 채우기 위해 미리 load하는 별도 CMake script에서 지정:
    # Put this in a file with a name like "zephyr-modules.cmake"
    set(ZEPHYR_MODULES <path-to-module1> <path-to-module2>
      CACHE STRING "pre-cached modules")
    CMake command line에 -C zephyr-modules.cmake를 추가해 이 file을 사용하게 합니다.

모듈을 사용하지 않기

ZEPHYR_MODULES를 직접 지정하지 않고 West도 설치하지 않으면 build에 추가 모듈이 들어가지 않습니다. 외부 repository의 code나 Kconfig option이 필요하지 않은 application은 계속 build할 수 있습니다.

모듈 변경 제출

새 모듈을 제출하거나 기존 모듈을 변경할 때 주 Zephyr repository가 변경을 검증할 수 있도록 참조가 필요합니다. 이미 merge된 code는 commit hash, tag 또는 branch name을 사용합니다. Pull request는 module 변경과 함께 Zephyr main tree를 build할 수 있도록 revision field에 pull request number를 지정해야 합니다.

Pull request 정보가 든 상태로 main branch에 잘못 merge되지 않도록 PR을 DNM(Do Not Merge)으로 표시하거나 draft pull request로 만드는 것이 좋습니다. Draft는 Ready for review로 표시할 때까지 자동 알림을 줄입니다. Module이 먼저 merge되어 영구 commit hash가 생기면 submitter 또는 maintainer가 revision을 그 hash로 바꿔야 합니다.

서로 다른 여러 모듈의 dependent 변경도 같은 절차로 제출할 수 있습니다. 이 경우 pull request가 있는 모든 모듈 entry를 변경합니다.

새 모듈 제출 절차

외부 source 절차에 따라 TSC 승인을 받아 외부 source code를 모듈로 통합하십시오.

요청이 승인되면 project team이 새 repository를 만들고 기본 정보를 초기화하여 project contribution guideline에 따라 module project에 code를 제출할 수 있게 합니다.

다른 GitHub project의 fork로 module을 유지한다면 upstream 대비 Zephyr module file과 변경은 zephyr라는 특별 branch에서 유지해야 합니다.

Zephyr maintainer가 repository를 만들고 초기화한 뒤 contributor를 collaborator로 추가합니다. 새 repository에 module content를 제출하고 주 Zephyr tree의 west.yml에 다음 정보를 추가합니다.

- name: <name of repository>
  path: <path to where the repository should be cloned>
  revision: <ref pointer to module pull request>

my_module을 manifest에 추가하는 예:

- name: my_module
  path: modules/lib/my_module
  revision: pull/23/head

위 예의 23은 my_module repository에 제출한 pull request number입니다. Module 변경을 review하고 merge하면 revision을 module repository commit hash로 바꿔야 합니다.

기존 모듈 변경 제출 절차

  1. Contribution guideline과 Contributor expectation에 따라 기존 repository에 pull request로 변경을 제출합니다.
  2. 주 Zephyr tree의 west.yml에서 module 참조 entry를 변경하는 pull request를 다음 정보와 함께 제출합니다.
    - name: <name of repository>
      path: <path to where the repository should be cloned>
      revision: <ref pointer to module pull request>

my_module을 manifest에 추가하는 예:

- name: my_module
  path: modules/lib/my_module
  revision: pull/23/head

위 예의 23은 my_module repository에 제출한 pull request number입니다. Module 변경을 review하고 merge하면 revision을 module repository commit hash로 바꿔야 합니다.

Source

출처

영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.