01 | 工作区和GOPATH
下载APP
关闭
渠道合作
推荐作者
01 | 工作区和GOPATH
2018-08-10 郝林 来自北京
《Go语言核心36讲》
课程介绍
讲述:黄洲君
时长09:47大小13.45M
这门课中 Go 语言的代码比较多,建议你配合文章收听音频。
你好,我是郝林。从今天开始,我将和你一起梳理 Go 语言的整个知识体系。
在过去的几年里,我与广大爱好者一起见证了 Go 语言的崛起。
从 Go 1.5 版本的自举(即用 Go 语言编写程序来实现 Go 语言自身),到 Go 1.7 版本的极速 GC(也称垃圾回收器),再到 2018 年 2 月发布的 Go 1.10 版本对其自带工具的全面升级,以及可预见的后续版本关键特性(比如用来做程序依赖管理的go mod命令),这一切都令我们欢欣鼓舞。Go 语言在一步步走向辉煌的同时,显然已经成为软件工程师们最喜爱的编程语言之一。
我开办这个专栏的主要目的,是要与你一起探索 Go 语言的奥秘,并帮助你在学习和实践的过程中获取更多。
我假设本专栏的读者已经具备了一定的计算机基础,比如,你要知道操作系统是什么、环境变量怎么设置、怎样正确使用命令行,等等。
当然了,如果你已经有了编程经验,尤其是一点点 Go 语言编程经验,那就更好了,毕竟我想教给你的,都是 Go 语言中非常核心的技术。
最后,我来说一下专栏的讲述模式。我总会以一道 Go 语言的面试题开始,针对它进行解答,我会告诉你为什么我要关注这道题,这道题的背后隐藏着哪些知识,并且,我会对这部分的内容,进行相关的知识扩展。
好了,准备就绪,我们一起开始。
我们学习 Go 语言时,要做的第一件事,都是根据自己电脑的计算架构(比如,是 32 位的计算机还是 64 位的计算机)以及操作系统(比如,是 Windows 还是 Linux),从Go 语言官网下载对应的二进制包,也就是可以拿来即用的安装包。
随后,我们会解压缩安装包、放置到某个目录、配置环境变量,并通过在命令行中输入go version来验证是否安装成功。
在这个过程中,我们还需要配置 3 个环境变量,也就是 GOROOT、GOPATH 和 GOBIN。这里我可以简单介绍一下。
GOROOT:Go 语言安装根目录的路径,也就是 GO 语言的安装路径。
GOPATH:若干工作区目录的路径。是我们自己定义的工作空间。
GOBIN:GO 程序生成的可执行文件(executable file)的路径。
其中,GOPATH 背后的概念是最多的,也是最重要的。那么,今天我们的面试问题是:你知道设置 GOPATH 有什么意义吗?
关于这个问题,它的典型回答是这样的:
你可以把 GOPATH 简单理解成 Go 语言的工作目录,它的值是一个目录的路径,也可以是多个目录路径,每个目录都代表 Go 语言的一个工作区(workspace)。
我们需要利用这些工作区,去放置 Go 语言的源码文件(source file),以及安装(install)后的归档文件(archive file,也就是以“.a”为扩展名的文件)和可执行文件(executable file)。
事实上,由于 Go 语言项目在其生命周期内的所有操作(编码、依赖管理、构建、测试、安装等)基本上都是围绕着 GOPATH 和工作区进行的。所以,它的背后至少有 3 个知识点,分别是:
1. Go 语言源码的组织方式是怎样的;
2. 你是否了解源码安装后的结果(只有在安装后,Go 语言源码才能被我们或其他代码使用);
3. 你是否理解构建和安装 Go 程序的过程(这在开发程序以及查找程序问题的时候都很有用,否则你很可能会走弯路)。
下面我就重点来聊一聊这些内容。
知识扩展
1. Go 语言源码的组织方式
与许多编程语言一样,Go 语言的源码也是以代码包为基本组织单位的。在文件系统中,这些代码包其实是与目录一一对应的。由于目录可以有子目录,所以代码包也可以有子包。
一个代码包中可以包含任意个以.go 为扩展名的源码文件,这些源码文件都需要被声明属于同一个代码包。
代码包的名称一般会与源码文件所在的目录同名。如果不同名,那么在构建、安装的过程中会以代码包名称为准。
每个代码包都会有导入路径。代码包的导入路径是其他代码在使用该包中的程序实体时,需要引入的路径。在实际使用程序实体之前,我们必须先导入其所在的代码包。具体的方式就是import该代码包的导入路径。就像这样:
在工作区中,一个代码包的导入路径实际上就是从 src 子目录,到该包的实际存储位置的相对路径。
所以说,Go 语言源码的组织方式就是以环境变量 GOPATH、工作区、src 目录和代码包为主线的。一般情况下,Go 语言的源码文件都需要被存放在环境变量 GOPATH 包含的某个工作区(目录)中的 src 目录下的某个代码包(目录)中。
2. 了解源码安装后的结果
了解了 Go 语言源码的组织方式后,我们很有必要知道 Go 语言源码在安装后会产生怎样的结果。
源码文件以及安装后的结果文件都会放到哪里呢?我们都知道,源码文件通常会被放在某个工作区的 src 子目录下。
那么在安装后如果产生了归档文件(以“.a”为扩展名的文件),就会放进该工作区的 pkg 子目录;如果产生了可执行文件,就可能会放进该工作区的 bin 子目录。
我再讲一下归档文件存放的具体位置和规则。
源码文件会以代码包的形式组织起来,一个代码包其实就对应一个目录。安装某个代码包而产生的归档文件是与这个代码包同名的。
放置它的相对目录就是该代码包的导入路径的直接父级。比如,一个已存在的代码包的导入路径是
那么执行命令
生成的归档文件的相对目录就是 github.com/labstack ,文件名为 echo.a 。
顺便说一下,上面这个代码包导入路径还有另外一层含义,那就是:该代码包的源码文件存在于 GitHub 网站的 labstack 组的代码仓库 echo 中。
再说回来,归档文件的相对目录与 pkg 目录之间还有一级目录,叫做平台相关目录。平台相关目录的名称是由 build(也称“构建”)的目标操作系统、下划线和目标计算架构的代号组成的。
比如,构建某个代码包时的目标操作系统是 Linux,目标计算架构是 64 位的,那么对应的平台相关目录就是 linux_amd64。
因此,上述代码包的归档文件就会被放置在当前工作区的子目录 pkg/linux_amd64/github.com/labstack 中。
(GOPATH 与工作区)
总之,你需要记住的是,某个工作区的 src 子目录下的源码文件在安装后一般会被放置到当前工作区的 pkg 子目录下对应的目录中,或者被直接放置到该工作区的 bin 子目录中。
3. 理解构建和安装 Go 程序的过程
我们再来说说构建和安装 Go 程序的过程都是怎样的,以及它们的异同点。
构建使用命令go build,安装使用命令go install。构建和安装代码包的时候都会执行编译、打包等操作,并且,这些操作生成的任何文件都会先被保存到某个临时的目录中。
如果构建的是库源码文件,那么操作后产生的结果文件只会存在于临时目录中。这里的构建的主要意义在于检查和验证。
安装操作会先执行构建,然后还会进行链接操作,并且把结果文件搬运到指定目录。
进一步说,如果安装的是库源码文件,那么结果文件会被搬运到它所在工作区的 pkg 目录下的某个子目录中。
如果安装的是命令源码文件,那么结果文件会被搬运到它所在工作区的 bin 目录中,或者环境变量GOBIN指向的目录中。
这里你需要记住的是,构建和安装的不同之处,以及执行相应命令后得到的结果文件都会出现在哪里。
总结
工作区和 GOPATH 的概念和含义是每个 Go 工程师都需要了解的。虽然它们都比较简单,但是说它们是 Go 程序开发的核心知识并不为过。
然而,我在招聘面试的过程中仍然发现有人忽略掉了它们。Go 语言提供的很多工具都是在 GOPATH 和工作区的基础上运行的,比如上面提到的go build、go install和go get,这三个命令也是我们最常用到的。
思考题
说到 Go 程序中的依赖管理,其实还有很多问题值得我们探索。我在这里留下两个问题供你进一步思考。
Go 语言在多个工作区中查找依赖包的时候是以怎样的顺序进行的?
如果在多个工作区中都存在导入路径相同的代码包会产生冲突吗?
这两个问题之间其实是有一些关联的。答案并不复杂,你做几个试验几乎就可以找到它了。你也可以看一下 Go 语言标准库中go build包及其子包的源码。那里面的宝藏也很多,可以助你深刻理解 Go 程序的构建过程。
补充阅读
go build 命令一些可选项的用途和用法
在运行go build命令的时候,默认不会编译目标代码包所依赖的那些代码包。当然,如果被依赖的代码包的归档文件不存在,或者源码文件有了变化,那它还是会被编译。
如果要强制编译它们,可以在执行命令的时候加入标记-a。此时,不但目标代码包总是会被编译,它依赖的代码包也总会被编译,即使依赖的是标准库中的代码包也是如此。
另外,如果不但要编译依赖的代码包,还要安装它们的归档文件,那么可以加入标记-i。
那么我们怎么确定哪些代码包被编译了呢?有两种方法。
运行go build命令时加入标记-x,这样可以看到go build命令具体都执行了哪些操作。另外也可以加入标记-n,这样可以只查看具体操作而不执行它们。
运行go build命令时加入标记-v,这样可以看到go build命令编译的代码包的名称。它在与-a标记搭配使用时很有用。
下面再说一说与 Go 源码的安装联系很紧密的一个命令:go get。
命令go get会自动从一些主流公用代码仓库(比如 GitHub)下载目标代码包,并把它们安装到环境变量GOPATH包含的第 1 工作区的相应目录中。如果存在环境变量GOBIN,那么仅包含命令源码文件的代码包会被安装到GOBIN指向的那个目录。
最常用的几个标记有下面几种。
-u:下载并安装代码包,不论工作区中是否已存在它们。
-d:只下载代码包,不安装代码包。
-fix:在下载代码包后先运行一个用于根据当前 Go 语言版本修正代码的工具,然后再安装代码包。
-t:同时下载测试所需的代码包。
-insecure:允许通过非安全的网络协议下载和安装代码包。HTTP 就是这样的协议。
Go 语言官方提供的go get命令是比较基础的,其中并没有提供依赖管理的功能。目前 GitHub 上有很多提供这类功能的第三方工具,比如glide、gb以及官方出品的dep、vgo等等,它们在内部大都会直接使用go get。
有时候,我们可能会出于某种目的变更存储源码的代码仓库或者代码包的相对路径。这时,为了让代码包的远程导入路径不受此类变更的影响,我们会使用自定义的代码包导入路径。
对代码包的远程导入路径进行自定义的方法是:在该代码包中的库源码文件的包声明语句的右边加入导入注释,像这样:
这个代码包原本的完整导入路径是github.com/golang/sync/semaphore。这与实际存储它的网络地址对应的。该代码包的源码实际存在 GitHub 网站的 golang 组的 sync 代码仓库的 semaphore 目录下。而加入导入注释之后,用以下命令即可下载并安装该代码包了:
而 Go 语言官网 golang.org 下的路径 /x/sync/semaphore 并不是存放semaphore包的真实地址。我们称之为代码包的自定义导入路径。
不过,这还需要在 golang.org 这个域名背后的服务端程序上,添加一些支持才能使这条命令成功。
分享给需要的人,Ta购买本课程,你将得18元
生成海报并分享
赞 58
提建议
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
上一篇
导读 | 学习专栏的正确姿势
下一篇
02 | 命令源码文件
精选留言(144)
- 郝林置顶2018-08-10有很多读写问归档文件是什么意思。归档文件在Linux下就是扩展名是.a的文件,也就是archive文件。写过C程序的朋友都知道,这是程序编译后生成的静态库文件。共 5 条评论187
- Geek_1ed70f置顶2019-01-27下午上班时间随便读了一下,感觉有点讲的太散,只吸收了20%,晚上专门花了时间精读几遍 吸收了100%后真的干货满满,以前不懂得原理都能知道了 这是网上博客不会有的工匠级解说49
- 全干工程师置顶2018-08-10什么是归档文件,归档文件里都是什么?有什么作用。
作者回复: 请看我置顶的留言。
23 - 千年孤独置顶2018-08-10如果在面试中让老师来回答“设置'GOPATH有什么意义?”这个问题,除去典型回答 老师会如何简要明了回答这个问题?
作者回复: 可以说,为了集中组织代码,以及代码互相引用。当然了,这么说后面试官可能还会让你具体解答。
共 2 条评论20 - 许明置顶2018-08-10ide 我觉得vscode就很好用了,我现在是vscode + glide
作者回复: 嗯,我也用这种组合。
共 3 条评论18 - 第五季节置顶2018-08-10工作区是指: 放go的源码目录。 gopath是指:指向工作区的路径。 归档文件: 相当于java的jar包。下载到本地私服 不知道对不对。纯属个人观点。展开
作者回复: 前两个对,归档文件在Linux下就是.a文件,也就是archive文件,是程序编译成功后生成的静态库文件。这跟Java的jar包还不太一样,jar包相当于动态链接库了。
共 2 条评论16 - 江山如画置顶2018-08-14对于初学者第一次看确实有些难懂,但是多看几遍后就会发现其实干货满满,我读了好几遍,接触golang也快一年了,但是很多知识点是第一次接触到,感谢郝林老师!
作者回复: 对你有帮助就好。
13 - xyang置顶2018-08-11go语言适合做什么业务,能概述性的罗列讲述下吗
作者回复: 你好,我会在后边另写文章介绍。
10 - giteebravo置顶2018-08-10一脸懵逼,并不知道归档文件是啥😄
作者回复: 请看我置顶的留言。
共 2 条评论8 - jians置顶2018-08-10看完再结合测试后的疑问: 在不同项目src中有同名包时,go build, install只会执行gopath中最早发现包的工作区,哪如何编译后面其他工作区中的同名包呢?
作者回复: 这就需要自己去放置了,或者临时把前面的工作区从gopath中去掉。
共 2 条评论6 - 白宇置顶2018-08-11请教一下,如何解决下载第三方包失败情况
作者回复: 你好,这属于是网络问题。
共 2 条评论5 - 第五季节置顶2018-08-10gopath 的设计类似java 。 具体的用途是执行命令要用 例如:go run、go install、go get等。 允许设置多个路径。 在idea里面的多个project或工具组建都并列放在gopath的src下面。 例如:go install myProject1 go install myProject2 所以老师说的这个归档文件。可以理解成工作空间吗? 至于老师说的两个问题。 1:按照代码的执行顺序 从上往下 每个引入的初始化。 2:引入一下试试就知道了。展开
作者回复: 归档文件的解释请看置顶的留言。
4 - 🄽🄸🅇🅄🅂置顶2018-08-12归档文件,可以理解为程序的动态链接库文件吗?
作者回复: 相当于静态链接文件。
3 - 有风的林子置顶2018-08-12目前还没用到GOPATH包含多个工作区,不知多个目录间的分隔符是什么?空格、冒号、还是分号?如果作者顺便说一下就好了,至少增加一个知识点。😁
作者回复: 你好,这根据具体的操作系统而定。
共 2 条评论4 - 张珂2019-09-19突然出现“库源码文件”和“命令源码文件”,只看名字不知道是什么。看了某个留言之后才知道“命令源码文件”是包含main入口函数的源码文件。虽说该专栏定位不是基础教学,但还是要照顾一下大家基础不一,阅读门槛太高也不好。 总体还感觉文字组织让人读起来很费劲,文字逻辑需要优化。 图好像也很少。文不如表,表不如图,图不如动画。有些东西一图胜千言。其他专栏都有很多图的,虽说音频很不方便,但我觉得音频对于方法论的讲述比较合适(比如架构的思想),不适合该专栏。大部分用户应该是用“阅读”来学习的。 个人观点展开27
- 咖啡色的羊驼2018-08-10对于作者的两个问题。三个纬度延伸总结回答下: 1.总执行顺序的角度 引入的包 -> 当前包的变量常量 -> init()[多个同一包则按照顺序执行] -> main函数 2.依赖包执行顺序 被依赖的总是优先执行初始化,一个包只会被初始化一次。 a引入b,b引入c,则执行顺序c -> b -> a 3.单个包执行顺序的角度 总的前提:按照包中源文件名的字典顺序来排序执行。 当前包排序后的变量常量 -> 排序后的init()展开25
- Bob.Chen2018-08-10请问对于之前不太了解go的同学,是否有推荐的入门书可以和专栏配合着看?19
- melon2018-08-29感觉一脸懵逼的,建议先看一下官网这篇深入浅出的文章:https://golang.org/doc/code.html,看完再回过头来看就了然了。18
- 乌慢2018-08-11对于新手来说看起来不是那么的通俗易懂,如果加上图解就更好了,希望以后更加好17
- 少年2019-02-19希望老师少用写陌生的概念,比如:命令源码文件。如果用,请加点解释和类比。用过javascript,php,python,感觉这篇看的还是一脸萌比。命令源码文件这词,还是在留言区看明白的。可以参照廖雪峰老师的文笔,傻比都能看明白。只是提供些反馈,希望老师的专栏越做越好。共 2 条评论14