打包 processing 的小结

这货的介绍和打包这货的原因写在 这篇帖子 ](介绍给大家一种简单又酷炫的语言 processing) 里。

打这个包修修补补弄了好几次,现在总算跑起来了。期间学到了不少以前不知道的新知识,作个小结。

processing 是使用 ant 进行 build 的,所以 build 很简单,直接运行 ant run 就可以了。不过第一次上传编译了不到一半就出错了:

   81s]       [get] Getting: http://processing.googlecode.com/files/jre-7u40-linux-x64.tgz
   81s]       [get] To: /home/abuild/rpmbuild/BUILD/processing-2.2.1/build/linux/jre.tgz
   81s]       [get] Error getting http://processing.googlecode.com/files/jre-7u40-linux-x64.tgz to /home/abuild/rpmbuild/BUILD/processing-2.2.1/build/linux/jre.tgz
   81s] 
   81s] BUILD FAILED
   81s] /home/abuild/rpmbuild/BUILD/processing-2.2.1/build/build.xml:196: The following error occurred while executing this line:
   81s] /home/abuild/rpmbuild/BUILD/processing-2.2.1/build/build.xml:645: java.net.UnknownHostException: processing.googlecode.com
   81s] 	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:178)
   81s] 	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
   81s] 	at java.net.Socket.connect(Socket.java:579)
   81s] 	at java.net.Socket.connect(Socket.java:528)
   81s] 	at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
   81s] 	at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
   81s] 	at sun.net.www.http.HttpClient.openServer(HttpClient.java:527)
   81s] 	at sun.net.www.http.HttpClient.<init>(HttpClient.java:211)
   81s] 	at sun.net.www.http.HttpClient.New(HttpClient.java:308)
   81s] 	at sun.net.www.http.HttpClient.New(HttpClient.java:326)
   81s] 	at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:996)
   81s] 	at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:932)
   81s] 	at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:850)
   81s] 	at org.apache.tools.ant.taskdefs.Get$GetThread.openConnection(Get.java:660)
   81s] 	at org.apache.tools.ant.taskdefs.Get$GetThread.get(Get.java:579)
   81s] 	at org.apache.tools.ant.taskdefs.Get$GetThread.run(Get.java:569)
   81s] 
   81s] Total time: 31 seconds
   81s] error: Bad exit status from /var/tmp/rpm-tmp.BI510k (%build)
   81s] 
   81s] 
   81s] RPM build errors:
   81s]     Bad exit status from /var/tmp/rpm-tmp.BI510k (%build)
   84s]    73.641749] SysRq : Power Off
   84s]    73.644350] reboot: Power down

对照了一下错误发现在它的 build.xml 里有这样一段:

<get src="http://processing.googlecode.com/files/${jre.file}" 
       dest="linux/jre.tgz" 
       usetimestamp="true" />

就是说在编译过程当中需要到 processing.googlecode.com 下载一个东东然后才能编译。而在 OBS 上编译的时候每次都会卡在这一步。

搜了一下这个 java 异常 「java.net.UnknownHostException」。说可能是因为网址没有写对(据说有时候要去掉 http:// 什么的),已经可以排除这个,因为改了会有别的错误,而且我本地 build 是通过的。剩下只有可能就是网络不通和系统 host 有错这种情况。

所以现在怀疑 是不是 OBS build 的时候是不是不能连接到外部网络? 如果确实是不能的话,那么考虑直接下载这个 jre.tgz 添加的到源码包里面去。

先想着本地下载这个包添加到源码里去。但是发现本地完全下不下来这个 jre.tgz。。。一看到带有 google 字眼。。。只有第一次 build 的时候花了半个多小时靠运气才弄好。那次编译的时候 install 有个打字错误,file 也没写。但是可以肯定 build 是过了的。等弄好那个以后发现本地编译会一直卡在那个下载的步骤(和 OBS 不一样,是卡住不是报错)。

所以考虑让 OBS 帮着下这个包。作为源码的一部分。搜了一下发现 OBS 是可以这样做的。这就源代码处理服务。

  1. 源代码处理服务
    wiki 上说是:

我们要用到的就是「从网络抓取源代码」。这个很简单。

这个用 osc 的话非常方便的。osc 和版本控制比如 git svn 什么的相似。可以用来管理控制你的私人车库。你可以用 osc ls 来列出可以用的仓库,用 osc checkout 来检出我们的仓库。然后操作完了以后可以用 osc commit 来上传。具体参考 wiki 。

我们可以用 osc add 来添加一个远程的代码像这样:
osc add < 目标文件的网址>

让我们来试一试。

osc add http://processing.googlecode.com/files/${jre.file}

。当然直接这样是不行的。这里有个 ${jre.file} 变量,spec 是不认得的。让我们我们要向上找找这个东西到底指的是什么。这个过程就略去了。直接在 build.xml 里查找 jre.file 出现的地方就好了。我们发现原来根据不同的架构和系统会有不同的文件需要下载。这里我们需要下载两个。jre-7u40-linux-x64.tgz 和 jre-7u40-linux-i586.tgz。

好了现在我们添加:

osc add http://processing.googlecode.com/files/jre-7u40-linux-x64.tgz
osc add http://processing.googlecode.com/files/jre-7u40-linux-i586tgz

这样添加以后会在你的软件包目录里多出一个 _service 文件。检查一下里面的内容:

<services>
  <service name="download_url">
    <param name="protocol">http</param>
    <param name="host">processing.googlecode.com</param>
    <param name="path">/files/jre-7u40-linux-i586.tgz</param>
  </service>
  <service name="download_url">
    <param name="protocol">http</param>
    <param name="host">processing.googlecode.com</param>
    <param name="path">/files/jre-7u40-linux-x64.tgz</param>
  </service>
</services>

每次编译前都会执行它。然后当你需要使用下载的包的时候只要直接用源码包的名字就可以了。你就可以当作这个源码包已经在你的仓库里了。

最后在 spec 文件的 source 字段里添加这两个文件。然后 copy 或者 mv 到源码包里就好了。比如我是这样的。

cd build
cp %{SOURCE2} %{SOURCE3} .

好啦我知道用宏会高级一点而且可靠一点,但是暂时就先这样。让他跑起来再说。。。

完了我们需要更改那个 build 文件让他不从外部下载文件,而是从源码包里直接 move 到相应位置。(事后想了一下也可以直接在 spec 中把他 copy 到目标目录)。我们先来看一下怎么给这个 build.xml 打补丁。

  1. 打补丁
    补丁就是你修改了源代码以后对源代码修改的一个记录。为什么不直接改了算了呢?主要还是为了便于管理吧。

生成补丁的方式还蛮多的,但大同小异。比如我喜欢这样做:
我之前有在本地测试,所以 ~/rpmbuid/BUILD 目录下会有一个很干净的解压好的源代码目录。我就直接使用它 copy 出一个旧的目录。比如这样

cp processing-2.2.1 processing-2.2.1.orig

然后去 processing-2.2.1 里修改代码。照着 build.xml 里其他的 move 代码依样画葫芦就好了。

删掉

<get src="http://processing.googlecode.com/files/${jre.file}" 
       dest="linux/jre.tgz" 
       usetimestamp="true" />

添加

<move file="${jre.file}" tofile="linux/jre.tgz" />

然后生成一个补丁:

diff -uNr processing-2.2.1.orig processing-2.2.1 >../SOURCES/build.patch

补丁的名字随意,只要是 patch 结尾就好了。但是最好也是和你补丁的内容有关,长点无所谓,让人看名字就大概知道这个补丁干什么的最好,这里我就偷懒了,直接叫 build.patch。检查一下补丁的内容:

diff -uNr processing-2.2.1.orig/build/build.xml processing-2.2.1/build/build.xml
--- processing-2.2.1.orig/build/build.xml	2014-06-28 12:14:03.835963273 +0800
+++ processing-2.2.1/build/build.xml	2014-06-28 20:08:27.423042408 +0800
@@ -640,9 +640,7 @@
 	      value="jre-tools-6u37-linux${sun.arch.data.model}.tgz" />
     -->
 
-    <get src="http://processing.googlecode.com/files/${jre.file}" 
-	 dest="linux/jre.tgz" 
-	 usetimestamp="true" />
+    <move file="${jre.file}" tofile="linux/jre.tgz" />
 
 <!--	   
     Cannot use ant version of tar because it doesn't preserve properties.

好了,只要在 spec 文件中添加这个补丁就 ok 了。

把补丁和修改了的 spec 文件上传。编译。

3.Packaging desktop menu categories
但是又错了。。。不过这次 build 已经通过了。算是个好消息吧。build 通过了对于这个 java 程序来说剩下的就是把 build 出来的东西 copy 到系统里就好了。先来看看这个錯喔。

WARNING: Empty GenericName:
/home/abuild/rpmbuild/BUILDROOT/processing.x86_64//usr/share/applications/processing.desktop

Categories 错误。因为这个软件是一个你需要在 desktop 文件中加入下面这个东东才可以。这样安装好了以后才会让软件在正确的分类中显示,比如我们要在 kickoff 中找到他。这里我们只要添加

Categories=Development;IDE;

到 desktop 文件里就行了。如果是其它类型的软件可以参考 wiki。里面有很多分类。

但是我的 desktop 是直接 copy 之前教育源那个旧版的 processing 的,为什么会错呢?原来他里面是有这句的。我当时觉得无关又看不太懂就给删了。

%if 0%{?suse_version} > 1020
%suse_update_desktop_file %{name} Development IDE
%fdupes -s %{buildroot}
%endif

10.2。。好像我们没有那么低的版本。。。不管删了,直接在 desktop 里改。

好了,再上传编译。

4.arch-dependent-file-in-usr-share
在安装完了以后报了一堆的错误,都是 arch-dependent-file-in-usr-share。

这又是为什么呢?编译和安装都成功了这又是为什么恩?原来这是 osb 里的 rpmlint。

因为这个程序是一个 Java 程序。它自带了一个 java,然后所有的库啊执行文件什么的都在一个目录里。我们安装的时候就是简单的把这些东西全都 copy 到 /usr/share 里。然后写一个 processing 脚本扔到 /usr/bin 里让这个脚本运行的时候可以执行 /usr/share 中的可执行文件。但是 OBS 在完成了编译以后会检查。一检查完了,被发现了。一些依赖架构的 lib 文件怎么可以放在 /usr/share 下呢!但是这个程序就是这样。你把它拆开了他就不能正确运行了。那要怎么办呢?

我们可以让 rpmlint 不要报这个错误,告诉他们这是没有问题的。这时候我们需要在源码里再添加一个 processing-rpmlintrc。这个文件只要添加就好了。然后我们需要在里面写点什么让它忽略这些警告和错误。要怎么写呢?好在原来的那个 processing 包里有这个文件我们直接拿来用好了。

addFilter("E: arch-dependent-file-in-usr-share")
addFilter("W: unstripped-binary-or-object")
addFilter("W: script-without-shebang")
addFilter("W: hidden-file-or-dir")
addFilter("W: file-not-in-%lang")

具体什么意思可以参考 wiki。这里主要就是第一条,让他忽略 arch-dependent-file-in-usr-share 这个错误。

好了,再上传,编译终于成功了,现在我们的软件终于跑起来。。。。。真是不容易。下载安装运行一下:


恩,很好,他安安稳稳的呆在开发 - 集成环境这一栏里。可以添加模块和运行。

  1. 其它
    反思一下很多错误之前还是可以避免的,比如最后那个应该在本地用 rpmlint 就可以检查出来。不过也确实了解很多以前不知道的东西,比如 rpmlint 的检查、desktop 可能出错的地方、源码服务以及 osc 的很多用法。

以后有空弄一下 osc 看能不能让他挂载 iso 在本地测试编译,不要每次都上传了,虽然 OBS 很土豪,但是节约点资源总是好的。还有怎么用 osc 和别人协作、通过 obs 为其他项目服务等等,毕竟如果每个人都只是弄自己的个人源话 openSUSE 也不会有那么多稳定可靠的软件是吧。

好了不多说了先去复习考试。。。。祝各位学生同学考试顺利。。。。

PS:最后想说在 openSUSE 下学习打包还是相当幸福的,因为基本上所有 wiki 里的东东玛格学姐都给翻译了。。。。真是不容易啊。。。。

1赞

写得不错,学习收藏了。个人比较懒,每次都是改改别人的 SPEC :sweat:
源代码处理服务,不知道可不可以 git clone 这样抓源码?

可以的。可以用源代码服务来构建一个软件的每日版。它是支持从 github 这样的 git 仓库直接抓源代码然后压缩归档。