Несоответствие ABI при сборке проекта go с рецептом yocto

Я пытаюсь написать рецепт Yocto для создания проекта Go lang для целевой платформы x86_64 (ветка rocko). Мой рецепт 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"

Каким должен быть правильный способ решения этой проблемы?


person aicastell    schedule 05.02.2018    source источник


Ответы (2)


Итак, я нашел лучший способ предотвратить эту проблему, а также дополнительную информацию об основной проблеме.

Лучшее решение

В своем рецепте добавьте следующую строку:

GO_LINKSHARED = ""

Это предотвратит -builmdmode=shared и выполнит обычную сборку вместо связывания со стандартной библиотекой. Забавно, что, удалив привязку к стандартной библиотеке, я увеличил размер бианри только на 100 КБ, а libstd.so составил 30 МБ.

Основная проблема

Основная проблема заключается в том, что когда вы используете режим сборки по умолчанию shared, когда вы собираете двоичный файл go, вы также собираете среду выполнения go libstd.do в другом пакете rpm. Теоретически, если ваша цель имеет ту же версию библиотеки времени выполнения, вам не нужно снова устанавливать среду выполнения. Однако, похоже, это не так. Go хеширует все определения пакетов, которые он помещает в libstd, а затем хеширует эти хэши, чтобы создать хэш ABI. Два экземпляра libstd.so одной и той же версии go должны иметь один и тот же хеш, потому что у них одинаковые функции, но это не так. Я написал более технический отчет об ошибке в системе отслеживания ошибок yocto здесь.

person Liam Kelly    schedule 08.03.2018
comment
Очень хорошее исправление. Большое спасибо! Я прочитал отчет об ошибке, и он содержит действительно ценную информацию. Надеюсь, это будет исправлено в ближайшее время. Большое спасибо, что уделили время изучению этого вопроса, г-н Лайам Келли! :-) - person aicastell; 09.03.2018
comment
У меня возникали действительно странные проблемы с SIGSEGV, используя ветку сумо poky с go 1.10.3 -- кросс-компиляция для armv6 (цель raspberrypi0-wifi). Настройка GO_LINKSHARED = "" полностью устранила проблему. Спасибо! - person bvarner; 07.10.2018

Могу предоставить дополнительную информацию по этому вопросу:

$ 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"

И ни один из них не работает (опять же проблема несоответствия ABI). Спасибо!! :)

person aicastell    schedule 06.02.2018
comment
Значения жестко закодированы в goarch.bbclass. Я обнаружил, что единственный способ обойти это — создать файл go-runtime_%.bbappend и скопировать вашу версию функции do_compile. - person Liam Kelly; 07.03.2018
comment
Это работает, как было предложено. Большое спасибо, мистер Лайам Келли! :-) - person aicastell; 08.03.2018