gopath없이 로컬 패키지를 가져 오는 방법


171

나는 사용 GOPATH했지만이 현재 문제에 직면하고 있는데 도움이되지 않습니다. 프로젝트와 관련된 패키지를 만들 수 있기를 원합니다.

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

나는 여러 가지 방법을 시도했지만 어떻게받을 수 있나요 package1.go[작업에 binary1.gobinary2.go에 그래서?

예를 들어; 나는 할 수 있도록하려면 import "package1"다음 실행할 수 go build binary1.go및 모든 오류가 패키지에서 찾을 수 없음을 발생하지 않고 잘 작동 GOROOT하거나 GOPATH. 이런 종류의 기능이 필요한 이유는 대규모 프로젝트를위한 것입니다. 다른 여러 패키지를 참조하거나 하나의 큰 파일로 유지하고 싶지 않습니다.


2
각 바이너리의 소스 파일을 자체 디렉토리에 저장해야합니다.
fuz

.go단일 디렉토리의 모든 파일은 동일한 패키지의 일부이므로 import동일한 패키지 (예 : 동일한 디렉토리)의 파일이 필요하지 않습니다 . 새로운 Go 모듈 시스템의 기능 중 하나 인 GOPATH 외부에서 작업하는 것을 언급했습니다. 이 응답 커버 등 단일 저장소에 여러 개의 모듈을 가지고 있는지 여부, 모듈 내에서 패키지를 배치, 현지 패키지를 가져 오기 구조를 모듈
typical182

3
그리고이 행동은 모든 사람에게 괜찮습니까? 전체 git/repo/to/my/project경로 를 지정하지 않으면 기본적으로 로컬 하위 패키지를 가져올 수 없습니까? 나는 누군가 가이 행동을 원하는 이유를 보지 못합니다. 프로젝트를 다른 위치 (예 : Docker 이미지)로 옮길 경우 모든 경로를 다시 변경해야합니까? 왜 이것이 그렇게 복잡한 지에 대한 답을 찾고 있습니다.
milosmns

답변:


176

이동 종속성 관리 요약 :

  • vgo 이동 버전이 다음과 같은 경우 : x >= go 1.11
  • dep또는 vendor이동 버전이 다음 과 같은 경우 :go 1.6 >= x < go 1.11
  • go 버전이 다음과 같은 경우 수동으로 : x < go 1.6

편집 3 : Go 1.11에는 대체 할 기능 vgo이 있습니다. dep

를 사용하려면 모듈 설명서를 vgo참조하십시오 . 아래의 TLDR :

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

이 메소드는 go.mod프로젝트 디렉토리에서 호출 된 파일을 작성합니다 . 그런 다음로 프로젝트를 빌드 할 수 있습니다 go build. GO111MODULE=auto이 설정되어 있으면 프로젝트가에있을 수 없습니다 $GOPATH.


편집 2 : 공급 업체 방법이 여전히 유효하며 문제없이 작동합니다. vendor이 때문에, 주로 수동 프로세스입니다 depvgo작성되었습니다.


편집 1 : 내 옛날 방식은 더 이상 "올바른"방법이 아닙니다. 당신은 사용해야 공급 업체의 능력을, vgo또는 dep이동 1.6에서 기본적으로 사용되는 (지금은) 참조하십시오 . 기본적으로 vendor디렉토리 내에 "외부"또는 "종속"패키지를 추가합니다 . 컴파일시 컴파일러는이 패키지를 먼저 사용합니다.


녹이다. GOPATH하위 폴더를 package1만든 다음 과 같은 import "./package1"in binary1.gobinary2.go스크립트를 사용 하여 로컬 패키지를 가져올 수있었습니다 .

binary1.go

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

따라서 현재 디렉토리 구조는 다음과 같습니다.

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

또한 상대 경로 (적어도 1.5 이상)도 작동합니다. 예를 들면 다음과 같습니다.

import "../packageX"

4
하나는 서로 참조하는 두 개의 하위 폴더가있을 때까지 정상적으로 작동합니다. 예를 들어 package2도 하위 폴더이고 package1이 필요한 경우 시스템이 중단됩니다.
Carl

7
import "../package1"
Felix Rabe

12
상대적인 가져 오기 경로는 좋지 않습니다 .
Dave C

1
#golang이 '네임 스페이스'를 제공하는 경우 '상대 가져 오기 경로'또는 '하위 패키지'는 나쁜 아이디어라는 데 동의 할 수 있습니다. '
mission.liao

1
기능 이름은 Capitilized 키워드로 시작해야합니다
kokemomuke

71

"로컬 패키지"와 같은 것은 없습니다. 디스크의 패키지 구성은 패키지의 상위 / 하위 관계와 직교합니다. 패키지에 의해 형성된 유일한 실제 계층은 종속성 트리이며, 일반적으로 디렉토리 트리를 반영하지 않습니다.

그냥 사용

import "myproject/packageN"

정당한 이유없이 빌드 시스템과 싸우지 마십시오. 예를 들어, 상대적 가져 오기 경로가있는 프로젝트는 얻을 수 없기 때문에 사소하지 않은 프로그램에서 가져 오기 당 12 개의 문자를 저장하는 것은 좋은 이유가 아닙니다.

가져 오기 경로의 개념에는 몇 가지 중요한 특성이 있습니다.

  • 가져 오기 경로는 전 세계적으로 고유 할 수 있습니다.
  • GOPATH와 함께 가져 오기 경로를 명확하게 디렉토리 경로로 변환 할 수 있습니다.
  • GOPATH 아래의 모든 디렉토리 경로는 명확하게 가져 오기 경로로 변환 될 수 있습니다.

위의 모든 것은 상대 가져 오기 경로를 사용하여 망칩니다. 하지마.

추신 : Go 컴파일러 테스트의 레거시 코드에는 상대적 가져 오기를 사용하는 곳이 거의 없습니다. ATM, 이것이 상대 수입이 전혀 지원되는 유일한 이유입니다.


2
패키지GOPATH에 대한 이해를 돕기 위해이 소개 비디오를 살펴 보는 것이 좋습니다 . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter

7
나는 이것이 나쁜 조언이라고 생각합니다. 예를 들어, 버전 관리에 gopkg.in을 사용하면 위에서 설명한대로 "미니"pakage에 대한 절대 가져 오기 경로가 좋지 않습니다. 소스 저장소를 손상 시키거나 버전이 지정된 저장소는 쓸모 없게됩니다.
그렉

import "myproject/packageN". myproject내 프로젝트를 보유한 폴더 이름은 무엇입니까?
securecurve

그것은 완전히 잘못되었습니다. 지금 개인 저장소와 함께 어떻게 사용합니까?
agilob

44

아마도 패키지를 모듈화하려고합니다. 나는 그 있으리라 믿고있어 package1하고 package2있으며, 방법으로, 동일한 패키지의 일부를하지만 가독성 당신이있는 거 분할 여러 파일로 사람들을 위해.

이전 사례가 본인의 사례 인 경우 여러 패키지에 동일한 패키지 이름을 사용할 수 있으며 동일한 파일이있는 것처럼 보입니다.

이것은 예입니다 :

add.go

package math

func add(n1, n2 int) int {
   return n1 + n2
}

빼기

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
}

나는 Go 전문가가 아니며 이것이 StackOveflow의 첫 번째 게시물이므로 조언이 있으면 잘 받아 들일 것입니다.


23

비슷한 문제가 있으며 현재 사용중인 솔루션은 Go 1.11 모듈을 사용합니다. 나는 다음과 같은 구조를 가지고 있습니다

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

그리고 나는 project1과 project2에서 package1과 package2를 사용하여 가져올 수 있습니다

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

실행 후 go mod init projects. go buildproject1 및 project2 디렉토리에서 사용 하거나 go build -o project1/exe project1/*.goprojects 디렉토리에서 수행 할 수 있습니다 .

이 방법의 단점은 모든 프로젝트가 go.mod에서 동일한 종속성 목록을 공유한다는 것입니다. 여전히이 문제에 대한 해결책을 찾고 있지만 근본적인 것처럼 보입니다.


9

go.mod를 도입 한 이후로 로컬 및 외부 패키지 관리가 더 쉬워 졌다고 생각합니다. go.mod를 사용하면 GOPATH 외부에서도 프로젝트를 진행할 수 있습니다.

로컬 패키지 가져 오기 :

폴더 demoproject를 만들고 다음 명령을 실행하여 go.mod 파일 을 생성 하십시오.

go mod init demoproject

demoproject 디렉토리 안에 아래와 같은 프로젝트 구조가 있습니다 .

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

데모 목적으로 model.go 파일 에 다음 코드를 삽입 하십시오.

package model

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

에서 main.go , 나는 "demoproject / SRC / 모델"을 참조하여 직원 모델을 수입

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

외부 의존성 가져 오기 :

go get프로젝트 디렉토리 내에서 명령을 실행 하십시오.

예를 들면 다음과 같습니다.

go get -u google.golang.org/grpc

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...(go.mod 폴더에 빌드)
Sebi2020

그러한 금지는 있지만 답을 찾는 데 창피한 시간이 걸렸으며 귀하의 게시물이 가장 읽기 쉽고 유용했습니다. 감사합니다!
Harold Cavendish

8

"로컬"패키지를 프로젝트에 추가하려면 폴더를 추가하십시오 (예 : "package_name"). 그리고 구현 파일을 해당 폴더에 넣으십시오.

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

당신의 package main일에서 :

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

package_name폴더 이름은 어디에 있으며 whatever_name1.go 및 whatever_name2.go 파일에 사용 된 패키지 이름과 일치해야합니다. 즉, 서브 디렉토리가있는 모든 파일은 동일한 패키지 여야합니다.

가져 오기에서 상위 폴더의 전체 경로를 지정하는 한 더 많은 하위 디렉토리를 중첩 할 수 있습니다.


2
이것은 커널 패닉 동안 바이너리에서 덤프 된 스택 추적이 항상 가장 바람직한 동작은 아니지만 github.com 경로를 보여 준다는 점을 제외하고는 좋은 제안입니다. 이것을 억제하는 플래그가 있지만 단순한 패키지 구성을 달성하는 데 필요하지는 않으며 때로는 실패합니다.
Kenny Powers

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

3

당신이 사용할 수있는 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()
}

바 /go.mod

module github.com/my/bar

go 1.14

바 /fn.go

package github.com/my/bar

import "fmt"

func MyFunc() {
    fmt.Printf("hello")
}

로컬 패키지를 가져 오는 것은 외부 pacakge를 가져 오는 것과 같습니다.

go.mod 파일을 제외하고는 외부 패키지 이름을 로컬 폴더로 바꿉니다.

폴더의 경로는 전체 또는 상대 "/ path / to / bar"또는 "../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 -로컬 모듈 /

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.