So importieren Sie lokale Pakete ohne Gopath

171

Ich habe verwendet, GOPATHaber für dieses aktuelle Problem, mit dem ich konfrontiert bin, hilft es nicht. Ich möchte in der Lage sein, projektspezifische Pakete zu erstellen:

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

Ich habe mehrere Möglichkeiten ausprobiert, aber wie komme ich package1.gozur Arbeit in der binary1.gooder der binary2.gound so weiter?

Beispielsweise; Ich möchte in der Lage sein import "package1"und dann laufen können go build binary1.gound alles funktioniert einwandfrei, ohne dass der Fehler ausgelöst wird, dass das Paket nicht auf GOROOToder gefunden werden kann GOPATH. Der Grund, warum ich diese Art von Funktionalität benötige, liegt in großen Projekten. Ich möchte nicht auf mehrere andere Pakete verweisen oder sie in einer großen Datei aufbewahren müssen.

Schwach
quelle
2
Sie sollten die Quelldateien für jede Binärdatei in einem eigenen Verzeichnis ablegen.
Fuz
Alle .goDateien in einem einzelnen Verzeichnis sind Teil desselben Pakets, und Sie müssen keine importDateien im selben Paket (dh im selben Verzeichnis) speichern. Sie haben erwähnt, dass Sie außerhalb von GOPATH arbeiten, einer der Funktionen des neuen Go-Modulsystems. Diese Antwort behandelt die Modulstruktur, das Importieren lokaler Pakete, das Anordnen von Paketen innerhalb eines Moduls, ob mehrere Module in einem Repository vorhanden sein sollen oder nicht usw.
typisch182
3
Und dieses Verhalten ist bei allen in Ordnung? Dass Sie Ihre lokalen Unterpakete grundsätzlich nur importieren können, wenn Sie den gesamten git/repo/to/my/projectPfad angeben ? Ich sehe nur nicht den Grund, warum jemand dieses Verhalten wollen würde. Was passiert, wenn Sie Ihr Projekt an einen anderen Ort verschieben (z. B. Docker-Image) und alle Pfade erneut ändern müssen? Ich suche nach Antworten, warum dies so kompliziert ist.
Milosmns
@milosmns siehe meine Antwort stackoverflow.com/a/60915633/175071
Timo Huovinen

Antworten:

175

Zusammenfassung des Abhängigkeitsmanagements:

  • vgo Wenn Ihre Go-Version lautet: x >= go 1.11
  • depoder vendorwenn Ihre go-Version ist:go 1.6 >= x < go 1.11
  • Manuell, wenn Ihre Go-Version ist: x < go 1.6

Bearbeiten 3: Go 1.11 verfügt über eine Funktion , vgodie wird ersetzen dep .

Informationen zur Verwendung vgofinden Sie in der Dokumentation zu Modulen . TLDR unten:

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

Diese Methode erstellt eine Datei, die go.modin Ihrem Projektverzeichnis aufgerufen wird . Sie können dann Ihr Projekt mit erstellen go build. Wenn GO111MODULE=autofestgelegt, kann Ihr Projekt nicht ausgeführt werden $GOPATH.


Bearbeiten 2: Die Vendoring-Methode ist weiterhin gültig und funktioniert ohne Probleme. vendorist aus diesem Grund weitgehend ein manueller Prozess depund vgowurde erstellt.


Edit 1: Während mein alter Weg funktioniert, ist es nicht mehr der "richtige" Weg, es zu tun. Sie verwenden sollten Anbieter Fähigkeiten, vgooder dep(bis jetzt), die standardmäßig in Go 1.6 aktiviert sind; siehe . Grundsätzlich fügen Sie Ihre "externen" oder "abhängigen" Pakete in einem vendorVerzeichnis hinzu. Nach der Kompilierung verwendet der Compiler diese Pakete zuerst.


Gefunden. Ich war in der Lage Import lokale Paket mit GOPATHdurch einen Unterordner zu erstellen package1und dann mit dem Import import "./package1"in binary1.gound binary2.goSkripte wie folgt aus :

binary1.go

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

Meine aktuelle Verzeichnisstruktur sieht also so aus:

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

Ich sollte auch beachten, dass relative Pfade (zumindest in go 1.5) ebenfalls funktionieren; beispielsweise:

import "../packageX"

quelle
4
Das funktioniert so lange, bis Sie zwei Unterordner haben, von denen einer auf einen anderen verweist. Wenn beispielsweise package2 auch ein Unterordner war und package1 benötigte, bricht das System zusammen.
Carl
7
import "../package1"
Felix Rabe
12
Relative Importpfade sind eine schlechte Idee .
Dave C
1
Wenn #golang 'Namespace' bereitstellt, kann ich Ihnen zustimmen, dass 'relativer Importpfad' oder 'Unterpakete' schlechte Ideen sind.
Mission.liao
1
Funktionsname sollte mit Capitilized Schlüsselwort beginnen
kokemomuke
71

Es gibt kein "lokales Paket". Die Organisation von Paketen auf einer Festplatte ist orthogonal zu allen Eltern-Kind-Beziehungen von Paketen. Die einzige echte Hierarchie, die von Paketen gebildet wird, ist der Abhängigkeitsbaum, der im allgemeinen Fall den Verzeichnisbaum nicht widerspiegelt.

Benutz einfach

import "myproject/packageN"

und kämpfe nicht ohne guten Grund gegen das Build-System. Das Speichern eines Dutzend Zeichen pro Import in einem nicht trivialen Programm ist kein guter Grund, da beispielsweise Projekte mit relativen Importpfaden nicht abrufbar sind.

Das Konzept der Importpfade hat einige wichtige Eigenschaften:

  • Importpfade können global eindeutig sein.
  • In Verbindung mit GOPATH kann der Importpfad eindeutig in einen Verzeichnispfad übersetzt werden.
  • Jeder Verzeichnispfad unter GOPATH kann eindeutig in einen Importpfad übersetzt werden.

All dies wird durch die Verwendung relativer Importpfade ruiniert. TU es nicht.

PS: Es gibt nur wenige Stellen im Legacy-Code in Go-Compilertests, die relative Importe verwenden. ATM, dies ist der einzige Grund, warum relative Importe überhaupt unterstützt werden.

zzzz
quelle
2
Ich empfehle, sich dieses Intro-Video anzusehen, um die Pakete und den GOPATH besser zu verstehen . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter
7
Ich denke, das ist ein schlechter Rat. Wenn Sie beispielsweise gopkg.in für die Versionierung verwenden, haben Sie kein Glück mit den absoluten Importpfaden für Ihre "Mini" -Pakete, wie oben beschrieben. Entweder Sie brechen das Quell-Repo oder das versionierte wird unbrauchbar.
Greg
import "myproject/packageN". myprojectist der Ordnername, der mein Projekt enthält?
Securecurve
Das ist völlig falsch. Wie verwende ich es jetzt mit privaten Repositories?
Agilob
44

Vielleicht versuchen Sie, Ihr Paket zu modularisieren. Ich gehe davon aus package1und bin in gewisser package2Weise Teil desselben Pakets, aber aus Gründen der Lesbarkeit teilen Sie diese in mehrere Dateien auf.

Wenn der vorherige Fall Ihr Fall wäre, könnten Sie denselben Paketnamen in diesen Mehrfachdateien verwenden, und es wäre so, als ob es dieselbe Datei gäbe.

Dies ist ein Beispiel:

add.go

package math

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

subtrahieren.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
}

Ich bin kein Go-Experte und dies ist mein erster Beitrag in StackOveflow. Wenn Sie also einen Rat haben, wird er gut angenommen.

Juan Jose Tugores
quelle
23

Ich habe ein ähnliches Problem und die Lösung, die ich derzeit verwende, verwendet Go 1.11-Module. Ich habe die folgende Struktur

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

Und ich kann Paket1 und Paket2 aus Projekt1 und Projekt2 mithilfe von importieren

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

Nach dem Laufen go mod init projects. Ich kann go buildaus den Verzeichnissen project1 und project2 oder aus dem Projektverzeichnis verwenden go build -o project1/exe project1/*.go.

Der Nachteil dieser Methode ist, dass alle Ihre Projekte dieselbe Abhängigkeitsliste in go.mod verwenden. Ich bin immer noch auf der Suche nach einer Lösung für dieses Problem, aber es sieht so aus, als wäre es von grundlegender Bedeutung.

Mad Wombat
quelle
9

Seit der Einführung von go.mod denke ich, dass sowohl die lokale als auch die externe Paketverwaltung einfacher wird. Mit go.mod ist es auch möglich, ein go-Projekt außerhalb des GOPATH durchzuführen.

Lokales Paket importieren:

Erstellen Sie ein Ordner- Demoprojekt und führen Sie den folgenden Befehl aus, um die Datei go.mod zu generieren

go mod init demoproject

Ich habe eine Projektstruktur wie unten im Demoprojektverzeichnis .

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

Fügen Sie für die Demo den folgenden Code in die Datei model.go ein .

package model

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

In main.go habe ich das Mitarbeitermodell importiert, indem ich auf "demoproject / src / model" verwiesen habe.

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)
}

Externe Abhängigkeit importieren:

Führen Sie einfach den go getBefehl im Projektverzeichnis aus.

Beispielsweise:

go get -u google.golang.org/grpc

Es sollte die Modulabhängigkeit in der Datei go.mod enthalten

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

Tanver Hasan
quelle
can't load package: package .: no Go files in...(Gehe in den Ordner von go.mod)
Sebi2020
Solch eine Banalität, aber ich habe peinlich viel Zeit gebraucht, um die Antwort zu finden, und Ihr Beitrag war am lesbarsten und nützlichsten. Danke dir!
Harold Cavendish
8

Um Ihrem Projekt ein "lokales" Paket hinzuzufügen, fügen Sie einen Ordner hinzu (z. B. "Paketname"). Und legen Sie Ihre Implementierungsdateien in diesem Ordner ab.

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

Wenn package mainSie dies tun:

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

Wo package_nameist der Ordnername und er muss mit dem Paketnamen übereinstimmen, der in den Dateien Whatever_name1.go und Whatever_name2.go verwendet wird. Mit anderen Worten, alle Dateien mit einem Unterverzeichnis sollten vom selben Paket sein.

Sie können weitere Unterverzeichnisse weiter verschachteln, solange Sie beim Import den gesamten Pfad zum übergeordneten Ordner angeben.

Homan
quelle
2
Dies ist ein guter Vorschlag, außer dass während einer Kernel-Panik der Stack-Trace, der aus der Binärdatei ausgegeben wird, beispielsweise den Pfad github.com anzeigt, was nicht immer das wünschenswerteste Verhalten ist. Es gibt Flags, um dies zu unterdrücken, aber es sollte nicht notwendig sein, nur um eine einfache Paketorganisation zu erreichen, und ich habe festgestellt, dass dies gelegentlich fehlschlägt.
Kenny Powers
package myproject/package_name is not in GOROOT (/usr/lib/go-1.14/src/myproject/package_name)
Sebi2020
3

Sie können verwenden 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")
}

Das Importieren eines lokalen Pakets entspricht dem Importieren eines externen Pakets

außer in der Datei go.mod ersetzen Sie diesen externen Paketnamen durch einen lokalen Ordner.

Der Pfad zum Ordner kann vollständig oder relativ "/ path / to / bar" oder "../bar" sein.

https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive https://thewebivore.com/using-replace-in-go-mod-to-point -zu-Ihrem-lokalen-Modul /

Timo Huovinen
quelle