Yerel paketleri gopath olmadan içe aktarma


171

Ben kullandım GOPATHama bu mevcut sorun için ben yardımcı olmuyor. Bir projeye özgü paketler oluşturmak istiyorum:

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

Ben birden fazla yol çalıştı ama nasıl alırım package1.goiş için binary1.goveya binary2.goüzerinde ve böylece?

Örneğin; Ben edebilmek istiyorum import "package1"ve daha sonra çalıştırmak mümkün go build binary1.gove her şey hata paket bulunabilir edilemeyeceğini atılan olmadan cezası çalışır GOROOTveya GOPATH. Bu tür bir işleve ihtiyaç duymamın nedeni büyük ölçekli projeler için; Birden fazla pakete başvurmak veya bunları büyük bir dosyada tutmak istemiyorum.


2
Her bir ikili dosya için kaynak dosyalarını kendi dizinine koymanız gerekir.
fuz

.goTek bir dizindeki tüm dosyalar aynı paketin parçasıdır importve aynı paketteki (yani aynı dizindeki) dosyalara ihtiyacınız yoktur . Yeni Go modülleri sisteminin yeteneklerinden biri olan GOPATH dışında çalışmayı söylemiştiniz. Bu cevap kapakları vb tek depoda birden modüllerini olması olsun veya olmasın bir modül içindeki paketleri düzenlenmesi, yerel paketler ithal yapısını modülü
typical182

3
Ve bu davranış herkes için uygun mu? Tüm git/repo/to/my/projectyolu belirtmedikçe temel olarak yerel alt paketlerinizi içe aktaramayacağınızı mı düşünüyorsunuz? Kimsenin bu davranışı istemesinin nedenini görmüyorum. Projenizi başka bir konuma (örneğin Docker görüntüsü) taşırsanız, tüm yolları tekrar değiştirmeniz gerekir? Bunun neden bu kadar karmaşık olduğunu cevapları arıyorum.
milosm

Yanıtlar:


176

Go bağımlılık yönetimi özeti:

  • vgo go sürümünüz: x >= go 1.11
  • depveya vendorgo sürümünüz:go 1.6 >= x < go 1.11
  • Git sürümünüz manuel olarak: x < go 1.6

Edit 3: Go 1.11'in yerini alacak bir özelliği vgovar . dep

Kullanmak için Modül belgelerine vgobakın . Aşağıdaki TLDR:

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

Bu yöntem, go.modprojeler dizininizde bir dosya oluşturur . Daha sonra projenizi ile inşa edebilirsiniz go build. Eğer GO111MODULE=autoayarlanır, sonra proje olamaz $GOPATH.


Düzenleme 2: Tedarikçi yöntemi hala geçerlidir ve sorunsuz çalışır. vendorbu nedenle büyük ölçüde manuel bir süreçtir depve vgoyaratılmıştır.


Düzenleme 1: Eski yolum çalışıyor olsa da, artık "doğru" yolu değil. Sen kullanarak olmalıdır satıcı yetenekleri, vgoya depgit 1.6 varsayılan olarak etkin olduğunu (şimdilik); bakın . Temel olarak "harici" veya "bağımlı" paketlerinizi bir vendordizine eklersiniz ; derleme önce derleyici bu paketleri kullanacaktır.


Bulundu. Birlikte mümkün ithalat yerel paketi oldu GOPATHbir alt klasör oluşturarak package1ve daha sonra ithal import "./package1"içinde binary1.gove binary2.gobunun gibi komut:

binary1.go

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

Yani şu anki dizin yapım şöyle:

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

Ayrıca göreceli yollar (en azından 1.5 gidin) de işe yarar; Örneğin:

import "../packageX"

4
Biri diğerine atıfta bulunan iki alt klasör olana kadar bu işe yarar. Örneğin, paket2 de bir alt klasörse ve paket1'e ihtiyaç duyduysa, sistem bozulur.
Carl

7
import "../package1"
Felix Rabe

12
Göreli içe aktarma yolları kötü bir fikirdir .
Dave C

1
#golang 'ad alanı' sağlıyorsa, 'göreli içe aktarma yolunun' veya 'alt paketlerin' kötü fikir olduğunu 'kabul edebilirim.
mission.liao

1
İşlev adı
Capitilized

71

"Yerel paket" diye bir şey yoktur. Bir disk üzerindeki paketlerin organizasyonu, paketlerin üst / alt ilişkilerine diktir. Paketlerin oluşturduğu tek gerçek hiyerarşi, genel durumda dizin ağacını yansıtmayan bağımlılık ağacıdır.

Sadece kullan

import "myproject/packageN"

iyi bir sebep olmadan inşa sistemi ile savaşmayın. Önemsiz herhangi bir programda içe aktarma başına bir düzine karakter kaydetmek iyi bir neden değildir, çünkü örneğin, göreli içe aktarma yollarına sahip projeler alınamaz.

İçe aktarma yolları kavramının bazı önemli özellikleri vardır:

  • İçe aktarma yolları global olarak benzersiz olabilir.
  • GOPATH ile birlikte, içe aktarma yolu açık bir şekilde bir dizin yoluna çevrilebilir.
  • GOPATH altındaki herhangi bir dizin yolu açık bir şekilde bir içe aktarma yoluna çevrilebilir.

Yukarıdakilerin tümü, göreli içe aktarma yolları kullanılarak mahvedilir. Bunu yapma.

Not: Go derleyici testlerinde eski kodda göreli içe aktarma kullanan birkaç yer vardır. ATM, göreli ithalatların desteklenmesinin tek nedeni budur.


2
Paketleri ve GOPATH'ı daha iyi anlamak için bu tanıtım videosuna göz atmanızı öneririm . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter

7
Bence bu kötü bir tavsiye. Örneğin, sürümleme için gopkg.in'i kullanırsanız, yukarıda açıklandığı gibi "mini" paketleriniz için mutlak içe aktarma yollarıyla şansınız kalmaz. Ya kaynak repoyu bozarsınız ya da versiyonlanmış olanı işe yaramaz hale gelir.
Greg

import "myproject/packageN". myprojecttutan klasör adı nedir?
Sececurve

Bu tamamen yanlış, şimdi özel depolarla nasıl kullanırım?
agilob

44

Belki paketinizi modüler hale getirmeye çalışıyorsunuzdur. Varsayıyorum package1vepackage2 bir şekilde aynı paketin bir parçası ama okunabilirlik için bunları birden fazla dosyaya bölüyorsunuz.

Önceki durum sizinkiyse, aynı paket adını bu birden çok dosyaya kullanabilirsiniz ve aynı dosya varmış gibi görünecektir.

Bu bir örnektir:

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
}

Ben bir Go uzmanı değilim ve bu benim ilk yazı StackOveflow, yani bazı tavsiyeleriniz varsa iyi karşılanacaktır.


23

Benzer bir sorunum var ve şu anda kullandığım çözüm Go 1.11 modüllerini kullanıyor. Aşağıdaki yapıya sahibim

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

Ve kullanarak package1 ve package2'yi project1 ve project2'den alabilirim

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

Koştuktan sonra go mod init projects. Ben kullanabilir go buildproject1 ve Project2 dizinleri veya Yapabileceğim go build -o project1/exe project1/*.goprojeler dizinden.

Bu yöntemin dezavantajı, tüm projelerinizin go.mod'da aynı bağımlılık listesini paylaşmasıdır. Hala bu soruna bir çözüm arıyorum, ancak bu temel olabilir.


9

Go.mod'un tanıtımından bu yana, hem yerel hem de harici paket yönetiminin daha kolay hale geldiğini düşünüyorum. Go.mod kullanarak, GOPATH dışında da projeye sahip olmak mümkündür.

Yerel paketi içe aktar:

Bir klasör demoproject oluşturun ve go.mod dosyası oluşturmak için aşağıdaki komutu çalıştırın

go mod init demoproject

Demoproject dizini içinde aşağıdaki gibi bir proje yapısı var .

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

Demo amaçlı olarak, model.go dosyasına aşağıdaki kodu ekleyin .

package model

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

In main.go , ben "Demoproject / src / model" başvurarak Çalışan modeli içe

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

Dış bağımlılığı içe aktarma:

Sadece koş go get proje dizininde komut .

Örneğin:

go get -u google.golang.org/grpc

Go.mod dosyasında modül bağımlılığını içermelidir

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 klasörüne gidin)
Sebi2020

Böyle bir banallik ama cevabı bulmak utanç verici bir zaman aldı ve yayınınız en okunaklı ve yararlı oldu. Teşekkür ederim!
Harold Cavendish

8

Projenize "yerel" bir paket eklemek için bir klasör ekleyin (örneğin "paket_adı"). Ve uygulama dosyalarınızı bu klasöre koyun.

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

Bunu sizde yapın package main:

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

Nerede package_nameKlasör adı ve whatever_name1.go ve whatever_name2.go dosyalarında kullanılan paket adıyla eşleşmelidir. Başka bir deyişle, alt dizine sahip tüm dosyalar aynı pakette olmalıdır.

İçe aktarma işleminde üst klasörün tam yolunu belirttiğiniz sürece daha fazla alt dizini iç içe yerleştirebilirsiniz.


2
Bu iyi bir öneridir, ancak herhangi bir çekirdek paniği sırasında, ikili dosyadan atılan yığın izinin örneğin her zaman en çok istenen davranış değil, github.com yolunu göstermesi dışında. Bunu bastırmak için bayraklar var, ancak sadece basit paket organizasyonuna ulaşmak için gerekli olmamalı ve zaman zaman başarısız olduğunu gördüm.
Kenny Powers

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

3

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

Yerel bir paketi içe aktarmak tıpkı harici bir pacakge ithal etmek gibidir

go.mod dosyasının dışında, bu dış paket adını yerel bir klasörle değiştirirsiniz.

Klasör yolu dolu veya göreli olabilir "/ path / to / bar" veya "../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-yerel-modül /

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.