谷歌gn编译文件的使用简介

Gn是什么?

它是Google用来维护chromium项目的编译工具,现在相关的开源项目都基于gn来进行编译管理。目前一些大型系统的都会使用gn,例如谷歌,鸿蒙。

Gn就是一个构建脚本生成器,是之前gyp的升级版本。

并且gn是基于c++编写,效率要比基于python的gyp快了近20倍。

图片

更多技术文章,全网首发公众号“摸鱼IT”,希望大家关注、转发、点赞!谷歌gn编译文件的使用简介

官网文档参考:https://gn.googlesource.com/gn/+/master/docs

参考文档:鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用 | 百篇博客分析OpenHarmony源码 | v60.02 - 掘金

GN文件的作用 

对于一套编译工具,要将源代码编译成最终可以执行文件,需要三个部分构件系统:GN、Ninja、GCC(这里也可以是其他的编译器)

GN作为编译逻辑部分。通过gn会将整个项目串联在一起,生成build.ninja文件。

Ninja作为构建中间部分,用最简单最快速的方式将编译文件编译参数传递给编译系统,由Ninja负责执行编译过程。

GCC作为编译部分,通常随编译系统而变化。

接下来介绍gn文件中几个重要的部分和语法:

引用 | Import 

.gn是源文件;.gni是头文件,类似C++中的头文件.h 通过import进行引用

import("//build/lite/config/hap_pack.gni")

目标项 | Targets 

目标是构建图中的一个节点。它通常表示将生成某种可执行文件或库文件。整个构建是由一个个的目标组成。

以下是一些常使用的内置目标:

action:运行一个脚本产生一个文件

executable:生成可执行文件

shared_library:动态库,一个.dll或.so

static_library:静态库,一个.lib文件或者.a

app:可执行程序

android_apk:生成一个APK

shared_library("cameraApp") #生成一个cameraApp的动态库

配置项 | Configs 

记录完成目标项所需的配置信息, 配置信息可以包括flags,defines,include_dirs等,但是不包括sources和deps/public_deps等依赖性文件。例如:

configs = [
    ":config_json_creator_test",
    "$ace_root:ace_test_config",
]

源文件 | Sources 

这个标签的意思是列出来需要编译的源文件,当然,可以在其中使用条件语句进行条件编译。

sources = [ #需要编译的源码
    "cameraApp/src/main/cpp/camera_ability.cpp",
    "cameraApp/src/main/cpp/camera_ability_slice.cpp",
    "cameraApp/src/main/cpp/camera_manager.cpp",
 ]

依赖项 | Deps 

即编译Targets所用到的依赖,依赖应按字母顺序排列。

当前文件中的 Deps 应首先写入,并且不能使用文件名限定。

其他 deps 应始终使用完全限定的路径名,除非出于某种原因需要相对路径名。​​​​​​

deps = [
    "${aafwk_lite_path}/frameworks/ability_lite:aafwk_abilitykit_lite",
    "${appexecfwk_lite_path}/frameworks/bundle_lite:bundle",
    "//foundation/distributeddatamgr/kv_store/interfaces/inner_api/kv_store:kv_store",
    "//foundation/graphic/surface",
    "//foundation/graphic/ui:lite_ui",
    "//foundation/graphic/utils:lite_graphic_utils",
    "//foundation/multimedia/camera_lite/frameworks:camera_lite",
    "//foundation/multimedia/media_lite/frameworks/recorder_lite:recorder_lite",
    "//foundation/systemabilitymgr/samgr_lite/samgr:samgr",
]

替换 $ 

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

a = "moyupath"
b = "$a/king.cc"   #b -> "moyupath/king.cc"
c = "king${a}bar.cc"  #c -> "kingmoyupathbar.cc"

清单 [ ] 

没有办法得到一个列表的长度。如果你发现自己想要做这种事情,那么你就是想在构建中做太多的工作。

列表支持追加:​​​​​​

a = [ "first" ]
a += [ "second" ]  # [ "first", "second" ]
a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ]
b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ]
a = [ "first" ]a += [ "second" ]  # [ "first", "second" ]a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ]b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ]

代码示例

#目的是要得到项目各个模块的编译入口

group("ohos") {

  deps = []

  if (ohos_build_target == "") {

    # Step 1: Read product configuration profile.

    # 第一步:读取配置文件product_path的值来源于根目录的ohos_config.json,如下,内容由 hb set 命令生成

    # {

    #  "root_path": "/home/openharmony",

    #  "board": "hispark_aries",

    #  "kernel": "liteos_a",

    #  "product": "ipcamera_hispark_aries",

    #  "product_path": "/home/openharmony/vendor/hisilicon/hispark_aries",

    #  "device_path": "/home/openharmony/device/hisilicon/hispark_aries/sdk_liteos",

    #  "patch_cache": null

    #}

    product_cfg = read_file("${product_path}/config.json", "json")



    # Step 2: Loop subsystems configured by product.

    # 第二步:循环处理各自子系统,config.json中子系统部分格式如下hb

    #"subsystems": [

    #  {

    #    "subsystem": "aafwk",

    #    "components": [

    #      { "component": "ability", "features":[ "enable_ohos_appexecfwk_feature_ability = false" ] }

    #    ]

    #  },

    #  ...

    #  {

    #    "subsystem": "distributed_schedule",

    #    "components": [

    #    { "component": "system_ability_manager", "features":[] },

    #    { "component": "foundation", "features":[] },

    #    { "component": "distributed_schedule", "features":[] }

    #    ]

    #  },

    #  {

    #      "subsystem": "kernel",

    #      "components": [

    #        { "component": "liteos_a", "features":[] }

    #      ]

    #   },

    #]

    foreach(product_configed_subsystem, product_cfg.subsystems) {#对子系统数组遍历操作

      subsystem_name = product_configed_subsystem.subsystem    #读取一个子系统 aafwk,hiviewdfx,security ==

      subsystem_info = {

      }



      # Step 3: Read OS subsystems profile.

           # 第三步: 读取各个子系统的配置文件

      subsystem_info =

          read_file("//build/lite/components/${subsystem_name}.json", "json")



      # Step 4: Loop components configured by product.

      # 第四步: 循环读取子系统内各控件的配置信息

      # 此处以内核为例://build/lite/components/kernel.json"

      # "components": [

      #   {

      #     "component": "liteos_a",              # 组件名称

      #     "description": "liteos-a kernel",     # 组件一句话功能描述

      #     "optional": "false",                  # 组件是否为最小系统必选

      #     "dirs": [                             # 组件源码路径

      #       "kernel/liteos_a"

      #     ],

      #     "targets": [                          # 组件编译入口

      #       "//kernel/liteos_a:kernel"

      #     ],

      #     "rom": "1.98MB",                      # 组件ROM值

      #     "ram": "",                            # 组件RAM估值

      #     "output": [                           # 组件编译输出

      #       "liteos.bin"

      #     ],

      #     "adapted_board": [                    # 组件已适配的主板

      #       "hispark_aries",

      #       "hispark_taurus",

      #       "hi3518ev300",

      #          "hi3516dv300",

      #     ],

      #     "adapted_kernel": [ "liteos_a" ],     # 组件已适配的内核

      #     "features": [],                       # 组件可配置的特性

      #     "deps": {

      #       "components": [],                   # 组件依赖的其他组件

      #       "third_party": [                    # 组件依赖的三方开源软件

      #         "FreeBSD",

      #         "musl",

      #         "zlib",

      #         "FatFs",

      #         "Linux_Kernel",

      #         "lwip",

      #         "NuttX",

      #         "mtd-utils"

      #       ]

      #     }

      #   },

      # ]

      foreach(product_configed_component,

              product_configed_subsystem.components) { #遍历项目控件数组

        # Step 5: Check whether the component configured by product is exist.

                  # 第五步: 检查控件配置信息是否存在

        component_found = false #初始为不存在

        foreach(system_component, subsystem_info.components) {#项目控件和子系统中的控件遍历对比

          if (product_configed_component.component ==

              system_component.component) { #找到了liteos_a

            component_found = true

          }

        }

                  #如果没找到的信息,则打印项目控件查找失败日志

        assert(

            component_found,

            "Component \"${product_configed_component.component}\" not found" +

                ", please check your product configuration.")

             

        # Step 6: Loop OS components and check validity of product configuration.

              # 第六步: 检查子系统控件的有效性并遍历控件组,处理各个控件

        foreach(component, subsystem_info.components) {

          kernel_valid = false   #检查内核

          board_valid = false   #检查开发板



          # Step 6.1: Skip component which not configured by product.

          if (component.component == product_configed_component.component) {

            # Step 6.1.1: Loop OS components adapted kernel type.

            foreach(component_adapted_kernel, component.adapted_kernel) {

              if (component_adapted_kernel == product_cfg.kernel_type &&

                  kernel_valid == false) { #内核检测是否已适配

                kernel_valid = true

              }

            }

                     # 如果内核未适配,则打印未适配日志

            assert(

                kernel_valid,

                "Invalid component configed, ${subsystem_name}:${product_configed_component.component} " + "not available for kernel: ${product_cfg.kernel_type}!")



            # Step 6.1.2: Add valid component for compiling.

                     # 添加有效组件进行编译

            foreach(component_target, component.targets) {//遍历组件的编译入口

              deps += [ component_target ] #添加到编译列表中

            }

          }

        }

      }

    }



    # Step 7: Add device and product target by default.

    # 第七步: 添加设备和项目的编译单元

    # "product_path": "/home/openharmony/vendor/hisilicon/hispark_aries",

    # "device_path": "/home/openharmony/device/hisilicon/hispark_aries/sdk_liteos",

      deps += [

      "${device_path}/../", #添加 //device/hisilicon/hispark_aries 进入编译项

      "${product_path}"            #添加 //vendor/hisilicon/hispark_aries 进入编译项

    ]

  } else {#编译指定的组件,例如 hb build -T targetA&&targetB

    deps += string_split(ohos_build_target, "&&")

  }

}

openharmony\applications\sample\camera\cameraApp下BUILD.gn文件:

import("//build/lite/config/hap_pack.gni")



#编的库名称

shared_library("cameraApp") {

  sources = [ #需要编译的源码

    "cameraApp/src/main/cpp/camera_ability.cpp",

    "cameraApp/src/main/cpp/camera_ability_slice.cpp",

    "cameraApp/src/main/cpp/camera_manager.cpp",

  ]



  deps = [#引用三方组件库

    "${aafwk_lite_path}/frameworks/ability_lite:aafwk_abilitykit_lite",

    "${appexecfwk_lite_path}/frameworks/bundle_lite:bundle",

    "//foundation/distributeddatamgr/kv_store/interfaces/inner_api/kv_store:kv_store",

    "//foundation/graphic/surface",

    "//foundation/graphic/ui:lite_ui",

    "//foundation/graphic/utils:lite_graphic_utils",

    "//foundation/multimedia/camera_lite/frameworks:camera_lite",

    "//foundation/multimedia/media_lite/frameworks/recorder_lite:recorder_lite",

    "//foundation/systemabilitymgr/samgr_lite/samgr:samgr",

  ]



  include_dirs = [#需要的头文件

    "cameraApp/src/main/cpp",

    "${aafwk_lite_path}/interfaces/kits/ability_lite",

    "${appexecfwk_lite_path}/interfaces/kits/bundle_lite",

    "${aafwk_lite_path}/interfaces/kits/want_lite",

    "//foundation/multimedia/camera_lite/interfaces/kits",

    "//foundation/multimedia/camera_lite/interfaces/kits",

  ]

  ldflags = [

    "-L$ohos_root_path/sysroot/usr/lib",

    "-Wl,-rpath-link=$ohos_root_path/sysroot/usr/lib",

    "-lstdc++",

    "-lcamera_lite",

    "-lsurface",

    "-lrecorder_lite",

  ]

  defines = [

    "ENABLE_WINDOW=1",

    "ABILITY_WINDOW_SUPPORT",

  ]

}



hap_pack("cameraApp_hap") {

  deps = [ ":cameraApp" ]

  mode = "hap"

  json_path = "cameraApp/src/main/config.json"

  ability_so_path = "$root_out_dir/libcameraApp.so"

  force = "true"

  cert_profile = "cert/camera_AppProvision_Release.p7b"

  resources_path = "cameraApp/src/main/resources"

  hap_name = "cameraApp"

  privatekey = "HOS Application Provision Release"

}

如上就简单介绍了gn文件的基本使用方法,小伙伴们快快学习使用起来!

猜你喜欢

转载自blog.csdn.net/qrx941017/article/details/132907603