我需要使用 Sun Studio 构建一个应用程序。此应用程序使用只能使用 Gnu C++ 构建的共享库。共享库有一个 C 接口,因此代码可由 Sun 编译器调用(这是为了避免名称混淆问题,另请参阅此问题)。
除了异常处理之外的一切都很好。当共享库中抛出异常时,程序会出现段错误。仅当使用 Sun Studio 编译器编译主程序时才会发生这种情况。使用 Gnu C++ 编译器编译下面的最小示例,程序运行良好,共享库检测到异常。
计划 A:动态链接以下是设置说明:
GCC SOLARIS STUDIO
shared
c_layer.so <----- application
(no exceptions) (uses exceptions sol studio)
|
| use flag -static -static-libstdc++ -static-lib-gcc
v
gcc_only_lib.so
libstdc++.so
(uses gcc exceptions)
结果:一旦抛出异常,就会违反分段(参见下面的代码)。
方案 B:静态链接
如上,但构建 c_layer.a
结果:
文件中未定义的第一个引用符号
__cxa_allocate_exception libs/cInterface/libcInterface.a(c_layer.cpp.o) std::string::~std::basic_string () libs/cInterface/libcInterface.a(c_layer.cpp.o) __cxa_end_catch libs /cInterface/libcInterface.a(c_layer.cpp.o) __cxa_free_exception libs/cInterface/libcInterface.a(c_layer.cpp.o) __cxa_begin_catch libs/cInterface/libcInterface.a(c_layer.cpp.o) __cxa_throw libs/cInterface/libcInterface。一个(c_layer.cpp.o)
问题:为什么异常处理不适用于 Sun Studio?
如果我像这样强制执行 gcc 运行时:
LD_PRELOAD=/usr/sfw/lib/amd64/libgcc_s.so ./example
它以不同的方式崩溃:
$> 在抛出 'std::runtime_error' 的实例后调用终止 $> 递归调用终止
(dbx) 其中 1__lwp_sigqueue(0x1, 0x6, 0xffffc1000bae5060, 0xffffffff, 0x0, 0xffff80ffbffff810), at 0xffff80ffbf51e70a [2] thr_kill(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0xffff80ffbf512ec8 [3] raise(0x0, 0x0, 0x0, 0x0, 0x0,0x0),在0xffff80ffbf4c291d [4] abort(0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0),at 0xffffffffffffffbf497ff2 [5] [6] __cxxabiv1::__terminate(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), 在 0xffff80ffbd9dbd5b [7] std::terminate(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), 在 0xffff80ffbd9dbda3 [8] __cx_areth (0x0, 0x0, 0x0, 0x0, 0x0, 0x0), 在 0xffff80ffbd9dc02d [9] __gnu_cxx::__verbose_terminate_handler(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), 在 0xffff80ffbd9de8d4 [10] __x0,0x1: 终止, 0x0, 0x0, 0x0, 0x0), 在 0xffff80ffbd9dbd5b [11] std::terminate(0x0,0x0, 0x0, 0x0, 0x0, 0x0), at 0xffff80ffbd9dbda3 [12] __cxa_throw(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0xffff80ffbd9dbfd6 [13] ClayerCall(0x0, 0x00, 0x0, 0x)0, , 在 0xffff80ffb9991116 =>[14] main(argc = 1, argv = 0xffff80ffbffffa78), "exampleMain.cpp" 中的第 6 行
这是重现问题的最小示例:
示例Main.cpp:
#include <clayer.h>
#include <stdio.h>
int main(int argc, char **argv)
{
if (!clayerCall())
printf("got exception\n");
else
printf("OK\n");
}
共享库头:
extern "C" {
bool clayerCall();
} // end extern "C"
共享库源:
#include "clayer.h"
#include <exception>
#include <stdexcept>
#include <stdio.h>
extern "C" {
bool clayerCall()
{
try
{
throw std::runtime_error("hhh");
return true;
}
catch (std::exception &ex)
{
return false;
}
}
} // end extern c
cmake 文件如下所示:
对于可执行文件
project(exampleMain)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)
add_definitions(-m64 -fPIC)
include_directories(../stackoverflow)
link_directories (
../stackoverflow
)
add_executable(example exampleMain.cpp)
target_link_libraries(
example
stdc++
clayer
)
为图书馆
project(clayer)
cmake_minimum_required(VERSION 2.8)
cmake_policy(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)
add_library(
clayer SHARED
clayer.cpp
)