gyp是google为chromium项目开发的管理工具,功能类似于cmake。gyp只能产生编译脚本,真正的编译工作还有靠其他工具,我选择了ninja。
$ sudo apt-get install gyp
$ sudo apt-get install ninja-build
#include
using namespace std;
template<typename T>
T add(T a, T b){ return a+b; }
int main()
{
cout<< add<int>(5,6)<cout<< add<double>(3.4,4.0)<return 0;
}
{
'targets':[
{
'target_name':'an',
'type':'executable',
'dependencies':[],
'defines':[],
'include_dirs':[],
'sources':[
'template_sample.cpp',
],
'conditions':[]
}
],
}
$ gyp –depth=. –format=ninja ./build.gyp
其中–depth=. 表示在当前文件夹下寻找开始的gyp脚本,必须显示的指出gyp没有默认设置。–format=ninja表示要生成ninja的脚本,默认生成的是Makefile。
执行后,会在当前目录下生成一个out目录。其结构如下:
$ ninja -C out/Default
注意-C是大写,执行成功后会在out/Default目录下生成一个叫做an的可执行文件,这个an就是在target_name字段指定的名字。
目前,gyp没有提供clean的方案,所以只能手动删除out目录。
编译参数一般增加在conditions字段,根据系统的不同增加cflags和ldflags,如下:
{
'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'
]
}
],
]
}
],
}
#include "defines.h"
#include
using namespace std;
int main(){
cout<< MY_NUMBER <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字段中被指出。这里需要注意,两个单引号之间一定是文件的路径,不要包含不必要的空格等其他字符。
测试程序的源码如下:
#include
using namespace std;
#ifdef BIG_NUMBER
int out_number = 10;
#else
int out_number = 1;
#endif
int main(){
cout<< out_number <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':[]
}
],
}
有时我们不是要输出一个可执行文件,而是要编译一个静态库或者动态库。这就要修改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脚本后,也可以生成静态库,这样做的好处是你可以在真正输出时再决定输出静态库还是动态库。尤其对于要一次生成多个库的情况下,这种方法尤其的好用。
目前我对gyp唯一的不满就是满屏的中括号和花括号,这个很讨厌,但这也是为了符合json标准的要求,所以编写时一定要细心,其他就没什么了。