--- 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, 並讓使用者可以用安裝檔進行安裝!