WSL配置PostgreSql开发环境
目标描述
本教程的目标是配置一套 PostgreSql 的本地开发调试环境。
本教程所需的前置环境和目标环境为:
操作系统:Windows + WSL Ubuntu 22.04
IDE:VS Code
即,我们将在 Windows + WSL Ubuntu 22.04 的环境中,使用 VS Code IDE 进行 PostgreSql 的调试开发。
我们推荐将 PostgreSql 安装至 WSL 中,在 Windows 中使用 VSC Remote 连接 WSL 进行开发调试。因为 WSL 的配置非常简单,且能够直接在 Windows 系统上使用 Linux ,而 Linux 的环境配置非常简单;在 Windows 上使用 VSC 方便快捷,能够地减少学习 Linux 的学习成本。
配置步骤
由于我们的目标不是为开源社区做贡献,而是为了解决我们的个性化问题,因此追求最新版本的 PG 可能会得不偿失(最新版本的软件往往可能会出现较大的变更,不利于初步学习。如果你有研究成果开源化的需求,可以考虑使用最新版本的 PG 源码)。
在这里我选用了 v17.0 的 PG 源码进行学习, v17.0 是 PG 目前最后一个大版本更新,同时兼容我需要研究的插件,如果你想研究的插件或功能有特定版本需求,这一步需要明确你下载的源码版本。

1、克隆源码至 WSL 并使用 VSC Remote 打开项目
这一步可以根据需求选择克隆最新版本的 github 版本的源码,也可以考虑直接下载某个版本的源码。
1.1 github
如果你需要向社区提出贡献,那最好选择直接克隆指定版本,重度开发之后的分支冲突是不可接受的:
$ git clone https://github.com/postgres/postgres.git$ cd postgres
## 一般更改代码都在特定的Branch上进行$ git checkout -b FEATTURE-NAME$ EDIT YOUR CODE$ git commit -a$ git diff --patience master my-feature > ../my-feature.patch1.2 官网版本目录
我们选择 17.0 版本直接下载,将下载的压缩包放置于 WSL,如下图:


1.3 使用 VSC Remote 打开任意 WSL 文件夹作为项目根目录:
接着,直接使用命令行或使用 VSC 远程连接 WSL 再打开命令行。这里只写如何用 VSC 连接 WSL 并打开文件夹和命令行:



然后执行解压命令:
tar -xf postgresql-17.0.tar.gz接着,打开一个新的 VSC 窗口,重复上面的连接步骤,将解压的 PG 文件夹直接打开。
2、编译
2.1 VSC 插件安装
推荐安装:


2.2 pg 编译依赖库安装
pg 需要安装下列库,可以在这里直接输入命令行安装;也可以按照 2.4 章节的 VSC -> tasks ,在准备编译时一键安装。
sudo apt install -y libsystemd-dev libxml2-dev libssl-dev libicu-dev zlib1g-dev libreadline-dev pkg-config2.3 编写 VSC 的编译配置文件
VS Code 中的任务 Task 可以配置为运行脚本和启动进程,以便可以在 VS Code 中使用许多现有工具,而无需输入命令行或编写新代码。工作区或文件夹特定任务是从工作区的 .vscode 文件夹中的 tasks.json 文件配置的。
我们需要打开 PG 源码根目录作为 VSC 的项目目录,然后 ctrl + shift + p 打开 VSC 的 Command Palette,然后按下图创建 Task 模板:



然后修改 tasks.json 为:
下面提供了两个配置文件,推荐使用后者。后者可以一键完成环境配置等任务。
2.3.1 官方简单示例
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "presentation" : { "reveal": "always" }, "tasks": [ { "label": "Configure", "type": "shell", "command": "./configure --enable-depend --enable-cassert --enable-debug", "problemMatcher": [ "$eslint-compact" ] }, { "label": "Make All", "type": "shell", "command": "make -j10 all", "problemMatcher": [ "$eslint-compact" ] }, { "label": "Make Clean All", "type": "shell", "command": "make clean", "problemMatcher": [ "$eslint-compact" ] }, { "label": "Make Install", "type": "shell", "command": "make install" } ]}这个 JSON 摘取于 http://www.postgres.cn/v2/news/viewone/1/459 ,提供了四个任务的配置:
1、Configure 是编译前的配置文件生成2、Make All 是编译全部代码3、Make Clean All 是清空所以编译结果4、Make Install 是编译并安装 PG对于我们开发人员来说,一般只需要使用前三个 Task ,使用的步骤是:
1、在第一次 Make All 之前,执行一次 Configure 任务,之后无需执行 Configure 。2、每次有代码变更后,执行 Make All 。如果遇到了不可解决的编译错误,尝试 Make Clean All 后重新 Make All。执行任务的方法是:
打开 Command Palette ,选择 Tasks: Run Task,最后选择对应的 Configure、Make 或者 make install 命令来进行 PostgreSQL 的编译等任务。
2.3.2 比较完整的配置
{ "tasks": [ { "type": "shell", "label": "install_depends", "command": "sudo apt install -y libsystemd-dev libxml2-dev libssl-dev libicu-dev zlib1g-dev libreadline-dev pkg-config", "options": { "cwd": "${workspaceFolder}" }, "detail": "Task install depends." }, { "type": "shell", "label": "build_env", "command": "mkdir build && mkdir -p pgsql/data", "options": { "cwd": "${workspaceFolder}" }, "detail": "Task add folders." }, { "type": "shell", "label": "build_config", "command": "../configure", "args": [ "--prefix=${workspaceFolder}/pgsql", "--with-icu", "--with-openssl", "--with-systemd", "--with-libxml", "--enable-debug" ], "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task Build MakeFile." }, { "type": "shell", "label": "make", "command": "make", "args": [ "-j12" ], "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task build." }, { "type": "shell", "label": "make_install", "command": "make", "args": [ "install" ], "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task install database." }, { "type": "shell", "label": "init_db", "command": "pgsql/bin/initdb", "args": [ "-D", "pgsql/data" ], "options": { "cwd": "${workspaceFolder}" }, "detail": "Task init default database." }, { "type": "shell", "label": "clean_db", "command": "make uninstall && make clean && rm -rf ../pgsql && rm -rf ../build", "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task clean database." }, { "type": "shell", "label": "build_db_conf", "dependsOn": [ "build_env", "build_config" ], "dependsOrder": "sequence", "detail": "Task add folders." }, { "type": "shell", "label": "build_db", "dependsOn": [ "make", "make_install", "init_db" ], "dependsOrder": "sequence", "detail": "Task add folders." }, { "type": "shell", "label": "rebuild_db", "dependsOn": [ "make", "make_install" ], "dependsOrder": "sequence", "detail": "Task add folders." }, ], "version": "2.0.0"}2.4 编译
我们在这里使用第二份 tasks.json 直接进行一系列的编译,经过实测后,该脚本还存在一些小问题。
1、我选用的 pg 版本还需要 bison flex 两个库。因此我修改了上述的 tasks.json 文件,添加了一些注释,并在安装依赖任务中添加了两个库的安装。
2、init_db 任务在系统第一次安装 pg 时还存在一些用户权限问题,pg 不推荐 root 用户进行初始化数据库,所以我选择了新建一个专门的 postgres 用户进行初始化 pg ,编写了对应的 task。并修改 init_db 这个 task 进行了适配。
2.4.1 新建 postgres 专用用户,将 PG 源码目录移动到该用户目录下
创建用户我提供了三种方法,选取其一就可以。我推荐第2个,直接在命令行中执行即可,比较简单。
1、编写创建用户脚本:
#!/bin/bash
# 检查是否存在 postgres 用户,如果不存在则创建它if ! id postgres &>/dev/null; then sudo useradd -m -s /bin/bash postgres echo "Postgres user created."else echo "Postgres user already exists."fi2、手动检查并创建(推荐、自定义密码):
id postgressudo useradd -m -s /bin/bash postgressudo passwd postgres3、使用我的 VSC task 直接创建:
2.4.2 章节的任务配置,让我们可以直接在 VSC 中以任务的形式创建 postgres 用户,按照直接执行 setup_postgres_user 任务即可。在 VSC 中执行 tasks.json 中编写的 task 的方法如下:
我们打开任意一个 WSL 目录作为 VSC 的项目根目录,按照 2.3 的教学创建 tasks.json 文件。然后在 VSC 中,按 ctrl + shift + p 打开 Command Palette ,创新新的 tasks 配置,然后将下面内容覆盖进去:
{ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "label": "setup_postgres_user", // 为 PG 新建一个用户,名为 postgres "type": "shell", "command": "sudo", "args": [ "bash", "-c", "if ! id postgres &>/dev/null; then sudo useradd -m -s /bin/bash postgres; fi" ], "detail": "Create the postgres user and set up the necessary directories" }, ]}接着 ctrl + shift + p 打开 Command Palette ,选择运行任务:

然后直接选择我们刚刚配置好的任务运行即可:

上述三个方法选一即可,建立完用户后,我们可以看到 home 目录下多出了一个 postgres 目录。这是 postgres 用户的个人目录。创建完了用户,记得把我们的 PG 压缩包移动到用户目录,然后解压!
tar -xf postgresql-17.0.tar.gz如下图:


2.4.2 使用 postgres 用户编译并初始化 pg
这是我添加了注释和修改后的完整 tasks.json :
{ "tasks": [ { "type": "shell", "label": "install_depends", // 1、apt 安装编译所需依赖 "command": "apt-get update && sudo apt install -y gcc libsystemd-dev libxml2-dev libssl-dev libicu-dev zlib1g-dev libreadline-dev pkg-config bison flex gdb lldb python3 python2 python3-lldb-14", // 新增了gcc bison flex gdb lldb python 依赖 "options": { "cwd": "${workspaceFolder}" }, "detail": "Task install depends." }, { "type": "shell", "label": "build_env", // 建立build和数据库数据存放目录 "command": "sudo", "args": [ "bash", "-c", "mkdir -p ${workspaceFolder}/build && mkdir -p ${workspaceFolder}/build/data && chown -R postgres:postgres /home/postgres" ], "options": { "cwd": "${workspaceFolder}" }, "detail": "Task add folders." }, { "type": "shell", "label": "build_config", // 生成构建配置,以 debug 模式构建 "command": "../configure", "args": [ "--prefix=${workspaceFolder}/build", "--with-icu", "--with-openssl", "--with-systemd", "--with-libxml", "--enable-debug", "--enable-cassert", "--enable-depend", "CFLAGS= -ggdb -O0 -g3 -Wall -fno-omit-frame-pointer" // 新增 g3 参数,支持调试器 ], "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task Build MakeFile." }, { "type": "shell", "label": "make", "command": "make", "args": [ "-j12" // 使用12核构建、主机性能不足时会造成卡顿 ], "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task build." }, { "type": "shell", "label": "make_install", // 安装数据库, make install "command": "make", "args": [ "install" ], "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task install database." }, // { // "label": "setup_postgres_user", // 为 PG 新建一个用户,名为 postgres,赋予该用户 数据目录 的权限 // "type": "shell", // "command": "sudo", // "args": [ // "bash", "-c", // "if ! id postgres &>/dev/null; then sudo useradd -m -s /bin/bash postgres && sudo chown -R postgres:postgres build/pgsql/data && sudo chmod -R 700 build/pgsql/data; else sudo chown -R postgres:postgres build/pgsql/data && sudo chmod -R 777 build/pgsql/data; fi" // ], // "detail": "Create the postgres user and set up the necessary directories" // }, { "label": "init_db", // 初始化 PG db 到当前目录的 pgsql/data 文件夹下 "type": "shell", "command": "sudo", "args": [ "-u", "postgres", // 指定以 postgres 用户执行,如果你已经有其它用户,可以直接将 postgres 替换为你的用户,以避免权限问题。如果修改了,还需要同步修改 setup_postgres_user 任务中的 postgres "build/bin/initdb", "-D", "build/data" ], // "dependsOn": "setup_postgres_user", "options": { "cwd": "${workspaceFolder}" }, "detail": "Initialize PostgreSQL database with initdb" }, { "type": "shell", "label": "clean_db", // 5、卸载现在安装的本数据库,然后删除所有相关文件 "command": "make uninstall && make clean && rm -rf ../pgsql && rm -rf ../build", "options": { "cwd": "${workspaceFolder}/build" }, "detail": "Task clean database." }, { "type": "shell", "label": "build_db_conf", // 2、构建DB配置,包含了 build_env 和 build_config 两个子任务 "dependsOn": [ "build_env", "build_config" ], "dependsOrder": "sequence", "detail": "Task add folders." }, { "type": "shell", "label": "build_db", // 3、构建数据库,包含了 编译、安装、初始化、配置监听端口、配饰系统环境变量、启动数据库主程序 子任务 "dependsOn": [ "make", "make_install", "init_db", "config_listen_port", "add_env_to_postgres", "start_or_restart_pg" ], "dependsOrder": "sequence", "detail": "Main task, build and start pg main program." }, { "type": "shell", "label": "rebuild_db", // 4、重新构建数据库并重启 "dependsOn": [ "make", "make_install", "start_or_restart_pg" ], "dependsOrder": "sequence", "detail": "Task add folders." },
{ "label": "switch_to_postgres", "type": "shell", "command": "sudo -u postgres bash -c 'echo Switched to postgres user.'", "problemMatcher": [] }, { "type": "shell", "label": "config_listen_port", // 配置数据库监听端口为5432,配置并重启后生效,可以直接使用 psql 作为客户端程序连接数据库 "command": "echo -e '\n# start listening ,config by dingning\nlisten_addresses = 'localhost'\nport = 5432' | sudo tee -a postgresql.conf", "options": { "cwd": "${workspaceFolder}/build/data" }, "detail": "Task config pg's listening port in data/postgresql.conf." }, { "type": "shell", // export postgres 用户的环境变量,使其可以直接使用 psql 而不是 /pgsql/bin.psql 连接数据库 "label": "export_sys_env", "command": "sudo -u postgres sh -c 'export PATH=${workspaceFolder}/build/bin && export PGHOST=127.0.0.1 && export PGPORT=5432 && export LD_LIBRARY_PATH=${workspaceFolder}/build/lib'", "options": { "cwd": "${workspaceFolder}/build/data" }, "detail": "Task config pg's system environment variable." }, { "type": "shell", "label": "add_env_to_postgres", // 添加环境变量到 postgres 用户的启动脚本 "command": "sudo -u postgres bash -c \"echo -e '\\n# PostgreSQL environment variables\\nexport PATH=${workspaceFolder}/build/bin\\nexport PGHOST=127.0.0.1\\nexport PGPORT=5432\\nexport LD_LIBRARY_PATH=${workspaceFolder}/build/lib\\nexport PGHOME=${workspaceFolder}/build\\nexport PGDATA=${workspaceFolder}/build/data' >> ~/.bashrc && source ~/.bashrc\"", "options": { "cwd": "${workspaceFolder}" }, "detail": "Add PostgreSQL environment variables to the postgres user's .bashrc file." }, { "type": "shell", "label": "start_or_restart_pg", // 启动 pg,日志文件写入 ${workspaceFolder}/pgsql/data/postmaster.log, 如果已经启动则重启 "command": "sudo -u postgres sh -c 'build/bin/pg_ctl -D build/data -l ${workspaceFolder}/build/data/postmaster.log status > /dev/null 2>&1 && build/bin/pg_ctl -D build/data -l ${workspaceFolder}/build/data/postmaster.log restart || build/bin/pg_ctl -D build/data -l ${workspaceFolder}/build/data/postmaster.log start'", "options": { "cwd": "${workspaceFolder}" }, "detail": "Start pg, if pg has been started, restart it." } ], "version": "2.0.0"}你只需要按照 1.3 的步骤打开我们刚刚在 postgres 用户下解压的 PG 源码文件夹作为根目录,然后按照 2.3 的教学创建 tasks.json 文件,最后使用上面的这个 tasks.json 覆盖默认的 tasks.json 模板,即可使用这份 tasks.json。
安装依赖、编译安装、初始化 PG 的流程为下面三个任务,依次执行即可:
install_depends # 一次性任务,第一次安装时执行一次即可build_db_conf # 生成 pg 构建配置文件,主要设置 编译要求 debug ,无代码优化,安装目录。build_db # 编译构建 pg ,初始化 pg 到数据目录 build/data ,注册可执行文件的路径到用户的环境变量中值得说一下的是,我写的这份 tasks.json 基本全覆盖了从依赖安装到编译、启动、重启、卸载的全流程任务。
build_db 任务将初始化 pg 到 build/data 目录,并将相关的依赖变量添加到用户 postgres 的环境变量中
执行完 build_db 任务,你就可以通过 createdb test 创建 test 数据库,通过 psql test 直接连接到 test 数据库 了
如需重新安装,只需要执行 clean_db 任务然后重新执行 build_db_conf 和 build_db 即可。
2.4.3 验证是否完成安装
执行完我们上述的 build_db 任务后,应当能够看到:

然后我们可以在命令行中直接尝试启动:
su - postgrescd postgresql-17.0pg_ctl -D pgsql/data -l logfile start如下图,启动成功:

检查进程状态:
ps aux | grep postgres
新建测试数据库并连接:
createdb testpsql test
到这里,我们就完成了 pg 的编译和初始化,可以配置 debug 环境了!
3、调试
我推荐使用 GDB 进行调试,原因是 WSL 上由 apt 安装的 GDB 和 LLDB 都有问题,我只找了 GDB 的解决方案。
3.1 新建并编辑 调试配置文件
ctrl + shift + p ,然后选择 Debug: Open launch.json ,选择 lldb/gdb 。因为 PG 并没有使用 cmake ,所以我们直接选择 lldb/gdb 调试器即可:

然后使用下面的调试配置文件,推荐使用 GDB ,亲测 WSL 上直接使用 apt 安装的 lldb 也不能完成调试:
LLDB
{ "version": "0.2.0", "configurations": [ { "name": "(CodeLLDB) Attach", // 需要使用 CodeLLDB 插件进行调试 "type": "lldb", "request": "attach", "program": "${workspaceFolder}/build/bin/postgres", "pid": "${command:pickProcess}" } ]}GDB
{ "version": "0.2.0", "configurations": [ { "name": "(gdb) 附加 pg", // 需要使用 ms-vscode.cpptools 插件进行调试 "type": "cppdbg", "request": "attach", "program": "${workspaceFolder}/build/bin/postgres", "processId": "${command:pickProcess}", "MIMode": "gdb", "preLaunchTask": "switch_to_postgres", "setupCommands": [ { "description": "为 gdb 启用整齐打印", "text": "-enable-pretty-printing", "ignoreFailures": true }, { "description": "将反汇编风格设置为 Intel", "text": "-gdb-set disassembly-flavor intel", "ignoreFailures": true } ] } ]}3.2 安装调试器
gdb
从 apt 官方下载的 gdb 无法直接适配 WSL ,原因是 gdb 在读取程序内存区时使用了 /proc/PID/mem 文件,但 WSL1 和 WSL2 都不支持这种内存管理方式,如下图:

因此你需要额外下载安装 WSL 社区的修复版本 GDB:
cd /home/postgressudo apt remove gdbsudo apt install libgmp-devwget https://ftp.gnu.org/gnu/gdb/gdb-13.1.tar.xztar -xf gdb-13.1.tar.xzcd gdb-13.1/./configuremake -j8sudo make install调试

这些程序是我们编译得到的可执行程序,我们可以通过 attach 进程的方式进行调试。
在调试之前,可以考虑将刚刚编译得到的 bin 程序目录使用下面的指令添加到 Linux 的环境变量中,这样可以直接使用这种格式的指令 psql 代替 postgresql-17.0 目录中使用 pgsql/bin/psql 指令。我已经在 task 的 build_db 任务里一键完成了环境变量的添加,如果你成功完成了 build_db 任务,那么这一步可以忽略。
export PATH=$PATH:/home/postgres/postgresql-17.0/pgsql/binexport PGHOST=127.0.0.1export PGPORT=5432创建新数据库的程序是 pgsql/bin/createdb ,具体指令为:
pgsql/bin/createdb test这样就创建了一个名为 test 的数据库,接着我们使用 psql 连接到数据库:
pgsql/bin/psql testselect pg_backend_pid();如下图,我们使用 psql 连接到数据库后,调用 pg 的 select pg_backend_pid(); 函数查询到当前连接的 pg 后端程序的进程号:

然后我们可以通过 attach 进程的方法进行调试:


参考资料
https://wiki.postgresql.org/wiki/So,_you_want_to_be_a_developer%3F http://www.postgres.cn/v2/news/viewone/1/459 https://blog.frognew.com/2023/11/install-postgresql-16-from-source-code.html https://github.com/microsoft/WSL/issues/8516
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!