搬运自github赫林的go_command_tutorial,绝对干货,感谢作者。


0.2 go install

命令Go install用于编译并安装指定的代码包及它们的依赖包。当指定的代码包的依赖包还没有被编译和安装时,该命令会先去处理依赖包。与go build命令一样,传给go install命令的代码包参数,应该以导入路径的形式提供。并且,go build命令的绝大多数标记也都可以用于go install命令。实际上,go install命令只比go build命令多做了一件事,即:安装编译后的结果文件到指定目录。

在对go install命令进行详细说明之前,让我们先回顾一下goc2p的目录结构。为了节省篇幅,我们在这里隐藏了代码包中的源码文件。如下:

$HOME/golang/goc2p:bin/pkg/src/cnet/logging/helper/ds/pkgtool/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们看到,goc2p项目中有三个子目录,分别是bin目录、pkg目录和src目录。现在只有src目录中包含了一些目录,而其他两个目录都是空的。

现在,我们来看看安装代码包的规则。

安装代码包

如果go install命令后跟的代码包中仅包含库源码文件,那么go install命令会把编译后的结果文件保存在源码文件所在工作区的pkg目录下。对于仅包含库源码文件的代码包来说,这个结果文件就是对应的代码包归档文件。相比之下,我们在使用go build命令对仅包含库源码文件的代码包进行编译时,是不会在当前工作区的src目录和pkg目录下产生任何结果文件的。结果文件会出于编译的目的被生成在临时目录中,但并不会对当前工作区目录产生任何影响。

如果我们在执行go install命令时不后跟任何代码包参数,那么命令将试图编译当前目录所对应的代码包。比如,我们现在要安装代码包pkgtool

hc@ubt:~/golang/goc2p/src/pkgtool$ go install -v -work
WORK=D:\cygwin\tmp\go-build758586887
pkgtool
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

我们刚刚说过,执行go install命令后会对指定代码包先编译再安装。其中,编译代码包使用了与go build命令相同的程序。所以,执行go install命令后也会首先建立一个名称以go-build为前缀的临时目录。如果我们想强行重新安装指定代码包及其依赖包,那么就需要加入标记-a:

hc@ubt:~/golang/goc2p/src/pkgtool$ go install -a -v -work
WORK=/tmp/go-build014992994
runtime
errors
sync/atomic
unicode
unicode/utf8
sort
sync
io
syscall
bytes
strings
time
bufio
os
path/filepath
pkgtool
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

可以看到,代码包pkgtool仅仅依赖了标准库中的代码包。

现在我们再来查看一下goc2p项目目录:

$HOME/golang/goc2p:bin/pkg/linux_386/pkgtool.asrc/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

现在pkg目录中多了一个子目录。读过本书第二章的读者应该已经知道,linux_386被叫做平台相关目录。它的名字可以由${GOOS}_${GOARCH}来得到。其中,${GOOS}${GOARCH}分别是环境变量GOOS和GOARCH的值。上述示例在计算架构为386()且操作系统为Linux的计算机上运行。所以,这里的平台相关目录即为linux_386。我们还看到,在goc2p项目中的平台相关目录下存在一个文件,名称是pkgtool.a。这就是代码包pkgtool的归档文件,文件名称是由代码包名称与“.a”后缀组合而来的。

实际上,代码包的归档文件并不都会被保存在pkg目录的平台相关目录下,还可能被保存在这个平台相关目录的子目录下。 下面我们来安装cnet/ctcp包:

hc@ubt:~/golang/goc2p/src/pkgtool$ go install -a -v -work ../cnet/ctcp
WORK=/tmp/go-build083178213
runtime
errors
sync/atomic
unicode
unicode/utf8
math
sort
sync
io
syscall
bytes
strings
bufio
time
strconv
math/rand
os
reflect
fmt
log
runtime/cgo
logging
net
cnet/ctcp
  • 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
  • 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

请注意,我们是在代码包pkgtool对应的目录下安装cnet/ctcp包的。我们使用了一个目录相对路径。

实际上,这种提供代码包位置的方式被叫做本地代码包路径方式,也是被所有Go命令接受的一种方式,这包括之前已经介绍过的go build命令。但是需要注意的是,本地代码包路径只能以目录相对路径的形式呈现,而不能使用目录绝对路径。请看下面的示例:

hc@ubt:~/golang/goc2p/src/cnet/ctcp$ go install -v -work ~/golang/goc2p/src/cnet/ctcp
can't load package: package /home/hc/golang/goc2p/src/cnet/ctcp: import "/home/hc/golang/goc2p/src/cnet/ctcp": cannot import absolute path
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

从上述示例中的命令提示信息我们可以看到,以目录绝对路径的形式提供代码包位置是不会被Go命令认可的。

这是由于Go认为本地代码包路径的表示只能以“./”或“../”开始,再或者直接为“.”或“..”。而代码包的代码导入路径又不允许以“/”开始。所以,这种用绝对路径表示代码包位置的方式也就不被支持了。

上述规则适用于所有Go命令。读者可以自己尝试一下,比如在执行go build命令时分别以代码包导入路径、目录相对路径和目录绝对路径的形式提供代码包位置,并查看执行结果。

我们已经通过上面的示例强行的重新安装了cnet/ctcp包及其依赖包。现在我们再来看一下goc2p的项目目录:

$HOME/golang/goc2p:bin/pkg/linux_386//cnetctcp.alogging.apkgtool.asrc/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们发现在pkg目录的平台相关目录下多了一个名为cnet的目录,而在这个目录下的就是名为ctcp.a的代码包归档文件。由此我们可知,代码包归档文件的存放路径的相对路径(相对于当前项目的pkg目录的平台相关目录)即为代码包导入路径除去最后一个元素后的路径。而代码包归档文件的名称即为代码包导入路径中的最后一个元素再加“.a”后缀。再举一个例子,如果代码包导入路径为x/y/z,则它的归档文件存放路径的相对路径即为x/y/,而这个归档文件的名称即为z.a。

现在来看代码包pkgtool的归档文件的存放路径。因为它的导入路径中只有一个元素,所以其归档文件就被直接存放到了goc2p项目的pkg目录的平台相关目录下。

此外,我们还发现pkg目录的平台相关目录下还有一个名为logging.a的文件。很显然,我们并没有显式的安装代码包logging。这是怎么回事呢?这是因为go install命令在安装指定的代码包之前,会先去安装指定代码包的依赖包。当依赖包被正确安装后,指定的代码包的安装才会开始。由于代码包cnet/ctcp依赖于代码包logging,所以当代码包logging被成功安装之后,代码包cnet/ctcp才会被安装。

还有一个问题:上述的安装过程涉及到了那么多代码包,那为什么goc2p项目的pkg目录中只包含该项目中代码包的归档文件呢?实际上,go install命令会把标准库中的代码包的归档文件存放到Go根目录的pkg目录中,而把指定代码包依赖的第三方项目的代码包的归档文件存放到那个项目的pkg目录下。这样就实现了Go语言标准库代码包的归档文件与用户代码包的归档文件,以及处在不同工作区的用户代码包的归档文件之间的彻底分离。

安装命令源码文件

除了安装代码包之外,go install命令还可以安装命令源码文件。为了看到安装命令源码文件是goc2p项目目录的变化,我们先把该目录还原到原始状态,即清除bin子目录和pkg子目录下的所有目录和文件。然后,我们来安装代码包helper/ds下的命令源码文件showds.go,如下:

hc@ubt:~/golang/goc2p/src$ go install helper/ds/showds.go
go install: no install location for directory /home/hc/golang/goc2p/src/helper/ds outside GOPATH
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

这次我们没能成功安装。该Go命令认为目录/home/hc/golang/goc2p/src/helper/ds不在环境GOPATH中。我们可以通过Linux的echo命令来查看一下环境变量GOPATH的值:

hc@ubt:~/golang/goc2p/src$ echo $GOPATH
/home/hc/golang/lib:/home/hc/golang/goc2p
  • 1
  • 2
  • 1
  • 2

环境变量GOPATH的值中确实包含了goc2p项目的根目录。这到底是怎么回事呢?

作者通过查看Go命令的源码文件($GOROOT/src/go/*.go)找到了其根本原因。在上一小节我们提到过,在环境变量GOPATH中包含多个工作区目录路径时,我们需要在编译命令源码文件前先对环境变量GOBIN进行设置。实际上,这个环境变量所指的目录路径就是命令程序生成的结果文件的存放目录。go install命令会把相应的可执行文件放置到这个目录中。

由于命令go build在编译库源码文件后不会产生任何结果文件,所以自然也不用会在意结果文件的存放目录。在该命令编译单一的命令源码文件时,在结果文件存放目录无效的情况下会将结果文件(也就是可执行文件)存放到执行该命令时所在的目录下。因此,即使环境变量GOBIN的值无效,我们在执行go build命令时也不会见到这个错误提示信息。

然而,go install命令中一个很重要的步骤就是将结果文件(归档文件或者可执行文件)存放到相应的目录中。所以,命令go install在安装命令源码文件时,如果环境变量GOBIN的值无效,则它会在最后检查结果文件存放目录的时候发现这一问题,并打印与上述示例所示内容类似的错误提示信息,最后直接退出。

这个错误提示信息在我们安装多个库源码文件时也有可能遇到。示例如下:

hc@ubt:~/golang/goc2p/src/pkgtool$ go install envir.go fpath.go ipath.go pnode.go util.go
go install: no install location for directory /home/hc/golang/goc2p/src/pkgtool outside GOPATH
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

而且,在我们为环境变量GOBIN设置了正确的值之后,这个错误提示信息仍然会出现。这是因为,只有在安装命令源码文件的时候,命令程序才会将环境变量GOBIN的值作为结果文件的存放目录。而在安装库源码文件时,在命令程序内部的代表结果文件存放目录路径的变量不会被赋值。最后,命令程序会发现它依然是个无效的空值。所以,命令程序会同样返回一个关于“无安装位置”的错误。这就引出一个结论,我们只能使用安装代码包的方式来安装库源码文件,而不能在go install命令罗列并安装它们。另外,go install命令目前无法接受标记-o以自定义结果文件的存放位置。这也从侧面说明了go install命令当前还不支持针对库源码文件的安装操作。

单从上述问题来讲,Go工具在执行错误识别及其提示信息的细分方面还没有做到最好。

go标准命令详解0.2 go install相关推荐

  1. go标准命令详解0.1 go build

    搬运自github赫林的go_command_tutorial,绝对干货,感谢作者. 为了让讲解更具关联性,也为了让读者能够更容易的理解这些命令和工具,本教程并不会按照这些命令的字典顺序讲解它们,而会 ...

  2. docker常用命令详解

    docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...

  3. 超级干货:3个性能监控和优化命令详解

    小编为大家整理出了三个有关性能监控和优化命令详细讲解,别看只有三个,但不影响他噎啊,本篇文章很长,涉及top命令.free命令和vmstat命令,真的是很详细的讲解,希望能帮到大家,另外还有两条相关的 ...

  4. android route命令详解,route cmd命令详解

    在本地 IP 路由表中显示和修改条目.使用不带参数的 route 可以显示帮助.接下来是小编为大家收集的route cmd命令详解,希望能帮到大家. route cmd命令详解 语法 route [- ...

  5. c linux time微秒_学习linux,看这篇1.5w多字的linux命令详解(6小时讲明白Linux)

    用心分享,共同成长 没有什么比每天进步一点点更重要了 本篇文章主要讲解了一些linux常用命令,主要讲解模式是,命令介绍.命令参数格式.命令参数.命令常用参数示例.由于linux命令较多,我还特意选了 ...

  6. net user命令详解

    net use \\ip\ipc$ " " /user:" " 建立IPC空链接  net use \\ip\ipc$ "密码" /user ...

  7. ffmpeg命令详解(转)

    一.ffmpeg命令详解 ffmpeg非常强大,轻松几条命令就可以完成你的工作. 把darkdoor.[001-100].jpg序列帧和001.mp3音频文件利用mpeg4编码方式合成视频文件dark ...

  8. 【Linux】crontab命令详解

    00. 目录 文章目录 00. 目录 01. crond简介 02. crond服务 03. crontab命令详解 04. 示例演示 05. 注意事项 01. crond简介 crond是linux ...

  9. centos关机与重启命令详解

    2019独角兽企业重金招聘Python工程师标准>>> Linux centos关机与重启命令详解与实战 Linux centos重启命令: 1.reboot 2.shutdown ...

最新文章

  1. # 异运算_小学数学整数、小数、分数加减法运算法则及练习(可打印)
  2. window 注册表五大类
  3. 我的 FPGA 学习历程(11)—— 实验:按键消抖
  4. What's VPC (by quqi99)
  5. 【2016年第1期】专题导读:农业大数据
  6. mysql 主从 通俗易懂_MySQL 主从同步架构中你不知道的“坑”(完结篇)
  7. 中专计算机系专业总结范文,计算机*的中专生自我鉴定范文
  8. application terminated怎么解决_优雅解决 SpringBoot 工程中多环境下 application.properties 的维护问题...
  9. 计算机英语 1000字论文范文,英语论文格式写作 1000字论文格式-免费论文范文
  10. Notepad++下载
  11. 另类搞笑:自我指涉例句不完全收集
  12. SDUT 1160 某年某月的天数
  13. Google Earth Engine(GEE)——NASA-USDA增强型SMAP全球土壤水分数据以10公里的空间分辨率提供全球的土壤水分信息
  14. 网站运行原理及开发流程
  15. 机械键盘的“轴”有什么区别?
  16. input输入框限制(座机,手机号码)
  17. 51/时钟周期、时钟频率、状态周期、机器周期
  18. mysql之聚簇索引与非聚簇索引
  19. 免费的 PPT 模版资源
  20. PHP开发的仿山楂岛留言程序源码

热门文章

  1. MySQL触发器使用详解
  2. 随机产生长度为20的字符串(数字和大小写字母)
  3. Query String Object 2.1.7
  4. 概率整形技术(PCS)介绍
  5. Linux下编译opencv
  6. python面试经典问题_Python面试中最常见的25个问题-结束
  7. texlive安装需要多久_LaTex编译环境安装与使用
  8. python列表迭代器_关于Python中迭代器的作用
  9. 利用OpenCV求矩阵的特征值和特征向量
  10. ubuntu9.10硬盘安装记录二