程序方程式

PkgFile介绍

1. 概述

Pkgfile遵循bash shell的语法规则,所以它看上去像是一个bash shell脚本,但不能称之为脚本,因为它不能单独执行,它只能作为pkgmk命令执行过程的配置文件。Pkgfile文件利用自身定义的变量以及函数, 为 “pkgmk命令应该怎样去编译一个二进制包“ 制定好了规则。pkgmk命令会根据Pkgfile中的环境设置编译出满足特定需求的二进制软件包(因为./configure 命令和它的参数,以及 make 命令和它的参数都写在了这个 文件中)。从这里就可以看出,Pkgfile的存在到底有什么意义,试想一下,如果咱们不用Pkgfile,那么每次编译一个软件包的时候就需要咱们重复去写./configure的内容、make的具体内容,这显然增加了咱们的工作 量,降低了工作效率。当然,这只是最显而易见的配置,与在这样的配置下体现出来的优势,其实这个文档中还有其他很多配置,比如安全性配置,打补丁等,这些知识都会随着作者使用经验的增加而添加进这个文档, 详细说明之。

本文档将会介绍Pkgfile文件的格式,看懂了基本格式,再加上以后使用中慢慢地体会,就会理解使用pkgmk命令编译二进制软件包的所以然和Pkgfile文档给我们带来的方便。在介绍格式的过程中,咱们以阅读编译 apache时用到的Pkgfile文件点击查看的形式进行。 我会以给代码添加注释的方式介绍Pkgfile文档,约定注释行以//开头。为什么不用“#”?因为Pkgfile中的注释用的是#,我用//以示区别,没别的意思。对于在编译apache二进制包的Pkgfile中没有涉及到的内容,会另行介绍。

还有一点需要明确的是,当咱们拿到一个源码包,需要把它编译成咱们需要的二进制包的时候,需要自己动手从头到尾写一个Pkgfile文件吗?答案是,不需要。可以下载要编译的源码包到工作目录(新建的那个用来 编译二进制包的目录)下,切换到工作目录下之后,在命令行输入命令mkpkgfile就可以生成一个Pkgfile文件,然后按照特定的需求进行改动,这个文件始终位于咱们在编译安装包的工作目录中。

另外,下面是《鸟哥的Linux私房菜.基础学习篇(第二版)》第412页的一段话,我觉得对咱们理解编译二进制包有一定的帮助,摘抄如下:
是否想过,如果您的Linux系统与厂商的系统一模一样,那么,在厂商的系统上编译出来的执行文件自然也就可以在您的系统上运行了。也就是说,厂商先在他们的系统上编译好用户所需要的套件,然后将编译好的 可执行套件直接发布给用户安装,这样,由于我们本来就使用厂商的Linux版本,系统是一样的,那么使用厂商提供的编译好的可执行文件就没有问题。简而言之,利用类似Windows的安装方式,由程序开发人员直接在 已知的系统上编译好,再将该程序供用户安装。

2. 编译apache二进制包时用到的Pkgfile

咱们来看看编译apache二进制包时用到的Pkgfile文档,我会尽最大努力把我认为需要加注释的行添加上注释。这个文档它并没有囊括Pkgfile的所有知识点,对于那些没有在这个Pkgfile文档中体现出来的知识点,会作另行介绍。

#!/bin/bash     // 告诉系统环境,用系统中的哪个shell来执行这个文档,作用跟shell脚本中的作用一样
# $Id: Pkgfile,v 1.5 2005/03/09 18:59:59 jue Exp $      //其他的以#开头的行都是注释,用于描述Pkgfile文档的一些基本信息
# Description: Apache HTTP server version 2.0.x
# URL:         http://httpd.apache.org/
# Depends on:  apr, openssl
# Group:       apache

# Packager: Zhao Yi <yzhao@linx-info.com>

#
# Changelog:
#

# 2007-02-05 Zhao Yi <yzhao@linx-info.com>
# release=x86_64-linx-3
# change start-script name from Apache2 to apache.

# 2007-01-04 Zhao Yi <yzhao@linx-info.com>
# release=x86_64-linx-2
# Initial version.

# Date  2008-10-20
# Author:       Tian Gengbao <gbtian@linx-info.com>
# release:      x86_64-linx-Rocky4.2
# Description:  release Rocky4.2 Generic version (Not Security Enhanced)  
#  
#

name=apache         // name在这里就是声明了一个变量,此变量表示要生成的二进制包的名字。这里需要apache的二进制包,所以给name变量赋值时用了apache。要编译什么包,改成什么包名字就好。
version=2.4.12      // version变量表示的是所用的源码包的版本,这里从网上下的apache的源码包的版本是2.4.12,所以给version变量赋值时用的是2.4.12。要编译的源码包是什么版本,改成对应版本号就好。
LINX_VERSION=linx   // 这里加的信息表示的是,同样的包,在咱们公司的版本号。这里咱们没有对apache作任何改动,所以这里咱们自己的版本为linx,假如哪天咱们改变了这个包里的内容,那这个版本号会改成linx1,还是
                    // 这个包,再改,就是linx2,依次类推。直到哪天人家的源码包的版本号变了,咱们又会从linx开始。


release=${PKGMK_ARCH}-${LINX_VERSION}-${OS_VERSION}     // 显然,release又是变量声明,${}是咱们熟悉的shell脚本中对变量的引用。LINUX_VERSION这个变量是咱们在上两行中定义的,那PKGMD_ARCH和
                    // OS_VERSION是从那里来的呢?这就是运行这个文档的环境提供的。
                    // PKGMK_ARCH变量表示的是系统环境所使用的微处理器的类型,比如x68_64,ia64等。
                    // OS_VERSION变量表示的是操作系统的版本号,比如Rocky4.2。


source=(http://www.apache.org/dist/httpd/httpd-$version.tar.gz \    // source中列出的是在编译二进制包的过程中会用到的源码包,要打的补丁包等。用pkgmk命令编译需要的二进制包的过程中,会在工作
        $name-$version-ssl_cert.patch linx.layout apache \          // 目录下检查所有在这里列出的软件包是否存在于当前的工作目录下,如果存在,编包过程中会将这些包拷贝到在工作目录下生成的
    httpd-$version-LINX-conf.patch)                                 // work/src目录下(这个目录是在编包过程中生成的,开始时没有);如果不存在,会在URL指出的地址下载;如果连URL中都没有,
                                                                    // 就会报错。如果,不把需要用到的软件包列在source下,但是在工作目录下存在,也没有问题,可以编出需要的软件包,但这不规范。


build(){                                                                    // build部分是Pkgfile文档的核心部分,所有在编译二进制包的过程中用到的命令都是在这里完成的。
    cd httpd-$version                                                       // 切换到解压缩后的源代码目录下。在编译apache二进制包时解压缩的是httpd-2.4.12.tar.gz,所以这里比较特殊。
                                                                            // 一般情况是,解压缩的源码包和要生成的二进制包是同名的,所以这条命令是cd $name-$versionif [ $PKGMK_ARCH = "i686" -o $PKGMK_ARCH = "ia64" ]; then       // 这里是对编译二进制包时所用的机器的微处理器型号的判断,基于不同的处理器平台编译出不同的二进制包。
    sed -i "s/lib64/lib/g" $SRC/linx.layout                         // $SRC就是pkgmd命令运行过程生成的wor/src目录,sed会修改这个目录下的linx.layout文件,将其中的所有lib64用lib替换掉。
    elif [ $PKGMK_ARCH = "x86_64" -o $PKGMK_ARCH = "ppc64" ]; then
    sed -i "s%/lib\>%/lib64%g" $SRC/linx.layout                     // sed命令将work/src目录下的文件linx.layout中的lib用lib64替换掉。
    fi

    if [ "$PKGMK_SEC" = "yes" ]; then                       // pkgmk命令在执行的时候,可以加上选项,当用了选项-s的时候,$PKGMK_SEC=yes是成立的。这个选项主要用于给软件包设置安全属性。
        patch -p1 < $SRC/httpd-$version-LINX-conf.patch 
    fi
    patch -p1 < $SRC/$name-$version-ssl_cert.patch
    cat ../linx.layout >> config.layout

    if [ $PKGMK_ARCH = "i686" -o $PKGMK_ARCH = "ia64" ]; then
        LIBDIR="/usr/lib"                                                   // 声明变量LIBDIR,并赋给相应的值。注意这些值是根据编译二进制包时使用的处理器类型而设定的。
        LIBEXECDIR="/usr/lib/apache"                                        // 声明变量LIBEXECDIR,并赋给相应的值。
    elif [ $PKGMK_ARCH = "x86_64" -o $PKGMK_ARCH = "ppc64" ]; then
        LIBDIR="/usr/lib64"
        LIBEXECDIR="/usr/lib64/apache"
    fi

// 下面涉及到一些./configure命令的参数。我们知道,对于不同的源码包,./configure命令的选项是各不相同的,所以咱们在编译一个二进制包的时候,如果有特殊的编译需求,还是需要到解压缩后的源码包目录下去查
// 看INSTALL文件的具体内容,它会给出咱们需要的信息。好在一些比较通用的选项,会在用mkpkgfile生成Pkgfile的时候自动添加进去。
    ./configure --enable-layout=LINX \          // Apache HTTP Server允许第三方的软件包安装,但是会导致软件在系统上的布局变动,所以这个选项可以指定自己系统上的布局。
                                                // 关于这点,apache的官方网站( http://httpd.apache.org/docs/2.4/install.html )有介绍。

                --enable-so \                   // 启用DSO性能。至于什么是DSO,可以查看一下DSO capability的相关资料。
                --enable-modules=all \          // 启用的模块,这里启用了所有的模块。
                --enable-mods-shared=all \      // 启用共享的DSO模块。
        --enable-ssl \                          // 启用ssl支持。
                --with-apr=/usr \               // 指定了apr的安装目录。
                --with-apr-util=/usr \          // 指定了apu的安装目录。
        --enable-deflate \                      // 压缩转换编码支持。
        --with-gdbm \                           // 这是安装apr-util时指定的选项,启用了apr_dbm_gdbm-1.so插件。
        --with-expat=/usr \
        --with-mpm=prefork \                    // 选择apache所使用的处理模块。
        --sysconfdir=/etc/apache \              // 只读的单一机器数据目录,用于存放httpd.conf和mime.types之类的服务器配置文件。
                --libdir=${LIBDIR} \            // 对象代码库的存放目录,这里引用了上面定义的变量LIBDIR。
                --libexecdir=${LIBEXECDIR} \    // 程序可执行目录,也就是动态加载模块目录的存放路径,这里也是引用了上面定义的变量LIBEXECDIR。
                --with-libdir=${LIBEXECDIR} \
        --localstatedir=/var \                  // 可改写的单一机器数据目录,这里指定为/var。
        --datadir=/var/www \                    // web服务器只读的体系无关数据目录。
        --mandir=/usr/share/man \               // 手册文档的存放目录。
        --infodir=/usr/share/info \             // 信息文档目录。
        --enable-nls                            // 加上自然语言支持模块。

// 上面列出了很多configure命令的选项,如果你能看懂全部选项所代表的意思,那你肯定对apache有相当的了解。我想说的是,configure后面所跟的选项是针对特定的软件包的,当咱们在编译一个软件包的时候
// 需要查看这个软件包的configure支持的选项才能编出满足特定需求的软件包。比如这里编apache的时候,怎么知道这些选项呢?首先去读一下解压缩后的源码包里的INSTALL文件,这里会提供我能需要的信息。
// 如果解压缩后的源码包里的configure命令支持help选项那更好,可以列出咱们需要的所有选项。
// 尽管不同的软件包,有自己的configure命令的选项,但是有许多基本的选项还是比较固定的,这里列举几个: 
// --help 这里首推这个选项,用它咱们就可以查看configure中的其他选项了。
// --prefix 制作出的Makefile会查看随此选项传递的参数,当一个包在安装时可以彻底的重新安置它的结构独立的部分。
// --bindir 指定二进制文件的安装位置,这里的二进制文件定义为可以直接被用户执行的程序。
// --sbindir 指定只能由超级用户执行的二进制文件的安装位置。
// --libexecdir 指定可执行支持文件的安装位置。不同于二进制文件的是,这些文件不由用户执行,但是可以由上面提到的二进制文件执行。
// --sysconfdir 指定在单个机器上使用的只读数据的安装位置。
// --libdir 指定库文件的安装位置。
// --includedir 指定C头文件的安装位置,其他语言如C++也可以使用此选项。
// --infodir 指定info格式文档的安装位置。info是被GNU工程所使用的文档格式。
// --mandir 指定手册页的安装位置。
// --build 指定软件包安装的系统平台,如果没有指定,默认值是--host选项的值。
// --host 指定软件运行的系统平台,如果没有指定,将会运行config.guss来检测。
// --target 指定软件面向的系统平台,这主要在程序语言工具如编译器和汇编器上下文中使用,如果没有指定,默认将使用--host选项的值。
// --disable-FEATURE 一些软件可以选择这个选项来提供为大型选项的编译配置。如果默认是提供这些特性的,可以使用--disable-FEATURE来禁用它。
// --enable-FEATURE 相反地,一些软件包可能提供了一些默认被禁止的特性,可以使用--enable-FEATURE来启用这个特性。
// --with-PACKAGE[=ARG] 在自由软件社区里,有使用已有软件包和库的优秀传统,当用configure来配置一个源码树时,可以提供其他已安装软件包的信息,例如,这里在编译apache是,用到了很多这个选项,可以体会一下。
// --without-PACKAGE 有时候可能希望在编译的软件包不与系统中已经安装的软件包交互,这时可以用这个选项。

    make 
    make DESTDIR=$PKG install       // make install命名用来安装软件包,DESTDIR是make命令的一个选项,它指定了软件包要安装在什么地方。$PKG是work/pkg目录,这里指定了软件包就安装在这里。

    mkdir -p $PKG/etc/apache/{ssl.key,ssl.crt}  // 在work/pkg/etc/apache目录下创建了2个目录
    touch $PKG/etc/apache/ssl.key/server.key    // 这些应该是跟apache相关的配置过程。重点是要知道这些操作都可以在Pkgfile中完成,至于如何配置apache不是咱们要讲的重点。
    touch $PKG/etc/apache/ssl.crt/server.crt
    mkdir -p $PKG/etc/rc.d/init.d
    install -D -m 754 ../apache $PKG/etc/rc.d/init.d/apache
    if [ "$PKGMK_SEC" = "yes" ]; then
     num=$(sed -n '/startproc/=' $PKG/etc/rc.d/init.d/apache)
     sed -i "$num s/ root/ httpd/g" $PKG/etc/rc.d/init.d/apache
    fi
    touch $PKG/var/log/apache/{error_log,access_log}
    chmod 1777 $PKG/var/run   
    chown -R root:root $PKG
}

3.没有在apache的Pkgfile中出现的知识点

Pkgfile文档与pkgmk命令是共生共存的,关于pkgmk命令的使用,在文档《pkg 命令说明文档V0.2.odt》中有详细的介绍。这里主要介绍编译二进制包的时候,给所编译的二进制包设置安全属性的-s,-pm,-pa选项。
(1)-s选项
当执行pkgmk命令的时候加上-s选项,会将软件包中属主和属组为”root:root”的文件更改为属主和属组为”sys:sys”;也会将参数PKGMK_SEC会设置成yes,表示要编译的是安全版的软件包,这个参数会传递给Pkgfile 、post_mk和post_add三个文件,即这三个文件中可以使用PKGMD_SEC变量。这三个文件中,分别会用if语句判断是否$PKGMK_SEC=”yes”,以确定是否在编译安全版本的软件包。如果是,要进行的一些安全操作会很自 然地在if语句中完成。
(2)-pm选项
加上这个选项之后pkgmk命令会执行post_mk文件(如有必要,这个文件会位于工作目录的根目录下。之所以这么说,是因为,并不是每一个所编译的软件包都需要这个文件),这个文件执行的过程中会修改软件包中 的文件的属主和访问权限、添加配置文件、以及添加post_add在安装完毕后设置该软件包的文件的扩展属性,系统中其他受影响的文件的包中属性也会改变。
(3)-pa选项
加上了这个选项,在这个软件包安装完成后,pkgmk命令会执行post_add.sh(如果存在,这个文件位于工作目录的根目录下),执行其中的一些操作,进行相应的安全设置。

4. 总结

这里介绍了Pkgfile文件的基本格式信息,这个文件的核心部分是build()部分,具体书写应根据安装包的实际需求进行。由于书写本文档时,作者也是个新手,所以肯定有很多不完善的地方, 在您的阅读过程中给您带来的不便敬请谅解,在以后的工作中会继续完善这个文档

发表评论