加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

自动化构建工具-scons简介

(2013-08-16 14:12:19)
标签:

it

linux

scons

分类: Linux的魅力

Windows用习惯了的人,在Linux强大的脚本面前,俨然菜鸟一只。工作却偏偏要跟Linux打交道,硬着头皮上吧。最近经常接触的就是用scons对java程序进行编译,做的最多的就是修改scons的配置文件SConstruct和SConscript。scons确实很好用,自动化的构建以及无需指定依赖关系莫过于是它最大的优点了。但是就是这一点,基于Python的SConstruct配置文件的内容就至关重要了。之前做的一个编译就是先对项目中的java文件用env.Java()进行编译,然后用env.Jar将class文件package成jar包。

使用的SConscript文件的python代码大致如下:

      env=Environment(JAVASOURCEPATH='src')
      srclist=[ 'src/a.java',   #source file list
                'src/b.java']
      compilelist=env.Java(target='classes',source=srclist)# compile the source files
      packagelist=env.Jar(target='dest.jar',source=compilelist)
      env.Default(compilelist)
      env.Default(packagelist)

抛砖引玉:

    现在有个问题,我要对编译后的class文件增加一行用户信息(bash脚本addline.sh),人后再用env.Jar将修改后的class文件package成jar包。按照scons上面的说明,我们可以使用env.Command()来调用addline.sh对class文件进行修改。所以新的SConscript理论上应该是:
      env=Environment(JAVASOURCEPATH='src')
      srclist=[ 'src/a.java',   #source file list
 
               'src/b.java']
      compilelist=env.Java(target='classes',source=srclist)# compile the source files
      updatelist=env.Command('bash addline.sh compilelist') #assume this line works
      packagelist=env.Jar(target='dest.jar',source=compilelist)
      env.Default(compilelist)
      env.Default(updatelist)
      env.Default(packagelist)


    事实上执行scons以后,上面就会出现错误,提示找不到class文件。分析原因,在scons reading SConscript文件之后,就开始自动检查依赖关系,发现bash命令可以首先执行,所以就先与env.Java()之前执行了env.Command()里面的命令,虽然我们用Default约束的执行的顺序,但是貌似没有起到作用。百思不得其解~最后还是用了一个很笨的方法,来解决的。说出来不怕笑话啊,就是把SConscript文件拆成了两个SConscript1和SConscript2,SConscript1完成env.Java();SConscript2 完成env.Command()和env.Jar()。如果哪位高手知道解决办法,还望指导一二。

下面是我收集的一些scons的相关资料,与大家共享。

scons简介

scons是一个用Python写的自动化构建工具。形象地说,scons就是这样一个构建工具:你告诉它要做的任务,以及必要的输入和输出,至于怎么做这个任务,scons自己去完成。 从构建的角度讲,sconsGNU make是同一类的工具。它是一种改进的、跨平台的GNU make的替代工具,其集成功能类似于autoconf/automake。相比较而言,scons是一个更简便、更可靠、更高效的编译软件。scons 还具有良好的夸平台性,可以运行在 Linux, AIX, BSD, HP/UX, IRIX, Solaris, Windows, Mac OS X OS/2 上。但用户需要安装pythonscons之后才能运行。scons与其它构建工具的一个显著的区别就是其配置文件是python scriptscons的构建思想与GNUmake是完全不同的,GNU make的核心是依赖关系,所以GNU提供Automaker来分析依赖性,辅助程序员产生makefile。而scons会自己找依赖关系,这个主要是借助于内部的scanner来扫描有改动的文件,然后才去编译链接生成可执行程序。


scons使用

2.1 基于python的配置文件

scons中可能出现的配置文件:SConstruct,SConstruct,SConstruct,SConscriptscons将在当前目录以下次序 SConstruct,SConstruct,SConstruct 来搜索配置文件,从读取的第一个文件中读取相关配置。在配置文件SConstruct中可以使用函数SConscript()函数来定附属的配置文件。按惯例,这些附属配置文件被命名为”SConscript”,当然也可以使用任意其它名字。 scons通过决定哪个具体的模块必须被rebuild,并执行相关的命令来进行rebuild。默认情况下,scons将在当前目录以以下次序(SConstruct,SConstruct,SConstruct)来搜索配置文件,从读取的第一个文件中读取相关配置。我们可以通过-f选项来指定替代的配置文件,具体方法如下:

scons –f configfilename

scons中的配置文件SConscriptpython脚本编写,所以我们能使用python脚本的灵活性来处理复杂的buildscons在读取和执行所有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命令编译这个程序。在LinuxUnix系统上,你会看到如下输出:

% 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也很容易了。不像ProgramObject两个编译方法,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'))

两个关键字可以直接指明targetsource,所以在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调用,这些都是高级一些的功能,这里不细说,详情可参见Sconsdoc


 

参考资料:

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.html

http://550480286.blog.163.com/blog/static/99093247201077113029413/



0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有