使用go模块和cgo时如何解决循环依赖

在我的项目中,我使用回调进行从 C 到 go 的双向调用,反之亦然,使用 CGO。我通过将 C 部分编译到库中,然后将 go 部分编译到库中,然后最后的链接器传递将它们放在一起,解决了循环依赖的问题。这在不使用 go 模块时工作正常。Go 源文件明确列在命令行上。有人告诉我,从 go 1.12 开始“这不是正确的方法”。


随着项目的发展,我现在想使用 go 模块。不幸的是,这改变了 go 编译器的行为。它现在想要解决外部依赖关系并将它们隐式包含在输出文件中。由于循环依赖,它现在总是以未定义的引用或多个定义结束。如何以“正确的方式”使用 cgo 和 go 模块时解决循环依赖关系?


这是说明问题的最小示例。从 Makefile 中的调用中删除文件名“hello.go”以查看它是如何分崩离析的。


这是错误消息:


hello.c:3: multiple definition of `c_hello'; $WORK/b001/_cgo_hello.o:/tmp/go-build/hello.c:3: first defined here

生成文件:


libchello.a: Makefile hello.c

    gcc -fPIC -c -o chello.o hello.c

    ar r libchello.a chello.o

libgohello.a: Makefile hello.go libchello.a

    env CGO_LDFLAGS=libchello.a go build -buildmode=c-archive -o libgohello.a hello.go

main: Makefile main.c libgohello.a libchello.a

    gcc -o main main.c libchello.a libgohello.a -pthread

.PHONY: clean

clean:

    rm -f main *.a *.o

    echo "extern void go_hello();" > libgohello.h

你好,去:


package main

/*

extern void c_hello();

*/

import "C"

import "time"

import "fmt"

//export go_hello

func go_hello() {

    fmt.Printf("Hello from go\n")

    time.Sleep(1 * time.Second)

    C.c_hello()

}

func main() {}

libgohello.h:


extern void go_hello();

你好ç:


#include "libgohello.h"

#include <stdio.h>

void c_hello() {

    printf("Hello from c\n");

    go_hello();

}

主.c:


void c_hello();

int main() {

    c_hello();

}

去.mod:


module hehoe.de/cgocircular


繁花不似锦
浏览 94回答 1
1回答

偶然的你

如果您查看该go build命令的详细输出,您将看到在将目录编译为完整的 go 包时,该main.c文件被包含在hello.go.从文档中:当 Go 工具看到一个或多个 Go 文件使用了特殊的 import "C" 时,它会在目录中查找其他非 Go 文件并将它们编译为 Go 包的一部分这里最简单的解决方案是将主要的 C 和 Go 包分开,这样它们就不会干扰彼此的构建过程。对此进行测试,删除main.c文件将构建libchello.a和libgohello.a,然后将其重新添加将完成main.
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go