|
|
基础版本(推荐) CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o fibu.exe fibu2.go 极致压缩版本(使用 UPX) # 先安装 UPX sudo apt-get install upx # 编译 + 压缩 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o myapp.exe main.go upx --best myapp.exe # 体积可减少 50-70% 带版本信息的发布版本 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \ -ldflags="-s -w -X main.Version=1.0.0 -X main.BuildTime=$(date +%Y%m%d)" \ -o myapp.exe main.go 验证静态链接 在 Ubuntu 上检查(使用 file 和 ldd) # 查看文件类型 file myapp.exe # 输出:myapp.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows # 检查依赖(静态编译应无外部依赖) # 注意:ldd 对 Windows exe 无效,需到 Windows 或用 wine 测试 在 Windows 上验证 打开 PowerShell 或 CMD:powershell # 查看依赖 dumpbin /dependents myapp.exe # 静态编译后应只显示:KERNEL32.dll 等系统核心 DLL # 或直接运行 myapp.exe |
// "github.com/ThomasRooney/gexpect" gexpect "github.com/google/goexpect" go mod tidy 剩下是修正对应的语法 |
|
推荐解决路径 首选:联系 gitee.com/tanpf/tools 维护者,建议替换为 github.com/google/goexpect(纯 Go) 次选:Fork 后自行修改,移除 expect 功能或使用条件编译 备选:如果 expect 是核心功能且必须保留,使用 mingw 编译并接受 DLL 依赖,或在 Linux 服务器端运行该功能 grep -r "gexpect" /ai/wks/gowks/src/tools/* go mod graph | grep gexpect |
# 安装 mingw-w64 sudo apt-get update sudo apt-get install mingw-w64 # 使用 mingw 编译(注意:生成的 exe 会依赖 libgcc.dll) CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 \ go build -o fibu.exe fibu2.go 缺点:生成的 fibu.exe 需要携带 libgcc_s_seh-1.dll 和 libwinpthread-1.dll,不是纯静态 完全静态化(需额外参数): CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 \ go build -ldflags="-s -w -linkmode external -extldflags '-static'" \ -o fibu.exe fibu2.go 带版本 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \ -ldflags="-s -w -X main.Version=1.0.0 -X main.BuildTime=$(date +%Y%m%d)" \ -o myapp.exe main.go |
|
|
|
|
|
|
|
### 现状:两种引入方式
同一个开发者的两个 gowks 工程,引入自己写的包用了两种完全不同的写法。
**方式一:fibu2.go(/ai/wks/gowks/src/cmd/fibu2,GOPATH 模式工程)**
```go
import (
dcc "gitee.com/tanpf/gin/dc/client" // 带别名的完整"域名式"路径
"gitee.com/tanpf/tools" // 每个包都要带全命名空间
)
```
**方式二:dws.go(/mnt/d/wks/gowks/src/cmd/edws,Go Modules 模式工程)**
```go
import (
"gowks/dws" // 模块名 + 包路径,简洁
)
```
差异不在写法本身,而在工程采用的是 GOPATH 模式还是 Go Modules 模式:
| 对比项 | 方式一 gitee.com/tanpf/tools | 方式二 gowks/dws |
|-----|------|------|
| 工程模式 | GOPATH 模式(无 go.mod) | Go Modules(go.mod 首行 module gowks) |
| 路径含义 | 包目录相对 $GOPATH/src 的路径 | 模块名 + 包相对模块根的路径 |
| 工程位置 | 必须钉在 $GOPATH/src 内 | 任意目录、任意盘符 |
| 前缀要求 | 域名式命名空间防重名 | 模块名随意,无需域名 |
| 依赖版本 | 全局一份,多版本无法共存 | 每模块独立,go.sum 锁定 |
| 写法 | 长 | 短,语义清晰 |
|
|
### GOPATH 模式原理(gitee.com/tanpf/tools)
Go 1.11 之前的唯一方式。核心规则只有一条:**import 路径 = 包目录相对 $GOPATH/src 的路径**,编译时 Go 拿着 import 字符串去 $GOPATH/src 下找同名目录。
fibu2 工程在本机的布局(GOPATH=/wks/gowks,软链到 /mnt/g/wks/gowks):
```text
/wks/gowks/ # GOPATH 根
└── src/ # 所有源码必须在它下面
├── cmd/fibu2/fibu2.go # package main
├── tools/ # 工具包真身(src/tools)
├── gin/dc/client/ # dcc 引入的包
└── vendor/ # 第三方依赖
```
要点:
- **域名前缀只是目录名**:gitee.com/tanpf/tools 不是网址,编译不联网,它只要求包物理放在 $GOPATH/src/gitee.com/tanpf/tools;域名起命名空间作用,防止大家的 tools 包互相冲突
- **路径与磁盘强耦合**:import 写死了 src 下的目录位置,每台机器都要把包按相同路径摆好。本机 G 盘副本里只有 src/tools、没有 src/gitee.com/tanpf/tools,fibu2.go 在这份副本上就找不到包——GOPATH 模式的典型痛点
- **老工程需 GO111MODULE=off**:本机 go env GO111MODULE=on,编译 fibu2 这类无 go.mod 的工程要临时切回 GOPATH 模式
- 第三方依赖放 src/vendor/ 下按相同规则解析;go get 会把源码直接拉进 src,污染工作区
|
|
### Go Modules 模式原理(gowks/dws)
Go 1.11 引入、1.16 起默认开启。核心规则:**import 路径 = go.mod 里声明的模块名 + 包相对模块根的路径**。
dws 工程的布局(模块根 = /mnt/d/wks/gowks/src,go.mod 所在目录):
```text
/mnt/d/wks/gowks/src/ # 模块根(有 go.mod 的目录)
├── go.mod # 首行 module gowks + 依赖清单
├── go.sum # 依赖版本与校验和
├── dws/ # import "gowks/dws" 的真身
│ ├── dws.go
│ └── driver_pgx.go
├── tools/tools.go # 对应 import "gowks/tools"
└── cmd/edws/dws.go # package main
```
解析过程(编译 cmd/edws 时):
1. Go 从源文件所在目录向上查找 go.mod,找到模块根,得知模块名为 gowks
2. import "gowks/dws" 的前缀与模块名匹配,判定为模块内部包
3. 去掉前缀 gowks,映射到模块根下的 dws 目录
要点:
- **模块名不必是域名**:gowks 这种短名只在模块内部使用;只有要发布给别人 go get 的公共模块才用完整域名(如 github.com/user/repo)
- **工程与 GOPATH 解耦**:工程可放任意盘符任意目录;第三方依赖不进 src,缓存在 GOMODCACHE(本机 /wks/gowks/pkg/mod)
- **版本互不干扰**:每个模块独立维护依赖清单,多个工程依赖同一包的不同版本可以共存
|
|
### 使用方式与选型建议
Go Modules 工程(gowks/dws 这种)的日常操作,全部在模块根(go.mod 所在目录)执行:
```bash
cd /mnt/d/wks/gowks/src
go mod init gowks # 首次创建模块(已有 go.mod 则跳过)
go mod tidy # 依据 import 整理依赖、更新 go.sum
go build ./... # 编译模块内全部包
go build ./cmd/edws # 只编译 edws 这个命令
go run ./cmd/edws ping --host 127.0.0.1 # 直接运行
```
GOPATH 工程(gitee.com/tanpf/tools 这种)在新版 Go 下的编译:
```bash
export GO111MODULE=off # 新版 Go 默认 on,老工程需临时切回
cd /wks/gowks/src/cmd/fibu2
go build -o fibu2 fibu2.go
```
老工程向 Modules 迁移(fibu2 这类工程的演进方向):
```bash
cd /wks/gowks/src
go mod init gowks
# import 逐个改短:gitee.com/tanpf/tools 改为 gowks/tools(包已在模块内)
```
```text
# 包暂时留在原路径、不想改 import 时,可在 go.mod 里 replace 过渡:
# replace gitee.com/tanpf/tools => ./tools
```
选型结论:
- 新工程一律 Go Modules:import 短、目录自由、依赖可锁版本
- gowks/dws 这种"模块名 + 包路径"是当前标准写法
- gitee.com/tanpf/tools 是 GOPATH 时代的历史写法,理解"src 下相对路径"的解析原理即可,便于维护 fibu2 等老工程
|