Перевод публикации Тита Винтерса в рабочей группе 21 (WG21) — комитета по стандартизации языка C++. Автор обсуждает важный вопрос: поддержку обратной бинарной совместимости или ABI (application binary interface).

В течение последних лет в WG21 я активно пропагандировал то, что прогресс важнее обратной совместимости. Но я сам перестаю в это верить, особенно в отношении поддержания бинарной совместимости (ABI). В трех последних релизах (C++14, C++17 и C++20) ABI было настолько стабильно, насколько нам это удавалось. Даже если WG21 решит нарушить обратную совместимость ABI в C++23, мы обеспечивали бинарную совместимость на многих платформах более 10 лет. По моему мнению, в масштабных переделках программных систем доминирует закон Хайрума. Сейчас и не скажешь, у скольких пользователей предположение о стабильности ABI стандартной библиотеки (неважно, сколь мудрое или сколь явное или неявное) твердо «прошито в подкорке», возможно у половины разработчиков на C++ в мире.


Я веду список того, что WG21 могла бы исправить в языке, если мы решим «поломать» ABI. И я не могу уверенно утверждать, что общая стоимость переделок, которое повлечет выполнение только этого списка сравнима с тем, в какую цену обойдется нарушение ABI всей экосистеме. Мы видели много мелких улучшений в консистентности API, качестве кода стандартной библиотеки и т.д., но без сомнения нет ни одного такого «прорывного» изменения, которое оправдало бы эту стоимость для рядового разработчика. Возможно, мы бы получили лучшее соответствие реализаций стандарту, дали бы шанс решить проблемы реализациям, сегодня не выполняющим спецификации стандарта. Но ни одно улучшение из моего списка явно не стоит таких затрат.


Что важнее, из-за ограничений ABI мы не можем устранить существенные потери производительности. Мы не можем избавиться от существенной стоимости передачи unique_ptr по значению [Выступление Chandler’а на CppCon 2019, будет опубликовано позже], не можем изменить std::hash или размещение класса в памяти для unordered_map без того, чтобы заставить всех перекомпилировать все повсюду. Производительность хэшей интенсивно изучалась в течении многих лет и с учетом оптимизации поиска в таблице и собственно хэширования, мы уверенны, что можем предоставить реализацию unordered_map/std::hash, совместимые по API и дающие 200—300% прироста производительности. Но ограничения ABI этого не позволяют. Дополнительные исследования по оптимизации и настройке SSO для std::string предполагают нетривиальное увеличение производительности (1% в микробенчмарках и при масштабировании) – API при этом не затронуто, но ограничения ABI не позволяют этого.

Суммарно заблокированные исключительно ABI потери производительности достигают нескольких процентных пунктов – возможно, до 5—10%. Это не то, без чего не может обойтись экосистема в целом, но может быть неприемлемо для некоторых организаций (Google среди них). Это, безусловно, большие потери производительности, чем допустимо для C++: вспомните, что это язык, утверждающий, что он не оставляет места для более производительного конкурента. Большинство пользователей не кажутся обеспокоенными таким снижением производительности: есть другие реализации хэш-таблиц для озабоченных абсолютной производительностью. Общая неэффективность, связанная с передачей unique_ptr по значению и другие проблемы ABI языка, выступают на первый план в очень небольшом числе задач. Организации, нуждающиеся в максимальной производительнсти могут идти своим собственным путем (и делают это), используя нестандартные библиотеки и нестандартную конфигурацию инструментария. Это закономерно и это нужно ясно понимать.



Изменение ABI затронет сравнительно большее число пользователей. Подозреваю, значительная доля этих пользователей и не подозревает, как сильна их зависимость от ABI. В экосистеме серверов Google’а почти все собирается из исходников, внешних зависимостей довольно мало и есть лучшая, чем в среднем возможность предпринять масштабный рефакторинг. Но даже для нас недавние ломающие ABI изменения стандартной библиотеки стоили 5-10 инженеро-лет.

Суммарная стоимость нарушения обратной совместимости ABI для всей экосистемы C++ можно консервативно оценить в «инженер—тысячилетие»: координация пересборки для каждого в мире поставщика всех на свете плагинов, .so или dll потребует огромных затрат человеческих ресурсов. Совместно с разделением экосистемы из-за C++20 модулей, изменение ABI во временном окне разработки и внедрения C++23 может привести к жесткому разделению экосистемы.



С этой дискуссией связано много вопросов, на которые невозможно ответить. Как долго можем мы продолжать до того момента, когда изменение ABI из просто полезного станет критической необходимостью? Если мы явно выберем поддержку стабильности ABI, насколько дорогим окажется изменение в момент, когда и если возникнет такая критическая необходимость? Если проблемы безопасности вроде Spectre и Meltdown потребуют изменить соглашение о вызовах, во что обойдется C++ преодоление этого рубежа? Какая доля разработчиков использует C++ из-за того, что мы утверждаем, что ставим производительность выше всего остального? Хуже того: как долго сможет C++ утверждать, что он самый быстрый язык и не заниматься такими оптимизациями?


Если мы сознательно не можем позволить или не хотим менять ABI, то это решение надо громко озвучить. Мы должны ясно сказать, что это язык, который ставит стабильность ABI выше нескольких последних процентов производительности. Я готов спорить, что на практике так и было в течение последних нескольких лет. Мы должны дать пользователям знать, что от нас ожидать, и дать им понять, что библиотеки вроде Boost, Folly или Absail ожидаемо правильный выбор, если нужна производительность. Но это ничем не помогает с такими связанными с ABI ограничениями в самом языке, как затраты на передачу unique_ptr. Стандартная библиотека сохраняет значение в такой модели развития: стандартная библиотека — это то, что мы используем для совместимости и стабильности. Это может потребовать изменения фокуса и направления развития: нам может хотеться проектировать для большей гибкости в изменяющихся условиях, а не для «чистой» производительности.


Если же мы утверждаем, что производительность важнее стабильности ABI, мы должны немедленно решить, когда именно мы «сломаем» обратную совместимость и сделать все возможное для того, чтобы экосистема приняла такие изменения. И ясно и громко заявить, что мы идем этим путем. Необходимо понять, что чем больше времени будет проходить между такими изменениями, тем более дорогими они станут – поскольку с течением времени будет все больше неподдерживаемой зависимости от ABI. Наши «реализаторы» очень ясно дали понять, что ломающие совместимость изменения C++11 были болезненными и дорогими. Желание избежать повторения таких расходов естественно, но требуется выбрать: либо мы не повторяем их, поскольку не изменяем ABI, либо сделав расходы меньше.


По сути, для WG21 существуют три возможности:

  1. Решить, в каком релизе будет изменено ABI, неважно в C++23 или C++26. Предупредить людей и немедленно разработать инструменты и диагностики, помогающие идентифицировать места, которые сломаются. Сосредоточится на более последовательной практике и инструментарии для поддержки изменений ABI в будущем. Не в интересах конкретного реализатора подвергнуть своих пользователей последствиям изменения ABI, если другие реализации этого не делают – смена ABI должна быть скоординированной активностью для пользы будущих пользователей. В идеале нужно ломать все – дать ясно понять, что код, скомпилированный в C++23 режиме несовместим с кодом, скомпилированным в предыдущих режимах. Если кто-то сможет обойтись без пересборки, а у других будут ошибки компановки или во время выполнения – это только усилит непонимание и разочарование.
  2. Решить, что мы стремимся к стабильности ABI, формализовав сегодняшнюю практику. Так было уже много лет, когда реализаторы стандарта имели право вето на ломающие изменения ABI – мы уже ставили обратную совместимость ABI выше чистоты дизайна и производительности. Если мы это признаем и ясно скажем пользователям, то экосистема станет лучше. Значение дополнительных библиотек вырастет для тех, кому нужно выжимать последние капли производительности, но не требуется стабильность, даваемая стандартом. Другие, ориентированные на производительность языки, могут в будущем оспорить наше положение.
  3. Не суметь выбрать направление и сохранить status quo. Для меня это худший сценарий: продолжаем и дальше неявно уделять больше внимания обратной совместимости ABI. Говорим «производительность» и голосуем «бинарная совместимость». Такой диссонанс вредит экосистеме и предполагает отсутствие согласия о приоритетах языка. Я искренне надеюсь, что усилиями реализаторов и DG, мы достигнем нужного консенсуса.

Полагаю, что вариант выбора №1 лучше подходит для пользователей, которым требуется максимальная производительность, но с ним связаны невероятная стоимость для экосистемы и он может в дальнейшем привести к фрагментации языка. Вариант выбора №2 – скучный, ответственный и достойный выбор: с печалью признать, что мы закрасили себя в углу комнаты и постараться минимизировать связанные с этим потери. Выбрать вариант №3 – значит не справиться с управлением, и я молюсь за то, чтобы этого избежать: любой явный выбор лучше, чем текущий диссонанс и неспособность достичь согласия в выборе долговременных целей.

Понимаю, что мы достигли нынешнего положения благодаря множеству мелких актов кажущегося разумным бездействия. За прошедшие 10 лет не было сделанного ни одного изменения, которое могло бы оправдать нарушение бинарной совместимости, но неявная политика поддержания обратной совместимости сделалась разрушительной для экосистемы. Однако, приняв такую политику явно, мы откроем другую возможность для постепенного ухода C++ со сцены: нельзя быть системным языком, ориентированным на производительность, оставляя столько места для более производительного языка. В теории, каждый вендор может сам решить «сломать» ABI в любом будущем релизе, но общее направление мысли кажется другим. Уверен, требуется обсуждение и достижение консенсуса между реализаторами стандарта и WG21: какие приоритеты выбрать?

Комментарии (50)


  1. ormoulu
    02.11.2019 21:13

    Что есть бинарная совместимость в C++? Как она реализуется?


    1. Ryppka Автор
      02.11.2019 21:16

      1. ormoulu
        03.11.2019 21:52

        Ну как бы… Совместимость с++ на уровне системных вызовов? Вроде бы нет. Совместимость на уровне процессора? Тоже мимо. Формат процедур? Какой угодно. Даже для одной ос/разрядности разные компиляторы из одного исходного кода сгенерят совершенно разный исполняемый.
        В общем, если бы вы смогли объяснить суть проблемы, было бы неплохо.


        1. ilammy
          03.11.2019 22:44

          Совместимость между разными компиляторами, между разными версиями одного и того же компилятора, или между разными версиями одного и того кода. Итоговая цель обычно в том, чтобы можно было независимо получать и обновлять бинарные артефакты. Например, чтобы обновляя библиотеку-зависимость в системе, быть уверенным в том, что приложение не сломается, потому что библиотека собрана чуть-чуть более новой версией компилятора, или в её исходном коде кто-то переименовал переменную.


          1. ormoulu
            02.11.2019 23:19

            То есть вся драма касается какой-то единственной реализации компилятора? Или компиляторов в одной ОС (и похоже это не win)? Как декорация имен может влиять на производительность? Как-то все еще не очень понятно.


            1. fougasse
              02.11.2019 23:27

              Майкрософт и стандартам не особо следует, потому рассуждать о ABI в их случае — странно.
              "Драмы" особой под тем же линуксом нет.
              При чём тут производительность декорации имён — вообще не понятно.
              Если у вас имена не совпадают — ничего работать не будет, но это таки нe ABI.


              1. ormoulu
                02.11.2019 23:32

                В статье жалуются на издержки производительности. Вы пишете про декорацию имен. Что из этого касается ABI — по прежнему непонятно.


                1. DerRotBaron
                  03.11.2019 02:19

                  В статье речь идет о том, что начиная с c++11 до c++20 код, собранный совместимыми компиляторами с разными версиями стандарта (из перечисленных) слинкуется.
                  Проблемы производительности в том, что стандарт предписывает реализацию {X} для класса T, тогда как реализация {Y}, ни в каком виде не совместимая бинарно (компилятор сгенерирует другой код и другую структуру для хранения в памяти), но полностью совместимая по API (ходит и крякает так же), может быть намного эффективнее.


                  1. keydon2
                    03.11.2019 04:53

                    В любом случае фрагментация по бинарной сомвместмости высока и все равно большинство библиотек проще (лучше?) самим пересобрать, чем искать собранную неизвестно кем с неизвестно какими параметрами. Т.е. рядовому пользователю пересобрать проект ради +10% производительности это просто божий дар.


                    Гораздо больше беспокоит историческое наследие в апи и что доступ к стандартам надо покупать (дикость для 2019го). Имхо лучше бы сломали к черту совместимость объявив c++ next, несовместимый с предыдущим, как сделали в Питоне. Что касается стоимости переписывания, так надо и стоимость дальнейшей поддержки учитывать. Сейчас и предыдущие стандарты не полностью поддерживаются компиляторами. И толку заботится об api и abi, если даже крупные корпорации не в состоянии за 5+ лет внедрить новшества? Подозреваю что в первую очередь из-за переусложненности языка и исторического наследства. Фактически у нас и сейчас несколько разных диалектов c++ современных стандартов, некоторые до сих пор 98 стандарт используют, а кто-то и вовсе переходит на раст, го, так что терять нечего, комитет, жги.


                    1. ilammy
                      03.11.2019 13:20

                      доступ к стандартам надо покупать (дикость для 2019го)

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


                      Можно и не участвовать в крысиных бегах, смотреть на открытые черновики стандарта, и делать как считаете нужными. У вас, правда, не будет плашечки Оффициально™ Соответствует Стандарту ISO, которая что-то значит для людей, не разбирающихся в реализации C++.


                    1. Antervis
                      03.11.2019 18:07
                      +2

                      Имхо лучше бы сломали к черту совместимость объявив c++ next, несовместимый с предыдущим, как сделали в Питоне.
                      вот как раз и не хотят «как в питоне». Для сравнения: сейчас средний с++ проект уже с modern c++, а питон2, поддержку которого уже собираются прекращать, живее всех живых.


                  1. qw1
                    03.11.2019 10:19

                    Проблемы производительности в том, что стандарт предписывает реализацию {X} для класса T, тогда как реализация {Y}, ни в каком виде не совместимая бинарно (компилятор сгенерирует другой код и другую структуру для хранения в памяти
                    Один комментатор ниже утверждал, что «проблемы общеизвестны людям, которые профессионально пишут на C++». А оказывается, каждый видит свои — кто в декорировании имён, кто в layout-ах структур в памяти (а как последние влияют на эффективность передачи unique_ptr, о которой пишет автор?).

                    Поэтому и надо сначала обозначить проблему чётко и ясно, а потом уже обсуждать.


                1. yleo
                  03.11.2019 15:40

                  Декорация имен является частью ABI, так как определяет какими именно будут имена сущностей C++ на уровне объектных файлов и DSO.


                  Если имена получаются не удобными для машины, то увеличиваются затраты на обработку объектных файлов и линковку с библиотеками. Грубо говоря, одна из "проблем" в том, что имена получаются длинные (килобайты из шаблонов) и библиотеки просто пухнут (нередко 10-20% объема файла, после обрезки debug info).


                  В случае с DSO (aka dll на Windows) добавляются затраты на связывание в runtime. Может показаться неожиданным, но загрузка и запуск большого проекта C++ клубком DSO может приводить к таблицам имен в 10-100 тысяч имен по 20-1000 байт длиной каждой. И всё это потому что про декорацию особенно не думали, тем более "не завезли" visibility, а потом не решились на visibility=hidden по умолчанию. Короче, печаль.


                  1. qw1
                    03.11.2019 19:48

                    не решились на visibility=hidden по умолчанию. Короче, печаль.
                    В чём проблема-то? Клиент библиотеки включает в свои таблицы импорта только те символы (методы, переменные), к которым фактически имеет доступ, а не все 100500 известных.
                    Сама библиотека может экспортировать только те символы, которые автор библиотеки посчитает нужным видеть клиентам (в MSVC это настраивается в def-файле). Вы бы хотели на уровне языка отмечать у членов класса видимость, чтобы было стандартизовано и не требовалась возня с implementation-specific фичами? Так пожалуйста, вводите в стандарт, от того, что библиотека экспортнёт не все символы, а только фактически используемые, ABI не ломается.


              1. ormoulu
                02.11.2019 23:34

                Статьи, выдаваемые гуглом, утверждают, что ABI это фактическая реализация конструкций языка, к примеру rtti, виртуальных функций, ну и тех же декораций. В этом случае ABI у M$, естественно, есть, просто свой (как и у остальных, впрочем). Но при чем тут производительность, или стандарты языка?


          1. loki82
            03.11.2019 20:55

            А обратная ситуация? Библиотека собрана в старом компилятор, и в новый не подключается. Если не так написал, сори. Но вот с каждой новой версией старое не собирается.


        1. fougasse
          02.11.2019 23:03

          Интерфейс бинарника стараются сохранить.
          Например декорация имён, порядок передачи аргументов в функции и т.п.
          Это позволяет абстрагироваться от "формата процедур" и "системных вызовов" и относительно просто организовать взаимодействие используя заголовочные файлы и здравый смысльпри проектировании библиотек.
          Естественно, что если полезть в потроха бинарника, который собран другой версией компилятора — никто никаких гарантий вам не даст.


          1. u_235
            02.11.2019 23:58

            Берем wxWidgets и с удивлением узнаем, что dll для одного компилятора не подходят для линковки с другим. Где тут совместимость на уровне ABI?


            1. mayorovp
              03.11.2019 15:00

              А это что, хорошо?


            1. yleo
              03.11.2019 15:20

              Это и есть несовместимость на уровне ABI. Но только это не проблемы стандарта C++, а результат сознательной преднамеренной (деструктивной) политики M$ (что неоднократно признавали топовые разработчики покинувшие анклав M$, и что легко проследить начиная от \r\n до OID-ов в ActiveDirectory), в том числе и в отношении ABI.


              1. u_235
                04.11.2019 11:16

                Но только это не проблемы стандарта C++
                Конечно, ведь в стандарте ABI не прописана даже в виде рекомендаций. И политика MS тут ни при чем — они просто делают как им удобно и выгодно.

                mayorovp Это ни хорошо и ни плохо, это просто факт.


            1. fougasse
              03.11.2019 20:01

              это Microsoft, у них свой подход


  1. qw1
    03.11.2019 21:20
    +2

    Плохая статья. Она говорит о какой-то проблеме, но не объясняет проблему. Достаточно было бы дать ссылку, если автор считает, что вопрос общеизвестен и не требует детализации.


    1. fougasse
      03.11.2019 21:37
      -1

      Oн(вопрос) и она(проблема) общеизвестны людям, которые профессионально пишут на C++.
      А хейтерам и ссылки не запретят возмущаться.


    1. 0xd34df00d
      03.11.2019 03:18

      Судя по тому, на что именно ссылается этот перевод, оригинальная статья — почти что письмо в мейллист комитета по стандартизации C++. Они, вероятно, представляют, о чем речь.


      1. qw1
        03.11.2019 08:26

        Они то может и представляют, но зачем сюда постить перевод, не вводя читателей в проблему. У меня может на работе тоже есть интересные задачи, но вырывать кусок из середины рабочей переписки и постить — не оценят.


    1. svr_91
      03.11.2019 14:15
      +1

      Проблема в необходимости прописывать
      _GLIBCXX_USE_CXX11_ABI=0
      и пересобирать все используемые библиотеки (и сам проект) для того, чтобы подключить какую-то старую библиотеку, которую пересобрать из исходиников тяжелее (или невозможно)


      1. qw1
        03.11.2019 20:10

        Вот оно что… Я уж было подумал, что что-то глобально хотят переделать в кодогенерации и соглашениях о вызовах. А тут всего-лишь расширение классов типа std::string, которое естественно потребует перекомпиляции всех модулей, шарящих между собой экземпляры таких классов.

        Тоже, конечно, важно. Но я бы предложил везде, где нужна производительность, линковать всё в один большой толстый бинарник, как это делает например Go (память сейчас не проблема). Заодно Whole Program Optimization и агрессивные inline-ы добавят к скорости.

        Либо, если хочется маленьких бинарников и динамической линковки (для утилит вроде cat и cp), не использовать на критических участках std::string, std::list, сделать std-классы максимально совместимыми (пусть и медленными при вызовах между границами модулей).


  1. lamerok
    03.11.2019 06:58

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


  1. AndDav
    03.11.2019 11:33

    Хочется привести хоть один реальный пример, когда комитет отказался менять API на потенциально более производительное ради сохранения ABI.

    std::set<std::string> s = ...;
    s.find("very very long string"); // конструирование std::string здесь
    

    Если бы после появления std::less<void> в C++14 определение std::set поменяли с
    template<class Key, class Compare = less<Key>, ...>
    class set {...};
    на
    template<class Key, class Compare = less<void>, ...>
    class set {...};
    предыдущий пример не требовал бы создание временной std::string, но это сломало бы ABI.


    1. yleo
      03.11.2019 14:49

      Вы путаете (как минимум в примерах) совместимость на уровне API (компилируется или нет) и ABI (работает ли скомпилированное).


      Совместимость на уровне API стараются сохранить, но смело ломают когда есть резон. А совместимость на уровне ABI со стороны WG21 менялась (если не ошибаюсь, но другого не помню) только с приходом COW для std::string в C++11. При этом было постелено немало "соломки", поэтому GNU libstdc++ и сейчас обеспечивает работу софта собранного для старого ABI.


      При этом WG21 примерно не причастен к массе граблей (например) в разных версиях MSVC.


      1. AndDav
        03.11.2019 15:55

        В каком случае в моем примере был бы сломан API? Весь код, компилирующийся в предположении, что set<T> это set<T, less<T>>, продолжит компилироваться если set<T> станет set<T, less<void>>.


        1. yleo
          03.11.2019 16:36

          Возможно я что-то неверно понял/воспринял в вашем комментарии, но показанное изменение определения std::set<> это смена API и ABI одновременно, причем смена API нивелируется/маскируется гибкостью C++.


          Поэтому вместо смены ABI в С++14 расширили API добавив template< class K > iterator find( const K& x ) во все релевантные контейнеры из Containers library.


          1. AndDav
            03.11.2019 16:43

            И этот самый template<class K> iterator find(const K& x) не помогает избежать создания временной строки при вызове s.find("very very long string") из моего первого примера так как less<string> все равно ожидает 2 аргумента типа string.


            1. yleo
              03.11.2019 17:15

              Опять-таки не уверен, что я вас правильно понял, но что мешает задействовать свой template<typename T = void> struct less c несколькими перегруженными operator()()?


              1. AndDav
                03.11.2019 18:14

                Можно задействовать и свой компаратор и стандартный std::less<void>, но это надо делать явно, я же говорил о том, что комитет решил не делать это поведением по умолчанию std::{set,map} чтобы не ломать ABI.


  1. slonopotamus
    03.11.2019 12:33
    +2

    Линукс: несколько лет назад уже было изменение ABI в такой небольшой штуке как std::string. Затронуло оно чуть менее чем весь софт на C++.


    Винда: совместимость между кодом, собранным разными версиями студии есть только в рамках VS2015-2019.


    О каких "более 10 лет бинарной совместимости на многих платформах говорит автор"?


    1. yleo
      03.11.2019 15:05

      Во-первых dual ABI в GNU libstdc++ как-раз таки обеспечивает совместимость на уровне ABI. Т.е возможно не только запустить старый софт на новой системе, но даже и на новой системе собрать софт, который будет работать на старой (может потребоваться некоторое шаманство для отвязки от symver для некоторых функций glibc).


      Во-вторых WG21 не причастен к граблям поставленных M$ с приходом "Universal Runtime" в MSVC (M$ делает подобное регулярно).


      1. slonopotamus
        03.11.2019 15:28

        Во-первых dual ABI в GNU libstdc++ как-раз таки обеспечивает совместимость на уровне ABI.

        ABI базового C++-класса изменилось. Кто в этом виноват, какие костыли можно применить чтобы оттянуть во времени неизбежное (переход на новый ABI) — не важно. По факту пользователи C++ страдали, наступали на проблемы, пересобирали кучу софта, обмазывали подпорками то что пересобрать нельзя и т.д.


        1. yleo
          03.11.2019 16:05

          Способов страдать бесконечно много. Наверное, умеючи, можно и Dual ABI задействовать с этой целью ;)


          Мне пришлось где-то добавить -D_GLIBCXX_USE_CXX11_ABI=0 в CXX_FLAGS, а пару раз даже для удобства приписать "#define _GLIBCXX_USE_CXX11_ABI 0" в системные h-файлы. Но на страдания это никак не тянет.


          Хотя если принципиально избегать RTFM, то можно позабавится ;)


          1. slonopotamus
            03.11.2019 16:24

            приписать "#define _GLIBCXX_USE_CXX11_ABI 0" в системные h-файлы

            Прелестно.


            Хотя если принципиально избегать RTFM

            1. Ваш намёк не вполне понятен.


            2. У Буратино есть два .so, один собран со старым ABI, второй с новым. Расскажите, в какое положение ему надо переключить _GLIBCXX_USE_CXX11_ABI при сборке .cpp-файла, использующего код из обоих .so.



            1. yleo
              03.11.2019 17:24

              приписать "#define _GLIBCXX_USE_CXX11_ABI 0" в системные h-файлы
              Прелестно.

              На всякий поясню — добавлялось в сборочные контейнеры для сборки "старых" проектов, чтобы совсем не трогать исходники с определениями опций сборки (включая CXX_FLAGS). В частности, так собирались so-шки со "старыми" строками с использованием новых toolchains и без модификации исходников (иногда принципиально важно).


              Хотя если принципиально избегать RTFM
              Ваш намёк не вполне понятен.

              Ради бога не подумайте что я хотел вас задеть и т.п. Просто большинство страданий обычно от незнания.


              У Буратино есть два .so, один собран со старым ABI, второй с новым. Расскажите, в какое положение ему надо переключить _GLIBCXX_USE_CXX11_ABI при сборке .cpp-файла, использующего код из обоих .so.

              Ну вы же сами прекрасно понимаете, что Буратине так не помочь и ему придется выбрать один из берегов (и какую из so-шек пересобрать). Но только это не страданья, а какая-то недодуманность при сборке so-шек и/или выборе поставщиков.


              Т.е. достаточно очевидно, что Буратине нужно определиться с политикой (выбрать одно из трех: только старый стандарт, только новый, либо сборка двух версий so-шек) и просто следовать выбору. Если уже только это приносит Буратине страданья, то его дела плохи — вскорости любые изменения начнут приносить ему боль (включая смены дня и ночи).


    1. Antervis
      03.11.2019 23:02

      Винда: совместимость между кодом, собранным разными версиями студии есть только в рамках VS2015-2019.
      О каких «более 10 лет бинарной совместимости на многих платформах говорит автор»?
      MS не особо пытаются сохранить бинарную совместимость между разными версиями MSVS. Была, например, поломка ABI в 15.6 — минорной! версии. Лучше смотрите в сторону libstdc++, например.


  1. yleo
    03.11.2019 14:23
    +1

    Меня печалит, что автор (Тит Винтерс) рассуждает и как-бы направляет WG21 в неверном направлении выбора между прогрессом и совместимостью. ABI не может быть вечным, его всё-равно неизбежно когда-нибудь придётся развивать/менять. Выражаясь вульгарно — Не следует обсуждать когда и как лучше кошке отрезать хвост: сегодня, завтра, сразу или частями. Нужно думать про анестезию.


    IMHO поэтому WG21 следует сосредоточится (хотя не уверен что это именно их задача) на выработке соглашений/рекомендаций/рецептов для совместного использования нескольких ABI, в том числе для предотвращения смешивания вызовов разных реализаций (один DSO создает новый std::string, а другой DSO разрушает его деструктором от старого std::string).


    Это бы не только сняло ряд проблем с развитием C++, но и буквально развязало руки реализаторам (просвистел помидор в сторону компилятора C++ для E2K). А если помечтать, то попутно можно было-бы дожать проблему с "километровыми" идентификаторами в DSO и т.д. и т.п. Но мне кажется, что большинство "коммитетных парней" чураются спускаться до уровня ABI и DSO, предпочитая рассуждать от высоких материях. Поэтому будем ждать когда условные Google или Apple снова занесут гранты реализаторам в обход "коммитетов".


  1. crea7or
    03.11.2019 15:34

    В совместимости уже нет такой необходимости, как раньше. За то время что я в IT было создано более 10 платформ практически с нуля. В мире много программистов и они что надо напишут/перепишут. А скорость сейчас всё важнее, прогресса большого у процессоров уже не наблюдается, надо выжимать что есть.


  1. Antervis
    03.11.2019 18:15

    грубо говоря, можно сначала ввести механизм (пример) по смешиванию разных версий языка, добавить в него методы конвертации между ABI*, а это уже и есть возможность менять ABI сохраняя обратную совместимость.

    * скажем, если при вызове foo(std::unique_ptr) из более новой «версии» в старую нужно лишь использовать другое соглашение о вызовах, то вызов foo(const std::string&) может создать проблемы, захоти мы поменять бинарное представление std::string. Для этого потребуется введение методов конвертации классов между версиями стдлибы. По сути, механизм для этого почти существует (inline неймспейсы/алиасы и пр.), не хватает лишь указания версии для парсинга.


  1. Sabubu
    03.11.2019 19:56

    Плохо понял, о чем речь? Совместимости ABI в C++ никакой нет, библиотека, скомпилированная одним компилятором, не линкуется с другой. У каждого компилятора своя реализация "стандартной библиотеки".


    Что касается совместимости в пределах одного компилятора, то в чем проблема сделать просто libcpp1 и libcpp2 и пусть старые проекты используют libcpp1, а новые — libcpp2? Для надежности можно поменять способ name mangling, чтобы при использовании неправильной библиотеки все рушилось с грохотом.


    Или же сделать 2 версии функций с суффиксами: function и function2.


    Что-то у меня ощущение, что проблемы будут разве что в скомпилированных 20 лет назад на проприетарном компиляторе библиотеках, от которых нет исходников.


    1. yleo
      03.11.2019 20:35

      Не то чтобы вы совсем не правы, но неправы достаточно значительно:


      • Есть проблемы порожденные отсебятиной M$ (off-topic: Microsoft регулярно кидает и подставляет разработчиков, но некоторые всё еще терпят. Последний пример = "TxF may not be available in future versions of Microsoft Window"). Эти проблемы видны только в некоторых кросс-платформенных сценариях и все уже примерно привыкли что "на виндовс всё через Ж".
      • В 90% остальных случаях есть GCC и CLANG, где с совместимостью ABI очень хорошо, если не прекрасно.
      • Есть embedded-like платформы, где местами есть некий зоопарк ABI и проприетарных компиляторов, хотя наблюдается устойчивая тенденция к принятию "ABI как в GCC" в качестве стандарта де-факта. Но в основном тут разные ABI по-определению (для разного порядка байт, PIC/неPIC и т.п.).
      • Есть какие-то старые платформы (Alpha, DOS) для которых нет актуальных ABI и если вы найдете или соберете компилятор, то ему как-бы не с чем быть несовместимым по ABI.

      Поэтому в 99.99% случаев вы получите совместимость по ABI от разных компиляторов, либо вам просто нужно знать что вы хотите и затребовать это задав опции.


      1. lamerok
        04.11.2019 14:24
        +1

        Вы описали столько различий, Microsoft не пользуйте, старое не трогайте, ембеддед — зоопарк, а потом написали, 99.99% получите совместимость. Вот у меня даже от версии к версии мой IAR по ABI несовместим, как вы и говорите, на каждой версии устойчивая тенденция к изменению все ближе и ближе к GCC, но от этого не легче.


        1. Antervis
          05.11.2019 02:41

          с++ позволяет сохранять бинарную совместимость за парой исключений типа запрета на COW для стандартных контейнеров и багфикса на «noexcept — часть сигнатуры функции» (который, кстати, и нужен для сохранения бинарной совместимости в будущем).

          Всё остальное в руках поставщиков компиляторов. Если майки не ставят перед собой цель сохранять бинарную совместимость, её и не будет — им нравится вариант «просто тащим все версии всего» (например, у меня сейчас установлено 9 версий c++redist).