Files
phs_v1.0.1.0/build/docs/cmake转gn指导文档.md
2024-09-27 19:16:49 +08:00

9.8 KiB
Raw Permalink Blame History

cmake转gn指导

概述

本文档介绍GN构建工具在OpenHarmony中的常见使用方法指导三方库由cmake构建到GN构建的转换。

GN常用的内置变量

名称 描述
current_cpu 当前工具链的处理器架构
current_os 当前工具链的操作系统类型
current_toolchain 表示当前使用的工具链
default_toolchain 表示默认使用的工具链
target_cpu 表示目标平台的CPU类型
target_os 表示目标平台的操作系统类型
root_build_dir 表示根目录的构建目录
root_gen_dir 表示根目录的生成目录
root_out_dir 表示根目录的输出目录
target_out_dir 表示目标文件的输出目录
target_gen_dir 表示中间文件的生成目录
defines 表示当前目标的预定义宏列表
include_dirs 表示当前目标的头文件搜索路径列表
cflags 表示当前目标的C语言编译选项列表
cxxflags 表示当前目标的C++语言编译选项列表
ldflags 表示当前目标的链接选项列表
asmflags 表示当前目标的汇编语言编译选项列表
libs 表示当前目标依赖的库文件列表

GN常用的内置函数

名称 描述
assert() 断言函数,如果条件不成立,则会抛出一个异常
defined() 判断变量是否已经定义
exec_script() 执行一个Python脚本
get_label_info() 获取标签信息,例如标签的名称、路径、类型等等
get_path_info() 获取路径信息,例如路径是否存在、是否是目录、是否是文件等等
group() 将一组目标文件组合成一个库文件
import() 导入其他GN构建文件
read_file() 读取文件内容
read_json() 读取JSON格式的文件
read_path() 读取路径中的内容,返回一个字符串列表
rebase_path() 重新定位路径,将路径中的某个部分替换为新的值
write_file() 写入文件内容
template() 处理字符串模板,将模板中的变量替换为实际的值,其功能类似与函数
action() 定义一个自定义的构建动作通过action调用python脚本完成期望动作
action_foreach() 针对每个元素执行一个自定义的构建动作
executable() 定义一个可执行文件
shared_library() 定义一个动态库
static_library() 定义一个静态库

如何使用GN进行构建

当将一个基于CMake的项目转换为使用GN进行构建时需要了解如何指定动态库、静态库和可执行文件的构建规则。以下是一个简单的指南介绍如何在GN中指定这些构建规则

  • 动态库

在CMake中可以使用add_library命令来指定动态库的构建规则。例如

add_library(mylib SHARED
  src/foo.cpp
  src/bar.cpp
)

在GN中可以使用shared_library模板来指定动态库的构建规则创建BUILD.gn文件内容如下

# 指定动态库名称
mylib_name = "mylib"

# 指定动态库源文件
mylib_sources = [
  "src/foo.cpp",
  "src/bar.cpp",
]

# 指定动态库编译选项和链接选项
mylib_cflags = [
  "-Wall",
]
mylib_ldflags = [
  "-L/usr/local/lib",
]

# 指定动态库构建规则
shared_library(mylib_name) {
  sources = mylib_sources
  cflags = mylib_cflags
  ldflags = mylib_ldflags
}
  • 静态库

在CMake中可以使用add_library命令来指定静态库的构建规则。例如

add_library(mylib STATIC
  src/foo.cpp
  src/bar.cpp
)

在GN中可以使用static_library模板来指定静态库的构建规则创建BUILD.gn文件内容如下

# 指定静态库名称
mylib_name = "mylib"

# 指定静态库源文件
mylib_sources = [
  "src/foo.cpp",
  "src/bar.cpp",
]

# 指定静态库编译选项
mylib_cflags = [
  "-Wall",
]

# 指定静态库构建规则
static_library(mylib_name) {
  sources = mylib_sources
  cflags = mylib_cflags
}
  • 可执行文件

在CMake中可以使用add_executable命令来指定可执行文件的构建规则。例如

add_executable(myapp
  src/main.cpp
)

在GN中可以使用executable模板来指定可执行文件的构建规则。例如

# 指定可执行文件名称
myapp_name = "myapp"

# 指定可执行文件源文件
myapp_sources = [
  "src/main.cpp",
]

# 指定可执行文件编译选项和链接选项
myapp_cflags = [
  "-Wall",
]
myapp_ldflags = [
  "-L/usr/local/lib",
]

# 指定可执行文件构建规则
executable(myapp_name) {
  sources = myapp_sources
  cflags = myapp_cflags
  ldflags = myapp_ldflags
}

OpenHarmony在GN原生模板的基础上进行了功能扩展提供了ohos_shared_library、ohos_static_library、ohos_executable模板在BUILD.gn中import("//build/ohos.gni")即可使用ohos_shared_library示例如下

import("//build/ohos.gni")
ohos_shared_library("helloworld") {
  sources = []
  include_dirs = []
  cflags = []
  cflags_c = []
  cflags_cc = []
  ldflags = []
  configs = []
  deps = []  # 部件内模块依赖

  # 跨部件模块依赖定义,
  # 定义格式为 "部件名:模块名称"
  # 这里依赖的模块必须是依赖的部件声明在inner_kits中的模块
  external_deps = [
    "part_name:module_name",
  ]

  output_name = ""           # 可选,模块输出名
  output_extension = ""      # 可选,模块名后缀
  module_install_dir = ""    # 可选,缺省在/system/lib64或/system/lib下 模块安装路径模块安装路径从system/vendor/后开始指定
  relative_install_dir = ""  # 可选,模块安装相对路径,相对于/system/lib64或/system/lib如果有module_install_dir配置时该配置不生效
  install_images = []        # 可选缺省值system指定模块安装到那个分区镜像中可以指定多个

  part_name = "" # 必选,所属部件名称
}

简单示例

假设我们有一个简单的CMake项目包含两个源文件main.cpp和hello.cpp以及一个头文件hello.h。CMakeLists.txt文件内容如下

cmake_minimum_required(VERSION 3.10)

project(hello)

add_executable(hello main.cpp hello.cpp hello.h)

目录结构如下:

hello/
├── include
│   └── hello.h
└── src
    ├── hello.cpp
    └── main.cpp

以下介绍如何在OpenHarmony编译框架中使用GN编译上述示例

  1. 在OpenHarmony代码中增加example目录将hello示例放在example目录下在hello目录下新建BUILD.gn文件示例如下
import("//build/ohos.gni")

config("hello_config") {
    include_dirs = [ "./include" ]
}

ohos_shared_library("hello_so") {
    configs = [ ":hello_config" ]
    sources = [ "./src/hello.cpp" ]
    part_name = "hello"
    subsystem_name = "example"
}

ohos_executable("hello") {
    deps = [ ":hello_so" ]
    configs = [ ":hello_config" ]
    sources = [ "./src/main.cpp" ]
    part_name = "hello"
    subsystem_name = "example"
}
  1. 在example目录下新建bundle.json文件示例如下
{
   "name": "@ohos/example",                 
   "description": "",             
   "version": "3.1",                                 
   "license": "MIT",                                 
   "publishAs": "code-segment",                      
   "segment": {
       "destPath": ""
   },                                                 
   "dirs": {},                                       
   "scripts": {},                                    
   "licensePath": "COPYING",
   "readmePath": {
       "en": "README.rst"
   },
   "component": {                                    
       "name": "hello",                                       # 部件名称
       "subsystem": "example",                                # 部件所属子系统             
       "syscap": [],                                 
       "features": [],                               
       "adapted_system_type": [],                    
       "rom": "",
       "ram": "",                               
       "deps": {
           "components": [],                         
           "third_party": []                         
       },
       "build": {                                    
           "group_type": {                                    # 部件编译入口,新增模块在此处配置
               "base_group": [ "//example/hello:hello" ],   
               "fwk_group": [],
               "service_group": []
           },
           "inner_kits": [],                         
           "test": []                                
       }
   }
}
  1. vendor\产品厂商\产品名\config.json中配置新增的example子系统和hello组件以rk3568为例示例如下
# 以rk3568为例
{
  "product_name": "rk3568",
  "device_company": "rockchip",
  "device_build_path": "device/board/hihope/rk3568",
  "target_cpu": "arm",
  "type": "standard",
  "version": "3.0",
  "board": "rk3568",
  "api_version": 8,
  "enable_ramdisk": true,
  "enable_absystem": false,
  "build_selinux": true,
  "build_seccomp": true,
  "inherit": [ "productdefine/common/inherit/rich.json", "productdefine/common/inherit/chipset_common.json" ],
  "subsystems": [
    {
      "subsystem": "example",
      "components": [
        {
          "component": "hello",
          "features": []
        }
      ]
    },
    ......
  ]
}
  1. 在build/subsystem_config.json中增加新增的example子系统路径示例如下
{
  "example": {
    "path": "example",
    "name": "example"
  }
  ......
}
  1. 执行编译命令以rk3568为例
./build.sh --product-name rk3568 -T hello

# build.sh是OpenHarmony编译入口脚本
# --product-name用于指定产品名
# -T指定编译目标单独编译
  1. 编译产物生成在out/rk3568/example/hello目录下
out/rk3568/example/hello/
├── hello
└── libhello_so.z.so