Đi xây dựng: Có thể tìm gói Gói (mặc dù GOPATH được đặt)


138

Mặc dù tôi có GOPATH đặt đúng, tôi vẫn không thể "đi xây dựng" hoặc "chạy" để tìm các gói của riêng mình. Tôi đang làm gì sai?

$ 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

Tôi gặp vấn đề tương tự khi tôi đi lấy github.com/adonovan/gopl.io/tree/master/ch1/helloworld Lý do là nó không có tệp tên helloworld.go. đi làm việc bằng cách khớp tên gói và tên tệp.
keniee van

Nó cũng có thể là bạn cần nâng cấp Go. Tôi đã có một vấn đề tương tự khi tôi có mã hiện có bằng cách sử dụng go.mod để xác định mô-đun. Trên một máy thử nghiệm, tôi đã tải xuống mã và đang cố biên dịch mã nhưng Go đã đưa ra cho tôi tất cả các loại lỗi liên quan đến GOPATH và không thể tìm thấy các mô-đun. Đó là phiên bản Go 1.7. Ngay khi tôi nâng cấp Go, nó đã hoạt động mà không gặp vấn đề gì.
KyferEz

$ go help gopath
Nhập

Câu trả lời:


161

Nó không hoạt động vì foobar.gotệp nguồn của bạn không có trong một thư mục được gọi foobar. go buildgo installcố gắng khớp các thư mục, không phải tập tin nguồn.

  1. Đặt $GOPATHthành một thư mục hợp lệ, ví dụ:export GOPATH="$HOME/go"
  2. Di chuyển foobar.gođến $GOPATH/src/foobar/foobar.govà xây dựng nên hoạt động tốt.

Các bước được đề xuất bổ sung:

  1. Thêm $GOPATH/binvào của bạn $PATHbằng cách:PATH="$GOPATH/bin:$PATH"
  2. Di chuyển main.go đến thư mục con của $GOPATH/src, vd$GOPATH/src/test
  3. go install testbây giờ nên tạo một tệp thực thi $GOPATH/bincó thể được gọi bằng cách nhập testvào thiết bị đầu cuối của bạn.

1
Đây không phải là một lỗi? My GOPATH=/usr/local/go-pkgs, vì vậy Go tìm kiếm /usr/local/go-pkgs/src/<package-name>nguồn, nhưng go getđặt nó vào /usr/local/go-pkgs/src/gopkg.in/<package-name>. Tại sao tôi phải tự di chuyển tất cả các gói của mình sau khi cài đặt? Điều đó thật ngớ ngẩn.
josiah

3
go getthông thường đặt các gói vào $GOPATH/src/vì vậy nếu bạn gọi go get domain.com/path/to/packagenó sẽ kết thúc $GOPATH/src/domain.com/path/to/package. Tôi đoán bạn cố gắng lấy một gói từ gopkg.in? Nếu vậy đó là hành vi dự định tuyệt đối và bạn chỉ nên nhập chúng với tên đầy đủ của họ; ví dụ import "gopkg.in/yaml.v1"như cũng được mô tả trong các tài liệu .
fasmat

1
À, tôi hiểu rồi. Cảm ơn đã xua tan sự thiếu hiểu biết của tôi.
josiah

10

Chỉnh sửa: vì bạn có nghĩa là GOPATH, hãy xem câu trả lời của fasmat (được nâng cấp)

Như đã đề cập trong phần " Làm thế nào để tôi thực hiện tìm gói của mình? ", Bạn cần đặt một gói xxxtrong một thư mụcxxx .

Xem thông số ngôn ngữ Go :

package math

Một tập hợp các tệp chia sẻ cùng một PackageNamehình thức thực hiện một gói.
Việc triển khai có thể yêu cầu tất cả các tệp nguồn cho một gói nằm trong cùng một thư mục.

Các tổ chức luật đề cập đến:

Khi xây dựng một chương trình nhập gói " widget", golệnh sẽ tìm src/pkg/widgetbên trong gốc Go, và sau đó, nếu nguồn gói không được tìm thấy ở đó, nó sẽ tìm kiếm src/widgetbên trong mỗi không gian làm việc theo thứ tự.

("không gian làm việc" là mục nhập đường dẫn trong GOPATH: biến đó có thể tham chiếu nhiều đường dẫn cho '' của bạn src, bin, pkg)


(Câu trả lời gốc)

Bạn cũng nên đặt GOPATHthành ~ / go, không GOROOT, như được minh họa trong " Cách viết mã đi ".

Đường dẫn Go được sử dụng để giải quyết các báo cáo nhập khẩu. Nó được thực hiện bởi và được ghi lại trong gói go / build.

Biến GOPATHmôi trường liệt kê các địa điểm để tìm mã Go.
Trên Unix, giá trị là một chuỗi phân tách bằng dấu hai chấm.
Trên Windows, giá trị là một chuỗi được phân tách bằng dấu chấm phẩy.
Trên Kế hoạch 9, giá trị là một danh sách.

Điều đó khác với GOROOT:

Các bản phân phối nhị phân Go cho rằng chúng sẽ được cài đặt trong /usr/local/go(hoặc c:\Gotrong Windows), nhưng có thể cài đặt chúng ở một vị trí khác.
Nếu bạn làm điều này, bạn sẽ cần đặt GOROOTbiến môi trường cho thư mục đó khi sử dụng các công cụ Go.


4
Ngoài ra còn có một đoạn giới thiệu video ngắn để thiết lập GOPATH
Ulf Holm Nielsen

1
Xin lỗi, tôi đã chỉnh sửa câu hỏi ban đầu. Ở mọi nơi tôi nói GOROOT tôi có nghĩa là GOPATH.
MitchellSalad

3

TL; DR: Thực hiện theo các quy ước của Go! (bài học đã học một cách khó khăn), kiểm tra các phiên bản cũ và loại bỏ chúng. Cài đặt mới nhất.

Đối với tôi giải pháp là khác nhau. Tôi đã làm việc trên một máy chủ Linux được chia sẻ và sau khi xác minh GOPATHcác biến môi trường của tôi và các biến môi trường khác nhiều lần nó vẫn không hoạt động. Tôi đã gặp một số lỗi bao gồm 'Không thể tìm thấy gói' và 'đường dẫn nhập không được nhận dạng'. Sau khi cố gắng cài đặt lại với giải pháp này theo hướng dẫn trên golang.org (bao gồm cả việc gỡ cài đặt ) vẫn gặp phải sự cố.

Đã cho tôi một thời gian để nhận ra rằng vẫn còn một phiên bản cũ mà chưa được gỡ bỏ cài đặt (chạy go versionsau đó which gomột lần nữa ... DAHH) mà đã cho tôi đến đây câu hỏi và cuối cùng giải quyết.


2

Mặc dù câu trả lời được chấp nhận vẫn đúng về việc cần khớp các thư mục với tên gói, nhưng bạn thực sự cần phải chuyển sang sử dụng các mô-đun Go thay vì sử dụng GOPATH. Người dùng mới gặp phải vấn đề này có thể bị nhầm lẫn về các đề cập đến việc sử dụng GOPATH (như tôi), hiện đã lỗi thời. Vì vậy, tôi sẽ cố gắng làm rõ vấn đề này và cung cấp hướng dẫn liên quan đến việc ngăn chặn vấn đề này khi sử dụng các mô-đun Go.

Nếu bạn đã quen thuộc với các mô-đun Go và đang gặp phải vấn đề này, hãy bỏ qua các phần cụ thể hơn của tôi bên dưới, bao gồm một số quy ước về Go dễ bị bỏ qua hoặc quên.

Hướng dẫn này dạy về các mô-đun Go: https://golang.org/doc/code.html

Tổ chức dự án với các mô đun Go

Khi bạn di chuyển sang các mô-đun Go, như được đề cập trong bài viết đó, hãy tổ chức mã dự án như được mô tả:

Một kho chứa một hoặc nhiều mô-đun. Một mô-đun là một tập hợp các gói Go liên quan được phát hành cùng nhau. Kho lưu trữ Go thường chỉ chứa một mô-đun, nằm ở thư mục gốc của kho lưu trữ. Một tệp có tên go.mod ở đó khai báo đường dẫn mô-đun: tiền tố đường dẫn nhập cho tất cả các gói trong mô-đun. Mô-đun chứa các gói trong thư mục chứa tệp go.mod của nó cũng như các thư mục con của thư mục đó, cho đến thư mục con tiếp theo chứa tệp go.mod khác (nếu có).

Đường dẫn của mỗi mô-đun không chỉ đóng vai trò là tiền tố đường dẫn nhập cho các gói của nó mà còn cho biết lệnh go sẽ tìm ở đâu để tải xuống. Ví dụ: để tải xuống mô-đun golang.org/x/tools, lệnh go sẽ tham khảo kho lưu trữ được chỉ định bởi https://golang.org/x/tools (được mô tả thêm tại đây).

Đường dẫn nhập là một chuỗi được sử dụng để nhập gói. Đường dẫn nhập của gói là đường dẫn mô-đun được nối với thư mục con trong mô-đun. Ví dụ: mô-đun github.com/google/go-cmp chứa một gói trong thư mục cmp /. Đường dẫn nhập của gói đó là github.com/google/go-cmp/cmp. Các gói trong thư viện chuẩn không có tiền tố đường dẫn mô-đun.

Bạn có thể khởi tạo mô-đun của mình như thế này:

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

Mã của bạn không cần phải được đặt trên github.com để xây dựng mã. Tuy nhiên, đó là cách tốt nhất để cấu trúc các mô-đun của bạn như thể cuối cùng chúng sẽ được xuất bản.

Hiểu những gì xảy ra khi cố gắng để có được một gói

Có một bài viết tuyệt vời ở đây nói về những gì xảy ra khi bạn cố gắng nhận gói hoặc mô-đun: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 Nó thảo luận về nơi gói được lưu trữ và sẽ giúp bạn hiểu lý do tại sao bạn có thể gặp lỗi này nếu bạn đang sử dụng các mô-đun Go.

Đảm bảo chức năng đã nhập

Lưu ý rằng nếu bạn gặp sự cố khi truy cập một chức năng từ một tệp khác, bạn cần đảm bảo rằng bạn đã xuất khẩu chức năng của mình. Như được mô tả trong liên kết đầu tiên tôi cung cấp, một chức năng phải bắt đầu bằng một chữ cái viết hoa được xuất khẩu và có sẵn để nhập vào các gói khác.

Tên của thư mục

Một chi tiết quan trọng khác (như đã được đề cập trong câu trả lời được chấp nhận) là tên của các thư mục là những gì xác định tên của các gói của bạn. (Tên gói của bạn cần khớp với tên thư mục của chúng.) Bạn có thể xem các ví dụ về điều này tại đây: https://medium.com/rungo/everything-you-need-to-ledge-about-packages-in-go-b8bac62b74cc Với có nghĩa là, tệp chứa mainphương thức của bạn (nghĩa là điểm vào của ứng dụng của bạn) là loại được miễn yêu cầu này.

Ví dụ, tôi gặp vấn đề với hàng nhập khẩu của mình khi sử dụng cấu trúc như thế này:

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

Tôi không thể nhập mã utilsvào maingói của tôi .

Tuy nhiên, một khi tôi đưa main.govào thư mục con của riêng nó, như được hiển thị bên dưới, hàng nhập của tôi hoạt động tốt:

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

Trong ví dụ đó, tệp go.mod của tôi trông như thế này:

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

go 1.14

Khi tôi đã lưu main.go sau khi thêm một tham chiếu vào utils.MyFunction(), IDE của tôi sẽ tự động kéo tham chiếu vào gói của tôi như thế này:

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

(Tôi đang sử dụng Mã VS với tiện ích mở rộng Golang.)

Lưu ý rằng đường dẫn nhập bao gồm thư mục con vào gói.

Xử lý một repo riêng

Nếu mã là một phần của repo riêng, bạn cần chạy lệnh git để cho phép truy cập. Mặt khác, bạn có thể gặp phải các lỗi khác Bài viết này đề cập đến cách thực hiện điều đó đối với các repos Github, BitBucket và GitLab riêng tư: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git- kho lưu trữ-dfe795068db4 Vấn đề này cũng được thảo luận ở đây: cách thích hợp để "đi lấy" một kho lưu trữ riêng là gì?


-6

Bạn đã thử thêm các thư mục tuyệt đối của đường đi đến 'con đường' của bạn?

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

$ PATH không liên quan gì đến đường dẫn của bạn cho các gói đi.
csgeek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.