Ubuntu 中编译 Go + PBC 程序为 Windows 11 可运行文件

1. 问题背景

在 Ubuntu 中使用 Go 编写如下程序:

go 复制代码
package main

import (
	"fmt"

	"github.com/Nik-U/pbc"
)

func main() {
	rbits := uint32(512)
	qbits := uint32(1024)

	params := pbc.GenerateA(rbits, qbits)
	pairing := params.NewPairing()

	g := pairing.NewG1().Rand()

	fmt.Println(g.Bytes())
}

如果只是在 Ubuntu 本地运行,安装好 GMP 和 PBC 后,普通编译即可:

bash 复制代码
go build -o pbc-test .
./pbc-test

但是如果希望在 Ubuntu 中编译出 Windows 11 可运行的 .exe,不能直接使用:

bash 复制代码
GOOS=windows GOARCH=amd64 go build

原因是 github.com/Nik-U/pbc 不是纯 Go 包,它通过 CGO 调用 C 语言 PBC 库,而 PBC 又依赖 GMP。Ubuntu 本地安装的 GMP/PBC 是 Linux 版本,Windows .exe 不能链接 Linux 的 .so 动态库。因此需要额外准备一套 Windows x64 目标版本的 GMP/PBC。

核心原则是:

text 复制代码
/usr/local        用于 Ubuntu 本地运行
/opt/pbc-win64   用于 Windows 交叉编译

不要混用这两个环境。


2. 总体思路

最小必要步骤只有四步:

  1. 安装 Windows 交叉编译器 MinGW。
  2. 用 MinGW 编译 Windows 版 GMP 和 PBC。
  3. 用 CGO 指向 Windows 版 GMP/PBC 编译 Go 程序。
  4. .exe 和所需 .dll 放到同一个目录,然后复制到 Windows 11 运行。

其中第 1、2 步只需要做一次。后续修改 Go 代码后,只需要重新执行 Go 编译和打包命令。


3. 安装 Windows 交叉编译器

先检查是否已经安装 MinGW:

bash 复制代码
which x86_64-w64-mingw32-gcc

如果输出类似:

text 复制代码
/usr/bin/x86_64-w64-mingw32-gcc

说明已经安装,可以跳过本节。

如果没有输出,则安装:

bash 复制代码
sudo apt update
sudo apt install -y gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64

为什么需要这一步?

因为 Ubuntu 默认的 gcc 只能生成 Linux 目标文件,而 Windows .exe 需要 Windows 目标格式。x86_64-w64-mingw32-gcc 的作用就是在 Linux 中生成 Windows x64 程序。


4. 设置 Windows 版 GMP/PBC 安装目录

建议单独使用 /opt/pbc-win64

bash 复制代码
export TARGET=x86_64-w64-mingw32
export PREFIX=/opt/pbc-win64

sudo mkdir -p "$PREFIX"
sudo chown -R "$USER:$USER" "$PREFIX"

为什么不直接安装到 /usr/local

因为 /usr/local 里面通常已经有 Ubuntu 本地版本的 GMP/PBC。如果把 Windows 版本也放进去,很容易导致头文件、库文件混淆。单独放到 /opt/pbc-win64 更清晰,也不会破坏 Ubuntu 本地可运行环境。


5. 编译 Windows 版 GMP

进入临时目录:

bash 复制代码
cd /tmp

下载并解压 GMP:

bash 复制代码
wget https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
tar -xf gmp-6.3.0.tar.xz
cd gmp-6.3.0

配置为 Windows x64 目标:

bash 复制代码
./configure \
  --host=$TARGET \
  --prefix=$PREFIX \
  --disable-static \
  --enable-shared \
  ABI=64

编译并安装:

bash 复制代码
make -j"$(nproc)"
make install

为什么这里使用 --host=$TARGET

因为我们不是给 Ubuntu 自己编译 GMP,而是给 Windows x64 编译 GMP。--host=x86_64-w64-mingw32 会让 GMP 使用 MinGW 工具链生成 Windows 版本的库。

为什么使用动态库?

这里的目标是让 Windows 11 能稳定运行。动态链接方式更直观,只需要把 .dll.exe 放到同一个目录。静态链接虽然可以减少文件数量,但更容易遇到链接顺序、运行库和符号问题。


6. 编译 Windows 版 PBC

回到临时目录:

bash 复制代码
cd /tmp

下载并解压 PBC:

bash 复制代码
wget https://crypto.stanford.edu/pbc/files/pbc-0.5.14.tar.gz
tar -xzf pbc-0.5.14.tar.gz
cd pbc-0.5.14

配置 PBC。注意这里要显式告诉 PBC 去哪里找刚刚编译好的 Windows 版 GMP:

bash 复制代码
CPPFLAGS="-I$PREFIX/include" \
LDFLAGS="-L$PREFIX/lib" \
./configure \
  --host=$TARGET \
  --prefix=$PREFIX \
  --disable-static \
  --enable-shared

编译并安装:

bash 复制代码
make -j"$(nproc)"
make install

为什么要设置 CPPFLAGSLDFLAGS

因为 PBC 依赖 GMP。这里的 GMP 不是 Ubuntu 系统自带的 GMP,而是刚刚安装到 /opt/pbc-win64 的 Windows 版 GMP。因此必须显式告诉 PBC:

text 复制代码
头文件在 /opt/pbc-win64/include
库文件在 /opt/pbc-win64/lib

7. 检查 Windows 版 GMP/PBC 是否安装成功

执行:

bash 复制代码
ls /opt/pbc-win64/include/gmp.h
ls /opt/pbc-win64/include/pbc/pbc.h
ls /opt/pbc-win64/lib
ls /opt/pbc-win64/bin

正常情况下应该能看到类似文件:

text 复制代码
/opt/pbc-win64/include/gmp.h
/opt/pbc-win64/include/pbc/pbc.h
/opt/pbc-win64/lib/libgmp.dll.a
/opt/pbc-win64/lib/libpbc.dll.a
/opt/pbc-win64/bin/libgmp-10.dll
/opt/pbc-win64/bin/libpbc-1.dll

其中:

text 复制代码
libgmp.dll.a    编译 Go 程序时用于链接
libpbc.dll.a    编译 Go 程序时用于链接
libgmp-10.dll   Windows 运行时需要
libpbc-1.dll    Windows 运行时需要

8. 编译 Go 程序为 Windows 11 可运行 exe

进入 Go 项目目录:

bash 复制代码
cd 你的Go项目目录

如果还没有初始化 Go module:

bash 复制代码
go mod init go-pbc-test
go get github.com/Nik-U/pbc

然后编译 Windows 版本:

bash 复制代码
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 \
CC=x86_64-w64-mingw32-gcc \
CGO_CFLAGS="-I/opt/pbc-win64/include" \
CGO_LDFLAGS="-L/opt/pbc-win64/lib -lpbc -lgmp" \
go build -v -o pbc-test.exe .

这条命令中各部分含义如下:

bash 复制代码
GOOS=windows

表示目标系统是 Windows。

bash 复制代码
GOARCH=amd64

表示目标架构是 x86_64,也就是普通 Windows 11 电脑使用的 64 位架构。

bash 复制代码
CGO_ENABLED=1

表示启用 CGO。github.com/Nik-U/pbc 必须通过 CGO 调用 C 语言 PBC 库,所以不能关闭 CGO。

bash 复制代码
CC=x86_64-w64-mingw32-gcc

表示让 CGO 使用 Windows 交叉编译器,而不是 Ubuntu 默认的 gcc

bash 复制代码
CGO_CFLAGS="-I/opt/pbc-win64/include"

表示告诉 C 编译器去哪里找 gmp.hpbc/pbc.h

bash 复制代码
CGO_LDFLAGS="-L/opt/pbc-win64/lib -lpbc -lgmp"

表示告诉链接器去哪里找 Windows 版 PBC/GMP 库。

其中 -lpbc -lgmp 的顺序建议不要反过来,因为 PBC 依赖 GMP。

编译成功后检查文件格式:

bash 复制代码
file pbc-test.exe

如果输出类似:

text 复制代码
pbc-test.exe: PE32+ executable (console) x86-64, for MS Windows

说明已经成功生成 Windows x64 可执行文件。


9. 整理 Windows 运行目录

这一步很关键。不能只把 pbc-test.exe 复制到 Windows。因为前面使用的是动态链接,所以 Windows 运行时还需要对应的 DLL。

创建运行目录:

bash 复制代码
mkdir -p dist-win64

复制 exe:

bash 复制代码
cp pbc-test.exe dist-win64/

复制 PBC 和 GMP 的 DLL:

bash 复制代码
cp /opt/pbc-win64/bin/libpbc-1.dll dist-win64/
cp /opt/pbc-win64/bin/libgmp-10.dll dist-win64/

最终目录应该是:

text 复制代码
dist-win64/
├── pbc-test.exe
├── libpbc-1.dll
└── libgmp-10.dll

然后把整个 dist-win64 文件夹复制到 Windows 11,在 Windows 中运行:

powershell 复制代码
.\pbc-test.exe

为什么必须复制 DLL?

因为 pbc-test.exe 运行时会动态加载 PBC,而 PBC 又会动态加载 GMP。Windows 默认只会在 exe 同目录、系统目录、PATH 等位置寻找 DLL。最简单可靠的做法就是把 DLL 放在 exe 同一个文件夹中。


10. 打包为 zip

可以直接打包:

bash 复制代码
zip -r pbc-test-win64.zip dist-win64

之后只需要把 pbc-test-win64.zip 复制到 Windows 11,解压后运行即可。


11. 常见错误与解决方法

11.1 找不到 libpbc-1.dll

报错:

text 复制代码
由于找不到 libpbc-1.dll,无法继续执行代码。重新安装程序可能会解决此问题。

原因:

Windows 找不到 PBC 动态库。

解决:

把下面文件复制到 exe 同目录:

bash 复制代码
cp /opt/pbc-win64/bin/libpbc-1.dll dist-win64/

正确目录:

text 复制代码
dist-win64/
├── pbc-test.exe
└── libpbc-1.dll

通常还需要一起复制 GMP:

bash 复制代码
cp /opt/pbc-win64/bin/libgmp-10.dll dist-win64/

11.2 找不到 libgmp-10.dll

报错:

text 复制代码
由于找不到 libgmp-10.dll,无法继续执行代码。

原因:

PBC 依赖 GMP,但是 Windows 找不到 GMP 动态库。

解决:

bash 复制代码
cp /opt/pbc-win64/bin/libgmp-10.dll dist-win64/

11.3 找不到 pbc/pbc.h

Go 编译时报错:

text 复制代码
fatal error: pbc/pbc.h: No such file or directory

原因:

CGO 没有找到 PBC 头文件。

检查:

bash 复制代码
ls /opt/pbc-win64/include/pbc/pbc.h

解决:

确保编译 Go 时包含:

bash 复制代码
CGO_CFLAGS="-I/opt/pbc-win64/include"

11.4 cannot find -lpbc 或 cannot find -lgmp

报错:

text 复制代码
cannot find -lpbc
cannot find -lgmp

原因:

链接器没有找到 Windows 版 PBC/GMP 库。

检查:

bash 复制代码
ls /opt/pbc-win64/lib

应该能看到:

text 复制代码
libpbc.dll.a
libgmp.dll.a

解决:

确保编译 Go 时包含:

bash 复制代码
CGO_LDFLAGS="-L/opt/pbc-win64/lib -lpbc -lgmp"

11.5 file format not recognized

报错:

text 复制代码
file format not recognized

原因:

通常是把 Linux 版库链接进 Windows exe 了。例如错误地链接了:

text 复制代码
/usr/local/lib/libpbc.so
/usr/local/lib/libgmp.so

解决:

不要使用 /usr/local/lib。Windows 交叉编译时必须使用:

text 复制代码
/opt/pbc-win64/lib

对应编译参数应为:

bash 复制代码
CGO_LDFLAGS="-L/opt/pbc-win64/lib -lpbc -lgmp"

12. 查看 exe 依赖了哪些 DLL

可以使用:

bash 复制代码
x86_64-w64-mingw32-objdump -p pbc-test.exe | grep "DLL Name"

也可以查看 PBC DLL 自己依赖什么:

bash 复制代码
x86_64-w64-mingw32-objdump -p /opt/pbc-win64/bin/libpbc-1.dll | grep "DLL Name"

如果输出中出现某个 DLL,而 Windows 运行时报缺失,就把对应 DLL 放到 exe 同目录。


13. 后续日常使用命令

如果 Windows 版 GMP/PBC 已经编译好,后续修改 Go 代码后,只需要执行下面命令。

编译:

bash 复制代码
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 \
CC=x86_64-w64-mingw32-gcc \
CGO_CFLAGS="-I/opt/pbc-win64/include" \
CGO_LDFLAGS="-L/opt/pbc-win64/lib -lpbc -lgmp" \
go build -v -o pbc-test.exe .

整理运行目录:

bash 复制代码
mkdir -p dist-win64

cp pbc-test.exe dist-win64/
cp /opt/pbc-win64/bin/libpbc-1.dll dist-win64/
cp /opt/pbc-win64/bin/libgmp-10.dll dist-win64/

打包:

bash 复制代码
zip -r pbc-test-win64.zip dist-win64

最终复制到 Windows 11 的文件夹应为:

text 复制代码
dist-win64/
├── pbc-test.exe
├── libpbc-1.dll
└── libgmp-10.dll

14. 总结

Ubuntu 本地可以运行,只说明本地 Linux 版 GMP/PBC 安装成功;它不能直接用于生成 Windows 11 可运行程序。

要在 Ubuntu 中编译 Windows 版 Go + PBC 程序,关键是:

text 复制代码
使用 MinGW 编译 Windows 版 GMP/PBC
使用 CGO 指向 Windows 版头文件和库文件
运行时把 exe、libpbc-1.dll、libgmp-10.dll 放在同一个目录

最重要的编译命令是:

bash 复制代码
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 \
CC=x86_64-w64-mingw32-gcc \
CGO_CFLAGS="-I/opt/pbc-win64/include" \
CGO_LDFLAGS="-L/opt/pbc-win64/lib -lpbc -lgmp" \
go build -v -o pbc-test.exe .

最重要的运行目录是:

text 复制代码
dist-win64/
├── pbc-test.exe
├── libpbc-1.dll
└── libgmp-10.dll

只要这三个文件放在一起,Windows 11 就可以正常运行该程序。

相关推荐
caimouse1 小时前
Reactos 第 5 章 进程与线程 — 5.14 Windows线程间的相互作用
windows
晓py1 小时前
Windows 本地挂载阿里云 ECS,并使用 Claude 操作挂载路径学习文档
windows·学习·阿里云
阿昭L1 小时前
Windows堆dword shoot
windows·安全·漏洞·堆溢出
jieyucx1 小时前
《Go 数据库编程开篇:彻底打通 database/sql 与 MySQL 驱动的连接池调优密码》
数据库·sql·golang
love530love1 小时前
Anaconda Navigator 升级后图形界面启动失败故障修复实录
人工智能·windows·python·anaconda·navigator
壮Sir不壮2 小时前
GO语言——GMP调度模型
linux·开发语言·golang·go·操作系统·线程·协程
biubiubiu07062 小时前
Ubuntu中3种定时任务
数据库·ubuntu·postgresql
再玩一会儿看代码2 小时前
2026 年 ChatGPT 套餐怎么选?Free、Go、Plus、Pro、Business、Enterprise 一次讲清楚
人工智能·gpt·chatgpt·golang·openai·codex
必胜刻2 小时前
Go项目实战:使用Ollama本地部署大模型实现AI智能笔记生成
人工智能·笔记·ai·语言模型·golang