TMaize Blog

GO的包管理和构建

在刚学 Go 的时候,尤其是之前有学过 Java 的时候,会对 Go 的导包感觉优点奇怪

首先要明确的是,Go 导入的是文件夹(文件夹下的 package),Java 导入的是具体的文件

当然了关于 Java 上的别名,静态导入,匿名类加载在 Go 上都有这些都有,知识语法不同,概念上也没啥区别

// Go的导包
import (
    "fmt"
    "github.com/opesun/goquery"
)

//Java的导包
import org.dom4j.DocumentException;

比如经常导入的 fmt 来分析

GO 编译器依次会去 GOROOT/src,GOPATH1/src,GOPATH2/src … 下去寻找名为 fmt 的文件夹

下面有许多的 go 文件,所有的以大写开头的变量,函数,结构等等的都会被导出

fmt.Println()的 Println 其实是 print.go 里的一个方法

那么疑问又来了,每个 Go 文件的第一行都会写 package xxx,那么这又是做什么用的呢

其实严格意义上说 Go 语言导入的包后,是通过 package name 来使用

fmt 文件夹下的所有 go 文件的第一行都是package fmt,包名与文件夹名是相同的,所以体现不出来,当然包名和文件夹名相同是一种规范的做法

比如这么一个文件 tmaize.net/demo/haha/Print.go,我们的包名设为 common

package common
import "fmt"
func P(msg string){
    fmt.Println(msg)
}

那么使用的时候

import "tmaize.net/demo/haha"
haha.P("Hello World")   //报错
common.P("Hello World") //这才是对的

所以:这就很好理解为什么一个文件夹下所有的 go 文件(一级目录)的 package name 只能取同一个名字了

为什么这么设计我个人理解应该是划分模块避免单个文件过大,抑或是容易针对单个文件做测试案例?

通过下面是 Java 和 Go 的 dmeo 应该比较容易看出来

Go

common/func1.go
    package Common
    func Func1(){}

common/func2.go
    package Common
    func Func2(){}

Java

Common.java
public class Common {
    // 两个语言的命名规范真的是....
    public static void Func1() {}
    public static void Func2() {}
}

最后要注意的是最好不要使用 local import

如果使用了,那么针对项目go build tmaize.net/demo会报错的local import "./haha" in non-local package

local import 的主要用途是写简单的小脚本非项目,直接对文件进行 go run,go build 是没问题的

依赖管理

在看完包的时候,大致就应该明白了 Go 的依赖管理方式

当我们的项目需要依赖自己(不要使用相对路径)/别人项目时候,通过 import 很容易就能把别人的轮子导进来使用

GO 编译器依次会去 GOROOT/src,GOPATH1/src,GOPATH2/src … 下去我们 import 的路径

但是肯定会有这种情况,我们要用到 A 项目,但是 A 项目又依赖 B 项目,但是 A 项目在 GOPATH 是存在的,但是 B 项目我们没有,难道要自己找到 B 项目,然后手动放到 GOPATH 的 src 下吗?

这时候就应该有一个依赖管理工具了,比如 Java 的 Maven 和 Gradle

对应的 Java 的依赖管理工具就是 go get,使用 go get A 项目的时候会自动分析 A 项目的依赖,然后吧他们都下载到 GOPATH 的第一个路径中

但是问题又来了,go get 实际就是 get clone,下载的都是最新的,没办法指定版本,而且我们的两个项目依赖同一个第三方库的不同版本,依赖脱离于项目等等这些都是问题

为此,go 在后来的版本中加入了 vendor。就是优先从项目源码树根目录下的 vendor 目录查找代码,这样就吧依赖和项目合到一起了,类似于 NodeJs 的 node_modules 目录,但是指定版本来事没办法实现,只能手动到 vendor 目录下切换依赖版本

所以又有了 godep,glide,govendor 等工具

golang.org 的官方依赖无法安装

由于网络原因一些 golang.org 下的包无法,比如go get -u golang.org/x/tools/

其实是可以从 github 下载的,在 GOPATH 下的 src 目录下新建golang.org/x再在下面使用git clone拉取 github 上的镜像就行了

镜像地址:https://github.com/golang

项目构建

项目构建全靠 GOPATH,因此就要将这个项目添加到 GOPATH

GOPATH 可以配置多个的,windows 下使用;隔开,第一个 GOPATH 是用来 go get 安装全局的依赖之类的

项目下会有三个目录,分别是 src,bin,pkg

任意目录下 go build 比如 go install tmaize.net/demo 会在 src 的同级创建 pkg 目录,产生平台相关的归档文件

注意:也可以针对某个文件使用 go build,会直接产出可执行文件

go install 其实是 go build 多了一步骤,如果程序有 main 包会在 bin 目录下生成可执行文件 项目名.exe

交叉编译

所谓交叉编译不是跨平台,而是就是在一个平台上生成另一个平台上的可执行代码

Go 是支持交叉编译的,只需要设置两个环境变量就行了,下面是两个平台下的构建脚本

Windows 系统,build.bat

set GOOS=windows
set GOARCH=amd64
go build -o dist/win_demo.exe demo.go

set GOOS=linux
set GOARCH=amd64
go build -o dist/linux_demo demo.go

Linux 系统,build.sh,注意脚本的换行格式为 LF

#!/bin/bash
export GOOS=windows
export GOARCH=amd64
go build -o dist/win_demo.exe demo.go

export GOOS=linux
export GOARCH=amd64
go build -o dist/linux_demo demo.go