Windows 求生手冊:以 MinGW 和 MSYS 建置 C 或 C++ 編譯環境

PUBLISHED ON OCT 18, 2017 — OPERATING SYSTEM

    在本文中,我們會用 MinGW + MSYS 建置 C 或 C++ 編譯環境;MinGW 是 GCC 在 Windows 上的移植品,而 MSYS 是小型的 POSIX 環境,用來編譯軟體。雖然 MinGW 使用起來不若 Visual C++ 這種包山包海的 IDE 那麼方便,但 MinGW 對 C 語言的支援比較進步,是值得考慮的替代性選擇;搭配 Code::Blocks 等 IDE,其實使用起來不會那麼不便。

    原本的 MinGW 較不親民,我們會採用改良過的 msys2。到 msys2 官網,根據 CPU 的位元數下載相對應的 msys2 安裝程式,按照指示安裝即可。在 64 位元的系統,不需刻意選 32 位元的 msys2 安裝程式,在 64 位元的 msys2 中即同時包含 32 和 64 位元的套件。

    使用 msys2 時,實際上我們有兩種終端機環境:

    • cmd:原生的 Windows 終端機環境,用於編譯 Windows 原生軟體和其他任務
    • msys:特殊的子系統,僅用於編譯和安裝套件

    我們要安裝套件時,會使用 msys 環境,而要編譯 Windows 原生軟體時,就會回到 cmd 環境。

    開啟一個 msys 視窗,更新系統的核心組件:

    $ pacman -Syu
    

    更新完成後,重開 msys 視窗,更新其他部分:

    $ pacman -Sy
    

    msys2 的套件有三種字首:

    • mingw-w64-i686:32 位元套件 (mingw32)
    • mingw-w64-x86_64:64 位元套件 (mingw64)
    • 無字首:僅用於 msys 環境中 (msys)

    用以下指令搜尋套件:

    $ pacman -Ss gcc
    

    用以下指令安裝 C/C++ 編譯器和其他常見的開發工具:

    $ pacman -S mingw-w64-x86_64-toolchain
    

    安裝好開發工具後,將相對應的路徑加入 PATH 變數,以 64 位元工具來說,將 C:\msys64\mingw64\bin 加入即可。

    開啟 cmd 終端機,檢查 GCC 版本:

    C:\> gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=(省略部分內容)
    Target: x86_64-w64-mingw32
    Configured with: (省略部分內容)
    Thread model: posix
    gcc version 7.2.0 (Rev1, Built by MSYS2 project)
    

    如果出現某個 GCC 版本,代表 C/C++ 編譯環境建置成功。

    除了提供 C/C++ 編譯環境外,msys2 還將一些常見的 C/C++ 函式庫包裝成套件,簡化編譯套件的過程。在這裡,我們以 GTK+3 為例,說明如何使用 msys2 套件。

    開啟 msys2 視窗,下載 64 位元版本的 GTK+3 套件:

    $ pacman -S mingw-w64-x86_64-gtk3
    

    在這裡,我們用 Go 社群的 gotk3 套件來展示使用套件的過程。請讀者先自行安裝 Go,再下載 gotk3 套件:

    C:\> go get github.com/gotk3/gotk3/gtk
    

    在這裡,以一個小型的視窗程式來試我們裝好的套件:

    package main
    
    import (
    	"github.com/gotk3/gotk3/gtk"
    	"log"
    )
    
    func main() {
    	// Initialize GTK without parsing any command line arguments.
    	gtk.Init(nil)
    
    	// Create a new toplevel window, set its title, and connect it to the
    	// "destroy" signal to exit the GTK main loop when it is destroyed.
    	win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
    	if err != nil {
    		log.Fatal("Unable to create window:", err)
    	}
    	win.SetTitle("Simple Example")
    	win.Connect("destroy", func() {
    		gtk.MainQuit()
    	})
    
    	// Create a new label widget to show in the window.
    	l, err := gtk.LabelNew("Hello, gotk3!")
    	if err != nil {
    		log.Fatal("Unable to create label:", err)
    	}
    
    	// Add the label to the window.
    	win.Add(l)
    
    	// Set the default window size.
    	win.SetDefaultSize(800, 600)
    
    	// Recursively show all widgets contained in this window.
    	win.ShowAll()
    
    	// Begin executing the GTK main loop.  This blocks until
    	// gtk.MainQuit() is run. 
    	gtk.Main()
    }
    

    編譯此程式後執行:

    C:\> go build demo.go
    C:\> .\demo.exe
    

    要注意的是,如果在電腦上裝多套 C/C++ 編譯環境及一些函式庫,像是 Strawberry Perl 內附的 GCC,要把 msys2 所在的路徑向前移,才會正確呼叫到相對應的函式庫。