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


171

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

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

나는 여러 가지 방법을 시도했지만 어떻게받을 수 있나요 package1.go[작업에 binary1.go나 binary2.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이 때문에, 주로 수동 프로세스입니다 dep및 vgo작성되었습니다.


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


녹이다. GOPATH하위 폴더를 package1만든 다음 과 같은 import "./package1"in binary1.go및 binary2.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.