使用SFML与C++20模块时GCC编译出现ODR违反错误的解决求助
我正在尝试用SFML和C++20模块搭建一个跨编译器项目,需要同时兼容MSVC和GCC 14.2。目前我梳理的现状(如果有错误欢迎指正):
- SFML官方暂未支持模块(不过有一个活跃的PR在推进相关支持,GCC存在例外兼容情况)
- GCC目前不支持头单元
所以我想了个折中方案:项目内部完全采用模块开发,通过全局模块片段引入SFML和标准库的内容(后续如果编译速度变慢再考虑预编译头优化)。
但搭建好项目后,在使用依赖std::string的SFML类sf::Font时,GCC编译直接抛出了ODR(单定义规则)违反错误。其中一个典型的错误日志如下:
[build] C:/.../bin/ld.exe: CMakeFiles/.../src/Game.cpp.obj: in function
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Alloc_hider::~_Alloc_hider()': [build] C:/.../lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/bits/basic_string.h:186: multiple definition ofstd::__cxx11::basic_string<char, std::char_traits, std::allocator >::_Alloc_hider::~_Alloc_hider()'; CMakeFiles/.../src/main.cpp.obj:C:/.../lib/gcc/x86_64-w64-mingw32/14.2.0/include/c++/bits/basic_string.h:186: first defined here
我把问题简化成了最小复现代码:
main.cpp
import Game; int main() { Game game; game.run(); }
Game.ixx
module; #include <SFML/Graphics.hpp> export module Game; export class Game { public: Game(); void run(); private: sf::RenderWindow m_window; sf::Font m_font; };
Game.cpp
module; #include <SFML/Graphics.hpp> module Game; Game::Game() : m_window(sf::VideoMode({1920u, 1080u}), "My Game"), m_font("Sansation.tff") { } void Game::run() { }
注:我保留了sf::RenderWindow成员,因为它并没有引发类似的错误。
我的CMakeLists.txt配置如下:
set(CMAKE_CXX_STANDARD 20) project(MyGame LANGUAGES CXX) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(FETCHCONTENT_FULLY_DISCONNECTED ON) include(FetchContent) FetchContent_Declare(SFML GIT_REPOSITORY https://github.com/SFML/SFML.git GIT_TAG 3.0.1 GIT_SHALLOW ON EXCLUDE_FROM_ALL SYSTEM) FetchContent_MakeAvailable(SFML) file(GLOB_RECURSE MODULE_INTERFACE_FILES CONFIGURE_DEPENDS "src/*.ixx") file(GLOB_RECURSE MODULE_IMPLEMENTATION_FILES CONFIGURE_DEPENDS "src/*.cpp") add_executable(${PROJECT_NAME}) target_sources(${PROJECT_NAME} PUBLIC src/main.cpp) target_sources(${PROJECT_NAME} PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES FILES ${MODULE_INTERFACE_FILES} PRIVATE ${MODULE_IMPLEMENTATION_FILES} ) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) target_link_libraries(${PROJECT_NAME} PRIVATE SFML::Graphics)
我现在完全摸不着头脑——从错误信息看,像是std::string这类标准库类的析构函数被重复定义了,但这看起来完全不符合常理。我猜测可能是模块上下文里的头文件包含守卫机制出了问题?但如果不在模块接口单元和实现单元中都引入SFML头文件,项目连基础编译都无法通过。
有没有大佬能帮忙分析下问题根源,或者给出可行的解决思路?
内容来源于stack exchange

