您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 使用WAnt-构建你的Delphi-项目
使用WAnt构建你的Delphi项目李研2005-01-08本文版权归李研和《程序员》杂志社所有,保留所有权利。欢迎意见和指正,请发至elliot.li@gmail.com。版本:$Id:essay.tex102006-06-0300:22:11Zyan$1简介XP(eXtremeProgramming)的相关实践已经被越来越多的人所了解和接受,而且越来越多的成功案例证明其对小型的项目和团队来讲比较有效。笔者历来重视XP中的任务自动化,这里我给大家介绍一下WAnt工具(),用以支持BorlandDelphi项目的从构建(build)、测试到提交(commit)、发布(release)的全套自动化工作。WAnt可以看作是著名的ApacheAnt()的Delphi版本,采用几乎完全相同的XML构建脚本,在开源社区中正在被越来越多的项目采用,比如著名的DUnit就是用WAnt进行构建。在本文中,笔者通过分析DUnit的WAnt构建脚本,来给大家介绍WAnt的相关概念,其中穿插了笔者实践中的经验。文章最后介绍了WAnt与Subversion和DUnit合作使用(笔者最喜欢的阵容之一)时的实际经验。熟悉Ant的朋友应该可以很快上手使用WAnt,但是本文并不需要读者有Ant经验。读者朋友对构建、测试、发布自动化的意义,思想以及目的应该有所了解。另外需要了解XML的简单概念。2WAnt/Ant的基本概念我在这里先简单介绍一下WAnt/Ant的基本概念。WAnt/Ant功能上类似于ant、make等构建工具,不过采用XML格式的构建脚本,可以执行构建、测试、提交、打包、发布、上传、发送邮件等等任何你能想到的任务(只要有相关的命令行工具支持)。你所要做的就是写一个want脚本,放在项目根目录,然后在需要的时候,执行want.exe来做你想要进行的任务。对于没写过XML构建脚本的朋友,下面的代码可能看起来有些吓人,但是他们确实都很简单,而且一般情况下,我们不需要手工书写自动构建脚本中的每个字,而是找一个以前项目的构建脚本略加更改即可使用。所以大家也不必费心去记忆相关细节。13WANT经验:DUNIT的WANT.XML分析2在文中,我会着重分析脚本的设计目的以及在实践工作中的用处,而不是钻研语法细节,望文而知意语句尽量略过。对于XML和Ant的更深入学习,请参阅相关资料。编写自动构建脚本的基本思路是:所有能自动化的工作,都尽量自动化。这包括:清除临时文件、建立所需的目录、修改版本号、编译、测试、在版本仓库中打标签(tag)、压缩打包等等。从而人们就可以把精力集中在具有创造力的工作上了,比如编写代码和单元测试,在必要的时候调整一下主版本号等等。3WAnt经验:DUnit的want.xml分析我下面分析的是DUnit9.0.5的want.xml,你可以从sourceforgeDUnitCVSrepository上得到它,也可以直接用浏览器查看=1.39&view=auto。我们从头来看:projectname=DUnitExtremeTestingFrameworkforDelphidefault=testbasedir=.WAnt/Ant构建脚本的root是project,name属性是project的名字,可以随需填写。project是由target构成的,每个target就是一项任务,比如编译、测试、打包等等。default属性指明了不加参数启动want.exe时默认执行的任务。一般将其设为test,因为这是我们平常使用最多的任务。basedir是一个property,你可以将其看作一个变量,在脚本中任意位置都可以通过${basedir}来引用。我们一般将basedir设置为“.”,表示want.xml文件所在的目录,就是项目的根目录。propertyname=dunit.releasevalue=%{DUNIT_RELEASE}/(1)propertyname=app.namevalue=dunit/propertyname=old.versionvalue=?{release.ini:releases:current}/(2)regexpproperty=old.buildtext=${old.version}pattern=^.*\.([0-9]+)$subst=\1/(3)propertyname=buildvalue=={1+${old.build}}if=dunit.release/(4)3WANT经验:DUNIT的WANT.XML分析3propertyname=buildvalue=${old.build}unless=dunit.release/regexpproperty=versiontext=${old.version}pattern=\.[0-9]*$subst=.${build}/(5)regexpproperty=comma.versionpattern=\.subst=,text=${version}/这一段是用来处理“项目的版本号”的。先不要去管语法细节,我们来看这一段的设计目标:通过“环境变量DUNIT_RELEASE是否存在”来控制是否进行“发布(release)”。如果要“发布”,则项目的build号(即版本号中最后一部分,例如9.0.5中的5)自动增1;如果不“发布”,继续采用原版本号。版本号记录在release.ini中(这个文件和want.xml一起,放在项目目录的根目录,也纳入版本管理系统)。这类似于Delphi中的Auto-incrementbuildnumber,不过这里的设计更加好用,而且适合于自动构建以及团队协调工作。平常我们在调试、编写代码的时候,会经常调用WAnt,而在代码调试通过以前,我们并不希望每次编译都改动版本号,因为那样会使版本号演进太快,难于管理。只有在我们觉得合适的时候(比如Nightlybuild、项目发布的时候),所有的更动都已测试通过并且提交(commit),需要发布了,我们才需要改动项目的版本号。这也是实现每晚构建(Nightly-build)所需的基本功能。如果需要改动除了build号主版本号或次版本号,只需手工修改release.ini文件即可。然后我们来看实现方法:property用来定义一个变量,变量名为name,值为value,非常容易理解。欲在以后引用此变量,就像这样写:${build}。(1)表示dunit.release是否被设置取决于环境变量DUNIT_RELEASE,这个dunit.release会在以后被用来判断build号是否要增1;(2)从release.ini的releases节的current键中读入当前版本号,赋给old.version;(3)使用正则表达式来从old.version中析出old.build;(4)如果设置了dunit.release,则build增1,否则不增;(5)用build来替换掉old.version中的原build号;tstampformatproperty=whenpattern=yyyy,mm,dd,HH,nn,ss/3WANT经验:DUNIT的WANT.XML分析4formatproperty=date.tagpattern=yyyy-mm-dd//tstamptstamp定义两个变量when和data.tag,其内容为当前时间。propertyname=src.dirvalue=${basedir}/src/propertyname=doc.dirvalue=${basedir}/doc/propertyname=test.dirvalue=${basedir}/tests/propertyname=etc.dirvalue=${basedir}/etc/propertyname=samp.dirvalue=${basedir}/examples/propertyname=scratch.dirvalue=${basedir}/scratch/propertyname=bin.dirvalue=${basedir}/bin/propertyname=dist.dirvalue=${basedir}/dist/propertyname=framework.dirvalue=${basedir}/framework/propertyname=contrib.dirvalue=${basedir}/contrib/将项目的目录定义为变量,便于下文引用,也便于以后统一修改。在我们自己的项目中,按照自己的习惯定义即可。这里介绍一下开源社区一般的习俗:README项目说明文件,存放在根目录;want.xml构建脚本,存放在根目录;src目录存放源码;doc目录存放文档,比如变更说明CHANGELOG,代码规范HACKING等等;tests目录存放测试程序;scratch目录存放构建中间文件,比如obj、dcp等等;bin目录存放构建结果;lib目录存放用到的库文件;etc目录存放其它文件,比如DUnit的versioninfo模板就放在etc目录。targetname=preparedescription=builddirectorystructuremkdirdir=${scratch.dir}/mkdirdir=${bin.dir}/mkdirdir=${framework.dir}//target3WANT经验:DUNIT的WANT.XML分析5targetname=cleandeletedir=${scratch.dir}/deletedir=${bin.dir}/deletedir=${framework.dir}//target可以说是约定成俗,每个WAnt/Ant项目中几乎都会有这么几个target:clean清除上次构建遗留的文件,使之不要干扰本次的构建;prepare有时也叫init,用来进行编译前的准备工作,一般是建立存放编译中间文件和结果的目录(如上段代码所示的scratch目录);versioninfo根据version变量来设置源代码文件中的版本号变量,使发布程序中各处的版本号保持一致(比如启动界面、About窗口、日志信息、资源段等等),详见下文;compile有时也叫build,即执行构建操作;test自动测试;tag自动在版本仓库中打标签;package将结果自动打包形成zip发布包,或是执行InstallShield之类的工具来生成安装文件;dist发布。一般是clean、prepare、versioninfo、compile、test、tag、packge的顺序执行。注意:任务并不是按从上到下的顺序执行的,而是要你在命令行上指定执行哪个任务。也不需要考虑向前引用(forwardreference)的问题,所以clean不必放在prepare之前。在每个target里面,执行顺序是从上到下的。targetname=versioninfodepends=prepareregexpproperty=comma.versionpattern=\.0*([1-9]*[0-9])subst=,\1text=${version}/echoinput=${etc.dir}/versioninfo.template.rc(1)file=${src.dir}/versioninfo.rc/echoinput=${etc.dir}/versioninfo.template
本文标题:使用WAnt-构建你的Delphi-项目
链接地址:https://www.777doc.com/doc-3760978 .html