Mingw64编译静态库测试代码时__debugbreak与__fastfail重复定义问题
我在构建GoogleTest C++测试程序,用来测试一个静态C库,采用静态链接被测库的配置。该配置在Linux下编译链接完全正常,但在Windows的MINGW64 shell中编译时,出现了__debugbreak和__fastfail的多重定义错误——每个C源文件生成的目标文件里都包含了这两个函数的定义。但使用相同的CMake配置在常规PowerShell中编译却无异常。
编译链接错误日志
cd C:/Users/Ilya/work/build/foc_lib/test && C:/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/widget-a0_test.dir/objects.a cd C:/Users/Ilya/work/build/foc_lib/test && C:/msys64/mingw64/bin/ar.exe qc CMakeFiles/widget-a0_test.dir/objects.a @CMakeFiles/widget-a0_test.dir/objects1 cd C:/Users/Ilya/work/build/foc_lib/test && C:/msys64/mingw64/bin/g++.exe -Wall -Wextra -Werror -fno-exceptions -Wno-unknown-pragmas -pedantic -O0 -DNDEBUG -g -Wl,--whole-archive CMakeFiles/widget-a0_test.dir/objects.a -Wl,--no-whole-archive -o widget-a0_test.exe -Wl,--out-implib,libwidget-a0_test.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles/widget-a0_test.dir/linkLibs.rsp C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ../libwidget-a0.a(maths.c.obj): in function `__debugbreak': C:/msys64/mingw64/include/_mingw.h:582: multiple definition of `__debugbreak'; ../libwidget-a0.a(foc.c.obj):C:/msys64/mingw64/include/_mingw.h:582: first defined here C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ../libwidget-a0.a(maths.c.obj): in function `__fastfail': C:/msys64/mingw64/include/_mingw.h:603: multiple definition of `__fastfail'; ../libwidget-a0.a(foc.c.obj):C:/msys64/mingw64/include/_mingw.h:603: first defined here C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ../libwidget-a0.a(svpwm.c.obj): in function `__debugbreak': C:/msys64/mingw64/include/_mingw.h:582: multiple definition of `__debugbreak'; ../libwidget-a0.a(foc.c.obj):C:/msys64/mingw64/include/_mingw.h:582: first defined here C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ../libwidget-a0.a(svpwm.c.obj): in function `__fastfail': C:/msys64/mingw64/include/_mingw.h:603: multiple definition of `__fastfail'; ../libwidget-a0.a(foc.c.obj):C:/msys64/mingw64/include/_mingw.h:603: first defined here collect2.exe: error: ld returned 1 exit status
问题
- 为什么Windows下的编译器会给每个源文件的目标文件都添加这两个函数?
- 有什么有效的方法可以解决这个错误?
环境版本
- gcc.exe (Rev6, Built by MSYS2 project) 12.2.0
- cmake version 3.25.1
解答
问题1:原因分析
这是MINGW头文件的实现特性导致的。在_mingw.h中,__debugbreak和__fastfail是作为静态内联函数的替代实现定义的——当编译器未开启足够优化或不支持某些内联特性时,头文件会直接展开成非内联的函数定义,而非仅声明。
由于你的每个C源文件都包含了该头文件,每个目标文件中都会生成一份这两个函数的定义。当静态链接时,链接器合并所有目标文件的符号,就触发了多重定义冲突。
而PowerShell中编译正常,是因为你在PowerShell中使用的可能是MSVC编译器,或是不同的MINGW环境配置:MSVC的头文件中这两个函数是正确的声明(或通过inline/static修饰避免重复定义);或是PowerShell下的MINGW默认开启了内联优化,编译器会将这些小函数内联到调用处,不会生成独立的全局符号。
问题2:解决方法
以下是几种可靠的解决途径:
开启优化等级强制内联
在CMake中给被测静态库的编译目标添加优化等级(如-O1及以上),编译器会自动内联这些小函数,避免生成重复的全局符号。配置示例:target_compile_options(your_static_lib PRIVATE -O1)也可针对MINGW环境单独设置:
if(MINGW) target_compile_options(your_static_lib PRIVATE -O1) endif()定义宏强制头文件生成内联函数
通过定义__MINGW_INLINE_INLINE宏,让_mingw.h将这两个函数定义为inline,从而避免重复定义。可在CMake中为目标添加编译宏:if(MINGW) target_compile_definitions(your_static_lib PRIVATE __MINGW_INLINE_INLINE) endif()链接器忽略重复定义(临时方案)
给测试程序的链接阶段添加-Wl,--allow-multiple-definition选项,让链接器忽略这些重复的符号。配置示例:if(MINGW) target_link_options(your_test_target PRIVATE -Wl,--allow-multiple-definition) endif()此方法最简单,但可能掩盖其他真正的重复定义问题,优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者ilya1725

