自动化构建工具-scons简介
(2013-08-16 14:12:19)
标签:
itlinuxscons |
分类: Linux的魅力 |
Windows用习惯了的人,在Linux强大的脚本面前,俨然菜鸟一只。工作却偏偏要跟Linux打交道,硬着头皮上吧。最近经常接触的就是用scons对java程序进行编译,做的最多的就是修改scons的配置文件SConstruct和SConscript。scons确实很好用,自动化的构建以及无需指定依赖关系莫过于是它最大的优点了。但是就是这一点,基于Python的SConstruct配置文件的内容就至关重要了。之前做的一个编译就是先对项目中的java文件用env.Java()进行编译,然后用env.Jar将class文件package成jar包。
使用的SConscript文件的python代码大致如下:
抛砖引玉:
下面是我收集的一些scons的相关资料,与大家共享。
一 scons简介
scons是一个用Python写的自动化构建工具。形象地说,scons就是这样一个构建工具:你告诉它要做的任务,以及必要的输入和输出,至于怎么做这个任务,scons自己去完成。 从构建的角度讲,scons与GNU make是同一类的工具。它是一种改进的、跨平台的GNU make的替代工具,其集成功能类似于autoconf/automake。相比较而言,scons是一个更简便、更可靠、更高效的编译软件。scons 还具有良好的夸平台性,可以运行在 Linux, AIX, BSD, HP/UX, IRIX, Solaris, Windows, Mac OS X 和 OS/2 上。但用户需要安装python和scons之后才能运行。scons与其它构建工具的一个显著的区别就是其配置文件是python script。scons的构建思想与GNU的make是完全不同的,GNU make的核心是依赖关系,所以GNU提供Automaker来分析依赖性,辅助程序员产生makefile。而scons会自己找依赖关系,这个主要是借助于内部的scanner来扫描有改动的文件,然后才去编译链接生成可执行程序。
二scons使用
2.1 基于python的配置文件
scons中可能出现的配置文件:SConstruct,SConstruct,SConstruct,SConscript。scons将在当前目录以下次序 SConstruct,SConstruct,SConstruct 来搜索配置文件,从读取的第一个文件中读取相关配置。在配置文件SConstruct中可以使用函数SConscript()函数来定附属的配置文件。按惯例,这些附属配置文件被命名为”SConscript”,当然也可以使用任意其它名字。 scons通过决定哪个具体的模块必须被rebuild,并执行相关的命令来进行rebuild。默认情况下,scons将在当前目录以以下次序(SConstruct,SConstruct,SConstruct)来搜索配置文件,从读取的第一个文件中读取相关配置。我们可以通过-f选项来指定替代的配置文件,具体方法如下:
scons –f configfilename
scons中的配置文件SConscript由python脚本编写,所以我们能使用python脚本的灵活性来处理复杂的build。scons在读取和执行所有SConscript文件之后,才对目标进行构建,具体流程,我们可以看一下示例:
$ scons foo.out
scons: Reading SConscript files …
scons: done reading SConscript files.
scons: Building targets ...
cp foo.in foo.out
scons: done building targets.
2.2 Environment设定
Scons需要在一个特定的Enviroment(环境)中来构建软件,环境中定义了一些构建软件过程中需要的变量和变量的值。但scons不会自动复制构建目标文件的外部环境,以保证无论何时调用scons,构建的结果不会出现差异。无论何时创建enviroment,你可以通过以下步骤从外部环境中复制环境变量PATH的值到创建的enviroment
import os
env = Environment(ENV = {’PATH’ : os.environ[’PATH’]})
相似的,可以复制诸如$PATH,$HOME,$JAVA_HOME,$LANG,$SHELL,$TERM等环境变量的值到创建的enviroment
import os
env = Environment(ENV = {’PATH’ : os.environ[’PATH’],
‘HOME’:os.environ[’HOME’]})
或者你可以复制完整的一个外部enviroment:
import os
env = Environment(ENV = os.environ)
如果如上完全拷贝外部环境,我们必须保证外部环境中的环境变量被正确的设置。
2.3 Default()来显示的指定默认目标
使用命令scons将会build当前目录下的所有的目标文件。如果在命令行中没有指定需要build的目标,我们需要使用函数Default()来显示的指定默认目标。即使在SConscript file中使用Default指定build目标,我们也可以在命令行中显示的指定当前目录(.),来build所有当前目录下的所有目标,具体命令格式如下
scons .
如果想build当前目录以外的任何文件,可以使用绝对路径来指定build目录,具体格式如下
scons /dir/
在windows下也可以使用盘符,具体如下:
scons c:\ d:\
为了build特定的目标,我们可以用指定目标为命令行参数,具体如下:
scons foo bar
如果想清除build过程中产生的中间文件和目标文件,可以使用以下命令进行清除
scons –c .
2.4 示例
a) C程序编译
这是一个用C语言编写的著名的"Hello,World!"程序:
int main()
{
printf("Hello, World!\n");
}
用SCons编译它,需要在一个名为SConstruct的文件中输入如下命令:
Program('hello.c')
这个短小的配置文件给了SCons两条信息:你想编译什么(一个可执行程序),你编译的输入文件(hello.c)。Program是一个编译器方法(builder_method),一个Python调用告诉SCons,你想编译一个可执行程序。
现在运行scons命令编译这个程序。在Linux或Unix系统上,你会看到如下输出:
% scons
scons: Reading SConscript files...
scons: done reading SConscript files.
scons: Building targets...
cc -o hello.o -c hello.c
cc -o hello hello.o
scons: done building targets
b)java程序编译
SCons同样使得编译Java也很容易了。不像Program和Object两个编译方法,Java编译方法需要你指定一个目录,这个目录是用来存放编译后的class文件的,以及一个存放.java源文件的目录:
Java('classes', 'src')
如果src目录仅仅包含一个hello.java文件,那么运行scons命令的输出会如下所示(在POSIX系统里):
% scons
scons: Reading SConscript files...
scons: done reading SConscript files.
scons: Building targets...
javac -d classes -sourcepath src src/hello.java
scons: done building targets.
c)多源文件编译指定
Program('program', ['prog.c', 'file1.c', 'file2.c']) #如果没有第一个参数,则以第二个参数(这是一个python list,用[ ]表示)的第一个元素为program的名字。如果你觉得列表里面每个文件都需要带一个引号太麻烦,可以利用Program('program', Split('main.c file1.c file2.c')) #这里的split函数是返回一个列表也可以这么用来提高可读性
src_files = Split('main.c file1.c file2.c') #中间多少个空格无所谓
Program('program', src_files)
也可利用Glob函数获得名字列表,Golb('*.c')返回规则匹配的string列表,就是类似上面的'prog.c', 'file1.c', 'file2.c'。
Program('program', Glob('*.c'))
两个关键字可以直接指明target和source,所以在Program
src_files = Split('main.c file1.c file2.c')
Program(target = 'program', source = src_files)
src_files = Split('main.c file1.c file2.c')
Program(source = src_files, target = 'program') #可以调换参数顺序
d)用Depends函数显示地的指明依赖性
有时scons扫描器检查不出一些文件的依赖性,可以利用Depends函数显示地的指明依赖性:
hello = Program('hello.c')
Depends(hello, 'other_file')
如果想让某个依赖文件改变时不重编,可以用Ignore函数设置忽略这些依赖性:
hello_obj=Object('hello.c')
hello = Program(hello_obj)
Ignore(hello_obj, 'hello.h')
Scons没有明显的依赖定义,Scons会为我们自动扫描依赖。我们只需告诉它构建出一个目标需要什么即可。Scons检查依赖关系中的文件变化的方法,除了通过时间戳,还可以通过MD5来判别,你可以通过设置Env来决定使用哪个。另外更强大的是你也可以自己编写文件更新检查方法放到SConstruct中被Scons调用,这些都是高级一些的功能,这里不细说,详情可参见Scons的doc。
参考资料:
SCons User Guide 1.2.0 :http://www.scons.org/doc/HTML/scons-user/book1.html
http://blog.chinaunix.net/uid-7321232-id-2645448.html
http://wenku.baidu.com/view/f88d3b1fc5da50e2524d7fd9
http://550480286.blog.163.com/blog/static/99093247201077113029413/

加载中…