Sun Studio, связывающая библиотеки gcc: исключения не работают
Мне нужно построить приложение с Sun Studio. Это приложение использует общую библиотеку, которую можно собрать только с помощью Gnu C++. Разделяемая библиотека имеет интерфейс C, так что код может вызываться компилятором Sun (чтобы избежать проблем с искажением имен, см. Также этот вопрос).
Все, кроме обработки исключений работает нормально. Когда исключение выдается в общей библиотеке, программа segfaults. Это происходит только тогда, когда основная программа компилируется с использованием Sun Studio Compiler. Скомпилировав минимальный приведенный ниже пример с помощью компилятора 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)
Результат: нарушение сегментации при возникновении исключения (см. Код ниже).
План Б: ссылка статически
как указано выше, но сборка 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_cface libcIn.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_inter. cpp.o)
Вопрос: Почему обработка исключений не работает с Sun Studio?
Если я приведу в исполнение gcc, как это:
LD_PRELOAD=/usr/sfw/lib/amd64/libgcc_s.so ./example
он падает по-разному:
$> terminate вызывается после создания экземпляра 'std::runtime_error' $> terminate вызывается рекурсивно
(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_000x0x0_0 0 0 0 0 0x0), в 0xffff80ffbd9de911 [6] __cxxabiv1::__ прекращается (0x0, 0x0, 0x0, 0x0, 0x0, 0x0), в 0xffff80ffbd9dbd5b [7] std::terminate(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) 0xffff80ffbd9dbda3 [8] __cxa_rethrow(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), в 0xffff80ffbd9dc02d [9] __gnu_cxx::__verbose_terminate_handler(0x0, 0x0x0x0x0x0x0x0x0: 00 0x0: 00 0x0: 00 0x0: 0x0 0x0: 00 __terminate(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), в 0xffff80ffbd9dbd5b [11] std::terminate(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), в 0xffff80ffbd9dbda3 0x0 00 0 0 0 0 0 0 0 (0) 0 [0] 0 [0] 0 [0] 0 [0] 0 [000] 0 [0] 0 [0] 0 [0] 0, 0x0, 0x0, 0x0), в 0xffff80ffbd9dbfd6 [13] clayerCall(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0xffff80ffb9991116 =>[14] main(argc = 1, argv = 0xffff80ffbffffa78), строка 6 в "exampleMain.cpp"
Вот минимальный пример для воспроизведения проблемы:
exampleMain.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"
общий источник 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
Файлы cmake выглядят так:
для исполняемого файла
project(exampleMain)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)
add_definitions(-m64 -fPIC)
include_directories(../stackru)
link_directories (
../stackru
)
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
)
2 ответа
Для обработки исключений требуется поддержка библиотек и компоновщиков, которые различаются в цепочке инструментов Sun Studio C++ и в Gnu C++ (таким образом, это похоже на искажение имен, которое, как вы уже заметили, отличается в двух цепочках инструментов). Использование связи "C" здесь вам не поможет, потому что реализации функций, которые вы связываете, зависят от этого средства обработки исключений. В общем случае вы не можете использовать код C++, построенный с двумя различными цепочками инструментов в одном исполняемом файле.
Если вам нужно использовать Sun Studio, потому что вы используете библиотеки с закрытым исходным кодом, которые совместимы только с Sun Studio, ваш самый простой путь вперед - это, вероятно, получить библиотеку, которая "собирается только с GNU C++", для сборки с помощью компилятора Sun C++, предполагая что эта библиотека с открытым исходным кодом. Это может быть не тривиально, и вам может потребоваться поддержка авторов библиотеки. Я сделал это, когда мне пришлось написать небольшие скрипты, похожие на команды GNU C++, которые вызывают компилятор Sun с правильными флагами.
Если об этом не может быть и речи, вам, возможно, придется обернуть библиотеку, которую вы пытаетесь использовать в службе, и использовать какой-либо механизм RPC для доступа к ней из скомпилированного кода Sun Studio.
Изменить: Поскольку библиотека, на которую ссылаются, является специально продвинутой, этот вопрос может быть полезным. Подводя итог, можно сказать, что некоторые компоненты boost могут быть собраны с вашей версией компилятора Sun.
Невозможно загрузить разделяемую библиотеку, созданную с помощью gcc, в исполняемый файл, созданный с помощью Solaris Studio 12.3., Если исключения не отключены.
Проблема в том, что исключения не являются частью C ABI. Среда выполнения Solaris Studio и среда gcc используют разные реализации вызовов _Unwind:
В gcc (в частности, в libstdC++) используются дополнительные нестандартные вызовы _Unwind, которые, естественно, отсутствуют в Solaris libc, детали реализации реализации Unwind в libc отличаются от деталей libgccs, поэтому, когда все стандартные процедуры _Unwind разрешаются в версии Solaris и одна нестандартная процедура _Unwind преобразуется в версию gcc, и вы получаете проблему (скорее всего, именно это и происходит с вами) ( дополнительную информацию см. здесь)
Невозможно выполнить один процесс с разными средами выполнения C++ для частей, созданных с помощью Solaris Studio и части gcc. Поэтому загрузка совместно используемой библиотеки, созданной с помощью gcc, в исполняемый файл, созданный с помощью Solaris Studio, невозможна.
Хорошей новостью является то, что начиная с версии Solaris Studio 12.4, если вы включите поддержку C++11, она может действительно работать:
В Oracle Solaris Studio 12.4 компилятор C++ поддерживает новый язык C++ 11 и ABI (двоичный интерфейс приложения). В режиме C++ 11 компилятор CC использует ABI g ++ и версию библиотеки времени выполнения g ++, которая поставляется вместе с Oracle Solaris Studio. В этом выпуске используется версия 4.8.2 библиотеки времени выполнения g ++. ( ссылка)