---
title: \[Day 28\] Cross Compile Windows Binaries
tags: ithome, ithome2023, cmake
---
[TOC]
明天改講 staging 好了...還要安裝感覺有點多
[Day 28] Cross Compile Windows Binaries
# 本日內容
* Build Windows Toolchain
* 來寫 CMake Toolchain File 吧
* Hello World!
* Prepare Staging
* Cross Compile!
* 預告
[Day 28 - Colab](https://colab.research.google.com/drive/1it-UckVjDFQl9jwDWzaMZl-o2sYSZjW1?usp=sharing)
今天會用到 [Day 27](https://ithelp.ithome.com.tw/articles/10329511) 介紹的內容
在 Linux 將 MinGW-w64 toolchain build 出來並 cross compile Windows 版本的可執行檔!
# Build Windows Toolchain
我們會用 [Day 27](https://ithelp.ithome.com.tw/articles/10329511) 已經裝好的 `crosstool-NG`, 將 `x86_64-w64-mingw32` cross config 加入 `toolchain`
做完必要的設定後 (請見 [Day 27](https://ithelp.ithome.com.tw/articles/10329511)), 我們就直接來 build toolchain 吧
```shell=
ct-ng build
```
需要 build 1 個多小時...

# 來寫 CMake Toolchain File 吧
上一篇有提過, toolchain package 的命名規則通常是 `<arch>[endian][-vendor]-<kernel>[-os]`, 以今天的 toolchain `x86_64-w64-mingw32` 來說, 就可以拆解成
* Arch: `x86_64`
* kernel: `w64`
* OS: `mingw32`
接著我們就可以用該名稱去找我們的 cross compiler 了
不過我們不需要完整的路徑, 只需要將 `CMAKE_FIND_ROOT_PATH` 設為 Toolchain Directory 即可, CMake 會自動去底下找指定的 cross compiler
`x86_64-w64-mingw32.cmake`
```cmake=
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER /root/x-tools/x86_64-w64-mingw32/bin/x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER /root/x-tools/x86_64-w64-mingw32/bin/x86_64-w64-mingw32-g++)
set(CMAKE_FIND_ROOT_PATH /root/x-tools/x86_64-w64-mingw32)
set(CMAKE_SYSROOT /root/x-tools/x86_64-w64-mingw32/x86_64-w64-mingw32/sysroot)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
```
* `CMAKE_FIND_ROOT_PATH`
* 會讓 `find_*()` 系列的搜尋路徑都加上該 prefix
* 搜尋規則視下面的 `CMAKE_FIND_ROOT_PATH_MODE_*` 決定
* `CMAKE_FIND_ROOT_PATH_MODE_*` 系列會影響對應的 `find_*()` 搜尋路徑
* 有 3 種設定: `NEVER`, `ONLY`, `BOTH`
* `NEVER`
* 不會搜尋 `CMAKE_FIND_ROOT_PATH` prefix 路徑
* `ONLY`
* 僅搜尋 `CMAKE_FIND_ROOT_PATH` prefix 路徑
* `BOTH`
* 先搜尋 `CMAKE_FIND_ROOT_PATH` prefix 路徑再搜尋沒有 prefix 的路徑
* `CMAKE_FIND_ROOT_PATH_MODE_PROGRAM`
* 通常會設為 `NEVER`
* `find_program()` 是為了控制 cmake build 的流程, 所以會找 build host 的 programs
* `CMAKE_FIND_ROOT_PATH_MODE_LIBRARY`, `CMAKE_FIND_ROOT_PATH_MODE_INCLUDE`
* 通常會設為 `ONLY`
* 因為我們是 cross build, 所以需要讓 cross compiler 能夠找到 build target 的 libraries 和 headers
# Hello World!
一樣, 我們寫一個簡單的 Hello World 來試試 binary 是否能在目標系統執行
`CMakeLists.txt`
```cmake=
cmake_minimum_required(VERSION 3.25)
project(Test CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQURIED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
list(APPEND CMAKE_MODULE_PATH cmake)
add_executable(Main main.cpp)
```
`main.cpp`
```cpp=
#include <iostream>
int main() {
std::cout << "Hello World!" << std::endl;
}
```
最後我們將寫好的 toolchain file `x86_64-w64-mingw32.cmake` 放到 `toolchain` 底下
這樣就準備完成啦!
# Cross Compile!
我們可以設定 cache variable `CMAKE_TOOLCHAIN_FILE`
```shell=
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=toolchain/x86_64-w64-mingw32.cmake
```
或是直接用 `--toolchain` option
```shell=
cmake -S . -B build --toolchain=toolchain/x86_64-w64-mingw32.cmake
```
Build 完後 (`cmake --build build`), 我們來看看產出的執行檔

可以看到 Windows 的執行檔格式 `.exe` 了
並且確認了無法在 Linux 執行

所以, 我們將 `Main.exe` 下載到 Windows 系統上執行

就能看到熟悉的 `Hello World!` 了🎉🎉🎉
至此, 我們終於解決了 [Day 2](https://ithelp.ithome.com.tw/articles/10314565) 時, 無法將 Linux-built binary 的執行檔給 Windows 使用的問題了
# 預告
雖然我們已經成功 cross compile 了, 但是跨平台之旅還沒有結束!
下一篇, 我們會用 [Day 22](https://ithelp.ithome.com.tw/articles/10325185) 介紹過的方法打包我們的 Windows executable, 並讓使用者可以用安裝檔進行安裝!