关于Stack-1.6.5中GHC选项多种设置方式协同机制的技术问询
Stack 1.6.5中GHC选项配置的协同逻辑、适用场景与生效时机详解
我在Stack的各个版本(包括1.6.5)上折腾过不少GHC选项配置,刚好能帮你理清这些规则。下面就把不同配置方式的协同逻辑、适用场景和生效时机拆解清楚:
一、核心优先级规则
Stack的GHC选项配置是分层生效的,优先级从高到低依次是:
项目单个包配置 > 项目全局(stack.yaml)配置 > 用户全局配置 > 系统全局配置
简单说:越贴近具体代码的配置,越能覆盖宽泛的全局配置。
二、各配置方式的适用场景与生效时机
1. 系统全局配置(/etc/stack/config.yaml)
- 适用场景:给服务器上所有用户的Stack项目统一设置基础规则,比如强制所有项目开启
-Wall警告,或者默认启用-O2优化。适合运维人员统一管控环境。 - 生效时机:Stack启动时自动加载,作用于所有未在更高优先级配置中覆盖对应选项的项目。
- 示例配置:
ghc-options: "$everything": -Wall -O2
2. 用户全局配置(~/.stack/config.yaml)
- 适用场景:针对你个人的所有Stack项目设置个性化选项,比如你习惯关闭
-Wmissing-home-modules警告,或者默认开启调试符号-g。 - 生效时机:Stack启动时加载,优先级高于系统全局配置,会直接覆盖系统全局中相同的选项。
- 示例配置:
ghc-options: "$everything": -Wno-missing-home-modules
3. 项目级配置(stack.yaml 或 package.yaml)
这是日常开发中最常用的配置层级,又分两种细分场景:
单个包专属配置(package.yaml)
- 适用场景:给项目中某个特定的包(比如库或可执行文件)设置专属选项。比如某个工具包需要关闭
-Wunused-do-bind警告,或者某个服务可执行文件需要强制开启调试符号。 - 生效时机:只有当构建这个特定包时才会生效,优先级最高,会覆盖所有更宽泛的配置。
- 示例配置(在某个包的
package.yaml中):
ghc-options: -g -Wno-unused-do-bind
项目组包配置(stack.yaml)
这里要用到Stack提供的特殊变量,用来批量作用于不同范围的包:
$locals:指代当前项目中所有本地包(即stack.yaml的packages字段列出的包)- 适用场景:给当前项目的所有本地代码统一设置规则,比如全局开启警告、统一优化级别。
- 生效时机:构建任何本地包时生效,优先级高于全局配置。
$targets:指代你通过stack build命令指定的目标包(如果没指定目标,就等同于$locals)- 适用场景:临时给某次构建的特定目标设置选项,比如调试时只给某个可执行文件加
-g,不影响其他包。
- 适用场景:临时给某次构建的特定目标设置选项,比如调试时只给某个可执行文件加
$everything:指代所有包,包括你依赖的第三方Hackage包- 适用场景:极端情况需要给所有依赖包设置选项时用(比如某个依赖有编译警告需要临时关闭),但要谨慎使用,可能破坏依赖的正常编译。
- 示例配置(
stack.yaml中):
ghc-options: "$locals": -Wall -O1 "$targets": -g "text": -Wno-deprecations # 给第三方text包关闭废弃警告
三、多配置的协同覆盖逻辑
当多个层级都设置了GHC选项时,遵循两个核心规则:
- 具体覆盖宽泛:比如针对单个包的
package.yaml配置会覆盖stack.yaml中$locals的设置,$locals会覆盖$everything的设置。 - 不同选项合并:如果不同层级设置的是不同的选项,这些选项会合并生效。比如全局设置了
-Wall,项目中设置了-g,最终构建时会同时使用-Wall -g。
四、Stack 1.6.5的特殊注意事项
因为你用的是1.6.5这个比较老的版本,有几个细节要注意:
$targets在无指定构建目标时,完全等同于$locals,但如果指定了多个目标,只会作用于那些明确指定的包。- 给第三方包设置选项时,必须明确写出包名,不支持新版本的通配符(比如
*)。 - 修改全局配置后,需要执行
stack config reload或者重启Stack才能生效,新版本会自动检测配置变化。
内容的提问来源于stack exchange,提问作者htmue
相关产品推荐
相关产品推荐

