Связывание с libstdc++ статически: каких подводных камней?



Мне нужно развернуть приложение C++, построенное на Ubuntu 12.10 с GCC 4.7 libstdc++ для систем под управлением Ubuntu 10.04, который поставляется со значительно более старой версией libstdc++.



В настоящее время я компилирую с -static-libstdc++ -static-libgcc, как предлагается в этом блоге: связывание libstdc++ статически. Автор предупреждает об использовании любого динамически загружаемого кода C++ при компиляции libstdc++ статически, что я еще не проверил. По-прежнему, все вроде бы пока все идет гладко: я могу использовать функции C++11 на Ubuntu 10.04, что и было мне нужно.



Я отмечаю, что эта статья с 2005 года, и, возможно, многое изменилось с тех пор. Его советы все еще актуальны? Есть ли какие-то скрытые проблемы, о которых я должен знать?

574   3  

3 ответов:

это сообщение в блоге довольно неточно.

насколько я знаю, изменения C++ ABI были введены с каждым основным выпуском GCC (т. е. с различными компонентами первого или второго номера версии).

не правда. Единственные изменения C++ ABI, введенные с GCC 3.4, были обратно совместимы, что означает, что C++ ABI был стабильным в течение почти девяти лет.

что еще хуже, большинство основных Linux дистрибутивы используют моментальные снимки GCC и / или исправляют их версии GCC, что делает практически невозможным точно знать, с какими версиями GCC вы можете иметь дело при распространении двоичных файлов.

различия между исправленными версиями дистрибутивов GCC незначительны и не изменяются ABI, например, 4.6.3 20120306 Fedora (Red Hat 4.6.3-2) совместим с восходящим FSF 4.6.X-релизов и почти наверняка с любым 4.6.x из любого другого дистрибутива.

на Библиотеки времени выполнения GNU / Linux GCC используют ELF symbol versioning, поэтому легко проверить версии символов, необходимые объектам и библиотекам, и если у вас есть libstdc++.so Это обеспечивает те символы, которые он будет работать, это не имеет значения, если это немного другая исправленная версия от другой версии вашего дистрибутива.

но никакой код C++ (или любой код, использующий поддержку среды выполнения C++) не может быть связан динамически, если это должно работать.

это не правда любой.

что сказал, статически связываясь с libstdc++.a Это один из вариантов для вас.

причина, по которой он может не работать, если вы динамически загружаете библиотеку (используя dlopen) заключается в том, что символы libstdc++, от которых он зависит, возможно, не были нужны вашему приложению, когда вы (статически) связали его, поэтому эти символы не будут присутствовать в вашем исполняемом файле. Это можно решить, динамически связывая общую библиотеку с libstdc++.so (что правильно делать, если это зависит от оно.) ELF symbol interposition означает, что символы, присутствующие в вашем исполняемом файле, будут использоваться общей библиотекой, но другие, не присутствующие в вашем исполняемом файле, будут найдены в любом случае libstdc++.so Это ссылки на. Если ваше приложение не использует dlopen вам не нужно заботиться об этом.

еще один вариант (и тот, который я предпочитаю) заключается в развертывании новых libstdc++.so рядом с вашим приложением и убедитесь, что он найден до системы по умолчанию libstdc++.so, Что можно сделать, заставив динамический компоновщик, чтобы посмотреть в нужном месте, либо с помощью $LD_LIBRARY_PATH переменная окружения во время выполнения или путем установки RPATH в исполняемом файле во время ссылки. Я предпочитаю использовать RPATH поскольку он не зависит от правильно настроенной среды для работы приложения. Если вы свяжете свое приложение с '-Wl,-rpath,$ORIGIN' (обратите внимание на одинарные кавычки, чтобы оболочка не пытается расширить $ORIGIN), то исполняемый файл будет иметь RPATH на $ORIGIN который говорит динамическому компоновщику искать общий доступ библиотеки в том же каталоге, что и сам исполняемый файл. Если вы ставите новые libstdc++.so в том же каталоге, что и исполняемый, он будет найден во время выполнения, проблема решена. (Другой вариант-поместить исполняемый файл в /some/path/bin/ и более новый libstdc++. so в /some/path/lib/ и '-Wl,-rpath,$ORIGIN/../lib' или любое другое фиксированное местоположение относительно исполняемого файла и установите RPATH относительно $ORIGIN)

одно дополнение к превосходному ответу Джонатана Уэйкли, почему dlopen () проблематично:

из-за нового пула обработки исключений в GCC 5 (см. PR 64535 и PR 65434), если вы dlopen и dlclose библиотека, которая статически связана с libstdc++, вы получите утечку памяти (объекта пула) каждый раз. Поэтому, если есть шанс, что вы когда-нибудь будете использовать dlopen, кажется, что это действительно плохая идея статически связать libstdc++. Обратите внимание, что это настоящий утечка в отличие от доброкачественной, упомянутой в PR 65434.

вам также может потребоваться убедиться, что вы не зависите от динамического glibc. Беги ldd на вашем результирующем исполняемом файле и обратите внимание на любые динамические зависимости (libc/libm/libpthread являются обычными подозреваемыми).

дополнительное упражнение будет строить кучу вовлеченных примеров C++11, используя эту методологию и фактически пробуя полученные двоичные файлы на реальной системе 10.04. В большинстве случаев, если вы не делаете что-то странное с динамической загрузкой, вы сразу узнаете, является ли программа работает или он падает.

Comments

    Ничего не найдено.