2017-02-10 5 views
0

Я пишу Windows DLL на C++. Эта библиотека имеет только интерфейс C и использует только стандартные библиотеки Windows, которые также имеют интерфейс C. Поэтому представляется мне безопасным статически связывать все библиотеки C++ с библиотекой, потому что я не зависим от версии C++ ABI при использовании только C-интерфейсов.Статическая ссылка libgcc на Windows DLL

К сожалению, когда я скомпилирую свою библиотеку с помощью -static-stdc++ -static-libgcc, моя библиотека перестает обрабатывать исключения и когда генерируется какое-то исключение, DLL вызывает свою статически связанную функцию _Unwind_RaiseException, которая прерывает все приложение.

Я думал, что это может быть поврежден libgtcc.a, поэтому я попытался обновить свой компилятор. Но результат одинаковый с MinGW 4.8 и MinGW 6.3.

Пожалуйста, кто-нибудь может объяснить мне, что на самом деле происходит здесь?

Klasyc

+2

Использование TDM-GCC. См. Краткое описание [здесь] (http://tdm-gcc.tdragon.net/quirks) – Ripi2

+0

Или MinGW, который поддерживает SEH. – rustyx

+0

@RustyX OP попробовал MinGW, который, как вы говорите, поддерживает SEH, но не если библиотеки статически связаны, а исключение выбрано через границу DLL. Это один из вопросов, который адресует TDM-GCC. MinGW отлично работает, если библиотеки времени выполнения динамически связаны (т. Е. В процессе есть только одна версия). –

ответ

0

Вы обрабатывать все исключения внутри DLL? Если какое-либо исключение «утечки» вне функции с соглашением о вызове C  , оно приведет к сбою приложения.

Я не имею никаких проблем с исключениями C++ под MinGW x86_64-5.3.0-win32-SEH-rt_v4-rev0 и mingw32 4.8.1 dwarf2 с статическим libstdC++/libgcc.

источник DLL (dll.cpp):

#include <windows.h> 
#include <exception> 
#include <iostream> 

extern "C" { 
__declspec(dllexport) int __stdcall test() { 
    try { 
     new int[-1]; 
     return 123; 
    } catch (const std::exception& ex) { 
     std::cerr << "Exception:" << ex.what() << std::endl; 
     return 456; 
    } 
} 
} 

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD  fdwReason, LPVOID lpvReserved) 
{ 
    return TRUE; 
} 

источник Применение (app.c):

#include <stdio.h> 

#ifdef __cplusplus 
extern "C" 
#endif 
__declspec(dllimport) int __stdcall test(); 

int main() { 
    printf("result: %d\n", test()); 
    return 0; 
} 

Собирать:

g++ -O2 -static-libgcc -static-libstdc++ -shared -Wl,--out-implib=dtest.lib -s -o dtest.dll dll.cpp

g++ -O2 -static-libgcc -static-libstdc++ -L. -s -o app app.c -ldtest

Выход:

Exception:std::bad_alloc 
result: 456 

Чтобы ответить на ваш комментарий "Зачем мне нужен компилятор с поддержкой SEH? Я думал, что SEH позволяет мне перехватывать исключения Windows »- в Windows SEH является де-факто стандартом для всех исключений, включая исключения C++ (при компиляции с Visual C++). MinGW имеет разные реализации для исключений C++ (SEH, SJLJ и DWARF), однако SEH является единственным механизмом с нулевыми накладными расходами, поэтому, если он доступен, вам действительно нужно предпочесть его для SJLJ и DWARF.

+0

Благодарим вас за пример. Когда я пытаюсь скомпилировать его, как и вы, он действительно работает. Но когда я пытаюсь скомпилировать 'app.c' с g ++ (мне нужно добавить' extern 'C '' в заголовок 'test()'), приложение сработает. Таким образом, кажется, что использование двух копий статического libgcc делает проблему. Обратите внимание, что я использую исключения DWARF-2, так как я должен производить 32-битный двоичный файл. – klasyc

+0

У меня нет этой проблемы. См. Мой обновленный ответ. – rustyx

+0

Извините за отложенный ответ. Попробуйте выполнить сборку DLL с помощью '-static-libgcc' и приложения без этого коммутатора. Сочетание статической DLL и динамического приложения, похоже, нарушает все. – klasyc

0

Спасибо RastyX за этот простой пример в его ответе. После некоторых исследований я узнал, что когда я компилирую DLL-часть с -static-libgcc и частью приложения без этого переключателя (обе части скомпилированы с тем же g ++).

Также благодаря Ripi2 для предложения TDM-GCC estion. Я пробовал обработку исключений SJLJ и DWARF-2, и оба они работают.

В заключение этого кажется, что libgcc MinGW не нравится, когда он создается более одного раза за процесс.В моем случае я использую одну ее копию в DLL (связанный статически) и одну ее копию в приложении, и это, вероятно, нарушает обработку исключений.

С другой стороны, TDM-GCC фокусируется на статической привязке базовых библиотек, поскольку его веб-страница говорит и, следовательно, создает двоичные файлы, которые зависят только от библиотек Windows, даже без переключателей командной строки -static-stdc++ -static-libgcc (это то, что я хочу). Также здесь работает обработка исключений, поэтому изменение инструментальной привязки - правильный путь для меня.

Смежные вопросы