MinGW 包指南
本页面说明如何为在 Windows 上运行的软件编写 PKGBUILD。
要在 Linux 上为 Windows 构建软件,你需要
- Windows 头文件和 WinAPI 和 C 标准库的导入库。有两种选择可以获取它们:
- mingw-w64:提供 32 位和 64 位工具链,支持安全 crt、Vista+ API、DDK (ReactOS) 和 DirectX (WINE)。有关支持的功能列表以及与旧版 MinGW.org 的区别,请参阅 此处。可通过安装 mingw-w64-headers 和 mingw-w64-crt 从官方仓库获取。AUR 中提供其他库的软件包依赖于这些软件包。
- MinGW:提供 32 位工具链,支持有限的 DirectX。它还存在线程局部存储和浮点库支持实现方面长期存在的错误。它已被从官方仓库和 AUR 中移除。
- 编译器及其运行时库。
- 对于 C/C++,可以使用 GCC 和 Clang。要使用 GCC,需要安装 mingw-w64-gcc,因为无法使用常规的 gcc 软件包。要使用 Clang,可以直接使用 clang,并指定 `*-w64-mingw32` 平台三元组作为目标。由于常规的 clang 软件包不包含 Windows 目标的编译器运行时库,因此需要单独编译它们,或者使用 mingw-w64-gcc 提供的运行时。AUR 中提供其他库的软件包依赖于 mingw-w64-gcc。
- 对于 Rust,可以使用 mingw-w64-rustAUR。常规的 rust 软件包不是为了能够交叉编译到 Windows 而构建的。如果使用 rustup 软件包安装了 Rust,则应添加 Windows 目标:
rustup target add x86_64-pc-windows-gnu。 - 对于 Go,可以使用常规的 go 软件包。
- C/C++ 标准库。可以使用 mingw-w64-gcc 提供的 libstdc++,或 LLVM 项目的 libc++。AUR 中提供其他库的软件包依赖于 libstdc++。
- 链接器和附加工具。可以使用 mingw-w64-binutils 提供的 GNU binutils,或 llvm 和 lld 提供的 LLVM/lld。还有 mingw-w64-toolsAUR,它提供了一些额外的 Windows 特定工具。
对于 ix86/x86_64,通常的选择是使用 mingw-w64- 配合 GCC/libstdc++ 和 binutils。因此,遵循 `mingw-w64-pkgname` 命名约定的 AUR 软件包就是这样使用的。本 Wiki 页面的其余部分将重点介绍这些软件包。
还有一些名为 `llvm-mingw-w64-pkgname` 的 AUR 软件包,它们使用 LLVM/Clang/libc++,并支持 aarch64,而不仅仅是 i686 和 x86_64。这些软件包依赖于 https://github.com/mstorsjo/llvm-mingw 的构建,并且不使用 Arch Linux 提供的 LLVM/Clang。只有少数核心软件包存在。
还有一些由 https://github.com/Martchus/PKGBUILDs 提供的名为 `mingw-w64-clang-arch-pkgname` 的软件包。这些软件包使用 Arch Linux 提供的 llvm、lld 和 clang,并且仅在其之上提供 mingw-w64、LLVM 编译器运行时和 libc++。到目前为止,这些软件包仅针对 aarch64 目标存在。它们主要通过转换脚本从 `mingw-w64-pkgname` AUR 软件包生成,以便在不额外付出太多努力的情况下提供比核心工具链更多的内容。到目前为止,已有超过 100 个 `mingw-w64-pkgname` 软件包被转换为 `mingw-w64-clang-aarch64-pkgname` 软件包。它们尚未上传到 AUR,因为它们是自动生成的,但生成器和二进制仓库可以在上述 GitHub 仓库中找到。
包命名
mingw-w64 的软件包应命名为 `mingw-w64-pkgname`。如果正在构建静态版本,则在软件包名称后添加 `-static`(在下面会说明何时需要这样做)。
打包
跨平台软件包的打包可能相当棘手,因为存在许多不同的构建系统和底层细节。但请注意以下几点:
- 始终将 mingw-w64-crt 添加到
depends,除非它依赖于另一个隐式依赖于它的软件包。 - 始终将 mingw-w64-gcc 添加到
makedepends,除非使用 mingw-w64-configureAUR 或 mingw-w64-cmakeAUR。 - 始终将
!strip、staticlibs和!buildflags添加到options。 - 始终使用原始的
pkgdesc,并在pkgdesc末尾追加(mingw-w64)。 - 始终使用并遵循官方软件包的原始
pkgver。 - 始终同时构建 32 位和 64 位版本的库。
- 始终将所有内容放在
/usr/i686-w64-mingw32和/usr/x86_64-w64-mingw32前缀下。 - 始终将架构设置为
any(除非软件包包含必须在构建系统上运行的可执行文件)。 - 始终同时构建共享库和静态库。
- autotools 项目通常支持一次构建两者,当使用 mingw-w64-configureAUR 时,共享库和静态库都已启用。
- 如果构建系统或项目不支持此功能,则分别构建两者。
- 如果共享构建和静态构建发生冲突(例如,因为头文件或 CMake 配置文件不同),请考虑将静态库安装到
/usr/i686-w64-mingw32/static和/usr/x86_64-w64-mingw32/static。 - 对于大型项目,请考虑创建一个单独的
-static软件包。
- 考虑移除不必要的文档(
rm -r $pkgdir/usr/i686-w64-mingw32/share/{doc,info,man},rm -r $pkgdir/usr/x86_64-w64-mingw32/share/{doc,info,man})。 - 考虑使用 mingw-w64-configureAUR 来构建使用 configure 脚本的项目。
- 考虑使用 mingw-w64-cmakeAUR 来构建使用 CMake 的项目。
- 考虑使用 mingw-w64-mesonAUR 来构建使用 Meson 的项目。
- 考虑使用 mingw-w64-makeAUR 来构建使用纯 Makefile 的项目。
- 考虑使用 mingw-w64-qt5-baseAUR 来构建使用 QMake 的项目。
- 考虑在
package()的 for 循环中显式使用 `${_arch}-strip` 来剥离符号,如以下 PKGBUILD 示例所示。- 考虑使用 `find` 命令来遍历
$pkgdir,因为并非所有 DLL、静态库或可执行文件都可能位于其正确的位置。- 如果二进制文件是 DLL,请使用
${_arch}-strip --strip-unneeded *.dll。 - 如果二进制文件是静态库,请使用
${_arch}-strip -g *.a。
- 如果二进制文件是 DLL,请使用
- 考虑使用 `find` 命令来遍历
- 如果软件包是模块化的(需要某些构建依赖项,但这些依赖项对最终用户是可选的),请将它们添加到
makedepends和optdepends。在更新现有软件包时,请务必将其从depends中减去。使用示例:mingw-w64-qt6-baseAUR。 - 如果软件包安装了
$pkgdir/usr/${_arch}/bin/*-config脚本,请将其符号链接到$pkgdir/usr/bin/${_arch}-*-config。 - 如果软件包使用 autoconf,请为
configure显式设置--build="$CHOST"以解决 autoconf bug #108405,或者使用 mingw-w64-configureAUR。
如上所述,所有文件都应安装到 /usr/i686-w64-mingw32 和 /usr/x86_64-w64-mingw32。具体来说,所有 DLL 都应放在 /usr/*-w64-mingw32/bin,因为它们是运行时需要的动态库。它们对应的 .dll.a 文件应放在 /usr/*-w64-mingw32/lib。请删除 /usr/share 中任何不必要的文档以及其他文件。交叉编译软件包并非为用户准备,而仅供编译器和二进制分发使用,因此您应尽量使其体积最小。
始终尝试使您的 mingw-w64 软件包的 pkgver 与官方 Arch Linux 仓库(非测试仓库)中相应常规软件包的 pkgver 匹配。这可以确保交叉编译的软件在 Windows 上运行方式完全相同,没有任何意外的 bug。如果 Arch 中的软件包已过时,通常有其原因,您仍应遵循 Arch 版本,而不是使用最新的上游发布版本。如果相应的本地软件包在 AUR 中,则无需遵循此版本策略,因为许多 AUR 软件包经常被放弃或无人维护。
示例
以下示例将尝试涵盖一些最常见的约定和构建系统。
Autotools
pkgname=mingw-w64-foo
pkgver=1.0
pkgrel=1
pkgdesc="Foo bar (mingw-w64)"
arch=('any')
url="http://www.foo.bar"
license=('GPL')
makedepends=('mingw-w64-configure')
depends=('mingw-w64-crt')
options=('!strip' '!buildflags' 'staticlibs')
source=("http://www.foo.bar/foobar.tar.gz")
sha256sums=('8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406')
_architectures="i686-w64-mingw32 x86_64-w64-mingw32"
build() {
cd foo-$pkgver
for _arch in ${_architectures}; do
mkdir -p build-${_arch} && pushd build-${_arch}
${_arch}-configure ..
make
popd
done
}
package() {
for _arch in ${_architectures}; do
cd "foo-$pkgver/build-${_arch}"
make DESTDIR="${pkgdir}" install
${_arch}-strip --strip-unneeded "$pkgdir"/usr/${_arch}/bin/*.dll
${_arch}-strip -g "$pkgdir"/usr/${_arch}/lib/*.a
done
}
CMake
pkgname=mingw-w64-foo
pkgver=1.0
pkgrel=1
pkgdesc="Foo bar (mingw-w64)"
arch=('any')
url="http://www.foo.bar"
license=('GPL')
makedepends=('mingw-w64-cmake')
depends=('mingw-w64-crt')
options=('!strip' '!buildflags' 'staticlibs')
source=("http://www.foo.bar/foobar.tar.gz")
sha256sums=('8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406')
_architectures="i686-w64-mingw32 x86_64-w64-mingw32"
build() {
cd foo-$pkgver
for _arch in ${_architectures}; do
${_arch}-cmake -B build-${_arch} .
make -C build-${_arch}
done
}
package() {
for _arch in ${_architectures}; do
cd "foo-$pkgver/build-${_arch}"
make DESTDIR="${pkgdir}" install
${_arch}-strip --strip-unneeded "$pkgdir"/usr/${_arch}/bin/*.dll
${_arch}-strip -g "$pkgdir"/usr/${_arch}/lib/*.a
done
}