如何使用调用未定义的 c 函数的 Go 构建共享库?

How do I build a shared library using Go that calls an undefined c function?

我想使用 Go 创建一个共享库,供 third-party 软件 (STAR-CCM+) 使用。该软件提供了一些实用程序 c 函数供我的代码调用,并期望我的代码 至少 定义一个特定的函数,third-party 软件将在加载后调用该函数图书馆。

我的问题是 Go 抱怨实用函数的未定义引用:

/tmp/go-build672782048/b001/_x002.o: In function `_cgo_c4b84da031f3_Cfunc_utility':
/tmp/go-build/cgo-gcc-prolog:50: undefined reference to `utility'

我如何编译一个共享库,它调用一个已声明但未由我的代码定义的 c 函数?

third-party软件提供了一个header类似这样的文件:

uclib.h

#ifndef UCLIB_H
#define UCLIB_H

// utility function defined by third party software, declared here
extern void utility(int);

// function expected to exist in .so and defined by user
// this function is expected to call `utility` one or more times
void user_function();

#endif

工作示例,仅 c

为了测试与第三方软件的交互,我仅使用 c:

构建了一个示例

usingc.c

#include "uclib.h"

void
user_function()
{
    utility(1);
}

建造:

$ gcc -fPIC -c usingc.c -o usingc.o
$ gcc -shared -o libmine.so usingc.o

这导致 libmine.so 第三方软件成功加载并注册其 utility 函数被 1 调用。请注意,utility 仅由我的代码声明,从未定义。

有问题的例子,Go

我用上面的 header 和两个文件创建了一个简单的 go 模块:

go.mod

module example.com/cgo_mwe

go 1.15

usinggo.go

package main

// #include "uclib.h"
import "C"

//export user_function
func user_function() {
    C.utility(C.int(2))
}

func main() {}

我尝试构建共享库并观察到错误:

$ go build -o libmineg.so -buildmode=c-shared
# example.com/cgo_mwe
/tmp/go-build672782048/b001/_x002.o: In function `_cgo_c4b84da031f3_Cfunc_utility':
/tmp/go-build/cgo-gcc-prolog:50: undefined reference to `utility'
collect2: error: ld returned 1 exit status

允许与未定义引用链接的三种可能的解决方案。后两个位于 golang-nuts Google Group:

  1. 通过 LDFLAGS-shared
  2. 忽略所有未定义的引用
// #include "uclib.h"
// #cgo LDFLAGS: -shared
import "C"
  1. 通过 LDFLAGS-Wl,-unresolved-symbols=ignore-all:
  2. 忽略所有未定义的引用
// #include "uclib.h"
// #cgo LDFLAGS: -Wl,-unresolved-symbols=ignore-all
import "C"
  1. 在头文件中标记已声明但未定义的函数as weak
#pragma weak utility
// utility function defined by third party software, declared here
extern void utility(int);

#3 的优点是未标记为弱的引用仍被称为未定义。