跨平台軟體建置:CMake 入門

當我們將軟體的價值視為服務時,跨平台就會越來越重要,因為它代表軟體能跨越限制,降低客戶使用成本,進而更快創造價值。工程師可能很難想像,當客戶拿到新軟體時,他需要面對一堆設定問題,還需要建置平台,這會是一件多讓人厭世的事。

常見的跨平台是指,軟體可在三大主流平台上運作,也就是支援 Windows、Linux、Mac;也有些跨平台指硬體平台,像是 x86 或 arm。本文會用 cmake 這個跨平台建置工具,分別建置可於 Windows 與 Linux 上執行的應用程式。

Prerequisite

對於 Windows 的開發者,建議用 MinGW 來建置,這個工具讓 Windows 上有跟 Linux 相同的操作經驗,可以避免二次學習。Windows 10 有很便利的 Package Management Chocolatey,類似 Ubuntu 的 apt 或 Fedora 的 yum,可以用來安裝 MinGW

choco install mingw -y

Install CMake

主角可以登場了,使用 Chocolatey 來安裝 cmake

choco install cmake -y

安裝完執行

cmake

來看是否安裝成功

如果 Command Prompt 找不到 cmake,確認有沒有將 cmake 的執行檔路徑加入 PATH 環境變數。 Command Prompt 會從 PATH 中抓指令,如果沒加的話記得加入並重新啟動 Command Prompt。

Prepare Source Code

先看一下 cmake 的資料夾結構,通常會是

project/
├── build/
├── src/
|   ├── CMakeLists.txt
|   └── hello.c
├── CMakeLists.txt
└── README

build 資料夾用於放置 cmake 的建構文件;src 用於放置原始碼;CMakeLists.txt 類似 GNU 中的 makefile,用於描述應該如何建構檔案。cmake 使用遞迴建構,每個子資料夾中都要放置該資料夾的 CMakeLists.txt。

當建立好資料夾後,在 src 底下產生 hello.c,內容是

#include <stdio.h>
int main()
{
    printf("Hello World!\n");
    return 0;
}

如此一來,環境就準備完成了。

Edit CMake makefile

有了環境後,開始 cmake 的重頭戲:編寫 CmakeLists.txt。先處理最上層專案目錄的 CmakeLists.txt

PROJECT (HELLO)
ADD_SUBDIRECTORY(src bin)

對,兩行,就這樣,有沒有很單純?cmake 的語法是

CMD (ARG)

所以這兩行的意思是:(1) 命名專案為 HELLO;(2) 加入子目錄 src,並將產生的目標檔放入 bin 目錄中。

接著來看 src 中的 CmakeLists.txt

ADD_EXECUTABLE(hello hello.c)

意思是使用 hello.c 產生 hello 執行檔。

由於專案目錄中的 CmakeLists.txt 會引用到 src 中的 CmakeLists.txt,當 cmake 執行時,它會讀取兩個 CmakeLists.txt,並按照命令來設定建置環境。

Compile for Windows

我們來試著建置 Windows 的應用程式,因為 cmake 的設計原則是將 src 與建置環境分開,不要讓 cmake 產生出來的文件汙染專案,強烈建議進入 build 中建置

cd build
cmake -G "MinGW Makefiles" ..

使用 -G 是選擇 build system 的 Generator;cmake 支援 Visual Studio 專案、MinGW Makefiles、CodeLite 專案等等。由於我們希望操作方式盡量一致,使用與 GNU 風格相同的 MinGW。

此時,會看到 cmake 在 build 下自動產生文件

project/
├── build/
|   ├── bin/
|   ├── CMakeFiles/
|   ├── cmake_install.cmake
|   └── Makefile
├── src/
|   ├── CMakeLists.txt
|   └── hello.c
├── CMakeLists.txt
└── README

看到 Makefile 後,直接反應就是 make 啦

mingw32-make

得到編譯訊息

D:\git\cmake-example\t2\build>mingw32-make
Scanning dependencies of target hello
[ 50%] Building C object bin/CMakeFiles/hello.dir/hello.obj
[100%] Linking C executable hello.exe
[100%] Built target hello

執行檔案

D:\git\cmake-example\t2\build>.\bin\hello.exe
Hello World!

Windows 版本建置完成。

Compile for Linux

將相同的專案複製到 Linux 底下,再次編譯。如果你是使用 Windows 為開發平台,可以使用 WSL 來建構 Linux 環境。執行步驟相同,只是使用 cmake 時不用加 MinGW,下 cmake 前記得清空 build 資料夾

cd build
rm -rf ./*
cmake ..

得到配置訊息

ken@DESKTOP-2R08VK6:/mnt/d/git/cmake-example/t2/build$ cmake ..
-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Warning (dev) in CMakeLists.txt:
    No cmake_minimum_required command is present.  A line of code such as

cmake_minimum_required(VERSION 3.10)

should be added at the top of the file.  The version specified may be lower
    if you wish to support older CMake versions for this project.  For more
    information run "cmake --help-policy CMP0000".
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/d/git/cmake-example/t2/build

進行編譯

make

得到

ken@DESKTOP-2R08VK6:/mnt/d/git/cmake-example/t2/build$ make
Scanning dependencies of target hello
[ 50%] Building C object bin/CMakeFiles/hello.dir/main.o
[100%] Linking C executable hello
[100%] Built target hello

執行程式

ken@DESKTOP-2R08VK6:/mnt/d/git/cmake-example/t2/build$ ./bin/hello 
Hello World!

如果對檔案格式有興趣,也可以用 file 指令查看

ken@DESKTOP-2R08VK6:/mnt/d/git/cmake-example/t2/build$ file ./bin/hello 
./bin/hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=e7fcca840caa7d5e99bdd0e26bf329b79b7e83fd, not stripped

可看到 ELF 是 Linux 可執行檔格式。

小結

cmake 雖然功能不錯,但學習曲線真的有點陡,別看簡單寫個 hello, world,中間的坑一堆;不是很理解 cmake 反人類的語法是怎麼設計的,跟其他語言差距非常大,剛開始發現沒有 case sensitive 時還很開心,結果程式碼一寫長就覺得風格混亂,維護困難;每個子資料夾都要 CmakeLists.txt 也讓人無言,容易迷路在專案結構中,看不到全貌;最麻煩的是除錯困難,範例又少,要使用 cmake 幾乎無法避免一系列花式踩坑。

但是!對於 C/C++ 的跨平台建構來說,cmake 仍是目前最方便最主流的工具,支援的 Generator 夠多,成熟度也高。如果開發者有使用 autotools 來建構專案的經驗,應該能上手 cmake。我不是要黑使用 Visual Studio 的開發者,但如果習慣 GUI 的人,應該會覺得痛苦指數很高。cmake 有自己的圖形介面,似乎也能跟 Visual Studio 整合,但這就留到日後再來慢慢研究了。

Reference

Read more

Weekly Issue 第 21 期:JetBrains 發表 2025 Go 生態系調查

最近在讀 Tony Fadell 的 "Build",作者曾經參與過 iPhone 的開發,各種經驗談讓人嘆為觀止,例如這段:「如果故事有某個部分銜接不上,那麼產品本身也會有某個地方行不通…這便是為什麼最後 iPhone 的表面是玻璃,而不是塑膠,以及為什麼 iPhone 沒有硬體鍵盤。」 好在哪呢?好在如果能掌握這個觀念,就能知道如何「閱讀」產品,看見一個產品,就像閱讀一則故事一樣,知道它的抑揚頓挫,知道它想表現的東西。我相信每個經歷過產品開發的人,看這本書都會很有感覺。   🗞️ 熱門新聞 The Go Ecosystem in 2025: Key Trends in Frameworks, Tools, and Developer Practices JetBrains 前陣子公布 Go 生態系的調查結果。

By Ken Chen

Weekly Issue 第 20 期:AI 泡沫的遺產

2000 年的 .com 泡沫雖然造成嚴重的經濟問題,但也給後續的網路世代留下豐富的遺產。我們現在使用的網路基礎建設,很多是因為泡沫的原因,才能一次性投資到位。而當下經歷的 AI 浪潮,在時間過去後,又會給我們留下什麼遺產呢? 🗞️ 熱門新聞 The Benefits of Bubbles 我看 Ben Thompson 的文章通常會有兩種感受,負面是他太囉唆了,把簡單的觀念講得太長(儘管容易懂),而正面是他的觀點一向很有創造性。 這篇也是,前陣子看到有篇談 AI 泡沫後,什麼都不會留下,因為 GPU 很快會隨著時間折舊掉。我持保留態度,我認為重點不僅是 GPU(正如我認為 .com 泡沫的重點不是 CPU),還有其他的東西,至於是什麼,我沒想到。 BT 認為是晶圓製造與電力,It's amazing,

By Ken Chen

Weekly Issue 第 19 期:Coursera 的預覽模式宣告 MOOC 終結

我有時會上課程網站買課,特別是國外的網站,有些課程內容品質高,而且還能無價體驗,我常常在想這在商業上怎麼行得通。Coursera 最近推出預覽功能,某方面來說,也是在宣告長期要往付費走。 網路最大的特點是開放,因為開放,我們看到不可思議的成長,也因為開放,我們有時會很惋惜理想的落幕。 🗞️ 熱門新聞 The Day MOOCs Truly Died: Coursera's Preview Mode Kills Free Learning 很有趣的一篇新聞:Coursera 的預覽模式給了 MOOC 最後一擊。 我對 Coursera 的商業模式不熟,看起來它之前是靠證書與服務營利。很難想像線上課程能用免費支撐這麼久,這幾乎是公益了,將內容鎖在付費牆後比較像可理解的商業行為。 讓我困惑的是,這些年 Coursera 是如何獲利?以及,當時投資人對它的想像是什麼? The PSF has withdrawn

By Ken Chen

Weekly Issue 第 18 期:OpenAI 發布 AI 瀏覽器 Atlas

OpenAI 最近發布 AI 瀏覽器,加上稍早的 Sora 2,在技術圈中引起一些討論。 我認為 OpenAI 嘗試將模型領域的優勢帶到應用面,但這也讓它顯得更像是一家營利公司,而非研究單位(雖然現在沒人會把 OpenAI 當成研究單位了)。 🗞️ 熱門新聞 Dane Stuckey (OpenAI CISO) on prompt injection risks for ChatGPT Atlas Simon Willison 聊了他對 OpenAI Altas 的看法,主要是資安方面。 幾個點:1) 提示詞注入問題依然存在,而且還沒有好解法;2) OpenAI 設計了登出模式與監視模式,讓使用者更容易意識到安全性。 在我看來第二點很重要,好設計應該要避免使用者犯錯,如果 AI 瀏覽器可以在登出狀態下執行,能避免掉很多麻煩的狀況,當然這意味著沒辦法自動購物。

By Ken Chen