今天帮一位朋友写了一个控制台性能工具,用 CMake 编译出来后将源码和 Makefile 文件发给他,结果他说他是 Windows 电脑——无法运行…

他请求我帮忙编译成 Windows 系统可用的可执行文件(.exe)。因为我的开发环境一直在 macOS 上,以前也只在 macOS 嵌入式设备间做过交叉编译,确实没有编译过 Windows 程序。由于 Windows 系统使用的库文件与 macOS 上的库文件格式和接口不同。在交叉编译时,需要确保为目标 Windows 平台提供正确的库文件。正好借此机会学习了一下,并在此记录。

配置交叉编译环境

1.首先确保 CMake 已安装(可通过 cmake --version 检查)安装 MinGW-w64 工具链,用于生成 Windows 可执行文件:

install

1
brew install mingw-w64

2.配置 CMakeLists.txt​

在项目根目录的 CMakeLists.txt 中,指定交叉编译工具链和目标平台。

1
2
3
cmake_minimum_required(VERSION 3.50)
project(MyWindowsApp)
add_executable(MyWindowsApp ${ROOT} ${SRCDIR})

这里基本上就是你在 macOS 上编译所需要的 CMakeLists.txt 文件内容。

3.设置工具链文件​

创建一个工具链文件(如mingw_toolchain.cmake),这个文件创建在 CMakeLists.txt 的同级目录。

1
2
3
4
5
6
7
8
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

其中 3-5 行也可以用绝对路径代替

1
2
3
# set(CMAKE_C_COMPILER /opt/homebrew/bin/x86_64-w64-mingw32-gcc)
# set(CMAKE_CXX_COMPILER /opt/homebrew/bin/x86_64-w64-mingw32-g++)
# set(CMAKE_RC_COMPILER /opt/homebrew/bin/x86_64-w64-mingw32-windres)

4.​生成构建文件​

在项目根目录中下运行,这里要确保已经完成了第 3 步,mingw_toolchain.cmake 文件存在。

1
2
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../mingw_toolchain.cmake ..

5.编译

1
make

确保代码和依赖库兼容 Windows 平台,生成的.exe文件将位于 build 目录中。若需 32 位文件,将工具链中的编译器替换为 i686-w64-mingw32-gcc 和 i686-w64-mingw32-g++。

6.检查

1
2
3
4
5
# 检查文件格式(应显示PE32+ executable)
file build/MyWindowsApp.exe

# 使用wine测试运行(可选)
wine build/MyWindowsApp.exe

其他

由于在 Windows 上使用 GBK 编码,macOS 用 UTF8,Windows 可能会出现中文乱码,可以在 CMakeLists.txt 中设置编译器字符集选项。

1
2
3
# 设置编译器字符集选项(适用于GCC/MinGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finput-charset=UTF-8 -fexec-charset=GBK")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -finput-charset=UTF-8 -fexec-charset=GBK")