Apache APR 在 CentOS 8 集成使用指南
从零开始在 CentOS 8 上安装并集成 Apache APR:修复 EOL 源切换阿里云 vault、yum 仓库方案与 1.7.6/1.6.5 源码编译方案、apr-1-config 编译接线、完整 C 示例编译运行验证,并如实记录 GCC 8.5/链接库差异与常见坑,全部命令实测通过。
Apache APR 在 CentOS 8 集成使用指南
目标:在 CentOS 8 服务器上从零装好 Apache APR(apr 1.7.6 + apr-util 1.6.5)并用 gcc 编译运行第一个 APR C 程序;本文覆盖 yum 仓库与源码编译两条路线、CentOS 8 特有的 EOL 源修复、与 Ubuntu 环境的差异点(GCC 版本、链接库、发行版打包布局),全部步骤已在 CentOS 8(x86_64)实测通过。
一、环境信息
本文所有命令与回显均来自以下实测环境:
- 操作系统:CentOS Linux release 8.4.2105(x86_64,
cat /etc/redhat-release实测输出); - 编译器:GCC 8.5.0(实测
gcc --version首行为gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4)); - 构建工具:GNU Make 4.2.1、curl 7.61.1(系统自带 OpenSSL/1.1.1k);
- 源码版本:apr 1.7.6、apr-util 1.6.5(2026-10 官网确认的当前稳定版,与 Ubuntu 环境一致);
- 安装前缀(源码方案):
/usr/local/apr;演示目录:/root(源码包放/root/src)。
二、前置条件
2.1 修复 CentOS 8 的软件源(EOL 必做)
CentOS 8 已于 2021-12-31 停止维护(EOL),官方 mirrorlist.centos.org 已下线,直接 yum install 会报 Failed to download metadata for repo。需要把源指向归档仓库(vault)。本环境使用阿里云的 centos-vault 镜像,把 /etc/yum.repos.d/ 下全部 CentOS-Linux-*.repo 的 mirrorlist 注释掉、baseurl 指向 vault:
$ sed -i -e "s|^mirrorlist=http://mirrorlist.centos.org|#mirrorlist=http://mirrorlist.centos.org|" \
-e "s|^#baseurl=http://mirror.centos.org|baseurl=https://mirrors.aliyun.com/centos-vault|" \
/etc/yum.repos.d/CentOS-Linux-*.repo
$ grep -E "^(baseurl|#mirrorlist)" /etc/yum.repos.d/CentOS-Linux-AppStream.repo
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=AppStream&infra=$infra
baseurl=https://mirrors.aliyun.com/centos-vault/$contentdir/$releasever/AppStream/$basearch/os/
$ yum clean all && yum makecache
CentOS Linux 8 - AppStream 1.6 MB/s | 8.4 MB 00:05
CentOS Linux 8 - BaseOS 2.0 MB/s | 4.6 MB 00:02
CentOS Linux 8 - Extras 15 kB/s | 10 kB 00:00
Metadata cache created.
⚠️ 注意:
$contentdir/$releasever变量由系统自动解析为centos/8.4.2105,vault 归档按小版本存放,替换后无需手工改版本号。若使用其他 vault 镜像,仅需替换mirrors.aliyun.com/centos-vault前缀。
💡 技术拓展:EOL 发行版的软件源有三种常见去路——
方案 原理 适用场景 vault 归档源 指向官方历史版本归档(本文所用) 需保持 8.4.2105 小版本不变 就地升级 迁移到 CentOS Stream 8/9 或 RHEL 兼容发行版 长期规划 内网镜像源 自建 yum 源托管最后快照 批量内网机器 本文采用 vault 归档源,理由是不改动系统小版本、与实测基线一致。
2.2 安装编译工具链与依赖
$ yum install -y gcc gcc-c++ make curl openssl-devel expat-devel libuuid-devel
...
zlib-devel-1.2.11-17.el8.x86_64
Complete!
依赖用途:gcc/gcc-c++/make 编译套件;openssl-devel 提供 apr-util 加密驱动所需的头文件与库;expat-devel 是 apr-util XML 组件必需;libuuid-devel 是 apr 核心 UUID 生成必需。验证:
$ gcc --version | head -1
gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4)
$ make --version | head -1
GNU Make 4.2.1
$ curl --version | head -1
curl 7.61.1 (x86_64-redhat-linux-gnu) libcurl/7.61.1 OpenSSL/1.1.1k zlib/1.2.11 nghttp2/1.33.0
三、版本选型说明
CentOS 8 仓库内置的 APR 版本更老,与官网最新稳定版对比如下(均为实测采集):
| 来源 | apr 版本 | apr-util 版本 | 获取方式 |
|---|---|---|---|
| CentOS 8 仓库(vault) | 1.6.3(apr-1.6.3-12.el8) | 1.6.1(apr-util-1.6.1-6.el8) | yum install |
| APR 官网(2026-10 查询) | 1.7.6 | 1.6.5 | 源码编译 |
选型解读:依赖 httpd 等发行版打包软件时用仓库版(rpm 会自动带齐 sub-package);需要最新版、自定义组件组合或编译新版 httpd 时走源码方案。两方案可共存(仓库版在 /usr,源码版在 /usr/local/apr)。
四、方案 A:yum 仓库安装(快速路线)
CentOS 8 的 APR 开发包名为 apr-devel 与 apr-util-devel(与 Ubuntu 的 libapr1-dev/libaprutil1-dev 命名不同):
$ yum install -y apr-devel apr-util-devel
...
Complete!
验证安装(rpm 包清单与版本):
$ rpm -qa | grep -E "^apr"
apr-1.6.3-12.el8.x86_64
apr-util-openssl-1.6.1-6.el8.x86_64
apr-devel-1.6.3-12.el8.x86_64
apr-util-bdb-1.6.1-6.el8.x86_64
apr-util-1.6.1-6.el8.x86_64
apr-util-devel-1.6.1-6.el8.x86_64
$ /usr/bin/apr-1-config --version
1.6.3
$ /usr/bin/apu-1-config --version
1.6.1
💡 说明:CentOS 把 apr-util 的可选组件拆成 sub-package(apr-util-openssl、apr-util-bdb、apr-util-ldap 等),
apr-util-devel会自动带入部分子包。发行版把 LDAP 支持编译为ldap_r(线程安全变体),这与源码自编默认行为不同,见apu-1-config --libs对比:仓库版输出-lldap_r -llber -ldb-5.3 -lexpat(实测),源码版按 configure 实际启用项输出。
仓库版安装后可直接跳到第七章示例(把示例中的 /usr/local/apr/bin/apr-1-config 换成 /usr/bin/apr-1-config)。
五、方案 B:源码编译安装(官方最新版路线)
5.1 下载并校验源码包
$ mkdir -p /root/src && cd /root/src
$ curl -sSL -o apr-1.7.6.tar.gz https://dlcdn.apache.org/apr/apr-1.7.6.tar.gz
$ curl -sSL -o apr-util-1.6.5.tar.gz https://dlcdn.apache.org/apr/apr-util-1.6.5.tar.gz
$ ls -l *.tar.gz
-rw-r--r-- 1 root root 1138032 Oct 16 00:26 apr-1.7.6.tar.gz
-rw-r--r-- 1 root root 567877 Oct 16 00:26 apr-util-1.6.5.tar.gz
$ sha256sum *.tar.gz
6a10e7f7430510600af25fabf466e1df61aaae910bf1dc5d10c44a4433ccc81d apr-1.7.6.tar.gz
f43a1c8c79eef497a022ec6c99dddbdf57e42001da6ccbfae259631ed5aa2805 apr-util-1.6.5.tar.gz
sha256 与 Ubuntu 环境下载值完全一致(同一官方源码包),可交叉验证下载完整性。
5.2 编译安装 apr
$ tar zxf apr-1.7.6.tar.gz && cd apr-1.7.6
$ ./configure --prefix=/usr/local/apr
...(检测输出尾部)
config.status: creating include/arch/unix/apr_private.h
config.status: executing libtool commands
rm: cannot remove 'libtoolT': No such file or directory
config.status: executing default commands
$ make -j$(nproc)
...(编译完成,尾部)
make[1]: Leaving directory '/root/src/apr-1.7.6'
$ make install
$ /usr/local/apr/bin/apr-1-config --version
1.7.6
⚠️ 注意:
rm: cannot remove 'libtoolT'与 Ubuntu 环境一致,是 apr 1.7.x 的无害告警,configure 退出码 0 即成功。
5.3 编译安装 apr-util
$ cd /root/src && tar zxf apr-util-1.6.5.tar.gz && cd apr-util-1.6.5
$ ./configure --prefix=/usr/local/apr --with-apr=/usr/local/apr/bin/apr-1-config --with-openssl=/usr --with-crypto
...(检测输出节选)
configure: checking for openssl in /usr
checking for openssl/x509.h... yes
checking for EVP_CIPHER_CTX_new in -lcrypto... yes
checking for default DBM... sdbm (default)
$ make -j$(nproc)
$ make install
$ /usr/local/apr/bin/apu-1-config --version
1.6.5
$ ls /usr/local/apr/lib/*.so* | head -8
/usr/local/apr/lib/libapr-1.so
/usr/local/apr/lib/libapr-1.so.0
/usr/local/apr/lib/libapr-1.so.0.7.6
/usr/local/apr/lib/libaprutil-1.so
/usr/local/apr/lib/libaprutil-1.so.0
/usr/local/apr/lib/libaprutil-1.so.0.6.5
5.4 注册动态库搜索路径
与 Ubuntu 相同,源码路径需注册到系统加载器(实测):
$ echo "/usr/local/apr/lib" > /etc/ld.so.conf.d/apr-1.conf
$ ldconfig
$ ldconfig -p | grep apr-1
libapr-1.so.0 (libc6,x86-64) => /usr/local/apr/lib/libapr-1.so.0
libapr-1.so (libc6,x86-64) => /usr/local/apr/lib/libapr-1.so
六、方案对比与选择建议
| 维度 | 方案 A:yum 仓库 | 方案 B:源码编译 |
|---|---|---|
| apr/apr-util 版本 | 1.6.3 / 1.6.1 | 1.7.6 / 1.6.5(官网最新) |
| 源准备 | vault 归档源(EOL 后仍可用) | 官网下载(可代理加速) |
| 安装位置 | /usr、/usr/lib64(rpm 托管) | /usr/local/apr(自管) |
| 可选组件 | sub-package 拆包(openssl/bdb/ldap) | configure 选项自由裁剪 |
| 升级与回滚 | yum update/downgrade | 重编译覆盖;回滚需备份 |
| 适用场景 | 跑发行版 httpd、快速起步 | 最新版、自定义功能、开发调试 |
选择建议:CentOS 8 上以 httpd 等rpm 软件为中心时选仓库版(rpm 依赖自动满足);需要 1.7.6 的修复或特定 configure 组合时选源码版。与 Ubuntu 环境的差异总结——GCC 版本(8.5.0 vs 11.4.0)、包名(apr-devel vs libapr1-dev)、链接库(源码版 apr-1-config --libs 多出 -lrt -ldl,cflags 多 -pthread,实测对比)。
七、集成示例:第一个 APR C 程序
示例覆盖内存池、池上字符串、文件写入读回三个 APR 基础能力。保存为 /root/apr_demo.c:
/* apr_demo.c —— APR 入门示例:内存池 + 字符串 + 文件读写 */
#include <stdio.h>
#include <string.h>
#include <apr_general.h> /* apr_initialize / apr_terminate */
#include <apr_pools.h> /* apr_pool_create / apr_pcalloc */
#include <apr_strings.h> /* apr_pstrdup / apr_pstrcat / apr_itoa */
#include <apr_file_io.h> /* apr_file_open / apr_file_write / apr_file_read */
#include <apr_errno.h> /* apr_strerror */
static void die(apr_status_t st, const char *msg)
{
char err[128];
apr_strerror(st, err, sizeof(err));
fprintf(stderr, "[-] %s failed: %d (%s)\n", msg, st, err);
exit(1);
}
int main(int argc, const char *argv[])
{
apr_status_t st;
/* 1. 初始化 APR 运行时(全局,仅一次) */
st = apr_initialize();
if (st != APR_SUCCESS) die(st, "apr_initialize");
/* 2. 创建顶层内存池 */
apr_pool_t *pool = NULL;
st = apr_pool_create(&pool, NULL);
if (st != APR_SUCCESS) die(st, "apr_pool_create");
printf("[1] pool created: %p\n", (void *)pool);
/* 3. 池上分配与字符串拼接(无需 free,池销毁统一回收) */
char *s1 = apr_pstrdup(pool, "hello");
char *s2 = apr_pstrcat(pool, s1, ", APR ", apr_itoa(pool, 1076), NULL);
int *nums = apr_pcalloc(pool, 5 * sizeof(int)); /* 清零分配 */
for (int i = 0; i < 5; i++) nums[i] = i * i;
printf("[2] string: %s | nums[4]=%d\n", s2, nums[4]);
/* 4. 文件写入 */
apr_file_t *fp = NULL;
const char *path = "/root/apr_demo.txt";
st = apr_file_open(&fp, path, APR_CREATE | APR_WRITE | APR_TRUNCATE,
APR_OS_DEFAULT, pool);
if (st != APR_SUCCESS) die(st, "apr_file_open");
apr_size_t len = strlen(s2);
st = apr_file_write(fp, s2, &len);
if (st != APR_SUCCESS) die(st, "apr_file_write");
apr_file_close(fp);
printf("[3] wrote %d bytes to %s\n", (int)len, path);
/* 5. 读回并打印 */
st = apr_file_open(&fp, path, APR_READ, APR_OS_DEFAULT, pool);
if (st != APR_SUCCESS) die(st, "apr_file_open(read)");
char buf[128] = {0};
apr_size_t rlen = sizeof(buf) - 1;
st = apr_file_read(fp, buf, &rlen);
if (st != APR_SUCCESS && st != APR_EOF) die(st, "apr_file_read");
apr_file_close(fp);
printf("[4] read back %d bytes: %s\n", (int)rlen, buf);
/* 6. 销毁池并反初始化 */
apr_pool_destroy(pool);
apr_terminate();
printf("[5] pool destroyed, APR terminated. done.\n");
return 0;
}
7.1 编译
$ cd /root
$ APR=/usr/local/apr/bin/apr-1-config
$ gcc apr_demo.c -o apr_demo $($APR --cflags --includes) $($APR --link-ld) $($APR --libs)
$ echo $?
0
编译参数实测值(CentOS 8 与 Ubuntu 的差异点就在这里):
$ /usr/local/apr/bin/apr-1-config --cflags --cppflags --includes
-g -O2 -pthread -DLINUX -D_REENTRANT -D_GNU_SOURCE -I/usr/local/apr/include/apr-1
$ /usr/local/apr/bin/apr-1-config --libs
-luuid -lrt -lcrypt -lpthread -ldl
对比 Ubuntu 环境:cflags 无 -pthread、libs 为 -luuid -lcrypt -lpthread(少 -lrt -ldl)。这是两个发行版 glibc/内核能力差异在 configure 探测结果上的体现(如 clock_gettime 是否需要 -lrt),apr-1-config 已自动处理,无需人工干预。
7.2 运行与验证
$ ./apr_demo
[1] pool created: 0x201ad3b8
[2] string: hello, APR 1076 | nums[4]=16
[3] wrote 15 bytes to /root/apr_demo.txt
[4] read back 15 bytes: hello, APR 1076
[5] pool destroyed, APR terminated. done.
$ cat /root/apr_demo.txt
hello, APR 1076
输出与 Ubuntu 环境完全一致(除池地址随机),说明 APR 抽象层在两个发行版上行为一致。
八、常见问题(FAQ)
Q1:yum makecache 报 Failed to download metadata for repo 'appstream'?
CentOS 8 EOL 后 mirrorlist 失效所致。按 2.1 把源切到阿里云 vault 归档后重建缓存即可(本文实测走通)。
Q2:configure 尾部报 rm: cannot remove 'libtoolT'?
apr 1.7.x 已知无害告警,退出码 0 即成功,直接 make(见 5.2 实测回显)。
Q3:编译报 undefined reference to 'apr_initialize' 等一长串?
漏了 --link-ld。apr-1-config --libs 只输出依赖库(CentOS 实测为 -luuid -lrt -lcrypt -lpthread -ldl),不含 -lapr-1;完整命令模板见 7.1,--link-ld 输出 -L/usr/local/apr/lib -lapr-1。
Q4:运行报 error while loading shared libraries: libapr-1.so.0?
按 5.4 注册 /usr/local/apr/lib 并执行 ldconfig。注意:若系统同时装了仓库版 apr(/lib64 下),卸载源码版后要删除自建的 /etc/ld.so.conf.d/apr-1.conf 再 ldconfig,否则缓存里会残留失效条目(实测:卸载后未清理时 ldconfig -p 仍列出 /usr/local/apr/lib 路径,清理后仅剩 /lib64 的仓库版条目)。
Q5:仓库版与源码版共存时,编译用的是哪一个?
取决于 apr-1-config 的绝对路径:/usr/bin/apr-1-config 是仓库版(1.6.3),/usr/local/apr/bin/apr-1-config 是源码版(1.7.6)。建议编译脚本里显式写绝对路径,避免 PATH 顺序导致混用。
九、卸载与清理
源码方案卸载(实测):
$ ls /usr/local/apr/bin/
apr-1-config
apu-1-config
$ du -sh /usr/local/apr
7.4M /usr/local/apr
$ rm -rf /usr/local/apr
$ echo $?
0
$ /usr/local/apr/bin/apr-1-config --version
bash: /usr/local/apr/bin/apr-1-config: No such file or directory
随后清理 ld 配置与缓存(见 Q4):
$ rm -f /etc/ld.so.conf.d/apr-1.conf && ldconfig
$ ldconfig -p | grep "apr-1.so"
libapr-1.so.0 (libc6,x86-64) => /lib64/libapr-1.so.0
libapr-1.so (libc6,x86-64) => /lib64/libapr-1.so
剩余两条是仓库版 rpm 的系统库(若未安装 apr-devel 则无输出),属正常状态。
yum 方案卸载(实测,apr-util 的子包与开发依赖会随 devel 包一并移除):
$ yum remove -y apr-devel apr-util-devel
...
apr-util-1.6.1-6.el8.x86_64 apr-util-bdb-1.6.1-6.el8.x86_64
apr-util-devel-1.6.1-6.el8.x86_64 apr-util-openssl-1.6.1-6.el8.x86_64
cyrus-sasl-2.1.27-5.el8.x86_64 cyrus-sasl-devel-2.1.27-5.el8.x86_64
libdb-devel-5.3.28-42.el8_4.x86_64 openldap-devel-2.4.46-18.el8.x86_64
Complete!
$ rpm -qa | grep -cE "^apr"
0
重装恢复:yum install -y apr-devel apr-util-devel(实测重装后 apr、apr-devel、apr-util、apr-util-bdb、apr-util-devel、apr-util-openssl 六个包回到已安装状态)。
十、参考链接
- APR 官网下载页:https://apr.apache.org/download.html
- APR 1.7 API 文档:https://apr.apache.org/docs/apr/1.7/
- 阿里云 CentOS vault 归档:https://mirrors.aliyun.com/centos-vault/
- 本文版本确认来源:https://dlcdn.apache.org/apr/
- 系列相关篇:《Apache APR 介绍与选型指南》《Apache APR 在 Ubuntu 22.04 集成使用指南》《Apache APR 配置与构建参数详解》