PAYATHON 2026

如何让 VSCode + stack 在启动时加载 .ghcup/env?

技术老齐

让 KDE 启动器运行一个包装脚本,先加载 ~/.ghcup/env,再启动 VSCode。这样,新启动的 VSCode 及其子进程就能继承这套环境。

日志还提示 Haskell 扩展可能在自行选择工具链。如果希望它使用 GHCup 当前设置的默认工具,还需要检查扩展的 haskell.manageHLS 配置。

为什么从终端启动正常,从 KDE 启动却出错?

终端中的 Bash 已经加载了 .ghcup/env,从该终端启动的 VSCode 因而能继承相应的 PATH。KDE 启动器使用桌面会话的环境,两者可能不同。

VSCode 启动时也可能通过登录 Shell 获取环境,具体结果取决于 Shell 的初始化配置。用包装脚本明确加载环境,可以减少对这些配置的依赖。VSCode 命令行文档

在 VSCode 的集成终端中执行 source ~/.ghcup/env,只能改变该终端及其后续子进程的环境,无法更新已经运行的扩展宿主。因此,即使终端里显示的版本正确,HLS 也未必使用了同一套工具。

创建加载 GHCup 环境的启动脚本

先创建目录:

mkdir -p "$HOME/.local/bin" "$HOME/.local/share/applications"

创建 ~/.local/bin/code-ghcup,写入:

#!/bin/sh

if [ -r "$HOME/.ghcup/env" ]; then
    . "$HOME/.ghcup/env"
fi

exec /usr/bin/code "$@"

. 是 POSIX Shell 加载脚本的写法,source 则是 Bash 等 Shell 提供的命令。"$@" 用于完整传递文件名、目录名和启动参数。

示例假定 VSCode 的启动命令位于 /usr/bin/code。先在能正常启动 VSCode 的终端中检查:

command -v code

如果输出的路径不同,就替换脚本中的路径,再赋予脚本执行权限:

chmod +x "$HOME/.local/bin/code-ghcup"

让 KDE 启动器使用这个脚本

创建 ~/.local/share/applications/code-ghcup.desktop:

[Desktop Entry]
Type=Application
Name=Visual Studio Code (GHCup)
Exec=/home/mark/.local/bin/code-ghcup %F
Terminal=false
Categories=Development;IDE;

将 /home/mark 替换为自己的主目录。.desktop 文件的 Exec 字段不会按 Shell 语法展开 ~ 或 $HOME,因此需要使用绝对路径。%F 用于传入多个文件参数。Desktop Entry 规范

之后,从 KDE 应用菜单中的 Visual Studio Code (GHCup) 启动。也可以用 KDE 菜单编辑器,将现有 VSCode 菜单项的启动命令改为这个脚本。

首次验证前,先保存工作,完全退出所有 VSCode 实例,再从新菜单项启动。后续窗口可能沿用已有实例的环境,仅打开新窗口或重载窗口,无法验证启动环境是否已经改变。VSCode 实例环境说明

检查 Haskell 扩展是否覆盖了工具链选择

日志中出现了这个路径:

/home/mark/.ghcup/tmp/ghcup-ghc-9.10.3_cabal-3.14.2.0_hls-2.14.0.0_stack-3.7.1/...

这提示扩展可能通过 GHCup 组装了一套指定版本的工具链。仅凭这段日志还无法确定当前设置,需要检查 haskell.manageHLS。

如果希望扩展使用启动环境中的 HLS,在 VSCode 的用户 settings.json 中加入:

{
  "haskell.manageHLS": "PATH"
}

这种模式要求已安装 haskell-language-server-wrapper 或 haskell-language-server,并且能从 PATH 找到。还要检查用户设置和工作区设置中是否指定了 haskell.serverExecutablePath,显式配置的路径会优先决定启动哪个服务程序。Haskell 扩展配置说明

如果保留 "haskell.manageHLS": "GHCup",扩展仍可根据项目和 haskell.toolchain 选择版本,因此各工具的版本未必都跟随 ghcup set 的全局默认值。工具链配置说明

PATH 一致后,Stack 仍可能选择另一份 GHC

Stack 使用哪个 GHC,还取决于项目配置。加载 .ghcup/env 会影响命令查找路径,但不会自动覆盖 stack.yaml 中的 snapshot、resolver 或 compiler 要求。

如果希望 Stack 查找 PATH 中符合项目要求的 GHC,可以在项目的 stack.yaml 中加入:

system-ghc: true

前提是该 GHC 的版本符合项目要求。Stack 默认可以使用自己管理的 GHC,因此只检查普通的 ghc --numeric-version 还不够。Stack 的 GHC 选择规则

在项目目录中运行以下命令,比较版本和库目录:

command -v ghc
ghc --numeric-version
ghc --print-libdir

stack exec ghc -- --numeric-version
stack exec ghc -- --print-libdir

同时,在 VSCode 的“输出”面板中选择对应项目的 Haskell 日志,确认实际启动的 HLS 路径。

日志中的 GHC ABIs don't match! 表示 HLS 预期的 GHC 库 ABI 与项目实际使用的库不同。即使两边都报告 9.10.3,ABI 也未必一致。如果统一环境后仍然报错,需要继续核对 GHC 的安装来源,以及 HLS 是否与该 GHC 构建兼容。必要时,可按 GHCup 的 Stack 集成说明统一 GHC 的安装来源,或使用针对实际 GHC 构建的 HLS。

备注:内容仅供参考。