Come importare pacchetti locali senza gopath


171

Ho usato GOPATHma per questo problema attuale sto affrontando non aiuta. Voglio essere in grado di creare pacchetti specifici per un progetto:

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

Ho provato diversi modi, ma come posso package1.golavorare in binary1.goo il binary2.goe così via?

Per esempio; Voglio essere in grado di import "package1"e quindi essere in grado di funzionare go build binary1.goe tutto funziona bene senza che venga generato l'errore su cui non è possibile trovare il pacchetto GOROOTo GOPATH. Il motivo per cui ho bisogno di questo tipo di funzionalità è per progetti su larga scala; Non voglio fare riferimento a più altri pacchetti o tenerli in un unico file di grandi dimensioni.


2
Dovresti mettere i file sorgente per ogni file binario nella sua directory.
fuz,

Tutti i .gofile in una singola directory fanno parte dello stesso pacchetto e non è necessario importfile nello stesso pacchetto (ovvero la stessa directory). Hai citato di lavorare al di fuori di GOPATH, che è una delle funzionalità del nuovo sistema di moduli Go. Questa risposta copre la struttura del modulo, l'importazione di pacchetti locali, l'organizzazione di pacchetti all'interno di un modulo, se disporre o meno di più moduli in un singolo repository, ecc.
tipico182

3
E questo comportamento va bene con tutti? Che fondamentalmente non puoi importare i tuoi sotto-pacchetti locali se non specifichi l'intero git/repo/to/my/projectpercorso? Semplicemente non vedo il motivo per cui qualcuno vorrebbe questo comportamento. Cosa succede se si sposta il progetto in un'altra posizione (ad es. Immagine Docker), è necessario modificare nuovamente tutti i percorsi? Sto cercando risposte perché questo è così complicato.
milosmns,

@milosmns vedere la mia risposta stackoverflow.com/a/60915633/175071
Timo Huovinen

Risposte:


176

Vai al riepilogo della gestione delle dipendenze:

  • vgo se la tua versione go è: x >= go 1.11
  • depo vendorse la tua versione go è:go 1.6 >= x < go 1.11
  • Manualmente se la tua versione go è: x < go 1.6

Modifica 3: Go 1.11 ha una funzione vgoche sostituirà dep .

Per utilizzare vgo, consultare la documentazione dei moduli . TLDR di seguito:

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

Questo metodo crea un file chiamato go.modnella directory dei progetti. Puoi quindi costruire il tuo progetto con go build. Se GO111MODULE=autoimpostato, il progetto non può essere presente $GOPATH.


Modifica 2: il metodo di vendita è ancora valido e funziona senza problemi. vendorè in gran parte un processo manuale, per questo motivo depe vgosono stati creati.


Modifica 1: mentre il mio vecchio modo di lavorare non è più il modo "corretto" di farlo. Dovresti utilizzare le funzionalità del fornitorevgo o dep(per ora) abilitate per impostazione predefinita in Go 1.6; vedi . In sostanza aggiungi i tuoi pacchetti "esterni" o "dipendenti" all'interno di una vendordirectory; al momento della compilazione il compilatore utilizzerà prima questi pacchetti.


Trovato. Sono stato in grado di importare il pacchetto locale GOPATHcreando una sottocartella package1e quindi importando con import "./package1"in binary1.goe binary2.goscript come questo:

binary1.go

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

Quindi la mia attuale struttura di directory appare così:

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

Dovrei anche notare che anche i percorsi relativi (almeno in go 1.5) funzionano; per esempio:

import "../packageX"

4
Funziona bene fino a quando non hai due sottocartelle con una che fa riferimento a un'altra. Ad esempio, se package2 era anche una sottocartella e necessitava di package1, il sistema si interrompe.
Carl,

7
import "../package1"
Felix Rabe,

12
I percorsi di importazione relativi sono una cattiva idea .
Dave C

1
se #golang fornisce "spazio dei nomi", posso essere d'accordo con te sul fatto che "percorso di importazione relativo" o "sotto-pacchetti" siano una cattiva idea ".
mission.liao,

1
Il nome della funzione dovrebbe iniziare con la parola chiave in
maiuscolo

71

Non esiste un "pacchetto locale". L'organizzazione dei pacchetti su un disco è ortogonale a qualsiasi relazione padre / figlio dei pacchetti. L'unica vera gerarchia formata dai pacchetti è l'albero delle dipendenze, che nel caso generale non riflette l'albero delle directory.

Basta usare

import "myproject/packageN"

e non combattere il sistema di compilazione senza una buona ragione. Il salvataggio di una dozzina di caratteri per importazione in qualsiasi programma non banale non è una buona ragione, perché, ad esempio, i progetti con percorsi di importazione relativi non possono essere acquisiti.

Il concetto di percorsi di importazione ha alcune proprietà importanti:

  • I percorsi di importazione possono essere univoci a livello globale.
  • Insieme a GOPATH, il percorso di importazione può essere tradotto in modo univoco in un percorso di directory.
  • Qualsiasi percorso di directory in GOPATH può essere tradotto senza ambiguità in un percorso di importazione.

Tutto quanto sopra è rovinato utilizzando i percorsi di importazione relativi. Non farlo.

PS: ci sono alcuni punti nel codice legacy nei test del compilatore Go che utilizzano le importazioni relative. ATM, questa è l'unica ragione per cui le relative importazioni sono supportate.


2
Consiglio di dare un'occhiata a questo video introduttivo per una migliore comprensione dei pacchetti e del GOPATH . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter

7
Penso che questo sia un cattivo consiglio. Se finisci per usare gopkg.in per il controllo delle versioni, ad esempio, sei sfortunato con percorsi di importazione assoluti per i tuoi "mini" pacchetti, come descritto sopra. O si interrompe il repository di origine o quello con versione diventa inutile.
Greg,

import "myproject/packageN". myprojectè il nome della cartella che contiene il mio progetto?
securecurve

È completamente sbagliato, come lo uso ora con i repository privati?
agilob,

44

Forse stai cercando di modulare il tuo pacchetto. Sto supponendo che package1epackage2 , in un certo senso, fanno parte dello stesso pacchetto ma per leggibilità li stai dividendo in più file.

Se il caso precedente fosse tuo, potresti usare lo stesso nome di pacchetto in quei file multipli e sarà come se ci fosse lo stesso file.

Questo è un esempio:

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
}

Non sono un esperto Go e questo è il mio primo post in StackOveflow, quindi se hai qualche consiglio sarà ben accolto.


23

Ho un problema simile e la soluzione che sto attualmente usando utilizza i moduli Go 1.11. Ho la seguente struttura

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

E sono in grado di importare package1 e package2 da project1 e project2 usando

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

Dopo aver corso go mod init projects. Posso usare go builddalle directory project1 e project2 o posso farlo go build -o project1/exe project1/*.godalla directory dei progetti.

L'aspetto negativo di questo metodo è che tutti i tuoi progetti finiscono per condividere lo stesso elenco di dipendenze in go.mod. Sto ancora cercando una soluzione a questo problema, ma sembra che potrebbe essere fondamentale.


9

Dall'introduzione di go.mod , penso che sia la gestione dei pacchetti locale che quella esterna diventino più facili. Utilizzando go.mod , è possibile avere progetti go anche al di fuori di GOPATH.

Importa pacchetto locale:

Creare un demoproject cartella ed eseguire il comando seguente per generare il file go.mod

go mod init demoproject

Ho una struttura di progetto come sotto nella directory demoproject .

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

A scopo dimostrativo, inserire il seguente codice nel file model.go .

package model

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

In main.go , ho importato il modello Employee facendo riferimento a "demoproject / src / model"

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

Importa dipendenza esterna:

Corri go get comando all'interno della directory del progetto.

Per esempio:

go get -u google.golang.org/grpc

Dovrebbe includere la dipendenza del modulo nel file 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...(vai a costruire nella cartella di go.mod)
Sebi2020

Tale banalità, ma mi ci è voluto un tempo imbarazzante per trovare la risposta e il tuo post è stato il più leggibile e utile. Grazie!
Harold Cavendish,

8

Per aggiungere un pacchetto "locale" al progetto, aggiungere una cartella (ad esempio "nome_pacchetto"). E metti i tuoi file di implementazione in quella cartella.

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

Nel tuo package mainfare questo:

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

Dov'è package_nameil nome della cartella e deve corrispondere al nome del pacchetto utilizzato nei file whatever_name1.go e whatever_name2.go. In altre parole, tutti i file con una sottodirectory devono essere dello stesso pacchetto.

È possibile nidificare ulteriormente più sottodirectory purché si specifichi l'intero percorso della cartella padre nell'importazione.


2
Questo è un ottimo suggerimento, tranne per il fatto che durante qualsiasi panico del kernel la traccia dello stack che è stata scaricata dal binario mostra ad esempio il percorso github.com, non sempre il comportamento più desiderabile. Ci sono flag per sopprimerlo, ma non dovrebbe essere necessario solo per ottenere una semplice organizzazione dei pacchetti, e ho scoperto che a volte fallisce.
Kenny Powers,

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

3

Puoi usare 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")
}

L'importazione di un pacchetto locale è come importare un pacakge esterno

ad eccezione del file go.mod, sostituisci il nome del pacchetto esterno con una cartella locale.

Il percorso della cartella può essere completo o relativo "/ path / to / bar" o "../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-modulo /

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.