Атрибут [[visible]], упрощающий создание динамических библиотек.

yndx-antoshkka
yndx-antoshkka

Наверное многие сталкивались с ситуацией, что чтобы создать динамическую биюлиотеку или плагин, необходимо написать подобный код:

    #if EXPORTING
    #   if MSVC
    #       define API __declspec(dllexport)
    #   else
    #       define API __attribute__((visibility("default")))
    #   endif
    #else
    #   if MSVC
    #       define API __declspec(dllimport)
    #   else
    #       define API
    #   endif
    #endif

После чего, все публичные методы библиотеки пометить описанным выше макросом API:

    // Public interface
    API bool grph_is_tree(graph* g);
    API bool grph_is_directed(graph* g);

В дальнешем нужно следить за параметрами сборки, правильно задавать макросы EXPORTING и возможно придется дорабатывать код (чтобы можно было собирать статические библиотеки с тем же заголовочным файлом, собираться на других платформах и т.п.)

Так вот, предлагаю сделать атрибут [[visible]], который берёт эту задачу на себя. Предложение уже доступно по адресу p0276r0

С радостью выслушаю любые идеи и замечания к предложению!

34
рейтинг
18 комментариев
Сергей Прейс
Есть, правда, проблемка: если я правильно помню, компиляторы имеют право игнорировать неподдерживаемые аттрибуты. Может надо как-то расширить ключевое слово extern на эту тему?
Сергей Прейс
yndx-antoshkka
Сергей Прейс, на каком-то из недавних заседаний решили, что компиляторы должны игнорировать не поддерживаемые атрибуты. Так что в том плане - всё верно.
yndx-antoshkka
Сергей Прейс
yndx-antoshkka, именно игнорирование атрибута меня и беспокоит: если visibility не поддерживается на платформе - это нормально. Но вот если конкретный компилятор его не поддержал (скажем, не успел) то будут проблемки: символы просто не проэкспортируются и будут недоступны в динамической библиотеке и как результат код приведённый в p0276r0 не сократится, а только раздуется за счёт проверок на версии компиляторов поддерживающих [[visible]].
Сергей Прейс
yndx-antoshkka
Сергей Прейс, у вас есть идеи как этого избежать?
yndx-antoshkka
Сергей Прейс
yndx-antoshkka, один из вариантов - сделать это не атрибутом, а ключевым словом или модификатором к extern, чтобы все компиляторы поддерживающие стандарт были обязаны это правильно обрабатывать.

Сейчас на linux и windows эта проблема решена по-разному. На Windows __declspec(dllexport) не может игнонироваться. Он появился одновременно с динамическими билиотеками и всегда поддерживался и правильно обрабатывался всеми компиляторами на платформе. На linux дефолтное поведение - это visibility=default и все символы экпортируются, а visibility=hidden - это оптимизация по атрибуту, который может игнорироваться. Изменение этого поведения делается по ключу и, соответсвеннo, vendor-specific (разработчики компилятора вообще говоря не обязаны это поддерживать). Соответсвенно, не очень понятно как стандарт будет устроен - по идее чтобы атрибуты работали правильно он должен быть устроен как дефолтное поведение на Linux, но это ухудшит жизнь на Windows и принесет мало пользы на Linux. Если же в стандарте будет предписан явный экспорт - это поломает обратную совместимость на Linux и сделает использование артибутов невозможным - такой атрибут нельзя будет игнорировать.

Сейчас идёт движение в сторону стандартизации модулей и интерфейсов и в рамках этого направления, я думаю, можно стандартизовать и внешнюю видимость на уровне языка на не платформо-специфичных свойств и атрибутов.
Сергей Прейс
Олег Ляттэ
Сергей Прейс, man gcc (5.3.0 Linux) рекомендует -fvisibility=hidden и помечать нужные символы/классы/неймспейсы __attribute__ ((visibility("default"))). Это не только согласуется с подходом Windows, но и является более корректным решением, т.к. экспортить всё, конечно, гарантирует видимость, но затрудняет оптимизацию, нарушает инкапсуляцию, замедляет загрузку DSO.

В любом случае, если вы используете -fvisibility=default (или просто оставляете поведение по умолчанию), то [[visible]], как и __attribute__ ((visibility("default"))), просто не имеет никакого эффекта, т.к. все символы и так экспортируются (видимы), и наличие этих атрибутов ничего не поломает.

Если же вы используете -fvisibility=hidden, то атрибут [[visible]] является по сути синонимом __attribute__ ((visibility("default"))), и действует аналогично __declspec(dllexport) в Windows.
Олег Ляттэ
Олег Ляттэ
Сергей Прейс, кстати, не думаю, что в этом случае стоит мериться на компиляторы, которые не успели поддержать стандартный атрибут. Тем более, что управление видимостью символов уже давно реализовано практически во всех компиляторах, так что поддержка стандарта в этом случае будет делом вполне тривиальным.
Олег Ляттэ
Сергей Прейс
Олег Ляттэ, боюсь, что за кучей написанных мною слов вы не поняли суть дилеммы.

Все атрибуты в стандарте сейчас "do not change the meaning of the program, but may result in generation of more efficient code". И "Any attribute-token that is not recognized by the implementation is ignored". Предложения по атрибутам, меняющим meaning of the program последовательно откланяются (на сколько я знаю) поскольку свойства влияющие на семантику должны быть (по идеологии стандарта) частью системы типов, а атрибуты - не являются.

Посему дилемма:
- Не удастся сделать атрибут [[visible]] при дефолтном -fvisibility=hidden (как на Windows). Такой атрибут не может быть проигнорирован компилятором с сохранением корректности кода. Надо либо менять базовые принципы концепции "атрибут" в стандарте либо использовать для определения видимости другую концепцию.
- Гипотетический атрибут [[visibility_hidden]] был бы совместим с концепцией атрибутов, но от него было бы мало пользы и его было бы сложно реализовать на Windows.

Поймите правильно, мне нравится идея стандартизованного управления видимостью для динамических библиотек. Я просто не вижу как это можно сделать стандартным C++ атрибутом (в том смысле в котором атрибуты сейчас понимаются в стандарте).
Сергей Прейс
Олег Ляттэ
Сергей Прейс, если я не ошибаюсь, стандартом С++ видимость символов при динамической линковке никак не регулируется. Атрибут видимости вообще предназначен больше для линковщика, и никак не меняет значение программы с точки зрения языка, а, значит, вполне соответствует общим требованиям к атрибутам.

Обязанность компилятора - скомпилировать файл с исходником в объектный файл в соответствии со стандартом. При этом компилятор _может_ - отнюдь не обязан - помочь линкеру связать динамические библиотеки (вспомните .def файлы у майкрософта - с их помощью вопрос экспорта символов решается вообще без какого-либо участия компилятора). Поэтому атрибут видимости вполне может игнорироваться компилятором без нарушения формальных требований.
Олег Ляттэ
Victor Dyachenko
Фича эта очень полезная, но, ради бога, не называйте атрибут "visible"!

Видимость - это очень общее понятие и касается не только символов для динамического связывания. Хотя бы в что-то, вроде "dl_visible", переименуйте. В данном случае слепо копировать имя атрибута из GCC - не очень хорошая идея. И уже есть прецеденты, когда, например, __attribute__((unused)) стал [[maybe_unused]].
Victor Dyachenko
yndx-antoshkka
Victor Dyachenko, готов переименовать атрибут, если будет предложено более красивое имя. "dl_visible" мне не по душе т.к. "dl" - малоизвестное платформозависимое сокращение.
yndx-antoshkka
Victor Dyachenko
Термин "dynamic linking" как-то привязан к какой-то платформе? Как мне кажется, очень даже общее понятие. Но не суть. Все, что угодно, но не "visible"!
Victor Dyachenko
Victor Dyachenko
Сейчас, фактически только две живые системы: POSIX и Windows.

POSIX: dlopen(), dlsym()
Windows: DLL

Попробую предложить ещё варианты...
Victor Dyachenko
Victor Dyachenko
А вот, кстати: [[dlsym]]. Коротко и по-делу :-)
Victor Dyachenko
yndx-antoshkka
Victor Dyachenko, [[dlsym]] мне по душе! Название proposal менять нельзя, но вот внутри наверное и правда использую имя [[dlsym]]
yndx-antoshkka
Сергей Тиунов
yndx-antoshkka, как насчет [[export]]? не так замысловато, как [[dlsym]].
Сергей Тиунов
Victor Dyachenko
Сергей Тиунов, перегружено разными смыслами ещё больше чем visible. В частности на текущий момент планируется к использованию для модулей (ключевое слово, а не аттрибут)
Victor Dyachenko
Anatoly Scheglov
Новый атрибут, внесение в стандарт таких понятий "динамическая библиотека" - слишком сложно чтобы заменить 13 строк кода (#if EXPORTING).
Стандарт и так большой; тулчейны и так поддерживают DLL/SO.
Anatoly Scheglov
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).