2017-10-11 98 views
2

我正在將一個項目從MSVC移植到mingw。該項目包含C和C++。然而,每當拋出一個異常,而不是被捕獲,std :: terminate被調用,應用程序崩潰。我不明白爲什麼如此任何意見將不勝感激。混合C和C++導致異常終止

我的工具鏈是安裝在Windows中的MSYS2環境中的cmake/ninja/mingw32。

MCVE:

# CMakeLists.txt 
cmake_minimum_required(VERSION 3.6) 
project(FailedExceptions) 
add_executable(FailedExceptions c_funcs.c main.cpp) 

//main.cpp 
#include <iostream> 
#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/xml_parser.hpp> 

int main() { 
    try { 
     boost::property_tree::ptree pt; 
     std::printf("reading file\n"); 
     boost::property_tree::read_xml("nonexistant-file", pt); 
     std::printf("provider file read\n"); 
    } catch (...) { 
     std::printf("Exception caught\n"); 
    } 
    return 0; 
} 

// c_funcs.c 
int SomeCFunction() 
{ 
    return 0; 
} 

輸出
$ cmake .. -GNinja 
-- The C compiler identification is GNU 7.2.0 
-- The CXX compiler identification is GNU 7.2.0 
-- Check for working C compiler: C:/msys64/mingw32/bin/cc.exe -- works 
-- Check for working CXX compiler: C:/msys64/mingw32/bin/c++.exe -- works 
-- Configuring done 
-- Generating done 
-- Build files have been written to: C:/msys64/home/sferguson/src/vis/build 

$ ninja -v 
[1/3] C:\msys64\mingw32\bin\cc.exe -MD -MT c_funcs.c.obj -MF c_funcs.c.obj.d -o c_funcs.c.obj -c ../c_funcs.c 
[2/3] C:\msys64\mingw32\bin\c++.exe -MD -MT main.cpp.obj -MF main.cpp.obj.d -o main.cpp.obj -c ../main.cpp 
[3/3] C:\msys64\mingw32\bin\c++.exe c_funcs.c.obj main.cpp.obj -o FailedExceptions.exe -Wl,--major-image-version,0,--minor-image-version,0 -lgcc_eh -lgcc_eh -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 

$ ./FailedExceptions.exe 
reading file 

This application has requested the Runtime to terminate it in an unusual way. 
Please contact the application's support team for more information. 
$ 

跟蹤:

我可以從Dr. Mingw那裏得到這個痕跡。它確實確實出現了崩潰發生在異常構建和實際投擲之間。

[email protected] 
[email protected] 
[email protected] 
msvcrt.dll!___crtExitProcess 
msvcrt.dll!__cinit 
msvcrt.dll!__exit 
msvcrt.dll!_abort 
FailedExceptions.exe!uw_init_context_1 
FailedExceptions.exe!boost::property_tree::xml_parser::xml_parser_error::xml_parser_error 
FailedExceptions.exe!boost::property_tree::xml_parser::read_xml<boost::property_tree::basic_ptree<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > 
FailedExceptions.exe!main 
FailedExceptions.exe!__tmainCRTStartup [D:/develop/scripts/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c @ 334] 
[email protected]@12 
[email protected] 
[email protected] 

故障排除:

  • 我發現一些帖子來自5-10年前這表明這可能是MinGW的的DW2和sjlj庫之間有衝突,但我只安裝了libgcc_s_dw2-1.dll二進制文件,其配備msys pacman存儲庫中的mingw-w64-i686-gcc-libs軟件包。
  • 我試着改變我的CMakeLists.txt文件來編譯一切與C++ project(FailedExceptions LANGUAGES CXX)。這可以防止cmake建立我的C文件。所以它對MCVE有效,但是我的完整項目缺少所有的C內容。
  • 我已經加了set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -fexceptions)但它似乎沒有效果。我已用ninja -v確認此標誌已添加到C文件編譯命令中。
  • 一旦我從構建中刪除C文件,一切正常。但即使我沒有在這個MCVE中使用C文件,我仍然在我的大項目中使用它。
  • 我發現了另一個更小的例子here。我可以重現那個問題IFF我也在同一個項目中編譯一個C文件。
+0

哪裏是'INT SomeCFunction()'叫什麼名字? – YSC

+1

是'boost :: property_tree :: read_xml'沒有將流作爲參數而不是字符串? – user463035818

+1

@YSC int SomeCFunction()不會在任何地方調用。它是簡單的鏈接。這是這裏的一個奇怪的細節。我不需要調用SomeCFunction()來銷燬main.cpp中的異常。我只需要鏈接到它。 – Stewart

回答

1

這是一個feature(bug?) cmake隱式庫檢測引入cmake 3.1。 CMake認爲在C模式下GCC需要鏈接gcc_eh,這會打破C++異常處理。

您可以通過將其添加到CMakeLists來禁用隱式庫檢測。TXT:

set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "") 

(不知道如何做到這gcc_eh從列表中排除)

+0

事實證明,當我使用這個命令時,'gcc_eh'是唯一被排除的庫。其他的都包含在CXX鏈路中,所以這個解決方案是完美的。 – Stewart

0

RustyX的答案是公認的,但我也發現了變通的另一個號碼,似乎工作:

  • set_source_files_properties(filename.c PROPERTIES LANGUAGE CXX)
  • set(CMAKE_C_COMPILER /path/to/cpp/compiler)
  • set(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS c)

但RustyX的是最好的答案爲止。

編輯:最後一個不工作。它仍然使用C編譯器構建。我還需要從CMAKE_C_SOURCE_FILE_EXTENSIONS中刪除c