2023-05-26    2023-09-07    1564 字  4 分钟

Linux 下源代码的编译安装,及其编译过程和可能遇到的问题。

![[assets/Pasted image 20230526085019.png]]

如何编译安装 

1

下载源码包,解压、进入源代码目录后,执行以下命令:

1
2
3
4
./configure
make
make install
# 多数时候需要 `sudo`

以上是典型的使用 GNU 的 AUTOCONF 和 AUTOMAKE 产生的程序的安装步骤。

如何理解编译过程 

2 3

./configure

configure 脚本是用来检查当前安装平台的开发环境,比如是不是有 CC 或 GCC ,也用来供用户指定程序包的编译参数、启用特性、安装路径等等。

一般用来生成 Makefile ,为下一步的编译做准备。 如下所示,可以通过在 configure 后加上参数来对安装进行控制,比如:

1
./configure --prefix=/usr

意味着将该软件安装在 /usr 下面,执行文件就会安装在 /usr/bin (而不是默认的 /usr/local/bin ),资源文件就会安装在 /usr/share (而不是默认的 /usr/local/share )。

# 通用的几个选项
--prefix=                      # 指定安装的路径
--sysconfdir=                  # 指定配置文件目录
--enable-feature=              # 启用某个特性
--disable-feature              # 禁用某个特性
--with-function                # 启用某个功能
--without-function             # 禁用某个功能

你可以通过 ./configure --help 查看更多。

make

make 是 Linux 开发套件里面自动化编译的一个控制程序。每个源代码都有专用的 Makefile ,在执行 make 时依据 Makefile 这个配置文件,调用指定的预处理器做处理、调用指定的编译器做处理、编译文件的顺序操作等。

一般情况下,它所使用的 Makefile 控制代码是由 configure 这个设置脚本根据给定的参数和系统环境生成的。

cmake

5

cmake 就是一个与 make 同级别的编译工具,只不过它依靠的不是 Makefile 作为编译规则,而是根据 CMakeLists.txt 来编译的。它比 make 更高级,可以根据不同平台、不同的编译器,通过编写 CMakeLists.txt ,可以控制生成的 Makefile ,从而控制编译过程。

![[assets/Pasted image 20230526085142.png]]

如果有嵌套目录,子目录下可以有自己的 CMakeLists.txt 。

make install

这条命令用来进行安装(当然有些软件需要先运行 make check 或 make test 来进行一些测试),一般需要你有 root 权限(因为要向系统写入文件)。

其实是一些脚本,根据 Makefile 文件中的设置将编译完成的文件安装到预定目录,如将创建出的二进制文件放到指定的二进制目录、库文件放到指定的库目录等等。

扩展 - C/C++ 编译过程 

4

![[assets/Pasted image 20230526085149.png]]

相关名词

编译 ,是读取源程序(字符流),对之进行词法和语法的分析,将高级语言转换为等效的汇编代码,再转换为机器代码,保存到目标文件 *.obj 中(如果编译通过)。

链接,是将有关的目标文件(库文件、 .o 文件)彼此互相连接,即在一个文件中引用的符号同在另一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

编译过程

编译分为两个过程: 预处理阶段和编译、优化阶段 。

预处理阶段:

  • 宏 #define ;
  • 条件编译指令,如 #ifdef, #ifndef, #else, #elif, #endif 等;
  • 头文件包含 #include <iostream> ;
  • 特殊符号,如 LINE 标识被解释为当前行号, FILE 被解释为当前被编译的 C 源程序的名称。

编译、优化阶段:

  • 针对代码优化,不依赖具体计算机;
  • 针对计算机的优化。

汇编把汇编语言代码翻译成目标机器指令,生成目标文件( .o 或 .obj 文件),至少需要表提供 3 张表:

  • 导出符号表 - 该目标文件可以提供的符号及地址;
  • 未解决符号表 - 该目标文件告诉链接器哪些符号没找到地址;
  • 地址重定向表。

链接的时候,链接器会为目标文件的 未解决符号表 里的符号在其他文件里寻找地址,但是每个目标文件的地址都是从 0x0000 开始的,这就导致直接将对方文件中符号拿过来用会是不正确的。为了区分不同的文件,链接器在链接时就会结每个目标文件的地址进行调整,如为 .o 导出的符号地址都加上起始地址。然而,因为加上了起始地址,符号在自身文件中的实际地址就不对了,需要再用一张地址重定向表记录符号相对自身文件的地址。

链接过程

链接方式分为:静态链接和动态链接。

静态链接 ,函数的代码将从其所在的静态链接库中被拷贝到最终的可执行程序中,这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。

动态链接 ,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所做的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚拟地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。

TODO 进阶 - Linux 下源码编译安装详解 

6