如何不使用gopath导入本地软件包


171

我已经习惯了,GOPATH但是对于当前问题,我却无济于事。我希望能够创建特定于项目的软件包:

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

我尝试了多种方法,但是如何package1.gobinary1.go或上工作binary2.go,以此类推?

例如; 我希望能够import "package1"然后能够运行,go build binary1.go并且一切正常,而不会引发在GOROOT或上找不到软件包的错误GOPATH。我需要这种功能的原因是针对大型项目;我不想引用多个其他软件包或将它们保存在一个大文件中。


2
您应该将每个二进制文件的源文件放入其自己的目录中。
2013年

.go单个目录中的所有文件都是同一软件包的一部分,并且您不必将import文件放在同一软件包(即同一目录)中。您提到了在GOPATH之外进行工作,这是新的Go模块系统的功能之一。这个答案盖的模块结构,导入本地包,一个模块内设置的包,是否要在单个存储库中的多个模块等
typical182

3
每个人的行为都可以吗?除非您指定完整git/repo/to/my/project路径,否则您基本上无法导入本地子包?我只是不明白为什么有人想要这种行为。如果将项目移动到另一个位置(即Docker映像),该怎么办,您需要再次更改所有路径?我正在寻找答案,为什么这是如此复杂。
milosmns

Answers:


176

转到依赖项管理摘要:

  • vgo 如果您使用的版本是: x >= go 1.11
  • dep或者vendor您的go版本是:go 1.6 >= x < go 1.11
  • 如果您使用的版本是: 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:虽然我的旧方法有效,但不再是“正确”的方法。您应该使用Go 1.6中默认启用的供应商功能,vgodep(目前)。。您基本上是在vendor目录中添加“外部”或“依赖”程序包;在编译时,编译器将首先使用这些软件包。


找到了。GOPATH通过创建的子文件夹,package1然后使用import "./package1"in binary1.gobinary2.go脚本导入,我能够导入本地包,如下所示:

binary1.go

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

因此,我当前的目录结构如下所示:

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

我还要指出,相对路径(至少在go 1.5中)也有效;例如:

import "../packageX"

4
在您有两个子文件夹且其中一个引用另一个子文件夹之前,此方法正常。例如,如果package2也是子文件夹,并且它需要package1,则系统将中断。
卡尔

7
import "../package1"
Felix Rabe 2014年

12
相对导入路径不是一个好主意
Dave C

1
如果#golang提供了“命名空间”,那么我可以同意“相对导入路径”或“子包”是个坏主意”。
mission.liao 2015年

1
函数名称应以Capitilized关键字开头
kokemomuke

71

没有“本地包”之类的东西。磁盘上软件包的组织与软件包的任何父/子关系正交。程序包形成的唯一真实层次是依赖关系树,在通常情况下,它不反映目录树。

只需使用

import "myproject/packageN"

并且不要无缘无故地与构建系统抗争。在任何不平凡的程序中每次导入都保存十几个字符不是一个好理由,因为例如,具有相对导入路径的项目不可获取。

导入路径的概念具有一些重要属性:

  • 导入路径可以是全局唯一的。
  • 结合GOPATH,可以将导入路径明确转换为目录路径。
  • GOPATH下的任何目录路径都可以明确转换为导入路径。

使用相对导入路径破坏了以上所有内容。不要做。

PS:Go编译器测试中的遗留代码中很少使用相对导入的地方。ATM,这是完全支持相对进口的唯一原因。


2
我建议观看此介绍性视频,以更好地了解软件包GOPATHyoutube.com/watch?v=XCsL89YtqCs
Joshua Pinter 2014年

7
我认为这是不好的建议。例如,如果最终使用gopkg.in进行版本控制,那么您将无法为“迷你”软件包提供绝对导入路径,如上所述。要么破坏源存储库,要么版本化的存储库变得无用。
格雷格

import "myproject/packageN"myproject我的项目的文件夹名称是什么?
securecurve

那是完全错误的,我现在如何在私有存储库中使用它?
agilob

44

也许您正在尝试模块化您的软件包。我假设package1package2是,在某种程度上,同一个包的一部分,但为便于阅读,您是那些分裂成多个文件。

如果以前的情况是您的情况,则可以在多个文件中使用相同的程序包名称,就像在相同的文件中一样。

这是一个例子:

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 build在project1和project2目录中使用,也可以go build -o project1/exe project1/*.go在projects目录中使用。

这种方法的缺点是所有项目最终都在go.mod中共享相同的依赖项列表。我仍在寻找解决此问题的方法,但看起来它可能是基础。


9

自从引入go.mod以来,我认为本地和外部软件包管理都变得更加容易。使用go.mod,也可以在GOPATH之外进行go项目。

导入本地包:

创建一个文件夹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 / model”导入了Employee模型

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

如此平淡无奇,但花了我大量的时间才能找到答案,而且您的帖子最清晰,最有用。谢谢!
哈罗德·卡文迪许

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文件夹名称,它必须与文件what_name1.go和what_name2.go中使用的程序包名称匹配。换句话说,所有带有子目录的文件都应位于同一软件包中。

只要在导入中指定父文件夹的完整路径,就可以进一步嵌套更多子目录。


2
这是一个很好的建议,除了在任何内核崩溃期间,从二进制文件转储的堆栈跟踪显示了例如github.com路径,而并不总是最理想的行为。有一些标志可以抑制这种情况,但是它并不一定只是为了实现简单的程序包组织而已,我发现它确实有时会失败。
肯尼·鲍尔斯

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

bar / go.mod

module github.com/my/bar

go 1.14

bar / 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 -到您的本地模块/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.