2010-01-05

autotools, deb 和 PPA 不完全攻略

最近在给自己的GameConqueror折腾 PPA, 那少不了折腾标题里的三样东西。下决心看了一遍三个东西的文档,整理如下

链接
autotools:
AutoconfAutomake

deb packaging:
Debian New Maintainers' Guide
Ubuntu Packaging Guide
Building Package for PPA

PPA stuff
PPA Overview
Uploading


那么一个一个说:
注意: 本篇系个人总结而非教程,如有疑问请参阅上述链接。


1. AUTOTOOLS
autotools 的精髓是让开发者免于手写繁琐的Makefile,同时又让最后生成的源码包符合GNU的一套标准。然而autotools本身也很难用。。。入门门槛比较高。当然难用是相对的,掌握了基本要领就可以了

需要手写的文件一般是一个configure.ac和若干个Makefile.am, ac和am分别是autoconf和automake的缩写

configure.ac定义了源码包整体信息,如名称,版本,编译环境等,最后根据configure.ac输出configure,而configure可以判断编译环境是否满足需要,这就是著名的./configure && make 的前一半

Makefile.am则是Makefile的另一种格式,由于绝大多数C/C++或一些其他语言的程序编译,打包,安装等等都是同一模式,所以才有了automake,Makefile.am的作用是决定程序的编译方式,还有各个文件的类型,是否打包,安装位置等等,这些由automake生成许多Makefile.in一起打包,等到编译时./configure会把Makefile.in再变成Makefile

关于configure.ac, 最开始可以用autoscan生成一个模板,自己慢慢改,有许多宏,都可以在autoconf的网页上查到

一般(我看到的)分为两个部分,前一半检查编译环境,后一半把检查的结果输出,一般就是进行宏替换等等。

检查编译环境,一般无非是编译器(是否存在,编译选项,特性支持),库(是否存在,版本),条件编译(是否启用的某个功能,或其他编译时指定的参数),这一部分去查AC_CHECK*,AM_CONDITIONAL这些宏好了,很好用

第二部分是宏替换,相关的宏是AC_CONFIG_FILES和AC_OUTPUT。Makefile.in是自动生成的,也会自动被替换,不用管它。我遇到的情况是需要写一个脚本,里面有个路径是安装路径,这样的话,我需要写一个script.in:

DATAPATH=@INSTALLPATH@

# do anything with $DATAPATH

然后在configure.ac里加上AC_CONFIG_FILES([script])

以及AS_AC_EXPAND(INSTALLPATH, "some path")

这样到时候configure的时候就会生成一个script,里面是DATAPATH=some path

其中AS_AC_EXPAND不是autotools里的宏,我是从ubuntu-tweak包里抄来的,再往上就找不到确切出处了

把这段放configure.ac里就好了
dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
dnl
dnl example
dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local

AC_DEFUN([AS_AC_EXPAND],
[
EXP_VAR=[$1]
FROM_VAR=[$2]

dnl first expand prefix and exec_prefix if necessary
prefix_save=$prefix
exec_prefix_save=$exec_prefix

dnl if no prefix given, then use /usr/local, the default prefix
if test "x$prefix" = "xNONE"; then
prefix=$ac_default_prefix
fi
dnl if no exec_prefix given, then use prefix
if test "x$exec_prefix" = "xNONE"; then
exec_prefix=$prefix
fi

full_var="$FROM_VAR"
dnl loop until it doesn't change anymore
while true; do
new_full_var="`eval echo $full_var`"
if test "x$new_full_var" = "x$full_var"; then break; fi
full_var=$new_full_var
done

dnl clean up
full_var=$new_full_var
AC_SUBST([$1], "$full_var")

dnl restore prefix and exec_prefix
prefix=$prefix_save
exec_prefix=$exec_prefix_save
])

另外需要看看AC_SUBST这个宏以及一些标准路径定义,如datadir等等

那么configure.ac基本就这么回事了,下面是Makefile.am

网上的很多教程上来就说“对于一个简单的hello程序,我们可以写如此一个Makefile.am”,但是再往下就没有了。但是像我每次看到Makefile.am里面的bin_PROGRAMS, xxx_SOURCES等等,我会想bin是啥玩意, PROGRAMS又是啥 -- 基本没查到,只能看文档。

实际是这样的
bin_PROGRAMS: bin是安装路径,即${prefix}/bin, 而prefix就是configure时指定的那个--prefix
_PROGRAMS: 是autotools里预设的宏,好比说,我想到了LaTeX里的\documentclass,基本就是一回事,其他还有_SCRIPTS, _DATA, _LIBRARIES,具体去查文档

如果定义了bin_PROGRAMS = scanmem # scanmem就是我正在搞的那个包
那么下面就会有scanmem_SOURCES = xxx.c yyy.c 这种,scanmem_XXX就是指定scanmem的具体内容了,除了_SOURCES还有_CFLAGS等等

类似的例子是dist_doc_DATA = AAA BBB, 这样 AAA BBB 会被安装到 docdir 里去,这也是个标准定义,一般是${prefix}/share/doc/$PACKAGE。 dist_则是前缀,为了将来把AAA BBB一起打包, make dist 默认是不把_DATA的内容放到包里

另外你可以可以自己写scanmem_PROGRAMS这种,但是要注意定义scanmemdir,就是对应的安装目录

还有一些:
EXTRA_DIST: 这种是强制把某些内容放到源码包里
SUBDIRS: 表示make的时候需要光顾的目录,如果 SUBDIRS = aaa . bbb, 那么就分别到aaa, 当前目录和bbb去make一番

常用的就这些把,记得把每个目录的Makefile.am都加到configure.ac里去,如
AC_CONFIG_FILES([Makefile
src/Makefile
xxx/Makefile
])

所有东西都搞完以后打个autoreconf (如果缺文件可能需要加--install)就齐活了,这时候已经可以./configure && make 了,如果想打包就make dist,这时候才终于发现了autotools的好用。。。

关于autotools的感想就这么多,总之还是看文档最有效,说的已经很清楚了。

2. DEB 打包
首先需要装一堆脚本,我也忘了有哪些了
主要需要的是debian这个目录,里面必要的文件是control copyright changelog rules这几个文件,如果没有的话可以用dh_make -e 这个命令生成一些基本的,但是我还是建议对照着一个现有的deb包看

control最简单了,照猫画虎就好了,第一大段是源码包信息,下面若干段是deb包信息,这个源码包最后打出几个deb包来就写几段

changelog需要一定格式,用dch命令,非常好用

dch:在最新的changelog entry加一段文字
dch -i: 新建一个changeleog entry,版本修订号加1
dch -v :新建一个changelog entry, 指定版本号为version

另外,最后的deb包的版本是由changelog最新一项决定的

rules:这个是打包用的Makefile,对于简单的包,可以用cdbs,虽然一听新名词显得很麻烦,但是实际上只需要如下几行

#!/usr/bin/make -f

include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/autotools.mk

DEB_CONFIGURE_EXTRA_FLAGS := --enable-gui

就行了,最下面是自定义的configure参数,还有一些其他的类似的变量

另外务必在control的Build-Depends里加上cdbs

copyright:最“没用”也是最难搞的,说明这个包是谁整的,原来作者是谁,原来的文件分别的版权和协议(由于我的包是多作者多协议,所以很麻烦),最后是这个包的协议。 这个文件对照着说明慢慢整好了。。。

这些文件都搞定以后,用debuild或者dpkg-buildpackage就好了

具体操作是这样:

首先搞来源码包,如scanmem-0.09.tar.gz,把它改名为scanmem_0.09.orig.tar.gz,注意包和版本号中间的-改为_,另外就是加个.orig
然后解压,进入scanmem-0.09目录,建立debian目录,写需要的东西。(可以用dh_make或者copy一份)
然后debuild,等会儿就好了

其他说明
1.debuild是编译成.dsc .orig.tar.gz .diff.gz这三个文件,还有个.changes 而dpkg-buildpackages则是最终搞若干个.deb

2.我的另一个需求是一个源码包搞出两个deb package出来,这个我搜了好久,现在似乎唯一可用的资源是ubuntu packaing guide以及这个链接http://www.miriamruiz.es/weblog/?p=42,我再整理一下,大致是这个样子

我现在是想编译两个包,分别是scanmem和gameconqueror,那么control文件里自然要分别写一套信息,而另一方面在debian目录里建立scanmem.install gameconqueror.install两个文件,分别是需要的文件列表,可以用通配符,例如
#scanmem.install
usr/bin/scanmem

#gameconqueror.install
usr/bin/gameconqueror
usr/share/gameconqueror/*

这样就可以了。

另外就是,默认rules是把需要的内容安装到debian/tmp/下,而如果用dh_make按照single binary的设置输出,rules文件会设成安装到debian/scanmem,需要改成tmp,否则报错

由于我主要是给PPA打包,所以用到的是debuild, dpkg-buildpackage以前自己编译内核是用过

3.我看了Debian的打包说明,发现了svn-buildpackage这个好东西,适合我这种直接在svn里搞的人。

直接在svn里建立debian目录和相关文件,然后svn-buildpackage --svn-builder=debuild -S -sa -k就搞定了,最后的东西到../build-area里去找,另外--svn-builder后面这堆参数是为PPA用的

3. PPA
ubuntu 社区的PPA确实是个好东西,装了很多PPA很是羡慕,现在也终于有一个自己的PPA了

激活PPA的大致流程是:

注册Launchpad帐号
建立一个PPA,设置名称,说明等等
创建一个自己的OpenPGP密钥,发布到Ubuntu Key Server, 再导入到Launchpad
签署Ubuntu Codes of Conduct,就是拿自己的私钥加密一个文件再上传

所有步骤在上面所述的PPA Overview链接都有说明,界面简介,高效,甚至有趣,我在操作过程中笑了好几次。倒不是多幽默,主要是确实好用,也是第一次实际操作公钥私钥这种东西。

然后就是上传了,按照Uploading Guide 慢慢来就好了。如果编译没问题,这一步很简单。只是注意要导入自己的公钥,以及签署Ubuntu Codes of Conduct。



基本就这些了,再一次跟开源世界亲密接触,真爽!
发表评论