英文:
Unable to cross compile Golang library from MacOS for Linux
问题
阅读文章后,我尝试了以下命令:
env GOOS=linux GOARCH=amd64 go build -buildmode=c-shared -o hello.so testlib.go
但是出现了错误:
go: no Go source files
然后我通过执行以下命令启用了CGO:
env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -buildmode=c-shared -o hello.so testlib.go
然后出现了一系列错误:
# runtime/cgo
linux_syscall.c:67:13: error: implicit declaration of function 'setresgid' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
linux_syscall.c:67:13: note: did you mean 'setregid'?
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/unistd.h:593:6: note: 'setregid' declared here
linux_syscall.c:73:13: error: implicit declaration of function 'setresuid' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
linux_syscall.c:73:13: note: did you mean 'setreuid'?
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/unistd.h:595:6: note: 'setreuid' declared here
以下是版本信息:
Go版本:go version go1.19.4 darwin/amd64
GCC版本:
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
英文:
After reading articles I tried this:
env GOOS=linux GOARCH=amd64 go build -buildmode=c-shared -o hello.so testlib.go
It gave an error:
go: no Go source files
Then I enabled CGO by doing this:
env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -buildmode=c-shared -o hello.so testlib.go
and it gave a set of errors:
env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -buildmode=c-shared -o hello.so testlib.go
# runtime/cgo
linux_syscall.c:67:13: error: implicit declaration of function 'setresgid' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
linux_syscall.c:67:13: note: did you mean 'setregid'?
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/unistd.h:593:6: note: 'setregid' declared here
linux_syscall.c:73:13: error: implicit declaration of function 'setresuid' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
linux_syscall.c:73:13: note: did you mean 'setreuid'?
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/unistd.h:595:6: note: 'setreuid' declared here
Below are the versions:
Go: go version go1.19.4 darwin/amd64
GCC:
=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
答案1
得分: 2
Go的移植政策提到:
>所有Linux的一流端口都是针对只使用glibc的系统。使用其他C库的Linux系统不受完全支持,也不被视为一流。
这就排除了基于glibc
替代品musl
的交叉编译器解决方案用于构建GO共享库。
如果你尝试了(如答案的第一个版本中所示,请参见编辑历史记录),当你使用file
和nm
命令进行检查时,一切看起来都很好。但是,如果你尝试在C程序中使用.so库,会出现以下崩溃:
error relocating ./libhello.so: free: initial-exec TLS resolves to dynamic definition in ./libhello.so
更多信息请参见:https://github.com/golang/go/issues/54805。
然后你需要一个基于gcc的交叉编译器-在macOS上不能使用clang进行此操作。最简单的方法是使用带有适当镜像的Docker,它将工作量减少到一个命令行:
docker run --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp golang:1.19 env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -buildmode=c-shared -o libhello.so testlib.go
参见https://index.docker.io/_/golang
对你的问题进行了一个小调整,将-o hello.so
改为-o libhello.so
,以便在基于libc的Linux上使用gcc进行简单的测试。
顺便说一下,可以这样做:
cd testdir
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`
gcc -Wall -Wextra -L. test.c -lhello -o test
./test
或者,如果你不想在编译时静态绑定.so文件/在运行时动态加载它,而是只想在运行时直接动态加载和绑定Go函数符号,测试看起来会更简单:
gcc -Wall -Wextra test2.c -o test2
./test2
英文:
Go's porting policy mentions:
>All Linux first class ports are for systems using glibc only. Linux systems using other C libraries are not fully supported and are not treated as first class.
This then excludes cross-compiler solutions based on the glibc
alternative musl
for building GO shared libraries.
If you try it anyway (as in the first version of the answer, see edit history), it looks good at first sight when you check it with the file
and nm
command. But if you try to use the .so lib with a C program, there is the following crash:
error relocating ./libhello.so: free: initial-exec TLS resolves to dynamic definition in ./libhello.so
More info here: https://github.com/golang/go/issues/54805.
You then need a gcc based cross compiler - clang on macOS cannot be used for this. The easiest way to do this is to use Docker with an appropriate image, it reduces the effort to a single command line:
docker run --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp golang:1.19 env GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -buildmode=c-shared -o libhello.so testlib.go
see https://index.docker.io/_/golang
One minor adjustment was to change the -o hello.so
in your question to -o libhello.so
to simply test with -lhello
using gcc on a libc-based Linux.
By the way, this can then be done in this way:
cd testdir
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`
gcc -Wall -Wextra -L. test.c -lhello -o test
./test
Or if you don't want to bind the .so file statically at compile time / load it dynamically at runtime as shown above, but only want to load and bind the Go function symbols directly dynamically at runtime, the test would look even simpler:
gcc -Wall -Wextra test2.c -o test2
./test2
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论