Cgo:对 [C 函数] 的未定义引用
Cgo: undefined reference to [C function]
我正在 运行在 docker 容器 (golang:1.18-bullseye
) 中安装一个 go 程序。
我试过 运行同时使用 go run main.go
和 go run .
我的代码看起来像这样,两个 header 文件都位于 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'
我该如何解决这个问题?
编辑:我将 header 更改为:
/*
#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
我能够重现并修复这个问题。还有一些额外的问题。首先只关注 运行ning go build
:
好的,go 编译器找到了头文件,但是找不到共享库。我认为您稍微修改了问题的代码,这不是问题,但是 LDFLAGS
中 -L
的路径必须是:
- 相对于源目录使用
${SRCDIR}
- 绝对路径
- 完全避免这种情况并利用 pkg-config
我只是使用包含
so
文件的相对目录作为 -L
. 的参数
好的,除此之外,您还必须在 LDFLAGS 中提供一个 -l
参数,以便在您指向的路径中找到文件(即:libvendera.so
需要 -lvendora
)。
一旦 go build
工作,您就有一个应用程序 still needs the know where so
文件到 运行(因此是一个共享库)。为此,您可能需要设置 LD_LIBRARY_PATH
并指向包含 so
文件的目录,就像您对 -L
.
所做的那样
我正在 运行在 docker 容器 (golang:1.18-bullseye
) 中安装一个 go 程序。
我试过 运行同时使用 go run main.go
和 go run .
我的代码看起来像这样,两个 header 文件都位于 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'
我该如何解决这个问题?
编辑:我将 header 更改为:
/*
#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
我能够重现并修复这个问题。还有一些额外的问题。首先只关注 运行ning go build
:
好的,go 编译器找到了头文件,但是找不到共享库。我认为您稍微修改了问题的代码,这不是问题,但是 LDFLAGS
中 -L
的路径必须是:
- 相对于源目录使用
${SRCDIR}
- 绝对路径
- 完全避免这种情况并利用 pkg-config
我只是使用包含
so
文件的相对目录作为-L
. 的参数
好的,除此之外,您还必须在 LDFLAGS 中提供一个 -l
参数,以便在您指向的路径中找到文件(即:libvendera.so
需要 -lvendora
)。
一旦 go build
工作,您就有一个应用程序 still needs the know where so
文件到 运行(因此是一个共享库)。为此,您可能需要设置 LD_LIBRARY_PATH
并指向包含 so
文件的目录,就像您对 -L
.