#c
#c
Вопрос:
Мне было интересно, есть ли простой способ использовать определения как встроенные внутри общей библиотеки, но при этом экспортировать символы для импорта другим приложением.
Комментарии:
1. Предоставить функцию-оболочку для API разделяемой библиотеки, которая вызывает встроенную функцию?
2. Есть ли способ без создания функции-оболочки?
3. Вы пробовали что-нибудь?
4. Если вы говорите о
inline
ключевом слове, то прежде всего помните, что на самом деле это всего лишь намек на то, что компилятору разрешено встроить функцию (это могут быть встроенные функции, которые не отмечены какinline
также). Кроме того, всеinline
функции с внешней связью (т. Е. Они не являютсяstatic
или помещены в (не встроенное) анонимное пространство имен) должны быть определены как любая другая функция внешней связи и, следовательно, могут быть вызваны из внешних «модулей».5. Учитывая комментарий выше, я думаю, что в большинстве случаев это доставит больше проблем, чем того стоит.
Ответ №1:
В соответствии с буквой стандарта это невозможно.
[dcl.inline]
6. Встроенная функция или переменная должна быть определена в каждой единице перевода, в которой она используется с использованием odr, и должна иметь точно такое же определение в каждом случае […] Если функция или переменная с внешней связью объявлена встроенной в одной единице перевода, она должна быть объявлена встроенной во всех единицах перевода, в которых она появляется; диагностика не требуется.
Таким образом, одна и та же функция не может быть встроенной в часть программы и не встроенной в другую часть. Вы должны использовать оболочку.
у gcc есть способ экспортировать inline
функции. Попробуйте -fkeep-inline-functions
или __attribute__((used))
. Неясно, насколько это полезно в контексте C , поскольку в соответствии с правилами вы должны экспортировать определения встроенных функций для всеобщего обозрения, а затем они будут встроены клиентом вашей разделяемой библиотеки. Clang поддерживает только __attribute__((used))
.
Если вы готовы проигрывать со стандартом, вы можете попытаться проигнорировать любое из двух приведенных предложений и надеяться на лучшее. Я пробовал оба метода с gcc, и они оба, похоже, работают, однако оба они приводят к неопределенному поведению, поэтому никаких гарантий.
-
Встроенная функция или переменная должна быть определена в каждой единице перевода, в которой она используется odr — игнорируйте это. Просто не определяйте это, когда вы не компилируете библиотеку. Пометьте его
__attribute__((used))
, чтобы выдавался символ.class X { inline void foo(); }; #ifdef BUILDING_SHARED_LIB void __attribute__((used)) X::foo() {} #endif
-
оно должно быть объявлено встроенным во всех единицах перевода, в которых оно появляется — игнорируйте это. Просто не объявляйте это
inline
(и, конечно, не определяйте его), когда вы не компилируете библиотеку. Пометьте его__attribute__((used))
, чтобы выдавался символ.class X { void foo(); }; #ifdef BUILDING_SHARED_LIB inline void __attribute__((used)) X::foo() {} #endif
Похоже, что оба метода работают для меня, однако, как я уже сказал, никаких гарантий быть не может, поскольку это UB в соответствии со стандартом. Однако Itanium ABI не заботится о том, объявлена ли функция встроенной или нет, поэтому, возможно, можно рассматривать ABI как дающий гарантию в случае 2. Я не могу ручаться за это.
Комментарии:
1. Большое спасибо! Это было то, что я имел в виду. Мне нужно будет протестировать это и подумать, стоит ли это внедрять. Знаете ли вы, реализовал ли MSVC какую-либо подобную функцию
-fkeep-inline-functions
?2. @PeterBechP не проверял это, но добавление обычного dllexport к встроенной функции должно помочь.
Ответ №2:
Вы можете использовать оболочку для экспорта:
// public header
MY_DLL_INTERFACE void foo(void);
// private header
inline void foo_impl(void) { … }
// impl
void foo(void) { foo_impl(); }