Files
nuttx/Documentation/implementation/make_build_system.rst
LuchianMihai e09c8e510e
Some checks failed
Build Documentation / build-html (push) Has been cancelled
Documentation/Make: add implementation/make_build_system.rst
This commit adds initial high level overview of the NuttX
make-based build system.  It documents:
* Tools used during the build process
* Mechanisms set in place during the build process

Signed-off-by: Luchian Mihai <luchiann.mihai@gmail.com>
2025-11-20 09:39:16 -05:00

608 lines
23 KiB
ReStructuredText

=================
Make Build System
=================
Currently, NuttX supports both CMake and Make build systems.
This guide explains the NuttX ``make``-based build system.
Due to *requirements, constraints, and the complexity of the build process*, NuttX divides
this work into multiple files, each handling specific parts of the build process.
As stated in :doc:`/introduction/inviolables`, multiple platforms should be supported:
- :ref:`win_mk`: handles windows platform support.
- :ref:`unix_mk`: handles unix-like platforms support.
NuttX supports multiple build modes. See :doc:`/guides/protected_build`:
- :ref:`flatlibs_mk`: Kernel and user-space built into a single ``blob``.
- :ref:`protectedlibs_mk`: Kernel and user-space built as two separate ``blobs``.
- :ref:`kernelibs_mk`: Kernel built into single ``blob``. User apps must be loaded
into memory for execution.
NuttX targets multiple libs, or ``silos``, each handling its own compilation:
.. note::
Gregory Nutt has a nice presentation about
`NuttX architecture <https://cwiki.apache.org/confluence/pages/viewpage.action?
pageId=139629399&preview=/139629402/140774623/nuttx-3-archoverview.pdf>`_
There the ``silo`` concept is explained. Only the ``silos`` there are listed below as libs.
The build mode influences the needed libs.
.. code-block:: console
$ ls -l staging/
drwxr-xr-x 2 xxx xxx 4096 Oct 6 16:02 .
drwxr-xr-x 27 xxx xxx 4096 Oct 6 16:02 ..
-rw-r--r-- 1 xxx xxx 323640 Oct 6 16:02 libapps.a
-rw-r--r-- 1 xxx xxx 384352 Oct 6 16:02 libarch.a
-rw-r--r-- 1 xxx xxx 62182 Oct 6 16:02 libbinfmt.a
-rw-r--r-- 1 xxx xxx 6468 Oct 6 16:01 libboards.a
-rw-r--r-- 1 xxx xxx 2820054 Oct 6 16:02 libc.a
-rw-r--r-- 1 xxx xxx 161486 Oct 6 16:01 libdrivers.a
-rw-r--r-- 1 xxx xxx 981638 Oct 6 16:02 libfs.a
-rw-r--r-- 1 xxx xxx 224446 Oct 6 16:02 libmm.a
-rw-r--r-- 1 xxx xxx 2435746 Oct 6 16:01 libsched.a
-rw-r--r-- 1 xxx xxx 51768 Oct 6 16:02 libxx.a
.. _verbosity:
Verbosity
---------
The ``V`` variable can be passed to ``make`` to control the build verbosity.
- **Quiet (Default):** The build output is minimal.
- **Verbose (`V=1 V=2`):** Shows the full compiler commands *(enables command echo)*.
- **Verbose Tools (`V=2`):** Enables verbose output for tools and scripts.
.. code-block:: console
# V=1,2: Enable echo of commands
$ make V=1
# V=2: Enable bug/verbose options in tools and scripts
$ make V=2
Build Process
-------------
.. note::
Keep the configuration step and board folder layout short.
Separate docs should be created.
The ``Make`` based build process starts with the NuttX tree configuration.
This is done by running ``tools/configure.sh`` script.
The configuration step, prepares the NuttX kernel tree, setting the board specific
arch, chip and board files.
The ``Make`` build system refers the needed subsystems using *generic* naming:
- The *current* architecture is refered as ``arch``
- The *current* chip is refered as ``chip``
- The *current* board is refered as ``board``
These *generic* names are mapped to the *actual* names by symlinks:
- The *current* chip directory gets symlinked to ``nutt/include/arch/chip``.
- The *current* board directory gets symlinked to ``nutt/include/arch/board``.
- The *current* arch directory gets symlinked to ``nutt/include/arch``.
The board config is stored as ``defconfig`` file, which is a minimal config,
storing only the configs that differs from default config values.
Due to NuttX's particularity of strict dependance to the ``app``
directory, the ``.config`` file is not generated by either ``kconfiglib`` or
``kconfig-frontends``, but rather by the an in-tree ``tools/process_config.sh``
script. This script takes a "base" input file (the boards ``defconfig`` file),
additional include paths (the most relevant being the ``apps`` top directory),
and generate an output file (the ``$(TOPDIR)/.config`` file).
.. code-block:: console
# part of configure.sh shell script, starting at line 240
#
# src_config=${configpath}/defconfig
# dest_config="${TOPDIR}/.config"
# original_config="${TOPDIR}/.config.orig"
# backup_config="${TOPDIR}/defconfig"
$ ln -sf ${src_makedefs} ${dest_makedefs} || \
{ echo "Failed to symlink ${src_makedefs}" ; exit 8 ; }
$ ${TOPDIR}/tools/process_config.sh -I ${configpath}/../../common/configs \
-I ${configpath}/../common \
-I ${configpath} -I ${TOPDIR}/../apps \
-I ${TOPDIR}/../nuttx-apps \
-o ${dest_config} ${src_config}
Starting the Build
^^^^^^^^^^^^^^^^^^
The root **Makefile** is the build process entrypoint. Its main job is
to check for a ``.config`` file and include the appropriate **host-specific Makefile**.
The "actual" first steps of the build process are handled by the host-specific
**Makefile** (either ``Win.mk`` or ``Unix.mk``).
Early on, during parsing, both host-specific **Makefile** will also include
- board's ``Make.defs`` file mentioned above. This will include also
- the main ``.config`` file.
- the tools ``config.mk`` file.
- the arch ``toolchain.defs`` file.
- based on the build mode, one of the following files:
- :ref:`flatlibs_mk`
- :ref:`protectedlibs_mk`
- :ref:`kernelibs_mk`
- :ref:`directories_mk`
Built-in dependency mechanism
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
The documentation for :ref:`mkdeps` should be extended. Lots of details
are missing. Part of the documentation here should be moved.
NuttX implements a built-in dependency mechanism. See :ref:`mkdeps`.
This mechanism uses ``gcc`` to generate a ``*.d`` like dependency files that can be
included by the **Makefile** to track file dependencies.
This mechanism is kick-started by the ``depend`` target, and targets specific
directories in the NuttX tree based on the build mode. It is *required* by both
``pass1dep`` and ``pass2dep``.
.. code-block:: makefile
pass1dep: context tools/mkdeps$(HOSTEXEEXT) tools/cnvwindeps$(HOSTEXEEXT)
$(Q) for dir in $(USERDEPDIRS) ; do \
$(MAKE) -C $$dir depend || exit; \
done
pass2dep: context tools/mkdeps$(HOSTEXEEXT) tools/cnvwindeps$(HOSTEXEEXT)
$(Q) for dir in $(KERNDEPDIRS) ; do \
$(MAKE) -C $$dir EXTRAFLAGS="$(KDEFINE) $(EXTRAFLAGS)" depend || exit; \
done
Both ``pass1dep`` and ``pass2dep`` sets different directories and orders
in which the ``depend`` target is ran. See :ref:`directories_mk`.
Building NuttX libs
^^^^^^^^^^^^^^^^^^^
The host-specific **Makefile** will not build the required NuttX libs.
It will defer work by "recursively" calling make in each of the directories
listed in the ``$(USERLIBS)`` and ``$(NUTTXLIBS)`` variables.
pass1 & pass2
^^^^^^^^^^^^^
The NuttX binary is always generated by running both ``pass1`` and ``pass2`` targets.
The actual dependencies of the mentioned targets may vary depending on the build mode.
Different NuttX build modes will not influence the "execution" of the ``pass1`` and ``pass2`` targets,
but rather will influence the dependencies pulled by those targets.
- ``pass1`` target depends on the ``$(USERLIBS)``.
- ``pass2`` target depends on the ``$(NUTTXLIBS)``.
.. code-block:: makefile
all: pass1 pass2
pass1: $(USERLIBS)
pass2: $(NUTTXLIBS)
The content of the ``$(USERLIBS)`` and ``$(NUTTXLIBS)`` variables is defined in each build mode makefile.
See :ref:`build_modes` above.
Staging the libs
^^^^^^^^^^^^^^^^
After compiling libraries defined by the ``$(USERLIBS)`` and ``$(NUTTXLIBS)`` at the previous step,
the ``make`` build system will ``install`` them at a special ``staging/`` directory, residing at the
root of the NuttX tree.
These libraries are passed to the the final target rule (``$(BIN)``).
.. code-block:: makefile
# Unix.mk : line 536
$(BIN): pass1 pass2
# ...
$(Q) $(MAKE) -C $(ARCH_SRC) EXTRA_OBJS="$(EXTRA_OBJS)" LINKLIBS="$(LINKLIBS)" APPDIR="$(APPDIR)" EXTRAFLAGS="$(KDEFINE) $(EXTRAFLAGS)" $(BIN)
# ...
.. _win_mk:
Win.mk
------
Although targeting different platforms, both **Win.mk** and **Unix.mk** aim to produce
the same output. The need for independent files is due to the differences in the
platform's approaches.
Forward vs Back slashes
^^^^^^^^^^^^^^^^^^^^^^^
One of the main differences is the use of forward slashes
(``/``) on unix-like platforms versus backslashes (``\``) on windows
${HOSTEXEEXT} ${HOSTDYNEXT}
^^^^^^^^^^^^^^^^^^^^^^^^^^^
These variables are used by the build system to configure the executable suffix required
by the used platform. They are defined in :ref:`config_mk`.
For windows platform:
- ``${HOSTEXEEXT}`` is set to ``.exe``.
- ``${HOSTDYNEXT}`` is set to ``.dll``.
Symbolic Linking
^^^^^^^^^^^^^^^^
For the windows platform, the build system handles symbolic links differently.
.. _unix_mk:
Unix.mk
-------
Versioning
^^^^^^^^^^
The build system will impact versioning if NuttX is cloned as a repo. See :ref:`versioning`.
config.h, .config, mkconfig
^^^^^^^^^^^^^^^^^^^^^^^^^^^
NuttX's build system defers the ``config.h`` generation to a separate tool called
``mkconfig``. See :ref:`makefile_host`.
.. code-block:: makefile
tools/mkconfig$(HOSTEXEEXT): prebuild
$(Q) $(MAKE) -C tools -f Makefile.host mkconfig$(HOSTEXEEXT)
The ``include/nuttx/config.h`` recipe calls the ``mkconfig`` executable generated by the
rule above to create the ``config.h`` file from the current ``.config`` file.
Symlinks & dirlinks
^^^^^^^^^^^^^^^^^^^
Dirlinks are symbolic links that allow the build system to use generic paths while pointing
to architecture-specific, chip-specific, or board-specific directories. This enables a single
build system workflow across many different hardware configurations.
- Symlink ``arch/<arch-name>/include`` to ``include/arch``
- Symlink ``boards/<arch>/<chip>/<board>/include`` to ``include/arch/board``
- Symlink ``arch/<arch-name>/include/<chip-name>`` to ``include/arch/chip``
- Symlink ``boards/<arch>/<chip>/<board>`` to ``arch/<arch-name>/src/board/<board>``
.. note::
Some boards make use of a ``common`` directory. In that case:
- ``boards/<arch>/<chip>/common`` is symlinked to ``arch/<arch-name>/src/board``
- ``boards/<arch>/<chip>/<board>`` is symlinked to ``arch/<arch-name>/src/board/<board>``
- Symlink ``arch/<arch-name>/src/<chip-name>`` to ``arch/<arch-name>/src/chip``
The ``.dirlinks`` file itself is just a timestamp marker that indicates all dirlinks have been
created.
Dummies
^^^^^^^
The main reason for the use of dummies is to handle some specific scenarios, such as external
code bases, custom chips and boards or to overcome tooling limitations. If any of the features below
are not used, the build system will fallback to a dummy.
- **${EXTERNALDIR}**
Possible values for ``$(EXTERNALDIR)`` are ``external`` or ``dummy``.
NuttX code base can be extended by using ``$(TOPDIR)/external/`` directory.
The build system searches for a ``Kconfig`` file in that directory. If found,
the build system defines the ``EXTERNALDIR`` variable to ``external`` and also
appends another lib (``libexternal``) to the build process.
.. code-block:: makefile
# External code support
# If external/ contains a Kconfig, we define the EXTERNALDIR variable to 'external'
# so that main Kconfig can find it. Otherwise, we redirect it to a dummy Kconfig
# This is due to kconfig inability to do conditional inclusion.
EXTERNALDIR := $(shell if [ -r $(TOPDIR)/external/Kconfig ]; then echo 'external'; else echo 'dummy'; fi)
- **dummy/Kconfig**
The ``dummy/Kconfig`` is used to handle custom chips and boards.
If in-tree chip/board is used, the build system will resolve to dummy_kconfig files.
- ``$(CHIP_KCONFIG)`` is set to ``$(TOPDIR)$(DELIM)arch$(DELIM)dummy$(DELIM)dummy_kconfig``
- ``$(BOARD_KCONFIG)`` is set to ``$(TOPDIR)$(DELIM)boards$(DELIM)dummy$(DELIM)dummy_kconfig``
If custom chip/board is used, the build system will resolve to their custom paths.
.. code-block:: makefile
# Copy $(CHIP_KCONFIG) to arch/dummy/Kconfig
arch/dummy/Kconfig:
@echo "CP: $@ to $(CHIP_KCONFIG)"
$(Q) cp -f $(CHIP_KCONFIG) $@
# Copy $(BOARD_KCONFIG) to boards/dummy/Kconfig
boards/dummy/Kconfig:
@echo "CP: $@ to $(BOARD_KCONFIG)"
$(Q) cp -f $(BOARD_KCONFIG) $@
- **boards/dummy.c**
A special ``boards/dummy.c`` file is used by the build system to generate a useless object.
The purpose of the useless object is to assure that libboards.a/lib is created. Some archivers
(ZDS-II, SDCC) require a non-empty library or they will generate errors.
.. _build_modes:
Build Modes
^^^^^^^^^^^
As specified above, NuttX supports multiple build modes. The build mode is selected
based on specific ``Kconfig`` options.
.. code-block:: makefile
# Library build selections
#
# NUTTXLIBS is the list of NuttX libraries that is passed to the
# processor-specific Makefile to build the final NuttX target.
# USERLIBS is the list of libraries used to build the final user-space
# application
# EXPORTLIBS is the list of libraries that should be exported by
# 'make export' is
ifeq ($(CONFIG_BUILD_PROTECTED),y)
include tools/ProtectedLibs.mk
else ifeq ($(CONFIG_BUILD_KERNEL),y)
include tools/KernelLibs.mk
else
include tools/FlatLibs.mk
endif
The content of each file referenced above is documented in its own section.
- tools/ProtectedLibs.mk :ref:`protectedlibs_mk`
- tools/FlatLibs.mk :ref:`flatlibs_mk`
- tools/KernelLibs.mk :ref:`kernelibs_mk`
.. _config_mk:
Config.mk
---------
``Config.mk`` contains common definitions used by many configuration files.
* It defines the logic behind the :ref:`verbosity`
* It resolves the platform specific particularities, such as
* build *tools* ``e.g. mkdeps, cnvwindeps, link.sh/.bat, unlink.sh/.bat``
* file extensions ``e.g. .exe, .dll for windows, .o, .a for unix``
* delim based on the host platform. ``e.g. \ for windows, / for unix``
* Resolve custom bard/chip/arch
* Defines the rules for the dependency mechanism
.. code-block:: makefile
OBJPATH ?= .
%.dds: %.S
$(Q) $(MKDEP) --obj-path $(OBJPATH) --obj-suffix $(OBJEXT) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $< > $@
%.ddc: %.c
$(Q) $(MKDEP) --obj-path $(OBJPATH) --obj-suffix $(OBJEXT) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $< > $@
%.ddp: %.cpp
$(Q) $(MKDEP) --obj-path $(OBJPATH) --obj-suffix $(OBJEXT) $(DEPPATH) "$(CXX)" -- $(CXXFLAGS) -- $< > $@
%.ddx: %.cxx
$(Q) $(MKDEP) --obj-path $(OBJPATH) --obj-suffix $(OBJEXT) $(DEPPATH) "$(CXX)" -- $(CXXFLAGS) -- $< > $@
%.ddh: %.c
$(Q) $(MKDEP) --obj-path $(OBJPATH) --obj-suffix $(OBJEXT) $(DEPPATH) "$(CC)" -- $(HOSTCFLAGS) -- $< > $@
* Defines the include flag prefix based on compiler
* Defines the common functions used to compile, assemble, archive files, etc.
This file (along with *<nuttx>*/.config) must be included at the top of
each configuration-specific Make.defs file like
.. code-block:: makefile
include $(TOPDIR)/.config
include $(TOPDIR)/tools/Config.mk
Subsequent logic within the configuration-specific Make.defs file may then
override these default definitions as necessary.
.. _flatlibs_mk:
FlatLibs.mk
-----------
This file defines the library sets for the **flat build mode**. In this mode,
the NuttX kernel and all user-space applications are compiled and linked into a
single, monolithic binary.
Its primary responsibilities are:
- **Populating ``NUTTXLIBS``:** The file systematically appends all required
libraries to the ``NUTTXLIBS`` variable. This includes core OS libraries
(``libsched``, ``libmm``, ``libc``), architecture and board support libraries,
and device drivers.
- **Conditional Library Inclusion:** It uses ``ifeq ($(CONFIG_XXX),y)`` checks
to conditionally include libraries for optional features based on the
system's Kconfig. For example, ``staging/libnet.a`` is added only if
``CONFIG_NET=y``, and ``staging/libcrypto.a`` is added if ``CONFIG_CRYPTO=y``.
- **Defining ``USERLIBS``:** In the flat build, there is no separate user-space
binary, so the ``USERLIBS`` variable is initialized but remains empty.
- **Setting ``EXPORTLIBS``:** It assigns the complete list of ``NUTTXLIBS`` to
the ``EXPORTLIBS`` variable. This ensures that the ``make export`` command
packages all the compiled libraries required to link the final binary.
.. _protectedlibs_mk:
ProtectedLibs.mk
----------------
This file defines the library sets for the **protected build mode**. In this mode,
the NuttX kernel and user-space applications are built as two distinct binaries,
enabling memory protection and a more robust system architecture.
Its primary responsibilities are:
- **Separate Library Lists:** Unlike the flat build, this file populates both
the ``NUTTXLIBS`` variable (for the kernel binary) and the ``USERLIBS`` variable
(for user-space applications).
- **Kernel vs. User Library Variants:** It explicitly differentiates between
kernel and user variants of core libraries. For instance:
- Kernel-specific libraries (e.g., ``libkc.a``, ``libkmm.a``, ``libkarch.a``)
are added to ``NUTTXLIBS``.
- User-space counterparts (e.g., ``libc.a``, ``libmm.a``, ``libarch.a``)
are added to ``USERLIBS``.
- **System Call Mechanism:** It includes essential components for the system
call interface:
- ``staging/libstubs.a`` (system call stubs) is added to ``NUTTXLIBS``.
- ``staging/libproxies.a`` (system call proxies) is added to ``USERLIBS``.
These facilitate safe communication between user applications and the kernel.
- **Conditional Library Inclusion:** Similar to other build modes, it uses
``ifeq ($(CONFIG_XXX),y)`` checks to conditionally include libraries for
optional features in both kernel and user-space, based on the Kconfig settings.
- **Exporting User Libraries:** A key distinction is that ``EXPORTLIBS`` is set
to ``$(USERLIBS)``. This means that the ``make export`` command will primarily
package the user-space libraries, which are then used by external build
systems or for linking user applications.
.. _kernelibs_mk:
KernelLibs.mk
-------------
This file defines the library sets for the **kernel build mode**. In this mode,
only the NuttX kernel is compiled and linked into a single binary. User
applications are expected to be loaded and executed separately, typically in a
protected user-space environment.
Its primary responsibilities are:
- **Kernel-Only ``NUTTXLIBS``:** The file populates the ``NUTTXLIBS`` variable
with all the necessary kernel-space libraries. This includes core OS
components (e.g., ``libsched``, ``libdrivers``), kernel variants of common
libraries (e.g., ``libkc.a``, ``libkmm.a``, ``libkarch.a``), and board support.
- **Empty ``USERLIBS``:** The ``USERLIBS`` variable is explicitly initialized
but remains empty, as this build mode does not produce a user-space binary.
- **System Call Stubs:** It includes ``staging/libstubs.a`` in ``NUTTXLIBS``,
providing the kernel-side implementation for system calls. User-space system
call proxies (``libproxies.a``) are not included, consistent with the absence
of a user-space build.
- **Conditional Library Inclusion:** It uses ``ifeq ($(CONFIG_XXX),y)`` checks
to conditionally include kernel-specific libraries for optional features
based on the system's Kconfig.
- **Exporting User Libraries (Empty):** ``EXPORTLIBS`` is set to ``$(USERLIBS)``.
Consequently, in this kernel-only build mode, ``EXPORTLIBS`` will be empty,
reflecting that no user-space libraries are produced for external packaging.
.. _directories_mk:
Directories.mk
--------------
This file defines the directories used throughout the NuttX build process.
These directory lists are not static but are **dynamically constructed**
based on the active Kconfig configuration.
The file begins by defining a ``BASEDIRS`` variable, which includes core directories
that are always part of the build. Subsequently, it uses conditional logic
(``ifeq ($(CONFIG_XXX),y)``) to append additional directories to various master lists,
such as ``ALLDIRS`` and ``CLEANDIRS``, only if their corresponding Kconfig options are
enabled.
For example:
- The ``net/`` directory is added to the build lists only if ``CONFIG_NET=y``.
- The ``graphics/`` directory is included if ``CONFIG_GRAPHICS=y``.
- The ``crypto/`` directory is included if ``CONFIG_CRYPTO=y``.
The file defines key variables that hold these dynamically generated directory lists:
- ``KERNDEPDIRS``: Directories containing kernel files for dependency generation.
- ``USERDEPDIRS``: Directories containing user-space files for dependency generation.
- ``CCLEANDIRS``: Directories where the ``clean_context`` target will execute.
- ``CLEANDIRS``: All known directories where the ``clean`` target will execute.
- ``CONTEXTDIRS``: Directories with special pre-build requirements, such as auto-generation of files or symbolic link creation.
.. _libtargets_mk:
LibTargets.mk
-------------
The ``LibTargets.mk`` file defines all the targets needed to build the NuttX
libraries from their respective source directories and then install the
resulting library file into the ``staging/`` directory.
For many core libraries (e.g., ``libc``, ``libm``, ``libmm``, ``libbuiltin``, ``libnx``, ``libarch``),
``LibTargets.mk`` defines distinct targets for **kernel** and **user** variants.
- **Kernel libraries** are typically prefixed with ``libk`` (e.g., ``libkc.a`` for kernel C library,
``libkmm.a`` for kernel memory management). These are compiled with specific
``EXTRAFLAGS`` that include ``$(KDEFINE)``, which sets kernel-specific preprocessor
definitions (e.g., ``-D__KERNEL__``). This ensures they are built with the necessary
context and APIs for the kernel environment.
- **User libraries** retain their standard names (e.g., ``libc.a``, ``libmm.a``).
These are compiled without the ``$(KDEFINE)`` flag, making them suitable for user-space
applications. The build process for user-mode libraries often depends on ``pass1dep``,
while kernel-mode libraries depend on ``pass2dep``, reflecting the two-pass build
strategy in protected and kernel build modes.
For each variant of a library, two main targets are defined:
1. **A build target:** This target recursively calls ``make`` within the library's
source directory (e.g., ``libs/libc/``, ``mm/``) to compile the sources and create
the library archive (``.a``) file. It passes the appropriate ``EXTRAFLAGS``
depending on whether it's a kernel-mode or user-mode build. The dependency for
these targets is either ``pass1dep`` or ``pass2dep``, ensuring dependencies are
checked before building.
2. **A staging target:** This target depends on the successful creation of the
library archive from the previous step. Its recipe calls the ``INSTALL_LIB``
macro (defined in ``Unix.mk`` or ``Win.mk``) to copy the newly created
library to the top-level ``staging/`` directory.
The file contains conditional logic, primarily based on ``CONFIG_BUILD_FLAT``,
to adjust dependencies (``pass1dep`` vs. ``pass2dep``) for libraries that can
be part of either the user or kernel space, ensuring they are built in the
correct pass according to the selected build mode.