Связывание с 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 года, и, возможно, многое изменилось с тех пор. Его советы все еще актуальны? Есть ли какие-то скрытые проблемы, о которых я должен знать?
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