什么是源代码?
源代码是计算机的人类可读指令,描述了如何执行计算。源代码使用编程语言表示。
下面,使用三种不同编程语言编写Hello World
,用着三种不同语言编写的程序以不同的方式打包。
用bash
编写Hello World
:
filename:bello
1 |
|
用Python
编写Hello World
:
filename:pello.py
1 | #!/usr/bin/env python |
用C
编写Hello World
:
filename:cello.c
1 |
|
以上程序的结果都是在命令行上输出Hello World
。
程序如何制作
人类可读的源代码有许多方法可以成为机器代码-计算机遵循实际执行程序的指令。但是,所有方法都可以简化为以下三种:
- 程序是本地编译的。
- 程序由原始解释来解释的。
- 程序由字节编译解释。
本机编译代码
本机编译的软件是用编程语言编写的软件,编译成机器代码,生成二进制可执行文件。这种软件可以独立运行。
以这种方式构建的RPM包是特定于体系结构的。这意味着如果在64位(x86_64)处理器的计算机上编译此类软件,则无法在32位(x86)处理器上执行。生成的包将在其名称中指定体系结构。
解释代码
某些编程语言(bash
或Python
)无法编译为机器代码。相反,他们的程序的源代码是由语言解释器或语言虚拟机逐步执行的,无需事先转换。
完全用解释型编程语言编写的软件不是特定于体系结构的,因此,生成的RPM包将包含noarch
字符串。
解释型语言或者是字节编译或原始解释。这两种类型在程序构建过程和包装过程中有所不同。
原始解释程序
原始解释程序语言根本不需要编译,它们由解释器直接执行。
字节编译程序
字节编译语言需要编译成字节代码,然后由语言虚拟机执行。
从源码构建软件
- 对于编译语言编写的软件,源代码通过构建(Build)过程生成机器代码。这个过程通常称为编译 (compiling),因不同的语言而异。生成的软件可以运行(run)或执行(executed),这使计算机可以执行程序员指定的任务。
- 对于原始解释语言编写的软件,源代码不是构建的,而是直接执行。
- 对于用字节编译的解释语言编写的软件,源代码被编译成字节代码,然后由语言虚拟机执行。
本机编译代码
使用C语言编写的cello.c
程序构建为可执行文件。
1 |
|
手动构建
从GNU编译器集合(GCC
)调用C编译器将源代码编译为二进制文件:
1 | gcc -g -o cello cello.c |
执行二进制文件cello
1 | ./cello |
这样,已经从源代码构建并运行本机编译的软件。
自动化构建
可以自动化构建,而不是手动构建源代码。这是大型软件常用的做法。通过创建Makefile
软件运行GNU
make
程序来自动完成构建。
要设置自动构建,需要创建一个名为Makefile
和相同的cello.c
:
Makefile:
1 | cello: |
现在构建软件,只需要运行make
:
1 | make |
由于已经有一个构建存在,可以执行make clean
后再次运行make
:
1 | make clean |
代码解读
字节编译代码
peool.py
用Python编写的程序编译为字节代码,然后由Python语言虚拟机执行。Pyhton源代码也可以是原始解释的,但字节编译版本更快。因此,RPM Packagers更喜欢将字节编译版本打包以分发给最终用户。
1 | #!/usr/bin/env python |
对于不同的语言,字节编译程序的过程是不同的。取决于语言,语言的虚拟机以及与该语言一起使用的工具和过程。
字节编译:
1 | python -m compileall pello.py |
执行以下字节代码:
1 | python pello.pyc |
解释代码
1 |
|
用shell脚本语言编写的程序,例如bash
是解释的。因此,只需要使源代码可执行文件运行它:
1 | chmod +x bello |
修补软件
补丁是源代码,更新其他源代码。被格式化为diff
因为它表示两个版本的文本之间的不同。
开发人员经常使用版本控制系统,例如
git
来管理源代码仓库,这些工具提供了自己创建差异或修补软件的方法。
在示例中,我们使用diff
从原始源代码创建补丁,然后使用patch
应用它。在创建RPM时,将在后面的部分中使用修补。
修补如何与RPM包装相关?在打包时,我们保留它,而不是简答地修改源代码,并在其上使用补丁。
在为cello.c
内容创建补丁:
保留原始源代码:
1
cp cello.c cello.c.orig
这是保留原始源代码文件的常用方法。
更改
cello.c
:1
2
3
4
5
6
int main(void) {
printf("Hello World from my very first patch!\n");
return 0;
}使用
diff
生成补丁:1
diff -Naur cello.c.orig cello.c
将补丁程序保存到文件中:
1
diff -Naur cello.c.orig cello.c > cello-output-first-patch.patch
恢复原始
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 | make clean |
您已经创建了一个补丁,修补了一个程序,构建了修补程序并运行它。
安装任意工具
Linux和其他类Unix系统相比的一大优势是文件系统层次标准(FHS)。它指定应在哪个目录中找到哪些文件。从RPM软件包安装的文件应根据FHS要求进行存放。例如,可执行文件应该放入系统PATH
变量中的目录。
我们将探索在系统中放置任意文件的两种流行方法:使用install
,make install
命令。
使用install命令
有时使用构建自动化工具并不是最佳的,例如,如果打包的程序很简答并且不需要额外的开销。在这些情况下,打包器通常使用install
命令,该命令将放置到具有指定权限集的文件系统中的指定目录中。
install
将bello
文件放入包含可执行脚本通用权限的usr/bin
:
1 | install -m 0755 bello /usr/bin/bello |
现在bello
位于$PATH
变量中列出的目录。因此可以从任何位置执行bello
。
使用make install命令
将以构建的软件安装到系统的自动方式是使用make install
命令。它要求Makefile
指定如何在系统中将任意文件安装到系统中。
将install
部分添加到Makefile:
1 | cello: |
$(DESTDIR)
变量是GNU
内置的,通常用于指定安装到不是根目录不同的目录。
现在,不仅可以使用Makefile
构建软件,还可以将其安装到目标系统。
要构建和安装程序:
1 | make |
现在cello
位于$PATH变量列出的目录中。
准备打包的源代码
创建源代码存档通常不是由RPM Packager完成的,而是由开发人员完成的。打包器使用现成的源代码存档。
软件应与软件许可证一起分发。例如,使用GPLv3许可证。许可证文本将进入每个文件中。RPM打包程序在打包时需要处理许可证文件。
LICENSE
实例:
1 | This program is free software: you can redistribute it and/or modify |
将源代码放入Tarball
我们将三个Hello World
程序中的每一个都放入一个gzip压缩的tarball中。软件通常以这种方式发布。
bello
假设这是0.1
版本的程序。
准备bello项目进行分发:
将文件放在一个目录中:
1
2
3mkdir /tmp/bello-0.1
mv ~/bello /tmp/bello-0.1/
cp /tmp/LICENSE /tmp/bello-0.1/创建用于分发的存档并将其移至
~/rpmbuild/SOURCES/
:1
2
3cd /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.c
和 Makefile
文件,
将文件放在一个目录中:
1
2
3
4mkdir /tmp/cello-1.0
mv ~/cello.c /tmp/cello-1.0/
mv ~/Makefile /tmp/cello-1.0/
cp /tmp/LICENSE /tmp/cello-1.0/创建用于分发的存档并移至
~/rpmbuild/SOURCES/
:1
2
3cd /tmp/
tar -cvzf cello-1.0.tar.gz cello-1.0
mv /tmp/cello-1.0.tar.gz ~/rpmbuild/SOURCES/添加补丁:
1
mv ~/cello-output-first-patch.patch ~/rpmbuild/SOURCES/