Too young, too simple. Sometimes, naive & stupid

准备打包软件

什么是源代码?

源代码是计算机的人类可读指令,描述了如何执行计算。源代码使用编程语言表示。

下面,使用三种不同编程语言编写Hello World,用着三种不同语言编写的程序以不同的方式打包。

bash编写Hello World

filename:bello

1
2
#!/bin/bash
printf "Hello World\n"

Python编写Hello World

filename:pello.py

1
2
#!/usr/bin/env python
print("Hello World")

C编写Hello World

filename:cello.c

1
2
3
4
5
#include <stdio.h>
int main(void) {
printf("Hello World\n");
return 0;
}

以上程序的结果都是在命令行上输出Hello World

程序如何制作

人类可读的源代码有许多方法可以成为机器代码-计算机遵循实际执行程序的指令。但是,所有方法都可以简化为以下三种:

  1. 程序是本地编译的。
  2. 程序由原始解释来解释的。
  3. 程序由字节编译解释。

本机编译代码

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

以这种方式构建的RPM包是特定于体系结构的。这意味着如果在64位(x86_64)处理器的计算机上编译此类软件,则无法在32位(x86)处理器上执行。生成的包将在其名称中指定体系结构。

解释代码

某些编程语言(bashPython)无法编译为机器代码。相反,他们的程序的源代码是由语言解释器或语言虚拟机逐步执行的,无需事先转换。

完全用解释型编程语言编写的软件不是特定于体系结构的,因此,生成的RPM包将包含noarch字符串。

解释型语言或者是字节编译或原始解释。这两种类型在程序构建过程和包装过程中有所不同。

原始解释程序

原始解释程序语言根本不需要编译,它们由解释器直接执行。

字节编译程序

字节编译语言需要编译成字节代码,然后由语言虚拟机执行。

从源码构建软件

  • 对于编译语言编写的软件,源代码通过构建Build)过程生成机器代码。这个过程通常称为编译compiling),因不同的语言而异。生成的软件可以运行run)或执行executed),这使计算机可以执行程序员指定的任务。
  • 对于原始解释语言编写的软件,源代码不是构建的,而是直接执行。
  • 对于用字节编译的解释语言编写的软件,源代码被编译成字节代码,然后由语言虚拟机执行。

本机编译代码

使用C语言编写的cello.c程序构建为可执行文件。

1
2
3
4
5
6
#include <stdio.h>

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

手动构建

从GNU编译器集合(GCC)调用C编译器将源代码编译为二进制文件:

1
gcc -g -o cello cello.c

执行二进制文件cello

1
2
./cello
Hello World

这样,已经从源代码构建并运行本机编译的软件。

自动化构建

可以自动化构建,而不是手动构建源代码。这是大型软件常用的做法。通过创建Makefile软件运行GNU make程序来自动完成构建。

要设置自动构建,需要创建一个名为Makefile和相同的cello.c

Makefile:

1
2
3
4
5
cello:
gcc -g -o cello cello.c

clean:
rm cello

现在构建软件,只需要运行make

1
2
make
make: 'cello' is up to date.

由于已经有一个构建存在,可以执行make clean后再次运行make

1
2
3
4
make clean 
rm cello
make
gcc -g -o cello cello.c

代码解读

字节编译代码

peool.py用Python编写的程序编译为字节代码,然后由Python语言虚拟机执行。Pyhton源代码也可以是原始解释的,但字节编译版本更快。因此,RPM Packagers更喜欢将字节编译版本打包以分发给最终用户。

1
2
#!/usr/bin/env python
print("Hello World")

对于不同的语言,字节编译程序的过程是不同的。取决于语言,语言的虚拟机以及与该语言一起使用的工具和过程。

字节编译:

1
2
python -m compileall pello.py
file pello.pyc

执行以下字节代码:

1
python pello.pyc

解释代码

1
2
#!/bin/bash
printf "Hello World\n"

用shell脚本语言编写的程序,例如bash是解释的。因此,只需要使源代码可执行文件运行它:

1
2
chmod +x bello
./bello

修补软件

补丁是源代码,更新其他源代码。被格式化为diff因为它表示两个版本的文本之间的不同。

开发人员经常使用版本控制系统,例如git来管理源代码仓库,这些工具提供了自己创建差异或修补软件的方法。

在示例中,我们使用diff从原始源代码创建补丁,然后使用patch应用它。在创建RPM时,将在后面的部分中使用修补。

修补如何与RPM包装相关?在打包时,我们保留它,而不是简答地修改源代码,并在其上使用补丁。

在为cello.c内容创建补丁:

  1. 保留原始源代码:

    1
    cp cello.c cello.c.orig

    这是保留原始源代码文件的常用方法。

  2. 更改cello.c:

    1
    2
    3
    4
    5
    6
    #include <stdio.h>

    int main(void) {
    printf("Hello World from my very first patch!\n");
    return 0;
    }
  3. 使用diff生成补丁:

    1
    diff -Naur cello.c.orig cello.c
  4. 将补丁程序保存到文件中:

    1
    diff -Naur cello.c.orig cello.c > cello-output-first-patch.patch
  5. 恢复原始cello.c:

    1
    cp cello.c.orig cello.c

我们保留原始文件cello.c,因为在构建RPM时,会使用原始文件,而不是修改过的文件。

cello.c要使用补丁cello.output-first-patch.patch,请将补丁文件重定向到patch命令:

1
patch < cello-output-first-patch.patch

构建并运行修补程序cello.c:

1
2
3
make clean
make
./cello

您已经创建了一个补丁,修补了一个程序,构建了修补程序并运行它。

安装任意工具

Linux和其他类Unix系统相比的一大优势是文件系统层次标准(FHS)。它指定应在哪个目录中找到哪些文件。从RPM软件包安装的文件应根据FHS要求进行存放。例如,可执行文件应该放入系统PATH变量中的目录。

我们将探索在系统中放置任意文件的两种流行方法:使用installmake install命令。

使用install命令

有时使用构建自动化工具并不是最佳的,例如,如果打包的程序很简答并且不需要额外的开销。在这些情况下,打包器通常使用install命令,该命令将放置到具有指定权限集的文件系统中的指定目录中。

installbello文件放入包含可执行脚本通用权限的usr/bin

1
install -m 0755 bello /usr/bin/bello

现在bello位于$PATH变量中列出的目录。因此可以从任何位置执行bello

使用make install命令

将以构建的软件安装到系统的自动方式是使用make install命令。它要求Makefile指定如何在系统中将任意文件安装到系统中。

install部分添加到Makefile:

1
2
3
4
5
6
7
8
9
cello:
gcc -g -o cello cello.c

clean:
rm cello

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

$(DESTDIR)变量是GNU内置的,通常用于指定安装到不是根目录不同的目录。

现在,不仅可以使用Makefile构建软件,还可以将其安装到目标系统。

要构建和安装程序:

1
2
make
make install

现在cello位于$PATH变量列出的目录中。

准备打包的源代码

创建源代码存档通常不是由RPM Packager完成的,而是由开发人员完成的。打包器使用现成的源代码存档。

软件应与软件许可证一起分发。例如,使用GPLv3许可证。许可证文本将进入每个文件中。RPM打包程序在打包时需要处理许可证文件。

LICENSE实例:

1
2
3
4
5
6
7
8
9
10
11
12
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/>.

将源代码放入Tarball

我们将三个Hello World程序中的每一个都放入一个gzip压缩的tarball中。软件通常以这种方式发布。

bello

假设这是0.1版本的程序。

准备bello项目进行分发:

  1. 将文件放在一个目录中:

    1
    2
    3
    mkdir /tmp/bello-0.1
    mv ~/bello /tmp/bello-0.1/
    cp /tmp/LICENSE /tmp/bello-0.1/
  2. 创建用于分发的存档并将其移至~/rpmbuild/SOURCES/:

    1
    2
    3
    cd /tmp
    tar -cvzf pello-0.1.1.tar.gz pello-0.1.1
    mv /tmp/pello-0.1.1.tar.gz /rpmbuild/SOURCES/

cello

项目包含 cello.cMakefile 文件,

  1. 将文件放在一个目录中:

    1
    2
    3
    4
    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/
  2. 创建用于分发的存档并移至 ~/rpmbuild/SOURCES/:

    1
    2
    3
    cd /tmp/
    tar -cvzf cello-1.0.tar.gz cello-1.0
    mv /tmp/cello-1.0.tar.gz ~/rpmbuild/SOURCES/
  3. 添加补丁:

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