资讯详情

鸿蒙源码构建工具Gn 与 Ninja 的介绍及使用入门

以前只听说过和用过嵌入式makefile和make编译命令。

最近鸿蒙HarmonyOS该系统的流行对其源代码的编译构建感兴趣,并了解到鸿蒙系统的编译构建是基于 Gn 和 Ninja 完成的。

那么什么是Gn 与 Ninja?比makefile强到哪了?

尝试了一下,被这个速度惊呆了!

为什么要用它?总结两点:1。与写作相比makefile省事,2.比make编译速度不止一点。

简单来说Gn有点类似cmake或automake辅助生成等makefile脚本的东东相当于构建脚本的命令。Ninja相当于构建指令,功能类似make命令。解释可能不准确,但可能更容易理解。

Ninja 是借由 Google Chrome 一种建筑工具诞生于项目,其目标是速度。换句话说,在 Google Chrome 在项目开发过程中,开发人员认为同类型的其他施工工具并不强大,所以他们会考虑重新开发更高效的工具。

官方介绍:https://ninja-build.org/

老大哥老古董类似于同类型的建筑界make ,make 即 GNU Make,一个程序用于决定如何使用命令来构建最终目标。make 有3 个特性:

make 只是一个通用程序,不知道如何具体完成目标建设。 make 需要 makefile 描述决定目标构建的具体方案。 make 需要借助其它工具(如:gcc)实施计划,最终完成工作。

Ninja 可以看作是更好更快的 make 。

GN是一个生成Ninja构建文件元构建系统,使您能够使用它Ninja构建你的项目。

gn、ninja安装,使用环境Ubuntu18.04,参见:https://blog.csdn.net/qiuguolu1108/article/details/103842556

如果编译安装麻烦,可以直接复制二进制文件gin和ninja到系统的/usr/bin使用文件夹。

gin和ninja二进制可执行文件,上述链接有说明。

以helloworld例如,建一个gn-test文件夹:

几个文件是必不可少的,需要手动按格式提前创建。否则,将直接执行gn gen ./out会报错的。

前提是必须有几个文件和文件夹。

必要的文件: .gn文件 根目录下的BUIlD.gn文件 gnconfig文件夹中的BUILDCONFIG.gn文件

可输入指令:

gn help dotfile

查看默认的.gin文件模板。

我的例子.gin文件如下:

buildconfig="//gnconfig/BUILDCONFIG.gn" 

然后在项目的根目录下创建gnconfig文件夹和内部BUILDCONFIG.gn文件。

我的BUILDCONFIG.gn文件内容如下:

set_default_toolchain("//gnconfig/toolchain:gcc")  cflags_cc = [ "-std=c  11" ]

你可以看到里面有一些指定的东西,所以你必须gnconfig在文件夹下放点东西。

在gnconfig创建文件夹toolchain再放一个文件夹BUILD.gn文件,内容很复杂,可以先复制原件:

# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.   toolchain("gcc") {   tool("cc") {     depfile = "{     
      {output}}.d"     command = "gcc -MMD -MF $depfile {     
      {defines}} {     
      {include_dirs}} {     
      {cflags}} {     
      {cflags_c}} -c {     
      {source}} -o {     
      {output}}"     depsformat = "gcc"     description = "CC {     
      {output}}"     outputs = [       "{     
      {source_out_dir}}/{     
      {target_output_name}}.{     
      {source_name_part}}.o",     ]   }     tool("cxx") {     depfile = "{     
      {output}}.d"     command = "g   -MMD -MF $depfile {     
      {defines}} {     
      {include_dirs}} {     
      {cflags}} {     
      {cflags_cc}} -c {     
      {source}} -o {     
      {output}}"     depsformat = "gcc"     description = "CXX {     
      {output}}"     outputs = [       "{     
      {source_out_dir}}/{     
      {target_output_name}}.{     
      {source_name_part}}.o",     ]   }     tool("alink") {     rspfile = "{     
      {output}}.rsp"     command = "rm -f {     
      {output}} && ar rcs {     
      {output}} @$rspfile"     description = "AR {     
      {target_output_name}}{     
      {output_extension}}"     rspfile_content = "{     
      {inputs}}"     outputs = [       "{     
      {target_out_dir}}/{     
      {target_output_name}}{     
      {output_extension}}",     ]     default_output_extension = ".a"     output_prefix = "lib"   }     tool("solink") {     soname = "{     
      {target_output_name}}{     
      {output_extension}}"  # e.g. "libfoo.so".     sofile = "{     
      {output_dir}}/$soname"     rspfile = soname   ".rsp"       command = "g   -shared {     
      {ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile"     rspfile_content = "-Wl,--whole-archive {     
      {inputs}} {     
      {solibs}} -Wl,--no-whole-archive {     
      {libs}}"       description = "SOLINK $soname"       # Use this for {     
      {output_extension}} expansions unless a target manually     # overrides it (in which case {     
      {output_extension}} will be what the target     # specifies).     default_output_extension = ".so"       # Use this for {     
      {output_dir}} expansions unless a target manually overrides     # it (in which case {     
      {output_dir}} will be what the target specifies).     default_output_dir = "{     
      {root_out_dir}}"       outputs = [       sofile,     ]     link_output = sofile     depend_output = sofile     output_prefix = "lib"   }     tool("link") {     outfile = "{     
      {target_output_name}}{     
      {output_extension}}"     rspfile = "$outfile.rsp"     command = "g   {     
      {ldflags}} -o $outfile @$rspfile {     
      {solibs}} {     
      {libs}}"     description = "LINK $outfile"     default_output_dir = "{    
      {root_out_dir}}"
    rspfile_content = "{
    
      {inputs}}"
    outputs = [
      outfile,
    ]
  }
 
  tool("stamp") {
    command = "touch {
    
      {output}}"
    description = "STAMP {
    
      {output}}"
  }
 
  tool("copy") {
    command = "cp -af {
    
      {source}} {
    
      {output}}"
    description = "COPY {
    
      {source}} {
    
      {output}}"
  }
}

 主要是.gn文件和gnconfig中的buildconfig这两项创建好后,基本保持不动,剩下的就是跟编译具体项目相关了。

如我的这个入门hellowold例子,跟目录下创建BUILD.gn文件,内容如下:

group("default"){
    deps = [
       "//src:hello",
    ]
}

在src目录里,创建BUILD.gn文件,内容如下:

executable("hello") {
    sources = [
        "test.c",
    ]
}

至此,总算是构建脚本整完了,感觉挺繁琐的。但是如果熟悉了,大概就是这套路吧。最后当你看到它惊人的构建速度时,就会觉得这一切都是值得的。

接下来就是敲命令啦:

项目根目录下执行 gn gen ./out

打开查看产生了如下内容:

最后生成可执行文件吧:

速度快的不到1秒就构建结束了。 

 查看下执行结果:

// test.c

#include <stdio.h>
#include "test.h"

int main()
{
    printf("Hello Ninja!\n");
    printf("CONST = %d\n", CONST);
    return 0;
}

标签: gn丝印三极管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台