Cgo: 对[C函数]的引用未定义。

huangapple go评论89阅读模式
英文:

Cgo: undefined reference to [C function]

问题

我正在一个 Docker 容器中运行一个 Go 程序(golang:1.18-bullseye)。

我尝试过使用 go run main.gogo run . 来运行它。

我的代码如下,两个头文件都位于 CFLAGS 中指定的 Include 目录下:

/*
#cgo LDFLAGS: -Lvendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so
#cgo CFLAGS: -I vendor/MyCoolLibrary/1.14.2/Include/
#include "my_cool_sdk.h"
#include "my_cool_logging.h"*/
import "C"
import (
	"fmt"
	"log"
	"os"
	"runtime"
)

func main() {
	ret := C.MyCoolFunc()
}

当我运行这段代码时,我得到了以下错误信息:

/usr/bin/ld: $WORK/b001/_x002.o: in function `_cgo_6bb9bcf96ac6_Cfunc_MyCoolFunc':
/tmp/go-build/cgo-gcc-prolog:110: undefined reference to `MyCoolFunc'

我该如何修复这个问题?

编辑:我将头文件更改为:

/*
#cgo LDFLAGS: -L${SRCDIR}/vendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so -lSDK-Linux-Shipping
#cgo CFLAGS: -I ${SRCDIR}/vendor/MyCoolLibrary/1.14.2/Include/
#include "my_cool_sdk.h"
#include "my_cool_logging.h"*/

然后运行 go build -x .,得到以下输出:

WORK=/tmp/go-build1175764972
mkdir -p $WORK/b001/
cd /home/helloworld
TERM='dumb' CGO_LDFLAGS='"-g" "-O2" "-L/home/helloworld/vendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so" "-lSDK-Linux-Shipping"' /usr/local/go/pkg/tool/linux_amd64/cgo -objdir $WORK/b001/ -importpath go-sandbox -- -I $WORK/b001/ -g -O2 -I ./vendor/MyCoolLibrary/1.14.2/Include/ ./main.go
cd $WORK
gcc -fno-caret-diagnostics -c -x c - -o /dev/null || true
gcc -Qunused-arguments -c -x c - -o /dev/null || true
gcc -fdebug-prefix-map=a=b -c -x c - -o /dev/null || true
gcc -gno-record-gcc-switches -c -x c - -o /dev/null || true
cd $WORK/b001
TERM='dumb' gcc -I /home/helloworld -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -I /home/helloworld/vendor/MyCoolLibrary/1.14.2/Include/ -o ./_x001.o -c _cgo_export.c
TERM='dumb' gcc -I /home/helloworld -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -I /home/helloworld/vendor/MyCoolLibrary/1.14.2/Include/ -o ./_x002.o -c main.cgo2.c
TERM='dumb' gcc -I /home/helloworld -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -I /home/helloworld/vendor/MyCoolLibrary/1.14.2/Include/ -o ./_cgo_main.o -c _cgo_main.c
cd /home/helloworld
TERM='dumb' gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -o $WORK/b001/_cgo_.o $WORK/b001/_cgo_main.o $WORK/b001/_x001.o $WORK/b001/_x002.o -g -O2 -L/home/helloworld/vendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so -lSDK-Linux-Shipping
# go-sandbox
/usr/bin/ld: cannot find -lSDK-Linux-Shipping
collect2: error: ld returned 1 exit status
英文:

I'm running a go program in a docker container (golang:1.18-bullseye).

I haev tried running it both with go run main.go and go run .

My code looks likes this, both header files are located in the Include directory given in the CFLAGS:

/*
#cgo LDFLAGS: -Lvendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so
#cgo CFLAGS: -I vendor/MyCoolLibrary/1.14.2/Include/
#include "my_cool_sdk.h"
#include "my_cool_logging.h"*/
import "C"
import (
	"fmt"
	"log"
	"os"
	"runtime"
)

func main() {
ret := C.MyCoolFunc()
}

When I run this code, I get this error message:

/usr/bin/ld: $WORK/b001/_x002.o: in function `_cgo_6bb9bcf96ac6_Cfunc_MyCoolFunc':
/tmp/go-build/cgo-gcc-prolog:110: undefined reference to `MyCoolFunc'

How can I fix this?

Edit: I changed the header to:

/*
#cgo LDFLAGS: -L${SRCDIR}/vendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so -lSDK-Linux-Shipping
#cgo CFLAGS: -I ${SRCDIR}/vendor/MyCoolLibrary/1.14.2/Include/
#include "my_cool_sdk.h"
#include "my_cool_logging.h"*/

and ran go build -x . and this is the output:

WORK=/tmp/go-build1175764972
mkdir -p $WORK/b001/
cd /home/helloworld
TERM='dumb' CGO_LDFLAGS='"-g" "-O2" "-L/home/helloworld/vendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so" "-lSDK-Linux-Shipping"' /usr/local/go/pkg/tool/linux_amd64/cgo -objdir $WORK/b001/ -importpath go-sandbox -- -I $WORK/b001/ -g -O2 -I ./vendor/MyCoolLibrary/1.14.2/Include/ ./main.go
cd $WORK
gcc -fno-caret-diagnostics -c -x c - -o /dev/null || true
gcc -Qunused-arguments -c -x c - -o /dev/null || true
gcc -fdebug-prefix-map=a=b -c -x c - -o /dev/null || true
gcc -gno-record-gcc-switches -c -x c - -o /dev/null || true
cd $WORK/b001
TERM='dumb' gcc -I /home/helloworld -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -I /home/helloworld/vendor/MyCoolLibrary/1.14.2/Include/ -o ./_x001.o -c _cgo_export.c
TERM='dumb' gcc -I /home/helloworld -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -I /home/helloworld/vendor/MyCoolLibrary/1.14.2/Include/ -o ./_x002.o -c main.cgo2.c
TERM='dumb' gcc -I /home/helloworld -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -I /home/helloworld/vendor/MyCoolLibrary/1.14.2/Include/ -o ./_cgo_main.o -c _cgo_main.c
cd /home/helloworld
TERM='dumb' gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -o $WORK/b001/_cgo_.o $WORK/b001/_cgo_main.o $WORK/b001/_x001.o $WORK/b001/_x002.o -g -O2 -L/home/helloworld/vendor/MyCoolLibrary/1.14.2/Bin/Linux/libSDK-Linux-Shipping.so -lSDK-Linux-Shipping
# go-sandbox
/usr/bin/ld: cannot find -lSDK-Linux-Shipping
collect2: error: ld returned 1 exit status

答案1

得分: 3

我已经能够重现并修复这个问题。还有一些额外的注意事项。首先,只专注于运行go build

好的,所以Go编译器找到了头文件,但找不到共享库。我认为你在问题中稍微修改了代码,所以这不是一个问题,但是LDFLAGS-L的路径必须是以下之一:

  • 相对于源代码目录,使用${SRCDIR}
  • 绝对路径
  • 完全避免这个问题,使用pkg-config

我只是使用包含so文件的相对目录作为-L的参数。

好的,除此之外,你还必须在LDFLAGS中给出一个-l参数,以便在你指定的路径中找到文件(例如:libvendera.so需要-lvendora)。

一旦go build成功,你就会得到一个需要知道so文件位置才能运行的应用程序(因此需要一个共享库)。为了做到这一点,你可能需要设置LD_LIBRARY_PATH,并指向包含so文件的目录,就像你在-L中所做的那样。

英文:

I was able to reproduce and fix this. There are also some additional gotchas. Start by just focusing on running go build:

Ok so the go compiler has found the header file, but cannot find the shared library. I think you modified your code for the question slightly and this is not an issue, but the path for -L in LDFLAGS has to be either:

  • relative to the source directory using ${SRCDIR}
  • an absolute path
  • avoid this entirely and leverage pkg-config
    I just used the relative directory containing the so file as my argument for -L.

Ok, that aside, you must also give a -l argument in LDFLAGS to find the file in the paths you pointed to (IE: libvendera.so needs -lvendora).

Once go build works you have an application that still needs the know where the so file is to run (so hence a shared library). To do this you will likely need to set LD_LIBRARY_PATH and point to the directory containing the so file much like you did with -L.

huangapple
  • 本文由 发表于 2022年4月5日 18:01:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/71749797.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定