【问题标题】:how to distribute go binary only package如何分发仅二进制包
【发布时间】:2018-10-30 01:43:08
【问题描述】:

我想以二进制形式分发包,不包括源代码。

我的演示项目目录结构是这样的:

demo
├── greet
│   ├── greet.go
│   └── hi
│       └── hi.go
├── hello
│   └── hello.go
└── main.go

ma​​in.go:

package main

import (
    "fmt"
    "demo/greet"
    "demo/hello"
)

func main(){
    fmt.Println("greet:")
    greet.Greet()

    fmt.Println("hello:")
    hello.Hello()
}

greet.go

package greet

import (
    "demo/greet/hi"
    "fmt"
)

func Greet(){
    fmt.Println("Greet Call Hi")
    hi.Hi()
}

hi.go

package hi

import "fmt"

func Hi(){
    fmt.Println("Hi")
}

hello.go

package hello

import (
    "fmt"
    "demo/greet"
)

func Hello(){
    fmt.Println("hello call greet")
    greet.Greet()
}

我这样做:

[user@localhost greet]$ go install -a ./...

它在 $GOPATH/pkg/linux_amd64/demo 中生成了 greet.a 和 greet/hi.a。 然后我编辑 hi.go 和 greet.go。

[user@localhost greet]$ cat greet.go
//go:binary-only-package

package greet
[user@localhost greet]$ cat hi/hi.go
//go:binary-only-package

package hi

然后我运行 main.go,我得到错误:

[user@localhost greet]$ cat hi/hi.go
# command-line-arguments
cannot find package demo/greet/hi (using -importcfg)
/home/user/go/pkg/tool/linux_amd64/link: cannot open file : open : no such file or directory

greet 是我要分发的包。如果我删除包hi,main.go 可以正常运行。

demo
├── greet
│   └── greet.go
├── hello
│   └── hello.go
└── main.go

安装:

[user@localhost greet]$ go install .
[user@localhost greet]$ vim greet.go
//go:binary-only-package

package greet
[user@localhost greet]$ cd ..
[user@localhost demo]$ go run main.go
greet:
Greet ...
hello:
hello call greet
Greet ...
[user@localhost demo]$ 

所以我的主要问题是:我如何构建二进制库而其他人看不到我的源代码。并且包有很多子包。(如果包没有子包,我使用//go:binary-only-package方法可以很好地工作)

请帮助或尝试提供一些解决此问题的想法。提前致谢。

【问题讨论】:

  • 您何时收到指示的错误?什么时候编译?或者你跑步的时候?您还说“当我写一个子包时,我得到了错误”。什么错误?你在写作时得到它是什么意思?是编译还是运行的时候?
  • @SeanF 非常感谢。我更新了我的问题。

标签: go


【解决方案1】:

"go run" 将编译并运行给定的主包。因此,它会检查源文件的时间戳,如果发现它们比以前编译的库(.a 文件)更新,则重新编译它们。

对于仅二进制包,它将跳过此步骤。因此,在这种情况下,它将检查任何给定的包是否只有一个带有文本 //go:binary-only-package 的源文件。这就是指定功能的方式。当它看到时,它将只使用 .a 文件。

当您有一个包含源文件的子包时,其中的文件似乎最终算作封闭根包的一部分,并且只有一个源文件的要求被打破了。因此,“运行”将失败。我怀疑这就是为什么它不起作用。这就是为什么删除 hi 子包会使其工作的原因。

仅二进制的预期用例是您编译您的包,然后当您将其提供给其他人使用时,您不包含任何源文件,只包含 .a 文件。但是要让这个工作,你需要能够告诉其他人的编译器你的包只是 .a 文件。为此,您只需要包含一个带有文本 //go:binary-only-package 的源文件。而且您在这里基本上已经表明,对于具有子包的包,整个东西必须只有一个这样的源文件,只能有一个,子包文件夹中不能有更多。所以只提供一个。这就是该功能的工作原理。您将 .a 文件和一个源文件提供给其他人。

【讨论】:

  • 真诚感谢您的回答。你解决了我的难题。但它有另一种方式来实现我的目标吗?把所有的go文件放到一个目录下是很复杂的。
  • 我不确定您所说的“非常复杂”是什么意思。 go 编译器将在正确的位置创建您的 .a 文件,您只需要删除源文件并为每个根包添加一个带有 //go:binary-only-package 的源文件。然后你把它发送给其他人。
  • 我的意思是它有很多子包。我应该将 greet/hi/hi.go 移动到 greet/hi.go 吗?
  • 好吧,编写一个简单的脚本甚至是一个对源文件进行必要更改的 go 程序可能并不难,这样您就不必手动进行。是否要移动代码或更改代码取决于您,但通常您会根据其功能而不是类似的东西来组织代码。
  • 好的,我明白了。非常感谢。
【解决方案2】:

注意(2019 年):仅二进制包将不再受支持。

正如Go 1.12 (February 2019) release notes 所述(在CL 152918 之后):

仅二进制包

Go 1.12 是最后一个支持仅二进制包的版本

这在Go issue 28152中有详细说明:

仅二进制包越来越难以安全地支持。

无法保证仅二进制包的编译使用与最终链接所使用的相同版本的依赖项(坚持这样做可能过于繁琐)。
因此,对于不再准确的依赖项,可能已使用转义分析结果或内联函数体编译仅二进制包。
结果可能是无声内存损坏。

我的记忆是,我们最初添加了仅二进制包,以便教授可以分发二进制解决方案集,以便没有完成实验 2 的学生仍然可以继续进行实验 3。
我不知道为什么其他人会再使用它们,但是随着编译器变得越来越复杂,它们可能会越来越崩溃。

This was also discussed here.

【讨论】:

猜你喜欢
  • 2021-10-11
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 2016-02-25
  • 2011-04-13
  • 1970-01-01
  • 2017-10-31
  • 1970-01-01
相关资源
最近更新 更多