Hello GYP

GYP,Generate Your Projects,一个google开源的构建系统,最开始用于Chromium项目,现在一些其他的开源项目也开始使用GYP,如V8node-gyp。本文是学习使用GYP的笔记,算是一个GYP的简明教程吧。

特别之处

在已经有很多的构建系统的情况下,gyp诞生的哲学或者说优点如下:

  1. 各平台使用各自主流的构建系统。
    • 程序员更熟悉自己的平台,减少学习成本。
    • 构建速度快。自己平台的主流构建系统的速度是各平台优化过的。
  2. 在一个平台上可以生成所有支持的平台的工程文件。
    • 如在mac上也可以生成Visual Studio工程,windows上也可以生成Xcode工程。
  3. 生成的工程文件和手工创建的工程文件没有区别
    • 这样,随时可以停止使用gyp。别人可以只使用相关工程文件而不使用gyp

安装

前提条件:本机需要安装python,git。

下载:
git clone https://chromium.googlesource.com/external/gyp

安装:
有两种安装方式。

  1. 执行安装命令
    1
    2
    
    cd <gyp-dir> # 刚才的下载目录
    [sudo] python setup.py install
    
    这个命令做的事情主要是安装python的第三方扩展到/Library/Python/2.7/site-packages/gyp-0.1-py2.7.egg,并把gyp的可执行文件copy到/usr/local/bin。
  2. 简易安装,直接将<gyp-dir>加入PATH。
  1. 使用

    1. 编写.gyp文件
    2. 运行gyp命令生成makefile、build.ninja文件或xcode、vs等工程
    3. 编译。根据第2步的结果,运行make、ninja或者在xcode、vs里编译

    举一个最简单的例子,源文件如下:

    main.cpp
    1
    2
    3
    4
    5
    6
    
    #include <iostream>
    
    int main(int argc, const char* argv[]) {
        std::cout << "Hello World!" << std::endl;
        return 0;
    }
    
    编写.gyp文件如下: main.gyp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    {
      'targets': [
        {
          'target_name': 'main',
          'type': 'executable',
          'sources': [
            'main.cpp',
          ],
        },
      ],
    }
    

    在源文件目录下运行命令gyp --depth=. main.gyp,生成工程文件。打开生成的工程文件编译、运行即可。

    更多例子可以参考play_gyp

    生成跨平台工程的实践经验

    如上个例子中展示的,运行gyp命令的大概方式为gyp --depth=. --generator-output=build -f ninja main.gyp,其中 –depth指定工程的根目录,–generator-output指定工程文件的输出目录,默认为当前目录,-f指定生成工程文件的类型,常用的有'make', ‘ninja’, ‘xcode’, ‘msvs’, ‘scons'。更多的命令行选项可以通过gyp -h查看。

    工程实践中还有一种更方便的生成不同平台工程的方法,即使用gyp的全局变量。定义全局变量的好处是可以使用别人封装好的gyp脚本,如Chromium工程中就可以使用gyp_chromium.py了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    
    # iOS 真机
    export GYP_DEFINES="$GYP_DEFINES OS=ios target_arch=armv7"
    export GYP_CROSSCOMPILE=1
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS=xcode
    
    # iOS 模拟器
    export GYP_DEFINES="$GYP_DEFINES OS=ios target_arch=ia32"
    export GYP_CROSSCOMPILE=1
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS=xcode
    
    # mac
    export GYP_DEFINES="$GYP_DEFINES OS=mac target_arch=x64"
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS=xcode
    
    # android arm target
    export GYP_DEFINES="$GYP_DEFINES OS=android"
    export GYP_CROSSCOMPILE=1
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS=ninja
    
    # android x86 target
    export GYP_DEFINES="$GYP_DEFINES OS=android target_arch=ia32"
    export GYP_CROSSCOMPILE=1
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS=ninja
    
    # android MIPS target
    export GYP_DEFINES="$GYP_DEFINES OS=android target_arch=mipsel"
    export GYP_CROSSCOMPILE=1
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS=ninja
    
    # windows
    export GYP_DEFINES="$GYP_DEFINES OS=win"
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS= msvs # or msvs-ninja
    export GYP_MSVS_VERSION = 2008
    
    # linux
    export GYP_DEFINES="$GYP_DEFINES OS=linux" # or unix
    export GYP_GENERATOR_OUTPUT=../build
    export GYP_GENERATORS=make
    
    # gyp 其他可用的 环境变量
    GYP_GENERATOR_FLAGS
    

    也可以通过修改GYP_GENERATORS,生成各种类型的工程文件

    • ninja for Ninja
    • make for Makefiles
    • msvs for Visual Studio
    • msvs-ninja for Visual Studio project building with ninja
    • xcode for Xcode

    gyp文件语法

    GYP的输入文件习惯上后缀为.gyp或.gypi。.gypi文件作为.gyp文件的include文件。 以Visual Studio为例,.gyp文件对应.sln工作空间,.gyp文件中的target对应.vcproj或.vxcproj工程。

    .gyp文件的顶级元素为'variables’, ‘includes’, ‘target_defaults’, ‘targets’, ‘conditions'。语法是JSON,或者说是允许trailing comments的python。.gyp文件之间其实可以不用相互引用,gyp会递归的扫描当前目录的所有子目录,处理扫描到的所有*.gyp文件。

    官方文档

    变量

    变量分为三类,Predefined、User-defined、Automatic。
    变量设置默认值的方法:name%:value。只有name未定义时,才将name的值设置为value.

    • Predefined,命名习惯为CAPITAL_LETTERS。
      1. OS:用于判断操作系统
      2. EXECUTABLE_PREFIX:可执行文件的前缀
      3. EXECUTABLE_SUFFIX:可执行文件的后缀
      4. INTERMEDIATE_DIR:中间文件目录,只对单一target有效
      5. SHARED_INTERMEDIATE_DIR:中间文件共享目录,所有target(包括跨.gyp文件的target)共用同一目录
      6. PRODUCT_DIR:输出文件(编译出的可执行文件、库等)的主目录
    • User-defined,命名习惯为lowercase_letters。变量使用的方式如下
      1. <(VAR) early phase, value is string
      2. >(VAR) post phase, value is string
      3. <@(VAR) early phase, value is list
      4. >@(VAR) post phase, value is list
    • Automatic,dictionary中,name:string的key/value对会自动生成一个_name的变量,值为string

    命令

    gyp可以执行shell命令,即将命令内容传递给shell执行,然后获得返回值。
    用法为<!(cmd)<!@(cmd),前者返回值为string,后者返回值为list。

    这样,虽然gyp没有提供通配符,但是可以通过命令实现这个功能,如实现添加当前目录下所有.cpp后缀的文件作为sources:

    1
    2
    3
    
    'sources': [
        '<!@(ls -1 ./*.cpp)',
    ],
    

    target的配置项目

    顶级元素下的target_defaults中可以设置所有targets共用的配置项目,targets中可以具体配置每个target。
    常用的target可分为可运行程序、静态库、动态库等,但在跨平台时,不同平台的target各不相同,参数的设置也相差很远。 target的通用框架如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    {
        'targets': [{
            'target_name': 'target_one',
            'type': 'executable',
            'dependencies': [
                'xyzzy',
                '../bar/bar.gyp:bar',
            ],
            'defines': [
                'DEFINE_FOO',
                'DEFINE_A_VALUE=value',
            ],
            'include_dirs': [
                '..',
            ],
            'sources': [
                'file1.cc',
                'file2.cc',
            ],
            'conditions': [
              ['OS=="linux"', {}],
              ['OS=="win"', {}]
            ],
        },],
    }
    
    target的一些常用配置,各个平台都差不多,gyp提供了统一的设置方法。
    defines为宏定义,对应-D或/D;
    include_dirs对应-I或/I;
    cflags为编译选项,对应类似-Werror或/Werror;
    ldflags为链接选项,对应类似-pthread;

    target还有一些在类型不同、平台不同时,差别很大的配置,列举一些如下:

    • 静态库或动态库

    direct_dependent_settings:定义一些编译参数、宏定义等,这些定义将导出到直接依赖该库(通常是第三方库)的target
    all_dependent_settings:定义一些编译参数、宏定义等,这些定义将导出到所有依赖该库的target,包含直接依赖和间接依赖
    link_settings:定义一些当将该库作为输入时需要配置的链接参数。通常是对静态库有效,动态库忽略
    export_dependent_settings:列出一些dependencies中的target,direct_dependent_settings定义的配置将应用到export_dependent_settings列出的target。即将依赖该库的配置导出到该库依赖的target

    • 跨平台工程

    针对各个平台不同的配置,gyp的策略是直接使用各平台工程的原生参数。如生成Xcode工程时,可以直接在gyp文件中使用SDKROOT,TARGETED_DEVICE_FAMILY等Xcode中使用的参数。

    在xcode_settings对象中设置Xcode的特有参数
    在msvs_settings对象中设置Visual Studio的特有参数。

    这种策略有一个便利之处。以Xcode工程为例,如果有不知道怎么设置的选项,可以先在Xcode工程中设置好,再从工程文件.xcodeproj包内的project.pbxproj文件中拷贝出来,同步到.gyp文件中。

    gyp的潜规则

    1. target的sources项会按照对应平台自动过滤后缀(*_linux.{ext}, *_mac.{ext}, *_posix.{ext} or *_win.{ext})不符合的源文件。

    参考资料

    1. gypDemo
    2. gypGettingStarted

     May 17th, 2014  build

    版权声明:自由转载-非商用-非衍生-保持署名 | BY-NC-ND 3.0



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值