Eclipse 平台、Eclipse 插件及 Eclipse Rich Client Platform 技术在业界已经得到了非常广泛的应用,使用
Eclipse 技术构建的工具,产品无论在开发人员的日常工作,抑或大型企业的生产运作上都发挥了巨大的作用。而和每个具有完备流程的软件工程一样,一个优秀的
Eclipse 插件 RCP 项目也缺少不了自动构建这一环。本文详细地介绍了 Eclipse 插件 RCP 项目的自动化构建的过程。
构建( build )在软件工程中是指将源文件及资源编译、打包成可在计算机上运行的软件。而自动化构建在软件行业已有非常悠久的历史,我们平时用的
Make 脚本, Ant 脚本都是常见的自动化构建的应用。而 Eclipse 插件系统的核心模块 PDE
同样也提供了完整的面向 Ant 的自动构建体系来编译和打包 Eclipse 插件 RCP 项目以用于发布。
在下面的部分中,详细讲述了进行 Eclipse 自动化构建的方法。文中示例适用于 Eclipse 3.2 和3.3。
Eclipse 平台提供了最简易的手动导出方式,您可以在 Eclipse IDE 的菜单中中选择 File->Export
命令,在弹出对话框中选择 Plug-in Development->Deployable features 导出 Eclipse
plug-in feature 或选择 Deployable plug-ins and fragments 导出 Eclipse
plug-in 或 fragment :
图 1. 导出 Feature 项目
在本例中,我们选择了导出一个 Eclipse plug-in feature ,在选择 Next 以后您可以看到如下的页面:
图 2. 选择项目和路径
在此页面中,您的 Eclipse 工作台中现存的 Eclipse Feature 项目将被列出于 Available Features
的选项之中。
在我们的例子中已有项目为 org.eclipse.test ,如果您的 Workbench 中存在其他 Feature 项目,也会被相应地列出。此后,您可以在
Directory或者 Archive file 中选择将此 Feature 项目导出为文件夹或压缩文件。
点选 Finish , Eclipse 将自动导出 org.eclipse.test 项目并打包为 C:\org.eclipse.test.zip
文件。
图 3. 导出项目的结构
可以看到, Eclipse 平台提供的一键式导出非常方便,已经可以满足普通插件开发者的需要。但它的可配置项较少,缺少自动加入版本号,时间戳等功能。而对于一个大型的项目,往往涉及多个模块联合编译构建;部分项目需要定期构建(例如
nightly build ),往往需要一个定时脚本在无人干预的情况下自动进行构建。此时 Eclipse 平台的手工一键导出已经不能完成这些要求,必须通过脚本的方式运行。为此
Eclipse 系统也提供了另一种基于 Ant 脚本的构建方式—— PDE headless-build ,我们在下面将详细讲述。
PDE (Plug-in Development Environment) headless-build 是一种基于 Ant
脚本的构建方式,它主要适用于 Eclipse plug-in 与 Eclipse RCP 项目的导出。
headless-build 所需安装的软件
在您开始 headless-build 之前需要安装如下软件:
- Eclipse SDK (必需)
- Ant (可选,在命令行模式中必须)
- CVS (可选,在自动获取 CVS 源控制的项目中必须)
由于 headless-build 是特定于 Eclipse 插件的构建平台,而 Eclipse 插件的编译构建都离不开Eclipse
本身的类库与资源,因而运行 headless-build 之前,您必须已经安装好带有 PDE 环境的 Eclipse SDK 。同时,如果您需要在纯命令行模式中启动构建或者其他必须使用外部
Ant 启动的模式,那您还必须安装 Ant 程序。
最后如果您的项目存储于 CVS 源控制中, headless-build 也提供了自动获取 CVS 源控制中代码和资源的功能。而在使用此项功能之前您必须安装有
CVS 客户端,并确保 cvs 命令已在环境变量中被定义。
headless-build 的启动和配置
由于 headless-build 必须基于 Eclipse 环境,因而我们必须通过启动 Eclipse 中相应的 application
来完成 build 过程。以下是一条简单的 build 启动命令。
java -jar plugins/org.eclipse.equinox.launcher_1.0.0.v20070606.jar \
-application org.eclipse.ant.core.antRunner -buildfile \
E:\soft\eclipse330\plugins\org.eclipse.pde.build_3.3.0.v20070612\scripts\build.xml \
–Dbuilder=”C:\Documents and Settings\YiTing\workspace33\pluginBuildExample\cfg”
|
这条命令和平时我们使用 java 命令启动 Eclipse IDE 环境类似,但是它的启动参数 –application 设置为
org.eclipse.ant.core.antRunner ,这将启动 Eclipse 的内置 Ant 运行器,而之后的参数
-buildfile build.xml 则类似于通常 Ant 启动参数中的脚本参数,指定了将被运行的 Ant 脚本。
在启动命令中,我们也可以设置 –D 参数,例如使用 –DbuildLabel 可更改最终构建完成的插件的后缀, -DcompilerArg
可设置编译 plug-in 中 Java 代码的编译参数,但通常情况下我们不必在启动参数中设置所有的可配置参数,因为 headless-build
已为此提供了一组基于 properties 和 xml 的配置文件:
allElements.xml
用于设定哪些 feature 或 plug-in 项目将会被 build 。 allElements.xml 的文件内容往往较为简单例如:
<project name="allElements Delegator">
<target name="allElementsDelegator">
<ant antfile="${genericTargets}" target="${target}">
<property name="type" value="feature" />
<property name="id" value="org.eclipse.test" />
</ant>
</target>
<target name="assemble.org.eclipse.test">
<ant antfile="${assembleScriptName}" dir="${buildDirectory}"/>
</target>
</project> |
在此样例中第一个 target 项指定了名为 org.eclipse.test 的 feature 项目将会被 build 。而第二个
target 则允许用户对不同环境下的插件设置不同的参数,例如:
<target name="assemble.org.eclipse.pde.build.container.feature.linux.motif.x86">
<ant antfile="${assembleScriptName}" dir="${buildDirectory}">
<property name="archiveName" value="${archiveNamePrefix}-linux.motif.x86.zip"/>
</ant>
</target> |
设定了 build 结果中应用于 linux motif x86 环境的 plug-in 的输出将以 linux.motif.x86.zip
为后缀。
build.properties
定义了大量的控制参数,用户可以通过改变此些参数控制整个 build 流程中7个方面的具体细节:基本设置,基础控制,输出控制,签名和
JNLP 控制,版本控制,获取源码控制,编译控制。每个部分中参数的具体含义可以参考
PDE 文档(参考1)。
在这里我们列举并解释其中最常用的控制项:
表 1. build.properties 中的常用参数
参数 |
功能 |
baseLocation
|
用于设定您的插件的目标Eclipse平台。例如,您所build的插件将会被安装于Eclipse
3.2.2平台上,那您必须为build过程准备一份Eclipse 3.2.2平台的本地拷贝。而baseLocation则设置为此平台的eclipse目录的路径。
|
buildDirectory
|
整个build过程的工作目录,在这个目录下将存放有build过程中生成的中间脚本、配置、log记录和最终输出的二进制文件。
|
buildType |
构建的种类,例如I、N、M。在Eclipse插件的版本设置中一般使用单个大写字母表示每个版本的种类,I表示集成版(integration
build),N表示每日版本(nightly build),M表示维护版本(maintenance build)。 |
buildLabel
|
完整的版本标签,一般您不需要改变此项设置,默认情况下buildLabel
= ${buildType}${buildId}。 |
buildId |
此项未在build.properties的文档中涉及,因为一般我们不在build.properties中设置buildId,而是通过headless-build启动参数加入,这样用户就可以在自定义的Ant脚本中任意生成符合项目需求的buildId。
|
compilerArg
|
设定编译插件中Java代码时使用的编译器参数。
|
configs |
控制目标插件的平台信息。通常的格式为:
configs = win32, win32, x86 & linux, gtk, ppc
表示输出的插件将有一份为win32系统、win32窗口和x86架构下的版本,而另一份则是linux系统,gtk窗口库和ppc架构下的版本。在build过程中之所以需要控制最终输出的结果集是因为Eclipse系统中部分核心模块如SWT对操作系统、窗口系统和硬件平台有特定的依赖,因而您所生成的插件也需要对此有区别的对待,以保证链接到正确的平台。
|
forceContextQualifier
|
用于替换feature和plug-in的version
number中的qualifier。 |
pluginPath
|
指定存放库插件的目录。您的插件一般总对其他插件有所依赖,因而您还必须制定所依赖的插件的存放目录。
|
skipFetch |
是否选择从cvs源控制中下载代码和资源。由于Eclipse系统和cvs的集成相对较为紧密,因而在headless-build构架中特有对cvs源控制的支持,如果skipMaps未设为true,系统将会试图从指定的cvs源中下载代码。关于headless-build与cvs的集成,我们在之后的章节中会介绍。
|
在构建的过程中,如果需要改变 version 中的 build 号,一般可以通过指定forceContextQualifier
来完成。 如在 feature 和 plug-in 中指定版本为 0.8.0.qualifier。然后在 build 的时候可以通过修改
forceContextQualifier 来实现 build 号的自增长。
customTargets.xml:
customTargets.xml 为用户在构建过程中的每个步骤中加入控制提供了可能。它的机制类似于我们通常编程中使用的回调函数。例如他提供了
preFetch 和 postFetch 两个 Ant target:
<target name="preFetch">
</target>
<target name="postFetch">
</target> |
通常用户可直接修改这两个 target 中的内容,以定制在获取代码前后的特殊行为。
allElements.xml、build.properties、customTargets.xml 是配置 headless-build
总体过程的3个支柱文件,用户需要负责编写它们,并将其放入同一被称为配置目录的文件夹,并将此目录的路径作为 –Dbuilder
参数值设定于 build 启动命令(例如前面样例命令中的 –Dbuilder=”C:\Documents and Settings\YiTing\workspace33\pluginBuildExample\cfg”)。
headless-build 的核心库文件与资源
正如前面所说,PDE headless-build 属于 Eclipse Plug-in Development Environment
的一部分。因而他的核心脚本文件都存储于 Eclipse 的 PDE 插件中。以作者目前的环境为例,PDE build 插件位于
plugins 目录下的 org.eclipse.pde.build 插件目录中。在此目录的 lib 文件夹中包含有 pde build
库的核心类文件,其中包括了绝大多数和 PDE build 相关的 Ant task 的实现,有兴趣的读者可以在 org.eclipse.pde.source
源代码插件中看到相应的代码。
图 4. 导出项目的结构
而对于我们的 build 任务,PDE headless-build 的核心脚本文件位于 scripts 和 templates
两个目录下。
scripts 文件夹中提供了 headless-build 的基础控制脚本。事实上无论是使用 headless-build
还是IDE 导出,我们都间接地通过执行这些脚本完成了一系列的过程。其中的 build.xml 文件是 build 过程的主脚本文件,在之前的启动命令中的
–buildfile 后的值就是此 build.xml 文件的路径。而 genericTargets.xml 则定义了在 build
过程的各个子过程的行为。
templates 文件夹中则提供了一系列的模板库。您可在 templates 下的 headless-build 目录中找到前面所说的
allElements.xml、build.properties、customTargets.xml 文件的模板。您可以方便地将其拷贝和修改,用作您自己的构建配置文件。
headless-build 的工作流程和通知机制
在之前的介绍中我们提到了 customTargets.xml 提供了对 headless-build 流程的多个节点的控制。而事实上
PDE 将 headless-build 分为多个子过程。customTargets.xml 正是针对了此些子过程提供了回调接口,以通知和触发用户定制的脚本被执行。
以下是 headless-build 整体流程的简图。
图 5. headless build 的工作流程
在其中,您需要提供的是最初的引入脚本(Ant 文件,批处理文件或命令行指令),之后 Eclipse 宿主会被启动并调用您指定的通常位于
PDE 插件 scripts 目录下的 build.xml,而此文件则会相应找到您在配置目录中定义的 customTargets.xml
文件,执行用户设定的回调脚本,并通过 customTargets.xml 调用 PDE 插件 scripts 下的 genericTargets.xml
启动 PDE 内部的各项子过程的执行代码。而在 genericTargets 中则定义了 headless-build 的4个子过程fetch、generate、process
和 assemble,下面我们对他们做简单的介绍。
表 2. build的四个子过程
子过程 |
描述 |
fetch |
负责从源控制中下载所需构建的插件项目的源文件
|
generate |
为每个插件分别生成自身的构建脚本。
|
process |
通过运行 generate
中生成的脚本,完成对每个插件的构建 |
assemble |
将 process 过程中生成的插件打包
|
我们知道,Eclipse 和 Ant 对于 cvs 源控制的支持非常优秀。同样,PDE 环境对 cvs 的集成度也相当好,用户可以在
fetch子 过程中自动下载存储于 cvs 源控制中的代码。而为了顺利运行 cvs,您必须在本地安装 cvs 客户端,并且保证
cvs 目录被设置于系统路径变量中:
图 6. cvs 命令示例
为了从源控制中正确找到相应的项目文件,PDE 还需要用户创建 map 文件,并在其中指定每个插件、功能部件等在 cvs 源控制中的位置,以下是一个
map 文件的样例:
feature@org.eclipse.test=CVS,HEAD,:pserver: anonymous \
@dev.eclipse.org:/cvsroot/eclipse,,org.eclipse.test-feature,
fragment@org.eclipse.ant.optional.junit=CVS,HEAD,:pserver: anonymous \
@dev.eclipse.org:/cvsroot/eclipse,,org.eclipse.ant.optional.junit,
plugin@org.eclipse.test=CVS,HEAD,:pserver: anonymous \
@dev.eclipse.org:/cvsroot/eclipse,,org.eclipse.test,
... |
其中定义了我们所需要构建的 org.eclipse.test 功能部件,及其相关的组件在 eclipse.org 的 cvs
源控制中的位置,tag,和密码等信息。之后 PDE 将根据这些信息执行 fetch 子过程,将源控制中代码下载到本地构建目录(
buildDirectory )中。
关于详细的 map 文件的语法格式请参见 PDE 详细说明(参考2)。
最后我们将用实例演示如何使用 PDE headless-build 架构来构建 Eclipse 的一个子功能部件 org.eclipse.test。该功能部件的源代码可在
eclispe.org 的 cvs 源控制 /cvsroot/eclipse 中找到。
在完成这个例子的过程中,我们使用了 eclipse3.3.0、Ant 1.7.0 和 CVSNT 2.5.03 的环境,您可能需要根据个人环境的不同做少许调整。完整的示例可以在下面的附件一下载。
如果观察 org.eclipse.test 功能部件的定义文件 feature.xml 您可以发现它由org.eclipse.ant.optional.junit
、 org.eclipse.test 、 org.eclipse.test.performance
和 org.eclipse.test.performance.win32 、 org.junit
、 org.junit4 六个子插件组成(注:org.eclipse.test.source 并非原生功能插件,而是衍生的源代码插件)
图 7. org.eclipse.test 的子插件
首先我们先建立一个 eclipse 项目 pluginBuildExample。
由于这些代码资源全部位于 eclipse.org 的 CVS 源控制中,所以,为了获取他们,我们首先需要创建 map 文件 build.map。
图 8. build.map
内容为:
feature@org.eclipse.test=CVS,HEAD,:pserver:$cvsuser$@dev.eclipse.org:/cvsroot/eclipse, \
$cvspass$,org.eclipse.test-feature,
fragment@org.eclipse.ant.optional.junit=CVS,HEAD,:pserver:$cvsuser$\
@dev.eclipse.org:/cvsroot/eclipse,$cvspass$,org.eclipse.ant.optional.junit,
plugin@org.eclipse.test=CVS,HEAD,:pserver:$cvsuser$\
@dev.eclipse.org:/cvsroot/eclipse,$cvspass$,org.eclipse.test,
plugin@org.eclipse.test.performance=CVS,HEAD,:pserver:$cvsuser$\
@dev.eclipse.org:/cvsroot/eclipse,$cvspass$,org.eclipse.test.performance,
fragment@org.eclipse.test.performance.win32=CVS,HEAD,:pserver:$cvsuser$\
@dev.eclipse.org:/cvsroot/eclipse,$cvspass$,org.eclipse.test.performance.win32,
#plugin@org.junit=CVS,HEAD,:pserver:$cvsuser$\
@dev.eclipse.org:/cvsroot/eclipse,$cvspass$,org.junit,
#plugin@org.junit4=CVS,HEAD,:pserver:$cvsuser$\
@dev.eclipse.org:/cvsroot/eclipse,$cvspass$,org.junit4, |
注意到 org.junit 和 org.junit4 在此 map 文件中被注释。因为我们之后使用的目标 eclipse 平台已经带有这两个插件,所以为了减少网络下载量,我们将其注释。
$cvsuser$、$cvspass$是两个可替换字段,在最终的 fetch 过程开始前,我们将会用真实的用户名和密码代替他们。
将 org.eclipse.pde.build_3.3.0.v20070612\templates\headless-build
下的3个文件拷贝至项目中的cfg 文件夹中:
图 9. cfg 文件夹
修改 allElements.xml 文件使其内容为:
<project name="allElements Delegator">
<target name="allElementsDelegator">
<ant antfile="${genericTargets}" target="${target}">
<property name="type" value="feature" />
<property name="id" value="org.eclipse.test" />
</ant>
</target>
<target name="assemble.org.eclipse.test">
<ant antfile="${assembleScriptName}" dir="${buildDirectory}"/>
</target>
</project>
|
注意到我们使用了 org.eclipse.test 替换了原先的 element.id,以告知 PDE 构建系统我们所需要构建的功能部件。
而 build.properties 和 customTargets.xml 则不需要做任何修改。
之后,我们创建 Ant 启动脚本 build.xml
图 10. build.xml
在这个脚本中我们定义了两个重要的 Ant target:copyRequisites 和 externBuild。
copyRequisites 将我们所需要的 map 文件拷贝至最终的工作目录,并在拷贝完毕后将 map 文件中的用户名和密码替换为真实的
cvs 用户和密码
<target name="copyRequisites">
<copy todir="${build.dir}/maps" overwrite="true">
<fileset dir="./map">
</fileset>
</copy>
<replace dir="${build.dir}/maps" token="$cvsuser$" value="${cvs.user}">
</replace>
<replace dir="${build.dir}/maps" token="$cvspass$" value="${cvs.pass}">
</replace>
</target>
|
而 externBuild 则通过创建新的 eclipse 进程启动了 PDE 构建过程。
<target name="externBuild" depends="init">
<java jar="${startup.jar}" fork="true">
<arg value="-application" />
<arg value="org.eclipse.ant.core.antRunner" />
<arg value="-DbuildDirectory=${build.dir}" />
<arg value="-Dbuilder=${cfg.dir}" />
<arg value="-DpluginPath=${plugin.path}" />
<arg value="-DbuildType=${build.type}" />
<arg value="-DbuildId=${build.time}" />
<arg value="-DbaseLocation=${sdk.dir}" />
<arg value="-buildfile" />
<arg path="${build.scripts}" />
</java>
</target>
|
在传入给此进程的参数中 buildDirectory 为用于构建功能部件的工作目录,builder 为此前所创建的配置目录 cfg。pluginPath
指定了已有插件(如 org.junit)的搜索路径,而 buildType、buildId、baseLocation 则复写了
build.properties 中的相应项。
一般而言,我们的构建脚本的内容较为固定,这样更适合存储于共享的源控制之中,以便于团队开发。而每台最终用于构建项目的计算机往往都有不同的环境和配置(例如,不同的
Eclipse 安装路径,不同的工作目录、CVS 帐号等等),因而,最后我们还需要创建一个本地配置文件 local.properties,每台构建用计算机都需要适当修改此文件的本地副本,以适合自身的环境。以下是作者在运行样例时所设置的本地环境。
#CORRECT THEM LOCALLY, DO NOT COMMIT THEM BACK TO CVS
#settings for the folders on your local build machine
# the temporary build space, source files will be copied to
# this place, and build occurs here
build.dir=E:/buildDir
# path to plugins will is needed by the build
plugin.path=E:/soft/eclipse330
# the location of your eclipse, you don't need to set this
# if you start the build from an eclipse enviroment
sdk.dir=E:/soft/eclipse330
# the startup.jar file of your eclipse, you don't need to set this
# if you start the build from an eclipse enviroment
startup.jar=E:/soft/eclipse330/plugins/org.eclipse.equinox.launcher_1.0.0.v20070606.jar
# the build script file
build.scripts=E:/soft/eclipse330/plugins/org.eclipse.pde.build_3.3.0.v20070612/\
scripts/build.xml
# the user account you are using to access cvs
cvs.user=anonymous
# the password corresponding to your cvs user account
cvs.pass=
|
过去,开发人员使用手工的方式集成与部署他们的项目,这样的过程存在太多的人为因素而极易导致错误的发生,因而手工模式在当今的系统开发过程中已很难再被沿用。而
Eclipse PDE 提供的自动化集成和构建架构则正是顺应此潮流,为规范化 Eclipse 插件开发的流程提供了诸多可能。
描述 |
名字 |
大小 |
下载方法 |
样例代码 |
pluginBuildExample.zip |
49KB |
|
|