Мы строим большой открытый исходный код программного обеспечения на различных платформах (Linux, Windows, Mac OS X, 32-битная и 64-битная) в течение нескольких лет без проблем. В последнее время, однако, сборка Mac OS X (64-разрядная версия) перестала работать правильно и начала зависать случайно. Это более или менее совпало с обновлением Mac OS X на нашей сборочной машине с 10.7 до 10.8.2 (но набор инструментов компилятора не изменился, он все еще llvm-gcc 4.2.1).
Наше приложение состоит из пары динамических (общих) библиотек и множества исполняемых файлов, использующих их. Одна из общих библиотек переопределяет new
а также delete
операторы по разным причинам. В Mac OS X (и Linux) все символы экспортируются по умолчанию, включая нашу перегруженную new
а также delete
операторы. Сбои в Mac OS X кажутся связанными с тем, что некоторая память выделяется одной подсистемой памяти (не нашей), а затем освобождается через нашу собственную (и несовместимую) delete
реализация.
Самое правильное решение, по-видимому, заключается в том, чтобы перегруженные операторы не были видны пользователям общей библиотеки. Это может быть достигнуто двумя способами: помечая операторов __attribute__((visibility("hidden")))
или используя -unexported_symbols_list
опция командной строки компоновщика для предотвращения экспорта некоторых символов. Первое решение, к сожалению, не работает: gcc выдает предупреждения о том, что операторы были объявлены по-разному (в <new>
) и, следовательно, атрибуты будут игнорироваться. Из моих чтений в разных местах, второе решение кажется правильным для этой проблемы. Однако по какой-то причине мы не можем заставить это работать.
При связывании общей библиотеки мы передаем -Wl,-unexported_symbols_list unexported_symbols_list.txt
вариант g ++, который по очереди должен быть передан ld. unexported_symbols_list.txt
Файл содержит следующий список символов:
__ZdaPv
__ZdaPvRKSt9nothrow_t
__ZdlPv
__ZdlPvRKSt9nothrow_t
__ZdlPvS_
__Znam
__ZnamRKSt9nothrow_t
__Znwm
__ZnwmPv
__ZnwmRKSt9nothrow_t
Это все вариации new
а также delete
что мы переопределяем и хотим быть скрытыми. Мы нашли эти символы, выполнив nm libappleseed.dylib
затем распаковка имен символов с помощью c++filt
,
Вот командная строка, сгенерированная CMake для ссылки libappeseed.dylib
:
/usr/bin/g++ -g -Werror -dynamiclib -Wl,-headerpad_max_install_names -framework Cocoa -lcurl -Werror -Wl,-unexported_symbols_list -Wl,unexported_symbols_list.txt -o ../mac-gcc4/appleseed/libappleseed.dylib [...]
К сожалению, несмотря на все наши усилия, кажется, что символы остаются (как показывает нм).
Есть идеи, что мы делаем не так?
Есть ли другой подход, который мы могли бы попробовать?
ОБНОВЛЕНИЕ 19 декабря 2012 г .:
Наша проблема и предполагаемое решение хорошо освещены в этой технической заметке Apple: http://developer.apple.com/library/mac/#technotes/tn2185/_index.html (раздел «Переопределение нового / удаление»).
Указатели на соответствующий исходный код:
operator new
а также operator delete
Переопределение: allocator.cppФрагмент nm
выводится после сборки libappleseed.dylib с -fvisibility=hidden
и работает strip -x libappleseed.dylib
:
...
00000000002a41b0 T __ZdaPv
00000000002a41f0 T __ZdaPvRKSt9nothrow_t
00000000002a4190 T __ZdlPv
00000000002a41d0 T __ZdlPvRKSt9nothrow_t
00000000002a4060 T __Znam
00000000002a4130 T __ZnamRKSt9nothrow_t
00000000002a3ff0 T __Znwm
00000000002a40d0 T __ZnwmRKSt9nothrow_t
...
Вы должны строить с -fvisibility=hidden
а затем экспортировать только то, что вы хотите. Прочитайте здесь:
http://gcc.gnu.org/wiki/Visibility
Это также объясняет -fvisibility-inlines-hidden
, Многие большие библиотеки (например, Qt) используют это. Преимущества довольно существенные.
Вы можете взглянуть на символьные карты / версии (опция —version-script ld)