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 目前最后一个大版本更新,同时兼容我需要研究的插件,如果你想研究的插件或功能有特定版本需求,这一步需要明确你下载的源码版本。

alt text

1、克隆源码至 WSL 并使用 VSC Remote 打开项目

这一步可以根据需求选择克隆最新版本的 github 版本的源码,也可以考虑直接下载某个版本的源码。

1.1 github

如果你需要向社区提出贡献,那最好选择直接克隆指定版本,重度开发之后的分支冲突是不可接受的:

1
2
3
4
5
6
7
8
$ 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.patch

1.2 官网版本目录

我们选择 17.0 版本直接下载,将下载的压缩包放置于 WSL,如下图:

alt text

alt text

1.3 使用 VSC Remote 打开任意 WSL 文件夹作为项目根目录:

接着,直接使用命令行或使用 VSC 远程连接 WSL 再打开命令行。这里只写如何用 VSC 连接 WSL 并打开文件夹和命令行:

alt text

alt text

alt text

然后执行解压命令:

1
tar -xf postgresql-17.0.tar.gz

接着,打开一个新的 VSC 窗口,重复上面的连接步骤,将解压的 PG 文件夹直接打开。

2、编译

2.1 VSC 插件安装

推荐安装:

alt text
alt text

2.2 pg 编译依赖库安装

pg 需要安装下列库,可以在这里直接输入命令行安装;也可以按照 2.4 章节的 VSC -> tasks ,在准备编译时一键安装。

1
sudo apt install -y libsystemd-dev libxml2-dev libssl-dev libicu-dev zlib1g-dev libreadline-dev pkg-config

2.3 编写 VSC 的编译配置文件

VS Code 中的任务 Task 可以配置为运行脚本和启动进程,以便可以在 VS Code 中使用许多现有工具,而无需输入命令行或编写新代码。工作区或文件夹特定任务是从工作区的 .vscode 文件夹中的 tasks.json 文件配置的。

我们需要打开 PG 源码根目录作为 VSC 的项目目录,然后 ctrl + shift + p 打开 VSC 的 Command Palette,然后按下图创建 Task 模板:

alt text

alt text

alt text

然后修改 tasks.json 为:

下面提供了两个配置文件,推荐使用后者。后者可以一键完成环境配置等任务。

2.3.1 官方简单示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
// 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 比较完整的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
{
"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"
}

摘自 https://www.cnblogs.com/microestc/p/17079518.html

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、编写创建用户脚本:

1
2
3
4
5
6
7
8
9
#!/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."
fi

2、手动检查并创建(推荐、自定义密码):

1
2
3
id postgres
sudo useradd -m -s /bin/bash postgres
sudo passwd postgres

3、使用我的 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 配置,然后将下面内容覆盖进去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
// 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 ,选择运行任务:

alt text

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

alt text

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

1
tar -xf postgresql-17.0.tar.gz

如下图:

alt text
alt text

2.4.2 使用 postgres 用户编译并初始化 pg

这是我添加了注释和修改后的完整 tasks.json :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
{
"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 pgsql/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 任务后,应当能够看到:

alt text

然后我们可以在命令行中直接尝试启动:

1
2
3
su - postgres
cd postgresql-17.0
pg_ctl -D pgsql/data -l logfile start

如下图,启动成功:

alt text

检查进程状态:

1
ps aux | grep postgres

alt text

新建测试数据库并连接:

1
2
createdb test
psql test

alt text

到这里,我们就完成了 pg 的编译和初始化,可以配置 debug 环境了!

3、调试

我推荐使用 GDB 进行调试,原因是 WSL 上由 apt 安装的 GDB 和 LLDB 都有问题,我只找了 GDB 的解决方案。

3.1 新建并编辑 调试配置文件

ctrl + shift + p ,然后选择 Debug: Open launch.json ,选择 lldb/gdb 。因为 PG 并没有使用 cmake ,所以我们直接选择 lldb/gdb 调试器即可:

alt text

然后使用下面的调试配置文件,推荐使用 GDB ,亲测 WSL 上直接使用 apt 安装的 lldb 也不能完成调试:

LLDB

1
2
3
4
5
6
7
8
9
10
11
12
{
"version": "0.2.0",
"configurations": [
{
"name": "(CodeLLDB) Attach", // 需要使用 CodeLLDB 插件进行调试
"type": "lldb",
"request": "attach",
"program": "${workspaceFolder}/build/bin/postgres",
"pid": "${command:pickProcess}"
}
]
}

GDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"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 都不支持这种内存管理方式,如下图:

alt text

因此你需要额外下载安装 WSL 社区的修复版本 GDB:

1
2
3
4
5
6
7
8
9
cd /home/postgres
sudo apt remove gdb
sudo apt install libgmp-dev
wget https://ftp.gnu.org/gnu/gdb/gdb-13.1.tar.xz
tar -xf gdb-13.1.tar.xz
cd gdb-13.1/
./configure
make -j8
sudo make install

https://github.com/microsoft/WSL/issues/8516

调试

alt text

这些程序是我们编译得到的可执行程序,我们可以通过 attach 进程的方式进行调试。

在调试之前,可以考虑将刚刚编译得到的 bin 程序目录使用下面的指令添加到 Linux 的环境变量中,这样可以直接使用这种格式的指令 psql 代替 postgresql-17.0 目录中使用 pgsql/bin/psql 指令。我已经在 task 的 build_db 任务里一键完成了环境变量的添加,如果你成功完成了 build_db 任务,那么这一步可以忽略。

1
2
3
export PATH=$PATH:/home/postgres/postgresql-17.0/pgsql/bin
export PGHOST=127.0.0.1
export PGPORT=5432

创建新数据库的程序是 pgsql/bin/createdb ,具体指令为:

1
pgsql/bin/createdb test

这样就创建了一个名为 test 的数据库,接着我们使用 psql 连接到数据库:

1
2
pgsql/bin/psql test
select pg_backend_pid();

如下图,我们使用 psql 连接到数据库后,调用 pg 的 select pg_backend_pid(); 函数查询到当前连接的 pg 后端程序的进程号:

alt text

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

alt text

alt text

参考资料

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