本文更新时间: `2025-10-12`
- 本文的**目的**: 记录Go语言学习的一些特殊点,便于以后快速使用,免得学了又忘了
## 一般编译方法
- 编译环境: win7 x64(可以在其他环境例如linux,安卓termux,下载对应的平台版本即可)
- 下载: https://golang.google.cn/dl/go1.17.2.windows-amd64.zip
- 解压到: D:\,即存在D:\go
- 下载项目源码: https://github.com/linpinger/reverse-ssh ,可以点击按钮Code,Download Zip来下载,或使用 `git clone https://github.com/linpinger/reverse-ssh.git`
- 将压缩文件解压到 D:\,即存在D:\reverse-ssh-master
- 打开cmd命令行(linux打开shell,下面的set改为export,路径改成实际路径)设置环境变量
```bat
echo 以下4行非必要,它的目的是建个临时文件夹,go编译项目的时候会将临时文件生成到这里
mkdir D:\go-tmp
set GOCACHE=D:\go-tmp
set TEMP=D:\go-tmp
set TMP=D:\go-tmp
echo 设置PATH变量,目的是在命令行下能找到go.exe
set PATH=D:\go\bin;%PATH%
echo 解压go1.17.2.windows-amd64.zip后的go目录
set GOROOT=D:\go
echo GOPATH据说会取消,目前是放项目的目录,编译时会生成bin pkg src 目录,自己的项目,可以放在src目录下
set GOPATH=D:\myGoPrj
echo 这是国内代理,方便下载go依赖库
set GOPROXY=https://goproxy.cn,direct
echo 设置编译目标平台及架构 例如 windows linux amd64 386 arm64,默认生成当前平台
set GOOS=windows
set GOARCH=amd64
echo go build -ldflags "-s -w"
```
- 命令行下进入项目目录 cd /d D:\reverse-ssh-master
- 执行 go mod tidy 以下载依赖的库
- 下载完毕,执行 go build 即可编译成exe,若要减小体积执行 go build -ldflags "-s -w",若要交叉编译成linux下的程序 设置环境变量GOOS 和 GOARCH然后再执行go build
- 其他:有些程序依赖gcc来编译c或c++文件,win下需要下载minGW64,linux下就简单些
- 目前的go版本在win下,起码是win7,若要编译为xp下可用的exe,需使用老版本的go,测试这个版本可以 https://golang.google.cn/dl/go1.11.13.windows-amd64.zip
- 编译时若出错,根据出错信息排查,可能是项目源码及依赖源码使用的是新的库,在D:\go\src下找出新老版本的差异来解决问题
### 2021-03-18 golang升级到1.16后的一些变化(对于个人的)
- `io/ioutil`中的函数转移到`io`和`os`包中,尽管目前还能用
- `embed` 包很有意思,可以嵌入资源文件到二进制文件中,目前还没用上,但很有兴趣
- `GO111MODULE`变量的值现在默认为`on`,实际影响很大,习惯了使用旧版自己下载依赖库的我被玩坏了,需要适应新的module机制
- `go mod init xxx`用来初始化模块,不然无法编译了,除非把`GO111MODULE`设为off,不过据说下个版本会取消,到时候就蛋疼了
- `go mod tidy` 会下载依赖的包,放到`$GOPATH/pkg`下
- `go mod vendor` 会复制已下载的包到vendor文件夹下,这样就可以修改该库了,这个未测试,头疼
- `git tag v0.1.0` 学会打tag,推送 `git push --tags`
- `export GOPROXY=https://goproxy.cn,direct` 可以加速下载module,当然翻一下也可以
### 2020-12-31 编译为安卓上可以调用的库
- android自己写的apk下运行自己编译的elf貌似路被堵死了(不知道android terminal是个怎么原理),目前只有走jni/NDK这条路了,测试了一下是可以,不过那个cpp语言看起来很麻烦,搜到了据说jna可以简化,不过cpp不是强项,还是用golang方便
- 参考: (https://www.jianshu.com/p/fff1be6484c6)
- 上面链接中的文章有几个细节有问题,最好还是看官方文档吧 (https://github.com/golang/go/wiki/Mobile)
- 整理后步骤如下:
- 设置环境变量(注意,ndk的版本,22.x版本编译会出错,目前测试21.1这个正常)及代理,`golang.org`被Q了,要下源码需要翻一下Q,可以用小飞机或v2rayN之类的
- 1.16以上: 清除GOPROXY变量的内容,使用小飞机(),删除pkg文件夹,保障成功率,怀疑gomobile每次运行都下载依赖到gocache里面,而不是和pkg里面共用mod,过程会调用go mod tidy来下载依赖,编译过程会调用cgo和ndk里面的clang来进行编译项目,故ndk不可缺少
```shell
export ANDROID_HOME=D:\\bin\\java\\AndroidSDK
export ANDROID_NDK_HOME=D:\\bin\\java\\AndroidSDK\\ndk\\21.1.6352462
export http_proxy=http://127.0.0.1:10809
export https_proxy=http://127.0.0.1:10809
git config --global http.proxy 'http://127.0.0.1:10809'
git config --global https.proxy 'http://127.0.0.1:10809'
```
- `go get golang.org/x/mobile/cmd/gomobile`
- `go build golang.org/x/mobile/cmd/gomobile`
- `go build golang.org/x/mobile/cmd/gobind`
- 把生成的`gomobile.exe` `gobind.exe`放到`go.exe`所在bin文件夹
- 按照golang的规则写一个go文件,注意包名不要是main哦,然后函数第一个字母大写,毕竟是要给android调用的,例如`github.com/linpinger/foxbook-golang/fox`
- `gomobile bind -target=android -ldflags "-s -w" fox`
- 可能会提示: `go get golang.org/x/mobile/bind`,执行一下
- 这样会生成`fox.aar`和`fox-sources.jar`
- 在android工程创建和src同级的libs文件夹,将fox.aar放到这里
- 修改build.gradle:
- `android`内添加`ndkVersion "21.1.6352462"`
- `android`内添加`dependencies { implementation fileTree(dir: 'libs', include: ['*.jar','*.aar']) }`
- `android/defaultConfig`内修改`minSdkVersion 15`,可选添加`ndk { abiFilters "arm64-v8a", "armeabi-v7a" // arm64-v8a、armeabi-v7a、x86_64、x86 }`
- 同步一下,java里调用比较简单了: `import fox.Fox; Fox.startHTTPServer("8080", "/sdcard/", "", "", true, true, false);`
### 2020-12-28 编译为安卓上可以执行的程序碰到的坑
- 编译时设置环境变量`GOOS`和`GOARCH`为`android`和`arm64`,会错误,不知道以后能不能改善,改成`linux`和`arm64`就可以编译通过
- 编译通过后会发现: 使用go自带的库进行http访问,会找不到站点,原因就是go的src目录下的`dnsconfig_unix.go`的第40行`dnsReadConfig`使用的是linux平台的方式去处理域名转ip,android平台有点不一样,所以需要把这个函数扩展一下
- 解决方法来自: (https://github.com/golang/go/issues/8877)
- 操作方法,替换这行: `func dnsReadConfig(filename string) *dnsConfig {` 为:
```golang
func dnsReadConfig(filename string) *dnsConfig {
if _, err := os.Stat("/system/bin/getprop"); err == nil {
return dnsReadConfigAndroid()
} else {
return dnsReadConfigUnix(filename)
}
}
func dnsReadConfigAndroid() *dnsConfig {
conf := &dnsConfig{
ndots: 1,
timeout: 5 * time.Second,
attempts: 2,
rotate: false,
}
for _, prop := range []string{"net.dns1", "net.dns2"} {
out, err := exec.Command("/system/bin/getprop", prop).Output()
if err != nil {
continue
}
ip := strings.TrimSpace(string(out))
if ParseIP(ip) != nil {
conf.servers = append(conf.servers, JoinHostPort(ip, "53"))
}
}
if len(conf.servers) == 0 {
conf.servers = []string{"119.29.29.29:53", "168.95.1.1", "8.8.8.8:53", "8.8.4.4:53", "4.2.2.1:53"}
}
return conf
}
// See resolv.conf(5) on a Linux machine.
func dnsReadConfigUnix(filename string) *dnsConfig {
```
- 另外在头部的import中加入两行依赖
```golang
"os/exec"
"strings"
```
- 然后重新编译一下,就可以在android下正常下载网页了
### 2018-06-12 交叉编译
- 原来go支持交叉编译,本人之前还傻傻的在多个平台上去编译,WTF
```shell
#! /bin/bash
export PATH="/dev/shm/go/bin:$PATH"
export GOROOT="/dev/shm/go"
# export GOPATH="/dev/shm"
export GOPATH="$HOME"
export GOARCH=amd64
export GOOS=linux
echo "- $GOOS $GOARCH"
go build -o foxbook-golang-x64-linux.elf -ldflags "-s -w" github.com/linpinger/foxbook-golang
export GOARCH=386
export GOOS=linux
echo "- $GOOS $GOARCH"
go build -o foxbook-golang-x86-linux.elf -ldflags "-s -w" github.com/linpinger/foxbook-golang
export GOARCH=amd64
export GOOS=windows
echo "- $GOOS $GOARCH"
go build -o foxbook-golang-x64.exe -ldflags "-s -w" github.com/linpinger/foxbook-golang
export GOARCH=386
export GOOS=windows
echo "- $GOOS $GOARCH"
go build -o foxbook-golang-x86.exe -ldflags "-s -w" github.com/linpinger/foxbook-golang
export GOARCH=amd64
export GOOS=darwin
echo "- $GOOS $GOARCH"
go build -o foxbook-golang-x64-MacOSX.bin -ldflags "-s -w" github.com/linpinger/foxbook-golang
echo "- zip all"
zip -9 foxbook-golang-bin.zip foxbook-golang-*
echo "# done"
```
### 包组织
- 当前项目的工作目录就是 环境变量 GOPATH 定义的目录,该目录下有 src, pkg, bin 子目录
- `GOPATH=c:\go_a\;d:\xxx\`
- `GOPATH=/home/fox/go_a:/dev/shm/00/`
- `package main`
- `import "fmt"`
- `import "github.com/axgle/mahonia"`
- 可以通过 `go get github.com/axgle/mahonia` 下载 该包 会在 GOPATH 下的src目录中存放
### 变量与运算符
- 结构体是值类型,在函数调用时,像切片(slice)、字典(map)、接口(interface)、通道(channel)这样的引用类型都是默认使用引用传递
- 大小写敏感,大小写影响变量及函数的作用范围,头字母小写算局部变量,头字母大写算全局变量,具体搜索一下
- 变量定义:
```go
html := "aaa"
var p = fmt.Println // alias, 可放在main函数外
var html string
var html string = "aaa"
var html1, html2, html3 string
var html1, html2, html3 string = "aaa", "bbb", "ccc"
html1, html2, html3 string := "aaa", "bbb", "ccc"
```
- `true` `false`
- `nil`
- `==` `!=`
- `&&` `||` `!`
- `=` `+=` `-+` `*=` `/=`
### 字符串
- 字符串与byte数组可互相转换: `str := string(bts)` `bts := []byte(str)`
- 当byte数组没有填满,但需要转换为字符串: `str := string(data[0:5])` ,这里的0:5就是数组实际有效的长度,在socket编程里面常见
- 字符串连接符: `str1 + str2`
- 字符串函数: 见包 [strings](https://golang.google.cn/pkg/strings/)
- 是否包含: `if strings.Contains(iStr, "