Go build: "Tidak dapat menemukan paket" (meskipun GOPATH diatur)

139

Meskipun saya telah GOPATHmenetapkan dengan benar, saya masih tidak bisa mendapatkan "pergi membangun" atau "jalankan" untuk menemukan paket saya sendiri. Apa yang saya lakukan salah?

$ 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
MitchellSalad
sumber
Saya menemui masalah yang sama ketika saya mendapatkan github.com/adonovan/gopl.io/tree/master/ch1/helloworld . Alasannya karena tidak memiliki file dengan nama helloworld.go. pergi bekerja dengan mencocokkan nama paket dan nama file.
keniee van
Mungkin juga Anda perlu memutakhirkan Go. Saya memiliki masalah serupa dengan kode yang ada menggunakan go.mod untuk mendefinisikan modul. Pada mesin uji saya telah mengunduh kode dan mencoba mengkompilasinya tetapi Go memberi saya segala macam kesalahan yang berhubungan dengan GOPATH dan tidak dapat menemukan modul. Itu Go versi 1.7. Segera setelah saya memutakhirkan Go, itu berfungsi tanpa masalah.
KyferEz
Ketik ini terminal untuk penjelasan terkini$ go help gopath
A1rPun

Jawaban:

162

Ini tidak berfungsi karena foobar.gofile sumber Anda tidak ada dalam direktori bernama foobar. go builddan go installmencoba untuk mencocokkan direktori, bukan sumber file.

  1. Setel $GOPATHke direktori yang valid, misexport GOPATH="$HOME/go"
  2. Pindah foobar.goke $GOPATH/src/foobar/foobar.godan bangunan harus bekerja dengan baik.

Langkah-langkah tambahan yang disarankan:

  1. Tambahkan $GOPATH/binke Anda $PATHoleh:PATH="$GOPATH/bin:$PATH"
  2. Pindah main.goke subfolder dari $GOPATH/src, mis$GOPATH/src/test
  3. go install testseharusnya sekarang membuat executable $GOPATH/binyang dapat dipanggil dengan mengetik testke terminal Anda.
fasmat
sumber
1
Bukankah ini bug? My GOPATH=/usr/local/go-pkgs, so Go mencari /usr/local/go-pkgs/src/<package-name>sumbernya, tetapi go getmemasukkannya ke dalam /usr/local/go-pkgs/src/gopkg.in/<package-name>. Mengapa saya harus memindahkan secara manual semua paket saya setelah menginstal? Itu konyol.
Yosia
3
go getbiasanya memasukkan paket ke dalam $GOPATH/src/jadi jika Anda menyebutnya go get domain.com/path/to/packageakan berakhir pada $GOPATH/src/domain.com/path/to/package. Saya kira Anda mencoba mengambil paket dari gopkg.in? Jika demikian itulah perilaku absolutly yang dimaksudkan dan Anda harus mengimpornya dengan nama lengkap mereka; misalnya import "gopkg.in/yaml.v1"seperti yang dijelaskan dalam dokumen .
fasmat
1
Ahhhh, begitu. Terima kasih telah menghilangkan ketidaktahuan saya.
josiah
10

Edit: karena Anda berarti GOPATH, lihat fasmat 's jawaban (upvoted)

Seperti disebutkan dalam " Bagaimana cara mencari paket saya? ", Anda perlu meletakkan paket xxxdi direktori xxx.

Lihat spesifikasi bahasa Go :

package math

Seperangkat file berbagi PackageNamebentuk yang sama implementasi paket.
Suatu implementasi mungkin mensyaratkan bahwa semua file sumber untuk suatu paket mendiami direktori yang sama.

The Kode organisasi menyebutkan:

Ketika membangun sebuah program yang mengimpor paket " widget" goperintah mencari src/pkg/widgetdi dalam root Go, dan kemudian - jika sumber paket tidak ditemukan di sana - itu mencari src/widgetdi dalam setiap ruang kerja secara berurutan.

("ruang kerja" adalah entri jalur di Anda GOPATH: variabel itu dapat mereferensikan banyak jalur agar ' src, bin, pkg' Anda menjadi)


(Jawaban asli)

Anda juga harus mengatur GOPATHuntuk ~ / pergi, tidak GOROOT, seperti yang diilustrasikan dalam " Cara Menulis Kode Pergi ".

Jalur Go digunakan untuk menyelesaikan pernyataan impor. Ini diimplementasikan oleh dan didokumentasikan dalam paket go / build.

The GOPATHlingkungan daftar variabel tempat untuk mencari kode Go.
Pada Unix, nilainya adalah string yang dipisahkan dengan titik dua.
Pada Windows, nilainya adalah string yang dipisahkan titik koma.
Pada Paket 9, nilainya adalah daftar.

Itu berbeda dari GOROOT:

Distribusi biner Go mengasumsikan mereka akan diinstal di /usr/local/go(atau di c:\Gobawah Windows), tetapi dimungkinkan untuk menginstalnya di lokasi yang berbeda.
Jika Anda melakukan ini, Anda perlu mengatur GOROOTvariabel lingkungan ke direktori itu saat menggunakan alat Go.

VONC
sumber
4
Ada juga intro video pendek untuk menyiapkan GOPATH
Ulf Holm Nielsen
1
Maaf, saya sudah mengedit pertanyaan asli. Di mana-mana saya mengatakan GOROOT saya maksud GOPATH.
MitchellSalad
3

TL; DR: Ikuti konvensi Go! (pelajaran dipelajari dengan cara yang sulit), periksa versi lama dan hapus . Instal terbaru.

Bagi saya solusinya berbeda. Saya bekerja di server Linux bersama dan setelah memverifikasi GOPATHbeberapa variabel lingkungan saya dan lainnya beberapa kali masih tidak berfungsi. Saya mengalami beberapa kesalahan termasuk 'Tidak dapat menemukan paket' dan 'jalur impor tidak dikenal'. Setelah mencoba menginstal ulang dengan solusi ini dengan instruksi pada golang.org (termasuk bagian uninstall ) masih mengalami masalah.

Butuh beberapa waktu untuk menyadari bahwa masih ada versi lama yang belum dihapus (berjalan go versionsekali which golagi ... DAHH) yang membuat saya ke pertanyaan ini dan akhirnya diselesaikan.

Moshisho
sumber
2

Meskipun jawaban yang diterima masih benar tentang perlunya mencocokkan direktori dengan nama paket, Anda benar-benar perlu bermigrasi untuk menggunakan modul Go alih-alih menggunakan GOPATH. Pengguna baru yang mengalami masalah ini mungkin bingung tentang sebutan untuk menggunakan GOPATH (seperti dulu), yang sekarang sudah ketinggalan zaman. Jadi, saya akan mencoba untuk mengatasi masalah ini dan memberikan panduan yang terkait dengan mencegah masalah ini saat menggunakan modul Go.

Jika Anda sudah terbiasa dengan modul Go dan mengalami masalah ini, lewati ke bagian yang lebih spesifik di bawah ini yang mencakup beberapa konvensi Go yang mudah diabaikan atau dilupakan.

Panduan ini mengajarkan tentang modul Go: https://golang.org/doc/code.html

Organisasi proyek dengan modul Go

Setelah Anda bermigrasi ke modul Go, seperti yang disebutkan dalam artikel itu, atur kode proyek seperti yang dijelaskan:

Repositori berisi satu atau lebih modul. Modul adalah kumpulan paket Go terkait yang dirilis bersamaan. Repositori Go biasanya hanya berisi satu modul, yang terletak di akar repositori. File bernama go.mod di sana mendeklarasikan jalur modul: awalan jalur impor untuk semua paket di dalam modul. Modul ini berisi paket-paket dalam direktori yang berisi file go.mod dan juga subdirektori dari direktori itu, hingga subdirektori berikutnya yang berisi file go.mod lain (jika ada).

Setiap jalur modul tidak hanya berfungsi sebagai awalan jalur impor untuk paket-paketnya, tetapi juga menunjukkan di mana perintah go harus mencari untuk mengunduhnya. Misalnya, untuk mengunduh modul golang.org/x/tools, perintah go akan berkonsultasi dengan repositori yang ditunjukkan oleh https://golang.org/x/tools (dijelaskan lebih lanjut di sini).

Jalur impor adalah string yang digunakan untuk mengimpor paket. Jalur impor paket adalah jalur modul yang digabungkan dengan subdirektori dalam modul. Misalnya, modul github.com/google/go-cmp berisi paket di direktori cmp /. Jalur impor paket itu adalah github.com/google/go-cmp/cmp. Paket di perpustakaan standar tidak memiliki awalan jalur modul.

Anda dapat menginisialisasi modul Anda seperti ini:

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

Kode Anda tidak perlu berada di github.com untuk membuatnya. Namun, ini adalah praktik terbaik untuk menyusun modul-modul Anda seolah-olah modul-modul itu pada akhirnya akan diterbitkan.

Memahami apa yang terjadi ketika mencoba untuk mendapatkan paket

Ada artikel bagus di sini yang membahas tentang apa yang terjadi ketika Anda mencoba untuk mendapatkan paket atau modul: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 Ini membahas di mana paket disimpan dan akan membantu Anda memahami mengapa Anda mungkin mendapatkan kesalahan ini jika Anda sudah menggunakan modul Go.

Pastikan fungsi yang diimpor telah diekspor

Perhatikan bahwa jika Anda mengalami kesulitan mengakses suatu fungsi dari file lain, Anda perlu memastikan bahwa Anda telah mengekspor fungsi Anda. Seperti dijelaskan dalam tautan pertama yang saya berikan, fungsi harus dimulai dengan huruf besar yang akan diekspor dan tersedia untuk diimpor ke paket lain.

Nama direktori

Detail penting lainnya (seperti yang disebutkan dalam jawaban yang diterima) adalah bahwa nama direktori adalah apa yang menentukan nama paket Anda. (Nama paket Anda harus mencocokkan nama direktori mereka.) Anda dapat melihat contoh ini di sini: https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc Dengan yang mengatakan, file yang berisi mainmetode Anda (yaitu, titik masuk aplikasi Anda) agak dikecualikan dari persyaratan ini.

Sebagai contoh, saya mengalami masalah dengan impor saya saat menggunakan struktur seperti ini:

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

Saya tidak dapat mengimpor kode utilske dalam mainpaket saya .

Namun, begitu saya menempatkan main.gosubdirektori sendiri, seperti yang ditunjukkan di bawah ini, impor saya bekerja dengan baik:

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

Dalam contoh itu, file go.mod saya terlihat seperti ini:

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

go 1.14

Ketika saya menyimpan main.go setelah menambahkan referensi utils.MyFunction(), IDE saya secara otomatis menarik referensi ke paket saya seperti ini:

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

(Saya menggunakan VS Code dengan ekstensi Golang.)

Perhatikan bahwa jalur impor menyertakan subdirektori ke paket.

Berurusan dengan repo pribadi

Jika kode tersebut merupakan bagian dari repo pribadi, Anda perlu menjalankan perintah git untuk mengaktifkan akses. Jika tidak, Anda dapat menemukan kesalahan lain. Artikel ini menyebutkan cara melakukan itu untuk repositori pribadi Github, BitBucket, dan GitLab: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git- repositories-dfe795068db4 Masalah ini juga dibahas di sini: Apa cara yang tepat untuk "mendapatkan" repositori pribadi?

devinbost
sumber
-6

Apakah Anda mencoba menambahkan direktori mutlak pergi ke 'jalan' Anda?

export PATH=$PATH:/directory/to/go/
RobEdouard
sumber
$ PATH tidak ada hubungannya dengan paket path for go Anda.
csgeek