我们已经在多个平台(Linux、Windows、Mac OS X、32位和64位)上构建了一个大型开源software,几年来没有遇到任何问题。然而,最近 Mac OS X 构建(64位)停止正常工作,并开始随机崩溃。这或多或少与我们的构建机器从 10.7 更新到 10.8.2 的 Mac OS X 更新同时发生(但编译器工具链没有改变,仍为 llvm-gcc 4.2.1)。
我们的应用程序由几个动态(共享)库和许多使用它们的可执行文件组成。其中一个共享库重载了
最明智的解决方案似乎是防止超载运算符对共享库的用户可见。这可以通过两种方式实现:使用
在链接共享库时,我们向g++传递了
这些是我们重载并希望隐藏的
以下是CMake生成的命令行,用于链接
我们的应用程序由几个动态(共享)库和许多使用它们的可执行文件组成。其中一个共享库重载了
new
和 delete
运算符,出于各种原因。在 Mac OS X(和 Linux)上,默认情况下导出所有符号,包括我们重载的 new
和 delete
运算符。在 Mac OS X 上的崩溃似乎与一些内存使用了一个内存子系统(不是我们的),然后通过我们自己的(不兼容的)delete
实现释放有关。最明智的解决方案似乎是防止超载运算符对共享库的用户可见。这可以通过两种方式实现:使用
__attribute__((visibility("hidden")))
标记运算符,或使用-unexported_symbols_list
链接器命令行选项来防止某些符号被导出。不幸的是,第一种解决方案不起作用:gcc发出警告,说运算符已经以不同的方式(在<new>
中)声明,因此属性将被忽略。从我在各个地方的阅读中得知,第二种解决方案似乎是解决这个问题的正确方法。但出于某种原因,我们无法使其工作。在链接共享库时,我们向g++传递了
-Wl,-unexported_symbols_list unexported_symbols_list.txt
选项,然后应该将其传递给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 [...]
很不幸,尽管我们付出了所有的努力,但符号仍然存在(如nm所示)。
我们做错了什么?有没有其他的方法可以尝试?
更新于2012年12月19日:
我们的问题以及所谓的解决方案在苹果公司的技术说明中得到了很好的涵盖:http://developer.apple.com/library/mac/#technotes/tn2185/_index.html(“覆盖new/delete”部分)。
相关源代码指针:
operator new
和operator delete
覆盖:allocator.cpp- 用于控制共享库符号可见性的宏:dllvisibility.h
-fvisibility=hidden
编译构建libappleseed.dylib
并运行strip -x libappleseed.dylib
后,nm
输出的片段如下:...
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
...
-unexported_symbols_list
与文件名之间有一个逗号分隔 - 这不会导致错误吗? - Dan Nissenbaum