英文:
Cgo: undefined reference to [C function]
问题
我正在一个 Docker 容器中运行一个 Go 程序(golang:1.18-bullseye)。
我尝试过使用 go run main.go 和 go 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 thesofile 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论