使用 yocto 配方构建 go 项目时 ABI 不匹配
ABI mismatch when building go project with a yocto recipe
我正在尝试编写一个 Yocto 配方来为 x86_64 目标平台(rocko 分支)构建一个 Go lang 项目。我的 yocto 配方可以很好地构建 Go 项目,使用 dep
工具解决依赖关系。但是构建的二进制文件不会 运行 在目标平台上。尝试在目标上执行它时,出现此错误:
$ /usr/bin/mybin
abi mismatch detected between the executable and libstd.so
fatal error: abi mismatch
runtime: panic before malloc heap initialized
这是我构建项目的自定义方法:
GO_IMPORT = "bitbucket.org/xxx/myproject"
SRC_URI = "git://${GO_IMPORT}/protocol=http;user=${GIT_USER}:${GIT_PASS};destsuffix=${PN}-${PV}/src/${GO_IMPORT}"
SRCREV = "7777ee7777777c9777774bb777780777759d777771777"
CGO_ENABLED = "0"
inherit go
do_compile_prepend() {
rm -f ${WORKDIR}/build/src/${GO_IMPORT}/Gopkg.toml
rm -f ${WORKDIR}/build/src/${GO_IMPORT}/Gopkg.lock
cd ${WORKDIR}/build/src/${GO_IMPORT}
dep init
dep ensure
}
do_install_append() {
rm -f ${D}/usr/bin/dep
}
deltask do_compile_ptest_base
deltask do_compile_ptest
DEPENDS = "go-dep-native mercurial-native"
INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
INHIBIT_PACKAGE_STRIP = "1"
RDEPENDS_${PN}-staticdev += "bash"
RDEPENDS_${PN}-dev += "bash"
处理这个问题的正确方法应该是什么?
我可以提供有关此问题的更多信息:
$ ldd /usr/bin/mybin
linux-vdso.so.1 (0x00007ffe321d9000)
libstd.so => /usr/lib/go/pkg/linux_amd64_dynlink/libstd.so (0x00007f95463d7000)
libc.so.6 => /lib/libc.so.6 (0x0000003436200000)
libdl.so.2 => /lib/libdl.so.2 (0x0000003436a00000)
libpthread.so.0 => /lib/libpthread.so.0 (0x0000003436600000)
/lib/ld-linux-x86-64.so.2 (0x0000003435e00000)
$ file /usr/bin/mybin
/usr/bin/mybin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=0103acf63634df77e600eb114bf59977462ca51d, with debug_info, not stripped
$ file /usr/lib/go/pkg/linux_amd64_dynlink/libstd.so
/usr/lib/go/pkg/linux_amd64_dynlink/libstd.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=2d2f135b2f9eab19a7ceff1923820bf635e10eb1, with debug_info, not stripped
问题似乎与动态库 libstd.so 的生成有关(由 GO_DYNLINK 控制)。该库的生成由 poky/meta/recipes-devtools/go/go-runtime.inc:
上定义的这段源代码管理
do_compile() {
export GOBIN="${B}/bin"
export CC="${@d.getVar('BUILD_CC').strip()}"
rm -rf ${GOBIN} ${B}/pkg
mkdir ${GOBIN}
cd src
./make.bash --host-only
cp ${B}/pkg/tool/${BUILD_GOTUPLE}/go_bootstrap ${B}
rm -rf ${B}/pkg/${TARGET_GOTUPLE}
./make.bash --target-only
if [ -n "${GO_DYNLINK}" ]; then
cp ${B}/go_bootstrap ${B}/pkg/tool/${BUILD_GOTUPLE}
GO_FLAGS="-buildmode=shared" GO_LDFLAGS="-extldflags \"${LDFLAGS}\"" ./make.bash --target-only
fi
cd ${B}
}
我做了一个测试,评论这个条件后:
# if [ -n "${GO_DYNLINK}" ]; then
# cp ${B}/go_bootstrap ${B}/pkg/tool/${BUILD_GOTUPLE}
# GO_FLAGS="-buildmode=shared" GO_LDFLAGS="-extldflags \"${LDFLAGS}\"" ./make.bash --target-only
# fi
我的食谱生成了一个有效的 mybin
静态链接。
因此,在提供所有这些信息后,我有更多问题:从我的自定义配方中设置此变量 GO_DYNLINK 的正确方法是什么?因为我尝试过以不同的方式设置它:
GO_DYNLINK=""
unset GO_DYNLINK
GO_DYNLINK="0"
其中 none 有效(同样是 ABI 不匹配问题)。谢谢!! :)
好的,所以我找到了防止此问题的更好方法以及有关核心问题的更多信息。
更好的解决方案
在您的食谱中添加以下行:
GO_LINKSHARED = ""
这将阻止 -builmdmode=shared
并执行正常的 go 构建而不是链接到标准库。有趣的是,通过删除到标准库的链接,我的二进制大小只增加了 100KB,libstd.so
是 30MB。
核心问题
核心问题是,当您使用默认 shared
构建模式时,当您构建一个 go 二进制文件时,您还会在另一个 rpm 包中构建 go 运行时 libstd.do
。理论上,如果您的目标具有相同的运行时库版本,则无需再次安装运行时。然而,情况似乎并非如此。 Go 对它放入 libstd
的所有包定义进行散列,然后对这些散列进行散列以创建 ABI 散列。同一个 go 版本的 libstd.so
的两个实例应该具有相同的哈希值,因为它们具有相同的功能,但事实并非如此。我在 yocto 的错误跟踪器 here 上写了一份更技术性的错误报告。
我正在尝试编写一个 Yocto 配方来为 x86_64 目标平台(rocko 分支)构建一个 Go lang 项目。我的 yocto 配方可以很好地构建 Go 项目,使用 dep
工具解决依赖关系。但是构建的二进制文件不会 运行 在目标平台上。尝试在目标上执行它时,出现此错误:
$ /usr/bin/mybin
abi mismatch detected between the executable and libstd.so
fatal error: abi mismatch
runtime: panic before malloc heap initialized
这是我构建项目的自定义方法:
GO_IMPORT = "bitbucket.org/xxx/myproject"
SRC_URI = "git://${GO_IMPORT}/protocol=http;user=${GIT_USER}:${GIT_PASS};destsuffix=${PN}-${PV}/src/${GO_IMPORT}"
SRCREV = "7777ee7777777c9777774bb777780777759d777771777"
CGO_ENABLED = "0"
inherit go
do_compile_prepend() {
rm -f ${WORKDIR}/build/src/${GO_IMPORT}/Gopkg.toml
rm -f ${WORKDIR}/build/src/${GO_IMPORT}/Gopkg.lock
cd ${WORKDIR}/build/src/${GO_IMPORT}
dep init
dep ensure
}
do_install_append() {
rm -f ${D}/usr/bin/dep
}
deltask do_compile_ptest_base
deltask do_compile_ptest
DEPENDS = "go-dep-native mercurial-native"
INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
INHIBIT_PACKAGE_STRIP = "1"
RDEPENDS_${PN}-staticdev += "bash"
RDEPENDS_${PN}-dev += "bash"
处理这个问题的正确方法应该是什么?
我可以提供有关此问题的更多信息:
$ ldd /usr/bin/mybin
linux-vdso.so.1 (0x00007ffe321d9000)
libstd.so => /usr/lib/go/pkg/linux_amd64_dynlink/libstd.so (0x00007f95463d7000)
libc.so.6 => /lib/libc.so.6 (0x0000003436200000)
libdl.so.2 => /lib/libdl.so.2 (0x0000003436a00000)
libpthread.so.0 => /lib/libpthread.so.0 (0x0000003436600000)
/lib/ld-linux-x86-64.so.2 (0x0000003435e00000)
$ file /usr/bin/mybin
/usr/bin/mybin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=0103acf63634df77e600eb114bf59977462ca51d, with debug_info, not stripped
$ file /usr/lib/go/pkg/linux_amd64_dynlink/libstd.so
/usr/lib/go/pkg/linux_amd64_dynlink/libstd.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=2d2f135b2f9eab19a7ceff1923820bf635e10eb1, with debug_info, not stripped
问题似乎与动态库 libstd.so 的生成有关(由 GO_DYNLINK 控制)。该库的生成由 poky/meta/recipes-devtools/go/go-runtime.inc:
上定义的这段源代码管理do_compile() {
export GOBIN="${B}/bin"
export CC="${@d.getVar('BUILD_CC').strip()}"
rm -rf ${GOBIN} ${B}/pkg
mkdir ${GOBIN}
cd src
./make.bash --host-only
cp ${B}/pkg/tool/${BUILD_GOTUPLE}/go_bootstrap ${B}
rm -rf ${B}/pkg/${TARGET_GOTUPLE}
./make.bash --target-only
if [ -n "${GO_DYNLINK}" ]; then
cp ${B}/go_bootstrap ${B}/pkg/tool/${BUILD_GOTUPLE}
GO_FLAGS="-buildmode=shared" GO_LDFLAGS="-extldflags \"${LDFLAGS}\"" ./make.bash --target-only
fi
cd ${B}
}
我做了一个测试,评论这个条件后:
# if [ -n "${GO_DYNLINK}" ]; then
# cp ${B}/go_bootstrap ${B}/pkg/tool/${BUILD_GOTUPLE}
# GO_FLAGS="-buildmode=shared" GO_LDFLAGS="-extldflags \"${LDFLAGS}\"" ./make.bash --target-only
# fi
我的食谱生成了一个有效的 mybin
静态链接。
因此,在提供所有这些信息后,我有更多问题:从我的自定义配方中设置此变量 GO_DYNLINK 的正确方法是什么?因为我尝试过以不同的方式设置它:
GO_DYNLINK=""
unset GO_DYNLINK
GO_DYNLINK="0"
其中 none 有效(同样是 ABI 不匹配问题)。谢谢!! :)
好的,所以我找到了防止此问题的更好方法以及有关核心问题的更多信息。
更好的解决方案
在您的食谱中添加以下行:
GO_LINKSHARED = ""
这将阻止 -builmdmode=shared
并执行正常的 go 构建而不是链接到标准库。有趣的是,通过删除到标准库的链接,我的二进制大小只增加了 100KB,libstd.so
是 30MB。
核心问题
核心问题是,当您使用默认 shared
构建模式时,当您构建一个 go 二进制文件时,您还会在另一个 rpm 包中构建 go 运行时 libstd.do
。理论上,如果您的目标具有相同的运行时库版本,则无需再次安装运行时。然而,情况似乎并非如此。 Go 对它放入 libstd
的所有包定义进行散列,然后对这些散列进行散列以创建 ABI 散列。同一个 go 版本的 libstd.so
的两个实例应该具有相同的哈希值,因为它们具有相同的功能,但事实并非如此。我在 yocto 的错误跟踪器 here 上写了一份更技术性的错误报告。