混合C和C ++导致异常终止

时间:2017-10-11 12:25:52

标签: c++ c cmake mingw

我正在将一个项目从MSVC移植到mingw。该项目包含C和C ++。但是,每当抛出异常而不是被捕获时,都会调用std :: terminate并且应用程序崩溃。我不明白为什么这样的建议会受到赞赏。

我的工具链是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.
$

跟踪:

我可以从Mingw博士那里得到这个痕迹。确实看起来崩溃发生在异常构造和实际抛出之间。

ntdll.dll!_NtTerminateProcess@8
ntdll.dll!_RtlExitUserProcess@4
kernel32.dll!_ExitProcessStub@4
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]
kernel32.dll!@BaseThreadInitThunk@12
ntdll.dll!___RtlUserThreadStart@8
ntdll.dll!__RtlUserThreadStart@8

故障排除:

  • 我发现5到10年前的一些帖子暗示这可能是mingw的dw2和sjlj库之间的冲突,但我只安装了libgcc_s_dw2-1.dll二进制文件,它们带有mingw-w64-i686-gcc msys pacman存储库中的-libs包。
  • 我尝试更改我的CMakeLists.txt文件,用C {+ {1}}编译所有内容。这可以防止cmake构建我的C文件。所以它确实适用于MCVE,但我的完整项目缺少所有C内容。
  • 我添加了project(FailedExceptions LANGUAGES CXX),但似乎没有效果。我已经通过set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -fexceptions)确认此标志已添加到C文件编译命令中。
  • 一旦从构建中删除C文件,一切正常。但即使我没有在这个MCVE中使用C文件,我仍然在我的大项目中使用它。
  • 我找到了另一个较小的例子here。我可以重现那个问题IFF我也在同一个项目中编译了一个C文件。

3 个答案:

答案 0 :(得分:1)

这是cmake feature(bug?)中引入的cmake隐式库检测中的3.1。 CMake认为在C模式下,GCC需要链接gcc_eh,这会打破C ++异常处理。

您可以通过将此添加到CMakeLists.txt来禁用隐式库检测:

set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "")

(不知道如何从列表中排除gcc_eh

答案 1 :(得分: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编译器构建。我还需要从c删除CMAKE_C_SOURCE_FILE_EXTENSIONS

答案 2 :(得分:0)

要添加上面的rustyx答案(我不允许发表评论),根据此拉取请求在cmake 3.10中修复此问题:https://gitlab.kitware.com/cmake/cmake/merge_requests/1460

我使用CMake 3.10.2进行了测试,现在似乎异常工作,而无需指定rustx提到的解决方法cmake节。