1. 程式人生 > >[Golang] GOROOT、GOPATH和Project目錄說明

[Golang] GOROOT、GOPATH和Project目錄說明

go env環境檢視

用go env 可檢視當前go環境變數。

$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/mac/MyCodeBase/Go-project/master"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/dg/1_zsnh6n2md7y5kpjj318fk00000gp/T/go-build668952288=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

GOROOT

GOROOT就是go的安裝路徑
在~/.bash_profile中新增下面語句:

GOROOT="/usr/local/go"
export GOROOT

當然, 要執行go命令和go工具, 就要配置go的可執行檔案的路徑:
操作如下:
在~/.bash_profile中配置如下:
export $PATH:$GOROOT/bin

GOPATH

        o install/go get和 go的工具等會用到GOPATH環境變數.
        GOPATH是作為編譯後二進位制的存放目的地和import包時的搜尋路徑 (其實也是你的工作目錄, 你可以在src下建立你自己的go原始檔, 然後開始工作)。
            GOPATH之下主要包含三個目錄: bin、pkg、src
            bin目錄主要存放可執行檔案; pkg目錄存放編譯好的庫檔案, 主要是*.a檔案; src目錄下主要存放go的原始檔
        不要把GOPATH設定成go的安裝路徑,
        可以自己在使用者目錄下面建立一個目錄, 如gopath
        操作如下:

        cd ~
        mkdir gopath

        在~/.bash_profile中新增如下語句:
        GOPATH=/Users/username/gopath
        GOPATH可以是一個目錄列表, go get下載的第三方庫, 一般都會下載到列表的第一個目錄裡面
        需要把GOPATH中的可執行目錄也配置到環境變數中, 否則你自行下載的第三方go工具就無法使用了, 操作如下:
        在~/bash_profile中配置,

        export $PATH:$GOPATH/bin

        建立一個go專案, 並且編譯執行:

        mkdir goproject
        cd goproject
        touch hello.go

        在hello.go中輸入:

        package main
        import "fmt"
        func main() {
           fmt.Println("Hello, GO !")
        }

        在專案根目錄下執行go build命令來構建你的專案, 構建後會生成hello檔案
        執行生成的檔案./hello, terminal中輸出: Hello, GO !
        當然你也可以直接執行命令go run hello.go來執行程式.

如果要上述設定生效, 可以執行命令: source ~/.bash_profile, 上述所有操作均為mac系統下的操作, 如果是非mac系統, 請自行變通.

當存在多個路徑時,好像優先採用第一個路徑。這個無關緊要了,只有需要的第三方包(庫)都能正確下載和使用就ok了。

GOBIN

go install編譯存放路徑。不允許設定多個路徑。可以為空。為空時則遵循“約定優於配置”原則,可執行檔案放在各自GOPATH目錄的bin資料夾中(前提是:package main的main函式檔案不能直接放到GOPATH的src下面。

GOPATH目錄結構

goWorkSpace  // (goWorkSpace為GOPATH目錄)
  -- bin  // golang編譯可執行檔案存放路徑,可自動生成。
  -- pkg  // golang編譯的.a中間檔案存放路徑,可自動生成。
  -- src  // 原始碼路徑。按照golang預設約定,go run,go install等命令的當前工作路徑(即在此路徑下執行上述命令)。

go目錄結構1:

project1 // (project1新增到GOPATH目錄了)
  -- bin
  -- pkg
  -- src  
     -- models       // package
     -- controllers  // package
     -- main.go      // package main[注意,本文所有main.go均指包main的入口函式main所在檔案]

 project2 // (project2新增到GOPATH目錄了)
      -- bin
      -- pkg
      -- src
         -- models       // package
         -- controllers  // package
         -- main.go      // package main

package main檔案直接在GOPATH目錄到src下。

使用go build可以在src資料夾下編譯生成名為“src”的可執行檔案。這是golang預設約定。一般我個人不怎麼用這個命令。因為它會生成可執行檔案在src目錄下面。

我一般用:go get 和 go install。

go get [main.go所在路徑]

引數 [main.go所在路徑]:可選。相對GOPATH/src路徑。 預設是.(src自己)。可指定src下面的子資料夾路徑。
go get會做2件事:1. 從遠端下載需要用到的包。2.執行go install。(從這裡也可以看出golang處處為了簡潔而遵循的“約定優於配置”原則)

go install [main.go所在路徑]

引數 [main.go所在路徑]:可選。 相對GOPATH/src路徑。預設是.(即當前所在目錄或工作目錄)。可指定src下面的子資料夾。
go install編譯生成名稱為[main.go父資料夾名]的可執行檔案,放到GOBIN路徑下。當GOBIN為空時,預設約定是:生成的可執行檔案放到GOPATH/bin資料夾中。產生的中間檔案(.a)放在project/pkg中(沒有變化時,不重新生成.a)。

我們再看此go目錄結構1,執行go install(以及go get的第二階段go install)會報錯:

注意:如果不用額外方式改變環境變數(公司目前用的是sh指令碼編譯),是編譯不過的。報錯:can’t load package: package .: no buildable Go source files in *

解決方法1:
曾經我也因為這個錯誤感到迷惑,認為所有都環境變數都沒有問題。網上也沒怎麼看到直接明確都解答。看了一些帖子後,觸類旁通,設定了GOBIN環境變數後解決。(好吧,我至今也沒有完整讀過英文官方文件。這種預設約定,官方文件上應該有。)

此解決方法有個弊端,多個project會導致多個GOPATH目錄。多個project下的目錄結構和包一致的話,直接編譯會導致編譯問題。因為go優先使用第一個GOPATH目錄,導致編譯衝突。(當然,你也可以每次手工或腳步修改GOPATH環境變數,感覺很麻煩。)不建議多個project直接設定到茫茫多的GOPATH中。當然有解決方法2,我認為是標準合理的解決方法,就是下面go目錄結構2了。

go目錄結構2:

goWorkSpace     // goWorkSpace為GOPATH目錄
  -- bin
     -- myApp1  // 編譯生成
     -- myApp2  // 編譯生成
     -- myApp3  // 編譯生成
  -- pkg
  -- src
     -- common 1
     -- common 2
     -- common utils ...
     -- myApp1     // project1
        -- models
        -- controllers
        -- others
        -- main.go 
     -- myApp2     // project2
        -- models
        -- controllers
        -- others
        -- main.go 
     -- myApp3     // project3
        -- models
        -- controllers
        -- others
        -- main.go 

一個solution裡面的多個project或工具元件都並列放在GOPATH的src下,如myApp1,myApp2,myApp3,common utils。
這時,GOBIN可以為空,編譯時,可以如下:
go install myApp1 或 go get myApp1
go install myApp2 或 go get myApp2
go install myApp3 或 go get myApp3

這時才是大家都認為的,把可執行程式myApp1、myApp2、myApp3生成在goWorkSpace/bin下面。多個GOPATH也就有了上面的“把每個GOPATH下的bin都加入到PATH中”。

提示:相同結構的project下同名包怎麼辦?
有同事在初學時,習慣按照go目錄結構1,瞭解到go目錄結構2後(以為僅僅是把main放到了子資料夾,其他controllers等包結構不變),有這樣的疑惑。他們原來就有這樣的問題,同時把go目錄加入到GOPATH後,編譯就出現問題,因為包名和路徑相同(相對GOPATH下的src),go只會優先查詢第一個符合的GOPATH)。只會每次編譯時手工修改GOPATH,或寫指令碼編譯。(我看著就覺得累,還徒增指令碼維護煩惱。)

解決方案就是:除了通用的,公有的工具、元件外,屬於各個project自己的東西,統統隨著main.go一起移到project目錄下。go目錄結構2就是這樣的。
匯入各個project下的controllers方法:import myApp1/controllers,import myApp2/controllers這樣的。go的import查詢的是包的路徑,並不是包名。你只用告訴go,你的包都放在哪了,go會從這些路徑下查詢有沒有所需要的包。只是大家一般習慣包名和資料夾名相同,容易誤解。只需要注意,一個資料夾下只允許有一個包名,允許有子資料夾定義不同的包。
import 採用的是相對路徑寫法:路徑是 相對GOROOT和GOPATH下的src。

也可以設定GOBIN,而且這時,由於可執行檔名稱不同,也不大容易產生覆蓋(需要避免的時多個GOPATH用相同的“myApp”project名稱。)

具體的還是看個人喜好和實際情況。我個人本地的環境大致是:

      
  -- my-goWorkSpace    // 主要是為了區分自己的鼓搗的一些東西和工作上的專案
  -- work-goWorkSpace
        -- bin
        -- pkg
        -- src                  
           -- myApp1
              -- .git
              -- models
              -- controllers
              -- main.go 
           -- myApp2
              -- .git
              -- models
              -- controllers
              -- main.go 
           -- myApp3
              -- .git
              -- models
              -- controllers
              -- main.go

本地是有多個GOPATH路徑的
注意:GOPATH目錄和GOPATH下的src不應該新增到原始碼管理中,而是各個project目錄myApp1、myApp2、myApp3各自時獨立的進行原始碼管理

我一般不設定GOBIN,把每個GOPATH下的bin都加入到PATH中。

個人理解,有任何問題,歡迎指正。