cmd/go: optimize CGO caching and dead code removal

cgvd09ve  于 6个月前  发布在  Go
关注(0)|答案(9)|浏览(51)

我写这段话的前提是,每个CGO生成的C函数 Package 器都存储在自己的C文件中。
编辑和编译一个CGO包可能需要一分钟或2分钟,即使只是一个小的变化。
应该可以缓存生成的.o文件,只有在该函数的代码发生变化时才重新编译它们。
在链接CGO Package 器时,Go应避免将未使用的 Package 器链接到一起以减小大小。

ff29svar

ff29svar1#

我们运行C链接器,而不是仅使用Go链接器,因为Go链接器不支持C全局构造函数或C异常处理或其他一些由C链接器处理的情况。我们可以在Go链接器中支持这些事情,但这并不简单。

uqcuzwp8

uqcuzwp82#

你是如何解决这个问题的?

ifsvaxew

ifsvaxew3#

将CGO代码放入子包中,这样如果你对主包进行更改,除非你更改了它们,否则不会重新编译使用CGO的这些包。

ou6hu8tu

ou6hu8tu4#

Go链接器确实支持在某些平台上读取各种格式(ELF,Mach-O,PE等)的C对象文件。但是正如@ianlancetaylor所指出的,C链接的支持是有限的,它不支持花哨的C/C++特性。如果你确定你的C代码不使用这些特性,并且你针对一个支持内部链接的平台,你可以尝试传递-ldflags=-linkmode=internal,然后Go链接器将链接C代码并生成一个不使用C链接器的可执行文件。(注意:链接可能会失败,请谨慎使用。)

这不会自动对C代码进行死代码消除,因为C对象语义基于节而不是基于函数。也许你可以尝试使用C编译器选项-ffunction-sections-fdata-sections。(Go链接器对其的支持未经充分测试,请谨慎使用。)

laawzig2

laawzig25#

对于每个使用import "C"的Go文件,我们生成一个C文件。并不是为每个C函数 Package 器使用单独的C文件。尽管我认为如果它看起来有用的话,我们可以这样做。
CC @bcmills@jayconrod

31moq8wy

31moq8wy6#

相关 #9887
目前,我认为我们缓存生成的 .c 文件,但不缓存 C 编译器产生的 .o 文件。
我们应该为每个 .c 文件编译执行单独的操作,并缓存这些操作的输出。

nimxete2

nimxete27#

请注意,正确缓存C对象文件需要检测是否包含的任何.h文件发生了变化。当人们更新到某个C依赖项的较新版本时,这种情况确实会出现。

sqserrrh

sqserrrh8#

好的点子。我们至少应该将包含的 .h 文件的哈希值纳入编译后的 .a 文件的缓存键中。我不认为我们现在正在这样做。

eh57zj3b

eh57zj3b9#

也许我们只能在实际编译包时运行C编译器,以获取C常量的值并确保正确调用C函数。
然后,在链接时,Go链接器链接整个程序,而不是使用C链接器。我们可能可以使用syscall从CGO Go代码 Package 器中在运行时调用C函数。
这将带来几个好处。由于没有调用C链接器,因此链接速度更快,Go链接器可能不需要花费时间构建与C链接器兼容的对象文件,静态链接的C代码(至少在每个对象文件的基础上)的死代码消除可能也可以完成,如果有其他平台的静态库,则可能支持交叉编译。Go包“github.com/veandco/go-sdl2/sdl”为SDL2运行的所有平台提供了静态库。
链接器需要支持读取几种不同格式的对象文件。

相关问题