ANT安装配置笔记和最佳实践

 
  1. ANT的安装/配置笔记
  2. 作者:车东 发表于:2003-03-06 17:03 最后更新于:2007-04-12 11:04
  3. 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明。
  4. http://www.chedong.com/tech/ant.html 
  5. --------------------------------------------------------------------------------
  6. 内容摘要:
  7. ant是一个基于JAVA的自动化脚本引擎,脚本格式为XML。除了做JAVA编译相关任务外,ANT还可以通过插件实现很多应用的调用。
  8. ANT的基本概念: 
  9. ANT的安装:解包,设置路径 
  10. ANT的使用:最好的学习只不过是一个简单实用的例子起步…… 
  11. ANT的基本概念:Java的Makefile
  12. 当一个代码项目大了以后,每次重新编译,打包,测试等都会变得非常复杂而且重复,因此c语言中有make脚本来帮助这些工作的批量完成。在Java 中应用是平台无关性的,当然不会用平台相关的make脚本来完成这些批处理任务了,ANT本身就是这样一个流程脚本引擎,用于自动化调用程序完成项目的编译,打包,测试等。除了基于JAVA是平台无关的外,脚本的格式是基于XML的,比make脚本来说还要好维护一些。
  13. 每个ant脚本(缺省叫build.xml)中设置了一系列任务(target):比如对于一个一般的项目可能需要有以下任务。
  14. 任务1:usage 打印本脚本的帮助信息(缺省) 
  15. 任务2:clean <-- init 清空初始化环境 
  16. 任务3:javadoc <-- build <-- init 生成JAVADOC 
  17. 任务4:jar <-- build <-- init 生成JAR 
  18. 任务5:all <-- jar + javadoc <-- build <-- init 完成以上所有任务:jar javadoc 
  19. 而多个任务之间往往又包含了一定了依赖关系:比如把整个应用打包任务(jar)的这个依赖于编译任务(build),而编译任务又依赖于整个环境初始化任务(init)等。
  20. 注:我看到很多项目的ant脚本中的命名基本上都是一致的,比如:编译一般叫build或者compile;打包一般叫jar或war;生成文档一般命名为javadoc或javadocs;执行全部任务all。在每个任务的中,ANT会根据配置调用一些外部应用并配以相应参数执行。虽然ANT可调用的外部应用种类非常丰富,但其实最常用的就23个:比如javac javadoc jar等。 
  21. ANT的安装
  22. 解包后在系统可执行路径中加入指向ant的bin的路径就可以了,比如可以在GNU/Linux上把以下配置加入/etc/profile中:
  23. export ANT_HOME=/home/ant
  24. export JAVA_HOME=/usr/java/j2sdk1.4.1
  25. export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin
  26. 这样执行ant 后,如果不指定配置文件ant会缺省找build.xml这个配置文件,并根据配置文件执行任务,缺省的任务设置可以指向最常用的任务,比如: build,或指向打印帮助信息:usage,告诉用户有那些脚本选项可以使用。
  27. ANT的使用
  28. 最好的学习过程就是看懂那些open source项目中的build.xml脚本,然后根据自己的需要简化成一个更简单的,ANT和APACHE上很多非常工程派的项目:简单易用,而且适应性非常强,因为这些项目的建立往往来源于开发人员日常最直接的需求。
  29. 以下是的一个WebLucene应用的例子:修改自JDOM的build.xml:
  30. <project default="usage" basedir=".">
  31.   <!-- =================================================================== -->
  32.   <!-- Initialization target                                               -->
  33.   <!-- =================================================================== -->
  34.   <target name="init">
  35.     <tstamp/>
  36.     <property file="${basedir}/build.properties" />
  37.     <property name="Name" value="ProjectFullName"/>
  38.     <property name="name" value="project_name"/>
  39.     <property name="version" value="0.2"/>
  40.     <property name="year" value="2003"/>
  41.     <echo message="----------- ${Name} ${version} [${year}] ------------"/>
  42.     <property name="debug" value="off"/>
  43.     <property name="optimize" value="on"/>
  44.     <property name="deprecation" value="on"/>
  45.     <property name="src.dir" value="./src/WEB-INF/src"/>
  46.     <property name="lib.dir" value="./src/WEB-INF/lib"/>
  47.     <property name="packages" value="com.chedong.*,org.apache.lucene.*"/>
  48.     <property name="build.src" value="./src/WEB-INF/build"/>
  49.     <property name="build.dest" value="./src/WEB-INF/classes"/>
  50.     <property name="build.javadocs" value="./src/doc"/>
  51.     
  52.     <path id="classpath">
  53.         <pathelement path="${jsdk_jar}"/>
  54.         <fileset dir="${lib.dir}">
  55.            <include name="**/*.jar"/>
  56.         </fileset>
  57.     </path>
  58.     
  59.     <filter token="year" value="${year}"/>
  60.     <filter token="version" value="${version}"/>
  61.     <filter token="date" value="${TODAY}"/>
  62.     <filter token="log" value="true"/>
  63.     <filter token="verbose" value="true"/>
  64.   </target>
  65.   <!-- =================================================================== -->
  66.   <!-- Help on usage                                                       -->
  67.   <!-- =================================================================== -->
  68.   <target name="usage" depends="init">
  69.     <echo message="${Name} Build file"/>
  70.     <echo message="-------------------------------------------------------------"/>
  71.     <echo message=""/>
  72.     <echo message=" available targets are:"/>
  73.     <echo message=""/>
  74.     <echo message="   jar      --> generates the ${name}.jar file"/>
  75.     <echo message="   build    --> compiles the source code"/>
  76.     <echo message="   javadoc  --> generates the API documentation"/>
  77.     <echo message="   clean    --> cleans up the directory"/>
  78.     <echo message=""/>
  79.     <echo message=" Please rename build.properties.default to build.properties"/>
  80.     <echo message=" and edit build.properties to specify JSDK 2.3 classpath."/>
  81.     <echo message=""/>
  82.     <echo message=" See the comments inside the build.xml file for more details."/>
  83.     <echo message="-------------------------------------------------------------"/>
  84.     <echo message=""/>
  85.     <echo message=""/>
  86.   </target>
  87.   <!-- =================================================================== -->
  88.   <!-- Prepares the source code                                            -->
  89.   <!-- =================================================================== -->
  90.   <target name="prepare-src" depends="init">
  91.     <!-- create directories -->
  92.     <mkdir dir="${build.src}"/>
  93.     <mkdir dir="${build.dest}"/>
  94.     
  95.     <!-- copy src files -->
  96.     <copy todir="${build.src}">
  97.       <fileset dir="${src.dir}"/>
  98.     </copy>
  99.   </target>
  100.   <!-- =================================================================== -->
  101.   <!-- Compiles the source directory                                       -->
  102.   <!-- =================================================================== -->
  103.   <target name="build" depends="prepare-src">
  104.     <javac srcdir="${build.src}"
  105.            destdir="${build.dest}"
  106.            debug="${debug}"
  107.            optimize="${optimize}">
  108.       <classpath refid="classpath"/>
  109.     </javac>
  110.   </target>
  111.   <!-- =================================================================== -->
  112.   <!-- Creates the class package                                           -->
  113.   <!-- =================================================================== -->
  114.   <target name="jar" depends="build">
  115.     <jar jarfile="${lib.dir}/${name}.jar"
  116.          basedir="${build.dest}"
  117.          includes="**"/>
  118.   </target>
  119.   <!-- =================================================================== -->
  120.   <!-- Creates the API documentation                                       -->
  121.   <!-- =================================================================== -->
  122.   <target name="javadoc" depends="build">
  123.     <mkdir dir="${build.javadocs}"/>
  124.     <javadoc packagenames="${packages}"
  125.              sourcepath="${build.src}"
  126.              destdir="${build.javadocs}"
  127.              author="true"
  128.              version="true"
  129.              use="true"
  130.              splitindex="true"
  131.              windowtitle="${Name} API"
  132.              doctitle="${Name}">
  133.       <classpath refid="classpath"/>
  134.     </javadoc>
  135.   </target>
  136.   <!-- =================================================================== -->
  137.   <!-- Clean targets                                                       -->
  138.   <!-- =================================================================== -->
  139.   <target name="clean" depends="init">
  140.     <delete dir="${build.src}"/>
  141.     <delete dir="${build.dest}/org"/>
  142.     <delete dir="${build.dest}/com"/>
  143.     <delete>
  144.       <fileset dir="${build.dest}" includes="**/*.class"/>
  145.     </delete>
  146.   </target>
  147. </project>
  148. <!-- End of file -->
  149. 缺省任务:usage 打印帮助文档,告诉有那些任务选项:可用的有build, jar, javadoc和clean.
  150. 初始化环境变量:init
  151. 所有任务都基于一些基本环境变量的设置初始化完成,是后续其他任务的基础,在环境初始化过程中,有2点比较可以方便设置:
  152. 1 除了使用却缺省的property设置了JAVA源路径和输出路径外,引用了一个外部的build.properties文件中的设置,
  153. <property file="${basedir}/build.properties" />
  154. 这样大部分简单配置用户只要会看懂build.properties就可以了,毕竟XML比起key value的属性文件还是要可读性差一些。用build.properties也可以方便其他用户从编译的细节中解放出来。
  155. 2 CLASSPATH设置:使用了其中的:
  156.     <path id="classpath">
  157.         <pathelement path="${jsdk_jar}"/>
  158.         <fileset dir="${lib.dir}">
  159.            <include name="**/*.jar"/>
  160.         </fileset>
  161.     </path>
  162. 则相当于设置了:CLASSPATH=/path/to/resin/lib/jsdk23.jar; /path/to/project/lib/*.jar;
  163. 文件复制:prepare-src
  164. 创建临时SRC存放目录和输出目录。
  165.   <!-- =================================================================== -->
  166.   <!-- Prepares the source code                                            -->
  167.   <!-- =================================================================== -->
  168.   <target name="prepare-src" depends="init">
  169.     <!-- create directories -->
  170.     <mkdir dir="${build.src}"/>
  171.     <mkdir dir="${build.dest}"/>
  172.     
  173.     <!-- copy src files -->
  174.     <copy todir="${build.src}">
  175.       <fileset dir="${src.dir}"/>
  176.     </copy>
  177.   </target>
  178. 编译任务:build
  179. 编译时的CLASSPATH环境通过一下方式找到引用一个path对象
  180. <classpath refid="classpath"/>
  181. 打包任务:jar
  182. 对应用打包生成项目所写名的.jar文件
  183.   <!-- =================================================================== -->
  184.   <!-- Creates the class package                                           -->
  185.   <!-- =================================================================== -->
  186.   <target name="jar" depends="build">
  187.     <jar jarfile="${lib.dir}/${name}.jar"
  188.          basedir="${build.dest}"
  189.          includes="**"/>
  190.   </target>
  191. 生成JAVADOC文档任务: javadoc
  192.   <!-- =================================================================== -->
  193.   <!-- Creates the API documentation                                       -->
  194.   <!-- =================================================================== -->
  195.   <target name="javadoc" depends="build">
  196.     <mkdir dir="${build.javadocs}"/>
  197.     <javadoc packagenames="${packages}"
  198.              sourcepath="${build.src}"
  199.              destdir="${build.javadocs}"
  200.              author="true"
  201.              version="true"
  202.              use="true"
  203.              splitindex="true"
  204.              windowtitle="${Name} API"
  205.              doctitle="${Name}">
  206.       <classpath refid="classpath"/>
  207.     </javadoc>
  208.   </target>
  209. 清空临时编译文件:clean
  210.   <!-- =================================================================== -->
  211.   <!-- Clean targets                                                       -->
  212.   <!-- =================================================================== -->
  213.   <target name="clean" depends="init">
  214.     <delete dir="${build.src}"/>
  215.     <delete dir="${build.dest}/org"/>
  216.     <delete dir="${build.dest}/com"/>
  217.     <delete>
  218.       <fileset dir="${build.dest}" includes="**/*.class"/>
  219.     </delete>
  220.   </target>
  221. TODO:
  222. 更多任务/扩展:(样例)
  223. 测试任务:JUnit测试 
  224. 代码风格检查任务:CheckStyle,Jalopy等 
  225. 邮件警报任务:可以把以上这些任务的输出警告发送到制定的用户列表中,这个任务可以设置每天自动运行。 
  226. 参考资料:
  227. Jakarta ANT:
  228. http://ant.apache.org
  229. ANT十五大最佳实践
  230. 作者:Eric M. Burke, coauthor of Java Extreme Programming Cookbook
  231. 原文:http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html
  232. 译者:徐彤MSN:xt121@hotmail.com
  233. 在Ant出现之前,构建和部署Java应用需要使用包括特定平台的脚本、Make文件、各种版本的IDE甚至手工操作的“大杂烩”。现在,几乎所有的开源Java项目都在使用Ant,大多数公司的内部项目也在使用Ant。Ant在这些项目中的广泛使用自然导致了读者对一整套Ant最佳实践的迫切需求。
  234. 本文总结了我喜爱的Ant技巧或最佳实践,多数是从我亲身经历的项目错误或我听说的其他人经历的 “恐怖”故事中得到灵感的。比如,有人告诉我有个项目把XDoclet 生成的代码放入带有锁定文件功能的版本控制工具中。当开发者修改源代码时,他必须记住手工检出(Check out)并锁定所有将要重新生成的文件。然后,手工运行代码生成器,只到这时他才能够让Ant编译代码,这一方法还存在如下一些问题:
  235. 生成的代码无法存储在版本控制系统中。 
  236. Ant(本案例中是Xdoclet)应该自动确定下一次构建涉及的源文件,而不应由程序员手工确定。 
  237. Ant的构建文件应该定义好正确的任务依赖关系,这样程序员就不必为了完成构建而不得不按照特定顺序调用任务。 
  238. 当我开始一个新项目时,我首先编写Ant构建文件。Ant文件明确地定义构建的过程,并被团队中的每个程序员使用。本文所列的技巧基于这样的假定:Ant构建文件是一个必须仔细编写的重要文件,它应在版本控制系统中得到维护,并被定期进行重构。下面是我的十五大Ant最佳实践。
  239. 1. 采用一致的编码规范
  240. Ant用户有的喜欢有的痛恨其构建文件的XML语法。与其跳进这一令人迷惑的争论中,不如让我们先看一些能保持XML构建文件简洁的方法。
  241. 首先也是最重要的,花费时间格式化你的XML让它看上去很清晰。不论XML是否美观,Ant都可以工作。但是丑陋的XML很难令人读懂。倘若你在任务之间留出空行,有规则的缩进,每行文字不超过90列左右,那么XML令人惊讶地易读。再加上使用能够高亮XML语法的优秀编辑器或IDE工具,你就不会有阅读的麻烦。
  242. 同样,精选含意明确、容易读懂的词汇来命名任务和属性。比如,dir.reports就比rpts好。特定的编码规范并不重要,只要拿出一套规范并坚持使用就行。
  243. 2. 将build.xml放在项目根目录中
  244. Ant构建文件build.xml可以放在任何位置,但是放在项目顶级目录中可以保持项目简洁。这是最常用的规范,开发者能够在顶级目录中找到预期的build.xml。把构建文件放在根目录中,也能够使人容易了解项目目录树中不同目录之间的逻辑关系。以下是一个典型的项目目录层次:
  245. [root dir]
  246.   | build.xml  
  247.   +--src 
  248.   +--lib (包含第三方 JAR包) 
  249.   +--build (由 build任务生成)  
  250.   +--dist (由 build任务生成) 
  251. 当build.xml在顶级目录时,假设你处于项目某个子目录中,只要输入:ant -find compile 命令,不需要改变工作目录就能够以命令行方式编译代码。参数-find告诉Ant寻找存在于上级目录中的build.xml并执行。
  252. 3. 使用单一的构建文件
  253. 有人喜欢将一个大项目分解成几个小的构建文件,每个构建文件分担整个构建过程的一小部分工作。这确实是看法不同的问题,但是应该认识到,将构建文件分割会增加对整体构建过程的理解难度。要注意在单一构建文件能够清楚表现构建层次的情况下不要过工程化(over-engineer)。
  254. 即使你把项目划分为多个构建文件,也应使程序员能够在项目根目录下找到核心build.xml。尽管该文件只是将实际构建工作委派给下级构建文件,也应保证该文件可用。
  255. 4. 提供良好的帮助说明
  256. 应尽量使构建文件自文档化。增加任务描述是最简单的方法。当你输入ant -projecthelp时,你就可以看到带有描述的任务清单。比如,你可以这样定义任务:
  257. <target name="compile"  
  258.    description="Compiles code, output goes to the build dir."
  259. 最简单的规则是把所有你想让程序员通过命令行就可以调用的任务都加上描述。对于一般用来执行中间处理过程的内部任务,比如生成代码或建立输出目录等,就无法使用描述属性。
  260. 这时,可以通过在构建文件中加入XML注释来处理。或者专门定义一个help任务,当程序员输入ant help时来显示详细的使用说明。
  261. <target name="help" description="Display detailed usage information">
  262.   <echo>Detailed help...</echo></target> 
  263. 5. 提供清除任务
  264. 每个构建文件都应包含一个清除任务,用来删除所有生成的文件和目录,使系统回到构建文件执行前的初始状态。执行清空任务后还存在的文件都应处在版本控制系统的管理之下。比如:
  265. <target name="clean" 
  266.     description="Destroys all generated files and dirs.">
  267.   <delete dir="${dir.build}"/>
  268.   <delete dir="${dir.dist}"/>
  269. </target> 
  270. 除非是在产生整个系统版本的特殊任务中,否则不要自动调用clean任务。当程序员仅仅执行编译任务或其他任务时,他们不需要构建文件事先执行既令人讨厌又没有必要的清空任务。要相信程序员能够确定何时需要清空所有文件。
  271. 6. 使用ANT管理任务从属关系
  272. 假设你的应用由Swing GUI组件、Web界面、EJB层和公共应用代码组成。在大型系统中,你需要清晰地定义每个Java包属于系统的哪一层。否则任何一点修改都要被迫重新编译成百上千个文件。糟糕的任务从属关系管理会导致过度复杂而脆弱的系统。改变GUI面板的设计不应造成Servlet和EJB的重编译。
  273. 当系统变得庞大后,稍不注意就可能将依赖于客户端的代码引入到服务端。这是因为典型的IDE项目文件编译任何文件都使用单一的classpath。而Ant能让你更有效地控制构建活动。
  274. 设计你的Ant构建文件编译大型项目的步骤:首先,编译公共应用代码,将编译结果打成JAR包文件。然后,编译上一层的项目代码,编译时依靠第一步产生的JAR文件。不断重复这一过程,直到最高层的代码编译完成。
  275. 分步构建强化了任务从属关系管理。如果你工作在底层Java框架上,偶然引用到高层的GUI模板组件,这时代码不需要编译。这是由于构建文件在编译底层框架时在源路径中没有包含高层GUI面板组件的代码。
  276. 7. 定义并重用文件路径
  277. 如果文件路径在一个地方一次性集中定义,并在整个构建文件中得到重用,那么构建文件更易于理解。以下是这样做的一个例子:
  278. <project name="sample" default="compile" basedir=".">
  279.   <path id="classpath.common">
  280.     <pathelement location="${jdom.jar.withpath}"/>
  281.     ...etc  </path>
  282.   <path id="classpath.client">
  283.     <pathelement location="${guistuff.jar.withpath}"/>
  284.     <pathelement location="${another.jar.withpath}"/>
  285.     <!-- reuse the common classpath -->
  286.     <path refid="classpath.common"/>
  287.   </path>
  288.   <target name="compile.common" depends="prepare">
  289.     <javac destdir="${dir.build}" srcdir="${dir.src}">
  290.           <classpath refid="classpath.common"/>
  291.           <include name="com/oreilly/common/**"/>
  292.     </javac>
  293.   </target>
  294. </project> 
  295. 当项目不断增长构建日益复杂时,这一技术越发体现出其价值。你可能需要为编译不同层次的应用定义各自的文件路径,比如运行单元测试的、运行应用程序的、运行Xdoclet的、生成JavaDocs的等等不同路径。这种组件化路径定义的方法比为每个任务单独定义路径要优越得多。否则,很容易丢失任务从属关系的轨迹。
  296. 8. 定义恰当的任务从属关系
  297. 假设dist任务从属于jar任务,那么哪个任务从属于compile任务哪个任务从属于prepare任务呢?Ant构建文件最终定义了任务的从属关系图,它必须被仔细地定义和维护。
  298. 应该定期检查任务的从属关系以保证构建工作得到正确执行。大的构建文件随着时间推移趋向于增加更多的任务,所以到最后可能由于不必要的从属关系导致构建工作非常困难。比如,你可能发现在程序员只需编译一些没有使用EJB的GUI代码时又重新生成了EJB代码。
  299. 以“优化”的名义忽略任务的从属关系是另一种常见的错误。这种错误迫使程序员为了得到恰当的结果必须记住并按照特定的顺序调用一串任务。更好的做法是:提供描述清晰的公共任务,这些任务包含正确的任务从属关系;另外提供一套“专家”任务让你能够手工执行个别的构建步骤,这些任务不提供完整的构建过程,但是让那些专家用户在快速而恼人的编码期间能够跳过某些步骤。
  300. 9.使用属性
  301. 任何需要配置或可能发生变化的信息都应作为Ant属性定义下来。对于在构建文件中多次出现的值也同样处理。属性既可以在构建文件头部定义,也可以为了更好的灵活性而在单独的属性文件中定义。以下是在构建文件中定义属性的样式:
  302. <project name="sample" default="compile" basedir=".">
  303.   <property name="dir.build" value="build"/>
  304.   <property name="dir.src" value="src"/>
  305.   <property name="jdom.home" value="../java-tools/jdom-b8"/>
  306.   <property name="jdom.jar" value="jdom.jar"/>
  307.   <property name="jdom.jar.withpath"
  308.                     value="${jdom.home}/build/${jdom.jar}"/>
  309.     etc...
  310. </project> 
  311. 或者你可以使用属性文件:
  312. <project name="sample" default="compile" basedir=".">
  313.   <property file="sample.properties"/>
  314.    etc...
  315. </project> 
  316. 在属性文件 sample.properties中:
  317. dir.build=build
  318. dir.src=src
  319. jdom.home=../java-tools/jdom-b8
  320. jdom.jar=jdom.jarjdom.jar.withpath=${jdom.home}/build/${jdom.jar} 
  321. 用一个独立的文件定义属性是有好处的,它可以清晰地定义构建中的可配置部分。另外,在开发者工作在不同操作系统的情况下,你可以在不同的平台上提供该文件的不同版本。
  322. 10. 保持构建过程独立
  323. 为了最大限度的扩展性,不要应用外部路径和库文件。最重要的是不要依赖于程序员的CLASSPATH设置。取而代之的是,在构建文件中使用相对路径并定义自己的路径。如果你引用了绝对路径如C:java ools,其他开发者未必使用与你相同的目录结构,所以就无法使用你的构建文件。
  324. 如果你部署开放源码项目,应该提供包含编译代码所需的所有JAR文件的发行版本。当然,这是在遵守许可协议的基础上。对于内部项目,相关的JAR文件都应在版本控制系统的管理中,并捡出(check out)到大家都知道的位置。
  325. 当你必须引用外部路径时,应将路径定义为属性。使程序员能够用适合他们自己的机器环境的参数重载这些属性。你也可以使用以下语法引用环境变量:
  326. <property environment="env"/>
  327. <property name="dir.jboss" value="${env.JBOSS_HOME}"/> 
  328. 11. 使用版本控制系统
  329. 构建文件是一个重要的制品,应该像代码一样进行版本控制。当你标记你的代码时,也应用同样的标签标记构建文件。这样当你需要回溯到旧版本并进行构建时,能够使用相应版本的构建文件。
  330. 除构建文件之外,你还应在版本控制中维护第三方JAR文件。同样,这使你能够重新构建旧版本的软件。这也能够更容易保证所有开发者拥有一致的JAR文件,因为他们都是同构建文件一起从版本控制系统中捡出的。
  331. 通常应避免在版本控制系统中存放构建成果。倘若你的源代码很好地得到了版本控制,那么通过构建过程你能够重新生成任何版本的产品。
  332. 12. 把Ant作为“最小公分母”
  333. 假设你的开发团队使用IDE工具,当程序员通过点击图标就能够构建整个应用时为什么还要为Ant而烦恼呢?
  334. IDE的问题是一个关于团队一致性和重现性的问题。几乎所有的IDE设计初衷都是为了提高程序员的个人生产率,而不是开发团队的持续构建。典型的IDE要求每个程序员定义自己的项目文件。程序员可能拥有不同的目录结构,可能使用不同版本的库文件,还可能工作在不同的平台上。这将导致出现这种情况:在Bob那里运行良好的代码,到Sally那里就无法运行。
  335. 不管你的开发团队使用何种IDE,一定要建立所有程序员都能够使用的Ant构建文件。要建立一个程序员在将新代码提交版本控制系统前必须执行Ant构建文件的规则。这将确保代码是经过同一个Ant构建文件构建的。当出现问题时,要使用项目标准的Ant构建文件,而不是通过某个IDE来执行一个干净的构建。
  336. 程序员可以自由选择任何他们习惯使用的IDE工具或编辑器。但是Ant应作为公共基线以保证代码永远是可构建的。
  337. 13. 使用zipfileset属性
  338. 人们经常使用Ant产生WAR、JAR、ZIP和 EAR文件。这些文件通常都要求有一个特定的内部目录结构,但其往往与你的源代码和编译环境的目录结构不匹配。
  339. 一个最常用的方法是写一个Ant任务,按照期望的目录结构把一大堆文件拷贝到临时目录中,然后生成压缩文件。这不是最有效的方法。使用zipfileset属性是更好的解决方案。它让你从任何位置选择文件,然后把它们按照不同目录结构放进压缩文件中。以下是一个例子:
  340. <ear earfile="${dir.dist.server}/payroll.ear"
  341.     appxml="${dir.resources}/application.xml">
  342.   <fileset dir="${dir.build}" includes="commonServer.jar"/>
  343.   <fileset dir="${dir.build}">
  344.     <include name="payroll-ejb.jar"/>
  345.   </fileset>
  346.   <zipfileset dir="${dir.build}" prefix="lib">
  347.     <include name="hr.jar"/>
  348.     <include name="billing.jar"/>
  349.   </zipfileset>
  350.   <fileset dir=".">
  351.     <include name="lib/jdom.jar"/>
  352.     <include name="lib/log4j.jar"/>
  353.     <include name="lib/ojdbc14.jar"/>
  354.   </fileset>
  355.   <zipfileset dir="${dir.generated.src}" prefix="META-INF">
  356.     <include name="jboss-app.xml"/>
  357.   </zipfileset>
  358. </ear> 
  359. 在这个例子中,所有JAR文件都放在EAR文件包的lib目录中。hr.jar和billing.jar是从构建目录拷贝过来的。因此我们使用zipfileset属性把它们移动到EAR文件包内部的lib目录。prefix属性指定了其在EAR文件中的目标路径。
  360. 14. 测试Clean任务
  361. 假设你的构建文件中有clean和compile的任务,执行以下的测试。第一步,执行ant clean;第二步,执行ant compile;第三步,再执行ant compile。第三步应该不作任何事情。如果文件再次被编译,说明你的构建文件有问题。
  362. 构建文件应该只在与输出文件相关联的输入文件发生变化时执行任务。一个构建文件在不必执行诸如编译、拷贝或其他工作任务的时候执行这些任务是低效的。当项目规模增长时,即使是小的低效工作也会成为大的问题。
  363. 15. 避免特定平台的Ant封装
  364. 不管什么原因,有人喜欢用简单的、名称叫做compile之类的批文件或脚本装载他们的产品。当你去看脚本的内容你会发现以下内容:
  365. ant compile
  366. 其实开发人员都很熟悉Ant,并且完全能够自己键入ant compile。请不要仅仅为了调用Ant而使用特定平台的脚本。这只会使其他人在首次使用你的脚本时增加学习和理解的烦扰。除此之外,你不可能提供适用于每个操作系统的脚本,这是真正烦扰其他用户的地方。
  367. 总结
  368. 太多的公司依靠手工方法和特别程序来编译代码和生成软件发布版本。那些不使用Ant或类似工具定义构建过程的开发团队,花费了太多的时间来捕捉代码编译过程中出现的问题:在某些开发者那里编译成功的代码,到另一些开发者那里却失败了。
  369. 生成并维护构建脚本不是一项富有魅力的工作,但却是一项必需的工作。一个好的Ant构建文件将使你能够集中到更喜欢的工作——写代码中去!
  370. 参考
  371. Ant 
  372. AntGraph: Ant依赖性的可视化工具 
  373. Ant: The Definitive Guide, O'Reilly 
  374. Java Extreme Programming Cookbook, O'Reilly 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值