使用go语言开发项目的现状

很多公司都是使用go语言来开发程序,但是开发中以及最终交付的代码需要满足以下条件:

build.shbuild.sh/etc/profilegitgitgolandgolandgolandmain

国外网址可能不行,直接从以下网址下载即可

https://www.gomirrors.org

下载的时候需要注意以下几点:

apt-getbrewgolandgolangGOMODULE
Macbrew
# 查看go的路径
fh@Feihu-3 go % which go
/usr/local/bin/go

# 实际上,这是一个软连接
fh@Feihu-3 go % ls -l /usr/local/bin/go
lrwxr-xr-x  1 fh  admin  26  8 22 16:01 /usr/local/bin/go -> ../Cellar/go/1.16.6/bin/go
fh@Feihu-3 go %
# 这些信息是没有修改过的
# 如果修改过的环境变量,存放的路径是GOENV中
# 修改命令,eg:
# go env -w GO111MODULE=on
fh@Feihu-3 go % go env
GO111MODULE=""    # 模块管理,注意此项
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/fh/Library/Caches/go-build"
GOENV="/Users/fh/Library/Application Support/go/env" # 当前变更的记录环境变量路径
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/fh/go/pkg/mod" # 下载的第三方包的路径
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/fh/go" # GOPATH,视情况而定
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct" # 从某个域名去下载第三方包,一定修改
GOROOT="/usr/local/Cellar/go/1.16.6/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.16.6/libexec/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.16.6"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/8m/dwtpjrx55ks5tbh3x08ln6wh0000gn/T/go-build60378254=/tmp/go-build -gno-record-gcc-switches -fno-common"

# 没有设置网络上的GOROOT、GOPATH等环境变量
fh@Feihu-3 go % echo $GOROOT

fh@Feihu-3 go % echo $GOPATH

fh@Feihu-3 go %
build.shgoland
GO111MODULE # 当前使用go.mod,配置为on
GOMODCACHE  # 修改,否则会从默认的去找 
GOPROXY     # 必须修改,否则下载会遇到问题
GOPATH			# 当前使用go.mod,不修改
代码结构
tree
RMB
fh@Feihu-3 RMB % tree
.
├── build
│   └── darwin
│       └── amd64
│           └── bin
│               ├── dn
│               ├── glog_demo
│               └── meta
├── pkg
│   └── mod
│       ├── cache
│       │   └── download
│       │       └── github.com
│       │           └── golang
│       │               └── glog
│       │                   └── @v
│       │                       ├── list
│       │                       ├── list.lock
│       │                       ├── v1.0.0.info
│       │                       ├── v1.0.0.lock
│       │                       ├── v1.0.0.mod
│       │                       ├── v1.0.0.zip
│       │                       └── v1.0.0.ziphash
│       └── github.com
│           └── golang
│               └── glog@v1.0.0
│                   ├── LICENSE
│                   ├── README.md
│                   ├── glog.go
│                   ├── glog_file.go
│                   ├── glog_test.go
│                   └── go.mod
└── src
    ├── base
    │   └── log
    │       └── log.go
    ├── build.sh
    ├── cmd
    │   ├── demo
    │   │   └── glog_demo.go
    │   └── server
    │       ├── dn.go
    │       ├── meta.go
    │       └── version.go
    ├── go.mod
    └── go.sum

21 directories, 24 files
RMB
# RMB下分为三个目录:
# src:存放自己编写的代码
# pkg: 第三方包
# build:生成的可执行文件

# 其中功能如下:
# 1. 调用glog第三方库,编写glog_demo,路径是RMB/build/darwin/amd64/bin/glog_demo
# 2. 生成meta可执行文件,路径是RMB/build/darwin/amd64/bin/meta
# 3. 生成dn可执行文件,路径是RMB/build/darwin/amd64/bin/dn
# 4. 在编译的时候,自动将git的信息、构建日期等传递到可执行文件中
# 5. 封装go语言的log,并测试
开发流程
RMB
RMB
RMBgo init rmbgo.modgo.modbuildgo.modgo.sum
mainbuild.sh
mainbuild.sh
# version.go隶属于main包
# meta.go、dn.go和version必须要放到同一个目录下
# 同一个包调用不同文件问题,后面继续说
fh@Feihu-3 RMB % ls src/cmd/server/*
src/cmd/server/dn.go		src/cmd/server/meta.go		src/cmd/server/version.go
#! /bin/bash

# 执行的命令中,返回非0错误码即退出,不再执行后面内容
set -e

# 增加调试信息,执行的时候会打印所有的信息,真实环境会注释掉
set -x

# build.sh放在src目录下,获取RMB/src的路径
PROJ_SRC="$(cd "$(dirname "$0")"; pwd -P)"

# src目录的上级就是RMB路径
PROJ_ROOT="$(cd "$(dirname "$PROJ_SRC")"; pwd -P)"

# build路径: RMB/build
PROJ_BUILD=${PROJ_ROOT}/build

# 环境变量设置,通过go env GOROOT获取
export GOROOT=$(go env GOROOT)

# 下载包路径,默认是下载失败的,主要是给go get使用
export GOPROXY=https://goproxy.io

# 下载的第三方包路径,并自动从这里查找
export GOMODCACHE=${PROJ_ROOT}/pkg/mod

# 开启模块
export GO111MODULE="on"

# 清空RMB/build目录
rm -rf "${PROJ_BUILD}"
mkdir -p "${PROJ_BUILD}"

# 代码格式化,例如:Tab、大括号等格式
# 帮助可查gofmt -h
gofmt -l -w -s "${PROJ_SRC}"

# 标记,通过脚本将这些信息扔到代码里面去
# 这段代码来自etcd的Makefile,并加以修改,其实也只是version.go里面传参数
# 内容是:软件版本、GO系统、GO架构、git的提交、构建日期、go版本、构建者
# 由于本人未使用git,请将gitCommit的值换成下面提到的命令即可
LD_FLAGS=" \
    -X main.rmbBuilderVersion='1.3.2' \
    -X main.goos=$(go env GOOS) \
    -X main.goarch=$(go env GOARCH) \
    -X main.gitCommit='adfjlkdf' \
    -X main.buildDate=$(date +'%Y-%m-%dT%H:%M:%SZ') \
    -X main.goversion=$(go env GOVERSION) \
    -X main.builder=$(whoami) \
    "

# -o: 生成的可执行文件路径,RMB/build/darwin/amd64/bin/meta
# -a: 强制重新构建包
# -race: 	开启数据竞态检测
# 注意: go build的最后一项是main函数所在的文件以及version文件
# 不增加version.go会失败,因为version.go里面的符号未提前生成,导致查询失败
go build -o "${PROJ_BUILD}"/$(go env GOHOSTOS)/$(go env GOHOSTARCH)/bin/meta \
         -a \
         -race \
         -ldflags "-X main.buildDate=$(date +'%Y-%m-%dT%H:%M:%SZ') \
                   -X main.goos=$(go env GOOS) \
                   -X main.goarch=$(go env GOARCH) \
                  " \
         "${PROJ_SRC}"/cmd/server/version.go "${PROJ_SRC}"/cmd/server/meta.go

go build -o "${PROJ_BUILD}"/$(go env GOHOSTOS)/$(go env GOHOSTARCH)/bin/dn \
         -a \
         -race \
         -ldflags "${LD_FLAGS}" \
         "${PROJ_SRC}"/cmd/server/version.go "${PROJ_SRC}"/cmd/server/dn.go

go build -o "${PROJ_BUILD}"/$(go env GOHOSTOS)/$(go env GOHOSTARCH)/bin/glog_demo \
         -a \
         -race \
         "${PROJ_SRC}"/cmd/demo/glog_demo.go
LD_FLAGS=-ldflags " \
    -X main.kubeBuilderVersion=$(shell git describe --tags --dirty --broken) \
    -X main.goos=$(shell go env GOOS) \
    -X main.goarch=$(shell go env GOARCH) \
    -X main.gitCommit=$(shell git rev-parse HEAD) \
    -X main.buildDate=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') \
    "

下载第三方包

我们在配置好了之后,一般是先提前下载第三方包,再去写代码,因为我们需要有代码提示,例如:

# 下载的包路径根据GOMODCACHE 来确定
# 后面查找的时候,也是从GOMODCACHE来找
# 所以,需要在环境变量里面设置GOMODCACHE路径
go get github.com/golang/glog
demo
package main

import (
	"flag"
	"fmt"
	"github.com/golang/glog"
)

func main() {
	flag.Parse()
	defer glog.Flush()

	glog.Info("Fish")
	glog.Infof("I like fish, value: %v", "mnkojj")

	fmt.Println("xx")
}

本工程代码的连接如下:

# 之前写的,可根据编译脚本来做调整
https://download.csdn.net/download/wfh2015/21710635

编译结果:

fh@Feihu-3 src % ./build.sh
go: downloading github.com/golang/glog v1.0.0  # 在有网却缺少库的情况,自动下载
fh@Feihu-3 src % tree ../build
../build
└── darwin
    └── amd64
        └── bin
            ├── dn
            ├── glog_demo
            └── meta

3 directories, 3 files
fh@Feihu-3 src % go mod tidy
fh@Feihu-3 src % go mod verify
all modules verified
fh@Feihu-3 src % go mod graph
rmb github.com/golang/glog@v1.0.0
fh@Feihu-3 src % go mod why
fh@Feihu-3 src %

至于其他的命令像什么,就不用说了:

go mod tidy
go mod graph
go mod verify
go mod graphv
GOMODCACHERMB

目前来看,不需要手动修改配置文件,基本满足在内网运行、DevOps运行的要求。

问题

同一个包调用不同文件的接口会报错

这个问题解决方法有两类:

# 脚本:
# 只需要将两个go文件同时放到go build 中即可,参考前面的build.sh脚本
# goland
# 1. [打开编辑配置] -> [运行种类] -> [文件]
# 2. [文件]所在行的[展开]按钮,增加多个文件,增加之后,编辑栏会有‘|’符号区分不同路径