Chromium GN入门学习(本文参考于谷歌Brett Wilson PPT学习资料及谷歌官网文档)

GN原文档(英文)

以前chromium采用的是GYP构建系统,最新的版本已经使用GN构建系统。

 GN的优点反正就是编译速度快,GYP比makefile快,GN比GYP快20倍(据说是),而且书写不再那么复杂难懂。所以如果你的代码很庞大,那么GN + ninja是个不错的搭配选择。我现在也是在搭建这样的编译环境。

也参考了别人的一些学习笔记,总之也是有收获的,要想融会贯通,还是需要自己学习不同人的长处,并且自己去实践。我也是刚入皮毛,有不对之处还望指出。

我的排版一向都很糟糕,不会排。 反正现在开始进入正题了。

--------------------------------------------------------------------------------

1. 获取GN代码,自己编译GN命令(本人linux用户)。

   git clone https://gn.googlesource.com/gn

   这些命令在你克隆完代码后到gn目录下面,打开README.md文件可以找到

    cd gn

    python build/gen.py

    ninja -C out

2. 编译完成后,到out目录下面可以看到已经生成gn可执行文件。

     然后你可以将gn拷贝到/usr/sbin下面,这样你在任何地方都可以直接执行gn命令,类似于ls等系统命令。

3. gn gen —— 根据GN规则生成ninja文件

    gn gen out —— out目录如果第一次时不存在, 执行完这条命令之后就会生成一个out目录,你也可以把out换成别的名字,out目录下面会有buid.ninja等几个文件。

  3.1 注意

        首先你要有".gn"文件,切记文件的全名就是 ".gn" ,这个文件是必须要有的,不然就会报错,因为它里面指定了                       buildconfig的值,假如你的源文件在src下面,那么你的src下面也应该有个.gn文件。(是否可以有多个.gn还未测试)

         其次,获取到的gn源码中有.gn文件,自己可以看看。

 3.2 BUILDCONFIG.gn

        这文件配置了一些默认的配置,还有使用的toolchain工具链。这个文件中的配置是全局的。

        当你编译的时候首先就会去找.gn文件,然后找到BUILDCONFIG.gn,再根据这个文件找到toolchain,

        有了toolchain就开始编译了,那么首先要找target, 入口就是和.gn同级目录下面的BUILD.gn文件。所以

        在你的.gn下面一定要有BUILD.gn文件。当你这些文件都固定之后,无论你在哪个路径下执行gn gen命令,

       生成的ninja文件内容都是一样的。因为你的target存在于BUILD.gn文件,而这些文件里面的配置没有变,所以即使

       你在src/server下面去执行gn gen out,那么你得到的东西和在src下面执行是完全一样的。(不好意思,一句话喜欢                      反复说,很罗嗦的我) 

3.3 两个斜杠 "//" 路径到底是什么 ?

      你看一些学习文档会发现它们都有提到一个源树绝对路径"//", 知道linux的都了解一个 "/"表示的是系统的根路径,

      在gn中,一个"/"也是代表了系统根路径,但两个斜杠"//"显然不是系统的根路径了。

      其实, "//" 表示的是.gn所在的路径,假如你的.gn 在src下面, 那么"//"就表示的是 src路径,因此,假如src下                               面有server目录,表示方法就是"//server"。

4. target 有哪些类型 ?

    在GN中,它表示你要编译什么文件出来,比如executable(可执行文件),static_library(静态库),shared_library(动态                   库),... ...

executable, shared_library, static_library

loadable_module: 运行时加载模块

source_set: 被编译的源文件集合,这种编译不会生成任何库文件

group: 声明一组target,你可以写一个group,里面放不同的库target,使用的时候就用group的名字代表这些targets

copy: 拷贝文件

action, action _foreach: 运行一个脚本时所用

bundle_data, create_bundle: Mac & iOS

component: shared library or source set depending on mode

test

app: executable or iOS application + bundle

android_apk, generate_jni, etc.: Lots of Android ones!

5. 条件及表达式

              语法类似C/C++, 比如判断语句: if() { }

              component() {

                sources = [

                  "a.cc",

                  "b.cc",

               ]

               if(is_win || is_linux) {

                  sources += ["win_helprt.cc"]

               } else {

                  sources -= ["a.cc"]

               }

              }

      6. 编译配置

                常用到的:

           6.1 flag标志

                cflags —— 会传递给C/C++/Object C/Object C++的编译器

                如果想只传给某一个编译器的话,使用下面的:

                cflags_c —— 跟在cflags后面,传递给C代码编译器

                cflags_cc —— 跟在cflags后面,传递给C++代码编译器

                cflags_objc —— 跟在cflags后面,传递给Object C代码编译器

                cflags_objcc —— 跟在cflags后面,传递给Object C++代码编译器

                ldflags —— 传递给链接器的参数,大部分target用不到这个,一般使用libs和lib_dirs

         6.2 target依赖关系

                 deps —— 私有链接依赖

                 public_deps —— 公有链接依赖

                 先比较上面两个, deps私有的,也就是无法继承依赖,A -> B -> C(A依赖B,B依赖C),

                 假设C里面有个头文件c.h, 那么B可以 #include "c.h" , 但是 A不行。

                 但如果是public_deps,那么A也可以像B一样 #include "c.h" 。

                 也就是是否可以越级传递关系。(我是这样理解的,比那些一大堆抽象的东西容易明白,如果B里面声明为public,那                     么 A应该也是可以使用, 请参考C++类的继承吧,需要验证哈,我不确定,只是看到文档有这样写)

                像这样的组合还有configs/public_configs

 

                data —— Runtime data file dependencies (没搞懂这个,直接从文档粘过来了)

                data_deps —— 运行时依赖,比如plugin,这些库可能编译时是没有的, 也许是第三方提供的, 那么在没有的时候

               需要编译通过,而在运行时只要有这个库就可以了,这样的库就设置在这里,等运行时使用。

        6.3 include_dirs/libs/lib_dirs

                 include_dirs —— target所要使用的头文件所在路径

                 libs —— target需要依赖的第三方库,参考下 "-l"的作用

                 lib_dirs —— target需要依赖的第三方库的路径,参考 "-L"的作用

       6.4 defines 

                 定义变量的,也就是类似于C/C++定义宏开关。 你想在对哪个target生效,你可以在相应的target里面定义。例如:

                executable("testgn") {

                    sources = [

                      "testgn.cpp",

                    ]

                    defines = ["FOR_TEST=true"]

                }

                那么你就可以在testgn.cpp中使用该宏。如果定义多个呢?

                defines = [

                  "FOR_TEST=true",

                  "FOR_TESTGN=true",

                  ... 

                ]

                以此类推放进去。

        6.5 visibility —— 对哪些targets可见(默认是public)

               visibility = [":*"]     —— 表示私有的,本target只能被本文件中的target所使用依赖

               visibility = [ "*" ]    —— 表示公有的,任何target都可以使用依赖本target

               visibility = [ "./*" ]  —— 当前目录及子目录下的target都可以依赖

               visibility = [ "//server:*" ] —— 表示只有//server/BUILD.gn文件中的target可以使用依赖本target

               visibility = [ "//server/*" ] —— 表示server或者子目录下的target可以使用依赖本target

               visibility = [ ]  —— 用于叶子节点(这个不是很懂现在,感觉是不让别人依赖了)

     7. action/template/copy/defined/declare_args

         7.1 action

                      运行python脚本来完成任务。                     

action(“myaction”) {
  script = “myscript.py”
  inputs = [ “myfile.txt” ]
  outputs = [
    “generated.txt”,  # Error!
  ]
}

                      GN不允许写到源树绝对路径下面,也就是你不能输出到 // 下面, 对于输出路径我们一般都选择在 $target_out_dir                         或者$target_gen_dir下面,因此上面可以这样改写: 

action(“myaction”) {
  script = “myscript.py”
  inputs = [ “myfile.txt” ]
  outputs = [
    target_out_dir + “/output.txt”,
  ]
  print(outputs)
}
或者
action(“myaction”) {
  script = “myscript.py”
  inputs = [ “myfile.txt” ]
  outputs = [
    “$target_out_dir/output.txt”,
  ]
  print(“out = $outputs”)
}

                     注意下区别,上面的target_out_dir没有$符号,且与后面的字符串用的是“+”连接;

                     下面的有 $符号,且类似于linux shell的变量用法。 

                      target_out_dir/target_gen_dir是可以直接使用的, 不是你自己定义的变量,应该是GN定义的。 

用法1:
action(“myaction”) {
  script = “myscript.py”
  inputs = [ “myfile.txt” ]
  outputs = [
    “$target_out_dir/output.txt”,
  ]
  args = [
    “-i”, inputs[0], outputs[0],
  ]
}
用法2:
action(“myaction”) {
  script = “myscript.py”
  inputs = [ “myfile.txt” ]
  outputs = [
    “$target_out_dir/output.txt”,
  ]
  args = [
    “-i”,
    rebase_path(inputs[0],
                root_build_dir)
    rebase_path(outputs[0],
                root_build_dir)
  ]
}

                     首先,想给脚本传递参数必须使用args。

                     然而用法1中虽然使用了args,但是传递进去的参数有错误。GN默认的是"//"路径。

                     python无法识别GN的风格,所以需要将"//"进行转化,用到rebase_path,其中root_build_dir就是"//out"路径。                     

         7.2 template

                      模板是可以被重复使用的,所以一般会写在gni文件中,这样只要gn文件导入后就可以使用了。

                      具体用法可看执行命令 gn help template

         7.3 copy —— 声明一个拷贝文件的target

                   所有文件的输出都在编译时指定的输出文件目录下面。(gn gen out, 则所有的输出文件都在out下面)

                   通常我们会用到$target_out_dir和$target_gen_dir目录

                   target_out_dir —— 指定你当前BUILD.gn所在路径,前缀是//out/obj

                   target_gen_dir —— 指定你当前BUILD.gn所在路径,前缀是//out/gen

                    假如当前编译的target为//server:server, 那么当前BUILD.gn目录就是server。

                   则 target_out_dir => //out/obj/server 

                        target_gen_dir => //out/gen/server

         7.4 defined

                       返回一个标识是否有定义过,通常在template中使用。可以检查一个标识的作用域。

                       例如:

                        defined(foo)  —— 检查foo是否在当前的作用域内被定义

                        defined(foo.bar) —— 检查bar是否在作用域foo中被定义

                        

         7.5 declare_args —— 声明编译时的参数

                      比如下面写的定义变量或者常量,在编译期间会传递给别的*.gn或者*.gni文件使用。

                       可参考 gn help buildargs

     8. import

                import —— 导入*.gni文件, *.gni文件可以定义共用的变量或者常量,如:

                declare_args() {

                  is_chrome_branded = false

                }

                enable_crashing = is_win

               然后在BUILD.gn文件中import即可使用is_chrome_branded/enbable_crashing

     9. gn help

                如果你想查看gn支持哪些命令,可以直接运行 gn help 。

                如果想查看命令或者函数或者参数的具体用法,那么就gn help <命令|函数|参数>。

                例如:

                 查看lib_dirs详解:  gn help lib_dirs

     10. configs

                 包括flags,defines,include_dirs等,但是不包括sources和deps/public_deps等依赖性文件

  • 9
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值