Skip to content

01 打包前的准备工作

1. 如何制作程序

虽然有很多方法将人类阅读的源码转换为机器码,但是可以归纳为以下三种:

  1. The program is natively compiled.
  2. The program is interpreted by raw interpreting.
  3. The program is interpreted by byte compiling.

  4. 程序是本地编译的

  5. 程序通过原始解释器解释
  6. 程序通过字节编译解释

1.1 Natively Compiled Code

本机编译的软件是指用编程语言编写的软件,编译成机器代码,生成二进制可执行文件。这种软件可以独立运行。

以这种方式构建的RPM包是特定于架构的。意味着如果你在64-bit架构的机器上编译,则不能在32-bit架构的机器上运行。打包的结果会在名字中含有特定的架构。

1.2 Interpreted Code

一些编程语言(bash、python等)不会编译成机器码。相反,他们的程序的源代码是由语言解释器或语言虚拟机逐步执行的,无需事先转换。

完全用解释型编程语言编写的软件不是特定于架构的。于是RPM包名中会含有noarch

解释型语言又分为两种,这两种类型在程序构建过程和打包过程中有所不同:

  • raw-interpreted:

Raw-interpreted 语言程序完全不需要编译,直接被解释器执行。

  • byte-compiled

Byte-compiled 语言需要被编译为字节码,然后在虚拟机中执行。

注意:某些语言可以选择两种模式中的一种。

2. 三种语言类型构建过程举例

2.1 Natively Compiled Code

C语言源码cello.c

#include <stdio.h>

int main(void) {
    printf("Hello World\n");
    return 0;
}

2.1.1 手动构建

gcc -g -o cello cello.c

执行:

$ ./cello
Hello World

2.1.2 自动构建

Makefile

cello:
        gcc -g -o cello cello.c

clean:
        rm cello

构建:

$ make
make: 'cello' is up to date.

执行:

$ ./cello
Hello World

2.2 Interpreted Code

2.2.1 Raw Interpreted Code

bello

#!/bin/bash

printf "Hello World\n"

运行:

$ chmod +x bello
$ ./bello
Hello World

2.2.2 Byte-Compiled Code

python源码可以是raw-interpreted,但是byte-compiled版本更快。因此,RPM倾向于打包byte-compiled版本以发布给最终用户。

pello.py

#!/usr/bin/env python

print("Hello World")

Byte-compile pello.py

$ python -m compileall pello.py

$ file pello.pyc
pello.pyc: python 2.7 byte-compiled

执行:

$ python pello.pyc
Hello World

3. 为软件打补丁

使用diff工具检查不同,输出补丁文件;使用patch工具对文件打补丁。类似于版本控制系统git

cello.c文件打补丁举例:

  1. 保存原文件
$ cp cello.c cello.c.orig
  1. 修改源码cello.c
#include <stdio.h>

int main(void) {
    printf("Hello World from my very first patch!\n");
    return 0;
}
  1. 使用diff生成一个补丁
$ diff -Naur cello.c.orig cello.c
--- cello.c.orig        2016-05-26 17:21:30.478523360 -0500
+++ cello.c     2016-05-27 14:53:20.668588245 -0500
@@ -1,6 +1,6 @@
 #include<stdio.h>

 int main(void){
-    printf("Hello World!\n");
+    printf("Hello World from my very first patch!\n");
     return 0;
 }
  1. 将补丁保存到文件中
$ diff -Naur cello.c.orig cello.c > cello-output-first-patch.patch
  1. 恢复原文件
$ cp cello.c.orig cello.c
  1. 使用patch应用补丁
$ patch < cello-output-first-patch.patch
patching file cello.c

4. 安装任意部件

linux使用了Filesystem Hierarchy Standard (FHS)来规定何种文件存放在哪里。

下面介绍两种方法将任意文件放在操作系统中。

4.1 使用 install 命令

有时使用自动构建工具(make等)并不是最优选择,比如,如果打包的程序简单而且不需要提取开销。此时经常使用install命令将文件以指定权限放在指定目录。

$ sudo install -m 0755 bello /usr/bin/bello

4.2 使用 make install 命令

Makefile中添加install部分:

cello:
        gcc -g -o cello cello.c

clean:
        rm cello

install:
        mkdir -p $(DESTDIR)/usr/bin
        install -m 0755 cello $(DESTDIR)/usr/bin/cello

构建与安装:

$ make
gcc -g -o cello cello.c

$ sudo make install
install -m 0755 cello /usr/bin/cello

5. 为打包准备源码

开发者经常发布软件方式是压缩打包源码。

软件应与软件许可证(license)一起分发,一般写在LICENSE文件中。GPLv3 license:

$ cat /tmp/LICENSE
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

5.1 将源码放到压缩包中

下面的例子使用gzip压缩包。

5.1.1 cello

  1. 将文件放在单独的文件中,版本是1.0
# 注意,文件夹名称必须和 “name-version” 一致
$ mkdir /tmp/cello-1.0

$ mv ~/cello.c /tmp/cello-1.0/

$ mv ~/Makefile /tmp/cello-1.0/

$ cp /tmp/LICENSE /tmp/cello-1.0/
  1. 创建用于发布的打包文件并移动到~/rpmbuild/SOURCES/
$ cd /tmp/

$ tar -cvzf cello-1.0.tar.gz cello-1.0
cello-1.0/
cello-1.0/Makefile
cello-1.0/cello.c
cello-1.0/LICENSE

$ mv /tmp/cello-1.0.tar.gz ~/rpmbuild/SOURCES/
  1. 添加补丁

    如果有补丁文件的话,将补丁文件也放在~/rpmbuild/SOURCES/下(如果不手动编写规则,好像不会应用补丁)。

$ mv ~/cello-output-first-patch.patch ~/rpmbuild/SOURCES/

现在,源码已经准备好打包到RPM中了。