在 CL 208117 ( #30316 )中,cmd/go
(截至Go 1.14版本)缺乏一种生成Go库C头文件的好方法,以便从C中使用它们。go install -buildmode=c-archive
和 go install -buildmode=c-shared
作为副作用,会为请求的包生成头文件。然而,今天的 -buildmode=c-archive
和 -buildmode=c-shared
需要命名的包是一个 package main
,这些命令不会为命名包的(传递)Go依赖项生成头文件。-i
标志确实为传递依赖项生成头文件,但它还有一个不想要的副作用:它为命名包的传递依赖项构建(并尝试安装)库,包括标准库中的传递依赖项。如果用户无法写入 GOROOT/pkg
,例如当一个非根用户正在使用一个作为根安装的 go
工具时,这将失败。
作为解决方法,可以运行 go tool cgo -exportheader
,但 go tool cgo
接受文件列表而不是包列表,并生成一些额外的输出(通常在 _obj
子目录中),而C调用者不需要直接使用这些输出。因此,我们仍然在不同的位置进行额外的工作。
我们应该看看如何使生成C头文件更容易,同时避免不必要的或不想要的副作用。
CC @ianlancetaylor@jayconrod
7条答案
按热度按时间zpgglvta1#
一种可能性是添加另一个
-buildmode
,例如-buildmode=c-header
,它可以执行所需的任何工作(并可能将额外的产物写入GOCACHE
),但只发出(或安装)头文件而不是整个存档。这可以作为具有特定包参数的
go tool cgo
调用的更直接替代品。eoxn13cs2#
另一个选项可能是让
-i
标志抑制标准库目标的错误,这样即使GOROOT
不可写,go install -i
命令也能正常工作。u1ehiz5o3#
https://golang.org/cl/208117提到了这个问题:
misc/cgo/testcarchive: avoid writing to GOROOT in tests
laawzig24#
https://golang.org/cl/208119提到了这个问题:
misc/cgo/testcshared: avoid writing to GOROOT in tests
bprjcwpo5#
我们可以让
go install
安装所有导入包的头文件,即使没有-i
也可以。这将改变行为,但仅限于不是main
但已导出函数的包,这种情况比较少见。23c0lvtd6#
也许吧,但导入本身似乎有点牵强附会:如果C代码使用了来自包
a
的标识符,那么构建过程应该提到包a
,而不是恰好导入了a
的其他包b
。另一方面,我想C库必须链接到某个(共享或归档)文件,该文件是由包
main
生成的,所以让go install
为链接到该包的所有标识符生成所有头文件似乎并不糟糕。qvk1mo1f7#
在这个问题中,用户想要在不同的文件中使用类型别名
type T1 = T2
,但是遇到了一些问题。以下是翻译后的文本内容:任何进展吗?我正在尝试使用 bcmills@ 建议的解决方法,即使用
go tool cgo -exportheader
,所以我的构建脚本包括:其中
foo.go
和bar.go
都位于同一个包中。这之前运行得很好,直到我尝试使用类型别名时。我想定义一个类型别名
type T1 = T2
,并在foo.go
和bar.go
中使用它。如果我在
foo.go
中定义了这个别名,go build
可以正常工作,就像预期的那样(T1
在bar.go
的作用域内)。然而,导出bar.go
的头文件失败了,而unrecognized Go type T1
可以正常工作。如果我在
foo.go
和bar.go
中定义了相同的别名,那么这两个文件的导出头文件都可以成功,但是在go build
中会出现重复声明错误(并不奇怪)。