软件开发中的持续集成与原生代码构建
1. 持续集成工具介绍
在软件开发中,持续集成是应对日益复杂的开发环境的必要步骤。随着项目复杂度增加、时间尺度缩短、团队分布化等问题的出现,持续集成能帮助我们更好地控制开发过程。以下为大家介绍几种常见的持续集成工具。
1.1 Gump
Gump是开源Java世界中的得力工具,它不仅能显示构建失败情况,还能指出项目是否因前置依赖失败而无法构建。不过,Gump也存在一些不足:
- 目前仅支持CVS。
- 配置、执行和自动化操作具有一定难度,需要深入了解其架构和配置才能有效使用。
- 非Java方面的特性可能会让许多开发者望而却步,例如使用shell脚本自动生成其他shell脚本,以及使用Perl进行失败邮件通知(但Perl并非运行Gump的必需组件)。
然而,Gump也有其独特的优势:
- 支持项目间依赖。在项目构建前,能使用最新代码库构建依赖库,提前预警API变化或确保一切正常。
- 输出和用户界面出色。所有项目都与依赖项的构建进行超链接,一键即可查看CVS更新日志,项目交叉引用有助于可视化复杂的项目关联。
1.2 持续集成工具对比
选择持续集成工具时,SCM支持是关键因素。如果不使用CVS,有两种选择:一是将SCM集成脚本编写到shell脚本中,并利用操作系统的调度功能实现自动化;二是使用CruiseControl。Anthill和Gump也可适配其他SCM系统,但可能需要自行进行底层实现。以下是几种工具的特性对比:
| 特性 | CruiseControl | Anthill | Gump |
| — | — | — | — |
| 安装/配置难度 | 中等难度 | 简单 | 困难 |
| 是否需要修改项目构建文件 | 是 | 否 | 否 |
| 多项目依赖支持 | 否 | 否 | 是 |
| SCM支持 | CVS、VSS、ClearCase、MKS、Perforce、PVCS、StarTeam和文件系统 | 仅CVS | 仅CVS |
| 是否自行控制SCM | 否(需手动在构建文件中编码) | 是 | 是 |
| 支持多项目构建的流程 | 设置运行器应用的另一个实例,并使用CruiseControl钩子配置每个项目的构建文件 | 通过Web界面添加另一个项目定义 | 将另一个项目添加到配置文件或工作区配置中,并重新生成/运行脚本 |
| 版本标记 | 支持默认和自定义标记,SCM不打标签 | 支持默认和自定义标记,成功构建后SCM自动打标签 | 构建有时间戳,无其他标记支持,SCM不打标签 |
2. 原生代码构建挑战与现有工具
在Java软件开发中,复杂项目往往会涉及原生代码,如访问Java未直接支持的操作系统特性的原生库、CORBA组件或COM对象,甚至是独立的原生可执行文件。因此,需要从Ant中编译原生代码。
2.1 使用现有构建工具的问题
Ant是Java程序的优秀构建工具,但在C或C++开发方面表现较弱。传统上,Makefiles和IDE是编译和链接原生代码的标准工具,但它们存在一些问题:
-
委托给IDE
:将编译任务交给IDE,如使用Microsoft Visual Studio 6或.NET进行构建,虽然能将复杂的构建过程委托给原生工具链,但会威胁到构建文件的稳定性和可移植性。新的IDE版本可能需要重新编写整个目标,且IDE构建通常难以在不同系统间移植,需要锁定系统配置。例如使用Microsoft Visual Studio 6构建的代码:
<target name="msdev" depends="headers">
<exec
executable="msdev.exe"
failonerror="true" >
<arg file="CpuInfo.dsw" />
<arg value="/MAKE"/>
<arg value=""CpuInfo - Release""/>
</exec>
</target>
而支持Microsoft Visual Studio.Net则需要对
<exec>
命令进行重大改写:
<target name="devenv" depends="headers">
<exec
executable="devenv.exe"
failonerror="true" >
<arg file="CpuInfo.sln" />
<arg value="/build"/>
<arg value="Release"/>
</exec>
</target>
-
使用Make
:Make能提供可共享的构建过程,并可与持续集成流程集成。使用
<exec>调用Make时,需确保failonerror属性设置为true。但Make的依赖规范过程复杂,需要大量GNU或Unix命令,且跨平台时可能需要使用autoconf进行配置,增加了构建的复杂性。例如使用Make的代码:
<target name="make" depends="headers">
<exec
executable="make"
failonerror="true" >
<arg value="-f"/>
<arg file="CpuInfo" />
<arg value="release"/>
</exec>
</target>
2.2 引入
<cc>
任务
Ant 1.5版本中没有C和C++编译及链接任务,但未来版本可能会添加。目前,SourceForge上的Ant-Contrib项目提供了
<cc>
任务,可编写单个构建文件,为多个平台编译C++代码并链接成合适的可执行文件。
安装
<cc>
任务的步骤如下:
1. 检查在线文档,看任务是否已包含在Ant中。若未包含,从SourceForge项目主页下载cpp-tasks存档(当前使用版本为1.0a)。
2. 将cpp-tasks.jar文件添加到项目的lib目录。
3. 在项目中声明
<cc>
任务及其四个支持的数据类型:
<path id="cc.classpath">
<pathelement location="lib/cpptasks.jar"/>
</path>
<taskdef resource="cpptasks.tasks"
classpathref="cc.classpath"
loaderRef="cctasks"/>
<typedef resource="cpptasks.types"
classpathref="cc.classpath"
loaderRef="cctasks"/>
<cc>
任务支持多种编译器,如aCC、bcc、gcc等。使用时,编译器需安装并能从命令行正常工作,即编译器命令在路径中,且相关环境变量(如INCLUDE和LIB)配置正确。
<cc>
任务的核心功能包括:
- 编译后缀为.c、.cc、.cxx、.cpp或.c++的C和C++源文件。
- 创建中间目标文件、可执行文件、共享库和静态库。
- 通过指定文件集(如src/*
/
.cpp)简单构建文件。
- 解析文件以确定依赖关系。
- 支持多平台和工具链。
以下是一个使用
<cc>
任务的示例:
<cc debug="false"
link="executable"
outfile="dist/application"
objdir="build/objects"
multithreaded="true"
exceptions="true" >
<compiler name="msvc" if="use-msvc"/>
<compiler name="gcc" if="use-gcc"/>
<fileset dir="src/cpp" includes="*.cpp"/>
<linker name="msvc" if="use-msvc"/>
<linker name="gcc" if="use-gcc"/>
<syslibset libs="kernel32,user32"/>
</cc>
该任务声明可使用GNU和Microsoft工具套件构建应用程序,启用代码中的多线程和异常处理,并生成发布版本。
综上所述,持续集成工具能帮助我们更好地管理软件开发过程,而
<cc>
任务为在Ant中构建原生代码提供了强大的支持。在实际开发中,可根据项目需求选择合适的工具和方法。
3. 构建JNI库
Java通过JNI(Java Native Interface)调用原生库,这是一个复杂而强大的机制。下面将探讨如何在Ant中构建和测试JNI代码。
3.1 JNI构建的复杂性
JNI机制十分复杂,需要专门的书籍才能详细阐述。不过,我们的重点是在Ant中实现JNI代码的构建和测试。
3.2 利用
<cc>
任务构建JNI库
可以使用前面介绍的
<cc>
任务来构建JNI库。以下是一个简单的构建流程:
1.
确定编译器
:选择适合的编译器,如
gcc
或
msvc
。
2.
配置任务参数
:设置输出文件、目标目录等参数。
3.
指定源文件
:通过
fileset
指定要编译的C++源文件。
以下是一个示例代码:
<cc debug="false"
link="sharedlib"
outfile="dist/libCpuInfo.so"
objdir="build/objects"
multithreaded="true"
exceptions="true" >
<compiler name="gcc" if="use-gcc"/>
<fileset dir="src/jni" includes="*.cpp"/>
<linker name="gcc" if="use-gcc"/>
<syslibset libs="java"/>
</cc>
在这个示例中,我们构建了一个共享库
libCpuInfo.so
,使用
gcc
编译器,源文件位于
src/jni
目录下。
4. 跨平台构建与
<cc>
任务细节
在软件开发中,跨平台支持是一个重要的需求。
<cc>
任务在这方面做出了努力,但也面临一些挑战。
4.1 跨平台构建的挑战
不同平台和工具的构建过程差异很大,这使得跨平台构建变得复杂。例如,不同编译器的选项可能不同,需要针对每个平台和编译器进行特定配置。
4.2
<cc>
任务的跨平台支持
<cc>
任务尝试在单个嵌套任务中描述多个平台和工具的原生代码构建过程。以下是其跨平台支持的一些要点:
-
代码和测试
:需要在所有支持的平台上进行代码编写和测试。
-
编译器选项
:对于非基本的编译器选项,需要为每个支持的编译器和链接器确定特定选项。
下面是一个跨平台构建的流程图:
graph LR
A[开始] --> B[选择平台]
B --> C{是否支持该平台?}
C -- 是 --> D[配置编译器和选项]
C -- 否 --> E[不支持该平台]
D --> F[编译和链接代码]
F --> G[生成可执行文件或库]
G --> H[测试]
H --> I[结束]
E --> I
5. 原生库的分发
构建好原生库后,需要将其分发给其他开发者或用户。以下是一些分发原生库的注意事项:
-
兼容性
:确保库与目标平台兼容。
-
依赖项
:明确库的依赖项,并确保这些依赖项也能正确安装。
-
版本管理
:使用版本号来管理库的不同版本。
可以使用以下步骤进行原生库的分发:
1.
打包
:将库文件和相关文档打包成一个压缩文件。
2.
发布
:将打包文件发布到合适的位置,如代码仓库或下载站点。
3.
文档说明
:提供详细的文档,说明如何安装和使用库。
6. 总结
在软件开发中,持续集成和原生代码构建是两个重要的方面。持续集成工具如Gump、CruiseControl和Anthill各有优缺点,开发者可以根据项目需求和SCM系统选择合适的工具。而在原生代码构建方面,
<cc>
任务为在Ant中编译和链接C和C++代码提供了强大的支持,尽管跨平台构建存在挑战,但通过合理配置和测试可以实现。
以下是持续集成工具和原生代码构建相关要点的总结表格:
| 类别 | 工具/任务 | 优点 | 缺点 |
| — | — | — | — |
| 持续集成 | Gump | 支持项目间依赖,输出和界面出色 | 仅支持CVS,配置复杂 |
| 持续集成 | CruiseControl | 优秀的报告功能,支持多种SCM | 设置有一定难度,需修改构建文件 |
| 持续集成 | Anthill | 安装简单,可通过Web应用全面控制 | 仅支持CVS |
| 原生代码构建 |
<cc>
任务 | 支持多平台,自动处理依赖 | 配置复杂,需测试所有支持平台 |
通过合理使用这些工具和技术,开发者可以更好地管理软件开发过程,提高开发效率和软件质量。
超级会员免费看

被折叠的 条评论
为什么被折叠?



