gopathなしでローカルパッケージをインポートする方法


171

私は使用しましたGOPATHが、この現在の問題で私が直面しているのは役に立ちません。プロジェクトに固有のパッケージを作成できるようにしたい:

myproject/
├── binary1.go
├── binary2.go
├── package1.go
└── package2.go

私は複数の方法を試してみましたが、どのように得るかpackage1.goで動作するようにbinary1.goか、binary2.goというように?

例えば; 私のことができるようにしたいimport "package1"し、次に実行することができgo build binary1.go、すべてがエラーがパッケージが上で見つけることができないというスローされることなく、罰金を動作しますGOROOTGOPATH。この種の機能が必要な理由は、大規模プロジェクトのためです。他の複数のパッケージを参照したり、それらを1つの大きなファイルに保持したりする必要はありません。


2
各バイナリのソースファイルを独自のディレクトリに配置する必要があります。
ファズ

.go1つのディレクトリ内のすべてのファイルは同じパッケージの一部でありimport、同じパッケージ(つまり、同じディレクトリ)内のファイルである必要はありません。新しいGoモジュールシステムの機能の1つであるGOPATHの外部での作業について説明しました。この回答は、モジュール構造、ローカルパッケージのインポート、モジュール内でのパッケージの配置、単一のリポジトリに複数のモジュールを
含める

3
そして、この振る舞いは誰でも大丈夫ですか?git/repo/to/my/projectパス全体を指定しない限り、基本的にローカルのサブパッケージをインポートできないことですか?誰もがこの振る舞いを望んでいる理由がわかりません。プロジェクトを別の場所(つまり、Dockerイメージ)に移動した場合、すべてのパスを再度変更する必要がありますか?これがとても複雑な理由を探しています。
milosmns

@milosmnsが私の回答を見るstackoverflow.com/a/60915633/175071
Timo Huovinen

回答:


176

依存関係管理の概要を確認します。

  • vgo goバージョンが次の場合: x >= go 1.11
  • depまたはvendor、goバージョンが次の場合:go 1.6 >= x < go 1.11
  • goバージョンが次の場合は手動で: x < go 1.6

編集3:Go 1.11には機能があります vgo置き換わる ありますdep

使用するには vgoには、モジュールのドキュメントを参照してください。以下のTLDR:

export GO111MODULE=on
go mod init
go mod vendor # if you have vendor/ folder, will automatically integrate
go build

このメソッドは、 go.modプロジェクトディレクトリに。その後、を使用してプロジェクトをビルドできますgo buildGO111MODULE=autoが設定されている場合、プロジェクトをに置くことはできません$GOPATH


編集2:ベンダー方式はまだ有効であり、問​​題なく機能します。 vendorこのために、大部分は手作業のプロセスであるdepvgo作成されました。


編集1:私の古い方法は機能しますが、それを行うための「正しい」方法ではありません。ベンダー機能を使用する必要があります、、vgoまたはdepGo 1.6ではデフォルトで有効になっている(現時点では)をます。参照してください。基本的に、「外部」または「依存」パッケージをvendorディレクトリ内に追加します。コンパイル時に、コンパイラはこれらのパッケージを最初に使用します。


見つかりました。私はローカルパッケージをインポートすることができましたGOPATHサブフォルダを作成からpackage1インポートしimport "./package1"、次のようにin binary1.goおよびbinary2.goスクリプトでインポートするました。

binary1.go

...
import (
        "./package1"
      )
...

したがって、現在のディレクトリ構造は次のようになります。

myproject/
├── binary1.go
├── binary2.go
├── package1/
   └── package1.go
└── package2.go

また、相対パス(少なくともgo 1.5では)も機能することにも注意してください。例えば:

import "../packageX"

4
これは、2つのサブフォルダーがあり、一方が他方を参照するまでは問題ありません。たとえば、package2もサブフォルダーであり、package1が必要な場合、システムは壊れます。
カール14

7
import "../package1"
Felix Rabe

12
相対インポートパスはお勧めできません。
Dave C

1
#golangが「名前空間」を提供している場合、「相対インポートパス」または「サブパッケージ」は不適切なアイデアであることに同意できます。
Mission.liao

1
関数名は大文字で始める必要があります
kokemomuke

71

「ローカルパッケージ」などはありません。ディスク上のパッケージの編成は、パッケージの親子関係と直交しています。パッケージによって形成される唯一の実際の階層は、依存関係ツリーです。これは、一般的に、ディレクトリツリーを反映していません。

使うだけ

import "myproject/packageN"

正当な理由がない限り、ビルドシステムと戦わないでください。簡単なプログラムでインポートごとに数十の文字を保存することは、たとえば、相対インポートパスを持つプロジェクトは取得できないため、適切な理由ではありません。

インポートパスの概念には、いくつかの重要なプロパティがあります。

  • インポートパスはグローバルに一意にすることができます。
  • GOPATHと組み合わせて、インポートパスをディレクトリパスに明確に変換できます。
  • GOPATHの下のディレクトリパスは、明確にインポートパスに変換できます。

上記のすべては、相対インポートパスを使用することによって台無しになります。それをしません。

PS:相対インポートを使用するGoコンパイラテストのレガシーコードの場所はほとんどありません。ATM、これが相対インポートがまったくサポートされる唯一の理由です。


2
パッケージGOPATHの理解を深めるために、この紹介ビデオをご覧になることをお勧めしますyoutube.com/watch?v=XCsL89YtqCs
Joshua Pinter 14

7
これは悪いアドバイスだと思います。たとえば、バージョニングにgopkg.inを使用する場合、上記のように、「ミニ」パッケージの絶対インポートパスではうまくいきません。ソースリポジトリを壊すか、バージョン管理されたリポジトリが役に立たなくなります。
グレッグ

import "myproject/packageN"myprojectプロジェクトを保持するフォルダ名は何ですか?
securecurve 2016年

これは完全に間違っています。プライベートリポジトリでどのように使用すればよいですか?
agilob

44

おそらく、パッケージをモジュール化しようとしているのでしょう。私はそれを想定しpackage1ていますpackage2されている、方法で、同じパッケージの一部が、読みやすさ、あなたがしている分割複数のファイルにそれらをのために。

前のケースがあなたのものであった場合、それらの複数のファイルに同じパッケージ名を使用でき、同じファイルがあったかのようになります。

これは例です:

add.go

package math

func add(n1, n2 int) int {
   return n1 + n2
}

subtract.go

package math

func subtract(n1, n2 int) int {
    return n1 - n2
}

donothing.go

package math

func donothing(n1, n2 int) int {
    s := add(n1, n2)
    s = subtract(n1, n2)
    return s
}

私はGoのエキスパートではありません。これはStackOveflowでの最初の投稿なので、アドバイスがあれば、高く評価されます。


23

同様の問題があり、現在使用しているソリューションではGo 1.11モジュールを使用しています。私は次の構造を持っています

- projects
  - go.mod
  - go.sum
  - project1
    - main.go
  - project2
    - main.go
  - package1
    - lib.go
  - package2
    - lib.go

そして、私はproject1とproject2からpackage1とpackage2を使用してインポートすることができます

import (
    "projects/package1"
    "projects/package2"
)

実行しgo mod init projectsた後。go buildproject1およびproject2ディレクトリから使用することもgo build -o project1/exe project1/*.go、projectsディレクトリから使用することもできます。

この方法の欠点は、すべてのプロジェクトが最終的にgo.modの同じ依存関係リストを共有することです。私はまだこの問題の解決策を探していますが、それは根本的なもののようです。


9

go.modの導入以来、ローカルと外部の両方のパッケージ管理が容易になると思います。go.modの使用すると、GOPATHの外でgoプロジェクトすることもできます。

ローカルパッケージをインポート:

フォルダーdemoprojectを作成し、次のコマンドを実行してgo.modファイルを生成します

go mod init demoproject

私はdemoprojectディレクトリ内に以下のようなプロジェクト構造を持っています。

├── go.mod
└── src
    ├── main.go
    └── model
        └── model.go

デモのために、model.goファイルに次のコードを挿入します。

package model

type Employee struct {
    Id          int32
    FirstName   string
    LastName    string
    BadgeNumber int32
}

main.go、私は「demoproject / SRC /モデル」を参照して従業員のモデルをインポート

package main

import (
    "demoproject/src/model"
    "fmt"
)

func main() {
    fmt.Printf("Main Function")

    var employee = model.Employee{
        Id:          1,
        FirstName:   "First name",
        LastName:    "Last Name",
        BadgeNumber: 1000,
    }
    fmt.Printf(employee.FirstName)
}

外部依存関係をインポート:

go getプロジェクトディレクトリ内でコマンドを実行するだけです。

例えば:

go get -u google.golang.org/grpc

go.modファイルにモジュールの依存関係を含める必要があります

module demoproject

go 1.13

require (
    golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
    golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
    golang.org/x/text v0.3.2 // indirect
    google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150 // indirect
    google.golang.org/grpc v1.26.0 // indirect
)

https://blog.golang.org/using-go-modules


can't load package: package .: no Go files in...(go.modのフォルダーにビルドを追加)
Sebi2020

そのような平凡さはありましたが、答えを見つけるのに恥ずかしいほどの時間を要し、あなたの投稿が最も読みやすくて役に立ちました。ありがとうございました!
ハロルドキャベンディッシュ

8

「ローカル」パッケージをプロジェクトに追加するには、フォルダー(たとえば、「package_name」)を追加します。そして、そのフォルダーに実装ファイルを置きます。

src/github.com/GithubUser/myproject/
 ├── main.go
 └───package_name
       └── whatever_name1.go
       └── whatever_name2.go

あなたのpackage mainこれで:

import "github.com/GithubUser/myproject/package_name"

package_nameフォルダー名はどこにあり、それはファイルwhatever_name1.goおよびwhatever_name2.goで使用されるパッケージ名と一致する必要があります。つまり、サブディレクトリを持つすべてのファイルは同じパッケージである必要があります。

インポートで親フォルダーへのパス全体を指定する限り、さらに多くのサブディレクトリーをネストすることができます。


2
これは良い提案ですが、カーネルパニック中にバイナリからダンプされたスタックトレースがgithub.comパスを表示することを除いて、常に最も望ましい動作とは限りません。これを抑制するためのフラグがありますが、単純なパッケージ構成を実現するためだけに必要なわけではなく、失敗することもあります。
ケニーパワーズ

package myproject/package_name is not in GOROOT (/usr/lib/go-1.14/src/myproject/package_name)
Sebi2020

3

使用できます replace

go modo init example.com/my/foo

foo / go.mod

module example.com/my/foo

go 1.14

replace example.com/my/bar => /path/to/bar

require example.com/my/bar v1.0.0

foo / main.go

package main
import "example.com/bar"

func main() {
    bar.MyFunc()
}

bar / go.mod

module github.com/my/bar

go 1.14

bar / fn.go

package github.com/my/bar

import "fmt"

func MyFunc() {
    fmt.Printf("hello")
}

ローカルパッケージのインポートは、外部パッケージのインポートと同じです。

go.modファイル内を除き、その外部パッケージ名をローカルフォルダーに置き換えます。

フォルダへのパスは、完全パスまたは相対パスにすることができます "/ path / to / bar"または "../bar"

https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive https://thewebivore.com/using-replace-in-go-mod-to-point -to-your-local-module /

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.