ideas icon indicating copy to clipboard operation
ideas copied to clipboard

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

Open apolukhin opened this issue 3 years ago • 3 comments

Перенос предложения: голоса +44, -3 Aвтор идеи: Антон Полухин @apolukhin

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

    #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]], который берёт эту задачу на себя. Предложение уже доступно по адресу https://wg21.link/p0276r0

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

apolukhin avatar Mar 12 '21 09:03 apolukhin

Сергей Прейс, 2 декабря 2016, 13:29 Есть, правда, проблемка: если я правильно помню, компиляторы имеют право игнорировать неподдерживаемые аттрибуты. Может надо как-то расширить ключевое слово extern на эту тему?

yndx-antoshkka, 2 декабря 2016, 16:18 Сергей Прейс, на каком-то из недавних заседаний решили, что компиляторы должны игнорировать не поддерживаемые атрибуты. Так что в том плане - всё верно.

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

yndx-antoshkka, 7 декабря 2016, 20:00 Сергей Прейс, у вас есть идеи как этого избежать?

Сергей Прейс, 8 декабря 2016, 12:30 yndx-antoshkka, один из вариантов - сделать это не атрибутом, а ключевым словом или модификатором к extern, чтобы все компиляторы поддерживающие стандарт были обязаны это правильно обрабатывать.

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

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

Олег Ляттэ, 9 декабря 2016, 0:55 Сергей Прейс, 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.

Олег Ляттэ, 9 декабря 2016, 1:05 Сергей Прейс, кстати, не думаю, что в этом случае стоит мериться на компиляторы, которые не успели поддержать стандартный атрибут. Тем более, что управление видимостью символов уже давно реализовано практически во всех компиляторах, так что поддержка стандарта в этом случае будет делом вполне тривиальным.

Сергей Прейс, 13 декабря 2016, 19:09 Олег Ляттэ, боюсь, что за кучей написанных мною слов вы не поняли суть дилеммы.

Все атрибуты в стандарте сейчас "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++ атрибутом (в том смысле в котором атрибуты сейчас понимаются в стандарте).

Олег Ляттэ, 15 декабря 2016, 1:46 Сергей Прейс, если я не ошибаюсь, стандартом С++ видимость символов при динамической линковке никак не регулируется. Атрибут видимости вообще предназначен больше для линковщика, и никак не меняет значение программы с точки зрения языка, а, значит, вполне соответствует общим требованиям к атрибутам.

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

Victor Dyachenko, 6 декабря 2016, 15:30 Фича эта очень полезная, но, ради бога, не называйте атрибут "visible"!

Видимость - это очень общее понятие и касается не только символов для динамического связывания. Хотя бы в что-то, вроде "dl_visible", переименуйте. В данном случае слепо копировать имя атрибута из GCC - не очень хорошая идея. И уже есть прецеденты, когда, например, __attribute__((unused)) стал [[maybe_unused]].

yndx-antoshkka, 7 декабря 2016, 16:07 Victor Dyachenko, готов переименовать атрибут, если будет предложено более красивое имя. "dl_visible" мне не по душе т.к. "dl" - малоизвестное платформозависимое сокращение.

Victor Dyachenko, 7 декабря 2016, 22:08 Термин "dynamic linking" как-то привязан к какой-то платформе? Как мне кажется, очень даже общее понятие. Но не суть. Все, что угодно, но не "visible"!

Victor Dyachenko, 7 декабря 2016, 22:13 Сейчас, фактически только две живые системы: POSIX и Windows.

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

Попробую предложить ещё варианты...

Victor Dyachenko, 7 декабря 2016, 22:15 А вот, кстати: [[dlsym]]. Коротко и по-делу :-)

yndx-antoshkka, 9 декабря 2016, 20:08 Victor Dyachenko, [[dlsym]] мне по душе! Название proposal менять нельзя, но вот внутри наверное и правда использую имя [[dlsym]]

Сергей Тиунов, 9 марта 2017, 20:07 yndx-antoshkka, как насчет [[export]]? не так замысловато, как [[dlsym]].

Victor Dyachenko, 10 марта 2017, 9:31 Сергей Тиунов, перегружено разными смыслами ещё больше чем visible. В частности на текущий момент планируется к использованию для модулей (ключевое слово, а не аттрибут)

Anatoly Scheglov, 27 декабря 2016, 17:23 Новый атрибут, внесение в стандарт таких понятий "динамическая библиотека" - слишком сложно чтобы заменить 13 строк кода (#if EXPORTING). Стандарт и так большой; тулчейны и так поддерживают DLL/SO.

apolukhin avatar Mar 12 '21 09:03 apolukhin

Комитет холодно встретил предложение из-за огромных различий в работе динамических библиотек на разных платформах.

apolukhin avatar Mar 19 '21 17:03 apolukhin

Аналогичное предложение было сделано в https://wg21.link/p1283r0 , но автор сказал что не будет над ним больше работать.

Можно будет воскресить идею

apolukhin avatar Sep 25 '21 07:09 apolukhin