@@ -62,7 +62,7 @@ The interfaces shown in the figure are described as follows:
...
@@ -62,7 +62,7 @@ The interfaces shown in the figure are described as follows:
-**Communications interfaces**
-**Communications interfaces**
- I2C: Since only a small amount of touch data is reported by the touchscreen, I2C is used to transmit the reported data. For details about the I2C protocol and interfaces, see [I2C](driver-platform-i2c-des.md#section5361140416).
- I2C: Since only a small amount of touch data is reported by the touchscreen, I2C is used to transmit the reported data. For details about the I2C protocol and interfaces, see [I2C](driver-platform-i2c-des.md#section5361140416).
- SPI: In addition to touch reporting data coordinates, some vendors need to obtain basic capacitance data. Therefore, Serial Peripheral Interface \(SPI\) is used to transmit such huge amount of data. For details about the SPI protocol and interfaces, see [SPI](driver-platform-spi-des.md#section193356154511).
- SPI: In addition to touch reporting data coordinates, some vendors need to obtain basic capacitance data. Therefore, Serial Peripheral Interface \(SPI\) is used to transmit such huge amount of data. For details about the SPI protocol and interfaces, see [SPI](driver-platform-spi-des.md#overview).
## How to Develop<a name="section65745222184"></a>
## How to Develop<a name="section65745222184"></a>
Serial Peripheral Interface (SPI) is a serial bus specification used for high-speed, full-duplex, and synchronous communication. SPI is developed by Motorola. It is commonly used for communication with flash memory, real-time clocks, sensors, and analog-to-digital (A/D) converters.
Serial Peripheral Interface (SPI) is a serial bus specification used for high-speed, full-duplex, and synchronous communication. SPI is developed by Motorola. It is commonly used for communication with flash memory, real-time clocks, sensors, and analog-to-digital (A/D) converters.
...
@@ -38,7 +38,7 @@ The figure below shows the connection between one controller and two devices (de
...
@@ -38,7 +38,7 @@ The figure below shows the connection between one controller and two devices (de
> Currently, these functions are only applicable in the communication initiated by the SPI controller.
> Currently, these functions are only applicable in the communication initiated by the SPI controller.
A watchdog, also called a watchdog timer, is a hardware timing device used to facilitate automatic correction of temporary hardware faults or recover from system malfunctions.
A watchdog, also called a watchdog timer, is a hardware timing device used to facilitate automatic correction of temporary hardware faults or recover from system malfunctions.
...
@@ -12,7 +12,7 @@ In the Hardware Driver Foundation (HDF), the watchdog uses the independent servi
...
@@ -12,7 +12,7 @@ In the Hardware Driver Foundation (HDF), the watchdog uses the independent servi


### "usr/sbin/ninja: invalid option -- w" Displayed During the Build Process
-**Symptom**
The build fails, and **usr/sbin/ninja: invalid option -- w** is displayed.
-**Possible Causes**
The Ninja version in use does not support the **--w** option.
-**Solution**
Uninstall Ninja and GN, and [install Ninja and GN of the required version](../../device-dev/get-code/gettools-ide.md).
### "/usr/bin/ld: cannot find -lncurses" Displayed During the Build Process
-**Symptom**
The build fails, and **/usr/bin/ld: cannot find -lncurses** is displayed.
-**Possible Causes**
The ncurses library is not installed.
-**Solution**
```shell
sudo apt-get install lib32ncurses5-dev
```
### "line 77: mcopy: command not found" Displayed During the Build Process
-**Symptom**
The build fails, and **line 77: mcopy: command not found** is displayed.
-**Possible Causes**
mcopy is not installed.
-**Solution**
```shell
sudo apt-get install dosfstools mtools
```
### "riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory" Displayed During the Build Process
-**Symptom**
The build fails, and the following information is displayed: <br>**riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory**
-**Possible Causes**
Permission is required to access files in the RISC-V compiler directory.
-**Solution**
1. Run the following command to locate **gcc_riscv32**:
```shell
which riscv32-unknown-elf-gcc
```
2. Run the **chmod** command to change the directory permission to **755**.
### "No module named 'Crypto'" Displayed During the Build Process
-**Symptom**
The build fails, and **No module named 'Crypto'** is displayed.
-**Possible Causes**
Crypto is not installed in Python 3.
-**Solution**
1. Run the following command to query the Python version:
```shell
python3 --version
```
2. Ensure that Python 3.9.2 or later is installed, and then run the following command to install PyCryptodome:
```shell
sudo pip3 install pycryptodome
```
### "xx.sh : xx unexpected operator" Displayed During the Build Process
-**Symptom**
The build fails, and **xx.sh [: xx unexpected operator** is displayed.
The OpenHarmony Compilation and Building subsystem provides a build framework based on Generate Ninja (GN) and Ninja. It abstracts the build and configuration granularity by component, and provides function enhancement for built-in modules and function extension for service modules. The OpenHarmony Compilation and Building subsystem provides the following functions:
- Allows products to be assembled and independently built by component.
- Supports version builds for mini, small, and standard systems and build of the software development kit (SDK), which facilitates application developers to use the Integrated development environment (IDE).
- Supports customization and independent build based on different chipset solutions.
### Application Scope
This guide is applicable to mini, small, and standard systems. The [Chipset Solution](subsys-build-chip_solution.md) applies to mini and small systems.
### Basic Concepts
Learn the following basic concepts before you get started:
- Platform
A platform consists of a development board and the kernel. The subsystems and components vary with the platform.
- Product
A product is a collection of components. The product image built can run on different development boards.
- Subsystem
OpenHarmony is designed with a layered architecture, which consists of the kernel layer, system service layer, framework layer, and application layer from bottom up. For details, see [OpenHarmony Technical Architecture](https://gitee.com/openharmony#technical-architecture). System functions are built from components, subsystems, and then to the system. In a multi-device deployment, you can customize subsystems and components as required. A subsystem, as a logical concept, consists of the least required components.
- Component
A component is a reusable software binary unit that contains source code, configuration files, resource files, and build scripts. It can be built independently, integrated in binary mode, and tested independently. The chipset solution mentioned in this guide is a special component in nature.
- Module
A module is a target to build. A component can also be a target to build.
- Feature
A component can provide differentiated functions through features.
- GN
GN is used to build Ninja files.
- Ninja
Ninja is a small high-speed building system.
- hb
hb is an OpenHarmony command line tool used to execute build commands.
The Compilation and Build subsystem implements compilation and packaging through configuration. The following describes the relationships between the product, subsystem, component, and module.
**Figure 1** Relationships between product, subsystem, component, and module
# The following modules must be installed for Python. You can obtain the **repo** file from the source code of the build environment mentioned in **Constraints**.
#Install LLVM, hc-gen, gcc_riscv32, Ninja, node-v14.15.4-linux-x64, and GN. If the shell in use is not bash or zsh, configure the following environment variables:
**NOTE**<br>The hb tool will be installed during the installation of ohos-build. If the hb installation fails, see [Installing hb](../../device-dev/quick-start/quickstart-lite-env-setup.md#installing-hb).
## Configuration Rules
To ensure that chipset and product solutions are decoupled from OpenHarmony, you need to follow certain rules during the configuration.
-v, --verbose show all command lines while building
-shs, --sign_haps_by_server
sign haps by server
--patch apply product patch before compiling
--compact-mode compatible with standard build system set to false if we use build.sh as build entrance
--gn-args GN_ARGS specifies gn build arguments, eg: --gn-args="foo="bar" enable=true blah=7"
--keep-ninja-going keeps ninja going until 1000000 jobs fail
--build-only-gn only do gn parse, donot run ninja
--log-level LOG_LEVEL
specifies the log level during compilationyou can select three levels: debug, info and error
--fast-rebuild it will skip prepare, preloader, gn_gen steps so we can enable it only when there is no change
for gn related script
--device-type DEVICE_TYPE
specifies device type
--build-variant BUILD_VARIANT
specifies device operating mode
```
- If you run **hb build** with no argument, the previously configured code directory, product, and options are used for the build. The **-f** option deletes all products to be built. It is equivalent to running **hb clean** and **hb build**.
- You can run **hb build***{component_name}* to build product components separately based on the development board and kernel set for the product, for example, **hb build kv_store**.
- You can run **hb build -p ipcamera@hisilicon** to skip the setting step and build the product directly.
- You can run **hb build** in **device/board/device_company** to select the kernel and build an image that contains the kernel and drivers only based on the current development board and the selected kernel.
**hb clean**
Deletes all the files except **args.gn** and **build.log** in the **out** directory. To clear files in a specified directory, add the directory parameter to the command, for example, **hb clean out/board/product**. By default, the files in the **out** directory are cleared.
```shell
hb clean
usage: hb clean [-h][out_path]
positional arguments:
out_path clean a specified path.
optional arguments:
-h, --help show this help message and exit
```
### Building Procedures
You can add and build a product, component, chipset solution, and module. For details, see:
-[Adding and Building a Product](subsys-build-product.md#adding-and-building-a-product)
-[Adding and Building a Component](subsys-build-component.md#adding-and-building-a-component)
-[Adding and Building a Module](subsys-build-module.md#adding-and-building-a-module)
-[Adding and Building a Chipset Solution](subsys-build-chip_solution.md#adding-and-building-a-chipset-solution)
## FAQs
-[Common Build Problems and Solutions](subsys-build-FAQ.md)
## Reference
-[deps and external_deps](subsys-build-reference.md#deps-and-external_deps)
-[Information Collected by the Open Source Software Notice](subsys-build-reference.md#information-collected-by-the-open-source-software-notice)
-[Parameters for Accelerating Local Build](subsys-build-reference.md#parameters-for-accelerating-local-build)
- The chipset solution is a special component. It is built based on a development board, including the drivers, device API adaptation, and SDK.
- The source code path is named in the **device/{Development board}/{Chipset solution vendor}** format.
- The chipset solution component is built by default based on the development board selected.
- The chipset solution directory structure is as follows:
```shell
device
└── board
└── company # Chipset solution vendor
└── hispark_aries # Developement board name
├── BUILD.gn # Build script
├── hals # OS device API adaptation
├── linux # (Optional) Linux kernel version
│ └── config.gni # Linux build configuration
└── liteos_a # (Optional) LiteOS kernel version
└── config.gni # LiteOS_A build configuration
```
**NOTE**<br>The **config.gni** file contains the configuration related to the build of the development board. The parameters in this file are used to compile all OS components and are globally visible during the build process.
- The **config.gni** file contains the following key parameters:
```shell
kernel_type: Kernel used by the development board, for example, LiteOS_A, LiteOS_M, or Linux.
kernel_version: Kernel version of the development board, for example, 4.19.
board_cpu: CPU of the development board, for example, Cortex-A7 or RISCV32.
board_arch: Chipset architecture of the development board, for example, ARMv7-A or RV32IMAC.
board_toolchain: Name of the customized build toolchain used by the development board, for example, gcc-arm-none-eabi. If this field is not specified, ohos-clang will be used by default.
board_toolchain_prefix: Prefix of the toolchain, for example, gcc-arm-none-eabi.
board_toolchain_type: Toolchain type. Currently, only GCC and clang are supported.
board_cflags: Build options of the .c file configured for the development board.
board_cxx_flags: Build options of the .cpp file configured for the development board.
board_ld_flags: Linking options configured for the development board.
```
### Adding and Building a Chipset Solution
The following uses the RTL8720 development board provided by Realtek as an example. The procedure is as follows:
1. Create a directory for the chipset solution.<br> Run the following command in the root code directory:
```shell
mkdir-p device/board/realtek/rtl8720
```
2. Create a directory for kernel adaptation and configure the **config.gni** file of the development board.<br> For example, to adapt the LiteOS-A kernel to the RTL8720 development board, configure the **device/realtek/rtl8720/liteo_a/config.gni** file as follows:
```shell
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type ="liteos_a"
# Kernel version.
kernel_version ="3.0.0"
# Board CPU type, e.g. "cortex-a7", "riscv32".
board_cpu ="real-m300"
# Board arch, e.g. "armv7-a", "rv32imac".
board_arch =""
# Toolchain name used for system compiling.
# E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang, riscv32-unknown-elf.
# Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toochain.
board_toolchain ="gcc-arm-none-eabi"
# The toolchain path instatlled, it's not mandatory if you have added toolchian path to your ~/.bashrc.
3. Write the build script.<br> Create the **BUILD.gn** file in the development board directory. The target name must be the same as that of the development board. The following is an example of the **device/board/realtek/rtl8720/BUILD.gn** file for the RTL8720 development board:
```shell
group("rtl8720"){# The build target can be shared_library, static_library, or an executable file.
# Content
......
}
```
4. Build the chipset solution.<br> Run the **hb build** command in the development board directory to start the build.
The **bundle.json** file of a component is stored in the root directory of the component source code. The following example shows how to configure the sensor service component of the pan-sensor subsystem:
```shell
{
"name": "@ohos/sensor_lite", # OpenHarmony Package Manager (HPM) component name, in the "@Organization/Component name" format.
"description": "Sensor services", # Description of the component function.
"version": "3.1", # Version, which must be the same as the version of OpenHarmony.
"license": "MIT", # Component license.
"publishAs": "code-segment", # HPM package release mode. The default value is code-segment.
"segment": {
"destPath": ""
}, # Code restoration path (source code path) set when publishAs is code-segment.
"dirs": {"base/sensors/sensor_lite"}, # Directory structure of the HPM package. This field is mandatory and can be left empty.
"scripts": {}, # Scripts to be executed. This field is mandatory and can be left empty.
"licensePath": "COPYING",
"readmePath": {
"en": "README.rst"
},
"component": {# Component attributes.
"name": "sensor_lite", # Component name.
"subsystem": "", # Subsystem to which the component belongs.
"syscap": [], # System capabilities provided by the component for applications.
"features": [], # List of external configurable features of a component. Generally, this parameter corresponds to sub_component in build.
"adapted_system_type": [], # Types of adapted systems, which can be mini, small, and standard.
"rom": "92KB", # Component ROM size.
"ram": "~200KB", # Component RAM size.
"deps": {
"components": [# Other components on which this component depends.
"samgr_lite",
"ipc_lite"
],
"third_party": [# Third-party open-source software on which this component depends.
"test": []# Entry for building the component's test cases.
}
}
}
```
>  **NOTE**<br>Existing components on the LiteOS are configured in the JSON file of the corresponding subsystem in the **build/lite/components** directory. The directory is named in the **{Domain}/{Subsystem}/{Component}** format. The component directory structure is as follows:
```shell
component
├── interfaces
│ ├── innerkits # APIs exposed internally among components
│ └── kits # APIs provided for application developers
├── frameworks # Framework implementation
├── services # Service implementation
├── BUILD.gn # Build script
```
You need to configure the component name, source code path, function description, mandatory or not, build target, RAM, ROM, output, adapted kernel, configurable features, and dependencies.
When adding a component, you must add the component definition to the JSON file of the corresponding subsystem. The component configured for a product must have been defined in a subsystem. Otherwise, the verification will fail.
### Adding and Building a Component
1. Add a component.<br> The following use a custom component as an example to describe how to compile a library, executable file, and configuration file.
In this example, **partA** consists of **feature1**, **feature2**, and **feature3**, which represent a dynamic library, an executable file, and an etc configuration file, respectively.
Add **partA** to a subsystem, for example, **subsystem_examples** (defined in the **test/examples/** directory).
The directory structure of **partA** is as follows:
```shell
test/examples/partA
├── feature1
│ ├── BUILD.gn
│ ├── include
│ │ └── helloworld1.h
│ └── src
│ └── helloworld1.cpp
├── feature2
│ ├── BUILD.gn
│ ├── include
│ │ └── helloworld2.h
│ └── src
│ └── helloworld2.cpp
└── feature3
├── BUILD.gn
└── src
└── config.conf
```
(a) Configure **test/examples/partA/feature1/BUILD.gn** for the dynamic library.
```shell
config("helloworld_lib_config"){
include_dirs =["include"]
}
ohos_shared_library("helloworld_lib"){
sources =[
"include/helloworld1.h",
"src/helloworld1.cpp",
]
public_configs =[":helloworld_lib_config"]
part_name ="partA"
}
```
(b) Configure **test/examples/partA/feature2/BUILD.gn** for the executable file.
```shell
ohos_executable("helloworld_bin"){
sources =[
"src/helloworld2.cpp"
]
include_dirs =["include"]
deps =[# Dependent modules in the component
"../feature1:helloworld_lib"
]
external_deps =["partB:module1"]# (Optional) Dependent modules of another component are named in the Component name:Module name format.
install_enable =true# By default, executable programs are not installed. Set this parameter to true if an executable program needs to be installed.
part_name ="partA"
}
```
(c) Configure **test/examples/partA/feature3/BUILD.gn** for the etc module.
```shell
ohos_prebuilt_etc("feature3_etc"){
source="src/config.conf"
relative_install_dir ="init"# (Optional) Relative directory for installing the module. The default installation directory is **/system/etc**.
part_name ="partA"
}
```
(d) Add the module configuration **test/examples/bundle.json** to the **bundle.json** file of the component. Each component has a **bundle.json** file in the root directory of the component. For details, see the [component bundle.json file](subsys-build-component.md#configuration-rules).
2. Add the component to **//vendor/{*product_company*}/{*product-name*}/config.json**.
For example, after you add "subsystem_examples:partA" to the product **config.json** file, **partA** will be built and packaged into the distribution.
3. Start the build.<br> You can start the build by using the [CLI or hb tool](subsys-build-all.md#build-commands). The following uses the CLI as an example:
You can run **--build-target***Component name* to build a component separately. For example, to build the musl component of hispark_taurus_standard, run the following command:
4. Obtain the build result.<br> You can obtain the generated files from the **out/hispark_taurus/** directory and the image in the **out/hispark_taurus/packages/phone/images/** directory.
This document describes how to declare, define, and configure features.
- Declare a feature
Declare the features of a component in **feature_list** of the **bundle.json** file of the component. Each feature must start with the **{component name}**.
The following is an example:
```
{
"name": "@ohos/xxx",
"component": {
"name": "partName",
"subsystem": "subsystemName",
"features": [
"{partName}_feature_A"
]
}
}
```
You can declare multiple features in **features** for a component.
- Define a feature
You can define the default value of a feature as follows:
```
declare_args() {
{partName}_feature_A = true
}
```
The value defined is the default value of the component. The product can overload the feature default values in the component list.
If a feature is used by multiple modules of a component, you are advised to define the feature in the global .gni file of the component and import the .gni file to the **BUILD.gn** file of each module.
- Configure a feature
In the **BUILD.gn** file, determine the code or modules to build based on features.
```
if ({partName}_feature_A) {
sources += [ "xxx.c" ]
}
# Dependency introduced by a feature can be isolated by feature.
if ({partName}_feature_A) {
deps += [ "xxx" ]
external_deps += [ "xxx" ]
}
# The bundle.json file does not support the if statement. If the sub_component contained in the bundle.json file needs to be deleted, define group().
group("testGroup") {
deps = []
if ({partName}_feature_A) {
deps += [ "xxx" ]
}
}
```
You can also define code macros for modules in the following way to implement differentiated configuration:
@@ -6,13 +6,11 @@ Generate Ninja (GN) is a meta-build system that generates build files for Ninja.
...
@@ -6,13 +6,11 @@ Generate Ninja (GN) is a meta-build system that generates build files for Ninja.
### GN
### GN
- GN is used in large software systems such as Chromium, Fuchsia, and OpenHarmony.
GN is used in large software systems such as Chromium, Fuchsia, and OpenHarmony. However, the GN syntax has limitations rooted in its design philosophy. For details, see https://gn.googlesource.com/gn/+/main/docs/language.md#Design-philosophy. For example, GN does not support wildcards and cannot get the length of a list. If you find it complex to implement something with GN, stop and consider whether it is necessary to do it. For more details about GN, see https://gn.googlesource.com/gn/+/main/docs/.
- However, the GN syntax has limitations rooted in its [design philosophy](https://gn.googlesource.com/gn/+/main/docs/language.md#Design-philosophy). For example, it does not support wildcards and cannot get the length of a list. If you find it complex to implement something with GN, stop and consider whether it is necessary to do it.
- For more details about GN, visit https://gn.googlesource.com/gn/+/main/docs/.
### Intended Audience and Purpose
### Intended Audience and Purpose
This document is intended for OpenHarmony developers. This document describes the GN coding style and practices. It does not cover the GN syntax. For details about the GN basics, see [GN Reference](https://gn.googlesource.com/gn/+/main/docs/reference.md).
This document is intended for OpenHarmony developers. It describes the GN coding style and practices, but does not cover the GN syntax. For details about the GN basics, see https://gn.googlesource.com/gn/+/main/docs/reference.md.
### General Principles
### General Principles
...
@@ -30,7 +28,7 @@ A local variable is a variable restricted to use in a certain scope and cannot b
...
@@ -30,7 +28,7 @@ A local variable is a variable restricted to use in a certain scope and cannot b
Different from global variables, local variables start with an underscore (_).
Different from global variables, local variables start with an underscore (_).
```
```shell
# Example 1:
# Example 1:
action("some_action"){
action("some_action"){
...
...
...
@@ -53,7 +51,7 @@ A global variable starts with a lowercase letter.
...
@@ -53,7 +51,7 @@ A global variable starts with a lowercase letter.
Use **declare_args** to declare the variable value only if the variable value can be modified by **gn args**.
Use **declare_args** to declare the variable value only if the variable value can be modified by **gn args**.
```
```shell
# Example 2
# Example 2
declare_args(){
declare_args(){
# The value of some_feature can be changed by gn args.
# The value of some_feature can be changed by gn args.
...
@@ -71,7 +69,7 @@ Name the subtargets in templates in the ${target_name}+double underscores (__)+s
...
@@ -71,7 +69,7 @@ Name the subtargets in templates in the ${target_name}+double underscores (__)+s
- The double underscores (__) help locate the module to which a subtarget belongs.
- The double underscores (__) help locate the module to which a subtarget belongs.
@@ -89,7 +87,7 @@ Name the subtargets in templates in the ${target_name}+double underscores (__)+s
...
@@ -89,7 +87,7 @@ Name the subtargets in templates in the ${target_name}+double underscores (__)+s
Name templates in the verb+object format.
Name templates in the verb+object format.
```
```shell
# Example 4
# Example 4
# Good
# Good
template("compile_resources"){
template("compile_resources"){
...
@@ -109,7 +107,7 @@ $ gn format path-to-BUILD.gn
...
@@ -109,7 +107,7 @@ $ gn format path-to-BUILD.gn
For example, the original import sequence is as follows:
For example, the original import sequence is as follows:
```
```shell
# Example 5
# Example 5
import("//b.gni")
import("//b.gni")
import("//a.gni")
import("//a.gni")
...
@@ -117,14 +115,14 @@ import("//a.gni")
...
@@ -117,14 +115,14 @@ import("//a.gni")
**gn format** sorts the files as follows:
**gn format** sorts the files as follows:
```
```shell
import("//a.gni")
import("//a.gni")
import("//b.gni")
import("//b.gni")
```
```
To maintain the original sequence, add an empty comment line.
To maintain the original sequence, add an empty comment line.
```
```shell
import("//b.gni")
import("//b.gni")
# Comment to keep the original sequence
# Comment to keep the original sequence
import("//a.gni")
import("//a.gni")
...
@@ -148,7 +146,7 @@ Lack of dependency leads to the following problems:
...
@@ -148,7 +146,7 @@ Lack of dependency leads to the following problems:
- Unexpected compilation error
- Unexpected compilation error
```
```shell
# Example 6
# Example 6
# Lack of dependency poses a possibility of compilation errors.
# Lack of dependency poses a possibility of compilation errors.
shared_library("a"){
shared_library("a"){
...
@@ -177,7 +175,7 @@ Another problem is unnecessary dependencies. Unnecessary dependencies reduce con
...
@@ -177,7 +175,7 @@ Another problem is unnecessary dependencies. Unnecessary dependencies reduce con
**_compile_js_target** does not necessarily depend on **_compile_resource_target**. If this dependency is added, **_compile_js_target** can be compiled only after **_compile_resource_target** is compiled.
**_compile_js_target** does not necessarily depend on **_compile_resource_target**. If this dependency is added, **_compile_js_target** can be compiled only after **_compile_resource_target** is compiled.
```
```shell
# Example 7:
# Example 7:
# Unnecessary dependencies slow down compilation.
# Unnecessary dependencies slow down compilation.
template("too_much_deps"){
template("too_much_deps"){
...
@@ -208,7 +206,7 @@ Unclear input leads to the following problems:
...
@@ -208,7 +206,7 @@ Unclear input leads to the following problems:
In the following example, **foo.py** references the functions in **bar.py**. This means **bar.py** is the input of **foo.py**. You need to add **bar.py** to **input** or **depfile** of **implict_input_action**. Otherwise, if **bar.py** is modified, **implict_input_action** will not be recompiled.
In the following example, **foo.py** references the functions in **bar.py**. This means **bar.py** is the input of **foo.py**. You need to add **bar.py** to **input** or **depfile** of **implict_input_action**. Otherwise, if **bar.py** is modified, **implict_input_action** will not be recompiled.
@@ -232,7 +230,7 @@ Unclear output leads to the following problems:
...
@@ -232,7 +230,7 @@ Unclear output leads to the following problems:
In the following example, **foo.py** generates two files: **a.out** and **b.out**. However, the output of **implict_output_action** declares only **a.out**. In this case, **b.out** is an implicit output, and the cache stores only **a.out**. When the cache is hit, **b.out** cannot be compiled.
In the following example, **foo.py** generates two files: **a.out** and **b.out**. However, the output of **implict_output_action** declares only **a.out**. In this case, **b.out** is an implicit output, and the cache stores only **a.out**. When the cache is hit, **b.out** cannot be compiled.
@@ -262,10 +260,10 @@ The native templates are not recommended due to the following reasons:
...
@@ -262,10 +260,10 @@ The native templates are not recommended due to the following reasons:
- The native **action** template cannot automatically detect the changes in the dependencies of the input file, and cannot start recompilation. See Example 8.
- The native **action** template cannot automatically detect the changes in the dependencies of the input file, and cannot start recompilation. See Example 8.
The table below lists the mapping between the GN native templates and templates provided by the compilation system.
The table below lists the mapping between the GN native templates and templates provided by OpenHarmony Compilation and Build subsystem.
| Template Provided by the Compilation System | GN Native Template |
| OpenHarmony Template | GN Native Template |
|:------------------- | -------------- |
| :------------------ | -------------- |
| ohos_shared_library | shared_library |
| ohos_shared_library | shared_library |
| ohos_source_set | source_set |
| ohos_source_set | source_set |
| ohos_executable | executable |
| ohos_executable | executable |
...
@@ -286,7 +284,7 @@ You are advised to use Python scripts instead of shell scripts in **action**. Co
...
@@ -286,7 +284,7 @@ You are advised to use Python scripts instead of shell scripts in **action**. Co
- Call **rebase_path** only in **args** of **action**.
- Call **rebase_path** only in **args** of **action**.
```
```shell
# Example 10
# Example 10
template("foo"){
template("foo"){
action(target_name){
action(target_name){
...
@@ -308,7 +306,7 @@ You are advised to use Python scripts instead of shell scripts in **action**. Co
...
@@ -308,7 +306,7 @@ You are advised to use Python scripts instead of shell scripts in **action**. Co
- If rebase_path is called twice for the same variable, unexpected results occur.
- If rebase_path is called twice for the same variable, unexpected results occur.
```
```shell
# Example 11
# Example 11
template("foo"){
template("foo"){
action(target_name){
action(target_name){
...
@@ -339,7 +337,7 @@ It is common to share data between modules. For example, module A wants to know
...
@@ -339,7 +337,7 @@ It is common to share data between modules. For example, module A wants to know
In the following example, the output of module **a** is the input of module **b**, and can be shared with module **b** via global variables.
In the following example, the output of module **a** is the input of module **b**, and can be shared with module **b** via global variables.
@@ -360,7 +358,7 @@ It is common to share data between modules. For example, module A wants to know
...
@@ -360,7 +358,7 @@ It is common to share data between modules. For example, module A wants to know
- To customize a template, pass (**forward**) **testonly** first because the **testonly** target may depend on the template target.
- To customize a template, pass (**forward**) **testonly** first because the **testonly** target may depend on the template target.
```
```shell
# Example 13
# Example 13
# For a customized template, pass testonly first.
# For a customized template, pass testonly first.
template("foo"){
template("foo"){
...
@@ -371,7 +369,7 @@ It is common to share data between modules. For example, module A wants to know
...
@@ -371,7 +369,7 @@ It is common to share data between modules. For example, module A wants to know
- Do not use asterisks (*) to **forward** variables. Required variables must be explicitly forwarded one by one.
- Do not use asterisks (*) to **forward** variables. Required variables must be explicitly forwarded one by one.
```
```shell
# Example 14
# Example 14
# Bad. The asterisk (*) is used to forward the variable.
# Bad. The asterisk (*) is used to forward the variable.
template("foo"){
template("foo"){
...
@@ -395,7 +393,7 @@ It is common to share data between modules. For example, module A wants to know
...
@@ -395,7 +393,7 @@ It is common to share data between modules. For example, module A wants to know
The value of **target_name** varies with the scope.
The value of **target_name** varies with the scope.
```
```shell
# Example 15
# Example 15
# The value of target_name varies with the scope.
# The value of target_name varies with the scope.
template("foo"){
template("foo"){
...
@@ -421,7 +419,7 @@ template("foo") {
...
@@ -421,7 +419,7 @@ template("foo") {
To export header files from a module, use **public_configs**.
To export header files from a module, use **public_configs**.
```
```shell
# Example 16
# Example 16
# b depends on a and inherits from the headers of a.
# b depends on a and inherits from the headers of a.
config("headers"){
config("headers"){
...
@@ -442,7 +440,7 @@ executable("b") {
...
@@ -442,7 +440,7 @@ executable("b") {
A custom template must contain a subtarget named **target_name**. This subtarget is used as the target of the template and depends on other subtargets. Otherwise, the subtargets will not be compiled.
A custom template must contain a subtarget named **target_name**. This subtarget is used as the target of the template and depends on other subtargets. Otherwise, the subtargets will not be compiled.
```
```shell
# Example 17
# Example 17
# A custom template must have a subtarget named target_name.
# A custom template must have a subtarget named target_name.
template("foo"){
template("foo"){
...
@@ -470,7 +468,7 @@ template("foo") {
...
@@ -470,7 +468,7 @@ template("foo") {
In addition to **sources**, **set_source_assignment_filter** can be used to filter other variables. After the filtering is complete, clear the filter and **sources**.
In addition to **sources**, **set_source_assignment_filter** can be used to filter other variables. After the filtering is complete, clear the filter and **sources**.
```
```shell
# Example 18
# Example 18
# Use set_source_assignment_filter to filter dependencies and add the dependencies with labels matching *:*_res to the dependency list.
# Use set_source_assignment_filter to filter dependencies and add the dependencies with labels matching *:*_res to the dependency list.
In the latest version, **set_source_assignment_filter** is replaced by **filter_include** and **filter_exclude**.
In the latest version, **set_source_assignment_filter** is replaced by **filter_include** and **filter_exclude**.
### Using deps and external_deps
### Setting deps and external_deps
- An OpenHarmony component is a group of modules that can provide a capability.
- When defining a module, you must specify **part_name** to indicate the component to which the module belongs.
An OpenHarmony component is a group of modules that can provide a capability. When defining a module, set **part_name** to specify the component to which the module belongs.
- You must also declare **inner-kit** of a component for other components to call. For details about the declaration of component **innerkit**, see **bundle.json** in the source code.
You must also declare **inner_kits** of a component for other components to call. For details, see **bundle.json** in the source code. **inner_kits** applies only to dependent modules in different components.
-**inner-kit** applies only to dependent modules in different components.
If modules **a** and **b** has the same **part_name**, modules **a** and **b** belong to the same component. In this case, declare the dependency between them using **deps**.
- If modules **a** and **b** has the same **part_name**, modules **a** and **b** belong to the same component. In this case, declare the dependency between them using **deps**.
If modules **a** and **b** have different **part_name**, modules **a** and **b** belong to different components. In this case, declare the dependency between them using **external_deps** in the *Component name:Module name* format. See Example 19.
- If modules **a** and **b** have different **part_name**, modules **a** and **b** belong to different components. In this case, declare the dependency between them using **external_deps** in the Component name:Module name format. See Example 19.
@@ -84,9 +84,9 @@ Resource files, which are stored in the **assets/entry/resources** directory for
...
@@ -84,9 +84,9 @@ Resource files, which are stored in the **assets/entry/resources** directory for
1. Save the developed application example to the **applications/standard/** directory.
1. Save the developed application example to the **applications/standard/** directory.
2. Configure the GN script **applications/standard/example/BUILD.gn**. The following is an example of the FA model. For details about more **BUILD.gn** configurations, see [GN Script Configuration Example](#gn-script-configuration-example).
2. Configure the GN script **applications/standard/example/BUILD.gn**. <br>The following is an example of the FA model. For details about more **BUILD.gn** configurations, see [GN Script Configuration Example](#gn-script-configuration-example).
The Compilation and Building subsystem provides a build framework based on Generate Ninja (GN) and Ninja. This subsystem allows you to:
- Assemble components into a product and build the product.
- Build chipset source code independently.
- Build a single component independently.
### Basic Concepts
Learn the following basic concepts before you start:
- Subsystem
A subsystem, as a logical concept, consists of one or more components. OpenHarmony is designed with a layered architecture, which consists of the kernel layer, system service layer, framework layer, and application layer from the bottom up. System functions are developed by levels, from system to subsystem and then to component. In a multi-device deployment scenario, you can customize subsystems and components as required.
- Component
A component is a reusable, configurable, and tailorable function unit. Each component has an independent directory, and can be built and tested independently and developed concurrently.
- GN
GN is short for Generate Ninja. It is used to build Ninja files.
- Ninja
Ninja is a small high-speed building system.
- hb
hb is an OpenHarmony command line tool used to execute build commands.
### Directory Structure
```
build/lite
├── components # Component description file
├── figures # Figures in the readme file
├── hb # hb pip installation package
├── make_rootfs # Script used to create a file system image
└── toolchain # Build toolchain configuration, which contains the compiler directories, build options, and linking options
```
### **Build Process**
The figure below shows the build process.
**Figure 1** Build process

1. Use **hb set** to set the OpenHarmony source code directory and the product to build.
2. Use **hb build** to build the product, development board, or component.
The procedure is as follows:
(1) Read the **config.gni** file of the development board selected. The file contains the build toolchain, linking commands, and build options.
(2) Run the **gn gen** command to read the product configuration and generate the **out** directory and **ninja** files for the solution.
(3) Run **ninja -C out/board/product** to start the build.
(4) Package the files built, set file attributes and permissions, and create a file system image.
## Configuration Rules
You can build a component, a chipset solution, and a product solution. To ensure that the chipset and product solutions are decoupled from OpenHarmony, follow the rules below:
### Component
The component source code directory is named in the *{Domain}/{Subsystem}/{Component}* format. The component directory structure is as follows:
> The .json file of the subsystem in the **build/lite/components** directory contains component attributes, including the name, source code directory, function description, mandatory or not, build targets, RAM, ROM, build outputs, adapted kernels, configurable features, and dependencies of the component. When adding a component, add the component information in the .json file of the corresponding subsystem. The component configured for a product must have been defined in a subsystem. Otherwise, the verification will fail.
```
component
├── interfaces
│ ├── innerkits # APIs exposed internally among components
│ └── kits # APIs provided for application developers
├── frameworks # Framework implementation
├── services # Service implementation
├── BUILD.gn # Build script
```
The following example shows how to configure attributes of the sensor service component of the pan-sensor subsystem:
```
{
"name": "@ohos/sensor_lite", # OpenHarmony Package Manager (HPM) component name, in the "@Organization/Component name" format.
"description": "Sensor services", # Description of the component functions.
"version": "3.1", # Version, which must be the same as the version of OpenHarmony.
"license": "MIT", # Component license.
"publishAs": "code-segment", # Mode for publishing the HPM package. The default value is code-segment.
"segment": {
"destPath": ""
}, # Code restoration path (source code path) set when "publishAs" is code-segment.
"dirs": {"base/sensors/sensor_lite"}, # Directory structure of the HPM package. This field is mandatory and can be left empty.
"scripts": {}, # Scripts to be executed. This field is mandatory and can be left empty.
"licensePath": "COPYING",
"readmePath": {
"en": "README.rst"
},
"component": { # Component attributes.
"name": "sensor_lite", # Component name.
"subsystem": "", # Subsystem to which the component belongs.
"syscap": [], # System capabilities provided by the component for applications.
"features": [], # List of external configurable features of a component. Generally, this parameter corresponds to sub_component in build and can be configured by the product.
"adapted_system_type": [], # Types of adapted systems. The value can be mini, small, and standard.
"rom": "92KB", # Component ROM size.
"ram": "~200KB",, # Component RAM size.
"deps": {
"components": [ # Other components on which this component depends.
"samgr_lite"
],
"third_party": [ # Third-party open-source software on which this component depends.
"test": [] # Entry for building the component's test cases.
}
}
}
```
Observe the following rules when writing the component's **BUILD.gn**:
- The build target name must be the same as the component name.
- Define the configurable features in the **BUILD.gn** file of the component. Name the configurable features in the ohos_{subsystem}*{component}*{feature} format. Define the features in component description and configure them in the **config.json** file.
- Define macros in the OHOS_{SUBSYSTEM}*{COMPONENT}*{FEATURE} format.
> The component build script is written in GN. For details about how to use GN, see [GN Quick Start Guide](https://gn.googlesource.com/gn/+/master/docs/quick_start.md). The component is the build target, which can be a static library, a dynamic library, an executable file, or a group.
The following example shows the **foundation/graphic/ui/BUILD.gn** file for a graphics UI component:
```
# Declare the configurable features of the component.
declare_args() {
enable_ohos_graphic_ui_animator = false # Whether to enable animation.
ohos_ohos_graphic_ui_font = "vector" # Configurable font type, which can be vector or bitmap.
}
# Basic component functions.
shared_library("base") {
sources = [
...
]
include_dirs = [
...
]
}
# Build only when the animator is enabled.
if(enable_ohos_graphic_ui_animator ) {
shared_library("animator") {
sources = [
...
]
include_dirs = [
...
]
deps = [ :base ]
}
}
...
# It is recommended that the target name be the same as the name of the component, which can be an executable file (.bin), shared_library (.so file), static_library (.a file), or a group.
executable("ui") {
deps = [
":base"
]
# The animator feature is configured by the product.
if(enable_ohos_graphic_ui_animator ) {
deps += [
"animator"
]
}
}
```
### Chipset Solution
- The chipset solution is a special component. It is built based on a development board, including the drivers, device API adaptation, and SDK.
- The source code path is named in the **device/{Development board}/{Chipset solution vendor}** format.
- The chipset solution component is built by default based on the development board selected.
- The chipset solution directory structure is as follows:
> The **config.gni** file contains build-related configuration of the development board. The parameters in the file are used to build all OS components, and are globally visible to the system during the build process.
- The **config.gni** file contains the following key parameters:
```
kernel_type: Kernel used by the development board, for example, LiteOS_A, LiteOS_M, or Linux.
kernel_version: Kernel version of the development board, for example, 4.19.
board_cpu: CPU of the development board, for example, Cortex-A7 or RISCV32.
board_arch: Chipset architecture of the development board, for example, ARMv7-A or RV32IMAC.
board_toolchain: Name of the customized build toolchain used by the development board, for example, gcc-arm-none-eabi. If this field is not specified, ohos-clang will be used by default.
board_toolchain_prefix: Prefix of the toolchain, for example, gcc-arm-none-eabi.
board_toolchain_type: Toolchain type. Currently, only GCC and clang are supported.
board_cflags: Build options of the .c file configured for the development board.
board_cxx_flags: Build options of the .cpp file configured for the development board.
board_ld_flags: Linking options configured for the development board.
```
### Product Solution
The product solution is a special component. It is a product built based on a development board. It includes the OS adaptation, component assembly and configuration, startup configuration, and file system configuration. The source code directory is named in the **vendor**/{*Product solution vendor*}/{*Product name*} format.
The product solution directory structure is as follows:
```
vendor
└── company # Product solution vendor
├── product # Product name
│ ├── init_configs
│ │ ├── etc # Startup configuration of the init process (only required for the Linux kernel)
│ │ └── init.cfg # System service startup configuration
│ ├── hals # OS adaptation
│ ├── BUILD.gn # Product build script
│ └── config.json # Product configuration file
│ └── fs.yml # File system packaging configuration
> Follow the preceding rules to create directories and files for new products. The Compilation and Building subsystem scans the configured products based on the rules.
The key directories and files are described as follows:
1.**vendor/company/product/init_configs/etc**
This folder contains the rcS, Sxxx, and fstab scripts. The init process runs the rcS, fstab, and S00-xxx scripts in sequence before starting system services. The **S***xxx* script is used to create device nodes and directories, scan device nodes, and change file permissions for the development board and product. These scripts are copied from the **BUILD.gn** file to the **out** directory of the product as required and packaged into the **rootfs** image.
This file is the configuration file for the **init** process to start services. Currently, the following commands are supported:
-**start**: starts a service.
-**mkdir**: creates a folder.
-**chmod**: changes the permission on a specified directory or file.
-**chown**: changes the owner group of a specified directory or file.
-**mount**: mounts a device.
The fields in the file are described as follows:
```
{
"jobs" : [{ # Job array. A job corresponds to a command set. Jobs are executed in the following sequence: pre-init > init > post-init.
"name" : "pre-init",
"cmds" : [
"mkdir /storage/data", # Create a directory.
"chmod 0755 /storage/data", #Modify the permissions. The format of the permission value is 0xxx, for example, 0755.
"mkdir /storage/data/log",
"chmod 0755 /storage/data/log",
"chown 4 4 /storage/data/log", # Change the owner group. The first number is the user ID (UID), and the second number is the group ID (GID).
...
"mount vfat /dev/mmcblock0 /sdcard rw,umask=000" # The command format is mount [File system type] [source] [target] [flags] [data].
# The value of flags can be nodev, noexec, nosuid, or rdonly only.
]
}, {
"name" : "init",
"cmds" : [ # Start services based on the sequence of the cmds array.
"start shell", # There is only one space between start and the service name.
...
"start service1"
]
}, {
"name" : "post-init", # Job that is finally executed. Operations performed after the init process is started, for example, mounting a device after the driver initialization).
"cmds" : []
}
],
"services" : [{ # Service array. A service corresponds to a process.
"name" : "shell", # Service name.
"path" : ["/sbin/getty", "-n", "-l", "/bin/sh", "-L", "115200", "ttyS000", "vt100"], # Full path of the executable file. It must start with "path".
"uid" : 0, # Process UID, which must be the same as that in the binary file.
"gid" : 0, # Process GID, which must be the same as that in the binary file.
"once" : 0, # Whether the process is a one-off process. The value 1 indicates that process is a one-off process, and the value 0 indicates the opposite. The init process does not restart the one-off process after the process exits.
"importance" : 0, # Whether the process is a key process. The value 1 indicates a key process, and the value 0 indicates the opposite. If a key process exits, the init process will restart the board.
"caps" : [4294967295]
},
...
]
}
```
3.**vendor/company/product/init_configs/hals**
This file contains the OS adaptation of the product. For details about APIs for implementing OS adaptation, see the readme file of each component.
4.**vendor/company/product/config.json**
The **config.json** file is the main entry for the build and contains configurations of the development board, OS, and kernel.
The following example shows the **config.json** file of the IP camera developed based on the hispark_taurus board:
```
{
"product_name": "ipcamera", # Product name
"version": "3.0", # Version of config.json. The value is 3.0.
"type": "small", # System type. The value can be mini, small, or standard.
"ohos_version": "OpenHarmony 1.0", # OS version
"device_company": "hisilicon", # Chipset vendor
"board": "hispark_taurus", # Name of the development board
This file defines the process for creating a file system image, for example, **rootfs.img** (user-space root file system) and **userfs.img** (readable and writable file). It consists of multiple lists, and each list corresponds to a file system. The fields are described as follows:
```
fs_dir_name: (Mandatory) specifies name of the file system, for example, rootfs or userfs.
fs_dirs: (Optional) specifies the mapping between the file directory in the out directory and the system file directory. Each file directory corresponds to a list.
source_dir: (Optional) specifies target file directory in the out directory. If this field is not specified, an empty directory will be created in the file system based on target_dir.
target_dir: (Mandatory) specifies the file directory in the file system.
ignore_files: (Optional) declares ignored files during the copy operation.
dir_mode: (Optional) specifies the file directory permissions. The default value is 755.
file_mode: (Optional) specifies the permissions of all files in the directory. The default value is 555.
fs_filemode: (Optional) specifies the files that require special permissions. Each file corresponds to a list.
file_dir: (Mandatory) specifies the detailed file path in the file system.
file_mode: (Mandatory) declares file permissions.
fs_symlink: (Optional) specifies the soft link of the file system.
fs_make_cmd: (Mandatory) creates the file system script. The script provided by the OS is located in the build/lite/make_rootfs directory. Linux, LiteOS, ext4, jffs2, and vfat are supported. Chipset vendors can also customize the script as required.
fs_attr: (Optional) dynamically adjusts the file system based on configuration items.
```
The **fs_symlink** and **fs_make_cmd** fields support the following variables:
-**${root_path}**: Code root directory, which corresponds to **${ohos_root_path}** of GN.
-**${out_path}**: The **out** directory of the product, which corresponds to **${root_out_dir}** of GN.
-**${fs_dir}**: File system directory, which consists of variables **${root_path}** and **${fs_dir_name}**.
> **fs.yml** is optional and not required for devices without a file system.
6.**vendor/company/product/BUILD.gn**
This file provides the product built entry. It is used to build the source code of the solution vendor and copy the startup configuration file. The **BUILD.gn** file in the corresponding product directory will be built by default if a product is selected.
The following is an example of the **BUILD.gn** file of a product:
```
group("product") { # The name must be the same as the product name (level-3 directory name under the product directory).
deps = []
# Copy the init configuration.
deps += [ "init_configs" ]
# Others
...
}
```
## Guidelines
### Prerequisites
The development environment has GN, Ninja, Python 3.9.2 or later, and hb available. For details about the installation method, see [Setting Up Environments for the Mini and Small Systems](../quick-start/quickstart-lite-env-setup.md).
### Using hb
**hb** is an OpenHarmony command line tool for executing build commands. Common hb commands are described as follows:
**hb set**
```
hb set -h
usage: hb set [-h] [-root [ROOT_PATH]] [-p]
optional arguments:
-h, --help show this help message and exit
-root [ROOT_PATH], --root_path [ROOT_PATH]
Set OHOS root path
-p, --product Set OHOS board and kernel
```
- If you run **hb set** with no argument, the default setting process starts.
- You can run **hb set -root***dir* to set the root directory of the source code.
- You can run **hb set -p** to set the product to build.
-v, --verbose show all command lines while building
-shs, --sign_haps_by_server
sign haps by server
--patch apply product patch before compiling
--compact-mode compatible with standard build system set to false if we use build.sh as build entrance
--gn-args GN_ARGS specifies gn build arguments, eg: --gn-args="foo="bar" enable=true blah=7"
--keep-ninja-going keeps ninja going until 1000000 jobs fail
--build-only-gn only do gn parse, donot run ninja
--log-level LOG_LEVEL
specifies the log level during compilationyou can select three levels: debug, info and error
--fast-rebuild it will skip prepare, preloader, gn_gen steps so we can enable it only when there is no change
for gn related script
--device-type DEVICE_TYPE
specifies device type
--build-variant BUILD_VARIANT
specifies device operating mode
```
- If you run **hb build** with no argument, the previously configured code directory, product, and options are used for the build. The **-f** option deletes all products to be built. It is equivalent to running **hb clean** and **hb build**.
- You can run **hb build***{component_name}* to build product components separately based on the development board and kernel set for the product, for example, **hb build kv_store**.
- You can run **hb build -p ipcamera@hisilicon** to skip the setting step and build the product directly.
- You can run **hb build** in **device/board/device_company** to select the kernel and build an image that contains the kernel and drivers only based on the current development board and the selected kernel.
**hb clean**
You can run **hb clean** to delete all the files except **args.gn** and **build.log** in the **out** directory. To clear files in a specified directory, add the directory parameter to the command, for example, **hb clean out/board/product**. By default, the files in the **out** directory are cleared.
```
hb clean
usage: hb clean [-h] [out_path]
positional arguments:
out_path clean a specified path.
optional arguments:
-h, --help show this help message and exit
```
### Adding a Component
To add a component, determine the subsystem to which the component belongs and the component name, and then perform the following steps:
1. Add the component build script after the source code development is complete.
The following example shows the **BUILD.gn** script (in the **applications/sample/hello_world** directory) for the **hello_world** executable file.
```
executable("hello_world") {
include_dirs = [
"include",
]
sources = [
"src/hello_world.c"
]
}
```
This script can be used to build a file named **hello_world** that can run on OpenHarmony.
To build the preceding component separately, run **hb set** to select a product and run the following command to build **hello_world** separately.
```
hb build -f -T //applications/sample/hello_world
```
After the component functions are verified on the development board, perform steps 2 to 4 to add the component to the product.
2. Add the component description.
The component description is stored in the **build/lite/components** directory. Add the new component to the .json file of the corresponding subsystem. The component description must contain the following fields:
-**component**: component name.
-**description**: description of the component functions.
-**optional**: whether the component is optional.
-**dirs**: source code directory of the component.
-**targets**: component build entry.
The following is an example of adding the **hello_world** component to the **applications.json** file.
```
{
"components": [
{
"component": "hello_world",
"description": "Hello world.",
"optional": "true",
"dirs": [
"applications/sample/hello_world"
],
"targets": [
"//applications/sample/hello_world"
]
},
...
]
}
```
3. Add the component to the product.
The product configuration file **config.json** is located in the **vendor/company/product/** directory. This file contains the product name, OpenHarmony version, device vendor, development board, kernel type, kernel version, subsystems, and components. The following example adds **hello_world** to the **my_product.json** file:
```
{
"product_name": "hello_world_test",
"ohos_version": "OpenHarmony 1.0",
"device_company": "hisilicon",
"board": "hispark_taurus",
"kernel_type": "liteos_a",
"kernel_version": "1.0.0",
"subsystems": [
{
"subsystem": "applications",
"components": [
{ "component": "hello_world", "features":[] }
]
},
...
]
}
```
4. Build the product.
1. Run the **hb set** command in the root code directory and select the product.
2. Run the **hb build** command.
### Adding a Chipset Solution
The following uses the RTL8720 development board provided by Realtek as an example. To a chipset solution, perform the following steps:
1. Create a directory for the chipset solution based on the [configuration rules](#chipset-solution).
Run the following command in the root directory of the code:
```
mkdir -p device/board/realtek/rtl8720
```
2. Create a directory for kernel adaptation and write the **config.gni** file of the development board.
For example, to adapt the LiteOS-A kernel to the RTL8720 development board, write the **device/realtek/rtl8720/liteo_a/config.gni** file as follows:
```
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_a"
# Kernel version.
kernel_version = "3.0.0"
# Board CPU type, e.g. "cortex-a7", "riscv32".
board_cpu = "real-m300"
# Board arch, e.g. "armv7-a", "rv32imac".
board_arch = ""
# Toolchain name used for system build.
# E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang, riscv32-unknown-elf.
# Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toochain.
board_toolchain = "gcc-arm-none-eabi"
# Toolchain installation path, which can be left blank if the installation path is added to ~/.bashrc.
Create the **BUILD.gn** file in the development board directory. The target name must be the same as that of the development board. The following is an example of the **device/realtek/rtl8720/BUILD.gn** file for the RTL8720 development board:
```
group("rtl8720") { # The build target can be shared_library, static_library, or an executable file.
# Content
...
}
```
4. Build the chipset solution.
Run the **hb build** command in the development board directory to start the build.
### Adding a Product Solution
You can customize a product solution by flexibly assembling a chipset solution and components. The procedure is as follows:
1. Create a product directory based on the [configuration rules](#product-solution).
The following uses the Wi-Fi IoT module on the RTL8720 development board as an example. Run the following command in the root directory to create a product directory:
```
mkdir -p vendor/my_company/wifiiot
```
2. Assemble the product.
Create a **config.json** file, for example for wifiiot, in the product directory. The **vendor/my_company/wifiiot/config.json** file is as follows:
```
{
"product_name": "wifiiot", # Product name
"version": "3.0", # Version of config.json. The value is 3.0.
"type": "small", # System type. The value can be mini, small, or standard.
"ohos_version": "OpenHarmony 1.0", # OS version
"device_company": "realtek", # Name of the chipset solution vendor
"board": "rtl8720", # Name of the development board
"kernel_type": "liteos_m", # Kernel type
"kernel_version": "3.0.0", # Kernel version
"subsystems": [
{
"subsystem": "kernel", # Subsystem
"components": [
{ "component": "liteos_m", "features":[] } # Component and its features
> Before the build, the Compilation and Building subsystem checks the validity of fields in **config.json**. The **device_company**, **board**, **kernel_type**, and **kernel_version** fields must match the fields of the chipset solution, and **subsystem** and **component** must match the component description in the **build/lite/components** file.
3. Implement adaptation to OS APIs.
Create the **hals** directory in the product directory and save the source code as well as the build script for OS adaptation in this directory.
4. Configure system services.
Create the **init_configs** directory in the product directory and then the **init.cfg** file in the **init_configs** directory, and configure the system services to be started.
5. (Optional) Configure the init process for the Linux kernel.
Create the **etc** directory in the **init_configs** directory, and then the **init.d** folder and the **fstab** file in the **etc** directory. Then, create the **rcS** and **S***xxx* files in the **init.d** file and edit them based on product requirements.
6. (Optional) Configure the file system image for the development board that supports the file system.
Create a **fs.yml** file in the product directory and configure it as required. A typical **fs.yml** file is as follows:
```
-
fs_dir_name: rootfs # Image name
fs_dirs:
-
# Copy the files in the out/my_board/my_product/bin directory to the rootfs/bin directory and ignore the .bin files related to testing.
source_dir: bin
target_dir: bin
ignore_files:
- Test.bin
- TestSuite.bin
-
# Copy the files in the out/my_board/my_product/libs directory to the rootfs/lib directory, ignore all .a files, and set the file permissions to 644 and folder permissions 755.
source_dir: libs
target_dir: lib
ignore_files:
- .a
dir_mode: 755
file_mode: 644
-
source_dir: usr/lib
target_dir: usr/lib
ignore_files:
- .a
dir_mode: 755
file_mode: 644
-
source_dir: config
target_dir: etc
-
source_dir: system
target_dir: system
-
source_dir: sbin
target_dir: sbin
-
source_dir: usr/bin
target_dir: usr/bin
-
source_dir: usr/sbin
target_dir: usr/sbin
-
# Create an empty proc directory.
target_dir: proc
-
target_dir: mnt
-
target_dir: opt
-
target_dir: tmp
-
target_dir: var
-
target_dir: sys
-
source_dir: etc
target_dir: etc
-
source_dir: vendor
target_dir: vendor
-
target_dir: storage
fs_filemode:
-
file_dir: lib/ld-uClibc-0.9.33.2.so
file_mode: 555
-
file_dir: lib/ld-2.24.so
file_mode: 555
-
file_dir: etc/init.cfg
file_mode: 400
fs_symlink:
-
# Create the soft link ld-musl-arm.so.1 -> libc.so in the rootfs/lib directory.
source: libc.so
link_name: ${fs_dir}/lib/ld-musl-arm.so.1
-
source: mksh
link_name: ${fs_dir}/bin/sh
-
source: mksh
link_name: ${fs_dir}/bin/shell
fs_make_cmd:
# Run the script to create an ext4 image from rootfs.
7. (Optional) Configure patches if the product and components need to be patched.
Create a **patch.yml** file in the product directory and configure it as required. A typical **patch.yml** file is as follows:
```
# Directory in which the patch is to be installed
foundation/communication/dsoftbus:
# Directory in which the patch is stored.
- foundation/communication/dsoftbus/1.patch
- foundation/communication/dsoftbus/2.patch
third_party/wpa_supplicant:
- third_party/wpa_supplicant/1.patch
- third_party/wpa_supplicant/2.patch
- third_party/wpa_supplicant/3.patch
...
```
Add **--patch** when running the **hb build** command. Then, the patch files can be added to the specified directory before the build.
```
hb build -f --patch
```
8. Write the build script.
Create a **BUILD.gn** file in the product directory and write the script. The following **BUILD.gn** file uses the Wi-Fi IoT module in step 1 as an example:
```
group("wifiiot") { # The target name must be the same as the product name.
deps = []
# Copy the init configuration.
deps += [ "init_configs" ]
# Add **hals**.
deps += [ "hals" ]
# Others
...
}
```
9. Build the product.
Run the **hb set** command in the code root directory, select the new product as prompted, and run the **hb build** command.
## Troubleshooting
### "usr/sbin/ninja: invalid option -- w" Displayed During the Build Process
-**Symptom**
The build fails, and **usr/sbin/ninja: invalid option -- w** is displayed.
-**Possible Causes**
The Ninja version in use does not support the **--w** option.
-**Solution**
Uninstall Ninja and GN, and [install Ninja and GN of the required version](../get-code/gettools-ide.md).
### "/usr/bin/ld: cannot find -lncurses" Displayed During the Build Process
-**Symptom**
The build fails, and **/usr/bin/ld: cannot find -lncurses** is displayed.
-**Possible Causes**
The ncurses library is not installed.
-**Solution**
```
sudo apt-get install lib32ncurses5-dev
```
### "line 77: mcopy: command not found" Displayed During the Build Process
-**Symptom**
The build fails, and **line 77: mcopy: command not found** is displayed.
-**Possible Causes**
mcopy is not installed.
-**Solution**
```
sudo apt-get install dosfstools mtools
```
### "riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory" Displayed During the Build Process
-**Symptom**
The build fails, and the following information is displayed: <br>**riscv32-unknown-elf-gcc: error trying to exec 'cc1': execvp: No such file or directory**
-**Possible Causes**
Permission is required to access files in the RISC-V compiler directory.
-**Solution**
1. Run the following command to locate **gcc_riscv32**:
```
which riscv32-unknown-elf-gcc
```
2. Run the **chmod** command to change the directory permission to **755**.
### "No module named 'Crypto'" Displayed During the Build Process
-**Symptom**
The build fails, and **No module named 'Crypto'** is displayed.
-**Possible Causes**
Crypto is not installed in Python 3.
-**Solution**
1. Run the following command to query the Python version:
```
python3 --version
```
2. Ensure that Python 3.9.2 or later is installed, and then run the following command to install PyCryptodome:
```
sudo pip3 install pycryptodome
```
### "xx.sh : xx unexpected operator" Displayed During the Build Process
-**Symptom**
The build fails, and **xx.sh [: xx unexpected operator** is displayed.
The Compilation and Building subsystem implements compilation and packaging by module, component, and product. A module is an target to build. It can be a dynamic library, static library, configuration file, or prebuilt module. The component to which a module belongs must be defined. A module can belong to only one component. OpenHarmony uses customized GN templates to configure modules. For details about the GN basics, see https://gn.googlesource.com/gn/+/main/docs/reference.md.
The common templates for module configuration are as follows:
```
# C/C++ templates
ohos_shared_library
ohos_static_library
ohos_executable
ohos_source_set
# # Prebuilt templates
ohos_prebuilt_executable
ohos_prebuilt_shared_library
ohos_prebuilt_static_library
#HAP templates
ohos_hap
ohos_app_scope
ohos_js_assets
ohos_resources
#Other templates
#Configuration file
ohos_prebuild_etc
#SA profile
ohos_sa_profile
```
You are recommended to use the OpenHarmony customized templates.
### C/C++ Template Example
The .gni file corresponding to the templates starting with **ohos** is located in **openharmony/build/templates/cxx/cxx.gni**.
**ohos_shared_library** example:
```shell
import("//build/ohos.gni")
ohos_shared_library("helloworld"){
sources =["file"]
include_dirs =[]# If there are duplicate header files, the header files defined earlier take effect.
cflags =[]# If there are duplicate or conflict settings, the settings in cflags take effect.
cflags_c =[]
cflags_cc =[]
ldflags =[]# If there are duplicate or conflict definitions, the settings in ohos_template take effect.
configs =[]
deps =[]# Define dependent modules that belong to the same component.
external_deps =[# Define dependent modules that belong to different components.
"part_name:module_name", # The value is in the Component name:Module name format.
]# The dependent module must be declared in inner_kits by the dependent component.
output_name =[string] # Name of the module output.
output_extension =[]# Extension name of the module.
module_install_dir =[]# Module installation directory. The default directory is /system/lib64 or /system/lib. Specify the directory from system/ or vendor/.
relative_install_dir =[]# Relative installation directory of the module (relative to /system/lib64 or /system/lib). If module_install_dir is configured, the parameter does not take effect.
part_name =[string] # (Mandatory) Component name.
output_dir
# Sanitizer variables
cfi =[boolean]
scs =[boolean]
scudo =[]
ubsan =[]
boundary_sanitize =[]
integer_overflow_sanitize =[]
testonly =[boolean]
license_as_sources =[]
license_file =[]# A .txt file.
remove_configs =[]
no_default_deps =[]
install_images =[]
install_enable =[boolean]
symlink_target_name =[]
version_script =[]
use_exceptions =[]
}
```
**ohos_static_library** example
```shell
import("//build/ohos.gni")
ohos_static_library("helloworld"){
sources =["file"]# Source code in .c format.
include_dirs =["dir"]# Directories to be included.
configs =[]# Configuration.
deps =[]# Define dependent modules that belong to the same component.
part_name =[string] # Component name.
subsystem_name =[string] # Subsystem name.
cflags =[]
external_deps =[# Define dependent modules that belong to different components.
"part_name:module_name", # The value is in the Component name:Module name format.
]# The dependent module must be declared in inner_kits by the dependent component.
lib_dirs =[]
public_configs =[]
# Sanitizer variables
cfi =[boolean]
scs =[boolean]
scudo =[]
ubsan =[]
boundary_sanitize =[]
integer_overflow_sanitize =[]
remove_configs =[]
no_default_deps =[]
license_file =[]# A .txt file.
license_as_sources =[]
use_exceptions =[]
}
```
**ohos_executable** example:
```shell
import("//build/ohos.gni")
ohos_executable("helloworld"){
configs =[]# Configuration.
part_name =[string] # Component name.
subsystem_name =[string] # Subsystem name.
deps =[]# Define dependent modules that belong to the same component.
external_deps =[# Define dependent modules that belong to different components.
"part_name:module_name", # The value is in the Component name:Module name format.
]# The dependent module must be declared in inner_kits by the dependent component.
ohos_test =[]
test_output_dir =[]
# Sanitizer variables
cfi =[boolean]
scs =[boolean]
scudo =[]
ubsan =[]
boundary_sanitize =[]
integer_overflow_sanitize =[]
testonly =[boolean]
license_as_sources =[]
license_file =[]# A .txt file.
remove_configs =[]
static_link =[]
install_images =[]
module_install_dir =[]# Module installation directory, starting from system/ or vendor/.
relative_install_dir =[]
symlink_target_name =[]
output_dir =[directory] # Directory in which output files are located.
install_enable =[boolean]
version_script =[]
use_exceptions =[]
}
```
**ohos_source_set** example
```shell
import("//build/ohos.gni")
ohos_source_set("helloworld"){
sources =["file"]# Source code in .c format.
include_dirs =[]# Directories to be included.
configs =[]# Configuration.
public =[]# Header files.
defines =[]
public_configs =[]
part_name =[string] # Component name.
subsystem_name =[string] # Subsystem name.
deps =[]# Define dependent modules that belong to the same component.
external_deps =[# Define dependent modules that belong to different components.
"part_name:module_name", # The value is in the Component name:Module name format.
]# The dependent module must be declared in inner_kits by the dependent component.
# Sanitizer variables
cfi =[boolean]
scs =[boolean]
scudo =[]
ubsan =[]
boundary_sanitize =[]
integer_overflow_sanitize =[]
testonly =[boolean]
license_as_sources =[]
license_file =[]
remove_configs =[]
no_default_deps =[]
license_file =[]# A .txt file.
license_as_sources =[]
use_exceptions =[]
}
```
**NOTE**<br>Only **sources** and **part_name** are mandatory.
### Prebuilt Template Example
The .gni file of the prebuilt templates is located in **openharmony/build/templates/cxx/prebuilt.gni**.
**ohos_prebuilt_executable** example
```shell
import("//build/ohos.gni")
ohos_prebuilt_executable("helloworld"){
sources =["file"]# Source.
output =[]
install_enable =[boolean]
deps =[]# Define dependent modules that belong to the same component.
public_configs =[]
subsystem_name =[string] # Subsystem name.
part_name =[string] # Component name.
testonly =[boolean]
visibility =[]
install_images =[]
module_install_dir =[]# Module installation directory, starting from system/ or vendor/.
relative_install_dir =[]# Relative module installation directory (relative to system/etc). If module_install_dir is configured, the parameter does not take effect.
symlink_target_name =[]
license_file =[]# A .txt file.
license_as_sources =[]
}
```
**ohos_prebuilt_shared_library** example
```shell
import("//build/ohos.gni")
ohos_prebuilt_shared_library("helloworld"){
sources =["file"]# .so files.
output =[]
install_enable =[boolean]
deps =[]# Define dependent modules that belong to the same component.
public_configs =[]
subsystem_name =[string] # Subsystem name.
part_name =[string] # Component name.
testonly =[boolean]
visibility =[]
install_images =[]
module_install_dir =[]# Module installation directory, starting from system/ or vendor/.
relative_install_dir =[]# Relative module installation directory (relative to system/etc). If module_install_dir is configured, the parameter does not take effect.
symlink_target_name =[string]
license_file =[string] # A .txt file.
license_as_sources =[]
}
```
**ohos_prebuilt_static_library** example
```shell
import("//build/ohos.gni")
ohos_prebuilt_static_library("helloworld"){
sources =["file"]# .so files.
output =[]
deps =[]# Define dependent modules that belong to the same component.
public_configs =[]
subsystem_name =[string] # Subsystem name.
part_name =[string] # Component name.
testonly =[boolean]
visibility =[]
license_file =[string] # A .txt file.
license_as_sources =[]
}
```
**NOTE**<br>Only **sources** and **part_name** are mandatory.
### HAP Templates
See [HAP Build Guide](subsys-build-gn-hap-compilation-guide.md).
### Other Templates
**ohos_prebuilt_etc** example:
```shell
import("//build/ohos.gni")
ohos_prebuilt_etc("helloworld"){
# The most common attributes of the ohos_prebuilt_etc template.
sources =["file"]
module_install_dir =[]# Module installation directory, starting from system/ or vendor/.
subsystem_name =[string] # Subsystem name.
part_name =[string] # (Mandatory) Component name.
install_images =[]
relative_install_dir =[]# Relative module installation directory (relative to system/etc). If module_install_dir is configured, the parameter does not take effect.
# Uncommon attributes of the ohos_prebuilt_etc template:
deps =[]# Define dependent modules that belong to the same component.
testonly =[boolean]
visibility =[]
public_configs =[]
symlink_target_name =[string]
license_file =[string]
license_as_sources =[]
}
```
**ohos_sa_profile** example:
```shell
import("//build/ohos.gni")
ohos_sa_profile("helloworld"){
sources =[".xml"]# .xml file.
part_name =[string] # Component name.
subsystem_name =[string] # Subsystem name.
}
```
**NOTE**: Only **sources** and **part_name** are mandatory.
## Adding and Building a Module
The figure below illustrates the process for adding a module. A module belongs to a component, which belongs to a subsystem. Please note that the chipset solution, as a special component, does not have a subsystem. You may need to:
- Add a module to an existing component.
- Add a module to a new component.
- Add a module to a new subsystem.

**Adding a Module to an Existing Component**
1. Configure the **BUILD.gn** file in the module directory and select the GN template.
2. Modify the **bundle.json** file.
```shell
{
"name": "@ohos/<component_name>, # HPM component name, in the "@Organization/Component name" format.
"description": "xxxxxxxxxxxxxxxxxxx", # Description of the component functions.
"version": "3.1", # Version, which must be the same as the version of OpenHarmony.
"license": "MIT", # Component license.
"publishAs": "code-segment", # HPM package release mode. The default value is code-segment.
"segment": {
"destPath": "third_party/nghttp2"
}, # Code restoration path (source code path) set when publishAs is code-segment.
"dirs": {}, # Directory structure of the HPM package. This field is mandatory and can be left empty.
"scripts": {}, # Scripts to be executed. This field is mandatory and can be left empty.
"licensePath": "COPYING",
"readmePath": {
"en": "README.rst"
},
"component": { # Component attributes.
"name": "<component_name>", # Component name.
"subsystem": "", # Subsystem to which the component belongs.
"syscap": [], # System capabilities provided by the component for applications.
"features": [], # List of configurable features of the component. Generally, this parameter corresponds to sub_component in build.
"adapted_system_type": [], # Types of adapted systems. The value can be mini, small, and standard.
"rom": "xxxKB" # ROM baseline. If there is no baseline, enter the current value.
"ram": "xxxKB", # RAM baseline. If there is no baseline, enter the current value.
"deps": {
"components": [ # Other components on which this component depends.
"third_party": [ # Third-party open-source software on which this component depends.
], # Component build entry. Configure the module here.
"inner_kits": [], # APIs between components
"test": [] # Entry for building the component's test cases.
}
}
}
```
**NOTE**<br>The **bundle.json** file must be in the folder of the corresponding subsystem.
3. Start the build and check whether a .so file or binary file is generated.
**Creating a Component and Adding a Module**
1. Configure the **BUILD.gn** file in the module directory and select the corresponding GN template. Note that **part_name** in the **BUILD.gn** file is the name of the component to add.
2. Create a **bundle.json** file in the folder of the corresponding subsystem.
3. Add the new component to the end of existing components in **vendor/{product_company}/{product-name}/config.json**.
```shell
"subsystems": [
{
"subsystem": "Subsystem to which the component belongs",
"components": [
{"component": "Component 1 name", "features":[]}, # Existing component 1 in the subsystem
{"component": "Component 2 name", "features":[] }, # Existing component 2 in the subsystem
{"component": "New component name", "features":[]}# New component in the subsystem
]
},
.
]
```
4. Start the build and check whether a .so file or binary file is generated.
**Creating a Subsystem and Adding a Module**
1. Configure the **BUILD.gn** file in the module directory and select the corresponding GN template. This step is the same as the step in "Creating a Component and Adding a Module."
2. Create a **bundle.json** file in the folder of the component of the subsystem. This step is the same as the step in "Creating a Component and Adding a Module."
3. Modify the **subsystem_config.json** file in the **build** directory.
```shell
{
"Subsystem 1 name": {# Existing subsystem 1
"path": "Subsystem 1 directory",
"name": "Subsystem 1 name"
},
"Subsystem 2 name": {# Existing subsystem 2
"path": "Subsystem 2 directory",
"name": "Subsystem 2 name"
},
"Subsystem name new": {# Subsystem to add
"path": "New subsystem directory",
"name": "New subsystem name"
},
}
```
The **subsystem_config.json** file defines the subsystems and their directories. When adding a subsystem, specify **path** and **name** for the subsystem.
4. If **product-name** in the **vendor/{product_company}/{product-name}** directory is **hispark_taurus_standard**, add the new component information to the end of existing components in the **config.json** file.
```shell
"subsystems": [
{
"subsystem": "arkui", # Name of the existing subsystem
"components": [# All components of the subsystem
{
"component": "ace_engine_standard", # Name of the existing component
"features": []
},
{
"component": "napi", # Name of the existing component
"features": []
}
{
"component": "component_new1", # Name of the new component to add
"features": []
}
]
},
{
"subsystem": "subsystem_new", # Name of the new subsystem to add
"components": [
{
"component": "component_new2", # Name of the component to be added to the new subsystem
"features": []
}
]
},
]
```
4. Start the build and check whether a .so file or binary file is generated.
**Building a Module**
You can start the build by using the [CLI or hb tool](subsys-build-all.md#build-commands). The following uses the CLI as an example:
You can run the **--build-target***Module name* command to build a module separately.
```shell
./build.sh --build-target Module Name
```
You can also build a product. For example, to build hispark_taurus_standard, run the following command:
```shell
./build.sh --product-name hispark_taurus_standard --build-target Module name --ccache
```
You can also build the component to which the module belongs.
```shell
./build.sh --product-name hispark_taurus_standard --build-target musl --build-target Module name --ccache
The product solution is a special component. It is a product built based on a development board. It includes the OS adaptation, component assembly and configuration, startup configuration, and file system configuration. The source code path of a product solution is in the **vendor/{Product solution vendor}/{Product name}** format.
The product solution directory structure is as follows:
```shell
vendor
└── company # Product solution vendor
├── product # Product name
│ ├── init_configs
│ │ ├── etc # Startup configuration of the init process (only required for the Linux kernel)
│ │ └── init.cfg # System service startup configuration
│ ├── hals # OS adaptation
│ ├── BUILD.gn # Product build script
│ └── config.json # Product configuration file
│ └── fs.yml # File system packaging configuration
└── ......
```
>  **NOTE**<br>Directories and files must be created for new products based on the preceding rules. The Compilation and Building subsystem scans the configured products based on the rules.
The key directories and files are described as follows:
1.**vendor/company/product/init_configs/etc**<br>This folder contains the rcS, Sxxx, and fstab scripts. The init process runs the rcS, fstab, and S00-xxx scripts in sequence before starting system services. The **S***xxx* script is used to create device nodes and directories, scan device nodes, and change file permissions for the development board and product. These scripts are copied from the **BUILD.gn** file to the **out** directory of the product as required and packaged into the **rootfs** image.
2.**vendor/company/product/init_configs/init.cfg**<br>**init.cfg** defines how the init process starts services. Currently, the following commands can be parsed:
-**start**: starts a service.
-**mkdir**: creates a folder.
-**chmod**: changes the permission on a specified directory or file.
-**chown**: changes the owner group of a specified directory or file.
-**mount**: mounts a device.
The fields in the file are described as follows:
```shell
{
"jobs" : [{# An array of Jobs. A job corresponds to a command set. Jobs are executed in the following sequence: pre-init > init > post-init.
"name" : "pre-init",
"cmds" : [
"mkdir /storage/data", # Create a directory.
"chmod 0755 /storage/data", # Modify the permissions. The format of the permission value is 0xxx, for example, 0755.
"mkdir /storage/data/log",
"chmod 0755 /storage/data/log",
"chown 4 4 /storage/data/log", # Change the owner group. The first number is the user ID (UID), and the second number is the group ID (GID).
......
"mount vfat /dev/mmcblock0 /sdcard rw,umask=000"# The command format is mount [File system type] [source] [target] [flags] [data].
# The value of flags can be nodev, noexec, nosuid, or rdonly only.
]
}, {
"name" : "init",
"cmds" : [# Start services based on the sequence of the cmds array.
"start shell", # There is only one space between start and the service name.
......
"start service1"
]
}, {
"name" : "post-init", # Job that is finally executed. Operations performed after the init process is started, for example, mounting a device after the driver initialization).
"cmds" : []
}
],
"services" : [{# An array of services. A service corresponds to a process.
"name" : "shell", # Service name.
"path" : ["/sbin/getty", "-n", "-l", "/bin/sh", "-L", "115200", "ttyS000", "vt100"], # Full path of the executable file. It must start with "path".
"uid" : 0, # Process UID, which must be the same as that in the binary file.
"gid" : 0, # Process GID, which must be the same as that in the binary file.
"once" : 0, # Whether the process is a one-off process. The value 1 indicates that process is a one-off process, and the value 0 indicates the opposite. The init process does not restart the one-off process after the process exits.
"importance" : 0, # Whether the process is a key process. The value 1 indicates a key process, and the value 0 indicates the opposite. If a key process exits, the init process will restart the board.
"caps" : [4294967295]
},
......
]
}
```
3.**vendor/company/product/init_configs/hals**<br>This folder contains the OS adaptation of the product. For details about the interfaces to be implemented, see readme of each component.
4.**vendor/company/product/config.json**<br>The **config.json** file is the main entry for compilation and build. It contains the configuration of the development board, OS components, and kernel.
The following example shows the **config.json** file of the IP camera developed based on the hispark_taurus board:
```shell
{
"product_name": "ipcamera", # Product name
"version": "3.0", # Version of config.json. The value is 3.0.
"type": "small", # System type. The value can be mini, small, or standard.
"ohos_version": "OpenHarmony 1.0", # OS version
"device_company": "hisilicon", # Chipset vendor
"board": "hispark_taurus", # Name of the development board
5.**vendor/company/product/fs.yml**<br>The **fs.yml** file defines the process for creating a file system image, for example, **rootfs.img** (user-space root file system) and **userfs.img** (readable and writable file). It consists of multiple lists, and each list corresponds to a file system. The fields are described as follows:
```shell
fs_dir_name: (Mandatory) specifies name of the file system, for example, rootfs or userfs.
fs_dirs: (Optional) specifies the mapping between the file directory in the out directory and the system file directory. Each file directory corresponds to a list.
source_dir: (Optional) specifies target file directory in the out directory. If this field is not specified, an empty directory will be created in the file system based on target_dir.
target_dir: (Mandatory) specifies the file directory in the file system.
ignore_files: (Optional) declares ignored files during the copy operation.
dir_mode: (Optional) specifies the file directory permissions. The default value is 755.
file_mode: (Optional) specifies the permissions of all files in the directory. The default value is 555.
fs_filemode: (Optional) specifies the files that require special permissions. Each file corresponds to a list.
file_dir: (Mandatory) specifies the detailed file path in the file system.
file_mode: (Mandatory) declares file permissions.
fs_symlink: (Optional) specifies the soft link of the file system.
fs_make_cmd: (Mandatory) creates the file system script. The script provided by the OS is located in the build/lite/make_rootfs directory. Linux, LiteOS, ext4, jffs2, and vfat are supported. Chipset vendors can also customize the script as required.
fs_attr: (Optional) dynamically adjusts the file system based on configuration items.
```
The **fs_symlink** and **fs_make_cmd** fields support the following variables:
- Code root directory, which corresponds to **${ohos_root_path}** of GN.
-**out** directory of the product, which corresponds to **${root_out_dir}** of GN.
- File system directory ${fs_dir}, which consists variables ${root_path} and ${fs_dir_name}.
>  **NOTE**<br>**fs.yml** is optional. You do not need to configure it for devices without a file system.
6.**vendor/company/product/BUILD.gn**<br>**BUILD.gn** provides the entry for product build. It is used to compile the source code of the solution vendor and copy the startup configuration file. The **BUILD.gn** file in the corresponding product directory will be compiled by default if a product is selected. The following is an example of the **BUILD.gn** file of a product:
```shell
group("product"){# The name must be the same as the product name (level-3 directory name under the product directory).
deps =[]
deps +=["init_configs"]# Copy init configuration.
... # Others
}
```
### Adding and Building a Product
You can customize a product solution by flexibly assembling a chipset solution and components. The procedure is as follows:
1. Create a directory for the product. <br>The following uses the Wi-Fi IoT module on the RTL8720 development board as an example. <br>Run the following command in the root directory of the code:
```shell
mkdir-p vendor/my_company/wifiiot
```
2. Configure the product. <br>Create a **config.json** file, for example for wifiiot, in the product directory. <br>The **vendor/my_company/wifiiot/config.json** file is as follows:
```shell
{
"product_name": "wifiiot", # Product name
"version": "3.0", # Version of config.json. The value is 3.0.
"type": "small", # System type. The value can be mini, small, or standard.
"ohos_version": "OpenHarmony 1.0", # OS version
"device_company": "realtek", # Name of the chipset solution vendor
"board": "rtl8720", # Name of the development board
"kernel_type": "liteos_m", # Kernel type
"kernel_version": "3.0.0", # Kernel version
"subsystems": [
{
"subsystem": "kernel", # Subsystem
"components": [
{"component": "liteos_m", "features":[] }# Component and its features
]
},
...
{
More subsystems and components
}
]
}
```
**NOTE**<br>Before the build, the Compilation and Building subsystem checks the validity of the fields in **config.json**. The **device_company**, **board**, **kernel_type**, and **kernel_version** fields must match the chipset solution, and the **subsystem** and **component** fields must match the component description in **build/lite/components**.
3. Implement OS adaptation APIs. Create the **hals** directory in the product directory and save the source code as well as the build script for OS adaptation in this directory.
4. Create the **init_configs** directory in the product directory and then the **init.cfg** file in the **init_configs** directory, and configure the system services to be started.
5. (Optional) Configure the init process for the Linux kernel. Create the **etc** directory in the **init_configs** directory, and then create the **init.d** folder and the **fstab** file in the **etc** directory. Then, create the **rcS** and **S***xxx* files in the **init.d** file and edit them based on product requirements.
6. (Optional) Configure the file system image for the development board that supports the file system.<br> Create the **fs.yml** file in the product directory, and configure it as required. A typical **fs.yml** file is as follows:
```shell
-
fs_dir_name: rootfs # Image name
fs_dirs:
-
# Copy the files in the out/my_board/my_product/bin directory to the rootfs/bin directory and ignore the .bin files related to testing.
source_dir: bin
target_dir: bin
ignore_files:
- Test.bin
- TestSuite.bin
-
# Copy the files in the out/my_board/my_product/libs directory to the rootfs/lib directory, ignore all .a files, and set the file permissions to 644 and folder permissions 755.
source_dir: libs
target_dir: lib
ignore_files:
- .a
dir_mode: 755
file_mode: 644
-
source_dir: usr/lib
target_dir: usr/lib
ignore_files:
- .a
dir_mode: 755
file_mode: 644
-
source_dir: config
target_dir: etc
-
source_dir: system
target_dir: system
-
source_dir: sbin
target_dir: sbin
-
source_dir: usr/bin
target_dir: usr/bin
-
source_dir: usr/sbin
target_dir: usr/sbin
-
# Create an empty proc directory.
target_dir: proc
-
target_dir: mnt
-
target_dir: opt
-
target_dir: tmp
-
target_dir: var
-
target_dir: sys
-
source_dir: etc
target_dir: etc
-
source_dir: vendor
target_dir: vendor
-
target_dir: storage
fs_filemode:
-
file_dir: lib/ld-uClibc-0.9.33.2.so
file_mode: 555
-
file_dir: lib/ld-2.24.so
file_mode: 555
-
file_dir: etc/init.cfg
file_mode: 400
fs_symlink:
-
# Create the soft link ld-musl-arm.so.1 -> libc.so in the rootfs/lib directory.
source: libc.so
link_name: ${fs_dir}/lib/ld-musl-arm.so.1
-
source: mksh
link_name: ${fs_dir}/bin/sh
-
source: mksh
link_name: ${fs_dir}/bin/shell
fs_make_cmd:
# Run the script to create an ext4 image from rootfs.
7. (Optional) Configure patches if the product and components need to be patched.<br>Create a **patch.yml** file in the product directory. A typical **patch.yml** file is as follows:
```shell
# Directory in which the patch is to be installed
foundation/communication/dsoftbus:
# Directory in which the patch is stored.
- foundation/communication/dsoftbus/1.patch
- foundation/communication/dsoftbus/2.patch
third_party/wpa_supplicant:
- third_party/wpa_supplicant/1.patch
- third_party/wpa_supplicant/2.patch
- third_party/wpa_supplicant/3.patch
...
```
Add **--patch** when running the **hb build** command. Then, the patch files can be added to the specified directory before the build.
```shell
hb build -f--patch
```
8. Write the build script. <br>Create a **BUILD.gn** file in the product directory and write the script. The following **BUILD.gn** file uses the Wi-Fi IoT module in step 1 as an example:
```shell
group("wifiiot"){# The target name must be the same as the product name.
deps =[]
deps +=["init_configs"]# Copy init configuration.
deps +=["hals"]# Add hals.
... # Others
}
```
9. Build the product.<br> You can start the build by using the [CLI or hb tool](subsys-build-all.md#build-commands). The following uses the CLI as an example. For example, the product name is **hispark_taurus_standard**. Run the following command:
When adding a module, you need to declare its dependencies in **BUILD.gn**. **deps** specifies dependent modules in the same component, and **external_deps** specifies dependent modules between components.
**Dependency Types**

The dependency between modules can be classified into **desp** (left in the figure above) and **external_deps** (right in the figure above).
-**desp**: The dependent module to be added belongs to the same part with the current module. For example, module 2 depends on module 1, and modules 1 and 2 belong to the samp component.
-**external_deps**: The dependent module to be added belongs to another component. For example, module 2 depends on module 1, and modules 1 and 2 belong to different components.
- Example of **deps**:
```shell
import("//build/ohos.gni")
ohos_shared_library("module1"){
...
part_name ="part1"# (Mandatory) Name of the component to which the module belongs.
...
}
```
```shell
import("//build/ohos.gni")
ohos_shared_library("module2"){
...
deps =[
"GN target of module 1",
...
]# Intra-component dependency
part_name ="part1"# (Mandatory) Name of the component to which the module belongs.
}
```
- Example of **external_deps**:
```shell
import("//build/ohos.gni")
ohos_shared_library("module1"){
...
part_name ="part1"# (Mandatory) Name of the component to which the module belongs.
...
}
```
```shell
import("//build/ohos.gni")
ohos_shared_library("module2"){
...
external_deps =[
"part1:module1",
...
]# Inter-component dependency. The dependent module must be declared in **inner_kits** by the dependent component.
part_name ="part2"# (Mandatory) Name of the component to which the module belongs.
}
```
**NOTE**<br>The dependency between components must be written in the format of **Component name:Module name** in **external_deps**. The dependent module must be declared in **inner_kits**.
## Information Collected by the Open Source Software Notice
An open source software notice is a file related to the project open source. It collects license information to comply with open source specifications.
**Information to Collect**
The notice collects only the licenses of the modules packaged in the image. For example, the licenses of the tools (such as Clang, Python, and Ninja) used during the build process are not collected.
A static library itself is not packaged. However, if it is packaged into the system as part of a dynamic library or executable file, the license of the static library will be collected for completeness.
The final **Notice.txt** file must include all licenses used by the files in the image and the mapping between modules and licenses.
The **Notice.txt** file is located in the **/system/etc/** directory.
**Rules for Collecting Information**
Licenses are collected by priority, which ranges from 1 to 4 in descending order of seniority.
1. Licenses that are directly declared in a module's **BUILD.gn** are given the top priority. The following is an example:
```shell
ohos_shared_library("example"){
...
license_file ="path-to-license-file"
...
}
```
2. If there is no explicitly declared license, the build script searches for the **Readme.OpenSource** file in the directory of **BUILD.gn**, parses the file, and collects the obtained licenses. If the **Readme.OpenSource** file does not contain license information, an error will be reported.
3. If the **Readme.OpenSource** file does not exist, the build script searches for the **License**, **Copyright**, and **Notice** files from the current directory to the root directory of the source code by default. If obtained license information will be used as the licenses of the module.
4. If no license is found, the default license (Apache License 2.0) will be used.
Pay attention to the following:
- For third-party open-source software, such as OpenSSL and ICU, **Readme.OpenSource** must be configured in the source code directory. Check whether **Readme.OpenSource** is in the same directory as **BUILD.gn** and whether the license configured in **Readme.OpenSource** is valid.
- If the source code is not licensed under the Apache License 2.0, the corresponding license file must be provided in the source code directory or declared by **license_file** for the module.
- If the source code file added to **BUILD.gn** is not from the current directory, check whether the license in the repository where the source code file is located is the same as that in the repository of **BUILD.gn**.
## Parameters for Accelerating Local Build
The following parameters can be added to the build command to speed up the build process:
-**--ccache**
- Ccache caches the output of C/C++ compilation. If the compilation input remains unchanged the next time, the compilation can be skipped and the results can be taken from the cache.
- Installing ccache:
- Quick installation: Run the **sudo apt-get install ccache** command.
- Download the binary file from the [official website](https://ccache.dev/download.html) and configure the ccache path to the environment variable.
- Usage: Run the **./build.sh --product-name***Product name***--ccache** command.
-**--fast-rebuild**
- The compilation process includes preloader -> loader -> GN -> Ninja. If the GN and product configuration files are not modified locally, adding **--fast-rebuild** will start from Ninja directly.
- Usage: Run the **./build.sh --product-name***Product name***--fast-rebuild** command.
-**enable_notice_collection=false**
- Adding this parameter can skip the process of collecting the module licenses of the open-source software.
- Usage: Run the **./build.sh --product-name***Product name***--gn-args --enable_notice_collection=false --ccache** command.
-**--build-target**
- This parameter specifies the module to compile. You can obtain the module name as follows:
- Pay attention to keywords such as **group**, **ohos_shared_library**, and **ohos_executable** in **BUILD.gn**.
- Run **./build.sh --product-name***Product name***--build-target***Module name***--build-only-gn** to generate **build.ninja** and locate the related module name in the file.
- Usage: Run the **./build.sh --product-name***Product name***--build-target ark_js_host_linux_tools_packages** command.
## Viewing Ninja Build Information
The **out/rk3568/.ninja_log** file records the build start time and end time (ms) of each module. A shorter interval indicates a faster build and higher compilation performance.
The four columns are start time, end time, modified timestamp (mtime), and command hash from left to right.

You can graphically display the build time as follows:
- Open **build.trace** locally.
Decompress **out/rk3568/build.trace.gz** and drag **build.trace** to **chrome://tracing/**.
- Open **build.trace** at **ci.openharmony.cn/events**.
You can open the **build.trace.html** file in each compilation output as follows:
1. Click **Success** under **Static Check**.
2. Click **Output** in the **Output** column. The **build.trace.html** file is displayed in the **build_trace** column on the left. Click the file to open it.
The Compilation and Building subsystem provides a build framework based on Generate Ninja (GN) and Ninja. This subsystem allows you to:
- Build products based on different chipset platforms, for example, hispark_taurus_standard.
- Package capabilities required by a product by assembling components based on the product configuration.
### Basic Concepts
Learn the following basic concepts before you start:
- Platform
A platform consists of the development board and kernel. The supported subsystems and components vary with the platform.
- Subsystem
OpenHarmony is designed with a layered architecture, which consists of the kernel layer, system service layer, framework layer, and application layer from the bottom up. System functions are developed by levels, from system to subsystem and then to component. In a multi-device deployment scenario, you can customize subsystems and components as required. A subsystem, as a logical concept, consists of the least required components.
- Component
A component is a reusable software unit that contains source code, configuration files, resource files, and build scripts. Integrated in binary mode, a component can be built and tested independently.
- GN
GN is short for Generate Ninja. It is used to build Ninja files.
- Ninja
Ninja is a small high-speed building system.
### Working Principles
The process for building an OpenHarmony system is as follows:
- Parsing commands: Parse the name of the product to build and load related configurations.
- Running GN: Configure the toolchain and global options based on the product name and compilation type.
- Running Ninja: Start building and generate a product distribution.
### Constraints
- You need to obtain the source code using method 3 described in [Obtaining Source Code](../get-code/sourcecode-acquire.md).
- Ubuntu 18.04 or later must be used.
- You must install the software packages required for build.
The command is as follows:
```
# Run the script in the home directory.
# ./build/build_scripts/env_setup.sh
# Do not run the command as the **root** user. Otherwise, the environment variables will be added to the **root** user. If your **shell** is not **bash** or **Zsh**, you need to manually configure the following content to your environment variables after the execution. To view your environment variables, run the **cd** command to go to your home directory and view the hidden files.
#You also need to install LLVM, hc-gen, gcc_riscv32, Ninja, node-v14.15.4-linux-x64, and GN, and import the non-bash or non-Zsh configuration in the shell to your environment variables.
```
## Building Guidelines
### Directory Structure
```
/build # Directory for build
├── __pycache__
├── build_scripts/ # Python scripts for build
├── common/
├── config/ # Build-related configurations
├── core
│ └── gn/ # BUILD.gn configuration
└── build_scripts/
├── docs
gn_helpers.py*
lite/ # hb and preloader entry
misc/
├── ohos # Process for building and packaging OpenHarmony
│ ├── kits # Kits build and packaging templates and processing
│ ├── ndk # NDK templates and processing
│ ├── notice # Notice templates and processing
│ ├── packages # Distribution packaging templates and processing
│ ├── sa_profile # SA profiles and processing
│ ├── sdk # SDK templates and processing, which contains the module configuration in the SDK
│ └── testfwk # Testing-related processing
├── ohos.gni* # Common .gni files for importing a module at a time.
├── ohos_system.prop
├── ohos_var.gni*
├── prebuilts_download.sh*
├── print_python_deps.py*
├── scripts/
├── subsystem_config.json
├── subsystem_config_example.json
├── templates/ # C/C++ build templates
├── test.gni*
├── toolchain # Build toolchain configuration
├── tools # Common tools
├── version.gni
├── zip.py*
```
### Build Command
- Run the following command in the root directory of the source code to build a full distribution:
```
./build.sh --product-name {product_name}
```
**{product_name}** specifies the product platform supported by the current distribution, for example, **hispark_taurus_standard**.
The image generated is stored in the **out/{device_name}/packages/phone/images/** directory.
- The **./build.sh** command supports the following options:
```
-h, --help # Display help information and exit.
--source-root-dir=SOURCE_ROOT_DIR # Specify the path.
--product-name=PRODUCT_NAME # Specify the product name.
--device-name=DEVICE_NAME # Specify the device name.
--target-cpu=TARGET_CPU # Specify the CPU.
--target-os=TARGET_OS # Specify the operating system.
-T BUILD_TARGET, --build-target=BUILD_TARGET # specifies one or more targets to build.
--keep-ninja-going # Keep Ninja going until 1,000,000 jobs fail.
--sparse-image
--jobs=JOBS
--export-para=EXPORT_PARA
--build-only-gn # Perform GN parsing and does not run Ninja.
--ccache # (Optional) Use ccache for build. You need to install ccache locally.
--fast-rebuild # Whether to use fast rebuild. The default value is False.
--log-level=LOG_LEVEL # Specify the log level during the build. The options are debug, info, and error. The default value is info.
--device-type=DEVICE_TYPE # Specify the device type. The default value is default.
--build-variant=BUILD_VARIANT # Specify the device operation mode. The default value is user.
```
### How to Develop
1. Add a component.
The following use a custom component as an example to describe how to write .gn scripts for a library, an executable file, and a configuration file.
In this example, **partA** consists of **feature1**, **feature2**, and **feature3**, which represent a dynamic library, an executable file, and an etc configuration file, respectively.
Add **partA** to a subsystem, for example, **subsystem_examples** (defined in the **test/examples/** directory).
The directory structure of **partA** is as follows:
```
test/examples/partA
├── feature1
│ ├── BUILD.gn
│ ├── include
│ │ └── helloworld1.h
│ └── src
│ └── helloworld1.cpp
├── feature2
│ ├── BUILD.gn
│ ├── include
│ │ └── helloworld2.h
│ └── src
│ └── helloworld2.cpp
└── feature3
├── BUILD.gn
└── src
└── config.conf
```
(a) Write **test/examples/partA/feature1/BUILD.gn** for the dynamic library.
```
config("helloworld_lib_config") {
include_dirs = [ "include" ]
}
ohos_shared_library("helloworld_lib") {
sources = [
"include/helloworld1.h",
"src/helloworld1.cpp",
]
public_configs = [ ":helloworld_lib_config" ]
part_name = "partA"
}
```
(b) Write **test/examples/partA/feature2/BUILD.gn** for the executable file.
```
ohos_executable("helloworld_bin") {
sources = [
"src/helloworld2.cpp"
]
include_dirs = [ "include" ]
deps = [ # Dependent modules in the component
"../feature1:helloworld_lib"
]
external_deps = [ "partB:module1" ] # (Optional) Dependent modules of another component are named in Component name:Module name format.
install_enable = true # By default, the executable file is not installed. You need to set this parameter to true for installation.
part_name = "partA"
}
```
(c) Write **test/examples/partA/feature3/BUILD.gn** for the etc module.
```
ohos_prebuilt_etc("feature3_etc") {
source = "src/config.conf"
relative_install_dir = "init" # (Optional) Relative directory for installing the module. The default installation directory is **/system/etc**.
part_name = "partA"
}
```
(d) Add the module configuration **test/examples/bundle.json** to the **bundle.json** file of the component. Each component has a **bundle.json** file in the root directory of the component. The sample code is as follows:
```
{
"name": "@ohos/<component_name>, # OpenHarmony Package Manager (HPM) component name, in the "@Organization/Component name" format.
"description": "xxxxxxxxxxxxxxxxxxx", # Description of the component functions.
"version": "3.1", # Version, which must be the same as the version of OpenHarmony.
"license": "MIT", # Component license.
"publishAs": "code-segment", # Mode for publishing the HPM package. The default value is code-segment.
"segment": {
"destPath": ""
}, # Set the code restoration path (source code path) when publishAs is code-segment.
"dirs": {}, # Directory structure of the HPM package. This field is mandatory and can be left empty.
"scripts": {}, # Scripts to be executed. This field is mandatory and can be left empty.
"licensePath": "COPYING", # Path of the module's license.
"readmePath": {
"en": "README.rst"
}, # Path of module's reademe.opensource.
"component": { # Component attributes.
"name": "<component_name>", # Component name.
"subsystem": "", # Subsystem to which the component belongs.
"syscap": [], # System capabilities provided by the component for applications.
"features": [], # List of the component's configurable features. Generally, this parameter corresponds to sub_component in build and can be configured.
"adapted_system_type": [], # Adapted system types, which can be mini, small, and standard. Multiple values are allowed.
"rom": "xxxKB" # ROM baseline. If there is no baseline, enter the current value.
"ram": "xxxKB", # RAM baseline. If there is no baseline, enter the current value.
"deps": {
"components": [], # Other components on which this component depends.
"third_party": [] # Third-party open-source software on which this component depends.
},
"build": { # Build-related configurations.
"sub_component": [], # Component build entry. Configure the module here.
"inner_kits": [], # APIs between components.
"test": [] # Entry for building the component's test cases.
}
}
}
```
2. Add the component to the product configuration file.
Add the component to **//vendor/{*product_company*}/{*product-name*}/config.json**.
For example, add "subsystem_examples:partA" to the product **config.json** file. **partA** will be built and packaged into the distribution.
3. Start the build.
For example, run the following command to build **hispark_taurus_standard**:
You can obtain the generated files from the **out/hispark_taurus/** directory and the image in the **out/hispark_taurus/packages/phone/images/** directory.
## FAQs
### How Do I Build a Module and Package It into a Distribution?
- Set **part_name** for the module. A module can belong to only one part.
- Add the module to **component.build.sub_component** of the component, or define the dependency between the module and the modules in **component.build.sub_component**.
- Add the component to the component list of the product.
### How Do I Set deps and external_deps?
When adding a module, you need to declare its dependencies in **BUILD.gn**. **deps** specifies dependent modules in the same component, and **external_deps** specifies dependent modules between components.
The dependency between modules can be classified into:
**deps**: The dependent module to be added belongs to the same component with the current module. For example, module 2 depends on module 1, and modules 1 and 2 belong to the same component.
**external_deps**: The dependent module to be added belongs to another component. For example, module 2 depends on module 1, and modules 1 and 2 belong to different components.
- Example of **deps**:
```
import("//build/ohos.gni")
ohos_shared_library("module1") {
...
part_name = "part1" # (Mandatory) Name of the component to which the module belongs.
...
}
```
```
import("//build/ohos.gni")
ohos_shared_library("module2") {
...
deps = [
"GN target of module 1",
...
] # Intra-component dependency
part_name = "part1" # (Mandatory) Name of the part to which the module belongs.
}
```
- Example of **external_deps**:
```
import("//build/ohos.gni")
ohos_shared_library("module1") {
...
part_name = "part1" # (Mandatory) Name of the component to which the module belongs.
...
}
```
-**bundle.json** file of the component to which module 1 belongs
```
{
"name": "@ohos/<component_name>", # HPM component name, in the "@Organization/Component name" format.
"description": "xxxxxxxxxxxxxxxx", # Description of the component functions.
"version": "3.1", # Version, which must be the same as the version of OpenHarmony.
"license": "MIT", # Component license.
"publishAs": "code-segment", # Mode for publishing the HPM package. The default value is code-segment.
"segment": {
"destPath": ""
}, # Code restoration path (source code path) when publishAs is code-segment.
"dirs": {}, # Directory structure of the HPM package. This field is mandatory and can be left empty.
"scripts": {}, # Scripts to be executed. This field is mandatory and can be left empty.
"licensePath "licensePath": "COPYING",
": "COPYING",
"readmePath": {
"en": "README.rst"
},
"component": { # Component attributes.
"name": "<component_name>", # Component name.
"subsystem": "", # Subsystem to which the component belongs.
"syscap": [], # System capabilities provided by the component for applications.
"features": [], # List of the component's configurable features. Generally, this parameter corresponds to sub_component in build and can be configured.
"adapted_system_type": [], # Adapted system types, which can be mini, small, and standard. Multiple values are allowed.
"rom": "xxxKB" # ROM baseline. If there is no baseline, enter the current value.
"ram": "xxxKB", # RAM baseline. If there is no baseline, enter the current value.
"deps": {
"components": [], # Other components on which this component depends.
"third_party": [] # Third-party open-source software on which this component depends.
},
"build": { # Build-related configurations.
"sub_component": ["part1"], # Component build entry. All modules of the component are listed here.
"inner_kits": [], # APIs between components.
{
"header": {
"header_base": "Header file directory", # Directory of the header files.
"header_files": [
"Header file name"
] # List of header file names.
},
"name": "GN target of module 1"
},
],
"test": [] # Entry for building the component's test cases.
}
}
}
```
```
import("//build/ohos.gni")
ohos_shared_library("module2") {
...
external_deps = [
"part1:module1",
...
] # Inter-component dependency. The dependent module must be declared in **inner_kits** by the dependent component.
part_name = "part2" # (Mandatory) Name of the component to which the module belongs.
> The values of **external_deps** are in the *Component name*:*Module name* format. The module name must exist in **inner_kits** of the dependent component.
### How Do I Add a Module to a Standard System?
You may need to:
- Add a module to an existing component.
- Add a module to a new component.
- Add a module to a new subsystem.
#### Adding a Module to an Existing Component
1. Configure the **BUILD.gn** file in the module directory and select the corresponding template.
Follow the procedure for adding a module to an existing component. Note that **part_name** in the **BUILD.gn** file is the name of the existing component.
2. Modify the **bundle.json** file. "GN target of the module in the component"
```
{
"name": "@ohos/<component_name>, # HPM component name, in the "@Organization/Component name" format.
"description": "xxxxxxxxxxxxxxxxxxx", # Description of the component functions.
"version": "3.1", # Version, which must be the same as the version of OpenHarmony.
"license": "MIT", # Component license.
"publishAs": "code-segment", # Mode for publishing the HPM package. The default value is code-segment.
"segment": {
"destPath": "third_party/nghttp2"
}, # Code restoration path (source code path) when publishAs is code-segment.
"dirs": {}, # Directory structure of the HPM package. This field is mandatory and can be left empty.
"scripts": {}, # Scripts to be executed. This field is mandatory and can be left empty.
"licensePath": "COPYING",
"readmePath": {
"en": "README.rst"
},
"component": { # Component attributes.
"name": "<component_name>", # Component name.
"subsystem": "", # Subsystem to which the component belongs.
"syscap": [], # System capabilities provided by the component for applications.
"features": [], # List of the component's configurable features. Generally, this parameter corresponds to sub_component in build and can be configured.
"adapted_system_type": [], # Adapted system types, which can be mini, small, and standard. Multiple values are allowed.
"rom": "xxxKB" # ROM baseline. If there is no baseline, enter the current value.
"ram": "xxxKB", # RAM baseline. If there is no baseline, enter the current value.
"deps": {
"components": [], # Other components on which this component depends.
"third_party": [] # Third-party open-source software on which this component depends.
], # Component build entry. Configure the module here.
"inner_kits": [], # APIs between components
"test": [] # Entry for building the component's test cases.
}
}
}
```
Note that the **bundle.json** file must be in the folder of the corresponding subsystem.
#### Creating a Component and Adding a Module
1. Configure the **BUILD.gn** file in the module directory and select the corresponding template. Note that **part_name** in the **BUILD.gn** file is the name of the newly added component.
2. Create a **bundle.json** file in the folder of the corresponding subsystem.
The **bundle.json** file consists of two parts: **subsystem** and **parts**. Add the component information to **parts**. When adding a component, you need to specify the **sub_component** of the component. If there are APIs provided for other components, add them in **inner_kits**. If there are test cases, add them in **test**.
3. Add the new component to the end of existing components in **//vendor/{product_company}/{product-name}/config.json**.
```
"subsystems": [
{
"subsystem": "Name of the subsystem to which the component belongs",
"components": [
{"component": "Component 1 name", "features":[]}, # Existing component 1 in the subsystem
{ "component": "Component 2 name", "features":[] }, # Existing component 2 in the subsystem
{"component": "New component name", "features":[]} # New component in the subsystem
]
},
...
]
```
#### Creating a Subsystem and Adding a Module
1. Configure the **BUILD.gn** file in the module directory and select the corresponding template.
Note that **part_name** in the **BUILD.gn** file is the name of the newly added component.
2. Create a **bundle.json** file in the folder of the component of the subsystem.
This step is the same as the step in "Creating a Component and Adding a Module."
3. Modify the **subsystem_config.json** file in the **build** directory.
```
{
"Subsystem 1 name": { # Existing subsystem 1
"path": "Subsystem 1 directory",
"name": "Subsystem 1 name"
},
"Subsystem 2 name": { # Existing subsystem 2
"path": "Subsystem 2 directory",
"name": "Subsystem 2 name"
},
"Subsystem name new": { # Subsystem to add
"path": "New subsystem directory",
"name": "New subsystem name"
},
...
}
```
This file defines the subsystems and their paths. To add a subsystem, specify **path** and **name** for the subsystem.
4. If **product-name** in the **//vendor/{product_company}/{product-name}** directory is **hispark_taurus_standard**, add the new component information to the end of existing components in the **config.json** file.
```
"subsystems": [
{
"subsystem": "arkui", # Name of the existing subsystem
"components": [ # All components of the subsystem
{
"component": "ace_engine_standard", # Name of the existing component
"features": []
},
{
"component": "napi", # Name of the existing component
"features": []
}
{
"component": "component_new1", # Name of the new component added to the existing subsystem
"features": []
}
]
},
{
"subsystem": "subsystem_new", # Name of the new subsystem to add
"components": [
{
"component": "component_new2", # Name of the component added to the new subsystem
"features": []
}
]
},
...
]
```
Verification:
- Check that **module_list** in the **BUILD.gn** file in the component directory under the corresponding subsystem directory contains the target defined in the **BUILD.gn** file of the new module.
- Check the .so file or binary file generated in the image created.
This file specifies the name, manufacturer, device, version, type of system to be built, and subsystems of the product.
2.**subsystem_config.json** in the **build** directory
```
{
"arkui": {
"path": "foundation/arkui",
"name": "arkui"
},
"ai": {
"path": "foundation/ai",
"name": "ai"
},
......
}
```
This file contains subsystem information. You need to configure **name** and **path** for each subsystem.
3.**bundle.json** of a subsystem
```
{
"name": "@ohos/<component_name>, # HPM component name, in the "@Organization/Component name" format.
"description": "xxxxxxxxxxxxxxxxxxx", # Description of the component functions.
"version": "3.1", # Version, which must be the same as the version of OpenHarmony.
"license": "MIT", # Component license.
"publishAs": "code-segment", # Mode for publishing the HPM package. The default value is code-segment.
"segment": {
"destPath": ""
}, # Code restoration path (source code path) when publishAs is code-segment.
"dirs": {}, # Directory structure of the HPM package. This field is mandatory and can be left empty.
"scripts": {}, # Scripts to be executed. This field is mandatory and can be left empty.
"licensePath": "COPYING",
"readmePath": {
"en": "README.rst"
},
"component": { # Component attributes.
"name": "<component_name>", # Component name.
"subsystem": "", # Subsystem to which the component belongs.
"syscap": [], # System capabilities provided by the component for applications.
"features": [], # List of the component's configurable features. Generally, this parameter corresponds to sub_component in build and can be configured.
"adapted_system_type": [], # Adapted system types, which can be mini, small, and standard. Multiple values are allowed.
"rom": "xxxKB" # ROM baseline. If there is no baseline, enter the current value.
"ram": "xxxKB", # RAM baseline. If there is no baseline, enter the current value.
"deps": {
"components": [], # Other components on which this component depends.
"third_party": [] # Third-party open-source software on which this component depends.
},
"build": { # Build-related configurations.
"sub_component": ["gn target of the module"], # Component build entry
"inner_kits": [], # APIs between components.
"test": [] # Entry for building the component's test cases.
}
}
}
```
The **bundle.json** file defines the components of a subsystem.
Each component contains the module's target **component.build.sub_component**, **component.build.inner_kits** for interaction between components, and test cases **component.build.test_list**. The **component.build.sub_component** is mandatory.
4.**BUILD.gn** of each module
You can create **BUILD.gn** from a template or using the GN syntax.
### How Do I Build a HAP?
#### **HAP Description**
An OpenHarmony Ability Package (HAP) includes resources, raw assets, JS assets, native libraries, and **config.json**.
#### **Templates**
The compilation and build subsystem provides four templates for building HAPs. The templates are integrated in **ohos.gni**. Before using the templates, import **build/ohos.gni**.
1.**ohos_resources**
This template declares resource targets. After a target is built by restool, an index file is generated. The resource source file and index file are both packaged into the HAP.
A **ResourceTable.h** file is also generated after resource building. This header file can be referenced if the resource target is relied on.
The resource target name must end with **resources**, **resource**, or **res**. Otherwise, a build error may occur.
The following variables are supported:
-**sources**: a list of resource paths.
-**hap_profile**: **config.json** of the HAP required for resource building.
-**deps**: (optional) dependency of the current target.
2.**ohos_assets**
This template declares asset targets.
Beware that the spelling is "assets" as opposed to "assert".
The asset target name must end with **assets** or **asset**.
The following variables are supported:
-**sources**: a list for raw asset paths.
-**deps**: (optional) dependency of the current target.
3.**ohos_js_assets**
This template declares a JS resource target. The JS resource is the executable part of an L2 HAP.
The JS asset target name must end with **assets** or **asset**.
The following variables are supported:
-**source_dir**: JS resource path, which is of the string type.
-**deps**: (optional) dependency of the current target.
4.**ohos_hap**
This template declares a HAP target. A HAP that will be generated and packaged into the system image.
The following variables are supported:
-**hap_profile**: **config.json** of the HAP.
-**deps**: dependency of the current target.
-**shared_libraries**: native libraries on which the current target depends.
-**hap_name**: (optional) name of the HAP. The default value is the target name.
-**final_hap_path**: (optional) destination path of the HAP. It takes precedence over **hap_name**.
-**subsystem_name**: name of the subsystem to which the HAP belongs. The value must be the same as that in **bundle.json**. Otherwise, the HAP will fail to be installed in the system image.
-**part_name**: name of the component to which the HAP belongs. The value must be the same as that in **bundle.json**.
-**js2abc**: whether to convert the HAP into ARK bytecode.
-**certificate_profile**: certificate profile of the HAP, which is used for signature. For details about signatures, see [Configuring Signature Information](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-debugging-and-running-0000001263040487#section17660437768).
-**certificate_file**: Certificate file. You must apply for the certificate and its profile from the official OpenHarmony website.
-**keystore_path**: keystore file, which is used for signature.
-**keystore_password**: keystore password, which is used for signature.
-**key_alias**: key alias.
-**module_install_name**: name of the HAP used during installation.
-**module_install_dir**: installation path. The default path is **system/app**.
### What Does an Open-Source Software Notice Collect?
#### Information to Collect
The notice collects only the licenses of the modules packaged in the image. For example, the licenses of the tools (such as Clang, Python, and Ninja) used during the build process are not collected.
A static library itself is not packaged. However, if it is packaged into the system as part of a dynamic library or executable file, the license of the static library will be collected for completeness.
The final **Notice.txt** file must include all licenses used by the files in the image and the mapping between modules and licenses.
The **Notice.txt** file is located in the **/system/etc/** directory.
#### Rules for Collecting Information
Licenses are collected by priority.
1. Licenses that are directly declared in a module's **BUILD.gn** are given the top priority. The following is an example:
```
ohos_shared_library("example") {
...
license_file = "path-to-license-file"
...
}
```
2. If there is no explicitly declared license, the build script searches for the **Readme.OpenSource** file in the directory of **BUILD.gn**, parses the file, and collects the obtained licenses.
If the **Readme.OpenSource** file does not contain license information, an error will be reported.
3. If the **Readme.OpenSource** file does not exist, the build script searches for the **License**, **Copyright**, and **Notice** files from the current directory to the root directory of the source code by default. If obtained license information will be used as the licenses of the module.
4. If no license is found, the default license (Apache License 2.0) will be used.
Check items:
1. For third-party open-source software, such as OpenSSL and ICU, **Readme.OpenSource** must be configured in the source code directory. Check whether **Readme.OpenSource** is in the same directory as **BUILD.gn** and whether the license configured in **Readme.OpenSource** is valid.
2. If the source code is not licensed under the Apache License 2.0, the corresponding license file must be provided in the source code directory or declared by **license_file** for the module.
3. If the source code file added to **BUILD.gn** is not from the current directory, check whether the license in the repository where the source code file is located is the same as that in the repository of **BUILD.gn**. License inconsistency entails follow-up operations.
Add the keyword **syscap** under **component** to configure system capabilities. If no value is assigned for a system capability, the default value **true** will be used. The value **true** means to enable the system capability, and the value **false** means the opposite.
In this example, Wi-Fi STA, AP, and HotspotExt are enabled, and P2P and Core are disabled.
## Configuring System Capabilities for a Product
When building a product, you may need to enable or disable specific system capabilities for it in **vendor/{company}/{product}/config.json**. If you do not configure system capabilities here, the system capabilities configured for the component will be used.
To configure system capabilities for a product, add the keyword **syscap** to the product **config.json** file and configure the system capabilities. The system capabilities configured for a product take precedence over the system capabilities configured for a component. If a system capability is set to **false** for the component and to **true** for the product, the system capability is enabled. The following is an example:
In this example, Wi-Fi AP and HotspotExt are disabled and P2P is enabled for the product. Considering the system capability configuration example for the component, STA and P2P are enabled and AP, Core, and HotspotExt are disabled.
## Configuration Tips
If a product does not have feature difference, you only need to configure system capabilities for components. If a product has feature difference, you can enable or disable specific system capabilities in the product configuration file.