第 22.12 节 安装 code-server 和 clangd
警告
本教程目前在 13.2-RELEASE 和 14.0-RELEASE 上测试正常,其他版本请慎重参考。
常见问题
为什么要有这篇教程?
- 有了 code-server 就意味着不用安装桌面环境即可获得运行在原生 FreeBSD 环境上的集成开发环境
- 利用熟悉的 vscode 界面和强大的 clangd 支援 FreeBSD 内核的开发
- 这样可以大大降低投入 FreeBSD 代码贡献以及二次开发所需的学习成本
为什么要用 Arch Linux 兼容层?
- 因为现在 FreeBSD 版的 code-server 被上游搞坏了几乎没法用
- 纵观历史版本也只有一个 revision 是好的
- 所以用 Linux 兼容层来运行是目前最节省时间节省生命的方案
- 并且 code-server 自从基于 node18 以后就对 glibc 的最低版本做出了更高的要求
- 源里那个 CentOS 运行时就运行不起它来了
兼容层?那还能用来搞 FreeBSD 的开发吗?
- 当然可以
- 虽然为了运行 code-server 我们用到了 Linux 兼容层
- 但是 clangd 还有任何其他开发工具将全部由 FreeBSD 提供
为什么 clangd 还有任何其他开发工具将全部由 FreeBSD 提供?
- 如你所见,出于综合因素考量现在 code-server 运行在 FreeBSD 的 Linux 二进制兼容模式下
- 但首先我们清楚,这是 Linux 二进制兼容模式,不是 Linux 模拟器模式,更不是 Linux 虚拟机模式
- 既然是 Linux 二进制兼容,那么尝试去运行 Linux 程序的主体一定还是 FreeBSD 内核本身,并没有额外多出来一个 Linux 内核
- 既然主体还是 FreeBSD 内核,那么一定会涉及到 Linux 程序和 FreeBSD 程序混合运行的问题
- 既然涉及到 Linux 程序和 FreeBSD 程序混合运行的问题,那么一定也会涉及调用 Linux 还是 FreeBSD 的动态链接库的问题
- 对于一个已经编译好的二进制程序来说,它要用到什么动态链接库是写死了的
- 假设一个 Linux 二进制程序依赖
/lib/glibc.so
,那么它一定会到/lib/glibc.so
去寻找这个文件,绝对不会看向其他地方 - 但是我们都知道在 FreeBSD 上 Linux 的运行时环境在
/compat/linux
下面 - 这时候要么给 Linux 二进制程序打补丁,把依赖
/lib/glibc.so
改成依赖/compat/linux/lib/glibc.so
- 想想也都知道,要给每个 Linux 二进制程序打补丁,这样做难度有多大,而且总归会有漏网之鱼吧?
- 那就试试第二个方法:在 FreeBSD 内核层面实现对路径的劫持
- 当一个 Linux 二进制程序尝试去
open
某个文件,假使说就是这个程序尝试去调用/lib/glibc.so
这个动态链接库的时候 - FreeBSD 内核首先会给
/lib/glibc.so
这个路径前面加上/compat/linux
变成/compat/linux/lib/glibc.so
- 这个过程对应用程序而言是透明的,即应用程序自己也不知道它拿到的到底是
/compat/linux/lib/glibc.so
还是/lib/glibc.so
- 用户还有 FreeBSD 内核站在上帝视角,可以知道它实际上拿到的是
/compat/linux/lib/glibc.so
- 但如果尝试去
open
的不是/compat/linux
下面有的文件,而是/compat/linux
外面的某个文件呢? - 这个时候内核会自动 fallback 到程序传入的原始路径,尝试再
open
一次,并祈祷这次能open
成功 - 如果这次还是失败,那就真的没有这个文件,
open
系统调用就失败了 - 我们回到 code-server 这里
- 已知 code-server 是一个 Linux 程序,当我们尝试打开一个文件或者目录,它一定是先去
/compat/linux
下面去找 - 假设你要打开
/usr/src
这个目录,一般来说你是想要看 FreeBSD 的源码树,对吧? - 可如果
/compat/linux/usr/src
这个目录存在,那么被打开的实际上就会是/compat/linux/usr/src
而不是你想要的/usr/src
- 这时候我们就需要把
/compat/linux/usr/src
这个目录删除掉,确保内核帮你 fallback 到真正的/usr/src
上面去 - 我们回到 clangd 这里
- 已知
/compat/linux/bin/clangd
是不存在的 - 那么当 code-server 尝试启动 clangd 的时候,一定会默认启动
/usr/local/bin/clangd
这个 clangd - 其他开发工具同理
- 这就是为什么 clangd 还有任何其他开发工具将全部由 FreeBSD 提供
还有什么需要补充的内容?
- 如何在服务器上通过 HTTPS 来提供 code-server 服务
- 探讨 Linux 兼容层与 Linux Jail 究竟有何区别
有什么需要注意的?
- 所有操作都使用 root 用户进行
- 请勿跳步
你这是在鼓励用户当 root 敢死队?
- 。。。
服务器启用 Linux 二进制兼容,并部署 archlinux-bootstrap 镜像
service linux enable
service linux start
fetch -o /tmp https://mirrors.cernet.edu.cn/archlinux/iso/latest/archlinux-bootstrap-x86_64.tar.gz
tar -C /tmp -xpf /tmp/archlinux-bootstrap-x86_64.tar.gz || true
cp -Rf /tmp/root.x86_64/* /compat/linux
服务器配置 pacman 源,并添加 archlinuxcn 仓库
cat >/compat/linux/etc/pacman.conf <<EOF
[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 DatabaseOptional
EOF
服务器初始化 Arch Linux 运行时环境
chroot /compat/linux pacman-key --init
chroot /compat/linux pacman-key --populate
服务器更新 Arch Linux 运行时环境,并安装 code-server
cp /etc/resolv.conf /compat/linux/etc
chroot /compat/linux pacman -Syu --noconfirm
chroot /compat/linux pacman -S --noconfirm archlinuxcn-keyring
chroot /compat/linux pacman -S --noconfirm code-server
服务器删除 Arch Linux 运行时环境中的无用目录
rm -Rf /compat/linux/home
rm -Rf /compat/linux/root
rm -Rf /compat/linux/usr/local
rm -Rf /compat/linux/usr/src
服务器安装 llvm 与 clangd 插件
pkg install -y llvm
ln -sf /compat/linux/lib/code-server/bin/code-server /usr/local/bin
code-server --install-extension llvm-vs-code-extensions.vscode-clangd
服务器通过 daemon 命令启动 code-server
daemon -p /root/.code-server.pid -f code-server --auth=none
客户端通过 SSH 建立隧道并通过浏览器连接到 code-server 服务器
ssh -L 8080:127.0.0.1:8080 -N root@server
在浏览器中访问 http://127.0.0.1:8080
(示例)浏览器中用 code-server 打开 FreeBSD 的源码树
code-server /usr/src
(示例)浏览器中编译最小化内核并生成 compile_commands.json
文件
pkg install -y bear
bear --append -- make KERNCONF=MINIMAL buildkernel
等待编译完成并生成 compile_commands.json
文件,然后你就可以开始阅读内核关键部分的源码了。
自动化安装脚本
为了便于读者快速获得开发环境,我们将安装 code-server 的步骤整理成一个脚本:
#!/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"
umount -Af
rm -Rf /compat/linux
rm -Rf /tmp/archlinux-bootstrap-x86_64.tar.gz
rm -Rf /tmp/root.x86_64
service linux enable
service linux start
fetch -o /tmp "$ARCHLINUX_MIRROR/iso/latest/archlinux-bootstrap-x86_64.tar.gz"
tar -C /tmp -xpf /tmp/archlinux-bootstrap-x86_64.tar.gz || true
cp -Rf /tmp/root.x86_64/* /compat/linux
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.gz
rm -Rf /tmp/root.x86_64
欢迎测试与反馈。