
在刷算法题时,我一直渴望能有一个完美的记录模板:既能沉淀解题思路,又能直接在笔记里运行代码查看结果。起初考虑过自建网页,但时间成本太高。回过头研究 Obsidian 时,发现了 Execute Code 插件。
然而,噩梦由此开始。Execute Code 对 C++ 的支持核心依赖于 Cling(一个交互式 C++ 解释器)。我最初执着于在 Windows 原生环境下解决问题,尝试加参数绕过硬编码、写脚本包装,甚至参考过网上关于在主机上手动编译 Cling 的教程(环境配置指南 – Cling 安装配置教程(含安装 Jupyter Kernel),让电脑持续开机数夜试图啃下这块硬骨头。但结果显示,Windows 上的 Cling 因为路径硬编码和 LLVM 兼容性问题,根本无法稳定运行。即使退而求其次想用脚本伪装 g++ 填入插件路径,也因插件对 Cling 交互特性的依赖(如交互式 stdin 输入框)而宣告失败。(此处省略6个小时的碰壁内耗😒)
最终,我选择了一个“降维打击”的方案:直接在 WSL2 内部安装运行 Linux 版 Obsidian。
环境配置:WSL2 镜像网络与代理
由于 WSL 和主机的网络端口默认不互通,为了让网络请求(特别是 Git 同步)顺畅,必须开启镜像网络模式。这能让 WSL 和主机共用网络端口。
在 Windows 用户目录(C:\Users\你的用户名)下新建或修改 .wslconfig 文件:
[wsl2]
networkingMode=mirrored
接着,在 WSL 的 ~/.bashrc 中配置自动代理脚本。这样不仅网络端口相同,还能确保每次打开终端都能自动挂上主机的代理:
# 自动探测主机 7897 代理端口
if nc -z -w 1 127.0.0.1 7897 2>/dev/null; then
export http_proxy="http://127.0.0.1:7897"
export https_proxy="http://127.0.0.1:7897"
export all_proxy="socks5://127.0.0.1:7897"
fi
双端共存:跨系统的 Git 同步逻辑
我习惯用 Git 同步笔记。Windows 主机上的 Git 验证通常会调用图形化的凭据管理器(弹出浏览器登录);但 WSL 作为纯命令行环境,无法弹出图形界面,这会导致同步失败。
解决原理: Windows 保持“网页验证”,WSL 采用“Access Token”验证。我们将两端的配置都设为 Global(全局),并清空 Local(局部) 配置。
-
GitHub 端的准备: 在 Settings -> Developer settings -> Personal access tokens (classic) 中生成一个 Token。
-
WSL 端的全局配置:
git config --global credential.helper store
# 随后在第一次询问时,用户名填你的 GitHub 账号,密码处粘贴 Token 即可
- Windows 端的全局配置:
git config --global credential.helper manager
- 关键一步:清除局部干扰 因为 WSL 和主机共用同一个仓库文件夹,如果仓库内部残留了之前的局部配置,会覆盖全局设置。必须在仓库根目录下运行:
git config --local --unset credential.helper
打破字体的跨系统隔离
WSL 下的 Obsidian 默认无法识别 Windows 安装的字体。我们要把 Windows 的字体库“借”给 Linux。这里必须执行两条指令,因为 系统自带字体 和 用户自行安装的字体 存储位置完全不同,缺一不可:
# 1. 链接系统核心字体(如微软雅黑、等线等)
sudo ln -s /mnt/c/Windows/Fonts /usr/share/fonts/windows
# 2. 链接用户文件夹下的字体(Windows 11 默认把用户安装的字体放在 AppData 下,不链接这里就看不到霞鹜文楷)
sudo ln -s /mnt/c/Users/你的Windows用户名/AppData/Local/Microsoft/Windows/Fonts /usr/share/fonts/windows_user
# 刷新 Linux 字体缓存
fc-cache -fv
映射完成后,在 Obsidian 的字体设置里直接填入中文名(如 霞鹜文楷)通常即可识别。如果失效,可以用以下指令抓取它们的英文真名(PostScript Name):
fc-list :lang=zh | cut -d: -f2 | sort -u
软件部署:在 WSL 中安装 Obsidian
由于我们要使用 WSL 里的 Cling,所以 Obsidian 也必须跑在 WSL 环境里。建议从官网下载最新的 .deb 安装包:
# 进入你下载包的 Windows 目录
cd /mnt/c/Users/你的用户名/Downloads
# 安装 Obsidian(系统会自动处理依赖)
sudo apt install ./obsidian_1.12.7_amd64.deb -y
Cling 的调教与版本博弈
我通过 Conda 安装了 Cling。但 Cling 极其“娇气”,如果系统库太新,它会弹出如下完整的红色警告,极其影响心情:
Warning in cling::IncrementalParser::CheckABICompatibility(): Possible C++ standard library mismatch, compiled with __GLIBCXX__ '20240521' but running with '20250605'
这是因为 Cling 的官方版本(编译于 20240521)与当下(20250605)最新的 C++ 运行库不匹配。解决办法是强制安装与其编译时代相符的特定版本库,实现“精准迎合”:
conda install -c conda-forge cling libstdcxx-ng=13.2.0 libgcc-ng=13.2.0 -y
输入框死锁:Inject Code 的两种方案
在使用 Execute Code 插件时,有一个严重的逻辑缺陷:如果程序没有任何输出(因为警告被消除了),插件就不会唤醒输入框渲染。当代码运行到 cin >> x; 时,程序在等输入,插件在等输出,两边陷入死锁。
为了“刺激”插件弹出输入框,我们需要在 Execute Code 的 Inject C++ code 设置中注入一段代码。
方案一:全局构造函数法(利用结构体) 通过在 main 运行前执行一段代码来唤醒插件。为了防止多个代码块导致重复定义报错,必须加上宏定义锁(Header Guard):
#ifndef WAKE_UP_INJECT
#define WAKE_UP_INJECT
#include <iostream>
struct __WakeUp { __WakeUp() { std::cerr << " \b"; } } __wakeup;
#endif
方案二:宏定义劫持法(更轻量,推荐) 利用 C++ 的逗号表达式劫持输入流。这种方法不声明变量,不存在重定义冲突:
#include <iostream>
#include <cstdio>
// 劫持 cin 和 scanf,在执行前向标准错误流发送一个退格键
#define cin (std::cerr << " \b", std::cin)
#define scanf(...) (std::cerr << " \b", scanf(__VA_ARGS__))
总结
经过这一番折腾,我终于在 Obsidian 里实现了一个完美的算法研究台。通过 WSL 镜像网络解决了代理难题,通过双端 Global 配置解决了 Git 同步冲突,最后利用 Inject Code 巧妙地打破了插件的输入死锁。
当我做完这一切时我已经很累了,总共也花了快10个小时吧(连续不断的,以后再也不这样连续干同一个活了,太痛苦了),写完还要去上课,还有期中考试,生活呵。😒





