如何解决简单的 CGO 示例因“重复符号”错误而无法编译
我想举一个简单的例子,用 CGO 从 Go 中调用 C 代码。但由于某种原因,我无法达到预期。编译失败并出现以下错误:
go build main.go
# awesomeProject1/print
duplicate symbol '_do_print' in:
$WORK/b002/_x002.o
$WORK/b002/_x003.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
代码:
// print/print.c
#include <stdio.h>
void do_print(char * x){
printf("%s",x);
}
// print/print.go
package print
// #include <print.c>
import "C"
func DoPrint() {
C.do_print(C.CString("Hello!"))
}
// main.go
package main
import "awesomeProject1/print"
func main() {
print.DoPrint()
}
如果我将 do_print
函数设为静态,它会编译,但我将无法为以后想要集成的第 3 方代码执行此操作。
我是否遗漏了文档中的一些重要内容?教程都一样,并声称可以在我的示例失败的地方工作。请帮忙!
转到版本 1.16.4
解决方法
这里有两件事:
-
go build
编译*.c
和*.go
1 -
#include <print.c>
完全等同于用print.c
的内容覆盖 include 语句
因此,您对 print.c
的内容进行了两次编译:一次是在 print.c
由 CC 编译时,另一次是在 print.go
由 CGo 编译时。因此,print.c
和 print.go
的目标文件均包含 print.c
中定义的所有导出符号。所以你得到了 do_print
的两个副本。使 do_print
静态工作是因为 CC 不会导出声明为 static
的函数。
包含 .c
文件(例如 #include <file.c>
)几乎总是一个坏主意。如果您有正当理由#include
函数体,约定是使用标头 (.h
) 文件。这就是 C++ 模板库所做的(如 Boost、IIRC)。因为C文件通常不被包含,H文件通常被包含,包含一个C文件会颠覆预期,因此很可能会造成混乱和问题。
1 IIRC,如果包中的任何 Go 文件导入 "C"
,Go 将编译包中的 C 文件。也就是说,如果包中没有 Go 文件使用 CGo,Go 将忽略该包中的 C 文件。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。