-2

我有一个非常简单的设置:一个 .go 文件(test.go)和一个 .c 文件(PMDK.c)。我在 Go 中包含 .c 文件,如下所示:

测试.go

package main

/*
#include "PMDK.c"
#cgo pkg-config: libpmem
*/
import "C"

func main() {
    C.helloWorld()
}

当我运行go run test.go时,它只构建一次。无论我对PMDK.c做什么更改,我的程序每次都具有完全相同的行为。

我还尝试了 go build test.go,这导致了相同的结果。最后,在CGo 不编译同一目录中的 C 文件之后,我只是去构建。这不起作用,因为我必须创建一个 .mod 文件(go build test.go)。然后,问题是PMDK.c中的三个函数(helloWorld和另外两个)据说被定义了多次。我不能让它建立我的改变。顺便说一句,如果我将源文件复制/移动到另一个目录并在那里构建它们,则更改将适用(仅一次,再次)。

4

1 回答 1

4

问题的核心是您的设置错误:您的 Go 代码应该#include在 Cgo 前缀中仅包含您想要单独编译的任何 C 代码的标头。例如:

package main

/*
#include "pmdk.h"
*/
import "C"

func main() {
    C.helloWorld()
}

可以将 C 代码放入前缀中:

package main

/*
#include <stdio.h>
void helloWorld() {
        printf("hello world from C\n");
}
*/
import "C"

...

但是如果你把你的 C 代码放到一个单独的文件中prog.c等等),你应该创建一个小的头文件来简单地声明每个函数,以及#include来自 C 代码和 Go 代码的头文件。1

跑步:

go build

然后,如果 C 代码发生了变化,将编译它,如果发生了变化,将编译 Go 代码,并将两者适当地链接在一起。如果您#include将 C 代码直接放入 Go 包中,就像您所做的那样,go build将构建 C 代码并构建包含 C 代码的 Go 代码,这就是您获得重复定义的原因。

无论您在 Cgo 标头中嵌入什么 C 代码,都不应出现在其他任何地方。这是放置小型“管道适配器”的好地方,如果您有一些现有的 C 代码主要与 Go 一起使用,但需要一些调整。


1这是 C 中的一种通用技术,用于确保函数的头文件声明与相同函数的 C 源代码定义一致。也就是说,标题fifth.h可能会说:

void func(int arg1, char *arg2);

并且,C 代码将分别读取:

#include "fifth.h"

void func(int zorg, char *evil) {
    // ...
}

C 编译器将检查声明是否与定义匹配。

于 2021-08-30T11:29:09.360 回答