如何使用gyp管理c++工程(ubuntu版)

3 篇文章 0 订阅
1 篇文章 0 订阅

1.简介

gyp是google为chromium项目开发的管理工具,功能类似于cmake。gyp只能产生编译脚本,真正的编译工作还有靠其他工具,我选择了ninja。

2.安装gyp和ninja

$ sudo apt-get install gyp
$ sudo apt-get install ninja-build

3.一个简单的例子

1.首先准备一个源文件,我写了template_sample.cpp,代码如下:
#include <iostream>
using namespace std;

template<typename T>
T add(T a, T b){ return a+b; }

int main()
{
     cout<< add<int>(5,6)<<endl;
     cout<< add<double>(3.4,4.0)<<endl;
     return 0;
}           
2.编写gyp使用的文件,build.gyp(后缀是.gyp即可,名字随便)
{
   'targets':[
        {
            'target_name':'an',
            'type':'executable',
            'dependencies':[],
            'defines':[],
            'include_dirs':[],
            'sources':[
                'template_sample.cpp',
            ],
            'conditions':[]
        }
    ],  
}
3.生成ninja脚本,命令如下:

$ gyp –depth=. –format=ninja ./build.gyp

其中–depth=. 表示在当前文件夹下寻找开始的gyp脚本,必须显示的指出gyp没有默认设置。–format=ninja表示要生成ninja的脚本,默认生成的是Makefile。
执行后,会在当前目录下生成一个out目录。其结构如下:
这里写图片描述

4.编译,执行如下命令:

$ ninja -C out/Default

注意-C是大写,执行成功后会在out/Default目录下生成一个叫做an的可执行文件,这个an就是在target_name字段指定的名字。

5.clean整个工程重新编译

目前,gyp没有提供clean的方案,所以只能手动删除out目录。

4.gyp脚本的编写

4.1 如何增加编译、链接参数

编译参数一般增加在conditions字段,根据系统的不同增加cflagsldflags,如下:

{
   'targets':[
        {
            'target_name':'an',
            'type':'executable',
            'dependencies':[],
            'defines':[],
            'include_dirs':[],
            'sources':[
                'template_sample.cpp',
            ],
            'conditions':[
              ['OS=="win"',{
                             'cflags':[],
                             'ldflags':[]
                         },{
                              'cflags':[
                                   '--std=c++11',
                               ],
                              'ldflags':[]
                         }
              ],
            ]
        }
    ],
}

注意conditions字段的变化:'OS=="win"'是条件语句的后要有”,”号,第一个括号内表示条件为真时的参数,第二个括号表示条件为假时的参数。上面的例子中,我在不是win的系统上增加了–std=c++11这个参数。
另外,这里有必要提一下链接顺序问题。在链接的时候,链接器对符号表的寻找是按照你输入的命令的顺序进行的,比如a.o 需要libm.so的函数,那么libm.so在链接命令里就必须写在a.o 的后面,因为链接器发现a.o有函数没有找到,就只会去他后面的库里找,如果你把libm.so写在前面,自然就找不到。所以在增加链接库的时候,不要在ldflags里增加-l类的参数,这类参数要加在libraries字段里如:

{
   'targets':[
        {
            'target_name':'an',
            'type':'executable',
            'dependencies':[],
            'defines':[],
            'include_dirs':[],
            'sources':[
                'template_sample.cpp',
            ],
            'conditions':[
              ['OS=="win"',{
                             'cflags':[],
                             'ldflags':[]
                         },{
                              'cflags':[
                                   '--std=c++11',
                               ],
                              'ldflags':[]'libraries':[
                                  '-lm'
                              ]
                         }
              ],
            ]
        }
    ],
}

4.2头文件路径设定—–include_dirs字段的使用

有如下工程目录结构
这里写图片描述
main.cpp的代码如下:

#include "defines.h"
#include <iostream>
using namespace std;

int main(){
    cout<< MY_NUMBER <<endl;
    return 1;
}

可见main.cpp文件引用了defines.h这个头文件,所以在编译的时候需要告诉编译系统到哪里去寻找这个defines.h文件。为此buid.gyp如下:

{
   'targets':[
        {
            'target_name':'an',
            'type':'executable',
            'dependencies':[],
            'defines':[],
            'include_dirs':[
                'include'
            ],
            'sources':[
                'main.cpp',
            ],
            'conditions':[]
        }
    ],  
}

可以看出头文件的位置include在include_dirs字段中被指出。这里需要注意,两个单引号之间一定是文件的路径,不要包含不必要的空格等其他字符

4.3 编译参数增加宏定义—defines字段使用

测试程序的源码如下:

#include <iostream>
using namespace std;

#ifdef BIG_NUMBER
int out_number = 10; 
#else
int out_number = 1;
#endif
int main(){
    cout<< out_number <<endl;
    return 1;
}

可以看出,如果BIG_NUMBER宏被定义,则输出为10 ,否则为1。在使用Makefile的时候,我们可以通过为gcc增加-DBIG_NUBMER参数的方式来定义这个宏。那在gyp管理的时候,我们就要使用defines字段,代码如下:

{
   'targets':[
        {
            'target_name':'an',
            'type':'executable',
            'dependencies':[],
            'defines':[
                 'BIG_NUMBER'
            ],
            'include_dirs':[],
            'sources':[
                'main.cpp',
            ],
            'conditions':[]
        }
    ],  
}

4.4 编译静态库(动态库)

有时我们不是要输出一个可执行文件,而是要编译一个静态库或者动态库。这就要修改type字段,上文中type字段使用了executable,实际还可以设为static_library,修改后的gyp脚本如下:

{
   'targets':[
        {
            'target_name':'an',
            'type':'static_library',
            'dependencies':[],
            'defines':[],
            'include_dirs':[],
            'sources':[
                'main.cpp',
            ],
            'conditions':[]
        }
    ],  
}

这样在out/Default/obj的目录下就会生成一个liban.a的静态库。
动态库的方式类似,只需把type字段设置为shared_library即可。
另外还有一种使用变量的方法,在这里提前介绍一下。就是将type字段设置为<(library),完整的代码如下:

{
   'targets':[
        {
            'target_name':'an',
            'type':'<(library)',
            'dependencies':[],
            'defines':[],
            'include_dirs':[],
            'sources':[
                'main.cpp',
            ],
            'conditions':[]
        }
    ],  
}

然后在使用gyp工具的时候指定这个library的值,如:

$ gyp –depth=. –format=ninja -Dlibrary=static_library ./build.gyp

这样生成ninja脚本后,也可以生成静态库,这样做的好处是你可以在真正输出时再决定输出静态库还是动态库。尤其对于要一次生成多个库的情况下,这种方法尤其的好用。

5.gyp的缺点

目前我对gyp唯一的不满就是满屏的中括号和花括号,这个很讨厌,但这也是为了符合json标准的要求,所以编写时一定要细心,其他就没什么了。

未完待续

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值