Abel'Blog

我干了什么?究竟拿了时间换了什么?

0%

go[0]-入门

简介

学习golang的入门的信息;本章只记录一下golang语言的历史,go语言环境搭建,如何编译go语言程序。

历史

Go语言(或 Golang)起源于 2007 年,并在 2009 年正式对外发布。Go 是非常年轻的一门语言,它的主要目标是“兼具 Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性”。golang的 1.13 版本的时候,被gc被重新,将增加内存回收速度(2014-05)。

环境部署

官方网站

国内下载地址

Linux

1
2
3
4
5
6
tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
# 设置环境变量
/etc/bash.bashrc
$HOME/.bashrc
export PATH=$PATH:/usr/local/go/bin

Windows

直接通过安装包安装;

需要配置的环境变量

1
2
3
4
5
6
7
8
GOPATH=D:\\work\\gopath
# 配置 GOPROXY 环境变量
export GOPROXY=https://goproxy.io,https://goproxy.cn,direct
# 还可以设置不走 proxy 的私有仓库或组,多个用逗号相隔(可选)
export GOPRIVATE=git.mycompany.com,github.com/my/private
export GO111MODULE=on

go env -w GOPROXY=https://goproxy.cn,direct

linux环境搭建

先解压缩golang的包

1
2
3
tar -xf ./go.1.xxx.tar.gz -C /usr/local
# 可能需要删除掉之前的目录
rm -rf /usr/local/go/

升级的时候最好能将之前的目录都删除掉。

使用go env查询具体的环境信息。通过编辑~/.bashrc文件的环境变量来修改配置。

常用命令

go build

参数 说明 示例
-o 可执行文件名
-a 强制重编译所有包()包含标准库
-p 并行编译使用CPU核心数
-v 显示等待编译包名
-n 显示编译命令,但不执行
-x 显示正在执行的编译命令
-work 显示临时工作目录,完成后不删除
-race 启动数据竞争检查(旨在amd64
-gcflags 编译器参数
-ldflags 链接器参数
-race 开启DATA RACE检测

编译器选项:

参数 说明
-B 禁用越界检查
-N 禁用优化
-l 禁用内联
-u 禁用unsafe
-S 输出汇编代码
-m 输出优化信息,检查内存逃逸也可以通过这个来检查

ldflags:

参数 说明
-s 禁用符号表
-w 禁用DRAWF调试信息
-X 设置字符串全局变量值 -X ver=”0.99”
-H 设置可执行文件格式 -H windowsgui

详细参数可以通过:

1
2
go tool compile -h
go tool link -h

获取更多信息也可以直接到
src/cmd/[compile|link]
目录下阅读doc.go文档。

go install

参数和go build一致,只是将编译结果安装到bin/pkg目录中。go install支持增量编译。如果没有修改,将会直接链接pkg目录中的静态包。编译器用buildid检查文件清单和导入依赖。

在没有mod之前,有些项目都是通过go install来编译工程的,并且将GOBIN环境变量临时修改成发布目录,如果已经用上了mod方式,尽量使用go build来编译工程。

算法源码可以阅读

src/cmd/go/pkg.go

go get

下载第三方包到GOPATH列表中第一个工作目录。

参数 说明
-d 仅下载,不安装
-u 更新包,包括其依赖项
-f 和-u配合,强制更新,不检测过期与否
-t 下载测试代码所需的依赖包
-insecure 使用HTTP非安全协议
-v 输出详细信息verbose
-x 显示正在执行的命令

go env

显示全部环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\abel\AppData\Local\go-build
set GOENV=C:\Users\abel\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\main\code\fanghaoli\server
set GOPRIVATE=
set GOPROXY=https://goproxy.cn
set GOROOT=c:\go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=c:\go\pkg\tool\windows_amd64
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\abel\AppData\Local\Temp\go-build072770210=/tmp/go-build -gno-record-gcc-switches

go clean

清理工作目录,伤处编译和安装遗留的目标文件

参数 说明
-i 清理go install 安装的文件
-r 递归清理所有依赖包
-x 显示在执行的清理操作
-n 仅显示清理命令,不执行

编译

如果喜欢使用gdb调试,一般需要使用 -gcflags “-N -l”阻止优化和内联,否则调试的时候会找不到调试信息。
当发布是,参数-ldflags “-w-s”会让连机器剔除掉符号表和调试信息,除了可以减少可执行文件的大小外,还能稍微增加反编译的难度。可以借助工具来对可执行文件进行减肥upx

交叉编译

corss compile,就是在一个平台下出其他平台所需的可执行文件。只需要使用GOOS、GOARCH来调整环境变量指定平台和架构。
go env GOOS
使用go install命令为目标平台预编译好标准库,避免go build每次都完整编译。
交叉编译不支持cgo。

编写一个build_linux.bat文件。

1
2
3
set GOARCH=amd64
set GOOS=linux|windows|android|darwin|freebsd|netbsd|openbsd|solaris
go build

跨平台编译需要下载一些库。

1
2
3
4
https://github.com/golang/crypto.git
https://github.com/golang/net.git
https://github.com/golang/sys.git
https://github.com/golang/tools.git

解压缩之后放到这个目录下:

1
$GOPATH/src/golang.org/x

golang-how-to-cross-compile-on-linux-for-windows

  1. 如果没有动用过cgo,全部代码都是golang编写成的,就直接执行下面的命令就好了;
1
GOOS=windows GOARCH=amd64 go build
  1. 如果使用了cgo,这样你就需要使用mingw-w64编译器
1
2
3
4
5
6
7
8
9
10
11
12
sudo apt-get install gcc-multilib
sudo apt-get install gcc-mingw-w64

x86_64-w64-mingw32-gcc --version

GOOS=windows GOARCH=386 \
CGO_ENABLED=1 CXX=i686-w64-mingw32-g++ CC=i686-w64-mingw32-gcc \
go build -o xxx.exe

GOOS=windows GOARCH=amd64 CGO_ENABLED=1 \
CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc \
go build package-import-path

条件编译

编译器支持文件级别的条件编译。

1.将平台和架构信息添加到文件名尾部。

hello_darwin.go hello_linux.go 测试一下
GOOS=darwin.go build -x
将会只编译hello_darwin.go。
也可以对架构做条件
sys_arm64.go sys_darwin_3866.s sys_freebsd_amd64.s
文件名中可以使用GOOS,或者加上GOARCH。

2.使用build编译命令。

a.go

1
2
3
4
5
6
7
// +build windows
<---必须有空行

package main
func hello() {
println("xxxx")
}

b.go

1
2
3
4
5
6
// +build linux darwin
// +build 386,/!cgo

package main
....
}

3.使用自定义tag指令。

1
2
3
4
5
// +build !release
// +build log


go build-tags "release log" && ./xxxx

go mod

如何使用本地库

在本工程里面go.mod中写入这样的话,将本地下载好的工程引入。

1
replace gitee.com/zhenghexcs/bevtreestatus => D:\work\trunk\new_project_server\server\bevtreestatus

go vendor

最近有个项目的代码是使用的go1.13版本编写的,还使用了vendor来管理中三方依赖库。所以就开始使用这样的方式来处理。

基本用法

知乎的介绍

关闭module export GO111MODULE="off"

安装govendor go get -u -v github.com/kardianos/govendor

Error: Package "/home/franky/code/btcnode-master" not a go package or not in GOPATH.

这种情况是使用了老版本的golang,还想用新版本的指令安装程序造成的问题。只需要切换成最新版本。

将这个工程拷贝到正确的目录下。

老版本的golang管理这些工程的代码的时候,需要将代码拷贝到$HOME/go/src/github.com/yourname/project/目录下来运行编译。

如果需要调试的时候,需要在工程的根目录里面创建launch.json文件,里面将会说明启动的时候需要什么参数。

这个就是一个例子,定制了当前工程里面的/client子目录的调试方式。

使用老版本的golang需要将"dlvFlags": ["--check-go-version=false"]打开。

最新delve仅支持调试go1.14及以上版本的代码,但有时有需要用较低版本golang,不方便升级golang。新版本的调试器,能挂载到老版本的程序上调试的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/client",
"dlvFlags": ["--check-go-version=false"],
"args": ["--env", "local"]
}]
}

// 这种就是将当前文件调试:
"program": "${file}",

If you really don’t want to update your Go version, then you can downgrade your dlv version to 1.6, but I don’t see why you would want to go all the way back to 1.2.0 or 1.3.2 versions of dlv from 2019. Those are very old. Each version of dlv usually supports 3 versions of go - recent stable and 2 older versions. If you try using a version of Go that is older or newer than those 3 expected versions, you get the error above. You can suppress them and debugging would in general work, but some things might be off. You can observe the pattern from dlv release changelog:

1.7.0: Add Go 1.17, drop Go 1.14
1.6.0-1: Add Go 1.16, drop Go 1.13

1.3.0: Add Go 1.13
1.2.0: Add Go 1.12

老版本的go需要配合老版本的dlv否则会出现很多的问题。

could not open debug info - debuggee must not be built with ‘go run’ or -ldflags=’-s -w’, which strip debug info

查看-ldflags参数表:

ldflags:

参数 说明
-s 禁用符号表
-w 禁用DRAWF调试信息
-X 设置字符串全局变量值 -X ver=”0.99”
-H 设置可执行文件格式 -H windowsgui

很细碎,最终还是用了新版本的dlv挂载调试老版本的代码。

govendor

govendor-使用

可以考虑直接从网站上下载这个govendor程序。

golang <= 1.13 版本

这个版本的golang,使用的是vendor的包管理。

这次解决了一个问题:

问题:

  1. 源代码是 a.com 域名;代码目录下有个 vendor/b.com ; 代码中大量引用了 b.com/common/ 库;
  2. 将代码切到 ${GO_ROOT}/src/a.com/project 编译,将会让 a.com 下的 vendor/b.com 库无法被扫描到;
  3. 解决办法是将 ${GO_ROOT}/src/a.com/project 放到 ${GO_ROOT}/src/b.com/project 目录就可以了;
  4. 还有一个办法,将源代码中 b.com/common/ 修改成 c.com/common/ ;并且将 vendor/b.com 目录修改成 vendor/c.com

很啰嗦;

golang 1.13 调试器

这个版本需要自己手动下载delve版本。

https://github.com/go-delve/delve/archive/refs/tags/v1.7.3.tar.gz

手动编译了之后就能调试了。

调试器失灵

could not launch process: error reading debug_info: decoding dwarf section info at offset 0x94ca8b: DW_FORM_strx with no .debug_str_offsets section

go install github.com/go-delve/delve/cmd/dlv@master

https://stackoverflow.com/questions/78996918/getting-the-following-error-while-trying-to-debug-go-tests-in-vscode-on-mac

参考