# wkbre Linux 系統下跨 Windows(MinGW) 平台源碼建構筆記
學習如何將 [wkbre 軟體](https://github.com/AdrienTD/wkbre/tree/master)跨平台源碼建構至 Windows(MinGW) 平台
[TOC]
## 智慧財產授權條款
除另外標註之內容外本作品的內容以[《Creative Commons 姓名標示-相同方式分享》授權條款第 4.0 國際版](https://creativecommons.org/licenses/by-sa/4.0/deed.zh_TW)或其任意更近期版本釋出供大眾*於授權範圍內*自由使用
## 重現環境
以下說明應該能重現本筆記之結果的環境細節:
### 作業系統
Ubuntu 23.10 AMD64
### wkbre
[第 c58f5fff <ruby>修訂版<rp>(</rp><rt>revision</rt><rp>)</rp></ruby>](https://github.com/AdrienTD/wkbre/commit/c58f5fffeed624c7fc4f36801bb30ea72668aece)
### CMake
3.27.4-1(來源:Ubuntu 23.10 軟體庫)
### MinGW-w64 <ruby>工具鏈<rp>(</rp><rt>toolchain</rt><rp>)</rp></ruby>
12.3.0-9ubuntu1+25.3(來源:Ubuntu 23.10 軟體庫)
## 操作過程
以下說明重現本筆記成果的操作過程:
### 啟動一文字界面終端機應用軟體
本筆記撰寫當下使用的是 KDE 桌面環境得 Konsole 應用軟體
### 切換作業目錄至要存放 wkbre 軟體源碼的目錄
執行下列命令以切換作業目錄至要存放 wkbre 軟體源碼的目錄:
```bash
cd /path/to/wkbre/srcdir/hosting/folder
```
### 將 wkbre 軟體的 Git <ruby>版控庫<rp>(</rp><rt>repository</rt><rp>)</rp></ruby><ruby>拓製<rp>(</rp><rt>clone</rt><rp>)</rp></ruby>到本地
執行下列命令將 wkbre 軟體的 Git 版控庫拓製到本地:
```bash
git clone https://github.com/AdrienTD/wkbre.git
```
您可以使用 `--depth` `git clone` 命令選項來限縮獲取的變更歷史深度
### 切換<ruby>作業目錄<rp>(</rp><rt>working directory</rt><rp>)</rp></ruby>至 wkbre 軟體的<ruby>來源程式碼<rp>(</rp><rt>source code</rt><rp>)</rp></ruby>目錄
執行下列命令以切換作業目錄至 wkbre 軟體的來源程式碼目錄:
```bash
cd wkbre
```
### <ruby>已知問題規避方案<rp>(</rp><rt>WORKAROUND</rt><rp>)</rp></ruby>:修正 bzip2 子目錄不適當的 CMakeLists.txt 檔案名稱
因 bzip2 子目錄的 CMakeLists.txt 檔案於區分大小寫的作業系統(如 Linux)下會無法被 CMake 讀到故需要執行下列命令手動修正檔案名稱:
```bash
mv bzip2/CMakeLists.{TXT,txt}
```
:::info
**附註:**
* `{TXT,txt}` 為 Bash 的<ruby>曲括號展開<rp>(</rp><rt>brace expansion</rt><rp>)</rp></ruby>語法
* 此修正已提交為 [Fix Linux MinGW cross-build incompatibilities by brlin-tw · Pull Request #1 · AdrienTD/wkbre](https://github.com/AdrienTD/wkbre/pull/1) 上游專案合併請求的一部分
:::
### 已知問題規避方案:修正不適當的<ruby>標頭檔案<rp>(</rp><rt>header file</rt><rp>)</rp></ruby>檔案路徑
因源碼引用的 C/C++ 程式語言標頭檔案於區分大小寫以及使用正斜線(/)作為檔案路徑目錄分隔符的作業系統(如 Linux)下會無法被 C/C++ 預處理器讀到故需要執行下列命令手動修正檔案路徑:
```bash
find_opts=(
# 比對完整檔案名稱(whole file name)(即路徑)
-path ./build
# 上述目錄表達式不走訪
-prune
-or
# 比對普通檔案
-type f
# 比對下列任一不區分大小寫的 C/C++ 程式碼檔案名稱式樣
'('
-iname '*.c'
-or
-iname '*.h'
-or
-iname '*.cpp'
-or
-iname '*.hpp'
')'
# 輸出的檔案路徑序列以空字元(null character)分隔以避免特殊檔案名稱影響執行結果
-print0
)
xargs_opts=(
# 輸入的資料為以空字元分隔的檔案路徑序列
--null
# 印出會被執行的命令以方便查看整個命令流水線(command pipeline)的行為
--verbose
# 宣告後方的位置依賴引數(positional arguments)均非 xargs 的命令選項
--
)
sed_opts=(
# 直接修改檔案而非輸出到標準輸出裝置(stdout)
--in-place
# 使用較為通用的擴展版正規表達式(E.R.E.)而非基本版正規表達式(B.R.E.)語法
--regexp-extended
# 修正大小寫不正確的標頭檔路徑
--expression='s@^#include[[:space:]]+<Windows.h>@#include <windows.h>@g'
--expression='s@^#include[[:space:]]+<gl/gl\.h>@#include <GL/gl.h>@g'
--expression='s@^#include[[:space:]]+<gl/glu\.h>@#include <GL/glu.h>@g'
# 修正目錄分隔符不正確的標頭檔路徑
--expression='s@^#include[[:space:]]+"..\\global\.h"@#include "../global.h"@g'
)
find . "${find_opts[@]}" \
| xargs "${xargs_opts[@]}" \
sed "${sed_opts[@]}"
```
:::info
**附註:** 此修正已提交為 [Fix Linux MinGW cross-build incompatibilities by brlin-tw · Pull Request #1 · AdrienTD/wkbre](https://github.com/AdrienTD/wkbre/pull/1) 上游專案合併請求的一部分
:::
### 已知問題規避方案:修正不適當的 Resource Compiler 輸入檔中的檔案路徑
因 Resource Compiler 輸入檔參照的外部檔案路徑於使用正斜線(/)作為檔案路徑目錄分隔符的作業系統(如 Linux)下會無法被 `windres` 程序讀到故需要執行下列命令手動修正檔案路徑:
```bash
sed_opts=(
# 直接修改檔案而非輸出到標準輸出裝置(stdout)
--in-place
# 使用較為通用的擴展版正規表達式(E.R.E.)而非基本版正規表達式(B.R.E.)語法
--regexp-extended
# 修正目錄分隔符不正確的資源檔案路徑
--expression='s@\.\\\\icon\.ico@./icon.ico@g'
--expression='s@redata\\@redata/@g'
)
sed "${sed_opts[@]}" wkbre.rc
```
:::info
**附註:** 此修正已提交為 [Fix Linux MinGW cross-build incompatibilities by brlin-tw · Pull Request #1 · AdrienTD/wkbre](https://github.com/AdrienTD/wkbre/pull/1) 上游專案合併請求的一部分
:::
### 已知問題規避方案:套用 ImVec4 資料類型變數傳入程式修正
1. 於<ruby>當前作業目錄<rp>(</rp><rt>current working directory</rt><rp>)</rp></ruby>創建一 fix-imvec4-rvalue-type.patch <ruby>程式修正檔<rp>(</rp><rt>patch file</rt><rp>)</rp></ruby>,新增下列內容後保存:
```diff
diff --git a/wkbre.cpp b/wkbre.cpp
index 1f2b2dc..6c65000 100644
--- a/wkbre.cpp
+++ b/wkbre.cpp
@@ -2401,7 +2401,8 @@ bool IGPlayerChooser(char *popupid, goref *p)
ImGui::AlignTextToFramePadding();
if (!p->valid())
{
- OldColorButton("color", ImVec4(1, 1, 1, 1));
+ ImVec4 color(1, 1, 1, 1);
+ OldColorButton("color", color);
ImGui::SameLine();
ImGui::Text("Click me to select a player.");
}
```
1. 執行下列命令以套用程式修正:
```bash
patch_opts=(
# 將程式修正檔中的檔案路徑移除一個路徑組成元件
--strip=1
)
patch "${patch_opts[@]}" <fix-imvec4-rvalue-type.patch
```
:::info
**附註:** 本修正與 [draft: Fix "cannot bind non-const lvalue reference of type ‘ImVec4&’ to an rvalue of type ‘ImVec4’" compilation error by brlin-tw · Pull Request #2 · AdrienTD/wkbre](https://github.com/AdrienTD/wkbre/pull/2/commits/da17ecf199bd8757c896faf81b515588c15321f9) 上游專案合併請求效果等價
:::
### 創建<ruby>軟體建構用檔案存放目錄<rp>(</rp><rt>build directory</rt><rp>)</rp></ruby>
為避免源碼建構用檔案與軟體源碼檔案混在一起,執行下列命令以創建軟體建構用檔案存放目錄:
```bash
mkdir_opts=(
# 在目錄(及其親目錄)已存在情境下不報錯
--parents
)
mkdir "${mkdir_opts[@]}" build
```
### 切換作業目錄至軟體建構用檔案存放目錄
執行下列命令以切換作業目錄至軟體建構用檔案存放目錄:
```bash
cd build
```
### 安裝 CMake 軟體建構系統檔案生成器
*以 root 身份*執行下列命令以安裝 CMake 軟體建構系統檔案生成器:
```bash
apt install cmake
```
### 安裝 MinGW-w64 跨平台軟體建構工具鏈
*以 root 身份*執行下列命令以安裝 MinGW-w64 跨平台軟體建構工具鏈:
```bash
apt install mingw-w64
```
### 設計 MinGW-w64 的 CMake <ruby>工具鏈定義檔<rp>(</rp><rt>toolchain file</rt><rp>)</rp></ruby>
於當前作業目錄創建一 TC-mingw.cmake 檔案,新增下列內容後保存:
```cmake
# CMake toolchain file for cross-compiling in MinGW
# Cross Compiling With CMake — Mastering CMake
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html
# the name of the target operating system
set(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc-win32)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++-win32)
# where is the target environment located
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
# adjust the default behavior of the FIND_XXX() commands:
# search programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# search headers and libraries in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
```
### 產生軟體建構系統檔案
執行下列命令以產生 GNU Make 軟體建構系統的建構規則檔:
```bash
cmake_opts=(
# 定義 `CMAKE_TOOLCHAIN_FILE` CMake 快取項目的值
-DCMAKE_TOOLCHAIN_FILE=TC-mingw.cmake
# 不編入測試邏輯
-DWKBRE_RELEASE=TRUE
)
cmake "${cmake_opts[@]}" ..
```
:::info
您可以透過 `-G` `cmake` 命令選項以指定其他軟體建構系統(如 Ninja)的源碼建構用檔案
:::
### 建構軟體
執行下列命令以開始進行軟體建構:
```bash
make_opts=(
# 使用系統中央處理器(CPU)的執行緒數進行平行建構
--jobs="$(nproc)"
)
make "${make_opts[@]}"
```
順利的話您應可以於命令輸出中看到軟體主程式被成功建構:
```output
...stripped...
[ 92%] Building CXX object CMakeFiles/wkbre.dir/script/value.cpp.obj
wkbre/script/objCreation.cpp:28:44: warning: multi-character character constant [-Wmultichar]
28 | if( *((uint*)(word[0])) == '_DNE' )
| ^~~~~~
[ 94%] Building CXX object CMakeFiles/wkbre.dir/imgui/imgui_demo.cpp.obj
[ 95%] Building CXX object CMakeFiles/wkbre.dir/imgui/imgui_draw.cpp.obj
wkbre/script/package.cpp:29:44: warning: multi-character character constant [-Wmultichar]
29 | if( *((uint*)(word[0])) == '_DNE' )
| ^~~~~~
[ 97%] Building CXX object CMakeFiles/wkbre.dir/imgui/imgui_widgets.cpp.obj
[ 98%] Building RC object CMakeFiles/wkbre.dir/wkbre.rc.res
[100%] Linking CXX executable wkbre.exe
[100%] Built target wkbre
```
且可於當前作業目錄中看到被建構的軟體主程式檔案:
```output
$ ls -l
total 2052
...stripped...
-rwxrwxr-x 1 brlin brlin 2012049 Jan 7 20:51 wkbre.exe
```
### 引入執行時期需要的 Windows 程式庫
執行下列命令引入執行時期所需要的 Windows 程式庫:
```bash
ln_opts=(
# 創建象徵式連結(symbolic link)而非硬連結(hard link)
--symbolic
# 如果連結以存在就直接取代
--force
)
# 將指定的檔案於當前作業目錄創建同名的象徵式連結
ln "${ln_opts[@]}" \
/usr/lib/gcc/x86_64-w64-mingw32/12-win32/libgcc_s_seh-1.dll \
/usr/lib/gcc/x86_64-w64-mingw32/12-win32/libstdc++-6.dll \
.
```
:::info
**注意:** 如果您要將軟體複製到其他系統使用請改用 `cp` 命令複製完整的程式庫檔案
:::
### 安裝 Wine Windows API 相容層
*以 root 身份*執行下列命令以安裝 Wine Windows API 相容層:
```bash
apt install wine
```
### 執行建構好的軟體
執行下列命令即可嘗試執行建構好的軟體:
```bash
wine wkbre.exe
```
![缺少遊戲資料檔案的錯誤對話框的螢幕截圖](https://hackmd.io/_uploads/HJEI-QudT.png "缺少遊戲資料檔案的錯誤對話框的螢幕截圖")
## 常用操作
以下說明進行本筆記之操作時可能會用到的常用操作:
### 移除 Git 版控庫所有未被版本控制系統追蹤(untracked)的檔案
1. 切換作業目錄至 Git 版控庫的<ruby>作業副本<rp>(</rp><rt>working copy</rt><rp>)</rp></ruby>目錄中
1. 執行下列命令以移除 Git 版控庫所有<ruby>未被版本控制系統追蹤<rp>(</rp><rt>untracked</rt><rp>)</rp></ruby>的檔案:
```bash
git_clean_opts=(
# 遞迴地移除未被版本控制系統追蹤的(untracked)目錄中的檔案
-d
# 啟用檔案刪除功能
-f
# 連同被(.gitignore 檔案/Git 配置)排除追蹤的檔案一起清理
-x
)
git clean "${git_clean_opts[@]}"
```
### 重設 Git 版控庫作業副本中尚未提交進版控庫的內容變更
1. 執行下列命令以切換作業目錄至 Git 版控庫的作業副本目錄中:
```bash
cd /path/to/wkbre
```
1. 執行下列命令以重設作業副本目錄中尚未提交進版控庫的內容變更:
```bash
git_reset_opts=(
# 除 HEAD 指標外還要重設作業副本中的被追蹤檔案內容
--hard
)
git reset "${git_reset_opts[@]}"
```
### 清理 GNU Make 軟體建構系統的<ruby>源碼建構中間產物<rp>(</rp><rt>intermediate build artifacts</rt><rp>)</rp></ruby>
1. 執行下列命令以切換作業目錄至 wkbre 軟體的軟體建構用檔案存放目錄中:
```bash
cd /path/to/wkbre/build
```
1. 執行下列命令以清理 GNU Make 軟體建構系統的源碼建構中間產物:
```bash
make clean
```
### 查看當前 Git 版本庫 HEAD 指標指向的修訂版與作業副本之間的內容差異
1. 執行下列命令以切換作業目錄至 Git 版控庫的作業副本目錄中:
```bash
cd /path/to/wkbre
```
1. 執行下列命令以查看當前 Git 版本庫 HEAD 指標指向的修訂版與作業副本之間的內容差異:
```bash
git diff
```
## 參考資料
以下列舉撰寫本文章期間所參考的第三方資料:
* [wkbre/README.md at master · AdrienTD/wkbre](https://github.com/AdrienTD/wkbre/blob/master/README.md)
說明軟體的相關資訊與基本的源碼建構說明
* [wkbre/docs/codedoc.txt at master · AdrienTD/wkbre](https://github.com/AdrienTD/wkbre/blob/master/docs/codedoc.txt)
說明軟體的進一步源碼建構細節
* [Cross Compiling With CMake — Mastering CMake](https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html)
說明如何使用 CMake 以進行跨 MinGW 平台建構
* git-clean(1) 的使用手冊頁面(manpage)
說明 `git clean` 命令的用途與相關命令選項
* cmake(1) 的使用手冊頁面(manpage)
說明 `cmake` 命令的用途與相關命令選項
* [Replace Text Recursively in Linux | ChatGPT](https://chat.openai.com/share/5d3bea6c-07fa-4445-a923-fea4f64ef904)
說明如何於 Linux 作業系統中遞迴地替換純文字文件的特定<ruby>式樣<rp>(</rp><rt>pattern</rt><rp>)</rp></ruby>的文字
* find(1) 的使用手冊頁面(manpage)
說明 `find` 命令的用途與相關命令選項
* xargs(1) 的使用手冊頁面(manpage)
說明 `xargs` 命令的用途與相關命令選項
* [Ubuntu – 軟體包內容搜尋結果 -- gl/gl.h](https://packages.ubuntu.com/search?searchon=contents&keywords=gl%2Fgl.h&mode=&suite=kinetic&arch=any)
列舉所有提供 gl/gl.h 結尾的檔案的 Ubuntu 軟體包
* [Ubuntu – 軟體包內容搜尋結果 -- gl/glu.h](https://packages.ubuntu.com/search?searchon=contents&keywords=gl%2Fglu.h&mode=&suite=kinetic&arch=any)
列舉所有提供 gl/glu.h 結尾的檔案的 Ubuntu 軟體包
* windres(1) 的使用手冊頁面(manpage)
說明 `windres` 命令的用途與相關命令選項
* [修正編譯器錯誤 | ChatGPT](https://chat.openai.com/share/81ac77f4-24df-4514-aff4-4a5f6de6e18f)
說明如何修正 `ImVec4` 資料類型變數傳入邏輯編譯報錯
---
除另外標註之內容外本作品的內容以[《Creative Commons 姓名標示-相同方式分享》授權條款第 4.0 國際版](https://creativecommons.org/licenses/by-sa/4.0/deed.zh_TW)或其任意更近期版本釋出供大眾*於授權範圍內*自由使用
<style>
/* 調大旁註文字的字元大小 */
rt{
font-size: 10pt;
}
</style>