级别: 初级 Kirk Vogen (kirkvdevw@us.ibm.com), 高级 I/T 专家, IBM
2003 年 8 月 21 日 就在一年多以前,Java 开发人员 Kirk Vogen 探讨了如何合并 GNU Compiler for Java、Linux 和标准窗口小部件工具箱(Standard Widget Toolkit,SWT)的能力以创建本机的跨平台 Java 应用程序。在本文中,Kirk 重述了该主题并讨论了对 Windows、GNOME 和 SWT 2.0 的支持。这一次,他使用 Ant 来演示如何自动构建您的本机应用程序,然后演示了如何将所有这些集成到 Eclipse IDE。请在本文所附带的论坛中与作者及其他读者分享您对本文的看法。(您也可以单击本文顶部或底部的“讨论”来访问该论坛。)
在我们上一次讨论 GNU Compiler for Java(GCJ)和标准窗口小部件工具箱(Standard Widget Toolkit,SWT)时,我们有了一个创建在本机编译且具有本机操作系统观感的 Java 应用程序的解决方案。该解决方案使用 Linux 中的 SWT 1.0 和 GCJ。从那以后,添加了对 Linux 中的 GNOME 和 Windows 的支持。本文再次研究 GCJ 和 SWT。我们将探讨如何构建 SWT,以便您可以在您的应用程序中使用它。我们还将利用几个示例来阐明如何在应用程序及其构建过程中使用 SWT。最后,我们将探讨如何在 Eclipse IDE 中使用构建过程。如果您需要有关我们已讨论内容的背景知识,请参阅
参考资料来回顾有关 GCJ、SWT 及其所有原理的信息。
设置开发环境
在着手有趣的事情之前,您需要设置开发环境。您将需要以下软件包:
-
Ant 1.5.0 或更高版本基于 Java 的构建工具(有关 Ant 的详细信息,请参阅
参考资料)。
-
GCJ 3.2 或更高版本可以用几种方式获得 GCJ。大多数最新版本的 Linux 分发版(distribution)都带有 GCJ。RedHat 8.0 和 Mandrake 9.0 带有 GCJ 3.2。对于 Windows,请参阅侧栏
在 Windows 上安装 GCJ 3.2以获得安装指导信息。如果您正在运行未包含 GCJ 的 Linux 或 UNIX 版本,请参阅
参考资料以获得有关在您的环境中编译 GCJ 的指导信息。
-
补丁实用程序 构建过程使用 Ant
<patch> 任务来运行几个补丁。因此,您的系统需要安装补丁实用程序。大多数 Linux 系统都带有现成的补丁实用程序。但 Windows 没有。本文的源代码中已经包括了一个 Windows 版本的补丁实用程序(请参阅
参考资料)。该文件包含在
Utilities\win32 目录中。请将 patch.exe 文件放在您系统路径(PATH)中的目录中。
-
Eclipse 2.0.2只有打算在 Eclipse IDE 中运行构建程序时此软件包才是必需的(正如稍后在
用 Eclipse 进行本机构建中所讨论的那样)。
确保您的 PATH 环境变量可以访问前面列出的所有应用程序。这将确保 Ant 构建文件可以在需要时运行这些实用程序。
构建 SWT
既然已经设置好了开发环境,那么就让我们探讨如何将 SWT 构建到库中。这一过程包括将 SWT 源代码编译成本机目标代码并将它们全部包装成库。然后就可以使用这个库来链接到应用程序。
在继续阅读之前,请下载并解压缩
本文的源代码。该源代码包含几项内容,包括用于将 SWT 构建到库中的构建脚本、几个样本应用程序和来自 Eclipse 2.0.2 的 SWT 源代码。
在构建 SWT 时要记住几件事:目标操作系统、目标窗口系统和您希望使用的库类型。目前 AIX、HP/UX、Linux、Solaris 和 Windows 操作系统都支持 SWT。MacOS 和 QNX 也支持它(虽然本文不包括这两种操作系统)。除了操作系统之外,您还需要确定目标窗口系统,这在我们稍后运行构建文件时将很重要。如果您的操作系统是 Linux,那么您的窗口系统选项是 GNOME 或 Motif。如果您在另一个 UNIX 变体(如 AIX、HP/UX 或 Solaris)上,那么您窗口系统选项目前
只能是 Motif。如果您的操作系统是 Windows,则您的窗口系统选项就是这个系统 ― Windows。目前,由于 KDE 所使用的 Qt 工具箱存在明显的许可证问题,所以不支持 KDE。用其它窗口系统编译的应用程序将运行在 KDE 中,但是它们不会使用 KDE 的本机窗口小部件。
除了操作系统和窗口系统之外,还需要确定要构建那种库类型。您有两个选项:静态库或共享库。如果使用静态库,SWT 将在编译时链接到您的应用程序。如果使用共享库,SWT 将在运行时链接到您的应用程序。顾名思义,共享对象的主要优点是可以被共享。所有应用程序都可以在运行时动态地使用同一对象。因此,可执行程序的大小将小很多。在 Windows 中,只能使用静态库;GCJ 不支持 Java DLL 的装入(DLL 是 Windows 中的共享库)。
构建文件
构建文件的知识对于本文来说显得有些太长了,但是基本上,它的功能是:
- 检索特定操作系统和窗口系统的 SWT 源代码。
- 对 SWT 代码打几个补丁。由于会出现一些编译器小错误,因此有几个 SWT 文件将无法用 GCJ 编译 ― 例如,GCJ 在一些用内部类实现的事件侦听器方面出现问题。在这些情况下,人们对源代码应用一些小补丁,以便修复错误,同时保持代码功能不变。因为 GCJ 仍然在不断改进,所以这些错误最终应该是可以被消除的。
- 将代码编译成本机目标代码。
- 将目标代码包装成静态库或共享库。
要运行构建文件,导航至本文所包括的源代码的
Library 目录。您需要配置几个特性。首先,要设置目标操作系统,请使用
os 特性。要配置窗口系统,请使用
window_system 特性。最后,要控制库类型,请调用
static-library 或
shared-library 目标。在缺省情况下,构建文件调用
static-library 目标,并将操作系统设置成 Linux,将窗口系统设置成 GNOME。有关配置选项的完整说明,请在命令提示符处导航至
Library 目录,然后输入
ant help。
让我们研究一下构建 SWT 的几个常见示例:
- 要在 Linux 中创建 GNOME 静态库,只需输入
ant。在缺省情况下,构建文件调用
static-library 目标,因此在命令提示符处无需其它操作。
- 要在 Linux 中创建 GNOME 共享库,输入
ant shared-library。
- 要在 Linux 中创建 Motif 共享库,输入
ant -Dwindow_system=motif shared-library。
- 要创建 Windows 静态库,输入
ant -Dos=win32 -Dwindow_system=win32。请记住,目前 Windows
不支持共享库。
清单 1 显示了 Linux/GNOME 共享库构建的输出。
清单 1. Linux/GNOME 共享库构建的输出
[Library]$ant shared-library
Buildfile: build.xml
get-swt-source:
properties:
init:
ws/gtk/swtsrc.zip:
[zip] Building zip: /home/jdoe/Java/SWT/Eclipse_2.0.2_SWT_
Source/plugins/org.eclipse.swt.gtk/ws/gtk/swtsrc.zip
[unzip] Expanding: /home/jdoe/Java/SWT/Eclipse_2.0.2_SWT_Source/
plugins/org.eclipse.swt.gtk/ws/gtk/swtsrc.zip into
/home/jdoe/Java/SWT/Library
get-pi-source:
properties:
init:
ws/gtk/swt-pisrc.zip:
[unzip] Expanding: /home/jdoe/Java/SWT/Eclipse_2.0.2_SWT_Source/
plugins/org.eclipse.swt.gtk/ws/gtk/swt-pisrc.zip into
/home/jdoe/Java/SWT/Library
patch:
[patch] patching file GtkSelectionData.java
[patch] patching file GtkTargetEntry.java
[patch] patching file TableCursor.java
[copy] Copying 4 files to /home/jdoe/Java/SWT/Library/org/
eclipse/swt/custom
compile:
[javac] Compiling 4 source files
[echo] Compiling SWT with GCJ
init:
shared-up-to-date:
shared-library:
BUILD SUCCESSFUL
Total time: 1 minute 18 seconds
[Library]$
|
如果您在 Windows 中遇到构建困难并且已经安装了 Cygwin,请参阅侧栏
关于 Cygwin 和 GCJ 的说明。
 |
关于 Cygwin 和 GCJ 的说明
新版本的 Cygwin 带有 GCJ。然而,我在安装了 Cygwin 的机器上按照前面所讨论的构建过程进行操作时却遇到了一些问题。如果您安装了 Cygwin,可以通过从系统路径(PATH)临时除去
c:\cygwin\bin 来缓解任何可能出现的问题。如果 Cygwin 在路径(PATH)中,您会看到类似于以下的错误:
Public class `ACC'
must be defined in a file
called `ACC.java'
|
|
|
构建样本应用程序
既然您已经有了 SWT 库,现在就可以开始构建使用它的应用程序了。本文所包括的源代码 zip 文件(请参阅
参考资料)有几个样本应用程序。每个样本应用程序都包括一个通用构建文件,可以使用该文件作为您项目的起点。该构建文件:
- 编译您的项目可能拥有的任何资源(位图、GIF 和特性文件)
- 将源文件编译成本机目标代码
- 在 SWT 中静态或者通过共享库链接
- 创建一个可执行程序
- 提供将应用程序打包成一个 JAR 文件的能力(如果要将应用程序部署到 JVM 以便测试或作它用,可以很轻易地用构建文件做到)
构建文件只有一个设置供您配置:您将使用的库类型。在缺省情况下,构建文件假设您正在使用静态库。如果要使用共享库,只需将
link 特性设置成等于 dynamic(例如,
ant -Dlink=dynamic)。与其它构建文件一样,可以输入
ant help来获得配置选项的进一步描述。
让我们用 ControlExample 样本应用程序尝试构建文件。该应用程序演示很多 SWT 窗口小部件。它与 SwingSet 应用程序类似,后者是一个流行的 Swing 演示应用程序。要构建该应用程序,导航至您将本文所包括的源文件解压缩的地方,然后导航至
ControlExample 目录。输入
ant(同样,对于共享库,要输入
ant -Dlink=dynamic)。假设您已经创建了 SWT 库(在
../Library 目录中),构建文件应该无错误地运行。
在完成构建文件之后,就可以运行该应用程序了 — 嗯,差不多是这样。首先,你需要提供对 SWT 所需的一些库的访问。这些库主要是 SWT JNI 库。当您在 JVM 中运行 SWT 应用程序时,这一步也是必需的。在您解压缩本文源代码的目录中,导航至
Eclipse_2.0.2_SWT_Source 目录,然后按照对应于目标操作系统的指示进行操作。
- 对于 Windows,将
plugins\org.eclipse.swt.win32\os\win32\x86\swt-win32-2052.dll 文件复制到您路径(PATH)中的目录(例如
c:\WINNT\system32 )。或者,也可以修改 PATH 以指向该目录(例如
PATH=C:\MyExtractDir\Eclipse_2.0.2_SWT_Source\plugins\org.eclipse.swt.win32\os\win32\x86\;%PATH% )。
- 对于 Linux/GNOME,将文件
plugins/org.eclipse.swt.gtk/os/linux/x86/libswt-gtk-2052.so 和
plugins/org.eclipse.swt.gtk/os/linux/x86/libswt-pi-gtk-2052.so 复制到系统库所在的目录(例如
/usr/lib )。如果正在使用共享库,则还需要将共享库复制到系统路径(例如
~/MyExtractDir/Library/lib-org-eclipse-swt.so )。或者,也可以临时设置环境变量
LD_LIBRARY_PATH ,以指向这些文件所在的目录。例如,在 bash shell 中:
export LD_LIBRARY_PATH=~/MyExtractDir/Library:
~/MyExtractDir/Eclipse_2.0.2_SWT_Source/plugins/
org.eclipse.swt.gtk/os/linux/x86:$LD_LIBRARY_PATH
|
- 对于 Linux/Motif,将
plugins/org.eclipse.swt.motif/os/linux/x86/libswt-motif-2052.so 复制到系统库所在的目录(例如
/usr/lib )。另外,将
libXm.so.2 复制到同一目录。如果正在使用共享库,则还需要将共享库复制到系统路径(例如
~/MyExtractDir/Library/lib-org-eclipse-swt.so )。或者,也可以临时设置
LD_LIBRARY_PATH 环境变量,以指向这些文件所在的目录。例如,在 bash shell 中:
export LD_LIBRARY_PATH=~/MyExtractDir/Library:
~/MyExtractDir/Eclipse_2.0.2_SWT_Source:
~/MyExtractDir/Eclipse_2.0.2_SWT_Source/plugins/
org.eclipse.swt.motif/os/linux/x86:$LD_LIBRARY_PATH
|
请注意,如果您得到一条关于字体的错误消息,请尝试使用
export LANG=en_US.iso88591 命令。
设置好所有的文件之后,尝试运行应用程序。您应该看到类似于图 1 的屏幕。
图 1. ControlExample 应用程序
如果运行应用程序时遇到麻烦,则需要检查几项。在 Linux 中,如果应用程序在查找共享库时遇到麻烦,您将得到一条类似于以下的消息:
./AddressBook: error while loading shared libraries: lib-org-eclipse-swt.so:
cannot open shared object file: No such file or directory
|
如果应用程序无法找到某个 JNI 共享库,则您将得到一条类似于以下的消息:
Exception in thread "main"
|
无论是哪种情况,都要验证是否已经将必需的库复制到系统库目录(例如
/usr/lib )。
在 Windows 中,如果应用程序无法找到 JNI DLL,则不会发生什么事情 ― 您不会得到任何输出,而且不会显示应用程序。要强行得到一些调试输出,首先从 build.xml 构建文件删除
<arg value="-mwindows"/> 这一行。通过输入
ant clean(以便从头开始)重新运行构建过程,然后输入
ant。
现在,当您运行应用程序时,它将在命令提示符的位置显示与以下类似的错误输出:
Exception in thread "main" java.lang.UnsatisfiedLinkError:
swt-win32-2052: file not found
|
如果您得到这条错误消息,请验证 swt-win32-2052.dll 文件是否位于系统路径(PATH)中的目录中。
在继续进行之前,请查看本文所包括的其它应用程序。其中有一个小型文本编辑器示例和一个演示悬浮式帮助的示例。要构建那些应用程序,请遵循与 ControlExample 应用程序相同的过程。
用 Eclipse 进行本机构建
最后,我们来研究如何在 Eclipse IDE 中使用所有这些工具。将 IDE 与 GCJ 的本机编译能力结合起来将产生一个方便且功能强大的开发环境。您可以利用方便的 Eclipse 特性(如代码完成和调试器),还可以进行本机编译。
要进行设置,首先确保安装了 Eclipse 2.0.2(其它 2.x 版本也可以工作)。然后,启动 Eclipse。在缺省情况下,Eclipse 带有 Ant 1.4。因为构建文件要求有 Ant 1.5,所以您需要将它升级为 Ant 1.5。这实际上是一个非常简单的过程。选择
Windows > Preferences,然后导航至
External Tools。展开 External Tools,然后选择
Ant。您应该看到类似于图 2 的屏幕。
图 2. 修改前的 Ant 类路径
选择两个 ant JAR 文件(ant.jar 和 jakarta-ant-1.4.1-optional.jar),然后单击
Remove。然后,单击
Add Jar。导航至 Ant 安装目录的
lib 目录。选择
ant.jar,然后单击
Open。再次单击
Add Jar,这一次选择
optional.jar。当您全部做完时,您应该看到类似于图 3 的屏幕。
图 3. 包含 Ant 1.5 JAR 的 Ant 类路径
现在,需要为样本应用程序创建一个项目。选择
File > New > Project。在产生的对话框中,选择左窗格中的
Java和右窗格中的
Java Project。单击
Next,给出项目名称,然后单击
Finish。
创建完项目之后,导入一个样本应用程序。在本示例中,我们使用
TextEditor 样本。完成以下步骤:
- 在命令提示符处,导航至本文所包括的源代码被解压缩的目录。到达该目录之后,导航至 TextEditor 应用程序,然后输入
ant clean 以清除
.o 和
.class 文件。我们并不真的想把这些文件导入 Eclipse 工作空间。
- 单击新创建的项目,然后选择
File > Import。
- 在产生的对话框中,选择
File System,然后单击
Next。
- 单击
Browse按钮,然后导航至本文所包括的源代码被解压缩的目录。到达该目录之后,导航至 TextEditor 应用程序,然后单击
OK。
- 确保单击了左窗格中
TextEditor 旁边的框。这将确保导入所有源代码、资源和构建文件。单击
Finish。您的屏幕看起来应该类似于图 4。
图 4. 代码导入
既然您已经设置好,我们可以尝试一次本机编译。为此,在 Eclipse 中对
build.xml单击鼠标右键,然后选择
Run Ant。应该显示类似于图 5 的对话框。
图 5. Ant 运行对话框
在 Arguments 域中,我们需要提供以下三个特性的值:链接类型(只有在进行动态链接时才适用)、SWT JAR 文件的位置(以便编译器具有至 SWT 类的引用)以及您 SWT 库(您先前编译过的 SWT 库)的位置。例如:
-Dlink=dynamic -Dlibrary_dir=/home/jdoe/MyExtractDir/Library/
-Dswt.jar=/usr/local/eclipse/plugins/org.eclipse.swt.gtk_2.0.2/ws/gtk/swt.jar
|
在 Linux 中,注意不能在 Arguments 域使用颚化符号。出于某种原因,它会生成错误。使用全限定路径名(如
/home/jdoe/MyExtractDir... ,而不要使用
~/MyExtractDir... 或
~jdoe/MyExtractDir... )。
一旦填充了 Arguments 域,单击
Finish,然后让构建程序运行。如果得到错误信息,最可能的原因就是路径问题。再次检查 Arguments 域中的设置以确保它们引用有效的路径。
展望
尽管我没有在 AIX、HP/UX 或 Solaris 中测试过,但本文所描述的过程在这些系统中应该仍可工作。另外,如果您有一台 Macintosh 机器,那么安装 GCJ 和 Ant 并运行构建过程将会很有趣。在 MacOS 系统上,源代码有些滞后于其它操作系统的代码。因此,如果得到编译错误,您可能必须使用一些小型补丁。
另一个值得尝试的很“酷”的事是交叉编译。如果一切都设置正确,您可能会拥有一台可以为多种目标操作系统创建 SWT 应用程序的计算机。您只需为多种目标操作系统设置一个 GCJ 交叉编译器即可。有关交叉编译的信息,请浏览 GCJ/GCC 网站(请参阅
参考资料)。请记住:构建交叉编译器是很具挑战性的,但是如果有足够的文档作参考再加上其他用户的帮助,应该是可以实现的。
衷心感谢 GCJ 开发人员。在过去一年里,GCJ(特别是用于 Windows 的 GCJ)取得了长足的进步。没有他们的才干和奉献,我们将不会有这样有趣和独特的产品。
参考资料
关于作者  | 
|  | Kirk Vogen 是一名富有编程激情的 Java 热衷者。他在 IBM Global Services 致力于使用 WebSphere 构建电子商务应用程序。可以通过
kirkvdevw@us.ibm.com与他联系。
|
对本文的评价
|