Мне нужно построить приложение с 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_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)
Вопрос: Почему обработка исключений не работает с 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] повышение (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), в 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), в 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(../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.
Редактировать: поскольку библиотека, на которую ссылаются, специально повышена, этот вопрос может быть полезным Подводя итог, можно сказать, что некоторые компоненты 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 использует g ++ ABI и версию библиотеки времени выполнения g ++
поставляется с Oracle Solaris Studio. Для этого выпуска версия
4.8.2 из библиотеки времени выполнения g ++.
(ссылка)