我写这段话的前提是,每个CGO生成的C函数 Package 器都存储在自己的C文件中。编辑和编译一个CGO包可能需要一分钟或2分钟,即使只是一个小的变化。应该可以缓存生成的.o文件,只有在该函数的代码发生变化时才重新编译它们。在链接CGO Package 器时,Go应避免将未使用的 Package 器链接到一起以减小大小。
ff29svar1#
我们运行C链接器,而不是仅使用Go链接器,因为Go链接器不支持C全局构造函数或C异常处理或其他一些由C链接器处理的情况。我们可以在Go链接器中支持这些事情,但这并不简单。
uqcuzwp82#
你是如何解决这个问题的?
ifsvaxew3#
将CGO代码放入子包中,这样如果你对主包进行更改,除非你更改了它们,否则不会重新编译使用CGO的这些包。
ou6hu8tu4#
Go链接器确实支持在某些平台上读取各种格式(ELF,Mach-O,PE等)的C对象文件。但是正如@ianlancetaylor所指出的,C链接的支持是有限的,它不支持花哨的C/C++特性。如果你确定你的C代码不使用这些特性,并且你针对一个支持内部链接的平台,你可以尝试传递-ldflags=-linkmode=internal,然后Go链接器将链接C代码并生成一个不使用C链接器的可执行文件。(注意:链接可能会失败,请谨慎使用。)
-ldflags=-linkmode=internal
这不会自动对C代码进行死代码消除,因为C对象语义基于节而不是基于函数。也许你可以尝试使用C编译器选项-ffunction-sections和-fdata-sections。(Go链接器对其的支持未经充分测试,请谨慎使用。)
-ffunction-sections
-fdata-sections
laawzig25#
对于每个使用import "C"的Go文件,我们生成一个C文件。并不是为每个C函数 Package 器使用单独的C文件。尽管我认为如果它看起来有用的话,我们可以这样做。CC @bcmills@jayconrod
import "C"
31moq8wy6#
相关 #9887目前,我认为我们缓存生成的 .c 文件,但不缓存 C 编译器产生的 .o 文件。我们应该为每个 .c 文件编译执行单独的操作,并缓存这些操作的输出。
.c
.o
nimxete27#
请注意,正确缓存C对象文件需要检测是否包含的任何.h文件发生了变化。当人们更新到某个C依赖项的较新版本时,这种情况确实会出现。
sqserrrh8#
好的点子。我们至少应该将包含的 .h 文件的哈希值纳入编译后的 .a 文件的缓存键中。我不认为我们现在正在这样做。
eh57zj3b9#
也许我们只能在实际编译包时运行C编译器,以获取C常量的值并确保正确调用C函数。然后,在链接时,Go链接器链接整个程序,而不是使用C链接器。我们可能可以使用syscall从CGO Go代码 Package 器中在运行时调用C函数。这将带来几个好处。由于没有调用C链接器,因此链接速度更快,Go链接器可能不需要花费时间构建与C链接器兼容的对象文件,静态链接的C代码(至少在每个对象文件的基础上)的死代码消除可能也可以完成,如果有其他平台的静态库,则可能支持交叉编译。Go包“github.com/veandco/go-sdl2/sdl”为SDL2运行的所有平台提供了静态库。链接器需要支持读取几种不同格式的对象文件。
9条答案
按热度按时间ff29svar1#
我们运行C链接器,而不是仅使用Go链接器,因为Go链接器不支持C全局构造函数或C异常处理或其他一些由C链接器处理的情况。我们可以在Go链接器中支持这些事情,但这并不简单。
uqcuzwp82#
你是如何解决这个问题的?
ifsvaxew3#
将CGO代码放入子包中,这样如果你对主包进行更改,除非你更改了它们,否则不会重新编译使用CGO的这些包。
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链接器对其的支持未经充分测试,请谨慎使用。)laawzig25#
对于每个使用
import "C"
的Go文件,我们生成一个C文件。并不是为每个C函数 Package 器使用单独的C文件。尽管我认为如果它看起来有用的话,我们可以这样做。CC @bcmills@jayconrod
31moq8wy6#
相关 #9887
目前,我认为我们缓存生成的
.c
文件,但不缓存 C 编译器产生的.o
文件。我们应该为每个
.c
文件编译执行单独的操作,并缓存这些操作的输出。nimxete27#
请注意,正确缓存C对象文件需要检测是否包含的任何.h文件发生了变化。当人们更新到某个C依赖项的较新版本时,这种情况确实会出现。
sqserrrh8#
好的点子。我们至少应该将包含的 .h 文件的哈希值纳入编译后的 .a 文件的缓存键中。我不认为我们现在正在这样做。
eh57zj3b9#
也许我们只能在实际编译包时运行C编译器,以获取C常量的值并确保正确调用C函数。
然后,在链接时,Go链接器链接整个程序,而不是使用C链接器。我们可能可以使用syscall从CGO Go代码 Package 器中在运行时调用C函数。
这将带来几个好处。由于没有调用C链接器,因此链接速度更快,Go链接器可能不需要花费时间构建与C链接器兼容的对象文件,静态链接的C代码(至少在每个对象文件的基础上)的死代码消除可能也可以完成,如果有其他平台的静态库,则可能支持交叉编译。Go包“github.com/veandco/go-sdl2/sdl”为SDL2运行的所有平台提供了静态库。
链接器需要支持读取几种不同格式的对象文件。