移植busybox

1.准备busybox源码

  • 1.手动下载并解压到鸿蒙项目根目录third_party目录下: BusyBox
  • 2.wget命令拉取
wget https://www.busybox.net/downloads/busybox-1.38.0.tar.bz2
tar -jxf busybox-1.38.0.tar.bz2
# harmonyRoot为鸿蒙源码根目录
mv busybox-1.38.0.tar.bz2 harmonyRoot/third_party/busybox

2.将busybox加入GN+NINJA构建流程中

  • 1.在busybox目录下创建bundle.json文件,并添加以下内容
{
    "name": "@ohos/busybox",
    "description": "busybox Linux command line",
    "version": "1.38.0",
    "license": "GNU GENERAL PUBLIC LICENSE",
    "publishAs": "code-segment",
    "segment": {
        "destPath": "third_party/busybox"
    },
    "dirs": {},
    "scripts": {},
    "licensePath": "",
    "readmePath": {
        "en": ""
    },
    "component": {
        "name": "busybox",
        "subsystem": "thirdparty",
        "syscap": [],
        "features": [
            "busybox_feature_support_usr_symlink"
        ],
        "adapted_system_type": [
            "standard",
            "small"
        ],
        "rom": "73KB",
        "ram": "146KB",
        "deps": {
            "components": [
                "selinux",
                "openssl"
            ],
            "third_party": []
        },
        "build": {
            "sub_component": [
                "//third_party/busybox:busybox"
            ],
            "inner_kits": [
                {
                    "name" : "//third_party/busybox:busybox"
                }
            ],
            "test": []
        }
    }
}
  • 2.在busybox目录下创建busybox.gni文件,并添加以下内容
BUSYBOX_SRC_DIR = [ "//third_party/busybox" ]

declare_args() {
  busybox_feature_support_usr_symlink = false

  busybox_config_target = "defconfig"

  # 传给 make 的并行度,0 表示按 CPU 数。
  busybox_build_jobs = 0

  # 是否放宽告警(-w 关闭所有告警,避免 -Werror 类问题打断编译)。
  busybox_relax_warnings = true
}
  • 3.在busybox目录下创建BUILD.gn文件,并添加以下内容
import("//build/config/clang/clang.gni")
import("//build/config/sysroot.gni")
import("//build/ohos.gni")
import("busybox.gni")

if (target_cpu == "loongarch64") {
  _target_triple = "loongarch64-linux-ohos"
} else if (target_cpu == "arm64") {
  _target_triple = "aarch64-linux-ohos"
} else if (target_cpu == "arm") {
  _target_triple = "arm-linux-ohos"
} else {
  _target_triple = "loongarch64-linux-ohos"
}

_busybox_build_dir = "$target_out_dir/busybox_build"
_busybox_binary = "$_busybox_build_dir/busybox"

if (defined(ohos_lite)) {
  group("busybox") {
    # None
  }
} else {
  _clang_bin = "$clang_base_path/bin/clang"
  _llvm_bin_dir = "$clang_base_path/bin"

  action("busybox_make") {
    script = "ohos_build_busybox.py"

    inputs = [ "ohos_build_busybox.py" ]

    outputs = [ _busybox_binary ]

    args = [
      "--src-dir",
      rebase_path(".", root_build_dir),
      "--build-dir",
      rebase_path(_busybox_build_dir, root_build_dir),
      "--config-target",
      busybox_config_target,
      "--clang-bin",
      rebase_path(_clang_bin, root_build_dir),
      "--llvm-dir",
      rebase_path(_llvm_bin_dir, root_build_dir),
      "--target-triple",
      _target_triple,
      "--sysroot",
      rebase_path(sysroot, root_build_dir),
      "--jobs",
      "$busybox_build_jobs",
    ]
    if (busybox_relax_warnings) {
      args += [ "--relax-warnings" ]
    }
  }

  ohos_prebuilt_executable("busybox") {
    # 由 action("busybox_make") 产出的二进制。
    source = _busybox_binary

    # 拷贝到 target_out_dir 下的名字
    output = "busybox"

    deps = [ ":busybox_make" ]

    symlink_target_name = [
      "ip",
      "vi",
      "candump",
      "cansend",
    ]

    if (busybox_feature_support_usr_symlink) {
      symlink_target_name += [
        # "../usr/bin/ip",
        # "../usr/bin/vi",
      ]
    }

    module_install_dir="bin"
    part_name = "busybox"
    subsystem_name = "thirdparty"
    install_images = [ "system" ]
    install_enable = true
  }
}

3.添加busybox编译脚本

  • busybox源码庞大,如果采用toybox那样用gn+ninja来编译,后续维护成本极大;所以采用脚本编译的方式,只需要的BUILD.gn中调用编译脚本即可,编译完成后的产物任然交由gn构建系统管理
  • busybox目录下创建ohos_build_busybox.py文件,并添加以下内容
#!/usr/bin/env python3

import argparse
import os
import shutil
import subprocess
import sys

def run(cmd, env=None, cwd=None):
    print(">>", " ".join(cmd))
    subprocess.check_call(cmd, env=env, cwd=cwd)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--src-dir", required=True,
                        help="busybox resource code root directory")
    parser.add_argument("--build-dir", required=True,
                        help="out-of-tree build directory")
    parser.add_argument("--config-target", default="defconfig",
                        help="be used to create .config")
    parser.add_argument("--clang-bin", required=True,
                        help="clang path")
    parser.add_argument("--llvm-dir", required=True,
                        help="llvm tools directory")
    parser.add_argument("--target-triple", required=True,
                        help="target architecture")
    parser.add_argument("--sysroot", required=True,
                        help="musl sysroot path")
    parser.add_argument("--jobs", type=int, default=0,
                        help="thread number of make command, 0: use all of cpu thread")
    parser.add_argument("--relax-warnings", action="store_true",
                        help="close all warning")
    args = parser.parse_args()

    # use absolute path
    src_dir = os.path.abspath(args.src_dir)
    build_dir = os.path.abspath(args.build_dir)
    clang_bin = os.path.abspath(args.clang_bin)
    llvm_dir = os.path.abspath(args.llvm_dir)
    sysroot = os.path.abspath(args.sysroot)
    os.makedirs(build_dir, exist_ok=True)

    # 1) assemble the target compiler command
    target_flags = [
        "--target=" + args.target_triple,
        "--sysroot=" + sysroot,
        "-fPIE",
        "-funsigned-char",
    ]
    cflags = list(target_flags)
    if args.relax_warnings:
        cflags.append("-w")
    # -D_GNU_SOURCE / -D__MUSL__ 让 busybox 在 ohos musl 下更顺
    # (-D__MUSL__ 避免 musl 与内核 uapi 的 sockaddr_storage 重复定义)
    cflags += ["-D_GNU_SOURCE", "-D__MUSL__",
               "-DBB_VER=\"" + get_bb_ver(src_dir) + "\""]

    # Concatenated cross-compilation toolchain
    cc_cmd = clang_bin + " " + " ".join(cflags)
    cxx_cmd = clang_bin + "++ " + " ".join(cflags)
    ar_cmd = os.path.join(llvm_dir, "llvm-ar")
    ld_cmd = os.path.join(llvm_dir, "ld.lld")
    strip_cmd = os.path.join(llvm_dir, "llvm-strip")
    nm_cmd = os.path.join(llvm_dir, "llvm-nm")
    ranlib_cmd = os.path.join(llvm_dir, "llvm-ranlib")

    # 2) parameters of make.
    make_vars = [
        "ARCH=" + arch_from_triple(args.target_triple),
        "CROSS_COMPILE=",
        "HOSTCC=cc",
        "CC=" + cc_cmd,
        "CXX=" + cxx_cmd,
        "AR=" + ar_cmd,
        "LD=" + ld_cmd,
        "STRIP=" + strip_cmd,
        "NM=" + nm_cmd,
        "RANLIB=" + ranlib_cmd,
        "SKIP_STRIP=y",
    ]

    dst_config = os.path.join(build_dir, ".config")

    # 3) make defconfig to create .config
    run(["make", "-C", src_dir, "O=" + build_dir, "-s",
         args.config_target] + make_vars)

    jobs = args.jobs if args.jobs > 0 else os.cpu_count()

    # 4) compile
    run(["make", "-C", src_dir, "O=" + build_dir, "-j" + str(jobs)] + make_vars)

    # 5) checkout 
    busybox_bin = os.path.join(build_dir, "busybox")
    if not os.path.isfile(busybox_bin):
        print("ERROR: busybox binary not found at " + busybox_bin,
              file=sys.stderr)
        sys.exit(1)
    print("OK: built " + busybox_bin)

def get_bb_ver(src_dir):
    # busybox 源码里有 include/VERSION
    for name in ("include/VERSION",):
        p = os.path.join(src_dir, name)
        if os.path.isfile(p):
            with open(p) as f:
                return f.read().strip()
    return "0"

def arch_from_triple(triple):
    # loongarch64-linux-ohos -> loongarch
    return triple.split("-")[0].rstrip("0123456789")

if __name__ == "__main__":
    main()

4.在厂商产品侧添加busybox

  • vi vender/xxx/xxx/config.json
  • 在该文件中的thirdparty子系统中添加busybox组件
{
      "subsystem": "thirdparty",
      "components": [
        ...
        {
          "component": "busybox",
          "features": []
        },
        ...
      ]        
}

5.验证

  • 编译完成后在out/board_name/packages/phone/system/bin/目录下会生成busybox可执行文件和BUILD.gn文件中symlink_target_name列表中列举的链接
  • 烧录镜像后即可正常使用
Logo

更多推荐