Build Implementation
Design Philosophy
The ARMINO build system is mainly designed with object-oriented thinking. Key points to understand:
CMakeLists.txt is scanned twice, allowing special handling during dependency expansion
Dependencies are expanded before building to simplify dependency specification
projects/components are derived from cmake’s projects/target, override defaults by setting specific variables before function calls, and set specific properties after function calls
Allow projects/components to add hooks before, during, and after core script execution
Provide encapsulated APIs to handle over 90% of common scenarios; only rare special cases require complex cmake scripts
Build Scripts
The ARMINO build system list files are located in /tools/build_tools/cmake. The modules implementing core build system functionality are as follows:
build.cmake - Build-related functions: build initialization, retrieving/setting build properties, build processing.
component.cmake - Component-related functions: adding components, retrieving/setting component properties, registering components.
kconfig.cmake - Generate configuration files (sdkconfig, sdkconfig.h, sdkconfig.cmake, etc.) from Kconfig files.
target.cmake - Set build target and toolchain file.
utilities.cmake - Other helper commands.
In addition to these files, there are two important CMake scripts in /tools/build_tools/cmake:
armino.cmake - Sets build parameters and imports the core modules listed above.
project.cmake - Imports
armino.cmakeand provides a customproject()command that handles all the heavy lifting when building executables. Included in the top-level CMakeLists.txt of standard ARMINO projects.
Other files in /tools/build_tools/cmake are supporting files or third-party scripts for the build process.
Build Process
The build process can be roughly divided into four phases: initialization, component list generation, component processing, and finalization.
Initialization
This phase sets up necessary parameters for the build.
- After importing
armino.cmakeintoproject.cmake, the following steps are executed:
Set
ARMINO_PATHfrom environment variable or infer relative path from theproject.cmakepath included in the top-level CMakeLists.txt.Add /tools/build_tools/cmake to
CMAKE_MODULE_PATHand import core modules and various helper/third-party scripts.Set build tools/executables, such as the default Python interpreter.
Set global build parameters: compile options, compile definitions, include directories for all components.
Add components from components and middleware to the build.
- The initial part of the custom
project()command executes the following steps:
Set
ARMINO_TARGETin environment variable or CMake cache, and set the correspondingCMAKE_TOOLCHAIN_FILEto use.Add components from
EXTRA_COMPONENTS_DIRSto the buildPrepare arguments for calling
armino_build_process()from variables likeCOMPONENTS/EXCLUDE_COMPONENTS,SDKCONFIG,SDKCONFIG_DEFAULTS, etc.
Calling the armino_build_process() command marks the end of this phase.
Component List Generation
This phase builds a list of components to be processed during the build, occurring in the first half of
armino_build_process().
Find the public and private dependencies of each component. Create a subprocess that executes each component’s CMakeLists.txt in script mode. The values of
armino_component_registerREQUIRES and PRIV_REQUIRES parameters are returned to the parent process. This is component dependency expansion (or early expansion). The variable CMAKE_BUILD_EARLY_EXPANSION is defined during this step.Recursively import components based on public and private dependencies.
Note
Each component’s CMakeLists.txt is executed twice. The first time occurs during the _<Component List Generation> phase to allow armino_component_register() to expand component dependencies.
At this time, Kconfig has not been loaded yet, so you cannot use CONFIG_XXX values from Kconfig to decide whether a component should be loaded. If you need to add component dependencies based on CPU during the component list generation phase,
you can refer to the following approach:
armino_build_get_property(target ARMINO_SOC)
if ("${target}" STREQUAL "bk7239")
list(APPEND depenency_component)
endif()
Component Processing
This phase processes the components in the build, the second half of
armino_build_process().
Load project configuration from the sdkconfig file and generate sdkconfig.cmake and sdkconfig.h header files. These two files define configuration variables/macros that can be accessed from build scripts and C/C++ source/header files respectively.
Import each component’s project_include.cmake.
Add each component as a subdirectory and process its CMakeLists.txt. The component CMakeLists.txt calls the registration command
armino_component_registerto add source files, import directories, create component libraries, link dependencies, etc.
Finalization
This phase is the remaining steps of
armino_build_process().
Create the executable and link it to the component libraries.
Generate project metadata files such as project_description.json and display information about the built project.
The execution steps of the compilation process are all saved in the
build.ninjafile in the build directory under the corresponding project soc. If you need to view the detailed compilation tree, you can check thearminofolder in the same directory, which stores.c.objand.afiles from the compilation process.
Please refer to /tools/build_tools/cmake/project.cmake for more information.