zephyr/doc/guides/build/index.rst

373 lines
13 KiB
ReStructuredText
Raw Normal View History

.. _build_overview:
Build and Configuration Systems
###############################
.. _cmake-details:
Build System (CMake)
********************
CMake is used to build your application together with the Zephyr kernel. A
CMake build is done in two stages. The first stage is called
**configuration**. During configuration, the CMakeLists.txt build scripts are
executed. After configuration is finished, CMake has an internal model of the
Zephyr build, and can generate build scripts that are native to the host
platform.
CMake supports generating scripts for several build systems, but only Ninja and
Make are tested and supported by Zephyr. After configuration, you begin the
**build** stage by executing the generated build scripts. These build scripts
can recompile the application without involving CMake following
most code changes. However, after certain changes, the configuration step must
be executed again before building. The build scripts can detect some of these
situations and reconfigure automatically, but there are cases when this must be
done manually.
Zephyr uses CMake's concept of a 'target' to organize the build. A
target can be an executable, a library, or a generated file. For
application developers, the library target is the most important to
understand. All source code that goes into a Zephyr build does so by
being included in a library target, even application code.
Library targets have source code, that is added through CMakeLists.txt
build scripts like this:
.. code-block:: cmake
target_sources(app PRIVATE src/main.c)
In the above :file:`CMakeLists.txt`, an existing library target named ``app``
is configured to include the source file :file:`src/main.c`. The ``PRIVATE``
keyword indicates that we are modifying the internals of how the library is
being built. Using the keyword ``PUBLIC`` would modify how other
libraries that link with app are built. In this case, using ``PUBLIC``
would cause libraries that link with ``app`` to also include the
source file :file:`src/main.c`, behavior that we surely do not want. The
``PUBLIC`` keyword could however be useful when modifying the include
paths of a target library.
Build and Configuration Phases
==============================
The Zephyr build process can be divided into two main phases: a configuration
phase (driven by CMake) and a build phase (driven by Make or Ninja).
.. _build_configuration_phase:
Configuration Phase
-------------------
The configuration phase begins when the user invokes *CMake*,
specifying a source application directory and a board target.
.. figure:: build-config-phase.svg
:align: center
:alt: Zephyr's build configuration phase
:figclass: align-center
:width: 80%
CMake begins by processing the :file:`CMakeLists.txt` file in the application
directory, which refers to the :file:`CMakeLists.txt` file in the Zephyr
top-level directory, which in turn refers to :file:`CMakeLists.txt` files
throughout the build tree (directly and indirectly). Its primary output is a
set of Makefiles or Ninja files to drive the build process, but the CMake
scripts also do some processing of their own:
Devicetree
:file:`*.dts` (*devicetree source*) and :file:`*.dtsi` (*devicetree source
include*) files are collected from the target's architecture, SoC, board,
and application directories.
:file:`*.dtsi` files are included by :file:`*.dts` files via the C
preprocessor (often abbreviated *cpp*, which should not be confused with
C++). The C preprocessor is also used to merge in any devicetree
:file:`*.overlay` files, and to expand macros in :file:`*.dts`,
:file:`*.dtsi`, and :file:`*.overlay` files.
The preprocessed devicetree sources (stored in :file:`*.dts.pre.tmp`) are
parsed by :zephyr_file:`gen_defines.py <scripts/dts/gen_defines.py>` to
generate a :file:`devicetree_unfixed.h` header with preprocessor macros.
As a debugging aid, :file:`gen_defines.py` writes the final devicetree to
:file:`zephyr.dts`. This file is just for reference. It is not used
anywhere.
The ``dtc`` devicetree compiler also gets run on the preprocessed devicetree
sources to catch any extra warnings and errors generated by it. The output
from ``dtc`` is unused otherwise.
The above is just a brief overview. For more information on devicetree, see
:ref:`dt-guide`.
Devicetree fixups
Files named :file:`dts_fixup.h` from the targets architecture, SoC, board,
and application directories are concatenated into a single
:file:`devicetree_fixups.h` file. :file:`dts_fixup.h` files are used to
rename generated macros to names expected by the source code.
Source code accesses preprocessor macros generated from devicetree by
including the :zephyr_file:`devicetree.h <include/devicetree.h>` header,
which includes :file:`devicetree_unfixed.h` and :file:`devicetree_fixups.h`.
Kconfig
:file:`Kconfig` files define available configuration options for for the
target architecture, SoC, board, and application, as well as dependencies
between options.
Kconfig configurations are stored in *configuration files*. The initial
configuration is generated by merging configuration fragments from the board
and application (e.g. :file:`prj.conf`).
The output from Kconfig is an :file:`autoconf.h` header with preprocessor
assignments, and a :file:`.config` file that acts both as a saved
configuration and as configuration output (used by CMake).
Information from devicetree is available to Kconfig, through the functions
defined in :zephyr_file:`kconfigfunctions.py
<scripts/kconfig/kconfigfunctions.py>`.
See :ref:`the Kconfig section of the manual <kconfig>` for more information.
Build Phase
-----------
The build phase begins when the user invokes ``make`` or ``ninja``. Its
ultimate output is a complete Zephyr application in a format suitable for
loading/flashing on the desired target board (:file:`zephyr.elf`,
:file:`zephyr.hex`, etc.) The build phase can be broken down, conceptually,
into four stages: the pre-build, first-pass binary, final binary, and
post-processing.
Pre-build
+++++++++
Pre-build occurs before any source files are compiled, because during
this phase header files used by the source files are generated.
Offset generation
Access to high-level data structures and members is sometimes
required when the definitions of those structures is not
immediately accessible (e.g., assembly language). The generation of
*offsets.h* (by *gen_offset_header.py*) facilitates this.
System call boilerplate
The *gen_syscall.py* and *parse_syscalls.py* scripts work
together to bind potential system call functions with their
implementations.
.. figure:: build-build-phase-1.svg
:align: center
:alt: Zephyr's build stage I
:figclass: align-center
:width: 80%
First-pass binary
+++++++++++++++++
Compilation proper begins with the first-pass binary. Source files (C
and assembly) are collected from various subsystems (which ones is
decided during the configuration phase), and compiled into archives
(with reference to header files in the tree, as well as those
generated during the configuration phase and the pre-build stage).
If memory protection is enabled, then:
Partition grouping
The *gen_app_partitions.py* script scans all the
generated archives and outputs linker scripts to ensure that
application partitions are properly grouped and aligned for the
targets memory protection hardware.
Then *cpp* is used to combine linker script fragments from the targets
architecture/SoC, the kernel tree, optionally the partition output if
memory protection is enabled, and any other fragments selected during
the configuration process, into a *linker.cmd* file. The compiled
archives are then linked with *ld* as specified in the
*linker.cmd*.
In some configurations, this is the final binary, and the next stage
is skipped.
.. figure:: build-build-phase-2.svg
:align: center
:alt: Zephyr's build stage II
:figclass: align-center
:width: 80%
Final binary
++++++++++++
The binary from the previous stage is incomplete, with empty and/or
placeholder sections that must be filled in by, essentially, reflection.
Device dependencies
The *gen_handles.py* script scans the first-pass binary to determine
relationships between devices that were recorded from devicetree data,
and replaces the encoded relationships with values that are optimized to
locate the devices actually present in the application.
When :ref:`usermode_api` is enabled:
Kernel object hashing
The *gen_kobject_list.py* scans the *ELF DWARF*
debug data to find the address of the all kernel objects. This
list is passed to *gperf*, which generates a perfect hash function and
table of those addresses, then that output is optimized by
*process_gperf.py*, using known properties of our special case.
Then, the link from the previous stage is repeated, this time with the
missing pieces populated.
.. figure:: build-build-phase-3.svg
:align: center
:alt: Zephyr's build stage III
:figclass: align-center
:width: 80%
Post processing
+++++++++++++++
Finally, if necessary, the completed kernel is converted from *ELF* to
the format expected by the loader and/or flash tool required by the
target. This is accomplished in a straightforward manner with *objdump*.
.. figure:: build-build-phase-4.svg
:align: center
:alt: Zephyr's build final stage
:figclass: align-center
:width: 80%
.. _build_system_scripts:
Supporting Scripts and Tools
============================
The following is a detailed description of the scripts used during the build process.
.. _gen_syscalls.py:
:zephyr_file:`scripts/gen_syscalls.py`
--------------------------------------
.. include:: ../../../scripts/gen_syscalls.py
:start-after: """
:end-before: """
.. _gen_handles.py:
:zephyr_file:`scripts/gen_handles.py`
--------------------------------------
.. include:: ../../../scripts/gen_handles.py
:start-after: """
:end-before: """
.. _gen_kobject_list.py:
:zephyr_file:`scripts/gen_kobject_list.py`
------------------------------------------
.. include:: ../../../scripts/gen_kobject_list.py
:start-after: """
:end-before: """
.. _gen_offset_header.py:
:zephyr_file:`scripts/gen_offset_header.py`
-------------------------------------------
.. include:: ../../../scripts/gen_offset_header.py
:start-after: """
:end-before: """
.. _parse_syscalls.py:
:zephyr_file:`scripts/parse_syscalls.py`
----------------------------------------
.. include:: ../../../scripts/parse_syscalls.py
:start-after: """
:end-before: """
.. _gen_idt.py:
:zephyr_file:`arch/x86/gen_idt.py`
----------------------------------
.. include:: ../../../arch/x86/gen_idt.py
:start-after: """
:end-before: """
.. _gen_gdt.py:
:zephyr_file:`arch/x86/gen_gdt.py`
----------------------------------
.. include:: ../../../arch/x86/gen_gdt.py
:start-after: """
:end-before: """
.. _gen_relocate_app.py:
:zephyr_file:`scripts/gen_relocate_app.py`
-------------------------------------------
.. include:: ../../../scripts/gen_relocate_app.py
:start-after: """
:end-before: """
.. _process_gperf.py:
:zephyr_file:`scripts/process_gperf.py`
---------------------------------------
.. include:: ../../../scripts/process_gperf.py
:start-after: """
:end-before: """
:zephyr_file:`scripts/gen_app_partitions.py`
--------------------------------------------
.. include:: ../../../scripts/gen_app_partitions.py
:start-after: """
:end-before: """
.. _kconfig:
Configuration System (Kconfig)
*******************************
The Zephyr kernel and subsystems can be configured at build time to adapt them
for specific application and platform needs. Configuration is handled through
Kconfig, which is the same configuration system used by the Linux kernel. The
goal is to support configuration without having to change any source code.
Configuration options (often called *symbols*) are defined in :file:`Kconfig`
files, which also specify dependencies between symbols that determine what
configurations are valid. Symbols can be grouped into menus and sub-menus to
keep the interactive configuration interfaces organized.
The output from Kconfig is a header file :file:`autoconf.h` with macros that
can be tested at build time. Code for unused features can be compiled out to
save space.
The following sections explain how to set Kconfig configuration options, go
into detail on how Kconfig is used within the Zephyr project, and have some
tips and best practices for writing :file:`Kconfig` files.
.. toctree::
:maxdepth: 1
kconfig/menuconfig.rst
kconfig/setting.rst
kconfig/tips.rst
kconfig/preprocessor-functions.rst
kconfig/extensions.rst