SCons 构建工具

先说明下什么是scons,scons是一个Python写的自动化构建工具,就比如老牌的cmake,或者如果经常跟google一些开源项目打交道的话,那肯定知道新近开始流行的gyp(google内部用的构建工具),scons实现跟它们有类似的功能。而scons又有区别于其他构建工具的特点,不得不承认,这些特点让我喜欢上了这个工具。

先简单总结下吸引我的几点:

1. 自动依赖分析

2. 工具本身由python实现,跨平台

3. 基于MD5识别构建文件的改变,并且可以自定义和扩展

4. 构建文件逻辑用python来写,功能强大,扩展性超强,跨平台

5. 简单易用(半小时内可以学会如何构建中小规模编译环境)

6. 官方提供的文档详细易理解(如果看过google的gyp的文档,那叫一个坑爹)

 

好了,进入正题,就让我们来循序渐进的来领略下scons的魅力吧。

首先是安装环境,

第一步当然是要保证系统中安装了python,貌似2.6和2.7下scons都没有问题,其他的自己尝试下吧。

第二步,安装scons。windows环境的话直接去官网下载exe直接安装即可。linux Debian系统下则更方便,可以直接用如下命令来安装:sudo apt-get install scons

安装完成后,在命令行验证一下,输入scons -v, 如果没有提示scons命令不存在则说明安装成功。不幸的是,windows下还真提示不存在了,怎么办?其实在python安装路径C:\Python27\Scripts下(我的python安装在C:\Python27)有个scons.bat,以后运行这个命令就可以(/scons.bat -v),为了方便可以把该路径追加到环境变量PATH中。

ok,环境搞定。

 

接着,一起来细细品味下scons吧。

1. 假设有如下【helloScons.c】文件:

 
  1. #include

  2. #include

  3. int main(int argc, char* argv[])

  4. {

  5. printf("Hello, SCons!\n");

  6. return 0;

  7. }

用scons怎么编译它呢?首先在helloScons.c相同路径下新建【SConstruct】文件,内容如下:

Program('helloScons.c')

 

命令行,进入该文件相同路径,运行‘scons’(windows下运行scons.bat)。可以看到如下运行结果:

 
  1. scons: Reading SConscript files ...

  2. scons: done reading SConscript files.

  3. scons: Building targets ...

  4. gcc -o helloScons.o -c helloScons.c

  5. gcc -o helloScons helloScons.o

  6. scons: done building targets.

编译完成,得到helloScons可执行文件。

如果我们希望生成其他名字的可执行文件呢?很简单,把【SConstruct】改成如下内容就可:

Program('newName', 'helloScons.c')

 

2. 我们稍微改动下,比如相同路径下再新建个文件extScons.c, extScons.h:

【extScons.h】

int add(int x, int y);

 

【extScons.c】

 
  1. int add(int x, int y)

  2. {

  3. return x + y;

  4. }

 

然后修改下【helloScons.c】:

 
  1. #include

  2. #include

  3. #include “extScons.h”

  4. int main(int argc, char* argv[])

  5. {

  6. printf("Hello, SCons %d!\n", add(1, 2));

  7. return 0;

  8. }

 

【SConstruct】文件怎么改呢?

Program(['helloScons.c', 'extScons.c'])

那如果你整个工程中有上百个.c,难道都要在SConstruct中一个一个写出来吗?当然不需要,下面这样也能达到跟上面一样的功能:

Program(Glob('*.c'))

 

3. 假设我们再变化一下,在当前路径下创建ext文件夹,把extScons.h和extScons.c移到ext文件夹里,【SConstruct】怎么写:

Program(['helloScons.c', 'ext/extScons.c'])

类似如果希望设置为文件夹下所有文件,也可以写成:

Program([Glob('*.c'), Glob('ext/*.c')])

 

4. 那么如果要把extScons.c编译成动态链接库.so,怎么做?

【SConstruct】文件如下:

 
  1. SharedLibrary('ext/extScons.c')

  2. Program(['helloScons.c'], LIBS=['extScons'], LIBPATH='./ext')

解释一下,SharedLibrary()指定把ext/extScons.c编译成动态链接库,如果想编译为静态链接库则使用StaticLibrary()。Program方法中,LIBS指定的是主程序helloScons.c需要使用的动态链接库libextScons.so,LIBPATH则指定的是libextScons.so的路径。

运行scons后,可以看到ext文件夹下生成了libextScons.so,主文件夹下生成了可执行程序helloScons。

 

5. 如果要把编译和链接两个步骤分开呢?没问题,scons提供了Object方法来编译生成.o(windows下为.obj)文件。

【SConstruct】文件如下:

 
  1. import os

  2. Object('ext/extScons.c')

  3. Library('ext/extScons.o')

  4. Object('helloScons.c')

  5. Program(['helloScons.o'], LIBS=['extScons'], LIBPATH='./ext')

Object方法用来编译生成.o文件,Library和Program则用来链接.o生成静态链接库和可执行文件。

还可以再改善下如上构建代码:

 
  1. import os

  2. ext = Object('ext/extScons.c')

  3. Library(ext)

  4. main = Object('helloScons.c')

  5. Program(main, LIBS=['extScons'], LIBPATH='./ext')

Object会返回编译产生的.o文件列表,可以直接把这个返回值传给Library和Program方法。在需要编译许多代码文件时,这点还是很有用的。

 

6. 如果需要在不同操作系统下编译链接不同的代码文件呢?scons可以很简单就实现。

我们再创建一个文件【helloSconsForWin.c】,作为windows环境下使用的主程序:

 
  1. #include

  2. #include

  3. #include "ext/extScons.h"

  4. int main(int argc, char* argv[])

  5. {

  6. printf("Hello, SCons in Windows %d!\n", add(1, 2));

  7. return 0;

  8. }

 

同时,假设我们又希望在Linux下以动态链接的形式,而在windows下以静态链接的形式使用extScons。【SConstruct】文件如下:

 
  1. import os

  2. if os.name == "posix":

  3. SharedLibrary('ext/extScons.c')

  4. Program(['helloScons.c'], LIBS=['extScons'], LIBPATH='./ext')

  5. elif os.name == "nt":

  6. StaticLibrary('ext/extScons.c')

  7. Program(['helloSconsForWin.c'], LIBS=['extScons'], LIBPATH='./ext')

纯粹的python语法,使用了os模块,如果你熟悉python的话,编译和链接的逻辑你可以随心所欲的写。

你可能感兴趣的:(C++)