大号在练葵花宝典 发表于 2024-11-12 07:01:37

鸿蒙NEXT开发【GN构建工程配置HarmonyOS编译工具链】编译构建

本文将先容如安在GN工程中配置HarmonyOS工具链,然后通过HarmonyOS工具链编译出可以在HarmonyOS环境下使用的三方库。
概述

HarmonyOS编译子系统是以GN和Ninja构建为基座,对构建和配置粒度进行部件化抽象、对内建模块进行功能加强、对业务模块进行功能扩展的系统,该系统提供以下基本功能:


[*]以部件为最小粒度拼装产品和独立编译。
[*]支持轻量、小型、尺度三种系统的解决方案级版本构建,以及用于支持应用开发者使用IDE开发的SDK开发套件的构建。
[*]支持芯片解决方案厂商的灵活定制和独立编译。
Ninja: 是一个专注于快速编译的小型构建系统。
GN: Generate Ninja的缩写,用于产生Ninja文件。
编译环境配置


[*] Linux编译环境搭建(如果已有对应版本的Linux开发环境,可跳过Linux环境搭建过程)
编译环境目前主要支持Ubuntu18.04和Ubuntu20.04(Ubuntu22.04暂不支持)。
[*] HarmonyOS SDK镜像下载:
从DevEco Studio的SDK Manager中获取SDK。
[*] 安装构建工具depot_tools并添加到环境变量。
任意位置创建工作目次depot_tools,cd到自己创建的目次,拉取工具(需要网络环境):
mkdir depot_tools
cd depot_tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
将depot_tools的路径加到环境变量中:
编译.bashrc文件将depot_tools路径信息加到最后一行。
```
vi ~/.bashrc                                    
```
在.bashrc文件的最后添加下面一行代码。
https://i-blog.csdnimg.cn/direct/3d5fb92f13a54105ae2f37383b483bfd.png
```
export PATH="$PATH:/xxx/depot_tools"
```
此处需配置绝对路径信息,例如这里创建的本地路径是/mnt/d/my_code/depot_tools,故此处配置如上图。
革新环境变量使其生效:
```
source ~/.bashrc
```

[*]使用GN需要Python环境,安装Python环境。
sudo apt update
sudo apt install python
直接输入指令sudo apt install python可能会安装失败,需要先输入sudo apt update更新一下可用包的最新列表。
https://i-blog.csdnimg.cn/direct/2d252edee126420ea06359db77c188ff.png
判断python是否安装乐成:
输入python显示python版本即可。
https://i-blog.csdnimg.cn/direct/b44d838a483a430a967e6614ac701ef4.png
GN构建工程适配流程

https://i-blog.csdnimg.cn/direct/90f3516761064d109216c6cc7e8b1e4f.png
起首,需要添加HarmonyOS平台的宏界说;然后配置好HarmonyOS平台的工具链信息(包括clang工具链,sysroot以及clang版本);接着需要在toolchain路径下配置各个架构的ohos_clang_toolchain;然后扩充gcc_toolchain模版功能,配置HarmonyOS用于启动引导步伐的.o文件信息。剩下的就是需要设置一些HarmonyOS的编译参数(主要是底子的编译选项、宏界说等);然后在BUILD.gn中不同架构平台的分支处,添加对应的HarmonyOS平台的分支,其中未适配HarmonyOS的三方库可以先走Linux分支的编译配置。更加具体的信息可参考下节的适配案例。
webRTC适配案例

本文将通过webRTC的GN构建工程案例来对上一章节的流程进行实操讲解。WebRTC (Web Real-Time Communications) 是一项实时通讯技能,它允许网络应用大概站点,在不借助中心前言的环境下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流大概其他任意数据的传输。下面我们来相识下怎样通过GN构建工程将webRTC适配到HarmonyOS系统上。
适配流程

示例代码中D:\my_code\compare_src_ohos\src_ohos\中为源代码,D:\my_code\src_ohos\路径下为修改之后的代码。

[*] 添加HarmonyOS平台宏界说
这里主要增长了适配HarmonyOS的default_compiler_configs和_default_toolchain。在GN工程里面,BUILDCONFIG.gn是第一位被剖析的,里面界说的变量相称于全局变量,可以被后续全部的.gn文件使用。我们编译过程中可能会配置一些编译选项以及一些头文件搜索路径。default_compiler_configs指向的文件里面会包括一些默认的编译选项以及头文件搜索路径等等。_default_toolchain指向了一个工具链相关的函数。具体修改点如下:
https://i-blog.csdnimg.cn/direct/1b875ba452394c3580727eacb4d718f9.png
[*] 设置HarmonyOS平台clang工具链相关路径
不同平台的工具链会有一些差异,以是需要使用HarmonyOS的工具链。这里主要修改config/clang/clang.gni文件。.gni文件类似于GN的头文件,会被import到各个.gn文件中使用其界说的一些变量。该文件中的核心修改点在于配置指向HarmonyOS SDK的工具链路径。别的还需修改clang_use_chrome_plugins的值为false,HarmonyOS中默认clang_use_chrome_plugins值为false,不设置可能会报错find-bad-constructs文件找不到。
此处ohos_sdk_native_root的值需要对应修改为自己本地HarmonyOS SDK中的native的路径。具体修改点如下:
https://i-blog.csdnimg.cn/direct/f4a883a4d7144e6d946b5e7f040893eb.png
[*] 设置HarmonyOS平台sysroot路径
sysroot里面包含了许多头文件搜索路径,配置了sysroot之后,编译过程中会去该目次下搜索需要的头文件。SDK里面会提供大量的头文件,这些头文件都会放在sysroot目次下,以是我们需要引入HarmonyOS对应的sysroot。具体修改点如下:
https://i-blog.csdnimg.cn/direct/ee259dbed29849558d0a3462d36ac444.png
[*] 修改HarmonyOS平台clang版本
这里主要是配置HarmonyOS对应的clang版本号。具体修改点如下:
https://i-blog.csdnimg.cn/direct/9593f56e188842da8a01e96a6bd948ce.png
[*] 设置各个架构的ohos_clang_toolchain
这里主要是在/src_ohos/build/toolchain路径下新建一个ohos/BUILD.gn文件,用于配置ohos_clang_toolchain,里面主要配置了HarmonyOS用于启动引导步伐的.o文件。同时设置HarmonyOS不同架构(主要包括ohos_clang_arm、ohos_clang_arm64、ohos_clang_x86_64)的ohos_clang_toolchain配置信息。具体添加内容如下:
import("//build/config/sysroot.gni")
import("//build/toolchain/gcc_toolchain.gni")

declare_args() {
# Whether unstripped binaries, i.e. compiled with debug symbols, should be
# considered runtime_deps rather than stripped ones.
ohos_unstripped_runtime_outputs = true
ohos_extra_cflags = ""
ohos_extra_cppflags = ""
ohos_extra_cxxflags = ""
ohos_extra_asmflags = ""
ohos_extra_ldflags = ""
}

# The ohos clang toolchains share most of the same parameters, so we have this
# wrapper around gcc_toolchain to avoid duplication of logic.
#
# Parameters:
#- toolchain_root
#      Path to cpu-specific toolchain within the ndk.
#- sysroot
#      Sysroot for this architecture.
#- lib_dir
#      Subdirectory inside of sysroot where libs go.
#- binary_prefix
#      Prefix of compiler executables.
template("ohos_clang_toolchain") {
gcc_toolchain(target_name) {
    assert(defined(invoker.toolchain_args),
         "toolchain_args must be defined for ohos_clang_toolchain()")
    toolchain_args = invoker.toolchain_args
    toolchain_args.current_os = "ohos"

    # Output linker map files for binary size analysis.
    enable_linker_map = true

    ohos_libc_dir =
      rebase_path(invoker.sysroot + "/" + invoker.lib_dir, root_build_dir)
    libs_section_prefix = "${ohos_libc_dir}/Scrt1.o"
    libs_section_prefix += " ${ohos_libc_dir}/crti.o"
    libs_section_postfix = "${ohos_libc_dir}/crtn.o"

    if (invoker.target_name == "ohos_clang_arm") {
      abi_target = "arm-linux-ohos"
    } else if (invoker.target_name == "ohos_clang_arm64") {
      abi_target = "aarch64-linux-ohos"
    } else if (invoker.target_name == "ohos_clang_x86_64") {
      abi_target = "x86_64-linux-ohos"
    }

    clang_rt_dir =
      rebase_path("${clang_lib_path}/${abi_target}/nanlegacy",
                  root_build_dir)
    print("ohos_libc_dir :", ohos_libc_dir)
    print("clang_rt_dir :", clang_rt_dir)
    solink_libs_section_prefix = "${ohos_libc_dir}/crti.o"
    solink_libs_section_prefix += " ${clang_rt_dir}/clang_rt.crtbegin.o"
    solink_libs_section_postfix = "${ohos_libc_dir}/crtn.o"
    solink_libs_section_postfix += " ${clang_rt_dir}/clang_rt.crtend.o"

    _prefix = rebase_path("${clang_base_path}/bin", root_build_dir)
    cc = "${_prefix}/clang"
    cxx = "${_prefix}/clang++"
    ar = "${_prefix}/llvm-ar"
    ld = cxx
    readelf = "${_prefix}/llvm-readobj"
    nm = "${_prefix}/llvm-nm"
    if (!is_debug) {
      strip = rebase_path("${clang_base_path}/bin/llvm-strip", root_build_dir)
      use_unstripped_as_runtime_outputs = ohos_unstripped_runtime_outputs
    }
    extra_cflags = ohos_extra_cflags
    extra_cppflags = ohos_extra_cppflags
    extra_cxxflags = ohos_extra_cxxflags
    extra_asmflags = ohos_extra_asmflags
    extra_ldflags = ohos_extra_ldflags
}
}

ohos_clang_toolchain("ohos_clang_arm") {
sysroot = "${sysroot}"
lib_dir = "usr/lib/arm-linux-ohos"
toolchain_args = {
    current_cpu = "arm"
}
}

ohos_clang_toolchain("ohos_clang_arm64") {
sysroot = "${sysroot}"
lib_dir = "usr/lib/aarch64-linux-ohos"
toolchain_args = {
    current_cpu = "arm64"
}
}

ohos_clang_toolchain("ohos_clang_x86_64") {
sysroot = "${sysroot}"
lib_dir = "usr/lib/x86_64-linux-ohos"
toolchain_args = {
    current_cpu = "x86_64"
}
}

[*] 扩充原来的gcc_toolchain模版功能
GN工程里面默认会配置gcc_toolchain,里面会包括一些tool,例如tool(“cc”)、tool(“cxx”)、tool(“tolink”)等等,编译不同的内容时调用其对应的配置项。这里主要是需要修改tool(“solink”)、tool(“solink_module”)中的rspfile_content配置以及tool(“link”)中的link_comand配置。我们需要在gcc_toolchain.gni中template(“gcc_toolchain”)下添加几个参数(libs_section_prefix、libs_section_postfix 、solink_libs_section_prefix、solink_libs_section_postfix )的识别。这几个参数是指向了上一步骤中配置的用于启动引导步伐的.o文件。这些参数会在我们需要修改的rspfile_content、link_comand中用到。具体修改如下:
https://i-blog.csdnimg.cn/direct/e180b14760004e34878c88e34f65a8bf.png
修改tool(“solink”)和tool(“solink_module”)中的rspfile_content为rspfile_content = “-Wl,–whole-archive {{inputs}} {{solibs}} -Wl,–no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix”,这里需要用到刚刚界说的参数信息。具体修改如下:
https://i-blog.csdnimg.cn/direct/2836a2c2b14549a2b6b401cf6e296c7d.png
修改tool(“link”)中link_command为link_command = “                                             l                               d                                           l                                  d                                  f                                  l                                  a                                  g                                  s                                                 ld {{ldflags}}                        ldldflags{extra_ldflags} -o “$unstripped_outfile” $libs_section_prefix KaTeX parse error: Expected group as argument to '\"' at end of input: …_group_flag @\"rspfile” {{solibs}} {{libs}} $end_group_flag $libs_section_postfix",这里需要用到刚刚界说的参数信息。
https://i-blog.csdnimg.cn/direct/14021154763647d0aa3c0f3072470f5c.png
[*] 设置HarmonyOS的一些编译参数,将其加入到BUILDCONFIG.gn中
这里需要在config路径下新建一个ohos/BUILD.gn文件,该文件主要是界说了一个config(“compiler”),该config会被注册到全部的编译目标,该config里面主要设置了底子的编译选项、宏界说等。
此处ohos_clang_base_path 的值需要对应修改为自己本地HarmonyOS SDK中的llvm的路径。具体添加内容如下:
import("//build/config/sysroot.gni")
assert(is_ohos)

ohos_clang_base_path = "/mnt/d/ohos/ohos-sdk/linux/native/llvm"
ohos_clang_version = "15.0.4"

if (is_ohos) {
if (current_cpu == "arm") {
    abi_target = "arm-linux-ohos"
} else if (current_cpu == "x86") {
    abi_target = ""
} else if (current_cpu == "arm64") {
    abi_target = "aarch64-linux-ohos"
} else if (current_cpu == "x86_64") {
    abi_target = "x86_64-linux-ohos"
} else {
    assert(false, "Architecture not supported")
}
}

config("compiler") {
cflags = [
    "-ffunction-sections",
    "-fno-short-enums",
    "-fno-addrsig",
]

cflags += [
    "-Wno-unknown-warning-option",
    "-Wno-int-conversion",
    "-Wno-unused-variable",
    "-Wno-misleading-indentation",
    "-Wno-missing-field-initializers",
    "-Wno-unused-parameter",
    "-Wno-c++11-narrowing",
    "-Wno-unneeded-internal-declaration",
    "-Wno-undefined-var-template",
    "-Wno-implicit-int-float-conversion",
]
defines = [
    # The NDK has these things, but doesn't define the constants to say that it
    # does. Define them here instead.
    "HAVE_SYS_UIO_H",
]

defines += [
    "OHOS",
    "__MUSL__",
    "_LIBCPP_HAS_MUSL_LIBC",
    "__BUILD_LINUX_WITH_CLANG",
    "__GNU_SOURCE",
    "_GNU_SOURCE",
]

ldflags = [
    "-Wl,--no-undefined",
    "-Wl,--exclude-libs=libunwind_llvm.a",
    "-Wl,--exclude-libs=libc++_static.a",

    # Don't allow visible symbols from libraries that contain
    # assembly code with symbols that aren't hidden properly.
    # http://crbug.com/448386
    "-Wl,--exclude-libs=libvpx_assembly_arm.a",
]

cflags += [ "--target=$abi_target" ]
include_dirs = [
    "${sysroot}/usr/include/${abi_target}",
    "${ohos_clang_base_path}/lib/clang/${ohos_clang_version}/include",
]

ldflags += [ "--target=$abi_target" ]

# Assign any flags set for the C compiler to asmflags so that they are sent
# to the assembler.
asmflags = cflags
}

[*] build/config/compiler/BUILD.gn中增长对is_ohos的判断
包管可以精确走HarmonyOS支持的编译分支。这里主要是为了防止clang版本号校验失败导致非常。具体修改如下:
https://i-blog.csdnimg.cn/direct/d7c455555f6d4c49995c941930d5fc51.png
[*] 未适配HarmonyOS的三方库走linux编译配置
当前部门三方库还未适配HarmonyOS,涉及到时可以先走linux的编译配置,例如:需要获取config.h文件时。
修改video_capture的BUILD.gn。具体修改如下:
https://i-blog.csdnimg.cn/direct/d4187a82173c4bfc90e042b4b8968561.png
修改zlib的BUILD.gn。具体修改如下:
https://i-blog.csdnimg.cn/direct/d807cb1f32264e52bd86a1e76f23eee9.png
修改libevent中的BUILD.gn。HarmonyOS SDK中没有queue.h头文件,需要使用compat dir目次下的queue.h头文件。具体修改如下:
https://i-blog.csdnimg.cn/direct/fdbbc8f56de34ebaa131380d867490c7.png
[*] 编译
先通过GN命令生成对应的ninja文件,然后使用ninja编译命令进行编译。
gn gen ../out/xxx --args='is_clang=true target_os="ohos" target_cpu="arm64" xxx'
ninja -v -C ../out/xxx ${target_name} -j16
可以根据需要在编译指令中添加对应参数信息。
检察具体编译命令:
可以在gn gen命令中添加–ninja-args="-v -dkeeprsp"用于检察具体编译命令,这个命令将会在编译过程中打印具体的编译命令,并且保存编译过程中生成的rsp文件。
检察一个目标被谁依赖:
例如gn refs out/intermediate/arm64_72 //pc:rtc_pc_base。这个命令将显示与目标//pc:rtc_pc_base相关的全部依赖项并列出全部引用了该目标的其他目标或文件。
常见问题总结

在对webRTC的GN工程进行HarmonyOS工具链适配过程中,碰到了一些常见问题场景。下面针对这些问题做一个具体分析。

[*] Assertion failed. Unsupported ARM OS
问题详情:
https://i-blog.csdnimg.cn/direct/6de20c5294244411b6d27090765b780d.png
问题原因/解决措施:
三方库内部没有做对is_ohos的判断,导致走到错误分支。当前许多业务模块还未适配HarmonyOS,临时可以走linux分支以包管正常编译。
具体修改:
https://i-blog.csdnimg.cn/direct/1268166238ab45a3b435acf196f221ef.png

[*]

[*] python找不到pkg-config文件:No such file or directory: ‘pkg-config’
问题详情:
https://i-blog.csdnimg.cn/direct/4a0dafa20ae0427e81e15b8831be50db.png
问题原因/解决措施:
缺少pkg-config插件,安装该插件。
具体指令:
sudo apt-get install pkg-config

[*] Unknown command line argument ‘-split-threshold-for-reg-with-hint=0’
问题详情:
https://i-blog.csdnimg.cn/direct/e0cb9ada441f48dd95302cdcf9ad9e6f.png
问题原因/解决措施:
编译过程中会提示部门配置不识别,需要将这些配置项删除。
具体修改:
https://i-blog.csdnimg.cn/direct/e9f763a8a3d949888b0ca21e937d55a1.png
[*] WARN范例导致的ERROR
问题详情:
https://i-blog.csdnimg.cn/direct/4b6eddea19bc40b98f208d43f9097bbe.png
问题原因/解决措施:
编译器驱动步伐偶然(很少)会在调用之前发出警告。实际的链接器需要确保这些警告是否也被视为致命错误。为了避免编译中出现因警告而造成堕落,可以添加编译参数treat_warnings_as_errors = false,大概去除config(treat_warnings_as_errors)中配置的“-Werror”,详情如下:
https://i-blog.csdnimg.cn/direct/ff981672c5134fc085e1db3e55d4150e.png
具体修改:

[*] 添加编译指令配置项treat_warnings_as_errors (建议使用)
https://i-blog.csdnimg.cn/direct/a5f49deb3d6241c2b5743eb0db3eef71.png
[*] 修改源代码
https://i-blog.csdnimg.cn/direct/3ded0d9919134062b73147c1ab300fc6.png

[*] error: reinterpret_cast from ‘pthread_t’ (aka ‘unsigned long’) to ‘rtc::PlatformThreadId’ (aka ‘int’) is not allowed
问题详情:
https://i-blog.csdnimg.cn/direct/48fd96acd6894155b2bdb90c7ebc366c.png
问题原因/解决措施:
rtc_base/platform_thread_types.cc未识别到is_ohos导致内部走错分支导致非常。目前HarmonyOS支持的接口是gettid(),rtc_base/platform_thread_types.cc需要识别到is_ohos然后调用gettid()。由于当前许多业务模块还未进行识别,临时需要走linux分支,故需要保存liunx的界说。
具体修改:

[*] 起首需要在根目次的BUILD.gn中配置识别HarmonyOS系统的变量is_ohos:
https://i-blog.csdnimg.cn/direct/057f553db1ee41169f3a10031fa6580c.png
[*] 修改rtc_base/platform_thread_types.cc业务代码:
https://i-blog.csdnimg.cn/direct/17340a2854b4460fa76cb39ac2719ad4.png

[*] fatal error: ‘config.h’ file not found
fatal error: ‘sys/queue.h’ file not found
问题详情:
https://i-blog.csdnimg.cn/direct/67605847dc2643eab57602d08329f2cb.png
https://i-blog.csdnimg.cn/direct/1e6d9b87f7cb46f89a450071f7eb3d72.png
问题原因/解决措施:
找不到config.h头文件,libevent尚未适配HarmonyOS,需要添加is_ohos的判断并走linux的文件路径探求config.h。
找不到’sys/queue.h’文件,HarmonyOS SDK中没有queue.h头文件,需要使用compat dir目次下的queue.h头文件。
具体修改:
https://i-blog.csdnimg.cn/direct/cc9aefbe32274bd3b2adad9755f38288.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 鸿蒙NEXT开发【GN构建工程配置HarmonyOS编译工具链】编译构建