使用MXE交叉编译时如何可靠检测原生Windows构建环境?
我来帮你搞定这个困扰你的问题~你遇到的核心矛盾其实是:MXE交叉编译时,编译器会自动定义_WIN32/_WIN64来标识目标平台是Windows,但这个宏无法区分你是在原生Windows上编译,还是从Linux交叉编译到Windows——而只有原生Windows环境里才真正存在<Windows.h>,所以才会导致编译失败。
下面给你几个实用的解决方案,你可以根据项目情况选:
方案一:用CMake区分主机系统和目标系统
CMake提供了专门的变量来区分「当前编译主机」和「目标编译平台」,这是最靠谱的方式:
CMAKE_HOST_SYSTEM_NAME:代表你正在编译的主机系统(比如你用WSL的话就是Linux,原生Windows就是Windows)CMAKE_SYSTEM_NAME:代表你要编译的目标系统(这里都是Windows)
你可以在项目的CMakeLists.txt里加这段配置:
# 只有在原生Windows主机上编译时,才定义NATIVE_WINDOWS宏 if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") target_compile_definitions(alembic PRIVATE NATIVE_WINDOWS) endif()
然后在代码里把原来的#if defined(_WIN32)改成:
#if defined(NATIVE_WINDOWS) #include <Windows.h> #endif
这样一来,只有当你在原生Windows上编译时,才会包含Windows头文件,交叉编译时就会跳过,完美解决问题。
方案二:直接检查头文件是否存在
另一种更直接的思路——不管主机是什么,只要<Windows.h>真的存在,就包含它;否则就跳过。用CMake的check_include_file模块来实现:
在CMakeLists.txt里添加:
include(CheckIncludeFile) # 检查Windows.h是否存在 check_include_file("Windows.h" HAVE_WINDOWS_H) # 如果存在,就给目标定义HAVE_WINDOWS_H宏 if(HAVE_WINDOWS_H) target_compile_definitions(alembic PRIVATE HAVE_WINDOWS_H) endif()
然后代码里改成:
#if defined(HAVE_WINDOWS_H) #include <Windows.h> #endif
这个方法更鲁棒,哪怕未来MXE的环境配置有变化,只要头文件存在就会正常工作,不存在就自动跳过。
方案三:通过编译器名称判断MXE环境
MXE交叉编译用的编译器会带有目标前缀,比如x86_64-w64-mingw32-gcc,而原生Windows的MinGW编译器一般没有这个前缀(就是gcc.exe)。你可以通过检查编译器名称来区分:
string(FIND "${CMAKE_CXX_COMPILER}" "-w64-mingw32-" MXE_COMPILER_FOUND) # 如果不是MXE编译器,且目标是Windows,就认为是原生环境 if(MXE_COMPILER_FOUND EQUAL -1 AND CMAKE_SYSTEM_NAME STREQUAL "Windows") target_compile_definitions(alembic PRIVATE NATIVE_WINDOWS) endif()
之后代码里的用法和方案一一样就行。
这些方法都能帮你可靠地区分原生Windows构建和MXE交叉编译场景,你可以根据Alembic项目的现有CMake配置选最合适的来集成~
备注:内容来源于stack exchange,提问作者Harry McKenzie

