实战记录:使用 Haskell.nix 交叉编译 Haskell 项目至 Windows

在 Haskell 开发中,使用 Nix 进行构建能带来极大的便利,尤其是涉及跨平台交叉编译时。本文记录了将一个基于 haskell.nix 的项目(haskell-periodic)配置为支持 Windows (mingwW64) 交叉编译的全过程。

1. 调整构建脚本 (Makefile)

原始的 Makefile 1 主要是针对 Linux (musl) 环境设计的,缺少对 Windows 可执行文件后缀(.exe)和特定工具链的支持。

为了支持 Windows 交叉编译,我们需要在 Makefile 中增加对 mingwW64 平台的分支判断,主要修改点如下:

  1. 定义 Strip 工具 :Linux 下通常使用 standard strip,但在交叉编译 Windows 版本时,必须使用对应的 x86_64-w64-mingw32-strip
  2. 处理文件后缀 :Windows 可执行文件需要 .exe 后缀,而 Linux 不需要。
  3. 修改输出目标:构建目标路径需要动态追加这个后缀。

修改后的 Makefile 片段:

Makefile

makefile 复制代码
# ... 之前的定义 ...

ifeq ($(PLATFORM),mingwW64)
# Windows 平台特定配置
STRIP = x86_64-w64-mingw32-strip
COMPILER ?= ghc9122
EXT = .exe
else
# ... 其他平台配置 ...
endif

# ...

# 针对每个组件,确保输出包含后缀 $(EXT)
periodic:
	PKG=periodic-client-exe make dist/$(PLATFORM)/$@$(EXT)

# ... 其他组件类似 ...

通过运行 make PLATFORM=mingwW64,构建系统现在可以正确识别目标平台并尝试生成 .exe 文件。

2. 遭遇链接错误:UCRT 与 MSVCRT 冲突

在调整完 Makefile 并尝试构建后,我们在链接阶段(Linking)遇到了如下错误:

Plaintext

vbnet 复制代码
multiple definition of `__getmainargs'
multiple definition of `_onexit'
multiple definition of `_amsg_exit'
...

问题分析:

这是一个经典的 Windows C 运行时冲突问题。现代的 GHC 和 Nix 工具链倾向于使用 UCRT (Universal C Runtime),但某些依赖或 GHC 内部组件可能引入了旧版的 MSVCRT (Microsoft Visual C Runtime)。当链接器同时遇到这两套库的符号定义时,就会报"多重定义"错误。

3. 修正 Nix 配置 (default.nix)

为了解决这个问题,我们需要通过 GHC 传递参数给链接器,告诉它允许符号的多重定义(让链接器自动选择其中一个)。

我们需要修改 default.nix 2222,利用 haskell.nix 提供的模块系统 (modules) 注入特定的 configureFlags

修改后的 default.nix 关键部分:

Nix

ini 复制代码
# ... 头部引入保持不变 ...

in pkgs.haskell-nix.cabalProject {
    # ... src, index-state 等配置 ...
    
    modules = [(
       {pkgs, ...}: {
         enableProfiling = enableProfiling;

         # --- Windows 交叉编译修复 ---
         # 针对 Windows 平台,添加链接器参数以解决 UCRT/MSVCRT 冲突
         packages.periodic-client-exe.configureFlags = pkgs.lib.optionals pkgs.stdenv.hostPlatform.isWindows [
           "--ghc-option=-optl-Wl,--allow-multiple-definition"
         ];

         # 如果 Server 端也需要在 Windows 构建,同样应用该修复
         packages.periodic-server.configureFlags = pkgs.lib.optionals pkgs.stdenv.hostPlatform.isMusl [
           # ... 保留原有的 Linux/Musl 链接库配置 ...
           "--ghc-option=-optl=-lssl"
           # ...
         ] ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isWindows [
           "--ghc-option=-optl-Wl,--allow-multiple-definition"
         ];
      })];
}

这里使用了 pkgs.lib.optionals pkgs.stdenv.hostPlatform.isWindows 来确保这些标志仅在编译 Windows 版本时生效,不会影响 Linux 版本的构建。

4. 最终结果

完成上述修改后,再次执行构建命令:

Bash

ini 复制代码
make PLATFORM=mingwW64

构建过程顺利通过链接阶段,成功在 dist/mingwW64/ 目录下生成了 Windows 可执行文件(如 periodic.exe)。通过这种方式,我们利用 Nix 强大的交叉编译能力,在不离开 Linux 开发环境的情况下,优雅地交付了 Windows 二进制文件。

相关推荐
小神.Chen19 分钟前
如何删除远程桌面的连接记录,一键清理mstsc远程桌面连接的记录
windows
John_ToDebug29 分钟前
WebHostView 与 TabStrip 交互机制深度解析
c++·chrome·windows
L1624761 小时前
Win11 共享→Windows Server 访问故障总结(极简可复用)
开发语言·windows·php
love530love2 小时前
ComfyUI MediaPipe 终极填坑:解决 incompatible function arguments 报错,基于代理模式的猴子补丁升级版
人工智能·windows·comfyui·mediapipe·猴子补丁·monkey patch·python 3.12
今夕资源网2 小时前
Windows Terminal更舒适的命令行环境 仅11MB 支持并行运行WSLLinux子系统 github开源项目
windows·github·命令行·cmd·terminal
java_logo4 小时前
SiYuan 思源笔记 Docker 部署终极指南:Windows+Linux 双平台
windows·笔记·docker·思源笔记·思源笔记部署·docker部署思源笔记·思源笔记文档
测试员周周6 小时前
【AI测试系统】第1篇:LangGraph 实战:用 State Graph 搭建 AI测试流水线(4 步编排 + RAG 增强 + 完整代码)
linux·windows·python·功能测试·microsoft·单元测试·多轮对话
祖国的好青年6 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
love530love6 小时前
Python 3.12 解决 MediaPipe “no attribute ‘solutions‘” 终极方案:基于全版本硬核实测的避坑指南
开发语言·人工智能·windows·python·comfyui·mediapipe·solutions
YJlio7 小时前
Windows Internals 读书笔记 10.3.3:Task Scheduler 架构详解
人工智能·windows·笔记·python·学习·chatgpt·架构