从源码包构建.deb文件的备忘

源码包是什么

我们知道ubuntu有别于gentoo之一的特点就是,gentoo是基于源码包安装的系统,而ubuntu是基于二进制的。我们执行一个apt-get install foo安装包命令时,apt从对应的apt source源地址下载一个二进制包-以.deb为后缀名的文件到/var/cache/apt/archives下,再用dpkg工具安装它们。这些.deb文件都是包的维护者在某台build machine上build之后放上去的,而与foo.deb对应的源码包,一般都是指三个文件的一个集合:foo.orig.gz, foo.dsc, foo.diff.gz. foo.orig.gz是该软件的原始源码,通常取自于git,svn或sourceforge,可以把它看作是中立的,和Linux发行版无关的源码。foo.diff.gz包含了将一份原始源码加工、改造为debian系安装包的非功能性的补丁文件,或许同时也包括一些功能性的修补源码bug的补丁。foo.dsc是一个包描述文件,它是一些ubuntu上的源码包处理工具如dpkg-source的输入。foo.diff.gz和foo.dsc扮演meta package的角色。一般来说,一个或者多个二进制包都对应一份源码包(因为多个二进制包可能由同一个源码产生),source.list的deb-src标鉴说明了可以通过apt-get从哪些网络地址获取源码包.

为什么从源码包生成软件

既然已经有了二进制包,为什么有时候还要从源码包来生成软件?因为二进制包毕竟是在别人的build machine上生成的,自然产生的二进制依赖也是基于维护人的环境。假如你想使用一个软件的更高版本,可能是因为高版本修订了当前使用版本的某个bug,或者想看看新的更省电的feature,当你把该软件高版本的apt source源添加到了source.list,然后使用apt-get update; apt-get install foo=high_version时,你发现apt-get抱怨很多运行时依赖得不到满足;而不得不把Ubuntu的整个release version升级,其实,你想做的只是升级这个软件包而已,发行版其他的部分仍然想保留已经使用了很久的版本,那这时从源码包构建软件就是必须的了。这里我个人就经历过这样的例子,在12.04LTS系统里,cairo-dock这个软件是有bug的,如果要升级,就得升级发行版,因为新的cairo-dock依赖新的xserver stack,而新的xserver stack牵涉的东西太多,那么就得升级发行版,当采用官方的源把xserver stack升级到最新版时,发现它已经帮你默认采用xmir了…天,我只是想用一个新版本的cairo-dock而已,并不想升级我的内核,libc,更不想用什么mir。这时我只有从网上下载更新版本的cairo-dock的源码包来构建,当然在构建过程中,必然会发先cairo-dock确实有些依赖不被当前的xserver stack所满足(比如用了更新的api或者数据结构都变了),那这时你就只有再把满足依赖的xserver stack包下下来编译(是一个递归收敛的过程),有可能要调整默认的编译参数(比如build最新的xserver core时把xmir disable掉)这个过程当然不容易,但做多了有经验后再碰到类似问题就相对容易多了。你也许会说从源码构建很简单啊,不就是git clone源码仓库然后./configure; make; make install吗?但这种构建方式只会产生二进制文件,不会产生二进制.deb包,操作系统的包管理器只有通过.deb包安装,它才知道用户安装过这个程序,有哪些二进制文件属于这个”包”等,这样不管以后的升级,卸载,替换等都有踪可循,如果直接从源码构建,那你以后要卸载它怎么办?你还记得它的源码放在哪里吗?它是用make uninstall卸载的还是其他什么命令?一些目录甚至可能是写死的,并且,如果你的软件包含一些库会被其他软件依赖,那么包管理器也可以通过包数据库为这些依赖提供线索,如果直接使用源码构建软件,那相当于你机器上的软件依赖链条出现了断裂,这会影响后续软件的安装卸载管理。

从源码包构建的备忘

  • 用dpkg-source -x
    foo.dsc从foo.orig.gz和foo.diff.gz创建工作目录foo:一份发行版中立的源码目录,加上一个debian目录以及目录下的meta文件,就构成了一份可以生成二进制deb包的源码工作目录。其实从apt-get
    source抓下来的目录,已经是通过dpkg-source -x解压过的了。dpkg-source
    -x所做的主要事情就是1.解压;2.把foo.diff.gz里的patch打到原始文件上。生成的foo目录下的源文件,都已经是打过deb源码包里的patch了的。
  • 在foo目录下,执行dpkg-buildpackage -us
    -uc构建包。-us和-uc参数是不做签名,适合于本地构建本地使用的情况。这个命令的输出有两个,一个是二进制deb包,另一个是源码包,为什么这里还要生成源码包?因为你可能改动某些文件,那么会生成新的diff.gz来记录所有你针对原始源码的改动,不管发布还是保存更改都更方便,下一次你只需要在生成的新的.dsc文件上执行dpkg-source -x就可以产生一个一模一样的源码了。如果你什么都没改动,那么新产生的源码包同你构建所来源的源码包是一样的。你也可以用参数-b和-S来控制这次构建只产生二进制包或者只产生源码包。
  • 两个最重要的meta文件,debian/control和debian/rules。control文件决定了哪些二进制包将从这份源码目录中构建,一个源码目录往往是好几个二进制包的输入源。你不想生成哪个屏蔽它就行。二进制包的运行时依赖关系也在包的声明中可见,并且control文件也声明了构建过程中的依赖,不过可以给dpkg-buildpackage传-d参数来忽略构建依赖。
  • debian/rules文件其实就是个Makefile,你可以执行make -f debian/rules target来单独执行某个目标。rules文件里基本上都是对debhelper脚本函数的调用,像是dh_*这样的函数,它们负责大部分的构建过程。常用的clean, install目标在rules文件中也有,有些基于源码包的Makefile上所做的事情如make clean需要通过make -f debian/rules clean来代替。
  • 和传统意义的Make过程有点不一样的就是,默认状态下,每次dpkg-buildpackage,其实都是把从configure.ac生成configure脚本,到生成Makefile,到构建source,到安装binary都做一遍,哪怕你并没有改过configure.ac,或者改过源代码.c文件,假如构建失败了,就需要尝试改动源代码重新构建,有时候需要反复尝试这个过程直到构建成功,如果包很大的话那需要花费的时间就很长,这时传入-nc参数可以让dpkg-buildpackage保留当前的构建结果,就像传统的make一样只会从出错的地方重新开始。当然,当对源代码的改动终止后,最后还是需要再执行一遍不带-nc参数的命令”dpkg-buildpackage -us -uc”来重新完全构建一遍,否则在生成源码包时可能会出错。
  • dpkg-buildpackage不用担心它会自动改变你的源文件(即通过dpkg-source
    -x产生的文件),当然前提是你确实改动的是”源”文件,比如是configura.ac而不是configure,是dkms.conf.in而不是dkms.conf。
  • 构建软件时做得最多的事就是根据自己系统的需求调整./configure参数了吧,比如–enable–xxx或者–disable-xxx,在rules文件中,通过带override前缀的target可以起到为默认的target定制参数的目的,如override_dh_auto_xconfigure:
  • 对源码包有修改最好通过dch -i来生成一个新的changelog文件,每个change item的title部分都是表示这次change的最新版本号,dpkg-buildpackage的输出二进制包的版本号其实就是从changelog里提取的(不是写在control文件里的)。

你可能感兴趣的:(Debian,ubuntu,操作系统,工具)