Derlemeye git: "Paket bulunamıyor" (GOPATH ayarlanmış olsa bile)


139

GOPATHDüzgün bir şekilde ayarlamış olsam da , kendi paketlerimi bulmak için "go build" veya "go run" alamıyorum. Neyi yanlış yapıyorum?

$ echo $GOROOT
/usr/local/go

$ echo $GOPATH
/home/mitchell/go

$ cat ~/main.go
package main
import "foobar"
func main() { }

$ cat /home/mitchell/go/src/foobar.go
package foobar

$ go build main.go
main.go:3:8: import "foobar": cannot find package

Github.com/adonovan/gopl.io/tree/master/ch1/helloworld adresine gittiğimde aynı problemle karşılaşıyorum Nedeni helloworld.go adında bir dosya olmaması olacak. paket adı ve dosya adını eşleştirerek çalışmaya gidin.
keniee van

Ayrıca, Go'yu yükseltmeniz gerekebilir. Bir modülü tanımlamak için go.mod kullanarak mevcut kodumun olduğu benzer bir sorun yaşadım. Bir test makinesinde kodu indirmiştim ve onu derlemeye çalışıyordum ama Go bana GOPATH ile ilgili her türlü hatayı veriyordu ve modül bulamamaktaydı. Go sürüm 1.7 idi. Go'yu yükselttikten hemen sonra sorunsuz çalıştı.
KyferEz

Güncel bir açıklama için bu terminali yazın$ go help gopath
A1rPun

Yanıtlar:


163

foobar.goKaynak dosyanız adlı bir dizinde olmadığı için çalışmaz foobar. go buildve go installkaynak dosyaları değil, dizinleri eşleştirmeye çalışın.

  1. $GOPATHGeçerli bir dizine ayarlayın , örn.export GOPATH="$HOME/go"
  2. Taşı foobar.goiçin $GOPATH/src/foobar/foobar.gove bina sadece iyi çalışması gerekir.

Önerilen ek adımlar:

  1. Ekle $GOPATH/binsizin için $PATHsaldırıdaki:PATH="$GOPATH/bin:$PATH"
  2. Taşı main.gobir alt klasöre $GOPATH/src, örneğin$GOPATH/src/test
  3. go install testşimdi terminalinize $GOPATH/binyazarak çağrılabilecek bir yürütülebilir dosya oluşturmalısınız test.

1
Bu bir hata değil mi? Benim GOPATH=/usr/local/go-pkgs, öyleyse Go /usr/local/go-pkgs/src/<package-name>kaynağı arar , ama go getonu yerleştirir /usr/local/go-pkgs/src/gopkg.in/<package-name>. Yüklemeden sonra neden tüm paketleri el ile taşımam gerekiyor? Bu çok aptalca.
josiah

3
go getnormalde paketleri içine koyar, $GOPATH/src/böylece ararsanız go get domain.com/path/to/packageson bulacaktır $GOPATH/src/domain.com/path/to/package. Sanırım içinden bir paket almaya çalışıyorsun gopkg.in? Bu kesinlikle amaçlanan bir davranışsa ve bunları tam adıyla içe aktarmanız gerekiyorsa; örneğin belgelerdeimport "gopkg.in/yaml.v1" de açıklandığı gibi .
fasmat

1
Ahhhh, anlıyorum. Cehaletimi giderdiğin için teşekkürler.
josiah

10

Düzenle: GOPATH demek beri, bkz fasmat 'ın cevabı (upvoted)

" Paketimi nasıl bulabilirim? " De belirtildiği gibi, xxxbir dizine bir paket koymanız gerekir xxx.

Go dil spesifikasyonuna bakın :

package math

Bir PackageNamepaketin uygulanışıyla aynı formu paylaşan bir dizi dosya .
Bir uygulama, bir paket için tüm kaynak dosyalarının aynı dizinde bulunmasını gerektirebilir.

Kod organizasyonu bahseder:

Paketi " widget" içe aktaran bir program oluştururken gokomut src/pkg/widgetGo kökünün içinde arar ve ardından - paket kaynağı orada bulunamazsa src/widget- sırayla her çalışma alanının içini arar .

("çalışma alanı", sizin için bir yol girişidir GOPATH: bu değişken, sizin ' src, bin, pkg' için birden çok yola başvurabilir )


(Orijinal cevap)

Ayrıca , " Go Kodu Nasıl Yazılır" bölümünde gösterildiği gibi GOPATH, ~ / go olarak ayarlamalısınız .GOROOT

Git yolu, içe aktarma ifadelerini çözmek için kullanılır. Go / build paketi tarafından uygulanır ve belgelenir.

GOPATHOrtam değişkeni listeleri yerleri Git koduna bakmak için.
Unix'te değer, iki nokta üst üste ile ayrılmış bir dizedir.
Windows'ta değer, noktalı virgülle ayrılmış bir dizedir.
Plan 9'da değer bir listedir.

Bu şundan farklıdır GOROOT:

Go ikili dağıtımları, bunların Windows içine /usr/local/go(veya c:\GoWindows altında) yükleneceğini varsayar , ancak bunları farklı bir konuma kurmak mümkündür.
Bunu yaparsanız GOROOT, Go araçlarını kullanırken ortam değişkenini o dizine ayarlamanız gerekecektir .


4
Ayrıca GOPATH
Ulf Holm Nielsen

1
Üzgünüm, orijinal soruyu düzenledim. GOROOT dediğim her yerde GOPATH'ı kastettim .
MitchellSalad

3

TL; DR: Go kurallarına uyun! (ders zor yoldan öğrendi), eski sürümleri kontrol edin ve kaldırın . En yeniyi yükleyin.

Benim için çözüm farklıydı. Paylaşılan bir Linux sunucusu üzerinde çalıştım ve benim GOPATHve diğer ortam değişkenlerimi birkaç kez doğruladıktan sonra hala çalışmadı. 'Paket bulunamıyor' ve 'tanınmayan içe aktarma yolu' dahil olmak üzere birkaç hatayla karşılaştım. Bu çözümle golang.org'daki talimatlarla ( kaldırma kısmı dahil ) yeniden yüklemeyi denedikten sonra hala sorunlarla karşılaşıldı.

Beni bu soruya götüren ve sonunda çözülen , hala kaldırılmamış ( go versionsonra which gotekrar çalışıyor ... DAHH) eski bir sürümün olduğunu fark etmem biraz zaman aldı .


2

Dizinleri paket adlarıyla eşleştirme ihtiyacı konusunda kabul edilen yanıt hala doğru olsa da, GOPATH kullanmak yerine gerçekten Go modüllerini kullanmaya geçmeniz gerekir. Bu sorunla karşılaşan yeni kullanıcıların, artık modası geçmiş olan GOPATH (benim gibi) kullanımından bahsedilmesi konusunda kafaları karışabilir. Bu yüzden, bu sorunu gidermeye çalışacağım ve Go modüllerini kullanırken bu sorunu önlemeyle ilgili rehberlik sağlayacağım.

Go modüllerine zaten aşina iseniz ve bu sorunu yaşıyorsanız, göz ardı edilmesi veya unutulması kolay olan bazı Go kurallarını kapsayan aşağıdaki daha özel bölümlerime geçin.

Bu kılavuz, Go modülleri hakkında bilgi verir: https://golang.org/doc/code.html

Go modülleri ile proje organizasyonu

O makalede belirtildiği gibi Go modüllerine geçtikten sonra, proje kodunu açıklandığı gibi düzenleyin:

Bir arşiv, bir veya daha fazla modül içerir. Modül, birlikte yayımlanan ilgili Go paketlerinin bir koleksiyonudur. Bir Go deposu, genellikle havuzun kökünde bulunan tek bir modül içerir. Burada go.mod adlı bir dosya modül yolunu bildirir: modül içindeki tüm paketler için içe aktarma yolu öneki. Modül, başka bir go.mod dosyası (varsa) içeren bir sonraki alt dizine kadar, go.mod dosyasını içeren dizindeki paketleri ve bu dizinin alt dizinlerini içerir.

Her modülün yolu yalnızca paketleri için bir içe aktarma yolu öneki işlevi görmez, aynı zamanda go komutunun onu indirmek için nereye bakması gerektiğini de belirtir. Örneğin, golang.org/x/tools modülünü indirmek için, go komutu https://golang.org/x/tools (burada daha fazla açıklanmıştır) tarafından belirtilen depoya başvurur .

İçe aktarma yolu, bir paketi içe aktarmak için kullanılan bir dizedir. Bir paketin içe aktarma yolu, modül içindeki alt diziniyle birleştirilen modül yoludur. Örneğin, github.com/google/go-cmp modülü cmp / dizininde bir paket içerir. Bu paketin içe aktarma yolu github.com/google/go-cmp/cmp şeklindedir. Standart kitaplıktaki paketlerin modül yolu öneki yoktur.

Modülünüzü şu şekilde başlatabilirsiniz:

$ go mod init github.com/mitchell/foo-app

Kodunuzun oluşturulması için github.com'da bulunması gerekmez. Ancak, modüllerinizi eninde sonunda yayınlanacaklar gibi yapılandırmak en iyi uygulamadır.

Bir paket almaya çalışırken ne olduğunu anlamak

Burada bir paket veya modül almaya çalıştığınızda ne olacağını anlatan harika bir makale var: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 Paketin nerede saklandığını ve nerede olacağını tartışıyor Go modüllerini zaten kullanıyorsanız neden bu hatayı aldığınızı anlamanıza yardımcı olur.

İçe aktarılan işlevin dışa aktarıldığından emin olun

Başka bir dosyadan bir işleve erişmede sorun yaşıyorsanız, işlevinizi dışa aktardığınızdan emin olmanız gerektiğini unutmayın. Sağladığım ilk bağlantıda açıklandığı gibi, bir işlevin dışa aktarılması ve diğer paketlere içe aktarılmaya uygun hale getirilmesi için büyük harfle başlaması gerekir.

Dizin isimleri

Diğer bir kritik ayrıntı da (kabul edilen cevapta bahsedildiği gibi), dizin adlarının paketlerinizin adlarını tanımlamasıdır. (Paketiniz adları dizini adlarla eşleşmesi gerekir.) Burada bu örnekler görebilirsiniz: https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc ile Bununla birlikte, mainyönteminizi içeren dosya (yani başvurunuzun giriş noktası) bu gereklilikten muaftır.

Örnek olarak, böyle bir yapı kullanırken ithalatımla ilgili sorunlar yaşadım:

/my-app
├── go.mod
├── /src
   ├── main.go
   └── /utils
      └── utils.go

Ben kodu almak edemedi utilsbenim içine mainpaketin.

Ancak, main.goaşağıda gösterildiği gibi kendi alt dizinine koyduğumda , içe aktarmalarım gayet iyi çalıştı:

/my-app
├── go.mod
├── /src
   ├── /app
   |  └── main.go
   └── /utils
      └── utils.go

Bu örnekte, go.mod dosyam şöyle görünür:

module git.mydomain.com/path/to/repo/my-app

go 1.14

Bir referans ekledikten sonra main.go'yu kaydettiğimde, IDE'm referansı paketime şu şekilde utils.MyFunction()otomatik olarak çekti:

import "git.mydomain.com/path/to/repo/my-app/src/my-app"

(Golang uzantısıyla VS Code kullanıyorum.)

İçe aktarma yolunun pakete alt dizini içerdiğine dikkat edin.

Özel bir depo ile uğraşmak

Kod özel bir deponun parçasıysa, erişimi etkinleştirmek için bir git komutu çalıştırmanız gerekir. Aksi takdirde başka hatalarla karşılaşabilirsiniz Bu makale özel Github, BitBucket ve GitLab depoları için bunun nasıl yapılacağını anlatır: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git- repositories-dfe795068db4 Bu konu ayrıca burada tartışılmaktadır: Özel bir depoyu "almaya gitmenin" doğru yolu nedir?


-6

Eğer mutlak dizin ekleyerek denediniz halindeyken sizin 'yol' için?

export PATH=$PATH:/directory/to/go/

$ PATH'in sizin git paketleri yolunuzla ilgisi yoktur.
csgeek
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.