OpenHarmony下GN语法普法

OpenHarmony下GN语法普法

引言

前面一直在折腾怎么移植,怎么编写,尼玛忘了搞最基本的GN语法了。这不必须给安排上!


一.GN表达式语言和GN作用域

GN 是简单的动态类型的命令式语言,其最终目的只是产生声明性的 Ninja 规则。一切都围绕作用域决定,它既是该语言的词法绑定(lexical binding,即静态绑定)结构,也是数据类型。

GN 值可以使用下列几种类型的任何一种:

  • 布尔型(boolean),或 true 或 false
  • 整型(integer),带符号,使用普通十进制语法;不常用
  • 字符串(string),总是使用"双引号"引住(注意下面关于 $ 的扩展)
  • (scope),使用花括号括住 { ... };见下。
  • 值列表(list of values),使用方括号括住:[ 1, true, "foo", { x=1 y=2 } ]是一个四元素列表。

值是动态类型的,因而没有隐式类型的强迫,但也就没有这样的类型检查。不同类型的值比较结果永不相等,但是比较它们并不是错误。

字符串字面值在双引号中将简单的 $var 或 v a r 表达式扩展。这是一种立即扩展( i m m e d i a t e e x p a n s i o n ):当 v a r 为字符串时, x {var} 表达式扩展。这是一种立即扩展(immediate expansion):当 var 为字符串时,x var表达式扩展。这是一种立即扩展(immediateexpansion):当var为字符串时,x{var}y 与 x + var + y 相同。这样,任何值都可以表示为打印美观的字符串。

字母、数字和下划线组成的标志符可以通过赋值运算符填充一个域。GN 语言所做的实际上就是使用 = 进行命令式赋值,并通过 += 进行修改(也有一些特殊的方式来产生副作用,如 print(),用于调试;又如 write_file(),谨慎使用)。

1.1 整形

整形就比较简单了,形如:

cpp 复制代码
x = 1
y = 2

关于这块有如下几点需要注意:

  • GN语法是空白不敏感的
  • GN语法不支持 ?= 这种

1.2 Strings 字符串

字符串括在双引号中,并使用反斜杠作为转义字符。仅仅支持如下转义序列是!

cpp 复制代码
- \"(双引号)
- \$(美元符号$)
- \\(反斜杠)

反斜杠的任何其他用法都被视为反斜杠。因此,例如,\b不需要转义,大多数 Windows 路径如 "C:\foo\bar.h")不需要转义。

通过符号 支持简单变量替换,其中美元符号 支持简单变量替换,其中美元符号 支持简单变量替换,其中美元符号后面的单词被替换为变量的值。如果没有非变量名称字符来终止变量名称,则可以选择${}将名称括起来。不支持更复杂的表达式,仅支持变量名称替换。

cpp 复制代码
a = "mypath"
b = "$a/foo.cc"  # b -> "mypath/foo.cc"
c = "foo${a}bar.cc"  # c -> "foomypathbar.cc"

1.3 Lists列表

除了把非空列表赋值给空列表(a == [])之外,没有办法获得列表的长度。如果你发现自己想做这种事情,意味着在构建中做太多的工作。
ps:说的是,列表不提供获取长度,也不应该获取长度。

1.3.1 列表追加

列表支持追加,如下所示。将一个列表追加到另一个列表,会把每一个列表项追加为第二个列表中的项,而不是将该列表追加为嵌套成员。

cpp 复制代码
a = [ "first" ]
a += [ "second" ]  # [ "first", "second" ]
a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ]
b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ]
1.3.2 列表删除

还可以从列表中删除项目,如下。列表中的减号运算符"-"搜索匹配项并删除所有匹配项。从另一个列表中减去一个列表将删除第二个列表中的每个项目。如果未找到匹配的项目,则会引发错误,因此您需要在删除列表项之前,需要提前知道该列表项是否存在。

cpp 复制代码
a = [ "first", "second", "third", "first" ]
b = a - [ "first" ]  # [ "second", "third" ]
a -= [ "second" ]  # [ "first", "third", "first" ]

鉴于无法测试列表项的添加引入,可以这样使用:设置一个文件或标志的主列表,然后根据各种条件删除不适用于当前版本的文件或标志。--- 注:这算是推荐做法,维护一个主列表,然后只做减法,排除不适合的列表项。这个和下文的GYP提供的建议一样。这里读起来有些奇怪。

在风格上,更喜欢只添加到列表中,让每个源文件或依赖项出现一次。这与Chrome团队过去为GYP提供的建议相反(GYP更愿意列出所有文件,然后基于条件删除您不需要的文件)。

1.3.3 列表项获取

列表支持从零开始的下标来提取值:

cpp 复制代码
a = [ "first", "second", "third" ]
b = a[1]  # -> "second"

[] 运算符是只读的,不能用于改变列表。其主要使用场景是当外部脚本返回多个已知值,并且您想要提取它们时。

在某些情况下,覆盖一个列表比追加到一个列表更容易。为了帮助满足这种情况,将非空列表赋值给值为非空列表的变量,会产生错误。如果要绕过此限制,请首先将目标变量赋值给一个空列表。如下:

cpp 复制代码
a = [ "one" ]
a = [ "two" ]  # Error: overwriting nonempty list with a nonempty list.
a = []         # OK
a = [ "two" ]  # OK

1.4 Conditionals条件表达式

条件语句类似于 C语言,如下。可以在大多数情况下,使用条件语句。甚至可以把整个target目标放在条件里,如果这些target只在特定的条件下才需要声明。

cpp 复制代码
  if (is_linux || (is_win && target_cpu == "x86")) {
    sources -= [ "something.cc" ]
  } else if (...) {
    ...
  } else {
    ...
  }

1.5 Looping循环

您可以使用foreach循环访问列表。这是不鼓励的。构建应该做的大多数事情通常都可以在不这样做的情况下来完成,如果你觉得有必要,这可能表明你在元构建中做了太多的工作。

cpp 复制代码
foreach(i, mylist) {
  print(i)  # Note: i is a copy of each element, not a reference to it.
}

1.6 Function calls函数调用

简单的函数调用看起来像大多数其他语言:

cpp 复制代码
print("hello, world")
assert(is_win, "This should only be executed on Windows")

这些函数是内置的,用户无法定义新的函数。一些函数采用以下代码块括起来:{ }

cpp 复制代码
static_library("mylibrary") {
  sources = [ "a.cc" ]
}

大多数函数定义了目标target。用户可以使用下面讨论的template模板机制定义这样的新功能。

准确地说,上面说的代码块{}作为函数参数来执行函数的。大多数块样式的函数执行代码块,并将生成的作用域做为供读取的变量字典。

1.7 Scoping and execution作用域与执行

文件和函数调用后面跟的{}块引入新的作用域。作用域是嵌套的。读取变量时,将按相反的顺序搜索包含作用域,直到找到匹配的名称。变量写入始终转到最内层的作用域。

除了最里面的作用域之外,无法修改任何封闭作用域。这意味着,例如,当您定义target目标时,您在块内执行的任何操作都不会"泄漏"到文件的其余部分。

每个文件在内部都表示为一个域,并且没有全局域。共享"全局域"可以定义在 .gni 文件中,并在它们被使用的地方导入(import("//path/to/something.gni"))。每个 .gni 文件在每个工具链(toolchain)中处理一次(见下以获取关于工具链的信息),然后结果域被复制到导入文件的域中。

目标的声明引入了一个子域:

cpp 复制代码
foo = true
executable("target") {
  foo = 12
}
# 目标之外,foo == true

当一个变量在域中被定义而未被使用时,GN 对于错误的诊断非常严格。目标内部的作用域就像目标的关键字参数列表一样,它检查参数名称是否正确拼写。如果必需的参数被忽略,那么目标定义代码也可以使用" assert()"来诊断错误。

一个值可以是一个域。那么当你使用它的时候,它就如同一个结构体:value.member。但是域总是一个 GN 代码块,它的执行用来产生其名称和值的集合:

cpp 复制代码
foo = {
  x = global_tuning + 42
  If (some_global && other_thing == "foobar") {
    y = 2
  }
}

这总是会定义 foo.x ,但仅有时会定义 foo.y。


二. GN源路径和GN标签

GN 使用 POSIX 风格路径(path)(总以字符串表示),它们既用于文件,也用于提及 GN 定义的实体。路径可以是相对的,即路径的表示是相对于包含 BUILD.gn 文件目录的。他们也可以是"绝对于源的(source-absolute)",即相对于源工作区。绝对于源的路径在 GN 中以 // 开头。

当最终在命令中使用源路径时,它们会转换为对应于操作系统的(OS-appropriate)路径,这些路径是绝对的或相对于构建目录(运行命令的位置)的路径。

GN源路径有三种可能形式:

  • 相对名称:
cpp 复制代码
"foo.cc"
"src/foo.cc"
"../src/foo.cc"
  • 源树绝对名称:
cpp 复制代码
"//net/foo.cc"
"//base/test/foo.cc"
  • 系统绝对名称(罕见,通常用于包含目录):
cpp 复制代码
"/usr/local/include/"
"/C:/Program Files/Windows Kits/Include"

2.1 GN标签

GN 标签是我们引用在 BUILD.gn 文件中定义的内容的方式。它们基于源路径,并且总是出现在 GN 字符串之内。GN 标签的完整语法是 "dir:name",其中 dir 部分是命名了特定 BUILD.gn 文件的源路径。name 指在该文件中使用 target_type("name") { ... } 定义的目标。简而言之,您可以定义一个名称与其所在目录名称相同的目标。无 : 部分的标签 "//path/to/dir" 是 "//path/to/dir:dir" 的略写。这是最常见的情况。常见形如:

cpp 复制代码
import("//build/ohos.gni")

print("xxxx_group in")
group("xxxx_group") {
  deps = [
    "cfg:init_configs",
    "distributedhardware:distributedhardware",
    "kernel:build_kernel",
    "//device/soc/xxxx/xxxx/hardware:hardware_group",
    "//device/board/xxxx/xxxx/window_cfg:window_config",
  ]
}

三. GN Build configuration构建配置

GN的最初开发的目的是为了替换CMAKE,用来构建各种模块。而构建肯定离不来各种配置构建选项!下面让我一一道来!

3.1 Targets目标

一个目标target是构建图中的一个节点。它通常表示将生成的某种可执行文件或库文件。目标依赖于其他目标。内置目标类型如下所示。可以使用命令gn help 以获取更多帮助。可以使用模板创建自定义目标类型,来扩充内置的目标类型。

  • action:运行脚本以生成文件。
  • action_foreach:为每个源文件运行一次脚本。
  • bundle_data:声明数据以进入 Mac/iOS 捆绑包。
  • create_bundle:创建苹果/iOS 捆绑包。
  • executable:生成可执行文件。
  • group:引用一个或多个其他目标的虚拟依赖关系节点。
  • shared_library:共享库.dll或 .so。
  • loadable_module:仅在运行时可加载.dll或 .so。
  • source_set:轻量级虚拟静态库(通常比真正的静态库更可取,因为它的构建速度更快)。
  • static_library:.lib 或 .a 文件(通常可以使用一个source_set替代)。

写在最后

好了今天的博客OpenHarmony下GN语法普法就到这里了。总之,青山不改绿水长流先到这里了。如果本博客对你有所帮助,麻烦关注或者点个赞,如果觉得很烂也可以踩一脚!谢谢各位了!!

1.GN 介绍
2.gn语法与操作学习

相关推荐
Industio_触觉智能1 天前
如何在开源鸿蒙OpenHarmony开启SELinux模式?RK3566鸿蒙开发板演示
openharmony·selinux·开源鸿蒙·鸿蒙开发板·rk3566开发板
xiaolaoshuXD6 天前
深入解析 OpenHarmony 构建系统-4-OHOSLoader类
编译·openharmony·build·构建·hb
雪域迷影6 天前
OpenHarmony的公共事件
openharmony·ces公共事件·资源调度服务
伊二7 天前
鸿蒙next ui安全区域适配(刘海屏、摄像头挖空等)
华为·harmonyos·鸿蒙·openharmony·团结引擎·huamony next
Industio_触觉智能15 天前
OpenHarmony4.1蓝牙芯片如何适配?触觉智能RK3568主板SBC3568演示
openharmony·rk3568·开源鸿蒙·鸿蒙开发板·触觉智能
ssslar16 天前
Harmony OS 如何实现 C++ NATIVE YUV420(其他数据格式如BGRA等)自渲染
华为·harmonyos·鸿蒙·openharmony
Industio_触觉智能19 天前
【鸿蒙新闻】10月29日警用鸿蒙开发者大会在北京胜利召开,开启智慧应用新时代!
鸿蒙系统·openharmony·开源鸿蒙·纯血鸿蒙·警用鸿蒙
Industio_触觉智能1 个月前
触觉智能Purple Pi OH鸿蒙开发板成功适配OpenHarmony5.0 Release,开启新征程!
harmonyos·openharmony·开源鸿蒙·鸿蒙开发板·触觉智能·原生鸿蒙
码匠许师傅1 个月前
【开源鸿蒙】OpenHarmony 5.0轻量系统最小开发环境搭建
python·pip·risc-v·openharmony·gcc·1024程序员节·hi3861
SuperHeroWu71 个月前
【HarmonyOS】鸿蒙目前最好用的路由管理 HMRouter (一)
华为·harmonyos·openharmony·路由管理·hmrouter·回退栈