Sun Studio 链接 gcc 库:例外不起作用



我需要用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.a(c_layer.cpp.o(

为什么 Exeption 处理不适用于 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(, 在 0xffff80ffbf51e70a [2] thr_kill(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbf512ec8 [3] raise(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, at 0xffff80ffbf4c291d [4] 中止(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbf497ff2 [5] __gnu_cxx::__verbose_terminate_handler(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9de911 [6] __cxxabiv1::__terminate(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9dbd5b [7] std::终止(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9dbda3 [8] __cxa_rethrow(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9dc02d [9] __gnu_cxx::__verbose_terminate_handler(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9de8d4 [10] __cxxabiv1::__terminate(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9dbd5b [11] std::终止(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9dbda3 [12] __cxa_throw(0x0, 0x0, 0x0, 0x0, 0x0, 0x0(, 在 0xffff80ffbd9dbfd6 [13] clayerCall(0x0, 0x0,0x0,0x0,0x0,0x0(,在0xffff80ffb9991116 =>[14] main(argc = 1, argv = 0xffff80ffbffffa78(, "exampleMain.cpp" 中的第 6 行


下面是重现该问题的最小示例:

示例主.cpp:

#include <clayer.h> 
#include <stdio.h>
int main(int argc, char **argv)
{
    if (!clayerCall())
        printf("got exceptionn");
    else
        printf("OKn");
}

共享库标头:

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
)
异常

处理需要库和链接器支持,这在 Sun Studio C++ 工具链和 Gnu C++ 之间有所不同(通过这种方式,它就像名称重整,您已经注意到两个工具链之间的区别(。 在这里使用"C"链接对您没有帮助,因为您要链接到的函数的实现取决于该异常处理工具。 通常不能使用C++同一可执行文件中通过两个不同的工具链生成的代码。

如果您因为使用的是仅与 Sun Studio 兼容的闭源库而必须使用 Sun Studio,那么最简单的方法可能是获取"仅使用 GNU C++ 构建"的库,以使用 Sun C++编译器构建,假设该库是开源的。 这可能不是微不足道的,您可能需要获得图书馆作者的支持。 当我不得不编写看起来像 GNU 的小脚本时,我已经这样做了C++命令,这些命令使用正确的标志调用 Sun 编译器。

如果这是不可能的,您可能必须将尝试使用的库包装在服务中,并使用某种 RPC 机制从 Sun Studio 编译的代码访问它。

编辑:由于链接到的库是专门增强的,因此这个问题可能会有所帮助。 总之,一些提升可能会使用您的 Sun 编译器版本构建。

如果未禁用例外,则无法将使用 gcc 构建的共享库加载到使用 solaris studio 12.3 构建的可执行文件中。

问题是例外不是 C ABI 的一部分。Solaris Studio 运行时和 gcc 运行时使用不同的_Unwind调用实现:

gcc(特别是libstdc++(碰巧使用了Solaris libc中不存在的其他非标准_Unwind调用,自然,libc中Unwind实现的实现细节与 libgccs 的,所以当所有标准_Unwind例程都是 解析为 Solaris 版本,一个非标准_Unwind例程是 解决到 GCC 版本,您会遇到问题(很可能就是这样 发生在你身上( (更多信息请看这里(

不可能执行一个进程,该

进程对使用 solaris studio 和 gcc 部件构建的部件执行不同的C++运行时。因此,无法使用使用 gcc 构建的共享库加载到使用 Solaris Studio 构建的可执行文件中。


好消息是,从 solaris studio 12.4 开始,如果打开 C++11 支持,它实际上可能会起作用:

在Oracle Solaris Studio 12.4中,C++编译器支持C++11,这是一个新的 语言和 ABI(应用程序二进制接口(。在 C++ 11 模式下, CC 编译器使用 g++ ABI 和 g++ 运行时库的一个版本 随 Oracle Solaris Studio 提供。对于此版本,版本 使用 G++ 运行时库的 4.8.2。 (参考资料(

相关内容

最新更新