Недавно нам было предложено отправить Linux-версию одной из наших библиотек, ранее разработанную под Linux и поставляемую для Windows, где развертывание библиотек, как правило, намного проще. Проблема, с которой мы столкнулись, заключается в том, чтобы удалить экспортированные символы до тех, которые находятся в открытом интерфейсе. Для этого есть три веские причины.Разделение общих библиотек Linux
- Чтобы защитить запатентованные аспекты нашей технологии от воздействия через экспортируемые символы.
- Во избежание проблем с конфликтующими именами символов.
- Чтобы ускорить загрузку библиотеки (по крайней мере, мне сказали).
Принимая простой пример, то:
test.cpp
#include <cmath>
float private_function(float f)
{
return std::abs(f);
}
extern "C" float public_function(float f)
{
return private_function(f);
}
собран с (г ++ 4.3.2, Л.Д. 2.18.93.20081009)
g++ -shared -o libtest.so test.cpp -s
и проверки символов с
nm -DC libtest.so
дает
w _Jv_RegisterClasses
0000047c T private_function(float)
000004ba W std::abs(float)
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
00000508 T _fini
00000358 T _init
0000049b T public_function
явно недостаточно. Так что в следующий мы переобъявить общественную функцию, как
extern "C" float __attribute__ ((visibility ("default")))
public_function(float f)
и компилировать с
g++ -shared -o libtest.so test.cpp -s -fvisibility=hidden
, который дает
w _Jv_RegisterClasses
0000047a W std::abs(float)
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
000004c8 T _fini
00000320 T _init
0000045b T public_function
что хорошо, за исключением того, что станд :: абс подвергается. Более проблематично, когда мы начинаем связываться в других (статических) библиотеках вне нашего контроля, все символы, которые мы используем из этих библиотек, экспортируются. Кроме того, когда мы начинаем использовать STL контейнеры:
#include <vector>
struct private_struct
{
float f;
};
void other_private_function()
{
std::vector<private_struct> v;
}
мы в конечном итоге с большим количеством дополнительного экспортом из библиотеки C++
00000b30 W __gnu_cxx::new_allocator<private_struct>::deallocate(private_struct*, unsigned int)
00000abe W __gnu_cxx::new_allocator<private_struct>::new_allocator()
00000a90 W __gnu_cxx::new_allocator<private_struct>::~new_allocator()
00000ac4 W std::allocator<private_struct>::allocator()
00000a96 W std::allocator<private_struct>::~allocator()
00000ad8 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::_Vector_impl()
00000aaa W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_impl::~_Vector_impl()
00000b44 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_deallocate(private_struct*, unsigned int)
00000a68 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_M_get_Tp_allocator()
00000b08 W std::_Vector_base<private_struct, std::allocator<private_struct> >::_Vector_base()
00000b6e W std::_Vector_base<private_struct, std::allocator<private_struct> >::~_Vector_base()
00000b1c W std::vector<private_struct, std::allocator<private_struct> >::vector()
00000bb2 W std::vector<private_struct, std::allocator<private_struct> >::~vector()
NB: С оптимизациями по вам нужно будет, чтобы убедиться, что вектор фактически используется, поэтому компилятор не оптимизирует неиспользуемые символы.
Я считаю, что мой коллега сумел построить одноранговой решение с участием версий файлов и изменения заголовков STL, что, кажется, работает, но я хотел бы спросить (!):
Есть чистый способ удалить все ненужные символы (IE, которые не являются частью открытой библиотеки) из общей библиотеки linux? Я пробовал довольно много вариантов для g ++ и ld с небольшим успехом, поэтому предпочел бы ответы, которые, как известно, работают, а не полагаются.
В частности:
- Символы из (закрытого источника) статических библиотек не экспортируется.
- Символы из стандартной библиотеки не экспортируются.
- Непубличные символы из объектных файлов не экспортируются.
Наш экспортироваться интерфейс C.
Я знаю других подобных вопросов на SO:
- NOT sharing all classes with shared library
- How to REALLY strip a binary in MacOs
- GNU linker: alternative to --version-script to list exported symbols at the command line?
но час У него был небольшой успех с ответами.
О статической привязке системных библиотек: для вас это незаконно. То есть, поскольку [(e)] (http://www.eglibc.org/) [GLIBC] (http://www.gnu.org/software/libc/) лицензируется в соответствии с [LGPL] (http://opensource.org/licenses/LGPL-3.0), и поскольку эта лицензия применяется ко всему используемому ему коду, за исключением случаев, когда она связана динамически, путем связывания статически вы делаете свой код, охватываемым LGPL, и должны предоставлять источники (любому, кому вы дали двоичный код и они запрашивают источники). Это не относится к libgcc и libstdC++, которые специально не применяются к любому коду, используя только открытый API, независимо от того, как он связан. –
Я знаю об этом и не имел в виду символы из glibc, все символы, указанные выше, генерируются путем создания шаблона из стандартной библиотеки C++ и по необходимости генерируются в моих объектных файлах (поскольку экземпляры шаблонов могут " t быть в библиотеке!). –