1# cmake转gn指导 2 3## 概述 4本文档介绍GN构建工具在OpenHarmony中的常见使用方法,指导三方库由cmake构建到GN构建的转换。 5 6## GN常用的内置变量 7| 名称 | 描述 | 8|-------------------|---------------| 9| current_cpu | 当前工具链的处理器架构 | 10| current_os | 当前工具链的操作系统类型 | 11| current_toolchain | 表示当前使用的工具链 | 12| default_toolchain | 表示默认使用的工具链 | 13| target_cpu | 表示目标平台的CPU类型 | 14| target_os | 表示目标平台的操作系统类型 | 15| root_build_dir | 表示根目录的构建目录 | 16| root_gen_dir | 表示根目录的生成目录 | 17| root_out_dir | 表示根目录的输出目录 | 18| target_out_dir | 表示目标文件的输出目录 | 19| target_gen_dir | 表示中间文件的生成目录 | 20| defines | 表示当前目标的预定义宏列表 | 21| include_dirs | 表示当前目标的头文件搜索路径列表 | 22| cflags | 表示当前目标的C语言编译选项列表 | 23| cxxflags | 表示当前目标的C++语言编译选项列表 | 24| ldflags | 表示当前目标的链接选项列表 | 25| asmflags | 表示当前目标的汇编语言编译选项列表 | 26| libs | 表示当前目标依赖的库文件列表 | 27 28## GN常用的内置函数 29| 名称 | 描述 | 30|------|-----| 31| assert() | 断言函数,如果条件不成立,则会抛出一个异常 | 32| defined() | 判断变量是否已经定义 | 33| exec_script() | 执行一个Python脚本 | 34| get_label_info() | 获取标签信息,例如标签的名称、路径、类型等等 | 35| get_path_info() | 获取路径信息,例如路径是否存在、是否是目录、是否是文件等等 | 36| group() | 将一组目标文件组合成一个库文件 | 37| import() | 导入其他GN构建文件 | 38| read_file() | 读取文件内容 | 39| read_json() | 读取JSON格式的文件 | 40| read_path() | 读取路径中的内容,返回一个字符串列表 | 41| rebase_path() | 重新定位路径,将路径中的某个部分替换为新的值 | 42| write_file() | 写入文件内容 | 43| template() | 处理字符串模板,将模板中的变量替换为实际的值,其功能类似与函数 | 44| action() | 定义一个自定义的构建动作,通过action调用python脚本完成期望动作 | 45| action_foreach() | 针对每个元素执行一个自定义的构建动作 | 46| executable() | 定义一个可执行文件 | 47| shared_library() | 定义一个动态库 | 48| static_library() | 定义一个静态库 | 49 50 51## 如何使用GN进行构建 52当将一个基于CMake的项目转换为使用GN进行构建时,需要了解如何指定动态库、静态库和可执行文件的构建规则。以下是一个简单的指南,介绍如何在GN中指定这些构建规则: 53- **动态库** 54 55在CMake中,可以使用add_library命令来指定动态库的构建规则。例如: 56``` 57add_library(mylib SHARED 58 src/foo.cpp 59 src/bar.cpp 60) 61``` 62在GN中,可以使用shared_library模板来指定动态库的构建规则,创建BUILD.gn文件,内容如下: 63``` 64# 指定动态库名称 65mylib_name = "mylib" 66 67# 指定动态库源文件 68mylib_sources = [ 69 "src/foo.cpp", 70 "src/bar.cpp", 71] 72 73# 指定动态库编译选项和链接选项 74mylib_cflags = [ 75 "-Wall", 76] 77mylib_ldflags = [ 78 "-L/usr/local/lib", 79] 80 81# 指定动态库构建规则 82shared_library(mylib_name) { 83 sources = mylib_sources 84 cflags = mylib_cflags 85 ldflags = mylib_ldflags 86} 87``` 88 89- **静态库** 90 91在CMake中,可以使用add_library命令来指定静态库的构建规则。例如: 92``` 93add_library(mylib STATIC 94 src/foo.cpp 95 src/bar.cpp 96) 97 98``` 99 100在GN中,可以使用static_library模板来指定静态库的构建规则,创建BUILD.gn文件,内容如下: 101``` 102# 指定静态库名称 103mylib_name = "mylib" 104 105# 指定静态库源文件 106mylib_sources = [ 107 "src/foo.cpp", 108 "src/bar.cpp", 109] 110 111# 指定静态库编译选项 112mylib_cflags = [ 113 "-Wall", 114] 115 116# 指定静态库构建规则 117static_library(mylib_name) { 118 sources = mylib_sources 119 cflags = mylib_cflags 120} 121``` 122 123- **可执行文件** 124 125在CMake中,可以使用add_executable命令来指定可执行文件的构建规则。例如: 126``` 127add_executable(myapp 128 src/main.cpp 129) 130``` 131在GN中,可以使用executable模板来指定可执行文件的构建规则。例如: 132``` 133# 指定可执行文件名称 134myapp_name = "myapp" 135 136# 指定可执行文件源文件 137myapp_sources = [ 138 "src/main.cpp", 139] 140 141# 指定可执行文件编译选项和链接选项 142myapp_cflags = [ 143 "-Wall", 144] 145myapp_ldflags = [ 146 "-L/usr/local/lib", 147] 148 149# 指定可执行文件构建规则 150executable(myapp_name) { 151 sources = myapp_sources 152 cflags = myapp_cflags 153 ldflags = myapp_ldflags 154} 155``` 156 157OpenHarmony在GN原生模板的基础上进行了功能扩展,提供了ohos_shared_library、ohos_static_library、ohos_executable模板,在BUILD.gn中import("//build/ohos.gni")即可使用,ohos_shared_library示例如下: 158``` 159import("//build/ohos.gni") 160ohos_shared_library("helloworld") { 161 sources = [] 162 include_dirs = [] 163 cflags = [] 164 cflags_c = [] 165 cflags_cc = [] 166 ldflags = [] 167 configs = [] 168 deps = [] # 部件内模块依赖 169 170 # 跨部件模块依赖定义, 171 # 定义格式为 "部件名:模块名称" 172 # 这里依赖的模块必须是依赖的部件声明在inner_kits中的模块 173 external_deps = [ 174 "part_name:module_name", 175 ] 176 177 output_name = "" # 可选,模块输出名 178 output_extension = "" # 可选,模块名后缀 179 module_install_dir = "" # 可选,缺省在/system/lib64或/system/lib下, 模块安装路径,模块安装路径,从system/,vendor/后开始指定 180 relative_install_dir = "" # 可选,模块安装相对路径,相对于/system/lib64或/system/lib;如果有module_install_dir配置时,该配置不生效 181 install_images = [] # 可选,缺省值system,指定模块安装到那个分区镜像中,可以指定多个 182 183 part_name = "" # 必选,所属部件名称 184} 185``` 186 187## 简单示例 188假设我们有一个简单的CMake项目,包含两个源文件:main.cpp和hello.cpp,以及一个头文件hello.h。CMakeLists.txt文件内容如下: 189``` 190cmake_minimum_required(VERSION 3.10) 191 192project(hello) 193 194add_executable(hello main.cpp hello.cpp hello.h) 195``` 196 197目录结构如下: 198``` 199hello/ 200├── include 201│ └── hello.h 202└── src 203 ├── hello.cpp 204 └── main.cpp 205``` 206 207以下介绍如何在OpenHarmony编译框架中使用GN编译上述示例: 2081. 在OpenHarmony代码中,增加example目录,将hello示例放在example目录下,在hello目录下新建BUILD.gn文件,示例如下: 209``` 210import("//build/ohos.gni") 211 212config("hello_config") { 213 include_dirs = [ "./include" ] 214} 215 216ohos_shared_library("hello_so") { 217 configs = [ ":hello_config" ] 218 sources = [ "./src/hello.cpp" ] 219 part_name = "hello" 220 subsystem_name = "example" 221} 222 223ohos_executable("hello") { 224 deps = [ ":hello_so" ] 225 configs = [ ":hello_config" ] 226 sources = [ "./src/main.cpp" ] 227 part_name = "hello" 228 subsystem_name = "example" 229} 230``` 231 2322. 在example目录下新建bundle.json文件,示例如下: 233``` 234{ 235 "name": "@ohos/example", 236 "description": "", 237 "version": "3.1", 238 "license": "MIT", 239 "publishAs": "code-segment", 240 "segment": { 241 "destPath": "" 242 }, 243 "dirs": {}, 244 "scripts": {}, 245 "licensePath": "COPYING", 246 "readmePath": { 247 "en": "README.rst" 248 }, 249 "component": { 250 "name": "hello", # 部件名称 251 "subsystem": "example", # 部件所属子系统 252 "syscap": [], 253 "features": [], 254 "adapted_system_type": [], 255 "rom": "", 256 "ram": "", 257 "deps": { 258 "components": [], 259 "third_party": [] 260 }, 261 "build": { 262 "group_type": { # 部件编译入口,新增模块在此处配置 263 "base_group": [ "//example/hello:hello" ], 264 "fwk_group": [], 265 "service_group": [] 266 }, 267 "inner_kits": [], 268 "test": [] 269 } 270 } 271} 272``` 273 2743. 在`vendor\产品厂商\产品名\config.json`中配置新增的example子系统和hello组件,以rk3568为例,示例如下: 275``` 276# 以rk3568为例 277{ 278 "product_name": "rk3568", 279 "device_company": "rockchip", 280 "device_build_path": "device/board/hihope/rk3568", 281 "target_cpu": "arm", 282 "type": "standard", 283 "version": "3.0", 284 "board": "rk3568", 285 "api_version": 8, 286 "enable_ramdisk": true, 287 "enable_absystem": false, 288 "build_selinux": true, 289 "build_seccomp": true, 290 "inherit": [ "productdefine/common/inherit/rich.json", "productdefine/common/inherit/chipset_common.json" ], 291 "subsystems": [ 292 { 293 "subsystem": "example", 294 "components": [ 295 { 296 "component": "hello", 297 "features": [] 298 } 299 ] 300 }, 301 ...... 302 ] 303} 304``` 305 3064. 在build/subsystem_config.json中增加新增的example子系统路径,示例如下: 307``` 308{ 309 "example": { 310 "path": "example", 311 "name": "example" 312 } 313 ...... 314} 315``` 316 3175. 执行编译命令,以rk3568为例: 318``` 319./build.sh --product-name rk3568 -T hello 320 321# build.sh是OpenHarmony编译入口脚本 322# --product-name用于指定产品名 323# -T指定编译目标,单独编译 324``` 325 3266. 编译产物生成在out/rk3568/example/hello目录下: 327``` 328out/rk3568/example/hello/ 329├── hello 330└── libhello_so.z.so 331```