实战记录:使用 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 二进制文件。

相关推荐
Bruce_Liuxiaowei22 分钟前
基于Regsvr32.exe的渗透测试完整记录
网络·windows·安全·网络安全·内网渗透
玖釉-28 分钟前
[Vulkan 实战] 深入解析 Vulkan Compute Shader:实现高效 N-Body 粒子模拟
c++·windows·图形渲染
日日行不惧千万里1 小时前
EFI 与 UEFI 详解
windows
huwei8532 小时前
python设计通用表格类 带右键菜单
开发语言·windows·python
数据知道3 小时前
万字详解 PostgreSQL 的详细安装方式(Linux、Windows、macOS、Docker 全平台覆盖)
linux·windows·postgresql
庞克记录3 小时前
win11电脑不识别移动固态
windows·电脑
Bruce_Liuxiaowei12 小时前
基于HTA的Meterpreter反向Shell攻击实验
网络·windows·经验分享·网络安全·渗透测试
2401_8823515213 小时前
Flutter for OpenHarmony 商城App实战 - 会员中心实现
windows·flutter
抠头专注python环境配置14 小时前
解决Windows安装PythonOCC报错:从“No module named ‘OCC’ ”到一键成功
人工智能·windows·python·3d·cad·pythonocc
C++实习生15 小时前
Visual Studio Express 2015 for Windows Desktop 中文学习版
windows·express·visual studio