ideas
ideas copied to clipboard
Атрибут [[visible]], упрощающий создание динамических библиотек.
Перенос предложения: голоса +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
С радостью выслушаю любые идеи и замечания к предложению!
Сергей Прейс, 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.
Комитет холодно встретил предложение из-за огромных различий в работе динамических библиотек на разных платформах.
Аналогичное предложение было сделано в https://wg21.link/p1283r0 , но автор сказал что не будет над ним больше работать.
Можно будет воскресить идею