Как я могу развернуть программу C++11 (с зависимостями) на CentOS 6, чей GCC — C++03?

GCC отлично подходит для совместимости с ABI, если вы используете тот же стандарт C++ [1].

Но мне кажется, что если разделяемая библиотека, скомпилированная GCC 4.3 в режиме C++03, предоставляет, скажем, std::string, это будет другой std::string, чем тот, который понимается исполняемым файлом, скомпилированным GCC 4.8 в режиме C++11. .

Причина, по которой я спрашиваю, заключается в том, что я планирую развернуть программу, скомпилированную GCC 4.8 в режиме C++ 11, на CentOS 6, чей максимальный упакованный GCC составляет 4.3... и некоторые общие библиотеки (будь то сторонние библиотеки C++ или более вещей системного уровня), предположительно, поэтому все они будут С++ 03. Но если бы это было так, мы бы никогда не смогли развернуть какие-либо программы на C++11 в старых дистрибутивах Linux, что кажется маловероятным.

Я наивно думаю, что здесь может быть проблема? И, если есть, как я могу решить это?


person Lightness Races in Orbit    schedule 04.08.2016    source источник
comment
inb4 просто попробуй Ну, кажется, что он работает, это не значит, что он должен работать   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
Я не мог представить, что это может работать безопасно. Как вы говорите, если вы передаете std::strings между разными частями, они, вероятно, будут иметь разную компоновку или реализацию. Я предполагаю, что даже если вы не выставите их в интерфейсах, вы можете столкнуться с конфликтами символов.   -  person Johan Lundberg    schedule 04.08.2016
comment
@JohanLundberg: Мм, действительно. Поэтому должно быть какое-то общее руководство для такого рода вещей. Или никто не развертывает C++11 со сторонними пакетами CentOS на CentOS 6?!   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
Вот некоторая связанная информация. Чтобы «решить» эту проблему, вы можете захотеть выпустить две версии (03 и 11)?   -  person Patrik H    schedule 04.08.2016
comment
@PatrikH: Мех. Хотя была причина, по которой я начал писать на C++11 :( Если я собираюсь выпустить версию на C++03, я мог бы просто вернуться к C++03 и потерять все преимущества нового языка. На самом деле, поскольку -std=c++11 не используется по умолчанию даже в GCC 4.8, не означает ли это, что приложение C++11 не будет работать из коробки и в CentOS 7??   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
Рассматривали ли вы создание собственных зависимостей? Если вы создаете корпоративное приложение, вы, вероятно, захотите сделать это в любом случае. Если вы создаете личное приложение, то я не могу себе представить, что вы используете так много сторонних библиотек, что оно становится совершенно неуправляемым.   -  person Andrew    schedule 04.08.2016
comment
@Andrew: я не понимаю, почему корпоративное приложение перестраивает сторонние зависимости, а не использует репозиторий пакетов по умолчанию из корпоративного дистрибутива Linux;)   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
Чтобы предотвратить именно тот сценарий, который вы описываете. Обычно вам необходимо обновить аппаратное обеспечение, переключить/обновить компиляторы, использовать различные версии программного обеспечения, установленного с дистрибутивом, и т. д. Сборка из исходного кода позволяет вам изменять гибкость в своем темпе. Если вы посмотрите на систему управления зависимостями, такую ​​как conan, это очень поможет с этой проблемой.   -  person Andrew    schedule 04.08.2016
comment
@Andrew: у меня нет контроля над платформой развертывания.   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
Но вы контролируете, какое программное обеспечение будет развернуто. Правильно?   -  person Andrew    schedule 04.08.2016
comment
@Andrew: Мое программное обеспечение да, но я не смогу полагаться на возможность установить менеджер зависимостей на целевой платформе. По сути, это RPM (и может быть несколько RPM).   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
@Lightness Создайте для целевой системы систему, которой вы можете управлять (при необходимости, перекрестную компиляцию), а затем разверните конечный продукт. Я столкнулся только с целевой системой, в которой я был ограничен тем, что мог развернуть, и это было связано с лицензионными ограничениями. Мы преодолели эту проблему, просто используя среду сборки и среду развертывания/цели.   -  person Andrew    schedule 04.08.2016
comment
@Andrew: Ну, конечно, а как еще мне его построить? Кажется, это не решает ни одну из проблем, описанных здесь.   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
@Lightness Не понимаю, почему бы и нет. Ваша проблема говорит о том, что вы используете компилятор, который не является системным по умолчанию (т.е. вы получили его в другом месте и развернули в своей целевой системе). Почему вы не можете применить тот же подход для сторонних библиотек? В противном случае вы ограничены GCC 4.3, так как это то, что входит в вашу целевую систему.   -  person Andrew    schedule 04.08.2016
comment
@Andrew: Потому что это сложнее. Проблема заключается в бинарной совместимости с библиотеками, уже присутствующими в целевой системе. К счастью, ниже есть несколько хороших предложений :)   -  person Lightness Races in Orbit    schedule 04.08.2016
comment
@Lightness Вы уже показали, что можете развертывать программное обеспечение, которое не входит в систему по умолчанию. Сделайте то же самое со своими библиотеками. В противном случае вы будете вынуждены перейти на С++ 03.   -  person Andrew    schedule 04.08.2016
comment
можете ли вы перекомпилировать библиотеки, которые вы используете на целевой машине? chroot может помочь.   -  person dau_sama    schedule 05.08.2016


Ответы (4)


На самом деле вы можете распространять программу, скомпилированную с помощью более нового компилятора g++, на платформе vanilla CentOS 6. Есть несколько способов сделать это: Самый простой — использовать DevToolset 3, что даст вам g++ 4.9.2 (набор инструментов 2 даст вам gcc 4.8.2). Затем просто скомпилируйте приложение с помощью этого g++. При распространении вашего программного обеспечения вы также должны поставлять libstdc++.so, поставляемый с g++ 4.9. Либо установите LD_LIBRARY_PATH, чтобы он загружался при запуске, либо установите RPATH, чтобы сообщить исполняемому файлу, где сначала искать библиотеки.

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

Да, вы также можете попытаться статически связать libstdc++.a. Найдите вариант -static-libstdc++:

Когда программа g++ используется для компоновки программы C++, она обычно автоматически связывается с libstdc++. Если libstdc++ доступна как разделяемая библиотека и параметр -static не используется, то это указывает на общую версию libstdc++. Обычно это нормально. Однако иногда полезно заморозить версию libstdc++, используемую программой, не переходя полностью к статической ссылке. Параметр -static-libstdc++ указывает драйверу g++ на статическую компоновку libstdc++ без обязательной статической компоновки других библиотек.

Но если вы сделаете статическую ссылку, вы не получите никаких обновлений безопасности и т. д. Конечно, вы не получите обновлений, если вы также отправите libstdc++.so самостоятельно, но добавочные обновления могут быть проще.

И что касается запуска вашего приложения: эмпирическое правило: компилируйте на самой старой платформе, которую вам нужно поддерживать, тогда ваши двоичные файлы (с самостоятельно поставляемой libstdc++ и другими необходимыми библиотеками), вероятно, будут работать и на более новых версиях. То есть, если вы компилируете на CentoOS 6, и он работает, то вы можете ожидать, что он будет работать и на CentOS 7. Если говорить о смежной теме, это как раз та причина, по которой, например, AppImage и сопутствующие решения рекомендуют строить на старой системе.

person dhaumann    schedule 04.08.2016
comment
Или статически связать libstdС++, да? - person Lightness Races in Orbit; 04.08.2016
comment
В качестве продолжения, как насчет развертывания на CentOS 7? Его GCC 4.8, но по умолчанию в GCC 4.8 используется C++03... Или CentOS 6 с GCC 4.3 в режиме -std=c++0x? - person Lightness Races in Orbit; 04.08.2016
comment
Эмпирическое правило: компилируйте на самой старой платформе, тогда ваши двоичные файлы (с поставляемым libstdc++), скорее всего, будут работать и на более новых версиях. То есть, если вы компилируете в CentoOS 6, и он работает, то вы можете ожидать, что он будет работать и в CentOS 7. Однако лучше проверить это. - person dhaumann; 04.08.2016
comment
Пока вы поставляете libstdС++, нет причин не использовать функции С++11 и т. д. Просто убедитесь, что вы скомпилировали все необходимые библиотеки с помощью одного и того же компилятора (вы даже можете изменить стандартную версию С++). - person dhaumann; 04.08.2016
comment
Ага, хорошо. Предположительно, тогда libstdc++ выполняет необходимое пространство имен, чтобы все это работало независимо от флагов компиляции. Просто важно использовать тот же libstdС++. Спасибо! - person Lightness Races in Orbit; 04.08.2016
comment
Итак, мое решение в основном таково. Независимо от того, какой компилятор использовался, я развертываю свои общие библиотеки C++ (включая libstdc++) вместе с продуктом и использую rpath. Мне нужно строить на самой целевой платформе, потому что я создаю RPM, и есть всевозможные зависимости, которые просто не сработали бы, если бы я попытался построить, например. Пакет CentOS 7 для CentOS 6 или 64-разрядный пакет CentOS 6 для 32-разрядной версии CentOS 6. Поэтому я буду использовать devtoolset на 64-битной CentOS 6 и, гм, сделать что-то еще на 32-битной (хотя я бы предпочел не собирать GCC из исходного кода каждый раз, когда я создаю экземпляр виртуальной машины сборки :/). - person Lightness Races in Orbit; 17.08.2016

На эту тему есть замечательная страница: https://gcc.gnu.org/wiki/Cxx11AbiCompatibility

Короче говоря, C++11 в gcc в основном ABI совместим с C++98, но есть пара несоответствий. На странице выше перечислены все из них.

Чтобы облегчить проблему, я могу предложить следующий подход:

  • Четко определите все ваши зависимости, которые являются библиотеками C++. Обычно их у вас не слишком много - в первую очередь приходит на ум буст, у вас есть что-нибудь еще?
  • Затем вы проверяете, есть ли нужные вашему приложению символы в списке сломанных ABI (см. выше). Если их нет, вы в чистоте.
  • Если это так, вы перекомпилируете библиотеку и либо распространяете ее как общую библиотеку вместе с вашим приложением (играя с флагами Rpath, чтобы убедиться, что ваше приложение загружает вашу версию), либо статически связываете ее.

На всякий случай вы могли бы также статически слинковаться с libstdc++.

person SergeyA    schedule 04.08.2016
comment
Итак, как я и предположил, ABI неодинаков в языковых стандартах. Но как решить проблему? - person Lightness Races in Orbit; 04.08.2016
comment
На странице описан алгоритм. Если вы найдете несовместимый символ, единственный вариант — перекомпилировать все библиотеки C++, необходимые вашему приложению, и распространять их вместе с ним. Вот что мы сделали. - person SergeyA; 04.08.2016
comment
Мой вопрос требует более подробной информации о том, что я могу сделать, чтобы исправить ситуацию. Нужно ли мне статически связывать новые сборки всех моих родных сторонних зависимостей? - person Lightness Races in Orbit; 04.08.2016
comment
@LightnessRacesinOrbit, прежде всего, нужно четко определить все ваши зависимости, которые являются библиотеками C++. Обычно их у вас не слишком много - в первую очередь приходит на ум буст, у вас есть что-нибудь еще? Затем вы проверяете, есть ли символы, которые нужны вашему приложению, в списке сломанных ABI. Если это так, вы перекомпилируете библиотеку и либо распространяете ее как общую библиотеку вместе с вашим приложением (играя с флагами Rpath, чтобы убедиться, что ваше приложение загружает вашу версию), либо статически связываете ее. С тем же успехом вы могли бы связать статически с libstdС++. - person SergeyA; 04.08.2016
comment
Хм, хорошо, теперь мы разговариваем - не могли бы вы добавить это в ответ? - person Lightness Races in Orbit; 04.08.2016

В моей компании мы используем gcc 5.1.0, скомпилированный и используемый на CentOS 5.5 (со старым gcc на борту).

Когда мы развертываем наше приложение, мы также распространяем libstdc++.so и libgcc_s.so, скомпилированные из исходников gcc 5.1.0.

Например:

/opt/ourapp/lib/libstdc++.so
/opt/ourapp/lib/libgcc_s.so
/opt/ourapp/bin/myapp

И для корректного запуска бинарника выполняем:

LD_LIBRARY_PATH=/opt/ourapp/lib/ myapp.

Надеюсь, поможет.

Недостатки: По крайней мере, вы не можете использовать собственный gdb в такой среде из-за несовместимости формата DWARF.

person user1503944    schedule 05.08.2016
comment
Я нахожу противоречивую информацию о необходимости повторного распространения libgcc_s.so. Можете ли вы объяснить, почему вы решили распространять его вместе с libstdc++.so? - person Lightness Races in Orbit; 17.08.2016

Если вы создаете программу на C++11 с помощью определения _GLIBCXX_USE_CXX11_ABI=0 (см. это) и вариант --abi-version=2 (см. это), вы должны совместим с любой сборкой библиотеки с GCC 4.3, включая libstdc++.

Версия ABI по умолчанию была от 2 до 4.9, кажется безопасным предположением, что CentOS использует ABI по умолчанию.

Макрос _GLIBCXX_USE_CXX11_ABI повлияет на типы стандартной библиотеки, чтобы использовать тот же макет, что и в версии до C++11. Это вызовет некоторые проблемы с соответствием C++11 (причина, по которой они были изменены в первую очередь), такие вещи, как сложность std::list<>::size().

Параметр командной строки --abi-version= влияет на ABI компилятора, соглашения о вызовах, изменение имени и т. д. ABI по умолчанию был 2 от 3.4 до 4.9.

person Arvid    schedule 04.08.2016
comment
(Вы имели в виду ABI версии 2?) - person Lightness Races in Orbit; 04.08.2016
comment
О, это интересно. Кажется, помимо этих изменений, я все еще могу использовать более новые типы, такие как std::thread, пока я статически связываю более новый libstdc++ для своих целей? Потому что у вас не может быть конфликта с чем-то, чего раньше вообще не существовало... Тогда для меня это был бы самый простой подход. - person Lightness Races in Orbit; 04.08.2016
comment
ах да, он говорит, что версия 2 abi была по умолчанию до 4.9. Полагаю, это немного неясно, но вы, вероятно, правы. 2 кажется лучшим предположением. - person Arvid; 04.08.2016
comment
Это было многообещающе — в конечном итоге мне действительно нужны функции из более поздних сборок библиотек, а не просто совместимость с ABI, поэтому я в конечном итоге перераспределил партию. Но хорошая информация, спасибо! - person Lightness Races in Orbit; 17.08.2016
comment
... и я осмелюсь сказать, что еще даже не приблизился к завершению тестирования, так что... :) - person Lightness Races in Orbit; 17.08.2016