21.1 开放源码的软件安装与升级简介
在 Windows 上装软件只需”下一步”,无法修改源码。Linux 大部分软件遵循 GPL,提供源代码,你可以自行修改。当安全漏洞出现时,不需等厂商发布补丁,可以先自行修补。
21.1.1 什么是开放源码、编译器与可可执行文件
Linux 系统真正认识的执行文件是二进制文件 (binary program):
file /bin/bash
# ELF 64-bit LSB executable, dynamically linked (uses shared libs)...
file /etc/init.d/network
# Bourne-Again shell script, ASCII text executable三个核心概念:
| 概念 | 说明 |
|---|---|
| 开放源码 | 写给人类看的纯文本程序码(如 C 的 .c 文件),机器不认识 |
| 编译器 | 将程序码翻译成机器语言,Linux 标准编译器为 gcc |
| 可可执行文件 | 编译链接后的二进制文件,机器可直接执行 |
编译过程:源码(.c) → 编译 → 目标文件(.o) → 链接(含函数库) → 可执行 binary
21.1.2 什么是函数库
函数库类似”副程序”——别人写好的可重复调用的功能模块。例如 PAM 模块提供身份认证功能,程序只需”调用”PAM 即可,不必自己实现。
函数库又分为动态与静态两大类(详见 21.5 节)。核心函数库在 /usr/include, /usr/lib, /usr/lib64。
21.1.3 什么是 make 与 configure
一套软件通常有大量源代码文件,手动一个一个编译不现实。make 读入 Makefile 规则文件,自动判别哪些文件需要重新编译。
configure 侦测程序的作用:
| 侦测内容 | 说明 |
|---|---|
| 编译器 | 有没有 gcc 等适合的编译器 |
| 函数库 | 需要的依赖函数库是否存在 |
| 平台相容性 | 操作系统、核心版本是否匹配 |
| 表头文件 | /usr/include 中必要的 header 文件 |
你的动作: ./configure → 产生 Makefile → make → 编译完成
⚠️ 不同 Linux distribution 的函数库路径、核心版本不同,所以在 CentOS 上编译的程序不能拿到 SuSE 上执行——这正是为什么需要源代码,在不同平台分别编译。
21.1.4 什么是 Tarball 的软件
Tarball = tar 打包 + gzip/bzip2/xz 压缩。将软件的所有源代码打包成一个压缩包。
| 扩展名 | 压缩方式 |
|---|---|
*.tar.gz / *.tgz | gzip |
*.tar.bz2 | bzip2(压缩率更高) |
*.tar.xz | xz(压缩率最高) |
解压后通常包含:
- 源代码文件
- 侦测程序(configure / config)
- 安装说明(INSTALL 或 README——最重要的参考文件!)
21.1.5 如何安装与升级软件
升级软件的原因:需要新功能、修补安全漏洞、改善性能。
两种安装方式:
| 方式 | 代表工具 | 特点 |
|---|---|---|
| 源代码编译 | Tarball + gcc + make | 弹性大,可客制化,但较繁琐 |
| 预编译 binary | RPM/YUM (Red Hat), dpkg/APT (Debian) | 快速方便,厂商预先编译好 |
Tarball 安装基本流程:下载 → 解包 → 读 README → ./configure → make → make install
21.2 使用传统程序语言进行编译的简单范例
前提:需安装 gcc。执行
yum groupinstall "Development Tools"一键安装所有开发工具。
21.2.1 单一程序:印出 Hello World
// hello.c
#include <stdio.h>
int main(void) {
printf("Hello World\n");
}gcc hello.c # 默认输出 a.out
./a.out # Hello World
gcc -c hello.c # 仅编译为目标文件 hello.o(不链接)
gcc -o hello hello.o # 指定输出文件名为 hello
./hello # Hello World21.2.2 主、副程序链接:副程序的编译
gcc -c thanks.c thanks_2.c # 分别编译为 .o
gcc -o thanks thanks.o thanks_2.o # 链接
./thanks # Hello World + Thank you!💡 分离编译的优势:若只修改了一个副程序,只需重新编译那个
.c即可,不必全部重新编译——大型项目节省大量时间。
21.2.3 调用外部函数库:加入链接的函数库
// sin.c — 计算 sin(90° = π/2)
#include <stdio.h>
#include <math.h>
int main(void) {
float value;
value = sin(3.14 / 2);
printf("%f\n", value);
}gcc sin.c -lm -L/lib -L/lib64
./a.out # 1.000000| 参数 | 含义 |
|---|---|
-l | 链接某个函数库(lib 省略,只写库名) |
-lm | 链接 libm.so(数学函数库),lib 和 .so 不需写 |
-L/path | 函数库搜寻目录(默认 /lib, /lib64) |
-I/path | include 表头文件搜寻目录(默认 /usr/include) |
21.2.4 gcc 的简易用法(编译、参数与链结)
| 命令 | 说明 |
|---|---|
gcc -c hello.c | 仅编译为目标文件 .o,不链接 |
gcc -O hello.c -c | 加入最优化(生成更快的执行文件) |
gcc sin.c -lm -L/lib -I/usr/include | 指定函数库、库路径、头文件路径 |
gcc -o hello hello.c | 指定输出文件名 |
gcc -Wall hello.c | 显示所有警告讯息(更严谨) |
-Wall、-O这类非必要参数称为旗标 FLAGS(C 语言用CFLAGS),在 makefile 中常被引用。
21.3 用 make 进行宏编译
21.3.1 为什么要用 make
假设一个程序有 4 个源文件,每次都要记得全部编译指令。make 的好处:
- 简化指令——一个
make替代一堆 gcc 命令 - 增量编译——只重新编译被修改过的文件
- 自动更新——依据相依性更新可执行文件
# makefile
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lmmake # 自动判断每个 .o 对应的 .c,编译并链接
# cc -c -o main.o main.c
# cc -c -o haha.o haha.c
# ...
make # 再次执行,无改动时:"main is up to date."
makevsshell script:make 会自动判断哪些文件需要重新编译,而不是每次全量执行。
21.3.2 makefile 的基本语法与变量
基本语法规则:
标的(target): 目标文件1 目标文件2
<tab> 指令列注意:指令行必须以 <tab> 开头(不能用空格!),# 为注解。
多标的示例:
main: main.o haha.o sin_value.o cos_value.o
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
clean:
rm -f main main.o haha.o sin_value.o cos_value.omake clean # 清除所有编译输出
make clean main # 先清除再重新编译使用变量简化:
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
gcc -o $@ ${OBJS} ${LIBS} # $@ = 当前标的(即 main)
clean:
rm -f main ${OBJS}makefile 变量语法:
| 规则 | 说明 |
|---|---|
变量 = 值 | 等号两边可有空格,但变量左边不可有 <tab> |
$(变量) 或 ${变量} | 引用变量 |
| 惯例大写 | LIBS, OBJS, CFLAGS |
$@ | 特殊变量,代表当前标的 (target) |
环境变量优先级:make 命令行 > makefile 内定义 > shell 原有环境变量
CFLAGS="-Wall" make clean main # 命令行传入 CFLAGS 优先于 makefile 内的定义21.4 Tarball 的管理与建议
21.4.1 使用源代码管理软件所需要的基础软件
| 工具 | 用途 |
|---|---|
| gcc/cc | C 语言编译器 |
| make + autoconfig | 自动化编译 + 自动创建 Makefile |
| kernel-header | 核心提供的 Library 及 Include 文件(驱动程序特别需要) |
CentOS 默认不安装开发工具,需要手动安装:
yum groupinstall "Development Tools" # 基础开发工具
yum groupinstall "X Software Development" # 图形界面开发(按需)
yum groupinstall "Legacy Software Development" # 旧版软件支持(按需)21.4.2 Tarball 安装的基本步骤
| 步骤 | 命令 | 说明 |
|---|---|---|
| 1. 解压缩 | tar -zxvf xxx.tar.gz -C /usr/local/src | 把源代码放到 /usr/local/src |
| 2. 读文档 | vi INSTALL; vi README | 最重要的步骤! 了解依赖和参数 |
| 3. 安装依赖 | (根据 README 安装缺失的套件) | 非必要但常见的步骤 |
| 4. 创建 Makefile | ./configure --prefix=/usr/local/xxx | 侦测环境 + 生成 Makefile |
| 5. 清除旧文件 | make clean | 清除上次编译残留的目标文件 |
| 6. 编译 | make | 编译生成可执行文件 |
| 7. 安装 | make install | 将文件复制到目标目录 |
⚠️ 每一步都必须成功才能往下走!
./configure失败 → 没有 Makefile →make无法进行 →make install无效。
21.4.3 一般 Tarball 软件安装的建议事项(如何移除?升级?)
路径选择:
| 方式 | 安装路径示例 | 优点 | 缺点 |
|---|---|---|---|
| 默认分散安装 | /usr/local/{bin,etc,lib,man} | 符合 PATH,指令直接可用 | 难以移除(文件散落四处) |
| 独立目录安装(推荐) | /usr/local/software/{bin,etc,...} | 直接 rm -rf 即可卸载 | 需手动添加 PATH 和 man path |
# 独立目录安装时,需手动配置 man page 搜寻
vim /etc/man_db.conf
# 添加:MANPATH_MAP /usr/local/software/bin /usr/local/software/man升级注意事项:软件之间可能存在相依性(如 Apache + PHP + MySQL 需按顺序安装),升级其中一个可能连带影响其他,需要重新编译。
💡 如今 EPEL 计划(https://fedoraproject.org/wiki/EPEL)已包含大部分常用软件,一般不需要自行用 Tarball 编译。除非该软件是专属/冷门软件。
21.4.4 一个简单的范例、利用 ntp 来示范
以安装 NTP 时间同步软件为例(nginx 版本 ntp-4.2.8p3):
# 1. 解压到 /usr/local/src
cd /usr/local/src
tar -zxvf /root/ntp-4.2.8p3.tar.gz
cd ntp-4.2.8p3
# 2. 读文档!
vi INSTALL
vi README
# 3. 查可用参数,创建 Makefile
./configure --help | more
./configure --prefix=/usr/local/ntp \
--enable-all-clocks --enable-parse-clocks
# 关键参数:--prefix=/path 指定安装路径(不指定默认为 /usr/local)
# 最后必须看到:config.status: creating Makefile ← 成功!
# 4. 编译安装
make clean; make
make check # 可选:测试
make install # 安装到 /usr/local/ntp21.4.5 利用 patch 更新源代码
patch 只更新被修改的部分文件,不需要重新下载完整新版本。
# patch 语法
patch -p数字 < patch_file-pN 的含义:去掉路径中 N 层目录。例如 patch 文件中路径为 main-0.1/cos_value.c:
-p0:完整路径 → 找main-0.1/cos_value.c-p1:去掉一层 → 找cos_value.c(在 main-0.1 目录内执行时用)
完整流程:
tar -zxvf main-0.1.tgz
cd main-0.1
# 应用补丁
patch -p1 < ../main_0.1_to_0.2.patch
# patching file cos_value.c
# patching file main.c
# patching file Makefile
# patching file sin_value.c
make clean main # 重新编译
./main # version 0.2
make install # cp -a main /usr/local/bin
make uninstall # rm -f /usr/local/bin/main
# 撤销补丁
patch -R -p1 < ../main_0.1_to_0.2.patch⚠️ patch 只更新源代码文件!更新后仍需重新编译才会生效。补丁通常只针对相邻版本,跨多个版本需逐个应用。
21.5 函数库管理
21.5.1 动态与静态函数库
| 特性 | 静态函数库 | 动态函数库 |
|---|---|---|
| 扩展名 | .a (libxxx.a) | .so (libxxx.so) |
| 编译方式 | 直接整合到程序中 | 仅保留指针 (Pointer) 指向函数库位置 |
| 文件大小 | 较大 | 较小 |
| 独立执行 | ✅ 可独立执行 | ❌ 函数库必须在且路径不能变 |
| 升级影响 | 函数库升级 → 所有程序重新编译 | 函数库升级 → 程序无需改动(只要文件名相同) |
💡 现代 Linux 倾向使用动态函数库——依赖关系太复杂,静态升级一个库会影响整个系统。
函数库存放位置:/lib64, /lib, /usr/lib64, /usr/lib, /lib/modules/(核心函数库)。
21.5.2 ldconfig 与 /etc/ld.so.conf
将常用动态函数库预载入内存缓存,加速读取:
# 1. 添加函数库所在目录(不是文件!)
vim /etc/ld.so.conf.d/vbird.conf
/usr/lib64/mysql # 每行一个目录
# 2. 更新缓存
ldconfig # 无输出 = 正常
ldconfig -p # 列出所有已缓存的函数库
# /etc/ld.so.cache ← 缓存数据实际存放文件21.5.3 程序的动态函数库解析:ldd
查看某个 binary program 依赖哪些动态函数库:
ldd /usr/bin/passwd
# libpam.so.0 => /lib64/libpam.so.0 ← PAM 模块
# libaudit.so.1 => /lib64/libaudit.so.1 ← SELinux audit
# libselinux.so.1 => /lib64/libselinux.so.1 ← SELinux
# libc.so.6 => /lib64/libc.so.6 ← C 标准库
ldd -v /lib64/libc.so.6 # 查看版本详细信息排查 RPM 安装的”相依属性”问题时,用
ldd检查缺少哪些函数库是最快的方式。
21.6 检验软件正确性
21.6.1 md5sum / sha1sum / sha256sum
下载的文件可能被篡改!通过文件指纹验证文件完整性:
md5sum ntp-4.2.8p3.tar.gz
# b98b0cbb72f6df04608e1dd5f313808b ntp-4.2.8p3.tar.gz
# 对比官方网站公布的 MD5 值,一致 = 文件未被篡改
sha1sum ntp-4.2.8p3.tar.gz
sha256sum ntp-4.2.8p3.tar.gz| 加密算法 | 强度 |
|---|---|
| MD5 | 较弱,已被攻破,但仍可做基本校验 |
| SHA1 | 中等 |
| SHA256(推荐) | 强,CentOS 7 官方推荐 |
实际应用——创建系统重要文件指纹数据库:
# 1. 列出重要文件
ls /etc/{passwd,shadow,group} > important.file
find /usr/sbin /usr/bin -perm /6000 >> important.file # 所有 SUID/SGID
# 2. 生成指纹 → 锁定文件
for f in $(cat important.file); do
md5sum $f >> finger1.file
done
chattr +i finger1.file # 防止被篡改
# 3. 定期比对(crontab 自动化)
# 如果有差异 → 发 email 告警命令速查表
| 命令 | 用途 |
|---|---|
file /bin/bash | 查看文件类型(binary 还是 script) |
gcc hello.c | 编译 C 程序(默认输出 a.out) |
gcc -c hello.c | 仅编译成 object file .o,不链接 |
gcc -o hello hello.c | 指定输出文件名 |
gcc -O hello.c -c | 编译时最优化 |
gcc -Wall hello.c | 显示所有警告讯息 |
gcc sin.c -lm -L/path -I/path | 链接函数库、指定库路径、指定头文件路径 |
make | 按 Makefile 编译 |
make clean | 清除目标文件 |
make install / make uninstall | 安装 / 卸载 |
./configure --prefix=/usr/local/xxx | 侦测环境 + 生成 Makefile |
patch -p1 < file.patch | 应用补丁(-pN=去掉N层目录) |
patch -R -p1 < file.patch | 撤销补丁 |
ldconfig | 重建动态函数库缓存 |
ldconfig -p | 列出所有缓存函数库 |
ldd /path/to/program | 查看程序依赖哪些 .so |
md5sum / sha1sum / sha256sum file | 计算文件指纹 |