OpenHarmony南向开发—如何快速上手GN

2024-04-27 15:52

本文主要是介绍OpenHarmony南向开发—如何快速上手GN,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

最近在研究鸿蒙操作系统的开源项目OpenHarmony,该项目使用了GN+Ninja工具链进行配置,编译,于是开始研究GN如何使用。
本文的所有信息均来自GN官网和本人个人体会。

GN快速入门

使用GN

GN的主要功能是根据配置文件(.gn, BUILD.gn等)生成build.ninja文件。build.ninja类似于Makefile,不同的是由Ninja负责执行编译过程。
获取GN可执行程序。
1)源码编译。可以到官网下载源码。也可以到我的GN源码(需要5积分)
2)鸿蒙源码提供的GN可执行程序。Ubuntu下路径为[源码路径]/prebuilts/build-tools/linux-x86/bin/
将可执行程序放入PATH路径下,或将可执行程序的路径放入PATH,便可在命令行中直接使用GN。

建立构建环境

使用官网示例代码examples/simple_build,可以到官网下载,或到simple_build下载。
进入simple_build代码目录下,将…/out/build作为构建目录。

simple_build$ tree
.
├── build
│   ├── BUILDCONFIG.gn
│   ├── BUILD.gn
│   └── toolchain
│       └── BUILD.gn
├── BUILD.gn
├── hello.cc
├── hello_shared.cc
├── hello_shared.h
├── hello_static.cc
├── hello_static.h
├── README.md
└── tutorial├── README.md└── tutorial.cc
simple_build$ gn gen ../out/build
Done. Made 3 targets from 4 files in 31ms
simple_build$ tree ../out/build
../out/build
├── args.gn
├── build.ninja
├── build.ninja.d
├── obj
│   ├── hello.ninja
│   ├── hello_shared.ninja
│   └── hello_static.ninja
└── toolchain.ninja

显示构建参数

simple_build$ gn args --list ../out/build
current_cpuCurrent value (from the default) = ""(Internally set; try `gn help current_cpu`.)
current_osCurrent value (from the default) = ""(Internally set; try `gn help current_os`.)

交叉编译

设置target_os=“android”,target_cpu = “arm”

simple_build$ gn args ../out/build
##在编辑器里输入
##    target_os=“android”
##    target_cpu = "arm"
##    保存,退出
Waiting for editor on "/media/hndz-dhliu/C7968B675F10B93B/download/gn/examples/out/build/args.gn"...
Generating files...
Done. Made 3 targets from 4 files in 32mssimple_build$ gn args ../out/build --list
current_cpuCurrent value (from the default) = ""(Internally set; try `gn help current_cpu`.)
......
target_cpuCurrent value = "arm"From /media/hndz-dhliu/C7968B675F10B93B/download/gn/examples/out/build/args.gn:4Overridden from the default = ""(Internally set; try `gn help target_cpu`.)
target_osCurrent value = "android"From /media/hndz-dhliu/C7968B675F10B93B/download/gn/examples/out/build/args.gn:3Overridden from the default = ""(Internally set; try `gn help target_os`.)

添加tutorial目标

在simple_build目录下有一个tutorial目录,其下有一个tutorial.cc文件。
在tutorial目录下,添加一个BUILD.gn文件

## tutorial/BUILD.gn
executable("tutorial") {sources = ["tutorial.cc",]
}

修改simple_build下BUILD.gn文件,使其引用tutorial目录下tutorial目标。

## simple_build/BUILD.gn
group("tools") { //虚目标节点deps = [# This will expand to the name "//tutorial:tutorial" which is the full name of our new target. Run "gn help labels" for more."//tutorial",]
}

测试验证。

simple_build$ gn gen ../out/build
Done. Made 5 targets from 5 files in 35ms
simple_build$ tree ../out/build
../out/build
├── args.gn
├── build.ninja
├── build.ninja.d
├── obj
│   ├── hello.ninja
│   ├── hello_shared.ninja
│   ├── hello_static.ninja
│   └── tutorial
│       └── tutorial.ninja
└── toolchain.ninja

目标由3更新为5,产生了tutorial/ tutorial.ninja文件。
编译验证

simple_build$ ninja -C ../out/build tutorial ##表示转到../out/build tutorial目录下编译
ninja: Entering directory `../out/build'
[2/2] LINK tutorial
simple_build$ ../out/build/tutorial 
Hello from the tutorial.

BUILD.gn配置说明

simple_build/BUILD.gn
静态库hello_static配置:用static_library声明静态库,用sources声明所用的源文件。

static_library("hello_static") {sources = ["hello_static.cc","hello_static.h",]
}

可用 gn help static_library 获取static_library的详细用法。
动态库hello_shared配置:用shared_library声明动态库,用sources声明所用的源文件,用defines声明所需要的宏定义。

shared_library("hello_shared") {sources = ["hello_shared.cc","hello_shared.h",]defines = [ "HELLO_SHARED_IMPLEMENTATION" ]
}

可用 gn help shared_library 获取shared_library的详细用法。
可执行程序配置:用executable声明一个可执行程序,用sources声明该可执行程序的源文件,用deps指示所用的库文件。

executable("hello") {sources = ["hello.cc",]deps = [":hello_shared",":hello_static",]
}

测试可执行程序。

simple_build$ ninja -C ../out/build
ninja: Entering directory `../out/build'
[7/7] LINK hello
simple_build$ ../out/build/hello 
Hello, world

验证删除…/out/build/tutorial,再次编译是否重新生成tutorial

simple_build$ rm ../out/build/tutorial 
simple_build$ ninja -C ../out/build
ninja: Entering directory `../out/build'
[2/2] STAMP obj/tools.stamp
simple_build$ ls ../out/build/tutorial -la
-rwxrwxrwx 1 hndz-dhliu hndz-dhliu 8304 3月   9 13:45 ../out/build/tutorial

使用config

库使用者常常需要一些编译选项,宏定义,头文件包含路径,可以将这些内容封装到一个config变量中。
示例如下

config("my_lib_config") {defines = [ "ENABLE_DOOM_MELON" ]include_dirs = [ "//third_party/something" ]
}

使用config,将config变量添加到某个目标的configs列表中。

static_library("hello_shared") {...# Note "+=" here is usually required, see "default configs" below.configs += [":my_lib_config",]
}

如果将config变量应用到所有目标中,则将config变量添加到public_configs列表中。

static_library("hello_shared") {...public_configs = [":my_lib_config",]
}

使用默认配置

默认配置将被用到所有目标中。
可通过print函数打印默认配置。

executable("hello") {print(configs)
}

运行gn,可能打印出如下信息。

$ gn gen out
["//build:compiler_defaults", "//build:executable_ldconfig"]
Done. Made 5 targets from 5 files in 9ms

修改配置。
示例,关闭//build:no_exceptions,启用//build:exceptions

executable("hello") {...configs -= [ "//build:no_exceptions" ]  # Remove global default.configs += [ "//build:exceptions" ]  # Replace with a different one.print("The configs for the target $target_name are $configs")##打印,用来检查
}

使用参数

通过 gn help buildargs可以学习参数是如何设置的。其加载过程如下,加载系统默认参数(),加载//.gn中的default_args,加载–args命令行参数,加载工具链的参数。使用参数首先要用declare_args声明参数,并赋默认值。如果加载顺序上没被赋值,则使用默认值。

声明参数

declare_args() {enable_teleporter = trueenable_doom_melon = false
}

可通过gn help declare_args 了解declare_args详细信息。

了解GN构建过程

使用 -v 可以了解GN的详细执行流程。

simple_build$ gn gen -v ../out/build
Using source root /media/hndz-dhliu/C7968B675F10B93B/download/gn/examples/simple_build
Got dotfile /media/hndz-dhliu/C7968B675F10B93B/download/gn/examples/simple_build/.gn
Using build dir /media/hndz-dhliu/C7968B675F10B93B/download/gn/examples/out/build/
Loading //build/BUILDCONFIG.gn
Loading //BUILD.gn
Running //BUILD.gn with toolchain //build/toolchain:gcc
Defining target //:hello(//build/toolchain:gcc)
Defining target //:hello_shared(//build/toolchain:gcc)
Defining target //:hello_static(//build/toolchain:gcc)
Defining target //:tools(//build/toolchain:gcc)
Loading //build/BUILD.gn (referenced from //build/BUILDCONFIG.gn:22)
Loading //build/toolchain/BUILD.gn (referenced from //BUILD.gn:5)
Loading //tutorial/BUILD.gn (referenced from //BUILD.gn:33)
Running //build/BUILD.gn with toolchain //build/toolchain:gcc
Defining config //build:compiler_defaults(//build/toolchain:gcc)
Defining config //build:executable_ldconfig(//build/toolchain:gcc)
Running //build/toolchain/BUILD.gn with toolchain //build/toolchain:gcc
Defining toolchain //build/toolchain:gcc
Computing //:hello_static(//build/toolchain:gcc)
Computing //:hello_shared(//build/toolchain:gcc)
Computing //:hello(//build/toolchain:gcc)
Running //tutorial/BUILD.gn with toolchain //build/toolchain:gcc
Defining target //tutorial:tutorial(//build/toolchain:gcc)
Computing //tutorial:tutorial(//build/toolchain:gcc)
Computing //:tools(//build/toolchain:gcc)
Done. Made 5 targets from 5 files in 30ms

构建过程如下
1)在当前目录及其父目录查找.gn文件(即dotfile),以此作为source root
2).gn文件中buildconfig变量指示build config file路径(该文件常用来配置相关编译工具链),root变量指示source root(不指定时则为.gn所在的目录)。
3)加载build config file
4)加载source root下的BUILD.gn文件以及其引用的相关文件。
可通过gn help dotfile了解其构建过程。

查找依赖

通过 gn desc <build_dir> 可以了解一个目标的详细信息。通过 gn desc <build_dir> deps --tree 可以查找一个目标的依赖信息。

simple_build$ gn desc ../out/build //:hello
Target //:hello
type: executable
toolchain: //build/toolchain:gccvisibility*metadata{}testonlyfalsecheck_includestrueallow_circular_includes_fromsources//hello.ccpublic[All headers listed in the sources are public.]configs (in order applying, try also --tree)//build:compiler_defaults//build:executable_ldconfigoutputs/media/hndz-dhliu/C7968B675F10B93B/download/gn/examples/out/build/helloldflags-Wl,-rpath=$ORIGIN/-Wl,-rpath-link=Direct dependencies (try also "--all", "--tree", or even "--all --tree")//:hello_shared//:hello_staticexternssimple_build$ gn desc ../out/build //:hello deps --tree
//:hello_shared
//:hello_static

通过gn help desc 了解desc的更多用法。

GN文件执行脚本
参照官方文档language.md
有两种方式:
1)使用action目标类型
2)使用exec_script函数

action("run_this_guy_once") {script = "doprocessing.py"sources = [ "my_configuration.txt" ]outputs = [ "$target_gen_dir/insightful_output.txt" ]# Our script imports this Python file so we want to rebuild if it changes.inputs = [ "helper_library.py" ]# Note that we have to manually pass the sources to our script if the# script needs them as inputs.args = [ "--out", rebase_path(target_gen_dir, root_build_dir) ] +rebase_path(sources, root_build_dir)}

exec_script(filename,arguments = [],input_conversion = "",file_dependencies = [])The default script interpreter is Python ("python" on POSIX, "python.exe" or "python.bat" on Windows). This can be configured by the script_executable variable, see "gn help dotfile".
Arguments:filename:File name of script to execute. Non-absolute names will be treated as relative to the current build file.arguments: A list of strings to be passed to the script as arguments. May be unspecified or the empty list which means no arguments.input_conversion: Controls how the file is read and parsed. See "gn help io_conversion".If unspecified, defaults to the empty string which causes the script result to be discarded. exec script will return None.dependencies: (Optional) A list of files that this script reads or otherwise depends on. These dependencies will be added to the build result such that if any of them change, the build will be regenerated and the script will be re-run.Exampleall_lines = exec_script("myscript.py", [some_input], "list lines",[ rebase_path("data_file.txt", root_build_dir) ])# This example just calls the script with no arguments and discards the# result.exec_script("//foo/bar/myscript.py")

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://gitee.com/MNxiaona/733GH

这篇关于OpenHarmony南向开发—如何快速上手GN的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/940915

相关文章

SpringBoot开发中十大常见陷阱深度解析与避坑指南

《SpringBoot开发中十大常见陷阱深度解析与避坑指南》在SpringBoot的开发过程中,即使是经验丰富的开发者也难免会遇到各种棘手的问题,本文将针对SpringBoot开发中十大常见的“坑... 目录引言一、配置总出错?是不是同时用了.properties和.yml?二、换个位置配置就失效?搞清楚加

Linux如何快速检查服务器的硬件配置和性能指标

《Linux如何快速检查服务器的硬件配置和性能指标》在运维和开发工作中,我们经常需要快速检查Linux服务器的硬件配置和性能指标,本文将以CentOS为例,介绍如何通过命令行快速获取这些关键信息,... 目录引言一、查询CPU核心数编程(几C?)1. 使用 nproc(最简单)2. 使用 lscpu(详细信

Python中对FFmpeg封装开发库FFmpy详解

《Python中对FFmpeg封装开发库FFmpy详解》:本文主要介绍Python中对FFmpeg封装开发库FFmpy,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、FFmpy简介与安装1.1 FFmpy概述1.2 安装方法二、FFmpy核心类与方法2.1 FF

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

基于Python开发一个有趣的工作时长计算器

《基于Python开发一个有趣的工作时长计算器》随着远程办公和弹性工作制的兴起,个人及团队对于工作时长的准确统计需求日益增长,本文将使用Python和PyQt5打造一个工作时长计算器,感兴趣的小伙伴可... 目录概述功能介绍界面展示php软件使用步骤说明代码详解1.窗口初始化与布局2.工作时长计算核心逻辑3

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1