位元詩人 [Windows] 程式設計教學:使用 C 和 C++ 相關的議題

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

在前文中,我們介紹數個應用程式語言,不過,我們有時候仍然需要 C (或 C++)。即使我們不寫 C (或 C++) 程式,也會要用以 C (或 C++) 寫成的延伸模組。雖然我們平日都使用腳本語言從事各種簡易的任務,必要時還是可以用 C (或 C++) 撰寫延伸模組,在關鍵步驟為程式加速。大部分高階語言都有 C API,可以用 C (或 C++) 撰寫延伸模組。使用 SWIG 也可以省下一些撰寫 binding 的功夫。近年來,許多高階語言提供 FFI (foreign function interface) 的機制,撰寫延伸模組的過程又更加簡化。

C 和 C++ 編譯環境

C 和 C++ 編譯環境可以分為以下三部分:

  • 編譯器 (compiler)
  • 函式庫 (library)
  • 工具鍵 (toolchain)

編譯器 (compiler)

C 和 C++ 有國際標準,而這兩個語言的標準近年來不斷翻新,尤其是 C++,幾乎可以視為一個新語言。C 標準有 C99、C11、C17,而 C++ 標準有 C++11、C++14、C++17 等各種版本。但 C 和 C++ 沒有所謂的官方實作品,不同編譯器對語言標準支援程度不一;通常不會在語言標準出來時馬上實作全部的特性,而會逐漸加入各種特性。其實編譯器沒有實作全部的語言標準不一定會對專案造成影響,撰寫程式碼時不一定會用到那些新的語法特性。

由於不同編譯器的 ABI (Application Binary Interface) 不相容,在專案一開始就要選擇想用的編譯器。在 Windows 上最常見的 C 和 C++ 編譯器,除了 Microsoft Visual C++ 外,就是 MinGW (GCC 的 Windows 移植品)。由於這兩套編譯器的 ABI 不相容,所産生的函式庫不會混合使用,而會選擇其中一個編譯系統,之後編譯專案的程式碼時,固定選擇該系統産生的機械碼。

工具鍵 (toolchain)

隨著專案規模變大,每次編譯都自行輸入指令較沒效率,發布程式碼專案時,讓使用者自行輸入指令來編譯軟體也不符實情。實際上,會使用工作流程自動化工具來簡化編譯軟體的動作。C 和 C++ 沒有所謂的官方自動編譯軟體,不同平台各自發展出不同的方案。在類 Unix 系統,最典型的工具就是 Make,後來 GNU 又進一步發展出 Autotools 這套自動化軟體。在 Visual Studio 中,則將流程自動化整合至其開發環境中,稱為 MSBuild。這兩者是各自獨立的,

由於 Windows 系統和類 Unix 系統使用不同的編譯工具,同一份專案要重覆建置兩套編譯設定檔,浪費一些心力在做重覆的工作。針對這個問題,出現新的自動編譯軟體,像是 CMake 或 Premake 等;在跨平台自動編譯軟體中,CMake 最為流行,是優先學習的對象。

函式庫 (library)

在撰寫程式時,通常不會只用標準函式庫所提供的功能,而會使用第三方函式庫。C 或 C++ 的函式庫是由標頭檔 (header) 和二進位檔 (binary file) 組成,本身沒有既定的套件形式,在不同平台上有不同的方式來因應。

在 GNU/Linux 和 BSD 上使用系統套件管理程式來因應這個議題,像是 Linux 上以 dev 或是 devel 命名的套件就是 C/C++ 的函式庫標頭檔。但這類函式庫套件往往會鎖定在特定的版本,比較不靈活,後來出來了將運行環境隔離起來的容器技術,如 Docker。

Mac 雖然是類 Unix 系統,但沒有內建的套件管理程式。目前會用第三方套件管理程式簡化套件管理的工作,像是 Homebrew 或 MacPorts 等。

而 Windows 系統較缺乏固定的套件管理程式,有些函式庫提供安裝程式,有時就是要手動將函式庫加入專案中。後來有 NuGet 這套套件管理程式,解決一部分套件管理的功能,但很多函式庫仍然無法以 NuGet 安裝。最近微軟釋出 vcpkg 專案,試圖解決套件的問題,成效如何仍待觀察。

MinGW 將 GCC 帶到 Windows 平台

在類 Unix 系統中,C 或 C++ 編譯環境相當成熟且易取得。而在 Windows 上則要自行建置環境。編譯器的部分較容易處理,安裝 MinGW 即可。只有編譯器和標準函式庫能從事的任務相對受限,通常也會需要社群函式庫,而社群函式庫則是較為困難的部分,有許多函式庫是以原始碼的形式發布,而 Windows 不支援 Autotools 等編譯工具。為了順利在 Windows 上使用類 Unix 系統中的函式庫,於是有 MSYS 計畫。

MSYS 其實有點像是前面文章中提到的 Cygwin,是一個小型的 POSIX 子系統。但和 Cygwin 的目標略有不同,MSYS 不是拿來從事日常生活上的任務,而是提供一個編譯程式的環境,所以,MSYS 內的工具不會像 Cygwin 裡那麼齊全,而是以編譯軟體相關的工具為主。MSYS 編譯出來的軟體是原生的 Windows 應用程式和函式庫,而不像 Cygwin 編譯出來的軟體只能在 Cygwin 環境中使用。

MSYS2 改良 MinGW

原本的 MSYS 僅提供編譯軟體的環境,但在 MSYS 中編譯軟體不是很容易的過程,要耗費許多時間,也很容易失敗。後來出現 MSYS2 計畫,這個計畫將 MSYS 重寫,除了原先 MSYS 提供的功能外,也引入 ArchLinux 所使用的套件管理程式 Pacman。此外,MSYS2 計畫預先編譯一些常見的函式庫套件,節省程式人自行編譯函式庫的時間。必要時,也可下載 C 和 C++ 相關的開發工具,自行編譯其他函式庫。

使用 MSYS2 時要注意,MSYS2 的軟體分為兩種,一種是原生的 Windows 環境下的軟體,一種是 MSYS 子系統內的軟體。MSYS2 的軟體共有三種類別,分別是

  • mingw32:32 位元的原生 Windows 原生程式
  • mingw64:64 位元的原生 Windows 原生程式
  • msys:適用於 MSYS 子系統的軟體

由於我們使用 MSYS 的目標是編譯 Windows 原生程式,編譯時應使用 mingw32 或 mingw64 開頭的開發工具為主,而 msys 開頭的軟體主要是用來執行 Autotools 和其他編譯軟體時會用到的工具。MSYS2 內也提供 MinGW,不需從其他來源安裝。

根據自己實際的情況,可選擇 32 位元或是 64 位元的 MSYS2 系統。如果使用 64 位元的系統,即使是要編譯 32 位元的軟體,也不需要刻意選擇 32 位元的 MSYS2 系統,64 位元的 MSYS2 系統即可編譯 32 或 64 位元的軟體。通常在安裝時,會選擇單純的路徑,像是 C:\msys32 或是 C:\msys64 等,以避免不可預期的錯誤。

安裝完後,可在 DOS 環境下輸入 msys2 即可進入 MSYS 子系統,或是從圖形介面按連結開啟該系統。要注意的是,MSYS 子系統的使用方式類似於 Cygwin 而和 DOS 環境不同。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。