在现有C项目中使用Go代码

pxq42qpu  于 2023-01-20  发布在  Go
关注(0)|答案(2)|浏览(146)

自从Go语言1.5问世以来,我开始重新审视如何将其集成到我现有的项目中。
这个项目的代码库完全是用C编写的,用于底层访问硬件和其他有趣的东西。然而,一些高级的东西是乏味的,我想开始用高级语言(Go)编写它们。
有没有办法从C程序调用Go语言的代码呢?我安装了Go语言1.5,它添加了-buildmode=c-archivehttps://golang.org/s/execmodes),我正在尝试让它工作。
然而,我似乎无法让Go语言生成适当的头文件,以使我的项目能够实际编译。当我生成归档文件时,我在导出的符号中看到了函数(使用objdump),但如果没有头文件来包含gcc,则会抱怨函数不存在(如预期的那样)
我对围棋还是个新手--但是,我喜欢这门语言,也想用它。有没有什么惯用的方法(“惯用的”在围棋世界里用得很多,我明白......)可以让这门语言很好地相互配合?
我之所以问这个问题,并且特别提到Go语言1.5,是因为根据这篇文档,https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit?pli=1#heading=h.1gw5ytjfcoke语言1.5增加了对非Go语言程序调用Go语言代码的支持,特别是在“Go语言代码链接到非Go语言程序并从非Go语言程序调用”一节中提到的

oknwwptz

oknwwptz1#

要构建一个可从C调用的归档文件,您需要将它们标记为导出的CGo符号。
例如,如果我创建一个包含以下内容的文件foo.go

package main

import (
    "C"
    "fmt"
)

//export PrintInt
func PrintInt(x int) {
    fmt.Println(x)
}

func main() {}

需要注意的重要事项包括:

  • 需要将软件包命名为main
  • 您需要有一个main函数,尽管它可以为空。
  • 您需要导入软件包C
  • 您需要特殊的//export注解来标记您希望从C调用的函数。

我可以用下面的命令把它编译成一个C可调用的静态库:

go build -buildmode=c-archive foo.go

结果将是一个归档文件foo.a和一个头文件foo.h。在头文件中,我们得到以下内容(省略不相关的部分):

...
typedef long long GoInt64;
...
typedef GoInt64 GoInt;
...
extern void PrintInt(GoInt p0);
...

这就足够调用导出的函数了,我们可以编写一个简单的C程序,像这样调用它:

#include "foo.h"

int main(int argc, char **argv) {
    PrintInt(42);
    return 0;
}

我们可以用如下命令编译它:

gcc -pthread foo.c foo.a -o foo

-pthread选项是必需的,因为Go语言运行时使用线程,当我运行生成的可执行文件时,它会打印42

w51jfk4q

w51jfk4q2#

上面的代码工作正常,但是gcc会抱怨函数和头文件。
应包括:

#define _GNU_SOURCE
#include <stdio.h>
#include "mygopkg.h"

如果您忘记了#define _GNU_SOURCE,gcc会抱怨:

warning: implicit declaration of function 'asprintf'; did you mean 'vsprintf'? [-Wimplicit-function-declaration]

如果您忘记了**#include“mygopkg.h”**,gcc将报告:

warning: implicit declaration of function 'PrintString' [-Wimplicit-function-declaration]

最后一点也同样重要。我推荐的生产代码构建命令行是:

go build -ldflags "-s -w"  -buildmode c-archive -o mygopkg.a

It'll save you 53% size of final mygopkg.a.

相关问题