---
# System prepended metadata

title: '[Day 28] Cross Compile Windows Binaries'
tags: [' cmake', ' ithome2023', ithome]

---

---
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 個多小時...
![](https://hackmd.io/_uploads/ryDH55Mea.png)


# 來寫 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`), 我們來看看產出的執行檔
![](https://hackmd.io/_uploads/rksa_6Gg6.png)

可以看到 Windows 的執行檔格式 `.exe` 了
並且確認了無法在 Linux 執行
![](https://hackmd.io/_uploads/S1QfF6fgT.png)

所以, 我們將 `Main.exe` 下載到 Windows 系統上執行
![](https://hackmd.io/_uploads/rySpFJ7gp.png)


就能看到熟悉的 `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, 並讓使用者可以用安裝檔進行安裝!