GO windows安装

软件下载

 
https://golang.google.cn/
https://dl.google.com/go/go1.20.5.windows-amd64.msi


环境变量配置

 
我的电脑--属性--环境变量-用户环境变量 添加一下

GOWKS=G:\tpf\gowks
GOROOT=%GOWKS%\app\gowin
GOBIN=%GOWKS%\bin
GOPATH=%GOWKS%

将下面的路径添加到path中
%GOROOT%\bin
%GOBIN%

GO linux安装

软件下载

 
https://dl.google.com/go/go1.19.3.linux-amd64.tar.gz
https://studygolang.com/dl/golang/go1.18.10.linux-amd64.tar.gz
https://golang.google.cn/

Go环境变量设置

 
export GOWKS=/opt/wks/gowks
export GOROOT=$GOWKS/app/go
export GOBIN=$GOWKS/bin
export GOPATH=$GOWKS
export PATH=$GOROOT/bin:$GOBIN:$PATH

GOWKS是自定义的GO工作空间,
GO软件安装在其app/go目录下,
GOWKS同时也是GOPATH,
这里面包含项目运行的GO软件,下载的依赖包,编辑后的命令,说明文档等一切项目相关的文件。

后续若进行项目迁移,不管是GO本身版本变化,还是它的依赖包版本变化,
直接将这个目录COPY走就解决了所有问题。

GO ENV
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct  # 国内七牛云提供

GO mod vendor使用

go mod

 
mkdir esql
cd esql 
go mod init 
就完成go mod的初始化化了

go mod tidy 
这一步自动将go文件引入的外部包写入mod文件,并修改sum文件

如果要使用或找不到本地包,则修改mod相应的包指向本地目录位置
require gitee.com/ol v0.0.0-00010101000000-000000000000 // indirect
replace gitee.com/ol => ../../ol

go vendor

 
进入包目录,执行
go mod vendor 
就可以将依赖的外部包打包一份到vendor目录下,repalce指向本地的除外

这里要求你的项目放在GOPATH/src目录下
依赖于GOPATH,可放于GOPATH/src目录下,或者GOPATH/src的项目目录下
查找顺序:从当前模块目录找vendor目录,一直找到GOPATH/src
使用:手动依赖包或自己写的模块放到vendor目录,或者mod模式下进入目录执行go mod vendor
好处:下载的依赖包随项目走,不用关心这些依赖包的版本变化导致项目不可用了

注意事项
go vendor是要放在gopath/src目录下的
如果gopath/src/vendor与gopath/src下存在相同的模块,则vendor目录的优先级高,
即会调用vendor下的模块
而go mod的模块目录如果使用replace指定特定目录后,就不会走vendor了
如果使用go mod编辑报错同时又是个人项目,可以关闭go mod:go env -w GO111MODULE=off
没了go mod的自动下载,就将手工将下载的依赖包放到vendor下,
项目迁移时,vendor随之迁移,这样的项目也是极其稳定的,
或者像文章开始那样搭建项目,项目相关所有文件都放在$GOWKS目录下,
迁移时,GO版本与其依赖包都不变化,这样就万无一失了。

如果没有使用go mod,那么下载并编辑项目github.com/kardianos/govendor,生成一个govendor
go get -u -v github.com/kardianos/govendor
go mod init
go mod tidy
go build

govendor用法
govendor init
初始化vendor目录

govendor add +external
添加外部依赖

govendor update +external
更新外部依赖

govendor update $PACKAGE_NAME
更新指定包的依赖

 


 


 


 


go环境变量配置2
 
export GOWKS=/opt/tpf/liu
export GOROOT=$GOWKS/app/go
export GOBIN=$GOWKS/bin
export GOPATH=$GOWKS
export PATH=$GOROOT/bin:$GOBIN:$PATH
go env
 
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct  # 国内七牛云提供
GO 变量定义

GO有四种数据类型,数字、布尔、字符、派生类型;这里使用 前三种 简单类型 来说明变量的定义与使用

 
int8/uint8 
int16/uint16 
int32/uint32 
int64/uint64 
float32
float64 
complex64
bool 
byte 
rune :32位有符号整型,存储Unicode字符
int/uint :是32位还是64位看平台,其他的通过名字就能看到多少位

uint8 0-255,int8则是-128-127,这两个是Go的最小长度类型,其他类型在内存中分配的长度都要比这两个大;

-------------------------------------------- 
package main

import "fmt"
var (   
    aa = 1   
    bb = true   
    ss = "作用域为包的变量"   
    s2,s3 = "包变量的位置可能写在包内的任何地方","即可以是引用的前面也可以在引用的后面"
)
//GO有四种类型,数字、布尔、字符、派生类型
//变量的默认值
func var1(){
    var a int
    var b bool
    var f float64
    var s string
    // %d 表示数字,%s表示字符串,%q可以为字符串带上双引号
    fmt.Printf("%d-%s-%q\n",a,s,s)  // 0--""
    fmt.Println(b)  //false
    fmt.Println(f)  //0
}

//变量初始化
func var2(){
    var a int = 100  //明确地写出了变量的类型
    var b,f,s = true,3.14,"批评别人时,一定要顾及听者的面子" //不定义类型,同时多变量写于一行
    fmt.Println(a,b,f,s)
    var aa = 300
    var ss = "在回答别人或对别人发表观点时,一定要先准确理解别人的意思"
    fmt.Println(aa,ss)
}

//较常用的变量声明赋值方式
func var3(){
    //多行合并为一行,省去了类型,连var关键字也省去了,编辑器自动判断变量类型;只能用于一次声明变量时使用
    s1,s2 := "话越多","越没有份量"
    fmt.Println(s1,s2)
    //第二次使用时,不可再加冒号
    s1,s2 = "讲话时不能只顾着自己说","更要注意对方的感受和情绪变化"
    fmt.Printf("%s,%q",s1,s2) //讲话时不能只顾着自己说,"更要注意对方的感受和情绪变化"
}

func main() {
    var1()
    var2()
    var3()
}
变量几个注意事项

变量的命名:
推荐使用studentName,而不是student_name
首字母大写有特殊的含义,比如一个包的方法要想在其他包中使用,那么该方法名称必须首字母大写,又比如结构体中的属性等

变量的作用域:
比如包a下有b.go与c.go,b.go中有方法C,则其他包引用的方式为a.C()
包,即文件所在目录的名称,包名文件夹下可以有多个文件,包内变量的作用域是可以跨越这些文件的;
比如,一个包中不允许存在两个相同名称的方法,会提示重复;
函数内的变量的作用域就只是在函数内了

字符串
字符串分为原生字符串、解释型字符串两种;
原生字符串使用``(反引号),解释型字符串使用双引号"",解释型字符串中可以解析转义字符;

GO 常量与枚举

 
package main

import (
    "fmt"
    "math"
)

//常量
func cons(){
    const a,b= 3,4  //常量的数字在不明确指定类型的情况下,即可以作为int使用,也可以作为float32/float64使用
    var c int
    c = int(math.Sqrt(a*a+b*b)) //不需要转float64
    fmt.Println(c)         //5
    const aa,bb int = 3,4
    cc := math.Sqrt(float64(aa*aa + bb*bb))
    fmt.Println(cc)        //5
    fmt.Println(s1,s2)     //你多少次在讲话前 没有去在意对方的心思
}

//包内常量,go的常量通常不全部大写表示,这是因为go语言定义的变量或常量,首字母大写是有特定含义的
const (
    s1,s2 ="你多少次在讲话前","没有去在意对方的心思"
)

//枚举
func enum(){
    //在go中可以简单地使用const常量来表示枚举
    const(
        java = 0
        net = 1
        c =2
        rust = 3
    )
    const(
        aa = iota //一个行计数器,从0开始,刚好与枚举从零开始相符,故而使用iota简化枚举的写法
        bb
        _  //_一个占位符,这样下面的dd才能被赋值3
        dd
    )
    const(
        byte = 1 <<(10 * iota)
        kb
        mb
        gb
        tb
        pb
    )
    fmt.Println(byte,kb,mb,gb,tb,pb)  //1 1024 1048576 1073741824 1099511627776 1125899906842624
}

func main() {
    cons()
    enum()
}
GO 数组与切片

数组

 
var arr1 = [4]uint8{192,168,0,1}
var arr2 = [...]uint8{192,168,0,2}

...,三个小黑点,由Go编译器计算该值的元素数量并以此获得其长度,也适用于函数参数

切片

 
var slic1= []string{"192.168.0.1","192.168.0.2"}
var slic2=append(slic1,"192.168.0.3")
var slic3=make([]string,50)

append可以为切片类型[]string追加元素

make可以高效地为一个切片初始化数据,make([]string,50)则是一次性初始化50个默认值为""的元素

len与cap

 
func main(){
    println(len(arr1),cap(arr2),len(slic2),cap(slic3))
}

输出
4 4 3 50

go map

 
package main
var m1 = map[string]bool{}

func main(){
    m1["魔镜,我是世界上最美的女人吗"]= false
    println(m1["魔镜,我是世界上最美的女人吗"])
    println(len(m1))
    delete(m1,"魔镜,我是世界上最美的女人吗")
    println(len(m1))
    delete(m1,"魔镜,我是世界上最美的女人吗")
    println(len(m1))
}

delete可以删除本身就不存在的元素,输出
false
1
0
0

相比数组的定义,
map多了关键字map,
以及key的类型,放在了中括号里 
map[key type]value type{}

GO 流程控制

for循环

 
for i:= 0;i<9;i++ {
    fmt.Println(i)
}

for循环数组

 
for index, val := range arr{
    fmt.Printf("第 %d 位 x 的值 = %d\n", index, val)
}
    

for循环map

 
for key, value := range oldMap {
    newMap[key] = value
}

for 永远循环,死循环中通常会有跳出循环的条件

 
for {
    record, err := r.Read()
    
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
    for i:= 0;i<r.FieldsPerRecord;i++ {
        fmt.Println(i,record[i])
    }
}

if 条件语句

 
package main

import (
    "fmt"
    "io/ioutil"
)
func if1(){
    const filename = "/tmp/a.log"
    if txt, err := ioutil.ReadFile(filename); err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("%s\n", txt)
    }
}

go switch: 找到第1个条件成立的分支就返回

 
package main

import (
    "fmt"
)

func switch1(level int) string{
    res := ""

    switch level{
    case 1:
        res = "100000"
    case 2:
        res = "30000"
    case 3:
        res = "10000"
    default:
        res = "1000"
    }
    return res
}
func switch2(level int) string{
    res := ""

    switch {
    case level == 100:
        res = "100000"
    case level > 90:
        res = "30000"
    case level > 80:
        res = "10000"
    case level > 60:
        res = "1000"
    case level <= 60:
        panic("You ......")
    }
    return res
}

func main() {
    res := switch1(1)  
    println(res) //100000

    fmt.Println(switch1(1),switch1(2))  // 100000 30000

    fmt.Println(switch2(100),switch2(88)) // 100000 10000

  //下面这个是直接报错,并不会输出前两个到第三个时再报错
  fmt.Println(switch2(100),switch2(88),switch2(38))
}

GO 结构体

结构体定义示例

 
变量  : var   name 数据类型 
常量  : const name 数据类型 
结构体: type   name 数据类型 --> type Student struct 

从上面三行感受一下GO语言变量设计的风格:
第一个关键词 表示要定义的事物属于哪个大类,是变量,还是常量,还是本身就是一个类型 
第二个关键词 表示要定义的事物的名称 
第三个关键词 表示细分的数据类型,是简单类型数字,还是复合类型 字符串,结构体等  

package main 
import (
	"fmt"
)

type Student struct {
    id int 
    name string
}

func (st *Student) ShowName(){
	st.name = "花开12瓣,瓣瓣为一生"
	fmt.Println(st.name)
}

func main(){
	s1 := Student{}
	s1.ShowName()
}

go fmt及数字转化

常用格式化输出

 
package main 
import (
    "fmt"
)
func main(){
    fmt.Println("我来人间一趟")
    fmt.Printf("%s\n","本来无念无想")
    ss := fmt.Sprintf("%v","一入红尘就变了模样")
    println(ss)
}

%d 表示十进制
%e 科学计数法,例如 -1.4e+11
%f 小数点
%o 表示八进制
%s 字符串表示(string类型或[]byte)
%p 十六进制内存地址,前缀ox
%v 通用格式,按数据本身的类型输出,比如是字符串,此时%v自动转为%s的效果

package main 
import (
	"fmt"
)

type Student struct {
    id int 
    name string
}

func main(){
	s1 := Student{id:1,name:"韩立"}
	
	fmt.Printf("%v\n",s1)   // {1 韩立}
	fmt.Printf("%+v\n",s1)  // {id:1 name:韩立}
	fmt.Printf("%#v\n",s1)  // main.Student{id:1, name:"韩立"}
	fmt.Printf("%T\n",s1)   // main.Student
}

数字之间及字符串的转化

 
package main
import (
    "fmt"
    "reflect"
    "strconv"
)

func  main()  {
    //查看一个数据的类型
    fmt.Println(reflect.TypeOf("123"))  // string
    fmt.Println(reflect.TypeOf(1.23))   // float64

    strconv.Atoi("123") // 字符串转数字 
    strconv.Itoa(123)  // 数字转字符串

    strconv.FormatUint(uint64(123), 8) // 10进制转8进制
    strconv.FormatUint(uint64(123), 16)// 10进制转16进制

    strconv.FormatFloat(float64(1.23), 'e', 4, 32) //10进制转float32,保留4位有效数字,e表示科学计算法
    strconv.FormatFloat(1.23, 'f', 4, 64)          //10进制转float64,保留4位有效数字,f表示浮点数 
}

go连接oracle

依赖库

 
github.com/godror/godror
database/sql

客户端安装

 
oracle客户端,instantclient-basic-linux.x64-11.2.0.4.0.zip
rpm -qa | grep libaio
yum install libaio

动态库设置:
sudo sh -c "echo /opt/app/instantclient_11_2 > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
$ cat /etc/ld.so.conf.d/oracle-instantclient.conf
/opt/app/instantclient_11_2

go build

 
root@kl:/opt/wks/gowks/src/cmd# dcService -c /etc/dc.cnf
dcService: /usr/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by dcService)
dcService: /usr/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by dcService)

# ldd --version
ldd (Ubuntu GLIBC 2.31-0ubuntu9.7) 2.31

# gcc -dumpversion
9

当初build时的glibc版本高于现在运行的

所以,build的glibc版本不要太高,不要高于使用者的glibc版本

 

    

 

    

简记

 
$ go tool dist list | grep windows
windows/386
windows/amd64
windows/arm
windows/arm64

# 基础静态编译命令
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o app.exe main.go

CGO_ENABLED=0	禁用 CGO,确保静态链接(不依赖 mingw-w64)
GOOS=windows	目标操作系统:Windows
GOARCH=amd64	目标架构:64位(常用)可选:386 (32位), arm64 (ARM64)
-ldflags="-s -w"	-s:去除符号表 -w:去除调试信息,可减小体积约 30%
-o app.exe	   输出文件名(必须带 .exe 后缀)
    

示例

 
cd /ai/wks/gowks/src/cmd/fibu2
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o fibu.exe fibu2.go
    

参考

 
 我来详细介绍如何在 Ubuntu 上将 Go 程序交叉编译为 Windows 平台的静态可执行文件(包含所有依赖)。

## 核心命令

```bash
# 基础静态编译命令
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o app.exe main.go
```

---

## 参数详解

| 参数 | 说明 |
|------|------|
| `CGO_ENABLED=0` | **禁用 CGO**,确保静态链接(不依赖 mingw-w64) |
| `GOOS=windows` | 目标操作系统:Windows |
| `GOARCH=amd64` | 目标架构:64位(常用)
可选:`386` (32位), `arm64` (ARM64) | | `-ldflags="-s -w"` | `-s`:去除符号表
`-w`:去除调试信息
可减小体积约 30% | | `-o app.exe` | 输出文件名(必须带 `.exe` 后缀) | --- ## 完整步骤 ### 1. 环境准备(Ubuntu) ```bash # 确认 Go 已安装 go version # 查看当前支持的目标平台 go tool dist list | grep windows # 输出示例: # windows/386 # windows/amd64 # windows/arm # windows/arm64 ``` ### 2. 创建示例程序 ```go // main.go package main import ( "fmt" "net/http" "os" ) func main() { // 测试标准库功能 resp, err := http.Get("https://api.ip.sb/geoip") if err != nil { fmt.Println("网络请求失败:", err) os.Exit(1) } defer resp.Body.Close() fmt.Printf("状态码: %d\n", resp.StatusCode) fmt.Println("静态编译的 Windows EXE 运行成功!") } ``` ### 3. 编译命令详解 #### 基础版本(推荐) ```bash CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o myapp.exe main.go ``` #### 极致压缩版本(使用 UPX) ```bash # 先安装 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% ``` #### 带版本信息的发布版本 ```bash 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`) ```bash # 查看文件类型 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 ``` --- ## 常见问题解决 ### ❌ 问题 1:使用了 CGO 依赖(如 SQLite、图形库) **错误提示**: ``` undefined: sqlite3.Conn ``` **解决方案**: ```bash # 方案 A:更换纯 Go 实现库 # 例如 sqlite → modernc.org/sqlite(纯 Go) # 方案 B:安装 mingw-w64 进行交叉编译(不推荐,依赖复杂) sudo apt-get install mingw-w64 CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build ... ``` ### ❌ 问题 2:需要 Windows 图标和 manifest **解决方案**(使用 goversioninfo): ```bash # 安装工具 go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@latest # 创建 versioninfo.json 定义图标和版本信息 # 然后生成资源文件 goversioninfo -icon=app.ico -manifest=myapp.exe.manifest # 编译(会自动嵌入资源) CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o myapp.exe ``` ### ❌ 问题 3:32位 Windows 兼容性 ```bash # 编译 32 位版本(兼容 Windows 7/XP) CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-s -w" -o myapp_x86.exe main.go ``` --- ## Makefile 模板(生产环境) ```makefile # Makefile BINARY_NAME=myapp VERSION=1.0.0 BUILD_TIME=$(shell date +%Y%m%d%H%M%S) # 编译标志 LDFLAGS=-s -w -X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME) .PHONY: all windows windows-x86 clean all: windows # 64位 Windows(主流) windows: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="$(LDFLAGS)" -o bin/$(BINARY_NAME)_amd64.exe . # 32位 Windows(兼容旧系统) windows-x86: CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="$(LDFLAGS)" -o bin/$(BINARY_NAME)_386.exe . # ARM64 Windows(Surface Pro X 等) windows-arm64: CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -ldflags="$(LDFLAGS)" -o bin/$(BINARY_NAME)_arm64.exe . clean: rm -rf bin/ # 一键打包所有架构 release: clean windows windows-x86 windows-arm64 @echo "所有版本编译完成:" @ls -lh bin/ ``` 使用: ```bash make release ``` --- ## 关键要点总结 | 要点 | 说明 | |------|------| | **必须禁用 CGO** | `CGO_ENABLED=0` 是静态编译的核心 | | **无需安装 mingw** | 纯 Go 代码不需要 Windows 编译器 | | **标准库全支持** | `net/http`, `crypto/tls`, `database/sql` 等都能静态编译 | | **第三方库注意** | 确认依赖库是否为纯 Go(查看 `go.mod` 中是否有 `C` 代码) | | **体积优化** | `-ldflags="-s -w"` + UPX 可将 10MB 程序压缩到 3MB | 这样编译出的 `exe` 文件可以在任何 Windows 系统(7/10/11/Server)上直接运行,无需安装 Go 运行时或任何 DLL。

 
gitee.com/tanpf/gin/dc/client 
  → gitee.com/tanpf/tools 
    → github.com/ThomasRooney/gexpect (依赖 CGO 的 expect 库)

gexpect 是一个用于自动化交互式命令行的库,底层依赖系统的 C 库,无法静态编译。


详细

 

 这个错误是因为 `github.com/ThomasRooney/gexpect` 库使用了 CGO(调用了 C 语言的 expect 库),而你设置了 `CGO_ENABLED=0` 禁用了 CGO,导致编译失败。

## 问题根源

```
gitee.com/tanpf/gin/dc/client 
  → gitee.com/tanpf/tools 
    → github.com/ThomasRooney/gexpect (依赖 CGO 的 expect 库)
```

`gexpect` 是一个用于自动化交互式命令行的库,底层依赖系统的 C 库,无法静态编译。

---

## 解决方案

### 方案 1:替换为纯 Go 实现的交互式命令行库(推荐)

找到 `gitee.com/tanpf/tools` 中使用 `gexpect` 的地方,替换为纯 Go 库:

| 原库 | 替换为 | 说明 |
|------|--------|------|
| `github.com/ThomasRooney/gexpect` | `github.com/creack/pty` + `os/exec` | 纯 Go 实现 PTY |
| | `github.com/google/goexpect` | Google 的纯 Go expect 实现 |
| | `github.com/alessio/shellescape` | 简单的命令转义 |

**示例替换**:
```go
// 原代码(使用 gexpect)
import "github.com/ThomasRooney/gexpect"
child, _ := gexpect.Spawn("ssh user@host")
child.Expect("password:")
child.SendLine("mypass")

// 新代码(使用 creack/pty)
import (
    "github.com/creack/pty"
    "os/exec"
)
cmd := exec.Command("ssh", "user@host")
ptmx, _ := pty.Start(cmd)
// 读写 ptmx 实现交互
```

### 方案 2:条件编译(隔离 CGO 依赖)

修改 `gitee.com/tanpf/tools` 的代码,使用**构建标签**隔离 CGO 依赖:

```go
// +build cgo

// tools_cgo.go
package tools

import "github.com/ThomasRooney/gexpect"

func UseExpect() {
    // 使用 gexpect 的代码
}
```

```go
// +build !cgo

// tools_nocgo.go
package tools

import "errors"

func UseExpect() error {
    return errors.New("expect 功能需要启用 CGO 编译")
}
```

这样 `CGO_ENABLED=0` 时会自动选择无 CGO 的实现。

### 方案 3:使用 mingw-w64 交叉编译(保留 CGO)

如果你必须使用 `gexpect`,可以安装 Windows 编译器:

```bash
# 安装 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`,不是纯静态。

**完全静态化(需额外参数)**:
```bash
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
```

### 方案 4:移除或替换依赖库

检查你的代码是否真的需要 `gitee.com/tanpf/gin/dc/client` 中的 expect 功能:

```bash
# 查看依赖关系
go mod why github.com/ThomasRooney/gexpect

# 查看哪些文件导入了它
grep -r "gexpect" /ai/wks/gowks/pkg/mod/gitee.com/tanpf/tools*
```

如果不需要该功能,可以:
1. Fork `gitee.com/tanpf/tools` 移除 expect 相关代码
2. 使用 `replace` 指令替换为修改后的版本

```go
// go.mod
replace gitee.com/tanpf/tools => github.com/yourname/tools v0.0.1
```

---

## 快速诊断命令

```bash
# 1. 确认哪些包需要 CGO
go list -f ': ' -deps . | grep -v "[]$"

# 2. 查看 gexpect 的依赖
go mod graph | grep gexpect

# 3. 尝试找出替代路径
go mod why -m github.com/ThomasRooney/gexpect
```

---

## 推荐解决路径

1. **首选**:联系 `gitee.com/tanpf/tools` 维护者,建议替换为 `github.com/google/goexpect`(纯 Go)
2. **次选**:Fork 后自行修改,移除 expect 功能或使用条件编译
3. **备选**:如果 expect 是核心功能且必须保留,使用 mingw 编译并接受 DLL 依赖,或在 Linux 服务器端运行该功能

需要我帮你查看具体的替换代码实现吗?

 


 

  

 


参考文章
    
    oracle客户端下载-夸克网盘