【问题标题】:Using Go in C++在 C++ 中使用 Go
【发布时间】:2020-07-19 07:15:12
【问题描述】:

Linux Debian Buster

go 版本 go1.11.6 linux/amd64

gcc 版本 8.3.0 (Debian 8.3.0-6)

libmylib.go

package main

import "C"

import (
    "fmt"
)

func say(text string) {
    fmt.Println(text)
}

func main(){}

mylib.h

#ifndef MY_LIB_H
#define MY_LIB_H

#include <string>

void say(std::string text);

#endif

ma​​in.cpp

#include <string>
#include "mylib.h"

using namespace std;

int main() {
    string text = "Hello, world!";

    say(text);

    return 0;
}

CGO_ENABLED=1 go build -o libmylib.so -buildmode=c-shared libmylib.go

g++ -L/path/to/lib/ -lmylib main.cpp -o my-test-program

/usr/bin/ld: /tmp/ccu4fXFB.o: 在函数'main'中: main.cpp:(.text+0x53): undefined reference to `say(std::__cxx11::basic_string)'
collect2: error: ld returned 1 exit状态

有变化:package main -&gt; package mylib

CGO_ENABLED=1 go build -o libmylib.so -buildmode=c-shared libmylib.go

-buildmode=c-shared 只需要一个主包

【问题讨论】:

  • 从 go 程序调用 C++ 代码可能要简单得多。您是否可以根据这种情况调整实际代码?
  • 我需要在我的 C++ 项目中使用 Go 文件中的一些函数。因为我不懂 Go,因此无法翻译 Go -> C++
  • 请不要评论你的问题,但edit它提供一些minimal reproducible example

标签: c++ go shared-objects object-files


【解决方案1】:

在 C++ 版本中,您必须使用 GoString 而不是 std::string。您收到的错误消息是由于类型不匹配,表现为链接时错误。

the cgo reference

这是一个工作示例。和你的有一些不同。在生成的头文件中需要//export指令来包含函数,参数是*C.char而不是stringGoString。 C++ 代码使用 cgo 生成的标头,并且必须从静态字符串中移除 const 强制转换(因为 go 没有类似 C 的 const)。

libmylib.go

package main

import "C"

import (
    "fmt"
)

//export say
func say(text *C.char) {
    fmt.Println(C.GoString(text))
}

func main() {}

main.cpp

#include "libmylib.h"

int main(void) {
    say(const_cast<char*>("hello world"));

    return 0;
}

命令

这编译成go文件,在当前目录生成libmylib.solibmylib.h

go build -o libmylib.so -buildmode=c-shared libmylib.go

编译 C++ 程序,将其链接到上面的共享库:

g++ -L. main.cpp -lmylib -o hello_program

要运行程序,LD_LIBRARY_PATH 需要设置为当前目录。如果安装了程序并将共享库放在一个合理的位置,那就不一样了。

LD_LIBRARY_PATH=. ./hello_program

【讨论】:

  • go tool cgo libmylib.go 。之后我得到了“obj”文件夹。 mylib.h extern void say(GoString text);main.cpp GoString text = "Hello, World!"; 。 >g++ -L/path/to/lib/ -lmylib main.cpp -o my-test-program. >main.cpp:5:21: 错误:从“const char [14]”转换为非标量类型“GoString”{aka '_GoString'} 请求 GoString text = "Hello, World!";更改为 extern void say(GoString text[]); 毫无意义。
  • 是的,您不能从 C++ 创建 GoString 类型的值。可能最简单的方法是传入一个以 null 结尾的 C 字符串(C 中的 char *,go 中的 *C.char),您可以使用 C.GoString(s) 将其转换为 go 字符串。
  • 这意味着你的 go 函数是:func say(s *C.char) { fmt.Println(C.GoString(s)) }
  • libmylib.go func say( text *C.char ) { fmt.Println( C.GoString( text ) ) } , main.cpp char* text = "Hello, World!"; , mylib.h extern void say(char* text);&gt;g++ -L/path/to/lib/ -lmylib main.cpp -o my-test-program&gt;main.cpp:(.text+0x1b): undefined reference to say(char*)'`。使用&gt;CGO_ENABLED=1 go build -o libmylib.so -buildmode=c-shared libmylib.go 命令创建共享对象文件。
  • 有什么理由不使用生成的头文件,如 cgo 参考中所述?但我想此时您当前问题的答案在 Basile 的答案中。
【解决方案2】:
g++ -L/path/to/lib/ -lmylib main.cpp -o test

可能是错误的。阅读GCC documentationinvoking GCC 章节。 g++ 的参数顺序很重要

另外,test(1) 可能是一些现有 可执行文件。我建议使用其他名称。

所以考虑编译

g++ -Wall -g -O main.cpp -L/path/to/lib/ -lmylib -o my-test-program

您可能需要调试信息 (-g)、警告 (-Wall) 和一些优化 (-O)

你做了评论

我需要在我的 C++ 项目中使用 Go 文件中的一些函数。

这很奇怪。我假设您的操作系统是一些 Linux。那么,你不能在一个运行 Go 程序的进程和另一个运行你的 C++ 程序的进程之间使用inter-process communication 设施吗?考虑在它们之间使用JSONRPCHTTP。 Go 和 C++ 中有几个开源库可以帮助您。

PS。正如我所评论的,从 Go 程序调用 C++ 代码可能要简单得多。当然,您确实需要阅读Go documentationblog about cgo,可能还有C++ dlopen minihowto 和一些C++ reference

【讨论】:

    猜你喜欢
    • 2010-12-15
    • 2019-01-02
    • 1970-01-01
    • 2015-11-19
    • 2019-09-18
    • 2022-08-05
    • 2018-09-03
    • 1970-01-01
    相关资源
    最近更新 更多