Apache APR 在 Ubuntu 22.04 集成使用指南

从零开始在 Ubuntu 22.04 上安装并集成 Apache APR:覆盖 apt 仓库方案与 1.7.6/1.6.5 源码编译方案、apr-1-config 编译接线、完整 C 示例(内存池/字符串/文件读写)编译运行验证与常见报错修复,全部命令实测通过。

Apache APRApache APRC/C++UbuntuUbuntu 22.04Linux2026/10/16

Apache APR 在 Ubuntu 22.04 集成使用指南

目标:在 Ubuntu 22.04 服务器上从零装好 Apache APR(apr 1.7.6 + apr-util 1.6.5)并用 gcc 编译运行第一个 APR C 程序;本文覆盖 apt 仓库与源码编译两条安装路线、编译链接命令模板、运行期动态库配置与踩坑修复,全部步骤已在 Ubuntu 22.04(x86_64)实测通过。

一、环境信息

本文所有命令与回显均来自以下实测环境:

  • 操作系统:Ubuntu 22.04(x86_64),内核 5.15 系列;
  • 编译器:GCC 11.4.0(实测 gcc --version 首行为 gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0);
  • 构建工具:GNU Make 4.3(实测 make --version 首行);
  • 源码版本:apr 1.7.6、apr-util 1.6.5(2026-10 官网 apr.apache.org 下载页确认的当前稳定版);
  • 安装前缀(源码方案):/usr/local/apr;
  • 演示目录:/root(源码包放 /root/src)。

二、前置条件(编译工具与依赖)

2.1 安装编译工具链

源码编译方案需要 gcc、make 及若干开发头文件;apt 方案只需第一步。更新索引并安装(实测执行,输出节选尾部):

$ apt-get update
...
Fetched 49.0 MB in 6s (7590 kB/s)
Reading package lists... Done
$ DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential curl libssl-dev libexpat1-dev uuid-dev
...
Setting up libssl-dev:amd64 (3.0.2-0ubuntu1.19) ...
Processing triggers for libc-bin (2.35-0ubuntu3.15) ...

依赖用途说明:

包作用是否必需
build-essentialgcc/g++/make 编译器套件源码方案必需
curl下载源码包(也可用 wget)必需
libssl-devOpenSSL 开发头文件,apr-util crypto 驱动用可选(需要加密功能时)
libexpat1-devexpat XML 解析库头文件,apr-util XML 组件必需apr-util 必需
uuid-devlibuuid 头文件,apr 核心 UUID 生成用必需

2.2 验证工具链

$ gcc --version | head -1
gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
$ make --version | head -1
GNU Make 4.3
$ uname -m
x86_64

三、版本选型说明

安装前先确认版本。Ubuntu 22.04 官方仓库内置的 APR 版本较旧,与官网最新稳定版对比如下(两组版本号均为实测采集):

来源apr 版本apr-util 版本获取方式
Ubuntu 22.04 官方仓库1.7.0(libapr1 1.7.0-8ubuntu0.22.04.2)1.6.1(1.6.1-5ubuntu4.22.04.3)apt-get install
APR 官网(2026-10 查询)1.7.61.6.5源码编译

选型解读:只作为 httpd/subversion 等软件的间接依赖,用仓库版即可省事;要跟进官方修复、或下游软件(如编译 httpd)要求较新 apr 时,走源码方案。两条路线可以共存(仓库版装在 /usr,源码版装在 /usr/local/apr,互不干扰)。

四、方案 A:apt 仓库安装(快速路线)

本节用 Ubuntu 官方仓库一步装齐运行库与开发头文件,适合快速上手或内网已有镜像源的服务器。apr 在 Ubuntu 上的开发包名为 libapr1-dev 与 libaprutil1-dev:

$ apt-get install -y libapr1-dev libaprutil1-dev
...
Setting up libaprutil1-dev (1.6.1-5ubuntu4.22.04.3) ...
Processing triggers for libc-bin (2.35-0ubuntu3.15) ...

验证安装结果(版本与包清单):

$ dpkg -l | grep libapr
ii  libapr1:amd64               1.7.0-8ubuntu0.22.04.2   amd64  Apache Portable Runtime Library
ii  libapr1-dev                 1.7.0-8ubuntu0.22.04.2   amd64  Apache Portable Runtime Library - Development Headers
ii  libaprutil1:amd64           1.6.1-5ubuntu4.22.04.3   amd64  Apache Portable Runtime Utility Library
ii  libaprutil1-dev             1.6.1-5ubuntu4.22.04.3   amd64  Apache Portable Runtime Utility Library - Development Headers
$ /usr/bin/apr-1-config --version
1.7.0
$ /usr/bin/apu-1-config --version
1.6.1

仓库版安装完成后即可跳到第六章的编译示例(把示例命令中的 /usr/local/apr/bin/apr-1-config 换成 /usr/bin/apr-1-config 即可)。

五、方案 B:源码编译安装(官方最新版路线)

本节从官网下载 1.7.6/1.6.5 源码编译安装到 /usr/local/apr,是获取最新版本的推荐路线,也是编译 httpd 时的常用前置。

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:23 apr-1.7.6.tar.gz
-rw-r--r-- 1 root root  567877 Oct 16 00:23 apr-util-1.6.5.tar.gz
$ sha256sum apr-1.7.6.tar.gz apr-util-1.6.5.tar.gz
6a10e7f7430510600af25fabf466e1df61aaae910bf1dc5d10c44a4433ccc81d  apr-1.7.6.tar.gz
f43a1c8c79eef497a022ec6c99dddbdf57e42001da6ccbfae259631ed5aa2805  apr-util-1.6.5.tar.gz

⚠️ 注意:若官网下载慢或超时,可改用代理:curl -x http://192.168.1.62:7897 -sSL -o apr-1.7.6.tar.gz https://dlcdn.apache.org/apr/apr-1.7.6.tar.gz(代理地址按实际网络替换)。

5.2 编译安装 apr

解压、configure、编译、安装,四步走(关键回显实测转录):

$ cd /root/src && tar zxf apr-1.7.6.tar.gz && cd apr-1.7.6
$ ./configure --prefix=/usr/local/apr
...(检测输出略)
config.status: creating test/Makefile
config.status: creating test/internal/Makefile
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
$ echo $?
0

⚠️ 注意:configure 尾部的 rm: cannot remove 'libtoolT': No such file or directory 是 apr 1.7.x 脚本的无害告警(libtool 模板变量在 Linux 上未生成导致),只要最终出现 config.status: executing default commands 且退出码为 0,configure 即已成功,可忽略继续 make。

$ make -j$(nproc)
...(编译输出节选)
/bin/bash /root/src/apr-1.7.6/libtool --silent --mode=link --tag=CC gcc -g -O2 ...
   -version-info 7:6:7 -o libapr-1.la -rpath /usr/local/apr/lib ...
make[1]: Leaving directory '/root/src/apr-1.7.6'
$ make install
...(安装输出节选尾部)
/usr/bin/install -c -m 644 build/apr_rules.out /usr/local/apr/build-1/apr_rules.mk
/usr/bin/install -c -m 755 apr-config.out /usr/local/apr/bin/apr-1-config
$ /usr/local/apr/bin/apr-1-config --version
1.7.6

版本回显 1.7.6 即安装成功。安装产物分布在四个目录:bin/(apr-1-config)、include/apr-1/(72 个头文件)、lib/(libapr-1.so.0.7.6 与 pkgconfig)、build-1/(构建辅助规则)。

5.3 编译安装 apr-util

apr-util 必须 --with-apr 指向上一步的 apr-1-config;本例同时启用 OpenSSL 加密驱动(依赖 2.1 装的 libssl-dev):

$ 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
...(检测输出节选)
checking for EVP_CIPHER_CTX_new in -lcrypto... yes
checking for OPENSSL_init_crypto in -lcrypto... yes
checking for default DBM... sdbm (default)
checking for postgresql/libpq-fe.h... no
checking for sqlite3.h... no
$ make -j$(nproc)
...(编译输出节选尾部)
make[1]: Leaving directory '/root/src/apr-util-1.6.5'
$ make install
...(安装输出节选尾部)
/usr/bin/install -c -m 755 apu-config.out /usr/local/apr/bin/apu-1-config
$ /usr/local/apr/bin/apu-1-config --version
1.6.5

💡 说明:--with-crypto 开启加密框架;没装 PostgreSQL/SQLite 客户端头文件时,configure 会显示 no 并继续——对应 DBD 驱动只是不编译,不影响其他功能。需要这些驱动时补装 libpq-dev、libsqlite3-dev(及 libldap2-dev、libdb-dev、libmariadb-dev 对应 LDAP/BDB/MySQL)后重新 configure 即可,详见《Apache APR 配置与构建参数详解》。

验证动态模块目录(含 crypto 驱动即成功):

$ ls /usr/local/apr/lib/apr-util-1/ | grep "\-1.so"
apr_crypto_openssl-1.so
apr_dbd_mysql-1.so
apr_dbd_sqlite3-1.so
apr_dbm_db-1.so
apr_ldap-1.so

(此处 mysql/sqlite3/bdb/ldap 模块是后补依赖重编后的结果;按 5.3 首轮默认 configure 只会有 apr_crypto_openssl-1.so。)

5.4 注册动态库搜索路径(关键一步)

源码安装到 /usr/local/apr/lib 后,系统加载器默认不搜索该目录,直接运行程序会报 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 | 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:apt 仓库方案 B:源码编译
apr/apr-util 版本1.7.0 / 1.6.11.7.6 / 1.6.5(官网最新)
是否需联网编译否(apt 源)是(官网下载)
安装位置/usr(系统托管)/usr/local/apr(自管)
升级方式apt upgrade重新下载源码编译
可选组件发行版拆包决定configure 选项自由裁剪
适用场景快速起步、间接依赖需要最新版/自定义功能/编译 httpd

选择建议:生产服务器若只跑 httpd 等发行版打包软件,用方案 A 跟随系统升级最省心;要做 APR 二次开发、需要 crypto/LDAP 等特定组合,或下游软件对版本有要求,用方案 B。

七、集成示例:第一个 APR C 程序

本节给出一个完整可运行的 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 编译命令模板

APR 自带 apr-1-config 输出编译参数,正确模板如下(源码方案路径;apt 方案把工具路径换成 /usr/bin/apr-1-config):

$ 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

⚠️ 注意:$($APR --link-ld) 不可省略。--libs 只输出 APR 的依赖库(-luuid -lcrypt -lpthread),不含 APR 库本身;少了 --link-ld(输出 -L/usr/local/apr/lib -lapr-1)会得到一屏 undefined reference to 'apr_initialize' 链接错误。详见第八章 Q3。

7.2 运行与验证

$ ./apr_demo
[1] pool created: 0x5e2caa69b3b8
[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

五个步骤全部按预期输出,落盘文件内容与写入字符串一致,集成环境验证完毕。池地址(0x5e2c...)每次运行不同属正常现象。

八、常见问题(FAQ)

Q1:configure 报 rm: cannot remove 'libtoolT': No such file or directory,是失败吗? 不是。apr 1.7.x 在 Linux 上的已知无害告警,configure 退出码为 0 即成功,直接继续 make(实测全过程见 5.2)。

Q2:./configure 报找不到 gcc 或编译器? 未装 build-essential。执行 apt-get install -y build-essential 后重新 configure(本文 2.1 实测安装的即该包)。

Q3:编译报 undefined reference to 'apr_pool_create_ex'、undefined reference to 'apr_initialize' 一长串? 链接参数不完整:apr-1-config --libs 输出只有 -luuid -lcrypt -lpthread(实测),不含 -lapr-1 本体。把命令改为 gcc apr_demo.c -o apr_demo $($APR --cflags --includes) $($APR --link-ld) $($APR --libs),其中 --link-ld 输出 -L/usr/local/apr/lib -lapr-1(实测)补齐库路径与库名。

Q4:编译通过但运行报 error while loading shared libraries: libapr-1.so.0: cannot open shared object file? 运行期找不到动态库。源码安装路径未注册到加载器,按 5.4 执行 echo "/usr/local/apr/lib" > /etc/ld.so.conf.d/apr-1.conf && ldconfig 后重试(实测注册后 ldconfig -p 可查到两条 libapr-1 条目)。临时验证也可用 LD_LIBRARY_PATH=/usr/local/apr/lib ./apr_demo。

Q5:想用 LDAP/MySQL/SQLite 等 apr-util 扩展怎么装? 补装对应开发包(libldap2-dev、libmariadb-dev、libsqlite3-dev、libdb-dev)后在 apr-util 源码目录 make distclean 再 configure,加上 --with-ldap --with-mysql --with-sqlite3 --with-berkeley-db(可组合),重新 make install。若不带依赖直接传 --with-ldap,configure 不会报错退出,而是逐个探测 -lldap50/-lldap 等全部失败后静默回退为无 LDAP 支持(实测行为),所以装完依赖要看 configure 输出里 setting LDADD_ldap to "-lldap -llber" 这类确认行。

九、卸载与清理

源码方案卸载:删除安装目录与 ld 配置即可(apr 源码 make install 无 uninstall 目标):

$ rm -rf /usr/local/apr
$ rm -f /etc/ld.so.conf.d/apr-1.conf && ldconfig
$ /usr/local/apr/bin/apr-1-config --version
bash: /usr/local/apr/bin/apr-1-config: No such file or directory

(回显 No such file or directory 即卸载完成;该输出取自同版本实测环境的卸载演练。)

apt 方案卸载(实测,purge 会连带清理依赖包):

$ apt-get purge -y libapr1-dev libaprutil1-dev
...
Removing libaprutil1-dev (1.6.1-5ubuntu4.22.04.3) ...
Removing libapr1-dev (1.7.0-8ubuntu0.22.04.2) ...
Removing libaprutil1 (1.6.1-5ubuntu4.22.04.3) ...
Removing libapr1 (1.7.0-8ubuntu0.22.04.2) ...
$ apt-get autoremove -y
...
0 upgraded, 0 newly installed, 3 to remove and 3 not upgraded.
Remv media-types
$ dpkg -l | grep libapr
(无输出,即已卸干净)

💡 说明:libapr1-dev/libaprutil1-dev 卸载后,运行库本体 libapr1/libaprutil1 若被其他软件依赖会自动保留;仅当无依赖者时 purge/autoremove 会一并移除。重装恢复:apt-get install -y libapr1-dev libaprutil1-dev(实测重装后 4 个包均回到 ii 状态)。

源码包与构建树清理:rm -rf /root/src/apr-1.7.6 /root/src/apr-util-1.6.5(保留 .tar.gz 可供下次重装),或在源码树内 make distclean 恢复 pristine 状态。

十、参考链接