源码编译安装
当包管理器提供的版本不满足要求(例如需要尝鲜开发版、需要打自定义补丁、或发行版仓库太旧)时,源码编译是唯一的选择。本节讲解从源码构建 PostgreSQL 18 的完整流程:依赖准备、configure 参数、编译安装、contrib 扩展,以及它与包管理器安装的取舍。
前置知识
阅读本节前,建议先了解:Docker 安装
基础概念
源码编译(Build from Source)指用 C 编译器把 PostgreSQL 的源代码编译成可执行文件,再安装到指定目录。理解几个名词:
- 构建系统(Build System):PostgreSQL 传统上使用 GNU Autoconf 生成的
configure脚本;PostgreSQL 16 起可选用 Meson + Ninja 构建,18 中 Meson 已经相当成熟 - 前缀(Prefix):
--prefix指定的安装根目录,默认/usr/local/pgsql,所有 bin / lib / share 都基于它 - 构建依赖(Build Dependency):编译期需要、运行期不一定需要的库,如
readline、zlib - 可选项(Feature):通过
--with-xxx/--without-xxx显式启用或关闭的功能模块 - contrib:官方随源码分发的扩展合集(如
pg_stat_statements、pgcrypto、postgres_fdw),需单独编译安装 - 编译工具链(Toolchain):
gcc/clang、make、pkg-config,以及各库的开发头文件包
| 安装方式 | 版本灵活性 | 升级维护 | 编译耗时 | 适用场景 |
|---|---|---|---|---|
| 包管理器(apt / dnf) | 低,跟随仓库 | 简单 | 无 | 绝大多数生产环境 |
| 官方二进制安装包 | 中 | 简单 | 无 | 不想加第三方源时 |
| Docker 镜像 | 中 | 简单 | 无 | 开发、CI、测试 |
| 源码编译 | 高,任意版本 | 复杂 | 10~30 分钟 | 尝鲜、打补丁、裁剪、嵌入式 |
| 源码 + 打包成 RPM/DEB | 高 | 可控 | 长 | 大规模集群统一交付 |
版本说明
PostgreSQL 18 起,官方同时推荐 Autoconf 与 Meson 两种构建方式。Meson 构建更快、增量编译体验更好,但仍需 Autoconf 才能生成 configure 脚本(源码发行包 postgresql-18.x.tar.bz2 已包含 configure,无需自行执行 autoconf)。
安装与配置
一、准备依赖包
编译 PostgreSQL 本身只需要 C 编译器和 make,但不带可选库会让功能严重残缺(例如没有 readline 就没有命令历史与补全)。推荐一次性装齐。
# Debian / Ubuntu:安装编译器与各开发库(-dev 包才是头文件)
sudo apt update
sudo apt install -y build-essential make pkg-config \
libreadline-dev zlib1g-dev libssl-dev libxml2-dev libxslt1-dev \
libperl-dev python3-dev tcl-dev libicu-dev libldap2-dev \
libpam0g-dev libselinux1-dev libkrb5-dev liblz4-dev libzstd-dev \
bison flex
# RHEL / Rocky / AlmaLinux:包名通常以 -devel 结尾
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y readline-devel zlib-devel openssl-devel libxml2-devel \
libxslt-devel perl-devel python3-devel tcl-devel libicu-devel \
openldap-devel pam-devel libselinux-devel krb5-devel lz4-devel libzstd-devel \
bison flex| 依赖库 | 对应 configure 选项 | 缺少后的后果 | 是否推荐 |
|---|---|---|---|
| readline | 自动探测 | psql 无命令历史、无 Tab 补全 | 强烈推荐 |
| zlib | --with-zlib | 无法使用 gzip 压缩的备份,pg_dump -Z 失效 | 强烈推荐 |
| OpenSSL | --with-openssl | 无法使用 SSL/TLS 加密连接 | 生产必装 |
| libxml2 | --with-libxml | 无 XML 类型与 xpath() 函数 | 按需 |
| libxslt | --with-libxslt | 无 xml2 contrib 的 XSLT 能力 | 按需 |
| ICU | --with-icu | 无 ICU 排序规则,多语言排序弱 | 推荐 |
| LZ4 | --with-lz4 | 无法使用 lz4 压缩 TOAST 与 WAL | 推荐 |
| Zstandard | --with-zstd | 无法使用 zstd 压缩 | 推荐 |
| Perl | --with-perl | 无法编写 PL/Perl 函数与部分构建脚本 | 按需 |
| Python | --with-python | 无法编写 PL/Python 函数 | 按需 |
| Tcl | --with-tcl | 无法运行部分回归测试 | 按需 |
| OpenLDAP | --with-ldap | 无法用 LDAP 做认证 | 按需 |
| PAM | --with-pam | 无法用 PAM 认证 | 按需 |
| bison / flex | —— | 源码仓库构建必需;发行包可省 | 视情况 |
二、下载源码
# 方式 A:官方发行包(推荐,已含 configure 脚本)
cd /usr/local/src
sudo curl -LO https://ftp.postgresql.org/pub/source/v18.0/postgresql-18.0.tar.bz2
sudo curl -LO https://ftp.postgresql.org/pub/source/v18.0/postgresql-18.0.tar.bz2.sha256
# 校验完整性,避免下载被篡改或截断
sudo sha256sum -c postgresql-18.0.tar.bz2.sha256
sudo tar -xjf postgresql-18.0.tar.bz2
cd postgresql-18.0
# 方式 B:Git 仓库(仅尝鲜开发版时需要,必须自行执行 configure 生成)
# git clone --depth 1 --branch REL_18_STABLE \
# https://git.postgresql.org/git/postgresql.git
# cd postgresql && ./configure # 由 autoconf 生成,故需要 bison/flex三、configure 参数详解
configure 决定了编译出什么样的 PostgreSQL。核心原则:功能只加不减,路径尽量固定。
# 完整示例:生产可用的编译配置
./configure \
--prefix=/usr/local/pgsql-18 \
--with-openssl \
--with-zlib \
--with-lz4 \
--with-zstd \
--with-icu \
--with-libxml \
--with-pam \
--with-ldap \
--with-perl \
--with-python \
--enable-thread-safety \
--enable-nls \
--enable-depend \
--with-systemd \
--with-extra-version=" (MyCorp Build)"| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--prefix=DIR | 路径 | /usr/local/pgsql | 安装根目录;多版本并存时务必带版本号 |
--with-openssl | 开关 | 关闭 | 启用 SSL/TLS 加密连接 |
--with-zlib | 开关 | 关闭 | 支持 zlib 压缩备份 |
--with-lz4 / --with-zstd | 开关 | 关闭 | 支持 lz4 / zstd 压缩 WAL、TOAST |
--with-icu | 开关 | 关闭 | 使用 ICU 排序规则,替代部分 OS locale 依赖 |
--with-libxml | 开关 | 关闭 | 提供 xml 类型与 XML 函数 |
--with-perl / --with-python | 开关 | 关闭 | 提供 PL/Perl、PL/Python 过程语言 |
--with-pam / --with-ldap / --with-kerberos | 开关 | 关闭 | 提供对应认证方式 |
--with-systemd | 开关 | 关闭 | 编译 systemd 服务通知支持(sd_notify) |
--enable-thread-safety | 开关 | 18 中默认开启 | 客户端库线程安全;老版本需显式开启 |
--enable-nls | 开关 | 关闭 | 多语言错误消息,需 gettext |
--enable-depend | 开关 | 关闭 | 自动跟踪头文件依赖,增量编译更准 |
--enable-debug | 开关 | 关闭 | 带调试符号编译,排障用,生产勿开 |
--enable-cassert | 开关 | 关闭 | 开启断言检查,极慢,仅开发用 |
--with-extra-version="TEXT" | 字符串 | 空 | 附加版本串,SELECT version() 可区分自编译版本 |
关于 --enable-cassert
--enable-cassert 会插入大量运行时断言,性能可下降数倍。它只在测试新功能或排查内核级 bug 时有价值,任何生产与性能测试环境都必须关闭。
configure 结束前会打印一份摘要,务必逐行确认可选功能是否真的启用:
PostgreSQL configuration:
EXEC_BACKEND .................. no
LDFLAGS ....................... -Wl,-rpath,'/usr/local/pgsql-18/lib'
with ICU ...................... yes
with LZ4 ...................... yes
with OpenSSL .................. yes
with systemd .................. yes
with zlib ..................... yes
...四、编译与安装
# 1. 编译。并行度建议为 CPU 核数,内存小的机器适当调低
make -j"$(nproc)"
# 2. 回归测试(可选但强烈建议,能验证编译结果是否可用)
make check
# 3. 安装到 --prefix 指定目录
sudo make install
# 4. 可选:安装文档(man 手册与 HTML 文档)
sudo make install-docs编译产物分布如下(以 --prefix=/usr/local/pgsql-18 为例):
/usr/local/pgsql-18/
├── bin/ # postgres、initdb、pg_ctl、psql、pg_dump 等全部可执行文件
├── include/ # 服务端与客户端头文件
├── lib/ # libpq 及扩展 .so 动态库
├── share/ # 时区数据、扩展 SQL 脚本、示例配置
└── doc/ # 安装文档时才有五、编译 contrib 扩展
contrib 扩展不会随 make install 一起安装,需要单独进入 contrib 目录编译:
cd contrib
# 查看可编译的扩展列表
ls -d */
# 全量编译安装(简单,但可能引入用不到的扩展)
make -j"$(nproc)"
sudo make install
# 只编译指定扩展(更可控,推荐)
for ext in pg_stat_statements pgcrypto postgres_fdw hstore citext; do
make -C "$ext" -j"$(nproc)" && sudo make -C "$ext" install
doneMeson 构建(PostgreSQL 16+)
若偏好更现代的构建方式,可用 Meson 替代 configure + make:
# 需要 meson >= 0.54 与 ninja
meson setup build --prefix=/usr/local/pgsql-18 \
-Dssl=openssl -Dzlib=enabled -Dicu=enabled -Dlz4=enabled
ninja -C build
sudo ninja -C build install详细说明
可执行文件与 PATH
源码安装不会自动把二进制加入 PATH,也不会创建 postgres 用户与 systemd 服务。这些都要手动补上。
# 全局引入可执行文件与动态库(/etc/profile.d 下的脚本对所有登录用户生效)
sudo tee /etc/profile.d/pgsql18.sh >/dev/null <<'EOF'
export PGHOME=/usr/local/pgsql-18
export PATH=$PGHOME/bin:$PATH
export LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH
export MANPATH=$PGHOME/share/man:$MANPATH
EOF
# 让新配置立即在当前会话生效
source /etc/profile.d/pgsql18.sh
# 验证:应输出 /usr/local/pgsql-18/bin/psql
which psql
psql --versionpsql (PostgreSQL) 18.0 (MyCorp Build)创建 postgres 运行用户
PostgreSQL 服务不允许以 root 身份运行,必须使用普通用户。
# 创建专用系统用户与同名组,不创建家目录(数据目录另行指定)
sudo groupadd -r postgres
sudo useradd -r -g postgres -d /var/lib/pgsql -s /bin/bash postgres
# 数据目录规划:与程序目录分离,便于单独挂盘与备份
sudo mkdir -p /var/lib/pgsql/18/data /var/log/pgsql
sudo chown -R postgres:postgres /var/lib/pgsql /var/log/pgsql
sudo chmod 700 /var/lib/pgsql/18/data # 数据目录必须仅属主可读为 systemd 编译的额外支持
--with-systemd 会让 PostgreSQL 在启动就绪后通过 sd_notify 通知 systemd,使 systemctl start 能准确判断「服务已可用」而非「进程已启动」。若不需要,可省略该参数。
# 若希望使用 systemd 的 Type=notify,需确保编译时带 --with-systemd
/usr/local/pgsql-18/bin/postgres --version
# 检查二进制是否链接了 libsystemd
ldd /usr/local/pgsql-18/bin/postgres | grep -i systemd实战示例
下面是在 Ubuntu 24.04 上,从零编译一套带常用扩展的 PostgreSQL 18,并以 systemd 托管的完整流程。
# ---------- 步骤 1:安装依赖 ----------
sudo apt update
sudo apt install -y build-essential pkg-config libreadline-dev zlib1g-dev \
libssl-dev libicu-dev liblz4-dev libzstd-dev libxml2-dev
# ---------- 步骤 2:下载并校验源码 ----------
cd /usr/local/src
curl -LO https://ftp.postgresql.org/pub/source/v18.0/postgresql-18.0.tar.bz2
curl -LO https://ftp.postgresql.org/pub/source/v18.0/postgresql-18.0.tar.bz2.sha256
sha256sum -c postgresql-18.0.tar.bz2.sha256
tar -xjf postgresql-18.0.tar.bz2 && cd postgresql-18.0
# ---------- 步骤 3:配置 ----------
./configure --prefix=/usr/local/pgsql-18 \
--with-openssl --with-zlib --with-lz4 --with-zstd --with-icu \
--with-libxml --enable-nls --enable-depend --with-systemd
# ---------- 步骤 4:编译并安装 ----------
make -j"$(nproc)"
sudo make install
cd contrib && make -j"$(nproc)" && sudo make install && cd ..
# ---------- 步骤 5:创建用户与数据目录 ----------
sudo groupadd -r postgres || true
sudo useradd -r -g postgres -d /var/lib/pgsql -s /bin/bash postgres || true
sudo mkdir -p /var/lib/pgsql/18/data /var/log/pgsql
sudo chown -R postgres:postgres /var/lib/pgsql /var/log/pgsql
sudo chmod 700 /var/lib/pgsql/18/data
# ---------- 步骤 6:初始化数据库集群 ----------
sudo -u postgres /usr/local/pgsql-18/bin/initdb \
-D /var/lib/pgsql/18/data -E UTF8 --locale=C.UTF-8 -U postgres
# ---------- 步骤 7:启动并验证 ----------
sudo -u postgres /usr/local/pgsql-18/bin/pg_ctl \
-D /var/lib/pgsql/18/data \
-l /var/log/pgsql/pg18.log start
/usr/local/pgsql-18/bin/pg_isready -h 127.0.0.1 -p 5432
/usr/local/pgsql-18/bin/psql -U postgres -c "SELECT version();"127.0.0.1:5432 - accepting connections
version
-----------------------------------------------------------------------------------------------------------
PostgreSQL 18.0 (MyCorp Build) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0, 64-bit
(1 row)# /etc/systemd/system/postgresql-18.service
# 由源码编译安装时,官方不会提供 unit 文件,需要自行编写
[Unit]
Description=PostgreSQL 18 database server (source build)
Documentation=https://www.postgresql.org/docs/18/
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=postgres
Group=postgres
# 数据目录通过 -D 传给 postgres 进程
Environment=PGDATA=/var/lib/pgsql/18/data
ExecStart=/usr/local/pgsql-18/bin/postgres -D ${PGDATA}
ExecReload=/bin/kill -HUP $MAINPID
# 优雅停止:SIGINT 等价于 pg_ctl stop -m fast
KillMode=mixed
KillSignal=SIGINT
TimeoutSec=300
# 数据目录不存在时由 systemd 自动创建
RuntimeDirectory=postgresql
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target# 重新加载 unit、设为开机自启并启动
sudo systemctl daemon-reload
sudo systemctl enable --now postgresql-18
systemctl status postgresql-18 --no-pager升级与卸载
# 同一大版本内升级(例如 18.0 → 18.1):重新编译后 make install 即可
cd /usr/local/src/postgresql-18.1
./configure --prefix=/usr/local/pgsql-18 [原有参数...]
make -j"$(nproc)" && sudo make install
sudo systemctl restart postgresql-18
# 注意:小节升级不需要 pg_upgrade,数据目录兼容
# 卸载:源码安装没有卸载脚本,只能手工删除
sudo systemctl stop postgresql-18
sudo rm -rf /usr/local/pgsql-18 # 程序目录
sudo rm -f /etc/profile.d/pgsql18.sh # 环境变量
sudo rm -f /etc/systemd/system/postgresql-18.service
sudo systemctl daemon-reload
# 数据目录请自行确认后再删:sudo rm -rf /var/lib/pgsql注意事项
- 源码安装没有任何包管理器依赖记录,将来无法用
apt remove卸载,必须有清晰的安装清单文档 --prefix强烈建议带大版本号(pgsql-18),否则将来装 19 会直接覆盖 18 的二进制,造成不可逆混乱- 服务进程不能以 root 运行;用
sudo make install安装程序,但务必用sudo -u postgres运行initdb与postgres - 数据目录权限必须是
700且属主为运行用户,否则initdb与启动都会直接拒绝 - 编译缺库不会报错中断,只是静默关闭该功能;务必回看
configure摘要,否则可能上线后才发现没有 SSL make check需要能在非 root 用户下运行,且不能在 root 身份下跑;它消耗几分钟但能提前发现工具链问题- 大版本升级(18 → 19)不能直接沿用数据目录,必须使用
pg_upgrade或逻辑导出导入 - 修改
./configure参数后应执行make clean或直接解压全新源码树,避免旧对象文件混入导致怪异行为 - 生产环境不要开启
--enable-cassert,也不建议开启--enable-debug - 从 Git 仓库构建需要
bison、flex,且必须先运行./configure生成构建脚本 - 缺少
LD_LIBRARY_PATH或 rpath 配置时,libpq可能链接到系统里的旧版本,出现难以排查的版本错乱
最佳实践
- 优先选择包管理器安装;只有确实需要特定版本、自定义补丁或特殊裁剪时才走源码编译
- 把整套编译命令写成可执行的构建脚本并纳入版本控制,保证任意机器可复现同一份二进制
- 固定依赖库版本,并在
--with-extra-version中写入公司/环境标识,方便SELECT version()溯源 - 大规模集群建议「编译一次,打成 RPM/DEB 包」,再用包管理器分发,兼顾可控性与可维护性
- 程序目录与数据目录彻底分离:数据目录放在独立数据盘,便于扩容、快照与备份
- 使用
--with-icu而非依赖 OS locale,减少容器/主机环境差异导致的排序规则不一致 - 启用
--with-systemd并配置Type=notify,让 systemd 正确感知服务就绪状态 - 编译后立即执行
make check,并把configure摘要与构建日志归档保存 - 用
ldd检查关键二进制(postgres、psql)的动态库来源,确认没有误链系统旧版libpq - 升级策略固定为「同一大版本内重新编译覆盖,大版本变更走 pg_upgrade」,并提前演练
下一节
继续学习:初始化数据库集群(initdb)