因爲手上這個處理器比較特殊,編譯時沒法隨便換工具鏈,必須得用 ARM 提供的 armclang。之前我的做法一直很樸素:開虛擬機,在裏面裝 Keil,然後把整套編譯流程放進去跑。能用是能用,但總歸不夠順手。
後來突然想到,之前買過 CrossOver,但早都丟到垃圾箱了。羣友能用 Wine 跑起來,我也應該能用它跑起來,於是翻出了 License,最後在 GPT 的幫助下,還真跑通了。
裝 Keil 不是什麼大問題,編單個文件也沒問題,一旦開始編譯複雜的項目,就遇到麻煩了:
ninja是在 macOS 上運行的- 它生成和傳遞的路徑,天然是 Unix 風格
- 而實際被調用的
armclang.exe是 Windows 程序 - Windows 程序只認 Windows 風格路徑
這意味着,構建系統吐出來的參數,不能直接原樣交給 CrossOver 裏的編譯器。中間必須有一層翻譯,把路徑從 macOS 風格轉成 Windows 風格,不然很多參數都會直接失效。
於是我 vibe code 了一個 wrap 文件來做這件事:cx-winpath-wrap
它的基本功能很簡單:攔住參數,識別裏面的路徑,然後翻譯成 Windows 能理解的形式,再把參數交給真正的 ARM 工具鏈。
編譯問題解決了,但還有個大坑:dependency 文件的處理。因爲 ninja 是否需要重新編譯,很多時候依賴的就是編譯器生成的 dependency 信息。這個鏈路如果處理不好,就會出現一種很煩的情況:明明源碼沒變,但構建系統總覺得依賴不對,於是每次都重新編譯。
經過 GPT 反覆嘗試(感覺是因爲它確實不擅長寫 bash),這個問題也搞定了。
有了路徑轉換腳本之後,後面的思路就比較直接了:在本地放幾個同名腳本,專門負責把調用轉發給 CrossOver 裏的 Windows 可執行文件。
例如 armclang 可以寫成這樣:
#!/bin/bash
exec "$HOME/.local/bin/cx-winpath-wrap" \
'C:\users\crossover\AppData\Local\Keil_v5\ARM\ARMCLANG\bin\armclang.exe' \
"$@"
其他幾個工具也一樣處理,比如:
armararmlinkfromelf
包裝腳本準備好之後,就可以直接在 toolchain.cmake 裏指定這些入口:
set(CMAKE_C_COMPILER "$ENV{HOME}/.local/bin/armclang")
set(CMAKE_AR "$ENV{HOME}/.local/bin/armar")
set(CMAKE_LINKER "$ENV{HOME}/.local/bin/armlink")
set(FROMELF "$ENV{HOME}/.local/bin/fromelf")
這樣整個調用鏈就串起來了:
cmake生成構建規則ninja在 macOS 上執行- 本地包裝腳本接管編譯命令
wrap負責路徑和 dependency 的轉換- CrossOver 裏的
armclang工具鏈真正完成編譯和鏈接