# 编译构建使用指导<a name="ZH-CN_TOPIC_0000001060378721"></a>

-   [前提条件](#section13333171022312)
-   [hb命令行工具使用](#section477242204612)
-   [新增组件](#section4207112818418)
-   [新增芯片解决方案](#section2737141421917)
-   [新增产品解决方案](#section720881917199)

## 前提条件<a name="section13333171022312"></a>

开发环境需安装gn、ninja构建工具、python 3.7.4及以上和hb。安装方法请见[搭建系统基础环境](../quick-start/搭建系统环境.md)。

## hb命令行工具使用<a name="section477242204612"></a>

hb是OpenHarmony的命令行工具，用来执行编译命令。以下对hb的常用命令进行说明。

1.  **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
    ```

    -   hb set 后无参数，进入默认设置流程
    -   hb set -root dir可直接设置代码根目录
    -   hb set -p设置要编译的产品

2.  **hb env**

    查看当前设置信息

    ```
    hb env
    [OHOS INFO] root path: xxx
    [OHOS INFO] board: hispark_taurus
    [OHOS INFO] kernel: liteos
    [OHOS INFO] product: ipcamera
    [OHOS INFO] product path: xxx/vendor/hisilicon/ipcamera
    [OHOS INFO] device path: xxx/device/hisilicon/hispark_taurus/sdk_linux_4.19
    ```

3.  **hb build**

    ```
    hb build -h
    usage: hb build [-h] [-b BUILD_TYPE] [-c COMPILER] [-t [TEST [TEST ...]]]
                    [--dmverity] [-p PRODUCT] [-f] [-n]
                    [component [component ...]]
    
    positional arguments:
      component             name of the component
    
    optional arguments:
      -h, --help            show this help message and exit
      -b BUILD_TYPE, --build_type BUILD_TYPE
                            release or debug version
      -t [TEST [TEST ...]], --test [TEST [TEST ...]]
                            compile test suit
      --dmverity            Enable dmverity
      -p PRODUCT, --product PRODUCT
                            build a specified product with
                            {product_name}@{company}, eg: ipcamera@hisilcon
      -f, --full            full code compilation
      -T [TARGET [TARGET ...]], --target [TARGET [TARGET ...]]
                            Compile single target
    ```

    -   hb build后无参数，会按照设置好的代码路径、产品进行编译，编译选项使用与之前保持一致。-f 选项将删除当前产品所有编译产品，等同于hb clean + hb build.
    -   hb build \{component\_name\}：基于设置好的产品对应的单板、内核，单独编译组件（e.g.：hb build kv\_store\)。
    -   hb build -p ipcamera@hisilicon：免set编译产品，该命令可以跳过set步骤，直接编译产品。
    -   在device/device\_company/board下单独执行hb build会进入内核选择界面，选择完成后会根据当前路径的单板、选择的内核编译出仅包含内核、驱动的镜像。

4.  **hb clean**

    清除out目录对应产品的编译产物，仅保留args.gn、build.log。清除指定路径可输入路径参数：hb clean out/board/product，默认将清除当前hb set的产品对应out路径。

    ```
    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
    ```


## 新增组件<a name="section4207112818418"></a>

本小节介绍如何新增一个组件，首先确定组件归属的子系统和组件名称，然后按如下步骤新增：

1.  源码开发完成后，添加组件编译脚本。

    以编译组件hello\_world可执行文件为例，applications/sample/hello\_world/BUILD.gn可以写为：

    ```
    executable("hello_world") {
      include_dirs = [
        "include",
       ]
      sources = [
        "src/hello_world.c"
      ]
    }
    ```

    如上编译脚本，可编译出一个可在OpenHarmony上运行的名为hello\_world的可执行文件。

    单独编译该组件，hb set任意选择一款产品，然后使用-T选项单独编译组件：

    ```
    hb build -f -T //applications/sample/hello_world
    ```

    组件在开发板上功能验证完成后，可按步骤2\~5将组件配置到产品中。

2.  添加组件描述。

    组件描述位于build/lite/components下，新增的组件需加入对应子系统的json文件中。一个组件描述必选的字段有：

    -   component：组件名称。
    -   description：组件的一句话功能描述。
    -   optional：组件是否为系统可选。
    -   dirs：组件源码路径。
    -   targets：组件编译入口。

    以将hello\_world组件加入应用子系统为例，在applications.json中添加hello\_world对象：

    ```
    {
      "components": [
        {
          "component": "hello_world",
          "description": "Hello world.",
          "optional": "true",
          "dirs": [
            "applications/sample/hello_world"
          ],
          "targets": [
            "//applications/sample/hello_world"
          ]
        },
        ...
       ]
    }
    ```

3.  将组件配置到产品。

    产品的配置文件config.json位于位于vendor/company/product/下，产品配置文件需包含产品名称、OpenHarmony版本号、device厂商、开发板、内核类型、内核版本号，以及配置的子系统和组件。以将hello\_world组件加入产品配置文件my\_product.json中为例，加入hello\_wolrd对象：

    ```
    {
        "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.  编译产品。

    1. 代码根目录输入hb set选择对应产品。

    2. 执行hb build。


## 新增芯片解决方案<a name="section2737141421917"></a>

编译构建支持添加新的芯片解决方案厂商，具体步骤如下：

1.  创建芯片解决方案目录。

    按照[芯片解决方案配置规则](编译构建概述.md#section1625463413327)创建目录，以芯片厂商realtek的“rtl8720“开发板为例, 在代码根目录执行：

    ```
    mkdir -p device/realtek/rtl8720
    ```

2.  创建内核适配目录，并编写开发板编译配置config.gni文件。

    以realtek的“rtl8720“开发板的liteos\_m适配为例，device/realtek/rtl8720/liteos\_a/config.gni的内容如下：

    ```
    # 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.
    board_toolchain_path =
        rebase_path("//prebuilts/gcc/linux-x86/arm/gcc-arm-none-eabi/bin",
                    root_build_dir)
    
    # Compiler prefix.
    board_toolchain_prefix = "gcc-arm-none-eabi-"
    
    # Compiler type, "gcc" or "clang".
    board_toolchain_type = "gcc"
    
    # Board related common compile flags.
    board_cflags = []
    board_cxx_flags = []
    board_ld_flags = []
    ```

3.  编写编译脚本。

    在开发板目录下创建BUILD.gn，target名称应与开发板名称一致。以realtek的rtl8720开发板为例，device/realtek/rtl8720/BUILD.gn内容可以是：

    ```
    group("rtl8720") { # target类型也可以shared_library, static_library, executable
      # 具体内容
      ......
    }
    ```

4.  编译芯片解决方案。

    在开发板目录下执行hb build，即可启动芯片解决方案的编译。


## 新增产品解决方案<a name="section720881917199"></a>

编译构建支持芯片解决方案和组件的灵活拼装，形成定制化的产品解决方案。具体步骤如下：

1.  创建产品目录

    按照[产品解决方案配置规则](编译构建概述.md#section1625463413327)创建产品目录，以基于“rtl8720“开发板的wifiiot模组为例，在代码根目录执行：

    ```
    mkdir -p vendor/my_company/wifiiot
    ```

2.  拼装产品

    在新建的产品目录下新建config.json文件，以步骤1中的wifiiot为例，vendor/my\_company/wifiiot/config.json可以是：

    ```
    {
        "product_name": "wifiiot",                        # 产品名称
        "ohos_version": "OpenHarmony 1.0",                # 使用的OS版本
        "device_company": "realtek",                      # 芯片解决方案厂商名称
        "board": "rtl8720",                               # 开发板名称
        "kernel_type": "liteos_m",                        # 选择的内核类型
        "kernel_version": "3.0.0",                        # 选择的内核版本
        "subsystems": [                            
          {
            "subsystem": "kernel",                        # 选择的子系统
            "components": [
              { "component": "liteos_m", "features":[] }  # 选择的组件和组件特性
            ]
          },
          ...
          {
             更多子系统和组件
          }
        ]
    }
    ```

    注意：编译构建系统编译前会对device\_company，board，kernel\_type，kernel\_version、subsystem、component字段进行有效性检查，其中device\_company，board，kernel\_type，kernel\_version应与已知的芯片解决方案匹配，subsystem、component应与build/lite/components下的组件描述匹配。

3.  适配OS接口

    在产品目录下创建hals目录，并将产品解决方案对OS适配的源码和编译脚本放入该目录下。

4.  配置系统服务

    在产品目录下创建init\_configs目录，并在init\_configs目录下创建init.cfg文件，按需配置要启动的系统服务。

5.  配置init进程（仅linux内核需要）

    在init\_configs目录下创建etc目录，然后在etc下创建init.d文件夹和fstab文件。最后按产品需求在init.d文件下创建并编辑rcS文件和Sxxx文件。

6.  配置文件系统镜像（可选，仅支持文件系统的开发板需要）

    在产品目录下创建fs.yml文件。fs.yml需按产品实际情况配置，一个典型的fs.yml文件如下：

    ```
    -
      fs_dir_name: rootfs # 镜像的名称
      fs_dirs:
        -
          # 将编译生成的out/my_board/my_product/bin目录下的文件拷贝到rootfs/bin中，并忽略测试bin
          source_dir: bin
          target_dir: bin
          ignore_files:
            - Test.bin
            - TestSuite.bin
        -
          # 将编译生成的out/my_board/my_product/libs目录下的文件拷贝到rootfs/lib中，忽略所有.a文件，并设置文件和文件夹的权限为644和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
        -
          # 创建一个proc空目录
          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:
        -
          # 在rootfs/lib下创建软连接ld-musl-arm.so.1 -> libc.so
          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:
        # 使用脚本将rootfs制作为ext4格式的image
        - ${root_path}/build/lite/make_rootfs/rootfsimg_linux.sh ${fs_dir} ext4
    -
      fs_dir_name: userfs
      fs_dirs:
        -
          source_dir: storage/etc
          target_dir: etc
        -
          source_dir: data
          target_dir: data
      fs_make_cmd:
        - ${root_path}/build/lite/make_rootfs/rootfsimg_linux.sh ${fs_dir} ext4
    
    ```

7.  编写编译脚本

    在产品目录下创建BUILD.gn文件，按产品实际情况编写脚本。以步骤1中的wifiiot为例，BUILD.gn示例如下：

    ```
    group("wifiiot") { # target名称与产品名一致
      deps = []
      # 拷贝init配置
      deps += [ "init_configs" ]
      # 将hals加入编译
      deps += [ "hals" ]
      # 其他
      ......
    }
    ```

8.  编译产品。

    在代码根目录执行hb set按提示选择新增的产品，然后执行hb build即可启动编译。


