Apache APR 常用 CLI 命令与工具详解
实测详解 APR 全部命令行工具:apr-1-config 与 apu-1-config 逐参数用法与组合模板、源码树自带的 testall 测试套件运行方法,并给出线程锁/时间/子进程/crypto 四个递进 C 示例的编译运行演示,基于 Ubuntu 22.04 与 CentOS 8 实测。
Apache APR 常用 CLI 命令与工具详解
目标:把 APR 在服务器上可直接操作的全部命令行工具一次讲清——apr-1-config、apu-1-config 两个配置脚本的逐参数用法与组合模板、源码树自带的 testall 自测套件,并用线程/锁、时间、子进程、加解密四个递进 C 示例演示「编译命令 + 运行结果」全流程;基于 apr 1.7.6 + apr-util 1.6.5 在 Ubuntu 22.04(GCC 11.4.0)与 CentOS 8(GCC 8.5.0)实测。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64)为主,CentOS 8.4.2105(x86_64)对照;
- 软件版本:apr 1.7.6、apr-util 1.6.5(源码编译安装于 /usr/local/apr);
- 编译器:GCC 11.4.0(Ubuntu)/ 8.5.0(CentOS),GNU Make 4.3 / 4.2.1;
- 演示目录:/root(示例源码与二进制均在此)。
二、工具概览
APR 是库(无独立守护进程),命令行工具天然少。apr 1.7.6 + apr-util 1.6.5 源码安装后,bin/ 目录实测只有两个工具:
$ ls /usr/local/apr/bin/
apr-1-config
apu-1-config
| 工具 | 所属 | 作用 |
|---|---|---|
| apr-1-config | apr 1.7.6 | 输出编译/链接 APR 核心库所需的编译器参数与路径 |
| apu-1-config | apr-util 1.6.5 | 输出编译/链接 apr-util 扩展库所需参数(含 LDAP/DBM 库信息) |
💡 技术拓展:老版本 Apache 生态里常见的
dbmmanage、htdigest、htpasswd等工具并不属于现代 apr-util——apr-util 自 1.3 时代后不再随包安装命令行工具,这些工具如今由 Apache httpd 的安装包提供(如 Ubuntu 的 apache2-utils)。apr-util 1.6.x 安装后只有上表两个 config 脚本(本文 ls 实测佐证)。
此外源码树附带两个测试套件工具(非安装产物,位于源码目录 test/ 下,编译源码后可用):apr 的 test/testall 与 apr-util 的 test/testall,见第六章。
三、前置条件
- 已完成 APR 安装(仓库版路径 /usr/bin/,源码版路径 /usr/local/apr/bin/,本文以源码版演示;安装过程见《Apache APR 在 Ubuntu 22.04 集成使用指南》);
- 运行示例需 gcc 与 make(Ubuntu
apt-get install -y build-essential;CentOSyum install -y gcc make); - 验证工具可用:
$ /usr/local/apr/bin/apr-1-config --version
1.7.6
$ /usr/local/apr/bin/apu-1-config --version
1.6.5
四、apr-1-config 详解
4.1 全参数速查(实测输出)
apr-1-config [OPTION],每个 OPTION 独立输出一行信息。20 个参数逐个实测的结果:
| 参数 | 实测输出 | 用途 |
|---|---|---|
--prefix | /usr/local/apr | 安装前缀 |
--bindir | /usr/local/apr/bin | 可执行文件目录 |
--includedir | /usr/local/apr/include/apr-1 | 头文件目录 |
--cc | gcc | configure 探测到的编译器 |
--cpp | gcc -E | 预处理器命令 |
--cflags | -g -O2 | 编译优化参数 |
--cppflags | -DLINUX -D_REENTRANT -D_GNU_SOURCE | 平台宏(必带) |
--includes | -I/usr/local/apr/include/apr-1 | 头文件搜索路径 |
--ldflags | (空) | 链接器附加参数 |
--libs | -luuid -lcrypt -lpthread | 依赖系统库(不含 -lapr-1!) |
--srcdir | /root/src/apr-1.7.6 | configure 时源码树路径 |
--installbuilddir | /usr/local/apr/build-1 | 构建规则目录 |
--link-ld | -L/usr/local/apr/lib -lapr-1 | 直接链接开关 |
--link-libtool | /usr/local/apr/lib/libapr-1.la | libtool 链接开关 |
--shlib-path-var | LD_LIBRARY_PATH | 动态库环境变量名 |
--apr-la-file | /usr/local/apr/lib/libapr-1.la | .la 文件路径 |
--apr-so-ext | lo | libtool 对象后缀 |
--apr-lib-target | -rpath $(libdir) $(OBJECTS) | libtool 目标模板 |
--apr-libtool | /usr/local/apr/build-1/libtool | libtool 副本路径 |
--version | 1.7.6 | 版本号 |
参数解读要点:--cppflags 的三个宏(LINUX/REENTRANT/GNU_SOURCE)必须出现在编译命令里,缺失会导致线程相关声明不完整;--libs 与 --link-ld 的分工见下方组合模板;CentOS 8 上 --cflags 多 -pthread、--libs 多 -lrt -ldl(双环境实测差异,工具已自动吸收,脚本无需区分发行版)。
4.2 日常组合用法
# 一行取全部编译参数(推荐写法)
$ /usr/local/apr/bin/apr-1-config --cflags --cppflags --includes
-g -O2 -DLINUX -D_REENTRANT -D_GNU_SOURCE -I/usr/local/apr/include/apr-1
# 官方推荐:直接链接(非 libtool 构建)
$ /usr/local/apr/bin/apr-1-config --link-ld --libs
-L/usr/local/apr/lib -lapr-1 -luuid -lcrypt -lpthread
# 官方推荐:libtool 构建(写 Makefile 时)
$ /usr/local/apr/bin/apr-1-config --link-libtool --libs
/usr/local/apr/lib/libapr-1.la -luuid -lcrypt -lpthread
# 版本号用于配置检查(如 httpd 编译脚本做最小版本判断)
$ test "$(/usr/local/apr/bin/apr-1-config --version)" = "1.7.6" && echo APR-OK
APR-OK
组合参数按顺序拼接输出(实测 --libs --link-ld 输出 -luuid -lcrypt -lpthread -L/usr/local/apr/lib -lapr-1)。
五、apu-1-config 详解
5.1 全参数速查(实测输出)
| 参数 | 实测输出(初始 sdbm 构建) | 实测输出(启用 ldap/bdb 后) | 用途 |
|---|---|---|---|
--prefix | /usr/local/apr | 同左 | 安装前缀 |
--bindir | /usr/local/apr/bin | 同左 | 可执行目录 |
--includedir | /usr/local/apr/include/apr-1 | 同左 | 头文件目录 |
--includes | -I/usr/local/apr/include/apr-1 -I/usr/include | 同左 | 头文件路径(多 -I/usr/include 给 expat) |
--ldflags | -L/usr/lib -L/usr/lib64 | 同左 | 链接搜索路径 |
--libs | -lexpat | -lldap -llber -ldb-5.3 -lexpat | 依赖库 |
--ldap-libs | (空) | -lldap -llber | LDAP 链接库 |
--dbm-libs | (空) | -ldb-5.3 | DBM 链接库 |
--avoid-ldap | (空) | (空) | 从 --libs 剔除 LDAP 信息 |
--avoid-dbm | (空) | (空) | 从 --libs 剔除 DBM 信息 |
--srcdir | /root/src/apr-util-1.6.5 | 同左 | 源码树路径 |
--link-ld | -L/usr/local/apr/lib -laprutil-1 | 同左 | 直接链接开关 |
--link-libtool | /usr/local/apr/lib/libaprutil-1.la | 同左 | libtool 链接开关 |
--apu-la-file | /usr/local/apr/lib/libaprutil-1.la | 同左 | .la 文件路径 |
--old-expat | @APR_XML_EXPAT_OLD@ | 同左 | 模板替换瑕疵(见 Q2) |
--db-version | 0 | 5 | DBM 后端版本(0=sdbm 内置,5=BDB 5.x) |
--version | 1.6.5 | 同左 | 版本号 |
💡 说明:两列输出对比直观展示 configure 选项如何改变工具行为——LDAP/BDB 启用是重编 apr-util(
--with-ldap --with-berkeley-db)的结果。--avoid-ldap/--avoid-dbm是布尔开关,作用是让同一次调用里的--libs输出不带对应库(便于构建系统按需裁剪),单独执行无输出属正常。
5.2 日常组合用法
# apu + apr 双库完整编译参数(crypto/DBD 等场景)
$ APR=/usr/local/apr/bin/apr-1-config; APU=/usr/local/apr/bin/apu-1-config
$ gcc app.c $($APR --cflags --includes) $($APU --includes) \
$($APR --link-ld) $($APU --link-ld) $($APU --libs) $($APR --libs)
# 检查 DBM 后端类型(运维排查 .db 文件兼容性)
$ /usr/local/apr/bin/apu-1-config --db-version
5
# 验证 LDAP 支持是否真的编入(输出空 = 未启用)
$ /usr/local/apr/bin/apu-1-config --ldap-libs
-lldap -llber
六、源码树测试套件:testall
APR 源码自带两套自测程序,用于安装后验证库正确性(不随 make install 安装,在源码树内编译运行)。这既是质量验证手段,也是排障利器(安装环境异常时 testall 会暴露)。
6.1 apr-util 测试套件
$ cd /root/src/apr-util-1.6.5/test
$ make
if test ! -d "./data"; then cp -r ./data data; fi
make[1]: Leaving directory '/root/src/apr-util-1.6.5/test'
$ ./testall
teststrmatch : SUCCESS
testuri : SUCCESS
testuuid : SUCCESS
testbuckets : SUCCESS
testpass : SUCCESS
testmd4 : SUCCESS
testmd5 : SUCCESS
testcrypto : SUCCESS
testldap : SUCCESS
testdbd : SUCCESS
testdate : SUCCESS
testmemcache : SUCCESS
testredis : SUCCESS
testxml : SUCCESS
testxlate : SUCCESS
testrmm : SUCCESS
testdbm : SUCCESS
testqueue : SUCCESS
testreslist : SUCCESS
testsiphash : SUCCESS
All tests passed.
⚠️ 注意:仅编了 openssl 驱动的环境下,testcrypto 用例运行时会滚出多行
Crypto driver 'nss' DSO could not be opened(按名探测未编译驱动的正常报错,stderr 输出),最终结果仍是 SUCCESS/All tests passed,不要误判为失败。
6.2 apr 核心测试套件
$ cd /root/src/apr-1.7.6/test && make
$ ./testall
...(40+ 用例,节选尾部)
testsockopt : SUCCESS
teststr : SUCCESS
teststrnatcmp : SUCCESS
testtable : SUCCESS
testtemp : SUCCESS
testthread : SUCCESS
testtime : SUCCESS
testud : SUCCESS
testuser : SUCCESS
testvsn : SUCCESS
testskiplist : SUCCESS
All tests passed.
两套套件在 Ubuntu 与 CentOS 8 双环境实测均全绿。
七、递进示例:从锁到 crypto 的编译运行
本节 4 个示例逐级递进,每个都给完整源码、编译命令与实测输出。编译命令统一用 5.2 节模板。
7.1 示例一:多线程 + 互斥锁(apr_thread_demo.c)
4 线程各累加计数器 10 万次,用 apr_thread_mutex 保护,验证并发正确性:
/* apr_thread_demo.c —— APR 线程 + 互斥锁:4 线程并发累加 */
#include <stdio.h>
#include <stdlib.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_thread_proc.h>
#include <apr_thread_mutex.h>
#define N_THREADS 4
#define N_LOOPS 100000
static apr_thread_mutex_t *g_lock = NULL;
static long long g_counter = 0;
static void *APR_THREAD_FUNC worker(apr_thread_t *th, void *data)
{
for (int i = 0; i < N_LOOPS; i++) {
apr_thread_mutex_lock(g_lock); /* 进入临界区 */
g_counter++;
apr_thread_mutex_unlock(g_lock);
}
return NULL;
}
int main(void)
{
apr_initialize();
atexit(apr_terminate);
apr_pool_t *pool;
apr_pool_create(&pool, NULL);
apr_thread_mutex_create(&g_lock, APR_THREAD_MUTEX_DEFAULT, pool);
apr_thread_t *tid[N_THREADS];
for (int i = 0; i < N_THREADS; i++) {
apr_thread_create(&tid[i], NULL, worker, NULL, pool);
printf("[+] thread %d started\n", i);
}
for (int i = 0; i < N_THREADS; i++) {
apr_status_t rv;
apr_thread_join(&rv, tid[i]);
}
printf("[=] expected %d, got %lld (%s)\n", N_THREADS * N_LOOPS, g_counter,
g_counter == 400000 ? "OK" : "MISMATCH");
apr_thread_mutex_destroy(g_lock);
apr_pool_destroy(pool);
return 0;
}
编译与实测运行(Ubuntu):
$ APR=/usr/local/apr/bin/apr-1-config
$ gcc apr_thread_demo.c -o apr_thread_demo $($APR --cflags --includes) $($APR --link-ld) $($APR --libs)
$ ./apr_thread_demo
[+] thread 0 started
[+] thread 1 started
[+] thread 2 started
[+] thread 3 started
[=] expected 400000, got 400000 (OK)
CentOS 8 同命令编译运行输出一致(实测 [=] expected 400000, got 400000 (OK)),线程 API 行为跨发行版一致。
7.2 示例二:时间处理(apr_time_demo.c)
微秒时间获取、本地/GMT 分解、strftime 格式化、RFC822 日期、apr_sleep 精度:
/* apr_time_demo.c —— APR 时间:获取/分解/格式化/测量 */
#include <stdio.h>
#include <stdlib.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_time.h>
int main(void)
{
apr_initialize();
atexit(apr_terminate);
apr_pool_t *pool;
apr_pool_create(&pool, NULL);
apr_time_t now = apr_time_now(); /* 微秒时间戳 */
printf("[1] now = %" APR_INT64_T_FMT " usec\n", now);
apr_time_exp_t lt, gt;
apr_time_exp_lt(<, now); /* 本地时间 */
apr_time_exp_gmt(>, now); /* GMT 时间 */
printf("[2] local : %04d-%02d-%02d %02d:%02d:%02d (tm_gmtoff=%d)\n",
lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday,
lt.tm_hour, lt.tm_min, lt.tm_sec, (int)lt.tm_gmtoff);
printf(" gmt : %04d-%02d-%02d %02d:%02d:%02d\n",
gt.tm_year + 1900, gt.tm_mon + 1, gt.tm_mday,
gt.tm_hour, gt.tm_min, gt.tm_sec);
apr_size_t rs; /* 自定义格式化 */
char buf[64];
apr_strftime(buf, &rs, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", <);
printf("[3] strftime: %s\n", buf);
char rfc[APR_RFC822_DATE_LEN]; /* HTTP 日期头格式 */
apr_rfc822_date(rfc, now);
printf("[4] rfc822: %s\n", rfc);
apr_time_t t0 = apr_time_now(); /* sleep 精度实测 */
apr_sleep(250000);
printf("[5] apr_sleep(250ms) actual cost = %" APR_INT64_T_FMT " usec\n",
apr_time_now() - t0);
apr_pool_destroy(pool);
return 0;
}
实测输出(Ubuntu;> 250283 usec 表示 sleep 精度优于 1ms):
$ gcc apr_time_demo.c -o apr_time_demo $($APR --cflags --includes) $($APR --link-ld) $($APR --libs)
$ ./apr_time_demo
[1] now = 1792110837312075 usec
[2] local : 2026-10-16 00:33:57 (tm_gmtoff=0)
gmt : 2026-10-16 00:33:57
[3] strftime: 2026-10-16 00:33:57 UTC
[4] rfc822: Fri, 16 Oct 2026 00:33:57 GMT
[5] apr_sleep(250ms) actual cost = 250283 usec
(CentOS 8 实测同构输出,仅时间戳随运行时刻不同。)
7.3 示例三:子进程创建与回收(apr_proc_demo.c)
用 apr_proc_create 启动 /bin/echo 并 apr_proc_wait 回收退出码:
/* apr_proc_demo.c —— APR 子进程:spawn /bin/echo 并 wait */
#include <stdio.h>
#include <stdlib.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_thread_proc.h>
int main(void)
{
apr_initialize();
atexit(apr_terminate);
apr_pool_t *pool;
apr_pool_create(&pool, NULL);
apr_procattr_t *attr;
apr_procattr_create(&attr, pool);
apr_procattr_io_set(attr, APR_NO_PIPE, APR_FULL_BLOCK, APR_FULL_BLOCK);
apr_procattr_cmdtype_set(attr, APR_PROGRAM_PATH); /* 按 PATH 查找 */
apr_proc_t proc;
const char *args[] = { "/bin/echo", "hello from APR child process", NULL };
apr_status_t st = apr_proc_create(&proc, args[0], args, NULL, attr, pool);
if (st != APR_SUCCESS) { fprintf(stderr, "proc create failed\n"); return 1; }
printf("[1] child spawned: pid=%d\n", proc.pid);
int exitcode = 0;
apr_exit_why_e why;
st = apr_proc_wait(&proc, &exitcode, &why, APR_WAIT);
printf("[2] wait: status=%d exitcode=%d why=%d (%s)\n", st, exitcode, (int)why,
why == APR_PROC_EXIT ? "normal exit" : "signaled");
apr_pool_destroy(pool);
return 0;
}
实测输出(Ubuntu 与 CentOS 8 一致,pid 每次不同):
$ gcc apr_proc_demo.c -o apr_proc_demo $($APR --cflags --includes) $($APR --link-ld) $($APR --libs)
$ ./apr_proc_demo
[1] child spawned: pid=38101
[2] wait: status=70005 exitcode=0 why=1 (normal exit)
💡 说明:
status=70005是 APR 把系统 waitpid 返回值封装后的原始状态码(低 8 位退出码 0、高位标记正常退出),判断结果请用 exitcode 与 why 字段,不要直接解读 status。
7.4 示例四:crypto 加解密(apr_crypto_demo.c,apr-util DSO 驱动)
加载 openssl 加密驱动,PBKDF2 派生 AES-256 密钥完成加解密回环(同时验证 apr-util DSO 模块加载机制):
/* apr_crypto_demo.c —— apr-util crypto:openssl 驱动 AES-256-CBC 加解密 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <apr_general.h>
#include <apr_pools.h>
#include <apu.h>
#include <apr_crypto.h>
int main(void)
{
apr_initialize();
atexit(apr_terminate);
apr_pool_t *pool;
apr_pool_create(&pool, NULL);
const apu_err_t *err = NULL;
const apr_crypto_driver_t *driver = NULL;
apr_status_t st;
st = apr_crypto_init(pool); /* 全局初始化(必须先于 get_driver) */
if (st != APR_SUCCESS) { fprintf(stderr, "crypto_init failed\n"); return 1; }
st = apr_crypto_get_driver(&driver, "openssl", NULL, &err, pool);
if (st != APR_SUCCESS) { fprintf(stderr, "load driver failed\n"); return 1; }
printf("[1] openssl crypto driver loaded\n");
apr_crypto_t *crypto = NULL;
apr_crypto_make(&crypto, driver, NULL, pool);
/* PBKDF2 由口令派生 AES-256 密钥 */
apr_crypto_key_t *key = NULL;
apr_size_t ivSize = 0;
const char *pass = "q1w2e3r4";
const unsigned char *salt = (const unsigned char *)"quzuo-salt-01";
st = apr_crypto_passphrase(&key, &ivSize, pass, strlen(pass),
salt, strlen((const char *)salt),
APR_KEY_AES_256, APR_MODE_CBC, 1, 1000,
crypto, pool);
if (st != APR_SUCCESS) { fprintf(stderr, "passphrase failed\n"); return 1; }
printf("[2] key derived: ivSize=%d bytes\n", (int)ivSize);
/* 加密 */
const char *plain = "quzuo APR crypto demo";
apr_size_t plen = strlen(plain);
apr_crypto_block_t *ectx = NULL;
const unsigned char *iv = NULL;
apr_size_t blockSize = 0;
apr_crypto_block_encrypt_init(&ectx, &iv, key, &blockSize, pool);
unsigned char *cipher = NULL;
apr_size_t clen = 0, flen = 0;
apr_crypto_block_encrypt(&cipher, &clen, (const unsigned char *)plain, plen, ectx);
apr_crypto_block_encrypt_finish(cipher + clen, &flen, ectx);
clen += flen;
printf("[3] plaintext(%d bytes) -> ciphertext(%d bytes), block=%d\n",
(int)plen, (int)clen, (int)blockSize);
/* 解密还原 */
apr_crypto_block_t *dctx = NULL;
apr_size_t dBlockSize = 0;
apr_crypto_block_decrypt_init(&dctx, &dBlockSize, iv, key, pool);
unsigned char *back = NULL;
apr_size_t blen = 0, dlen = 0;
apr_crypto_block_decrypt(&back, &blen, cipher, clen, dctx);
apr_crypto_block_decrypt_finish(back + blen, &dlen, dctx);
blen += dlen;
printf("[4] decrypted(%d bytes): %.*s\n", (int)blen, (int)blen, back);
apr_pool_destroy(pool);
return 0;
}
编译(注意需要 apu-1-config 参与)与实测输出:
$ APR=/usr/local/apr/bin/apr-1-config; APU=/usr/local/apr/bin/apu-1-config
$ gcc apr_crypto_demo.c -o apr_crypto_demo $($APR --cflags --includes) $($APU --includes) \
$($APR --link-ld) $($APU --link-ld) $($APU --libs) $($APR --libs)
$ ./apr_crypto_demo
[1] openssl crypto driver loaded
[2] key derived: ivSize=16 bytes
[3] plaintext(21 bytes) -> ciphertext(32 bytes), block=16
[4] decrypted(21 bytes): quzuo APR crypto demo
(Ubuntu 与 CentOS 8 双环境实测输出一致。)21 字节明文经 PKCS#7 填充成 32 字节密文、解密后完整还原,openssl DSO 驱动(apr_crypto_openssl-1.so)按名加载成功。
八、注意事项
- 工具路径二选一要固定:仓库版
/usr/bin/apr-1-config(apr 1.6.3)与源码版/usr/local/apr/bin/apr-1-config(1.7.6)版本不同,构建脚本写绝对路径避免混用; --libs不含库本体是设计如此:apr 自身以--link-ld输出,漏掉是链接错误的首要原因(实测 Q3 场景);- testall 需要在源码树内编译(make 后生成),且 apr-util 的 testcrypto 会打印未编译驱动的 DSO 报错(正常噪音);
- crypto 示例必须先
apr_crypto_init(pool)再apr_crypto_get_driver(),顺序颠倒会段错误(实测定位过程:pthread_mutex_lock 未初始化崩溃)。
九、常见问题(FAQ)
Q1:apr-1-config 报 command not found?
工具未安装或不在 PATH。仓库方案确认包已装(dpkg -l | grep libapr1-dev / rpm -qa | grep apr-devel),源码方案用绝对路径 /usr/local/apr/bin/apr-1-config。
Q2:apu-1-config --old-expat 输出 @APR_XML_EXPAT_OLD@?
apr-util 1.6.5 的模板替换瑕疵(实测原样输出占位符),不代表构建异常;判断 expat 用 --libs 是否含 -lexpat。
Q3:编译报 undefined reference to 'apr_initialize'?
链接参数漏 --link-ld。完整模板:gcc app.c $($APR --cflags --includes) $($APR --link-ld) $($APR --libs)(--libs 单独使用没有 -lapr-1,实测其输出仅 -luuid -lcrypt -lpthread)。
Q4:编译通过但运行报 libapr-1.so.0 cannot open shared object file?
动态库路径未注册:echo "/usr/local/apr/lib" > /etc/ld.so.conf.d/apr-1.conf && ldconfig(实测注册后 ldconfig -p 可见 libapr-1 条目)。
Q5:crypto 示例运行段错误(Segfault)?
最常见原因是漏掉 apr_crypto_init(pool)——apr-util 1.6.5 的 crypto 全局锁未初始化,apr_crypto_get_driver 内 pthread_mutex_lock 直接崩溃(实测 AddressSanitizer 定位到 crypto/apr_crypto.c:254)。补上初始化调用即恢复。
十、参考链接
- APR 工具与编译说明:https://apr.apache.org/compiling_unix.html
- APR 1.7 API 文档:https://apr.apache.org/docs/apr/1.7/
- apr-util 1.6 API 文档(crypto/DBD 章节):https://apr.apache.org/docs/apr-util/1.6/
- 系列相关篇:《Apache APR 介绍与选型指南》《Apache APR 在 Ubuntu 22.04 集成使用指南》《Apache APR 在 CentOS 8 集成使用指南》《Apache APR 配置与构建参数详解》