Мне нужно развернуть приложение C ++, построенное на Ubuntu 12.10 с libstdc ++ GCC 4.7, в системах под управлением Ubuntu 10.04, который поставляется со значительно более старой версией libstdc ++.
В настоящее время я компилирую -static-libstdc++ -static-libgcc
, как было предложено в этом сообщении в блоге: Статическое связывание libstdc ++ . Автор предостерегает от использования любого динамически загружаемого кода C ++ при статической компиляции libstdc ++, что я еще не проверял. Тем не менее, пока все, кажется, идет гладко: я могу использовать функции C ++ 11 в Ubuntu 10.04, что я и искал.
Хочу отметить, что эта статья написана в 2005 году, и, возможно, с тех пор многое изменилось. Его совет все еще актуален? Есть ли какие-то скрытые проблемы, о которых мне следует знать?
-static-libstdc++
варианте не было бы смысла , вы бы просто использовали-static
kernel too old
ошибку в некоторой системе ubuntu 1404. Glibc.so похожkernel32.dll
на окно, это часть интерфейса операционной системы, мы не должны встраивать его в наш двоичный файл. Вы можете использовать его,objdump -T [binary path]
чтобы увидеть динамическую загрузкуlibstdc++.so
или нет. Для программиста golang вы можете добавить#cgo linux LDFLAGS: -static-libstdc++ -static-libgcc
перед импортом "C"-static-libstdc++
не о том,-static
чтобыlibc.so
не было статической связи.Ответы:
Это сообщение в блоге довольно неточно.
Не правда. Единственные изменения C ++ ABI, внесенные после GCC 3.4, были обратно совместимы, то есть C ++ ABI был стабильным в течение почти девяти лет.
Различия между патченными версиями GCC дистрибутивов незначительны, и ABI не меняется, например, Fedora 4.6.3 20120306 (Red Hat 4.6.3-2) является ABI-совместимой с вышестоящими версиями FSF 4.6.x и почти наверняка с любой версией 4.6. x из любого другого дистрибутива.
В GNU / Linux библиотеки времени выполнения GCC используют управление версиями символов ELF, поэтому легко проверять версии символов, необходимые для объектов и библиотек, и если у вас есть программа,
libstdc++.so
которая предоставляет эти символы, она будет работать, не имеет значения, если это немного другая версия с исправлениями из другой версии вашего дистрибутива.Это тоже неправда.
Тем не менее, статическая ссылка
libstdc++.a
- это один из вариантов для вас.Причина, по которой это может не работать, если вы динамически загружаете библиотеку (используя
dlopen
), заключается в том, что символы libstdc ++, от которых она зависит, могли не понадобиться вашему приложению, когда вы (статически) связали его, поэтому эти символы не будут присутствовать в вашем исполняемом файле. Это можно решить, динамически связав разделяемую библиотеку сlibstdc++.so
(что в любом случае будет правильным, если это зависит от него.) Взаимодействие символов ELF означает, что символы, которые присутствуют в вашем исполняемом файле, будут использоваться разделяемой библиотекой, а другие - нет. присутствует в вашем исполняемом файле, будет найден там, гдеlibstdc++.so
он ссылается. Если ваше приложение не использует,dlopen
вам не нужно об этом заботиться.Другой вариант (и тот, который я предпочитаю) - развернуть новую версию
libstdc++.so
вместе с вашим приложением и убедиться, что она будет найдена до системы по умолчаниюlibstdc++.so
, что можно сделать, заставив динамический компоновщик искать в нужном месте, либо используя$LD_LIBRARY_PATH
переменную среды при запуске - time или установивRPATH
в исполняемом файле во время компоновки. Я предпочитаю использовать,RPATH
поскольку он не зависит от правильной настройки среды для работы приложения. Если вы свяжете свое приложение с'-Wl,-rpath,$ORIGIN'
(обратите внимание на одинарные кавычки, чтобы предотвратить попытку расширения оболочки$ORIGIN
), то исполняемый файл будет находитьсяRPATH
из$ORIGIN
которых сообщает динамическому компоновщику искать разделяемые библиотеки в том же каталоге, что и сам исполняемый файл. Если поставить новееlibstdc++.so
в том же каталоге, что и исполняемый файл, он будет найден во время выполнения, проблема решена. (Другой вариант - поместить исполняемый файл/some/path/bin/
и более новую libstdc ++. So/some/path/lib/
и связать его с'-Wl,-rpath,$ORIGIN/../lib'
любым другим фиксированным местоположением относительно исполняемого файла и установить RPATH относительно$ORIGIN
)источник
libstdc++.so.6
символическую ссылку, которая устанавливается во время установки, чтобы указать на прилагаемую библиотеку или на системную, если она новее. Существуют более сложные модели смешанной связи, используемые Red Hat DTS, но их сложно реализовать самостоятельно.Одно дополнение к отличному ответу Джонатана Уэйкли, почему dlopen () проблематичен:
Из-за нового пула обработки исключений в GCC 5 (см. PR 64535 и PR 65434 ), если вы откроете и dlclose библиотеку, которая статически связана с libstdc ++, вы каждый раз будете получать утечку памяти (объекта пула). Так что, если есть шанс, что вы когда-нибудь будете использовать dlopen, статическая линковка libstdc ++ кажется плохой идеей. Обратите внимание, что это настоящая утечка в отличие от утечки, упомянутой в PR 65434 .
источник
__gnu_cxx::__freeres()
Похоже, что эта функция хотя бы немного помогает в решении этой проблемы, поскольку освобождает внутренний буфер объекта пула. Но для меня довольно неясно, какое значение имеет вызов этой функции в отношении исключений, случайно сгенерированных впоследствии.Дополнение к ответу Джонатана Уэйкли относительно RPATH:
RPATH будет работать, только если рассматриваемый RPATH является RPATH запущенного приложения . Если у вас есть библиотека, которая динамически связывается с любой библиотекой через собственный RPATH, RPATH библиотеки будет перезаписан RPATH приложения, которое его загружает. Это проблема, когда вы не можете гарантировать, что RPATH приложения совпадает с RPATH вашей библиотеки, например, если вы ожидаете, что ваши зависимости будут в определенном каталоге, но этот каталог не является частью RPATH приложения.
Например, предположим, что у вас есть приложение App.exe, которое имеет динамически связанную зависимость от libstdc ++. So.x для GCC 4.9. В App.exe эта зависимость разрешена через RPATH, т.е.
App.exe (RPATH=.:./gcc4_9/libstdc++.so.x)
Теперь предположим, что есть еще одна библиотека Dependency.so, которая имеет динамически подключаемую зависимость от libstdc ++. So.y для GCC 5.5. Здесь зависимость разрешается через RPATH библиотеки, т.е.
Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y)
Когда App.exe загружает Dependency.so, он не добавляет и не добавляет в начало RPATH библиотеки . Он вообще с этим не справляется. Единственный рассматриваемый RPATH будет принадлежать запущенному приложению или App.exe в этом примере. Это означает, что если библиотека использует символы, которые находятся в gcc5_5 / libstdc ++. So.y, но не в gcc4_9 / libstdc ++. So.x, то библиотека не загрузится.
Это просто предупреждение, так как я сам сталкивался с этими проблемами в прошлом. RPATH - очень полезный инструмент, но при его реализации все же есть некоторые недостатки.
источник
Вам также может потребоваться убедиться, что вы не зависите от динамической glibc. Запустите
ldd
полученный исполняемый файл и обратите внимание на любые динамические зависимости (libc / libm / libpthread - подозреваемые).Дополнительным упражнением будет создание группы задействованных примеров C ++ 11 с использованием этой методологии и фактическая проверка полученных двоичных файлов на реальной системе 10.04. В большинстве случаев, если вы не сделаете что-то странное с динамической загрузкой, вы сразу узнаете, работает программа или она дает сбой.
источник
printf
), но пока glibc в Ubuntu 10.04 предоставляет все функции, необходимые для нового libstdc ++, нет проблем с зависимостью от динамического glibc, на самом деле настоятельно рекомендуется никогда не связывать статически в glibcЯ хотел бы добавить к ответу Джонатана Уэйкли следующее.
Играя
-static-libstdc++
в linux, я столкнулся с проблемойdlclose()
. Предположим, у нас есть приложение «A», статически связанное с ним,libstdc++
и оно загружается, динамически связанное сlibstdc++
плагином «P» во время выполнения. Все в порядке. Но когда «А» выгружает «Р», возникает ошибка сегментации. Я предполагаю, что после разгрузкиlibstdc++.so
"А" больше не может использовать символы, относящиеся кlibstdc++
. Обратите внимание, что если и «A», и «P» связаны статическиlibstdc++
, или если «A» связана динамически, а «P» статически, проблема не возникает.Резюме: если ваше приложение загружает / выгружает плагины, которые могут динамически связываться с ними
libstdc++
, приложение также должно быть связано с ним динамически. Это всего лишь мое наблюдение, и я хотел бы получить ваши комментарии.источник
sbrk
) делает определенные предположения и в значительной степени ожидает, что будет работать в одиночку в рамках одного процесса ... не уверен, ограничивается ли это ограничением конкретная версия glibc или что-то еще.