Node基于 GYP(Generate Your Projects)构建C\C++插件,在编译插件前需要编写一个.gyp配置文件,该文件相当于Node的 package.json 文件。

介绍

GYP(Generate Your Projects)是一个跨平台自动化项目构建工具,其由 Google 团队开发用于生成Chromium Web浏览器的原生IDE的项目文件。

node-gyp 是一个用 Node.js 编写的跨平台命令行工具,用于为 Node.js 编译本机插件模块。它包含 Chromium 团队以前使用的 gyp-next 项目的供应商副本,扩展以支持 Node.js 原生插件的开发。

流程

在通过node-gyp执行构建项目资源时,可以分解成两部分:

  1. 命令执行
  2. 执行配置文件

命令执行即通过node-gyp命令行工具,执行对于项目的配置文件,包含最基础的输出文件名称,配置各个平台的源文件,配置平台特有的编译器等信息。

node-gyp commands

通过node-gyp命令行工具,我们可以通过此构建node addon插件,和资源的清理、配置等操作,常用的命令有如下:

Command Description
help 显示帮助对话框
build Invokes make/msbuild.exe and builds the native addon
调用 make/msbuild.exe 并构建本机插件
clean Removes the build directory if it exists
删除构建目录(如果存在)
configure Generates project build files for the current platform
为当前平台生成项目构建文件
rebuild Runs clean, configure and build all in a row
连续运行干净、配置和构建
install Installs Node.js header files for the given version
安装给定版本的 Node.js 头文件
list Lists the currently installed Node.js header versions
列出当前安装的 Node.js 标头版本
remove Removes the Node.js header files for the given version
删除给定版本的 Node.js 头文件

node-gyp options

上文通过命令,我们可以执行不同的操作,但在操作时,可以通过指定不同的options来完成不同的运行时配置,例如指定Node版本、指定python版本等,所有可用的node-gyp配置参数如下:

Command Description
-j n, —jobs n Run make in parallel. The value max will use all available CPU cores
—target=v6.2.1 Node.js version to build for (default is process.version)
—silly, —loglevel=silly Log all progress to console
—verbose, —loglevel=verbose Log most progress to console
—silent, —loglevel=silent Don’t log anything to console
debug, —debug Make Debug build (default is Release)
—release, —no-debug Make Release build
-C $dir, —directory=$dir Run command in different directory
—make=$make Override make command (e.g. gmake)
—thin=yes Enable thin static libraries
—arch=$arch Set target architecture (e.g. ia32)
—tarball=$path Get headers from a local tarball
—devdir=$path SDK download directory (default is OS cache directory)
—ensure Don’t reinstall headers if already present
—dist-url=$url Download header tarball from custom URL
—proxy=$url Set HTTP(S) proxy for downloading header tarball
—noproxy=$urls Set urls to ignore proxies when downloading header tarball
—cafile=$cafile Override default CA chain (to download tarball)
—nodedir=$path Set the path to the node source code
—python=$path Set path to the Python binary
—msvs_version=$version Set Visual Studio version (Windows only)
—solution=$solution Set Visual Studio Solution version (Windows only)
—force-process-config Force using runtime’s process.config object to generate config.gypi file

node-gyp配置文件

如下展示基础的node-gyp配置文件内容:

  1. {
  2. 'variables': {},
  3. 'includes': [
  4. '../build/common.gypi',
  5. ],
  6. 'target_defaults': {},
  7. 'targets': [
  8. {
  9. 'target_name': 'target_1',
  10. },
  11. {
  12. 'target_name': 'target_2',
  13. },
  14. ],
  15. 'conditions': [
  16. ['OS=="linux"', {
  17. 'targets': [
  18. {
  19. 'target_name': 'linux_target_3',
  20. },
  21. ],
  22. }],
  23. ['OS=="win"', {
  24. 'targets': [
  25. {
  26. 'target_name': 'windows_target_4',
  27. },
  28. ],
  29. }
  30. ],
  31. ],
  32. }

整个文件就是一个Python字典,实际也是一个JSON文件,只有两点小区别:

  1. 使用#号做注释
  2. 在列表或字典最后一个元素之后使用,是合法的

    gyp顶级属性介绍

    variables

    定义变量,可以在文件的其他部分内插和使用。

    includes

    将包含在本文件中的其他文件列表。 按照惯例,包含文件的后缀名为.gypi(gyp include)。

    target_defaults

    设置,将应用于本.gyp文件中定义的所有目标。

    targets

    这个.gyp文件可以生成的目标列表。 其中每个目标都是一个字典,包含了描述构建目标所需的所有设置信息。

    conditions

    条件规范列表,可以根据不同变量的值修改由该.gyp文件定义的全局字 典中项目内容。如上例中,顶级字典中conditions部分的最常见用法是将平台相关的特定的目标添加到targets列表。

    gyp targets 属性介绍

    在 targets 中包含以下顶级设置:

    target_name

    目标名,在所有的.gyp文件中应该是唯一的。此名称将用于所成生的不同IDE的项目名,如:Visual Studio解决方案中的项目名称、Xcode配置中的目标名称、SCons配置的命令行构建此目标的别名。

    type

    设置为executable

    msvs_guid

    这只是过渡用法。用于将在生成的Visual Studio解决方案文件中使用的硬编码的GUID值,这使我们能够检查与gyp生成的项目文件互操作的chrome.sln文件。一旦Chromium中的所有内容都由gyp生成,GUID在调用中保持不变就不再重要了,我们就可以不在考虑这些设置,

    dependenciesdefines

    这个目标所依赖的其他目标列表。gyp生成的文件将保证其他目标在这个目标之前建立。任何dependencies列表中的库目标都将与此目标链接。此列表中的目标的direct_dependent_settings部分中列出的各种设置(define、include_dirs等)将应用于此目标的构建和链接方式。详见下面direct_dependent_settings介绍。

    defines

    将在编译命令行中传递的C预处理器定义(使用-D或/D选项)。

    include_dirs

    包含头文件的目录。将传递给编译命令行(使用-I或/I选项)。

    sources

    这个目标的源文件列表。
    所添加的文件路径,是相对于.gyp文件的路径。除非真的需要,否则就应该字线顺序排序。

    conditions

    将根据匹配条件更新目标字典中的不同设置。

    常用用例

    将会介绍一些常用的GYP用例用法,这些用法是代码片段,不包含完整的配置文件,在实际使用中可能需要配合其他的配置,需要注意一下。

    添加新的源文件

    这里面分两种情况,添加平台源文件和添加某个平台支持的源文件,添加方法相似但略有不同。

    添加某个平台的源文件

    在添加某个平台特有的源文件时,只需要在target中的source添加文件地址即可:
    1. {
    2. 'targets': [
    3. {
    4. 'target_name': 'target',
    5. 'sources': [
    6. 'file.cpp',
    7. 'file2.cpp',
    8. ],
    9. },
    10. ],
    11. },
    所添加的文件路径,是相对于.gyp文件的路径。除非真的需要,否则就应该字线顺序排序。

    添加一个平台相关的源文件

    平台相关的问题被命名为:*_linux.{ext}*_mac.{ext}*_posix.{ext}*_win.{ext}
    也就是说,你可以简单的使用以下标准后缀之一来添加特定于平台的源文件:
  • _linux (如 foo_linux.cc)
  • _mac (如 foo_mac.cc)
  • _posix (如 foo_posix.cc)
  • _win (如 foo_win.cc)

如,你可以像下面这样将文件添加到指定targets的sources列表中,即可添加平台相关的源文件:

  1. {
  2. 'targets': [
  3. {
  4. 'target_name': 'foo',
  5. 'type': 'executable',
  6. 'sources': [
  7. 'independent.cc',
  8. 'specific_win.cc',
  9. ],
  10. },
  11. ],
  12. },

Chromium .gyp文件会进行过滤,将不适合当前平台的文件过滤掉。在上面的示例中,specific_win.cc文件将会从非Windows版本的源列表中自动删除。

添加平台特有的源文件

如果平台相关的文件名不包含 *_{linux,mac,posix,win}字符串,但也不能修改文件名,可以通过以下两种模式来进行平台匹配:
方式一:
可以将文件添加到指定targets的sources列表中,并添加一个conditions节点来排除指定的文件名:

  1. {
  2. 'targets': [
  3. {
  4. 'target_name': 'foo',
  5. 'type': 'executable',
  6. 'sources': [
  7. 'linux_specific.cc',
  8. ],
  9. 'conditions': [
  10. ['OS == "linux"', {
  11. 'sources': [
  12. # 仅仅支持linux系统配置
  13. 'linux_specific.cc',
  14. ]
  15. }[,
  16. ],
  17. },
  18. ],
  19. },

方法二:
在conditions中的sources中添加平台相关的文件:

  1. {
  2. 'targets': [
  3. {
  4. 'target_name': 'foo',
  5. 'type': 'executable',
  6. 'sources': [],
  7. ['OS == "linux"', {
  8. 'sources': [
  9. 'linux_specific.cc',
  10. ]
  11. }],
  12. },
  13. ],
  14. },

添加一个新的可执行目标

在构建addon插件时,可能会存在需要创建多个可执行目标,通常是每个可执行目标类型需要新的一组源文件列表,一些编译器/连接器。

适用于所有平台的可执行目标

讲定义新的可执行目标的字典添加到 .gyp文件的targets 中,如:

  1. {
  2. 'targets': [
  3. {
  4. 'target_name': 'new_unit_tests',
  5. 'type': 'executable',
  6. 'defines': [
  7. 'FOO',
  8. ],
  9. 'include_dirs': [
  10. '..',
  11. ],
  12. 'dependencies': [
  13. 'other_target_in_this_file',
  14. 'other_gyp2:target_in_other_gyp2',
  15. ],
  16. 'sources': [
  17. 'new_additional_source.cc',
  18. 'new_unit_tests.cc',
  19. ],
  20. },
  21. ],
  22. }

适用于特定平台的可执行目标

添加适用于特定平台的可执行目标时,所定义的新的可执行目标不是添加到targets列表中,而是与其同级的conditions 节点中:

  1. {
  2. 'targets': [
  3. ],
  4. 'conditions': [
  5. ['OS=="win"', {
  6. 'targets': [
  7. {
  8. 'target_name': 'new_unit_tests',
  9. 'type': 'executable',
  10. 'defines': [
  11. 'FOO',
  12. ],
  13. 'include_dirs': [
  14. '..',
  15. ],
  16. 'dependencies': [
  17. 'other_target_in_this_file',
  18. 'other_gyp2:target_in_other_gyp2',
  19. ],
  20. 'sources': [
  21. 'new_additional_source.cc',
  22. 'new_unit_tests.cc',
  23. ],
  24. },
  25. ],
  26. }],
  27. ],
  28. }

向目标中添加设置

所有指定的target,都可以定义几种不同类型的设置。

添加新的预处理器定义(-D或/D标识)

新的预处理器定义可以通过defines设置:

  1. {
  2. 'targets': [
  3. {
  4. 'target_name': 'existing_target',
  5. 'defines': [
  6. 'BAR=some_value',
  7. ],
  8. },
  9. ],
  10. },

预处理器定义可以直接在targets设置中指定,也可以添加到conditions节点中;

添加新的包含目录(-I或/I标识)

添加新的目录可以通过 include_dirs 设置:

  1. {
  2. 'targets': [
  3. {
  4. 'target_name': 'existing_target',
  5. 'include_dirs': [
  6. '..',
  7. 'include',
  8. ],
  9. },
  10. ],
  11. },

上例中可以通过 targets 设置指定目录,也可以包含在 conditions 语句中。

添加新的 compiler flags

添加指定的 compiler flags 时,可以通过 cflags 来设置:

  {
    'targets': [
      {
        'target_name': 'existing_target',
        'conditions': [
          ['OS=="win"', {
            'cflags': [
              '/WX',
            ],
          }, { # OS != "win"
            'cflags': [
              '-Werror',
            ],
          }],
        ],
      },
    ],
  },

因为这些标识是因平台而定的,所以只能在conditions中设置。

gyp语法说明

参考:https://itbilu.com/nodejs/npm/By7L5p3ff.html

引用

User Documentation:https://gyp.gsrc.io/docs/UserDocumentation.md
译文:https://itbilu.com/nodejs/npm/Hklq5OweM.html
Input Format Reference:https://gyp.gsrc.io/docs/InputFormatReference.md