连接gcc libs的Sun Studio:异常不起作用

Beg*_*ner 5 c++ gcc solaris sunstudio

我需要使用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)
Run Code Online (Sandbox Code Playgroud)

结果:抛出异常后会发生分段违规(请参阅下面的代码).

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)

问题:为什么exeption处理不能与Sun Studio一起使用?


如果我像这样强制执行gcc运行时:

LD_PRELOAD=/usr/sfw/lib/amd64/libgcc_s.so ./example
Run Code Online (Sandbox Code Playgroud)

它崩溃的方式不同:

$>在抛出一个'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]上升(0x0,0x0) ,0x0,0x0,0x0,0x0),位于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 :: terminate(0x0,0x0,0x0,0x0,0x0,0x0),at 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 :: terminate(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),a t 0xffff80ffb9991116 => [14] main(argc = 1,argv = 0xffff80ffbffffa78),"exampleMain.cpp"中的第6行


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

exampleMain.cpp:

#include <clayer.h> 
#include <stdio.h>

int main(int argc, char **argv)
{
    if (!clayerCall())
        printf("got exception\n");
    else
        printf("OK\n");
}
Run Code Online (Sandbox Code Playgroud)

共享lib头:

extern "C" {

bool clayerCall();

} // end extern "C" 
Run Code Online (Sandbox Code Playgroud)

共享lib源:

#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
Run Code Online (Sandbox Code Playgroud)

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
)
Run Code Online (Sandbox Code Playgroud)

为图书馆

project(clayer)
cmake_minimum_required(VERSION 2.8)
cmake_policy(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)

add_library(
    clayer SHARED
    clayer.cpp
)
Run Code Online (Sandbox Code Playgroud)

ant*_*oft 7

异常处理需要库和链接器支持,这些支持在Sun Studio C++工具链和Gnu C++之间有所不同(这样就像名称修改一样,您已经注意到两个工具链之间存在差异).使用"C"链接对您没有帮助,因为您链接的函数的实现依赖于该异常处理工具.您通常不能使用在同一可执行文件中使用两个不同工具链构建的C++代码.

如果您必须使用Sun Studio,因为您使用的是仅与Sun Studio兼容的闭源库,那么最简单的方法可能是使用"仅使用GNU C++构建"的库来构建Sun C++编译器,假设该库是开源的.这可能不是微不足道的,您可能需要得到图书馆作者的支持.当我不得不通过编写看起来像GNU C++命令的小脚本来调用带有正确标志的Sun编译器时,我就完成了这个.

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

编辑:由于链接到的库是特别提升的,这个问题可能会有所帮助.总之,一些boost可能会与您的Sun编译器版本一起构建.


Beg*_*ner 5

如果未禁用异常,则无法将使用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和Oracle Solaris Studio随附的g ++运行时库版本.对于此版本,使用了g ++运行时库的4.8.2版.(参考)