Чи стосувалась C ++ 11 адреса проходження об'єктів std lib між динамічними / спільними межами бібліотеки? (т. е. дл і так)?


34

Однією з моїх головних скарг на C ++ є те, наскільки важко на практиці передавати std бібліотечні об'єкти поза динамічними межами бібліотеки (тобто dll / so).

Бібліотека std часто використовується лише в заголовку. Що чудово підходить для отримання дивовижних оптимізацій. Однак для DLL вони часто будуються з різними налаштуваннями компілятора, які можуть впливати на внутрішню структуру / код контейнерів бібліотеки std. Наприклад, у MSVC один dll може будуватись із налагодженням ітератора, тоді як інший будується з ним. Ці два dll можуть зіткнутися з проблемами, передаючи std-контейнери навколо. Якщо я експоную std::stringв своєму інтерфейсі, я не можу гарантувати, що код, який використовує клієнт, є std::stringточною відповідністю моєї бібліотеки std::string.

Це призводить до важких проблем налагодження, головних болів тощо. Ви або жорстко керуєте налаштуваннями компілятора у вашій організації, щоб запобігти цим проблемам, або використовуєте простіший C-інтерфейс, у якого цих проблем не буде. Або вкажіть для своїх клієнтів очікувані налаштування компілятора, які вони повинні використовувати (що виходить, якщо інша бібліотека визначає інші настройки компілятора).

Моє запитання - чи намагався C ++ 11 зробити щось для вирішення цих питань?


3
Я не знаю відповіді на ваше запитання, але можу сказати, що ваші занепокоєння розділені; вони є ключовим фактором, чому я не буду використовувати C ++ у своїх проектах, оскільки ми цінуємо стабільність ABI через витіснення кожного останнього циклу потенційної ефективності.
Дональні стипендіати

2
Будь ласка, розрізняйте. Важко між DLLс. Між SOs завжди було добре.
Ян Худек

1
Власне кажучи, це не проблема лише C ++. Можлива проблема з іншими мовами.
MrFox

2
@JanHudec Я можу гарантувати, що між ДП не працює майже настільки магічно, як ви, схоже, вказуєте. З огляду на видимість символів та те, як часто працює керування іменами, ви можете бути більш захищеними від проблеми, але компілювання одного .so з різними прапорами / тощо. І якщо припустити, що ви можете зв’язати його в програмі з іншими прапорами, це відповідь для катастрофи.
sdg

3
@sdg: прапори за замовчуванням та видимість за замовчуванням працює. Якщо ви їх поміняєте і потрапляєте в біду, це ваша проблема і не хто інший.
Ян Худек

Відповіді:


20

Ви впевнені, що будь-якого STL - насправді, нічого з будь-якої сторонньої бібліотеки, на яку шаблонується - краще уникати в будь-якому публічному API C ++. Ви також хочете дотримуватися довгого списку правил за адресою http://www.ros.org/reps/rep-0009.html#definition для запобігання злому ABI, що робить програмування загальнодоступними API C ++ справжньою справою.

І відповідь щодо C ++ 11 - ні, цей стандарт цього не стосується. Більш цікаво, чому ні? Відповідь тому, що C ++ 17 дуже доторкається до цього, і для реалізації модулів C ++ нам потрібні експортовані шаблони для роботи, і для цього нам потрібен компілятор типу LLVM, такий як clang, який може скинути повний AST на диск, а потім робити підходи, що залежать від виклику, для обробки багатьох випадків, що порушують ODR, у будь-якому великому проекті C ++ - який, до речі, включає багато GCC та код ELF.

Нарешті, я бачу чимало коментарів MSVC до ненависті та коментарів про GCC. Вони дуже дезінформовані - GCC на ELF принципово і безповоротно нездатний створювати дійсний і правильний код C ++. Причин цього багато і легіон, але я швидко наведу один приклад випадку: GCC на ELF не може безпечно створювати розширення Python, написані за допомогою Boost.Python, де більше ніж одне розширення на основі Boost.Python завантажено в Python. Це тому, що ELF зі своєю глобальною таблицею символів C просто не може бути спроектованим, щоб запобігти порушенням ODR, викликаючи segfault, тоді як PE та MachO, і справді запропонована специфікація модулів C ++ використовують усі таблиці символів на модулі - що, до речі, також означає набагато більш швидкий процес упродовж часу. І є ще багато проблем: див. StackOverflow, на який я нещодавно відповівhttps://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055, наприклад, коли викиди винятків C ++ безповоротно порушуються на ELF.

Останній пункт: що стосується взаємодії різних STL, це є великим болем для багатьох великих корпоративних користувачів, які намагаються змішати сторонні бібліотеки, які тісно інтегровані в деяку реалізацію STL. Єдине рішення - це новий механізм для C ++ для обробки інтеропу STL, і, хоча вони у нього є, ви також можете виправити інтероп компілятора, щоб ви могли (наприклад) змішати MSVC, GCC і кланг-компільовані об’єктні файли, і все це просто працює . Я б спостерігав, як C ++ 17 намагається бачити, що з’явиться в найближчі кілька років - я здивуюсь, якщо нічого не вийде.


Чудова відповідь! Я тільки сподіваюся, що Clang покращує сумісність з Windows, і це може встановити хороший стандартний компілятор. Система текстового включення / заголовка C ++ є жахливою, я з нетерпінням чекаю дня, коли модулі спростять організацію коду C ++, нескінченно прискорюють час компіляції та покращують сумісність компілятора з порушеннями ODR, які порушують.
Алессандро Стаматто

3
Особисто я очікую істотного збільшення часу компілятора. Швидко пройти внутрішньомодульний AST дуже важко, і нам, мабуть, знадобиться загальний кеш пам'яті загальної пам'яті. Однак майже все інше, що погано, стає кращим. BTW, файли заголовків, безумовно, залишаються навколо, поточні модулі C ++ мають файли інтерфейсу, які відображають 1-на-1 до файлів заголовків. Крім того, автоматично згенеровані файли інтерфейсу будуть легальними C ++, тому застарілий заголовок просто отримує макроси C і відфільтровується як файли інтерфейсу. Приємно, а?
Найлл Дуглас

Класно! У мене так багато сумнівів щодо модулів. Чи буде модульна система враховувати Текстове включення проти символічного включення? Завдяки цій директиві включати компілятор повинен перекомпілювати десятки тисяч рядків коду знову і знову для кожного вихідного файлу. Чи дозволить система модулів коли-небудь код без попередніх декларацій? Чи поліпшить / полегшить інструменти побудови?
Алессандро Стаматто

2
-1 за припущення, що всі сторонні шаблони є підозрюваними. Зміна конфігурації не залежить від того, чи налаштована річ є шаблоном.
DeadMG

1
@Alessandro: Запропоновані модулі C ++ явно вимикають макроси C. Ви можете використовувати шаблони або зараз. Запропоновані інтерфейси є легальними C ++, просто автогенерованими і можуть бути необов'язково попередньо компільовані для швидкості повторної повторної роботи, тобто не очікуйте жодного прискорення над існуючими попередньо складеними заголовками. Останні два запитання я фактично не знаю: це залежить :)
Найлл Дуглас

8

У специфікації ніколи не було цієї проблеми. Це тому, що в ньому є концепція під назвою "одне правило визначення", яка передбачає, що кожен символ має точно одне визначення в процесі запуску.

DLL-файли Windows порушують цю вимогу. Тому є всі ці проблеми. Тож Microsoft має це виправити, а не комітет зі стандартизації C ++. У Unix ніколи не було цієї проблеми, тому що спільні бібліотеки там працюють по-різному і за замовчуванням відповідають одному правилу визначення (ви можете явно його порушити, але ви, очевидно, це робите лише якщо знаєте, що можете собі це дозволити і потрібно вичавити кілька додаткових циклів).

DLL-файли Windows порушують одне правило визначення, оскільки:

  • Вони вказують жорсткий код, з якого буде використаний символ динамічної бібліотеки протягом статичного часу зв'язку, і розв’язують символи статично в бібліотеці, яка їх визначає. Отже, якщо той самий слабкий символ генерується в декількох спільних бібліотеках і цих бібліотеках, ніж звикнути в одному процесі, динамічний лінкер не має шансів об'єднати ці символи. Зазвичай такі символи є статичними членами або класовими імпедиментами шаблонів шаблонів, і це викликає проблеми при передачі екземплярів між кодом у різних DLL.
  • Вони твердо кодують, чи буде імпортовано символ із динамічної бібліотеки вже під час компіляції. Таким чином, код, пов'язаний з деякою бібліотекою статично, несумісний з кодом, динамічно пов'язаним з тією ж бібліотекою.

Unix, використовуючи експорт у форматі ELF, неявно імпортує всі експортовані символи, щоб уникнути першої проблеми та не розрізняє статично та динамічно розв'язані символи до тих пір, поки статичний час зв'язку не уникне другого.


Інше питання - це прапори компілятора. Ця проблема існує для будь-якої програми, що складається з декількох одиниць компіляції, динамічні бібліотеки не повинні бути задіяні. Однак це набагато гірше в Windows. У Unix не дуже важливо, чи ви пов'язуєте статично чи динамічно, ніхто так чи інакше не пов'язує стандартний цикл виконання (в Linux це навіть може бути незаконним), і немає спеціального часу налагодження, тому одна збірка є досить хорошою. Але те, як Microsoft впроваджував статичне та динамічне з'єднання, час налагодження та випуску та деякі інші варіанти, означає, що вони спричинили комбінаторний вибух потрібних варіантів бібліотеки. Знову випуск платформи, а не мова C ++.


2
@DougT.: GCC не має до цього нічого спільного. Платформа ABI має. У ELF об'єктний формат, який використовується більшістю Unices, спільні бібліотеки експортують усі видимі символи та імпортують усі символи, які вони експортують. Отже, якщо щось створюється в декількох бібліотеках, динамічний лінкер використовуватиме перше визначення для всіх. Простий, елегантний та робочий.
Ян Худек

1
@MartinBa: Немає чого зливатися, але це не є матерацією, поки це те саме і до тих пір, поки його не слід об'єднувати в першу чергу. Так, якщо ви використовуєте несумісні налаштування компілятора на платформі ELF, ви отримуєте той самий безлад, як і де завгодно. Навіть якщо не використовуються спільні бібліотеки, то тут дещо поза темою.
Ян Худек

1
@Jan - це стосується вашої відповіді. Ви пишете: "... одне правило визначення ... DLL-файли Windows порушують цю вимогу ... спільні бібліотеки працюють по-різному [в UNix] ...", але поставлене запитання стосується проблем із елементами std-lib (визначеними в заголовках) і причина, що в Unix немає проблем, не має нічого спільного з SO vs. DLL, але з тим, що в Unix (мабуть) є лише одна сумісна версія стандартної бібліотеки, а в Windows MS вирішили мати несумісні версії (налагодження) (з розширеною перевіркою тощо).
Мартін Ба

1
@MartinBa: Ні, головна причина, що існує проблема в Windows, полягає в тому, що механізм експорту / імпорту, який використовується в Windows, не може належним чином об'єднати статичні члени та перешкоди класів шаблонів у всіх випадках і не може об'єднати статично та динамічно пов'язані символи. Тож це набагато гірше через кілька варіантів бібліотеки, але головна проблема полягає в тому, що C ++ потребує гнучкості від лінкера, якого не має динамічний лінкер Windows.
Ян Худек

4
Я думаю, що це значення про те, що специфікація DLL порушена і відповідний попит на Msft для "виправлення" не відповідає. Те, що DLL не підтримують певні функції C ++, не є дефектом специфікації DLL. DLL - це механізм упаковки, нейтральний до мови, нейтральний для постачальників і ABI, щоб виставити вхідні точки машинному коду ("функціональні дзвінки") та краплі даних. Вони ніколи не мали на меті підтримувати вдосконалені функції будь-якої конкретної мови. Це не вина Msft або специфікація DLL, що деякі люди хочуть, щоб вони були чимось іншим.
Євро Міцеллі

6

Ні.

Проводиться велика робота по заміні заголовкової системи, функція якої називається Модулі і яка може вплинути на це, але, безумовно, не велика.


2
Я не думаю, що система заголовків не матиме жодного впливу на це. Проблеми полягають у тому, що DLL-файли Windows порушують одне правило визначення (це означає, що вони не дотримуються специфікацій C ++, тому комітет C ++ нічого не може з цим зробити) і що у Windows існує багато варіантів стандартного режиму виконання, який комітет C ++ може ' т нічого не робити.
Ян Худек

1
Ні, вони ні. Як вони могли, специфікація навіть не згадує щось подібне. Крім цього, коли програма (Windows) пов'язана з dlls Windows, ODR задовольняється: всі видимі (експортовані) символи повинні відповідати ODR.
Пол Міхалик

@PaulMichalik C ++ охоплює посилання (фаза 9), і мені здається, що принаймні прив'язка DLL / SO до часу завантаження припадає на фазу 9. Це означає, що символи із зовнішнім зв’язком (експортованим чи ні) повинні бути пов'язані та відповідати ОДР. Динамічне посилання на LoadLibrary / dlopen очевидно не підпадає під ці вимоги.
bames53

@ bames53: IMHO, характеристики є надто слабкими, щоб допускати такі заяви. .Dll / .so може розглядатися як «програма» самі по собі. Тоді як правила були задоволені. Щось на зразок завантаження інших "програм" під час виконання настільки не підкреслюється стандартом, що будь-які заяви щодо цього є досить умовними.
Пол Міхалик

@PaulMichalik Якщо виконуваному файлу потрібне посилання на час завантаження, то перед тим, як зв’язувати час завантаження, зовнішні об'єкти залишаються невирішеними, а інформація, необхідна для виконання, відсутня. LoadLibrary і dlopen знаходяться за межами специфікації, але час навантаження, що зв'язується досить чітко, повинен бути частиною фази 9.
bames53
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.