27.8 code-server 和 clangd 开发环境
本节在 13.2-RELEASE 和 14.0-RELEASE 上已验证通过,其他版本请谨慎参考。
code-server 是 VS Code 的开源服务器版,可通过 Arch Linux 兼容层运行(因上游 FreeBSD 版存在问题)。
27.8.1 概述
code-server 是 Visual Studio Code 的开源服务器版本,可在远程服务器上运行并通过浏览器访问。
由于上游 FreeBSD 版 code-server 存在问题,通过 Linux 兼容层运行 code-server 是当前可行的方案。本节使用 Arch Linux bootstrap 镜像构建 Linux 兼容层环境。
27.8.2 Linux 兼容层路径映射机制
借助 FreeBSD 内核的路径劫持特性,虽然为了运行 code-server 使用了 Linux 兼容层,但 clangd 以及其他所有开发工具仍然完全由 FreeBSD 提供。
首先需要明确,Linux 二进制兼容模式并非 Linux 模拟器,也并非 Linux 虚拟机。运行 Linux 程序的主体仍然是 FreeBSD 内核本身。
由于主体仍是 FreeBSD 内核,这必然涉及 Linux 程序和 FreeBSD 程序的混合运行,而混合运行又会带来动态链接库调用的问题。对已编译的二进制程序,其所需的动态链接库路径是硬编码的。例如,若某个 Linux 二进制程序依赖 /lib/glibc.so,则它一定会在 /lib/glibc.so 查找这个文件,而非其他位置。但在 FreeBSD 下,Linux 的运行时环境位于 /compat/linux 目录下。
为了解决这个问题,FreeBSD 在内核层面劫持路径:一个 Linux 二进制程序尝试 open /lib/glibc.so 时,FreeBSD 内核会自动在路径前加上 /compat/linux,使其变为 /compat/linux/lib/glibc.so。这一过程对应用程序而言是透明的,应用程序自身并不知道它最终获得的是哪个文件,但从 FreeBSD 内核的视角来看,它实际访问的是 /compat/linux/lib/glibc.so。
如果某个文件不在 /compat/linux 目录下,而是在 FreeBSD 本地系统目录中,FreeBSD 内核会自动回退到原始路径再次尝试。如果仍然找不到文件,open 系统调用才会真正失败。
回到 code-server,它作为一款 Linux 程序,在尝试访问文件或目录时,默认会先在 /compat/linux 下查找。假设需要打开 /usr/src 目录以查看 FreeBSD 的源代码树,如果 /compat/linux/usr/src 存在,那么实际被打开的是 /compat/linux/usr/src,而非真正需要的 /usr/src。因此需要删除 /compat/linux/usr/src,确保 FreeBSD 内核能够回退到正确的 /usr/src。
同样的逻辑也适用于 clangd。由于 /compat/linux/bin/clangd 并不存在,code-server 试图启动 clangd 时,它最终会调用 FreeBSD 提供的 /usr/local/bin/clangd,其他开发工具也同理。
27.8.3 服务器启用 Linux 二进制兼容,并部署 archlinux-bootstrap 镜像
首先启用 Linux 兼容层服务并设置开机自启:
# service linux enable # 设置 Linux 兼容层服务开机自启
# service linux start # 启动 Linux 兼容层服务下载并解压 Arch Linux 的 bootstrap 镜像:
# fetch -o /tmp https://mirrors.bfsu.edu.cn/archlinux/iso/latest/archlinux-bootstrap-x86_64.tar.zst # 下载 Arch Linux bootstrap 镜像到 /tmp
# mkdir -p /compat/linux # 确保 Linux 兼容目录存在
# tar --use-compress-program=unzstd -xpvf /tmp/archlinux-bootstrap-x86_64.tar.zst -C /compat/linux --numeric-owner --strip-components=1 # 解压 Arch Linux bootstrap 镜像到 FreeBSD Linux 兼容目录
# rm /tmp/archlinux-bootstrap-x86_64.tar.zst # 删除下载的压缩包27.8.4 服务器配置 pacman 源,并添加 archlinuxcn 仓库
软件源文件结构:
/compat/
└── linux/
└── etc/
└── pacman.conf # Pacman 包管理器配置文件编辑 /compat/linux/etc/pacman.conf 文件,配置软件源:
[options]
Architecture = auto
ParallelDownloads = 5
[core]
Server = https://mirrors.cernet.edu.cn/archlinux/$repo/os/$arch
SigLevel = Required DatabaseOptional
[extra]
Server = https://mirrors.cernet.edu.cn/archlinux/$repo/os/$arch
SigLevel = Required DatabaseOptional
[archlinuxcn]
Server = https://mirrors.cernet.edu.cn/archlinuxcn/$arch
SigLevel = Required DatabaseOptional27.8.5 服务器初始化 Arch Linux 运行时环境
在 Linux 兼容环境中初始化 pacman 密钥环:
# chroot /compat/linux pacman-key --init # 在 Linux 兼容环境中初始化 pacman 密钥环
# chroot /compat/linux pacman-key --populate # 在 Linux 兼容环境中填充 pacman 默认密钥27.8.6 服务器更新 Arch Linux 运行时环境,并安装 code-server
DNS 解析相关文件结构:
/
├── etc
│ └── resolv.conf # DNS 解析配置文件
└── compat
└── linux
└── etc
└── resolv.conf # Linux 兼容层 DNS 配置文件复制 FreeBSD 的 DNS 配置到 Linux 兼容环境:
# cp /etc/resolv.conf /compat/linux/etc在 Linux 兼容环境中更新软件包并安装 code-server:
# chroot /compat/linux pacman -Syu --noconfirm # 在 Linux 兼容环境中更新所有软件包,无需确认
# chroot /compat/linux pacman -S --noconfirm archlinuxcn-keyring # 安装 archlinuxcn-keyring 软件包,无需确认
# chroot /compat/linux pacman -S --noconfirm code-server # 安装 code-server 软件包,无需确认27.8.7 服务器删除 Arch Linux 运行时环境中的无用目录
删除 Linux 兼容环境中可能干扰 FreeBSD 本地路径访问的目录:
# rm -Rf /compat/linux/home # 删除 Linux 兼容层中的 /home 目录及其内容
# rm -Rf /compat/linux/root # 删除 Linux 兼容层中的 /root 目录及其内容
# rm -Rf /compat/linux/usr/local # 删除 Linux 兼容层中的 /usr/local 目录及其内容
# rm -Rf /compat/linux/usr/src # 删除 Linux 兼容层中的 /usr/src 目录及其内容现有目录状态:
/compat/
└── linux/
├── home/ # 用户主目录(已删除)
├── root/ # root 用户主目录(已删除)
└── usr/
├── local/ # 本地软件目录(已删除)
└── src/ # 源代码目录(已删除)27.8.8 服务器安装 LLVM 与 clangd 插件
在 FreeBSD 上本地安装 LLVM 工具链,并配置 code-server:
# pkg install -y llvm # 安装 LLVM 工具链
# ln -sf /compat/linux/lib/code-server/bin/code-server /usr/local/bin # 创建 code-server 的软链接到 /usr/local/bin
# code-server --install-extension llvm-vs-code-extensions.vscode-clangd # 在 code-server 中安装 clangd 扩展目录结构:
/
├── compat
│ └── linux
│ └── lib
│ └── code-server
│ └── bin
│ └── code-server # code-server 可执行文件
├── usr
│ └── local
│ └── bin
│ └── code-server # code-server 软链接
└── root
└── .code-server.pid # code-server PID 文件27.8.9 服务器通过 daemon 命令启动 code-server
使用 daemon 工具后台启动 code-server,关闭认证并将 PID 写入指定文件:
# daemon -p /root/.code-server.pid -f code-server --auth=none注意
使用 root 权限操作时请注意风险,做好数据备份。
27.8.10 客户端通过 SSH 建立隧道并通过浏览器访问 code-server 服务器
在客户端建立 SSH 本地端口转发,将本地 8080 端口映射到远程服务器的 127.0.0.1:8080:
# ssh -L 8080:127.0.0.1:8080 -N root@server # -N 表示不执行远程命令,仅负责转发网络流量在浏览器中访问 http://127.0.0.1:8080
27.8.11 (示例)在浏览器中用 code-server 打开 FreeBSD 的源代码树
使用 code-server 打开 /usr/src 目录作为工作区:
# code-server /usr/src27.8.12 (示例)在浏览器中编译最小化内核并生成 compile_commands.json 文件
安装 Bear 工具并生成内核构建的编译命令数据库:
# pkg install bear # 安装 Bear 工具,用于生成 compile_commands.json
# bear --append -- make KERNCONF=MINIMAL buildkernel # 使用 Bear 生成内核构建的编译命令,并构建 MINIMAL 内核等待编译完成并生成 compile_commands.json 文件后,即可开始阅读内核关键部分的源代码。
27.8.13 自动化安装脚本
为快速搭建开发环境,以下是 code-server 安装步骤的自动化脚本:
警告
此脚本会破坏现有的任何 Linux 兼容层。应理解后再执行,并做好备份工作。
#!/bin/sh
set -e
ARCHLINUX_MIRROR="https://mirrors.cernet.edu.cn/archlinux"
ARCHLINUXCN_MIRROR="https://mirrors.cernet.edu.cn/archlinuxcn"
FREEBSD_PKG_MIRROR="https://mirrors.cernet.edu.cn/FreeBSD-pkg"
rm -Rf /compat/linux
rm -Rf /tmp/archlinux-bootstrap-x86_64.tar.zst
service linux enable
service linux start
fetch -o /tmp "$ARCHLINUX_MIRROR/iso/latest/archlinux-bootstrap-x86_64.tar.zst"
mkdir -p /compat/linux
tar --use-compress-program=unzstd -xpvf /tmp/archlinux-bootstrap-x86_64.tar.zst -C /compat/linux --numeric-owner --strip-components=1
cat >/compat/linux/etc/pacman.conf <<EOF
[options]
Architecture = auto
ParallelDownloads = 5
[core]
Server = $ARCHLINUX_MIRROR/$repo/os/$arch
SigLevel = Required DatabaseOptional
[extra]
Server = $ARCHLINUX_MIRROR/$repo/os/$arch
SigLevel = Required DatabaseOptional
[archlinuxcn]
Server = $ARCHLINUXCN_MIRROR/$arch
SigLevel = Required DatabaseOptional
EOF
chroot /compat/linux pacman-key --init
chroot /compat/linux pacman-key --populate
cp /etc/resolv.conf /compat/linux/etc
chroot /compat/linux pacman --sync --refresh --sysupgrade --noconfirm
chroot /compat/linux pacman --sync --needed --noconfirm archlinuxcn-keyring
chroot /compat/linux pacman --sync --needed --noconfirm code-server
ln -sf /compat/linux/lib/code-server/bin/code-server /usr/local/bin
rm -Rf /compat/linux/home
rm -Rf /compat/linux/root
rm -Rf /compat/linux/usr/local
rm -Rf /compat/linux/usr/src
pkg upgrade -y git bash vim htop tmux llvm bear
code-server --install-extension llvm-vs-code-extensions.vscode-clangd
code-server --install-extension mhutchie.git-graph
rm -Rf /tmp/archlinux-bootstrap-x86_64.tar.zst目录结构:
/
├── compat
│ └── linux
│ ├── etc
│ │ ├── pacman.conf # Arch Linux pacman 配置文件
│ │ └── resolv.conf # DNS 解析配置(从 FreeBSD 复制)
│ ├── lib
│ │ └── code-server
│ │ └── bin
│ │ └── code-server # code-server 可执行文件
│ └── usr
│ ├── local # (已删除)
│ └── src # (已删除)
├── usr
│ ├── local
│ │ └── bin
│ │ ├── code-server # code-server 软链接(指向 /compat/linux/lib/code-server/bin/code-server)
│ │ └── clangd # clangd 可执行文件
│ └── src # FreeBSD 源代码目录(用于 code-server 工作区)
└── root
└── .code-server.pid # code-server 进程 ID 文件建议用户自行测试验证。
27.8.14 补充说明
27.8.14.1 HTTPS 配置
本节未涉及如何在服务器上通过 HTTPS 提供 code-server 服务。如需配置 HTTPS,可参考 code-server 官方文档配置 SSL 证书。
27.8.14.2 Linux 兼容层与 Linux Jail
本节使用 Linux 二进制兼容层,而非 Linux Jail。两者的主要区别是:Linux 兼容层共享 FreeBSD 内核,而 Linux Jail 提供更隔离的运行环境。