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 / *.tgzgzip
*.tar.bz2bzip2(压缩率更高)
*.tar.xzxz(压缩率最高)

解压后通常包含:

  • 源代码文件
  • 侦测程序(configure / config)
  • 安装说明(INSTALLREADME——最重要的参考文件!)

21.1.5 如何安装与升级软件

升级软件的原因:需要新功能、修补安全漏洞、改善性能。

两种安装方式

方式代表工具特点
源代码编译Tarball + gcc + make弹性大,可客制化,但较繁琐
预编译 binaryRPM/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 World

21.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/pathinclude 表头文件搜寻目录(默认 /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 的好处:

  1. 简化指令——一个 make 替代一堆 gcc 命令
  2. 增量编译——只重新编译被修改过的文件
  3. 自动更新——依据相依性更新可执行文件
# 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 -lm
make          # 自动判断每个 .o 对应的 .c,编译并链接
# cc -c -o main.o main.c
# cc -c -o haha.o haha.c
# ...
 
make          # 再次执行,无改动时:"main is up to date."

make vs shell 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.o
make 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/ccC 语言编译器
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/ntp

21.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计算文件指纹