Принять в стандарт RAII класс для работы с динамическими библиотекми

yndx-antoshkka
yndx-antoshkka

Предлагаю стандартизировать Boost.DLL, чтобы можно было с лёгкостью делать плагины и импортировать функции по мере необходимости из динамических библиотек:

auto cpp11_func = dll::import<int(std::string&&)>(
    "libmy.so", "i_am_a_cpp11_function"
);

cpp11_func("'Hello word' that is sent to shared library");

Предложение уже доступно по адресу: p0275r0

Приветствуются любые предложения по улучшению proposal или Boost.DLL!

30
рейтинг
в разработке
7 комментариев
Anatoly Scheglov
Динамический импорт функций по имени - это костыль. Не надо стандартизировать костыли.
Для сравнительно безопасных плагинов нужна стандартизация ABI (в т.ч. манглинга).
Anatoly Scheglov
yndx-antoshkka
Распишите пожалуйста подробнее ваше решение. Что именно вы предлагаете вместо подхода Boost.DLL?
yndx-antoshkka
Ivan Komissarov

yndx-antoshkka, я мимокрокодил, но есть мысль, что сделать С++ плагин по аналогии с QPluginLoader[1] гораздо проще, чем стандартизовать загрузку функций. API офк можно придумать любое, но идея в том, чтобы отдавать пользователю с++ объект, а не функцию. Из головы сходу приходит идея возвращать std::unqiue_ptr<IPlugin>, но это потребует динамической аллокации, возможно, есть способ лучше. ЗАТО это решит проблему манглинга - из Qt плагина наружу торчит _одна_ си (!) функция, возвращающая объект плагина и её манглинг известен.
Это предложение немного ортогонально вашему (и может быть реализовано через него), но позволяет скрыть очень много сложностей SOшек и может быт реализовано тупо через LoadLibrary/dlopen. При этом можно тупо забить на загрузку "сишных" функций - почти всё можно сделать через плагин.
Но, насколько я знаю, стандарт не любит интерфейсы и наследование:(
[1] http://doc.qt.io/qt-5/qpluginloader.html

Ivan Komissarov
Обновлено 
yndx-antoshkka

Ivan Komissarov, как вы верно заметили - при таком подходе мы теряем функциональность загрузки плагинов, написанных на старом C++, и плагинов, написанных на других языках программирования. Это кажется очень серьёзным недостатоком.

yndx-antoshkka
Ivan Komissarov

yndx-antoshkka, не теряем, так как нет никаких плагинов "на с++", из-за манглинга приходится заворачивать экспортируемые символы в "extern C" иначе код загрузки перестаёт быть переносимым. Поправьте, если ошибаюсь. В целом, я только за то, чтобы была встроенная обертка над dlopen/LoadLibrary, но только с поддержкой языка (т.е. манглинга). Иначе мы всё равно тащим кучу легаси в виде чисто-сишного АПИ плагина. ИМХО, не надо пихать в стандарт то, что сделано плохо по историческим причинам. Лучше дайте людям альтернативный инструмент как сделать правильнее\проще\удобнее и старые плагины сами отомрут. ИМХО, стандартизация даёт уникальную возможность что-то изменить к лучшему и этим надо пользоваться, а не тащить легаси (пусть оно теплое приятное и всем привычное).

Я подумал, что можно в клиентском коде сделать API типа

std::plugin<T> load_plugin("name"); // std::plugin это просто T & или обертка-аналог

а в плагине в cpp писать что-то типа

std::export_plugin<T> baz("name"); // объявили переменную

что, по сути, объявляет синглтон
чтобы не ограничиваться одним экспортируемым классом.
Тогда можно и функции экспортировать как-то так:

int foo(int bar) { return 0; }
std::export_plugin<std::function<int(int)>>("foo", foo);

Работать это будет как-то так - при экспорте плагина кладем его в реестр плагинов, который можно отрезолвить через неманглированный сишный вызов а дальше уже по имени выдирать сами инстансы (надо подумать как это сделать типо-безопасно, можно ли не юзать RTTI, в общем, сделать прототип)

Мой поинт в том, что нет никакого смысла мучаться с QLibrary когда есть QPluginLoader, это стандартное правило 20\80 - при разработке своего приложения просто пишется плагин с экспортом класса, а оставшиеся случаи - это да, указанные другие языки, сишные плагины/библиотеки (привет, OpenGL) и прочее. И в этих 20% случаев не факт, что загрузка символов - самая трудная часть (и стандартизация оной как-то облегчит жизнь), например для того же OpenGL есть куча версий, это всё надо как-то менеджить, да и миллиард функций удобнее будет обернуть в класс, а не хранить стопицот статик-переменных, в которые записали зарезолвленные указатели на эти функции.

Ivan Komissarov
yndx-antoshkka

Да, так может быть удобнее, но есть проблемы:

* Дополнительные накладные расходы на хранение строк

* Дополнительные накладные расходы на поддержку реестра

* Нет возможности подтягивать готовые С плагины. Я об этом уже писал, но наверное недостаточно подчеркнул необходимость такого функционала. Плагины C - это универсальный интрефейс, который поддерживается всеми языками програмирования. Если не поддерживать загрузку C плагинов, то из C++ приложения нельзя будет подтягивать библиотеки написанные на C/Java/.NET/... и соответственно полезность такого класса в стандарте сходит на нет. Многие проекты просто не могу себе такое позволить - у них уже есть большой набор плагинов и никто их переписывать не будет ЛИБО плагины для проекта разрабатываются сторонними разработчиками, и ограничивать их в выборе инструмента - это терять примущество по сравнению с аналогичными проектами.

Тот функционал что вы предлагаете, можно будет попробовать принять в стандарт отдельным предложением. При этом стоит посмотреть в сторону механизма базовой рантайм рефлексии плагинов  https://www.boost.org/doc/libs/1_67_0/doc/html/boost_dll/tutorial.html#boost_dll.tutorial.querying_libraries_for_symbols . С таким подходом несколько меньше накладных расходов, но сохраняется хоть какая-то совместимость с другими языками программирования.

yndx-antoshkka
yndx-antoshkka
Обновлённая версия предложения: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0275r1.html
yndx-antoshkka
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения