浅析 Ant 脚本部署 RCP 项目

来源:互联网 发布:淘宝1号店网址 编辑:程序博客网 时间:2024/05/31 15:19

目前 RCP 项目的部署方式主要有两种:一种是通过 Eclipse 的向导界面,另一种是利用 Ant 脚本的方式生成一个 RCP 项目。将 Ant 与 RCP 二者的特点相结合,可以更好的提高实际项目的部署效率。本文将通过实际案例来详细介绍如何用 Ant 脚本来打包一个 RCP 项目。

背景介绍

RCP 简介

RCP(Rich Client Platform),即富客户端平台,是一个基于 Eclipse 的开源技术框架,它可以给开发人员提供丰富的组件来构建一个应用,避免了从零开始的繁重开发任务,从而能够快速的完成应用程序的开发工作,开发人员就可以通过把更多的精力放在业务组件开发上来摆脱枯燥的界面布局等开发工作。同时,RCP 也可以让从未有过插件开发的开发人员更容易上手和了解插件开发的概念。

Ant 简介

Ant 是用 Java 语言编写的项目管理工具。它可以通过构建 XML 的配置文件来管理和部署项目。

问题的提出

利用 RCP 的特点可以缩短软件开发的周期,提高开发效率,然而,在实际开发中,生成产品的编译环境和开发人员使用的开发环境往往是不在同一个服务器或者机器上。对于有可视化界面的操作系统,我们也许可以通过界面向导方式生成最终产品。但是对于那些非可视化界面的编译环境,该如何生成产品呢?与 Ant 相结合,可以很好的解决这一问题。下面进行详细介绍。

环境准备

准备 Ant 环境

下载 Ant 安装包

在 Apache 官网下载 Ant 包,相关链接在参考资料。

配置环境变量

在环境变量里添加 ANT_HOME=C:\Test\Ant\apache-ant-1.8.4。

在 Path 里添加 %ANT_HOME%/bin 的路径。

检查 Ant 安装

以 Windows 为例,控制台里输入 ant -version。如果输出的是当前的 Ant 的版本并且没有报错,那说明 Ant 的环境变量配置已经好了。

准备 Eclipse

下载一个 Eclipse SDK 开发工具和与之对应的 Eclipse delta pack。在 delta pack 里包含了很多平台打包时所依赖的 jar 包。具体链接可以参照参考资料里的链接。

实际案例

通过上述的介绍,大家对 RCP 和 Ant 有了一个初步的了解。下文将通过一个例子来说明如何用 Ant 脚本来部署一个 RCP 项目。

创建 RCP 项目

步骤一:建立一个 RCP 的简单工程项目。

选择 plug-in Project 工程。

图 1. 创建插件工程
图 1. 创建插件工程

命名工程名字为 HelloRCP,然后进入下一步,在选择模板的向导页里选择,“Hello RCP”模板如图所示:

图 2 创建工程模板
图 2 创建工程模板

这个模板包含了一个标准的 RCP 工程所需要的包。项目创建好后,创建一个 product 文件,该文件用于定义生成产品所包含的依赖包、产品的信息等。

图 3. 项目文件结构
图 3. 项目文件结构

项目建立好后,下一步我们就可以开始编写 Ant 的 build 脚本了。

自定义 Ant 脚本

在 Ant 脚本的编写时,涉及到两个文件,一个是 build.xml,在这里用来定义对项目部署的整个流程。另一个是 build.properties,这个文件主要用来定义 build.xml 文件里用到的变量值。构建 Ant 脚本,可以通过图的形式来描述它们彼此之间的依赖关系。

图 4. Target 关系图
图 4. Target 关系图

从图中可以看出,各个 Target 间的依赖关系,可以更有利于理解和编写 Ant 脚本。build.xml 文件的内容如下 :

清单 1.build.xml
 <project name="HelloRCP" default="start">       <property file="build.properties" />       <!-- bootstrap -->       <target name="start">             <antcall target="external" />             <antcall target="deploy" />       </target>       <!-- invocation external build.xml -->       <target name="external">             <ant antfile="build.xml" dir="${external_build}"/>       </target>       <!-- start export rcp product -->       <target name="init">             <mkdir dir="${buildDirectory}" />             <mkdir dir="${buildDirectory}/plugins" />             <copy todir="${buildDirectory}/plugins">                   <fileset dir="../../">                   <!-- include source codes needed to be built.-->                         <include name="HelloRCP/**" />                   </fileset>             </copy>       </target>       <target name="pde-build">             <java classname="org.eclipse.equinox.launcher.Main"             fork="true" failonerror="true">                   <arg value="-application" />                   <arg value="org.eclipse.ant.core.antRunner" />                   <arg value="-buildfile" />                   <arg value="${eclipseLocation}/plugins/  org.eclipse.pde.build_${pdeBuildPluginVersion}/  scripts/productBuild/productBuild.xml" />                   <arg value="-Dtimestamp=${timestamp}" />                         <classpath>                               <pathelement location="${eclipseLocation}/plugins/  org.eclipse.equinox.launcher_${equinoxLauncherPluginVersion}.jar" />                         </classpath>             </java>       </target>       <target name="build" depends="clean, init, pde-build" />       <!-- end rcp export product-->       <!-- merge configure file -->       <target name="deploy" depends="build">       <!-- -->       </target>       <!-- end merge configure file -->       <!-- clean all temp file-->       <target name="clean">             <delete dir="${buildDirectory}" />       </target>  </project>

那么,每个 target 在这个 Ant 脚本里具体的角色是什么呢?

<target name="start">:是整个 Ant 脚本的启动 target,类似于一个类里的 main 方法。

<target name="deploy">:对项目配置文件的部署,比如需要的外部 jar、properties 文件等。

<target name="build">:对代码进行编译,并生成 RCP 的产品文件,包括执行文件,配置文件、相关的插件和产品的信息文件。

<target name="pre-build">:调用 Eclipse 的导出功能生成产品。

<target name="clean">:清除在编译过程中产生的临时文件。

<target name="init">:部署代码到指定位置,为编译做准备。

<target name="external">:用来调用其他 Ant 脚本。

下面对 build.xml 做一个简单的说明:

在一个 Ant 脚本里只包含一个 project 元素,并且 default 属性值定义的就是 Ant 脚本初始调用的 target,如 <project name="HelloRCP" default="start">,在这里 start target 被定义为初始被执行的 target。

对于 target 的调用这里用到了两种方法,一种是通过 depends 属性,来找到当前 target 所依赖的 target。比如 <target name="deploy" depends="build">在 deploy 这个 target 里,设置了 depends 这个属性,所以在这里会先去调用 build 这个 target,当 build target 执行完,再来执行 deploy target。depends 属性还可以指定多个 target,比如,<target name="build" depends="clean, init, pde-build" />在对 Ant 的 build.xml 脚本解析的时候会按顺序依次的调用这三个 target。另一种是通过 antcall 这个元素来调用 target,如 <antcall target=" external " />,直接通过 target 的名字来调用指定的 target。在这里调用到了 external target。

在实际工作中,可能某个工程已经有了自己的 Ant 脚本,而我们所需要做的就是调用这个脚本,如 external target 就是定义了一个外部脚本的调用,<ant antfile="ex_build.xml" dir="${external_app_destdir}"/>这个 external_app_destdir 名字就是用来定义另一个 Ant 脚本的具体位置,所以在框架解析到这个 target 的时候,会到指定的目录里去找名字为 ex_build.xml 的 Ant 脚本,这里要提醒的是,在 build.xml 定义的变量是可以被外部的编译脚本使用,但如果变量定义的值涉及到相对路径的时候,在对外部脚本解析的时候,框架会将这个 ex_build.xml 作为当前的编译目录,所以在 ex_build.xml 使用 build.xml 中定义的相对路径的时候,很容易产生路径文件找不到的编译错误,在编写脚本相对路径的时候,要明确这个相对路径是相对当前哪个 Ant 脚本来定义的。

清单 2.init target
 <target name="init">  <mkdir dir="${buildDirectory}" />  <mkdir dir="${buildDirectory}/plugins" />  <copy todir="${buildDirectory}/plugins">       <fileset dir="../../">            <include name="HelloRCP/**" />            <!-- include source codes needed to be built.-->       </fileset>       </copy>  </target>

在 init target 里,首先是创建了 build 的路径,然后将源代码拷贝到 plugins 里,之所以构建这个目录结构,是因为要满足在 Eclipse 的 PDE 框架里的目录结构,框架会从这个目录里取得源代码,然后进行相应的编译操作。这里的相对路径的写法是以当前的 build.xml 的路径为基准的。** 表示的是指定 HelloRCP 这个目录下的所有文件及子文件夹。当然如果有多个工程需要进行编译操作在 fileset 这个元素下 , 可以指定多个 include 元素。

清单 3 pde-build target
 <target name="pde-build">  <java classname="org.eclipse.equinox.launcher.Main" fork="true" failonerror="true">       <arg value="-application" />       <arg value="org.eclipse.ant.core.antRunner" />       <arg value="-buildfile" />       <arg value="${eclipseLocation}/  plugins/org.eclipse.pde.build_${pdeBuildPluginVersion}  /scripts/productBuild/productBuild.xml" />       <arg value="-Dtimestamp=${timestamp}" />             <classpath>                   <pathelement location="${eclipseLocation}/plugins  /org.eclipse.equinox.launcher_  ${equinoxLauncherPluginVersion}.jar" />             </classpath>  </java>  </target>

这部分是将工程编译产品的核心。首先,是运行 org.eclipse.equinox.launcher.Main 这个类,在这里要传入的几个参数,例如调用的具体的 antRunner、pde 的 jar 包等等。org.eclipse.ant.core.antRunner 用来解析运行 Ant 编译脚本的文件,里面提供了一些方法来设置那些在 build 过程中用的类,productBuild.xml 就是指在当前使用的 Eclipse 里 pde 要用到的生成产品的编译文件,具体位置就是 org.eclipse.pde.build 加上具体相应的版本号的文件夹的位置里。在 productBuild.xml 的脚本里,可以看出在生成产品的时候会对相应的依赖的 jar 包进行依赖性的检查和生成,在这里很容易出现在编译的时候对某个 jar 文件的丢失,导致 Ant 脚本生成时候的报错。如果有类似缺失依赖包的问题出现,就去工程里的 .product 的 dependencies 里导入相应的 jar 包。

到此,对一个 build.xml 的简单介绍就完成了,对于 Ant 脚本来说,能够完成的任务是非常丰富的,如并发,条件执行,编译,取得系统的环境变量等等,有兴趣的话可以参考 developer works 里对 Ant 的专题介绍。

Ant 脚本的配置文件

在 Ant 脚本里有两种主要有两种方式,一种是通过对 property 元素直接赋值,另一种是通过 build.properties 文件来定义变量的值,这种方式更有利于维护和可读性。本案例就是使用配置文件的方式来定义变量。build.xml 要先对配置文件进行导入,才会在 Ant 脚本里识别出变量的值。在默认情况下,build 的 xml 文件和配置文件在同一路径下,也可以去指定这个配置文件的具体位置。下面是 build.properties 文件的具体内容:

清单 4 build.properties
pdeBuildPluginVersion=3.8.0.v20120523-1555equinoxLauncherPluginVersion=1.3.0.v20120522-1813eclipseLocation=C:/eclipse-rcp-juno-win32-x86_64/eclipseproduct=HelloRCP/hellorcp.productrunPackager=truearchivePrefix=HelloRCPcollectingFolder=${archivePrefix}configs=win32, win32, x86_64allowBinaryCycles = trueflattenDependencies = truebuildDirectory=C:/DWbuildId=hellorcpbuildLabel=${buildType}.${buildId}timestamp=007baseLocation=C:/eclipse-rcp-juno-win32-x86_64/eclipsebaseos=win32basews=win32basearch=x86_64filteredDependencyCheck=falseresolution.devMode=falseskipBase=trueskipMaps=truemapsRepo=:pserver:anonymous@example.com/path/to/repomapsRoot=path/to/mapsmapsCheckoutTag=HEADmapsTagTag=v${buildId}skipFetch=trueJavaSE-1.6=${java.home}/lib/rt.jarlogExtension=.logjavacDebugInfo=truejavacFailOnError=truejavacVerbose=truejavacSource=1.6javacTarget=1.6external_build=C:/external

下面对 build 的配置文件做个简单的说明:

 pdeBuildPluginVersion=3.8.0.v20120523-1555

用来指定 Eclipse 里 pde 的版本,这个可以在 Eclipse 的 plugin 文件夹下找到。

 equinoxLauncherPluginVersion=1.3.0.v20120522-1813

指定 org.eclipse.equinox.launcher 的版本,同样也是在在 Eclipse 的 plugin 文件夹下。

 eclipseLocation=C:/eclipse-rcp-juno-win32-x86_64/eclipse

这个变量是用来设置运行的 Eclipse 的具体文件路径。

 buildDirectory=C:/DW

用来设置编译生成产品的具体位置。

 configs=win32, win32, x86_64

用来设置生成产品的具体运行在什么样的操作系统上。这里指定的是 windows 64 位的。

 buildId=hellorcp

导出产品的具体名称,要区分的是这个不是具体执行文件的名字而是生成产品文件夹的名字。到此一个 RCP 项目的建立,一个标准的 Ant 脚本和配置文件的编写就完成了。

运行

对于编写好的 Ant 脚本有两种方式可以运行,一种是通过 Eclipse 的图形界面 ( 右键工程里的 build.xml -> Run As -> Ant Build),在 Eclipse 的控制台会打印出运行 Ant 脚本时的一些输出信息。另一种方式就是通过命令的方式在一个搭建好 Ant 环境的平台上运行如:ant <build.xml>这样的命令来执行 Ant 脚本。第二种方式比较方便,因为我们可以直接以命令行的方式去打包我们要的产品,而不需要通过运行 Eclipse 来完成我们的操作,而且如果是通过远程机器来打包我们的产品时,我们也只需要传递一条命令,就可以完成部署工作了。我们通过命令方式来运行之前我们写好的 Ant 脚本文件。运行如下的命令:

 C:\workspace_rcp\HelloRCP\builds> ant

可以在控制台里看到 Ant 的编译信息,直到编译成功结束。现在我们可以看到已经部署好了我们要的产品。在 pde 的框架里,会对这个产品输出自动打成一个压缩包,根据具体项目需要我们可以编写脚本将我们需要的配置文件也放到这个压缩包里。如果有的开发人员觉得这个运行命令的方式不是很方便的话我们也可以写一个批处理文件,以 windows 为例,下面我们来写一个 .bat 文件,内容如下:

清单 4 Auto.bat
 call C:\Test\Ant\apache-ant-1.8.4\bin\ant.bat -file  C:\workspace_rcp\HelloRCP\builds\build.xml

这样以后如果有代码的更新时,我们只要运行这个 bat 文件就可以了。我们可以看到,通过命令方式运行的结果与 Eclipse 界面方式的导出是一样的,并且这种方式也节省在项目部署时候的时间,提高了效率。

常见问题

  • 用 product 运行时报找不到 application id 的错误怎么办 ?

    答:打开 product 这个文件,在 overview 里的 product definition 标签中配置 product 和 application。

  • 找不到 tools.jar 怎么办 ?

    答:有的时候在配置 Ant 时,会遇到 tools.jar 找不到,最直接的方式就是把 jdk 里的这个 jar 赋值到错误提示里的 jre 的目录里。

  • 找不到依赖包怎么办 ?

    答:如果在运行 Ant 脚本的时候,提示有 jar 包缺失,在 product 的 dependencies 里添加缺少的依赖包。

  • 如何生成多平台的产品 ?

    答:如果要生成多平台的产品时,只需要修改 build.properties 里的 configs 属性的值,如:configs= win32,win32,x86 & linux, gtk, x86_64 这样就会生成 Windows 32 位和 Linux 64 位的产品。

总结

本文已经将 Eclipse RCP 与 Ant 工具的结合使用介绍给大家了,在实际的项目操作中,我们不但可以利用 Eclipse RCP 的特点可以提高我们的开发速度,同时在结合了 Ant 之后,也提高了项目后期效率。希望本文的介绍可以给读者在实际的开发中提供一定的帮助。

参考资料

学习

  • 参考 Eclipse 帮助文档:提供了 Eclipse 更多帮助文档,如 PDE 的技术介绍等。
  • 参考 Eclipse 工具下载:通过此链接可以下载 Eclipse RCP 不同版本的开发工具,同时也有各个版本对应的 delta pack 包。
  • 参考 Ant 工具下载:可以下载到最新的 Ant 工具,同时,也有工具的使用说明

0 0
原创粉丝点击