close

貼上的影像_2020_11_1_上午2_58.png

在前一篇文章「Linux(Ubuntu)環境開發 C/C++ 應用程式」中已獲得使用微軟 Visual Studio Code for Linux 撰寫 Paho MQTT C/C++ Client 應用程式的能力,並寫了一支 MQTT Client Sample for C++ 放在 Github 上,後續也發現文章所說的建置方式:

  • 樹莓派的 Raspbian OS 上適用:今年 10 月 13 日,微軟 Visual Studio Code 支援 Linux ARM 32/64 平台。
  • 連 macOS 平台上建置方式也幾乎相同:(雖然少了 apt 套件管理,不過 apt 的指令大多數可用 Homebrew 替代 )。

突然意識到,Visual Studio Code 理所當然支援 Windows 平台啊!一定也能在 Windows 平台上這麼玩才對。如果能補足這個部分,那就滿足「一套原始碼,通吃 Windows / macOS / Linux (x86/64/ARM) 全平台」全制霸的目標。在以往所接觸過的領域中,雖然 Python/NodeJS (Javascript) 也做得到,不過 Python / NodeJS 本身並非原生運行,透過即時轉譯的效能比需編譯的 C/C++ 差,「全平台通吃」的程式碼,對於希望原始碼能以原生運行的意義上來說,還是有些不同。

為了攻克「在 Linux 上撰寫的 C/C++ 程式也能在 Windows 上運行」的目標,也就花了點時間研究。本來以為應該不難,沒想到還是繞了好大一圈,又踩了不少坑,所以這部分又值得寫一篇文章來好好抱怨一番,到底坑在哪裡。

上次寫的 MQTT Client Sample ,前提是必須先要有在 Linux 環境編譯安裝妥善的 Paho Mqtt C/C++ Library,所以若想要把程式碼原封不動搬到 Windows 上面編譯,就得先搞定在 Windows 平台上編譯安裝 Paho Mqtt C/C++ Library 。其實 Paho MQTT Client Library 的 Github 專案主頁(C / C++)也有稍微提到,透過跨平台的 CMake 工具即可在不同平台上進行編譯,只是沒有把詳細的做法寫出來。當我順著這個線索搜尋谷狗大神,確實找到了不少篇大同小異的中文教學,每篇都是圖文並茂,一切都很順利。

只是沒想到順著做下去,卻是採坑的開始。

網路找到的教學步驟就不多寫了,歸納一下踩到哪些坑:

  • 要下載並安裝超級肥大的微軟 IDE 開發神器 Visual Studio (注意:Visual Studio 與 Visual Studio Code 是不一樣的東西)。Paho 官網有提到,Visual Studio 版本必須大於 2015,下載安裝就耗掉一堆時間與大量硬碟空間,整套 Visual Studio 2015 離線版高達 46 GB。
  • 編譯產出的 .dll 與.lib 僅適用於 Visual Studio 開發環境,若做別的用途(非 Visual Studio 工具)則可能會出現相容性的問題。

我照著網路教學,透過 CMake -> Visual Studio 2015 -> 編譯產生了所需的 library / lib 等相關檔案之後,回到 Visual Studio "Code" 的環境裡,發現只有 C lib 可以 Link,而 C++ 的 lib 即使成功產出卻任何作用。最後終於是產出了執行檔,但用的卻是最粗暴的方法:把整套 Paho MQTT C++ Library 原始碼包進去一起編譯才成功,換句話說,最後一個部分 C++ 的 Library 等於沒有成功。

簡單的說,網路上的教學其實並沒有問題,問題是目標與用法不一樣。倘若你是想要用 Visual Studio 開發 Windowss 平台 C++ 的 Mqtt Client 應用,網路教學教你用 Visual Studio 編譯 Paho MQTT Client C/C++ Library 的方式適合你。倘若不是使用 Visual Studio 開發,並且你的 C++ Mqtt Client 應用的程式碼希望能跨平台編譯與運行,那麼就看以下的作法,因為網路教學會反而會讓你不小心踩坑。

光是下載安裝肥大的神器 Visual Studio 就耗掉不少時間與硬碟空間,千辛萬苦搞到最後一步還採坑,這過程實在是太虐心、太淚人...

好了,牢騷發洩完畢,後面開始來講正題。

這次的操作作法主要是兩個重點:

  • 在 Windows 平台上建構「類 Linux 」的編譯環境。
  • 在 Windows 平台的「類 Linux 」編譯環境下編譯 Paho MQTT Client C/C++ Library。

準備工作:

  • Windows 7 / 10 [此字元已经遮蔽]bit
  • Internet 網路環境

以下是操作步驟。

Windows 平台上建構「類 Linux 」編譯環境

什麼叫「類 Linux 」的編譯環境?這名詞我忘了是在哪看到了,似乎沒有嚴格的定義,純粹就字義上的說法,Linux 環境下的編譯指令不外乎就 gcc,g++,make,cmake ... 這些,打開終端機直接輸入指令參數就能編譯,而 Windows 預設環境下是沒有這些東西的。

所以這部分的目的是,打造出一個 Windows 環境下,有這些 Linux 常用編譯指令的操作環境。

1. 下載並安裝相關工具套件

  • MinGW-w64:上面提到 Linux 環境的 gcc / g++ ...等編譯指令程式,有大神已經把對應 Windows (64 bit) 版本的全做好了。安裝時選 x86_64,其他一直按 Next(下一步)就行了。

螢幕擷取畫面 2020-10-31 153729.png

截圖 2020-10-31 下午3.42.25.png

  • OpenSSH (64-bit):編譯 Paho MQTT C/C++ Libraries 會用到的套件,要下載「Win64 OpenSSL v1.1.1h」完整版( 63MB Installer 沒有 lite 的版本)。

如果出現說缺少什麼 「Visual C++ 201x Redistributables 」(即 Visual C++ 201x 可轉發套件)之類的,選擇是,跟著指示下載安裝 VC_redist.x64.exe ,再重新執行一次 OpenSSH 的安裝程序並依指示操作。

貼上的影像_2020_10_31_下午3_54.png

以下可選擇要、或不要下載安裝:

  • Doxygen:可依照程式碼內容,自動產出說明文件的工具,我是選擇下載安裝 doxygen-1.8.20-setup.exe 。後面會提到是否產出文件,若有勾選的話,就一定要安裝這個。

工具的下載安裝步驟的其他細節就不細說了。全部安裝完畢之後,一定要做兩個非常重要的動作(非常重要!)

  • 把工具的執行檔路徑加入 Windows 的環境變數 Path 中。
  • 將 mingw32-make.exe 複製為 make.exe。

第一個重要動作:以 Windows 10 為例,執行「控制台 - 所有控制台項目 - 系統」(或是桌面的電腦圖示「本機」按右鍵-內容):

貼上的影像_2020_10_31_下午3_47.png

進階 -> 環境變數

貼上的影像_2020_10_31_下午3_49.png

貼上的影像_2020_10_31_下午4_04.png

貼上的影像_2020_10_31_下午4_08.png

按照各工具套件的安裝程序預設值,路徑如下

  • C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin
  • C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\x86_64-w64-mingw32\bin

上兩個是 MinGW-w64 的兩個工具路徑,可以把它分別想像成 Linux 環境下的 /usr/bin 跟 /usr/local/bin ,該目錄底下就有 gcc / g++ / ... 這些指令執行程式。

  • C:\Program Files\OpenSSL-Win64\bin
  • C:\Program Files\CMake\bin
  • C:\Program Files\doxygen\bin

如果在工具套件的安裝過程中有另外給定安裝路徑,則 Path 的內容也要跟著改變。例如若把 OpenSSH 裝在 C:\OpenSSL 時,Path 也要改成 C:\OpenSSL\bin。

第二個重要動作:[MinGW-w64 安裝路徑]\mingw64\bin 底下有個執行檔 mingw32-make.exe,用複製的方式產生另一個執行檔名 make.exe。

截圖_2020-10-31_下午4_19_12.png

2. 測試「類 Linux 環境是否能正常運作」

執行「命令提示字元」,先 echo %Path% 看輸入的路徑是否生效,以及輸入 g++, gcc, cmake,make 等指令看看是否有運行的回應。

貼上的影像_2020_10_31_下午4_29.png

若顯示「xxx 不是內部、外部命令ooxx...」等類似找不到指令的錯誤,表示上述安裝與設定工具套件的過程中有誤,請仔細檢查上面的步驟,否則後面的步驟會出錯。

Windows 平台的「類 Linux 」編譯環境下編譯 Paho MQTT Client C/C++ Library

1. 下載 Paho MQTT Client C Library 與 Paho MQTT Client C++ Library 原始碼

Linux 環境有 git clone 指令可下載,Windows 環境得另外安裝 Git 的工具。若不想這麼麻煩,可直接使用瀏覽器,從 Github 專案首頁,點選 Code 的綠色下載按鈕 -> Download ZIP。C 跟 C++ 兩個都要下載。

Paho MQTT Client C Library
Paho MQTT Client C++ Library

貼上的影像_2020_10_31_下午11_05.png

下載兩者之後(paho.mqtt.c-master.zip 與 paho.mqtt.cpp-master.zip),請各自解壓縮到不同的目錄(例如以下說明中出現的 z:\paho.mqtt.c-master 與 z:\paho.mqtt.cpp-master)。

C 跟 C++ 下載原始碼之後,接著就是編譯這些原始碼的工作。前一篇文章說到,要先編譯 C Library,再編譯 C++ Library,因為 C++ 依附在 C 之上。

2. CMake GUI 設定 Paho MQTT Client C Library

終於輪到 CMake GUI 登場。強烈建議每次啟動 CMake GUI 時,先執行一次 Delete Cache 的動作,免得後續的操作出問題。

貼上的影像_2020_11_1_上午12_11.png

緊接著看圖說故事:設定的方式很重要,所以會用大量的圖片說明...

主畫面 1. Browse Source 選擇 C Library 原始碼目錄 -> 2. 直接輸入原始碼目錄+ 「/build」(這個目錄一開始並不存在)-> 3. 左下角 Configure 按鈕。

貼上的影像_2020_10_31_下午11_33.png

提示 build 目錄不存在,選擇「Yes」讓它自動產生。

貼上的影像_2020_10_31_下午11_39.png

接下是重點了。

貼上的影像_2020_10_31_下午11_44.png

這裡就是先前踩坑的開始。Paho MQTT Client Library 的 Git 專案首頁有說到要選擇 Visual Studio 2015 以後的版本,而網路教學也全都這麼說,只是這項操作並不符合「Windows 系統的類 Linux 編譯環境」的設定。

正確設定如下:

貼上的影像_2020_10_31_下午11_53.png

貼上的影像_2020_10_31_下午11_56.png

接著流程會回到設定主畫面,自動帶入 Entry 項目與相關訊息。

貼上的影像_2020_10_31_下午11_59.png

如果對紅色底有強迫症的話,可以再按一次 Configure 消除紅底。

貼上的影像_2020_11_1_上午12_09.png

將 1. PAHO_WITH_SSL 勾選,2. 再按一次 Configure,

貼上的影像_2020_11_1_上午12_19.png

會再出現新的 Entry 項目「OPENSSL_ROOT_DIR」,底下的訊息顯示 Found OpenSSL: [路徑]/bin/libcrypto.lib (found version "x.x.xx"),

貼上的影像_2020_11_1_上午12_21.png

如果不懂 Entry 項目如何設定的話,只要滑鼠移到 Entry 項目上,會跳出該項目的說明。

截圖_2020-11-01_上午12_28_01.png

以這個新跳出的 OPENSSL_ROOT_DIR 為例,要選擇包含 OpenSSL 的 libraries 與 includes 的目錄。顧名思義,也就是先前安裝 OpenSSL 的根目錄(預設是 C:\Program Files\OpenSSL-Win64 ),

貼上的影像_2020_11_1_上午12_35.png

最後,Entry 項目設定值如下:

貼上的影像_2020_11_1_上午12_45.png

Entry 重點項目說明如下:

CMAKE_INSTALL_PREFIX     : 編譯完成之後,安裝的目錄位置。要特別注意的是, Windows 10 作業系統下,C:\Program Files (x86)、C:\Program Files、C:\Windows 等一些系統重要目錄都有權限限制,無法隨意寫入,所以建議修改至有寫入權限的目錄下(例如上圖中的 C:\mqtt\Eclipse Paho C,目錄不存在時會自動產生)。
PAHO_BUILD_DOCUMENTATION : 是否產生文件檔。勾不勾選皆可。若勾選,須事先安裝 Doxygen 否則後面會出錯。
PAHO_BUILD_SAMPLES       : 是否編譯範例程式。勾不勾選皆可。
PAHO_BUILD_SHARED        : 是否編譯鏈結檔。勾選。
PAHO_BUILD_STATIC        : 是否編譯靜態鏈結檔。勾不勾選皆可。
PAHO_ENABLE_TESTING      : 是否產生測試單元,不要打勾,否則編譯會出錯。
PAHO_WITH_SSL            : 是否編譯 SSL 鏈結檔。建議勾選,免得後續無法產生所需的編譯檔案。

設定完之後,先按 Configure 再按 Generate。若沒有出現錯誤提示之類的話,C Library 的 CMake 設定工作就算完成了。

以上用了大量圖片說明,原因是 CMake GUI 介面簡單但沒有用戶導引指南,透過介面很難知道操作流程怎麼做。

3. 編譯 Paho MQTT Client C Library

上述的動作完成之後,接著是進行編譯。開啟新的命令提示字元視窗,移動到 Paho MQTT Client C Library 目錄(例如示範的 Z:\paho.mqtt.c-master),執行一串指令:

cmake --build build/ --target install

貼上的影像_2020_11_1_上午1_26.png

輸數完按 Enter,接著就會運行 cmake 編譯程序,大約幾十秒到幾分鐘的時間。

貼上的影像_2020_11_1_上午1_32.png

若一切順利沒有跳出錯誤訊息的話,就能在安裝目錄(c:\mqtt\Eclipse Paho C)看到最後編譯出來的成果。

貼上的影像_2020_11_1_上午1_37.png

bin 是 .exe 與 .dll 檔案, include 是標頭檔(.h),lib 是 library 檔(.a)。

4. 設定與編譯 Paho MQTT Client C++ Library

輪到設定編譯 Paho MQTT Client C++ Library (paho.mqtt.cpp),做法跟 C Library 大同小異,以下操作步驟只說重點。

CMake 導入 Paho MQTT Client C++ Library (paho.mqtt.cpp)時會出現兩個錯誤:

貼上的影像_2020_11_1_上午1_49.png

PAHO_MQTT_C_INCLUDE_DIRS-NOTFOUND  : 選擇編譯安裝完成的 include 目錄
PAHO_MQTT_C_LIBRARIES-NOTFOUND     : 選擇編譯安裝完成的 libpaho-mqtt3a.dll.a 檔

這裡就必須用到 C Library 的編譯成果了。

CMake GUI 的設定如下:

貼上的影像_2020_11_1_上午1_57.png

開啟命令提示字元視窗,移動到 Paho MQTT Client C++ Library 目錄(例如示範的 Z:\paho.mqtt.cpp-master),執行一串指令:

cmake --build build/ --target install

貼上的影像_2020_11_1_上午2_04.png

5. 將編譯完成的 Paho MQTT Client C/C++ Library 相關檔案放到對應類 Linux 的實體目錄

編譯 C / C++ Library 的結果會安裝在指定的 CMAKE_INSTALL_PREFIX 設定目錄中,不過「類 Linux 環境」卻不一定能直接找到這些檔案,所以要把這些檔案移動(或複製)到特定的目錄。

Paho C Libraries 的部分(上述示範的安裝位置 C:\mqtt\Eclipse Paho C):
bin\*.dll(與*.exe)   -> 複製到 [MinGW-w64 安裝目錄]\x86_64-w64-mingw32\bin
include\*.h -> 複製到 [MinGW-w64 安裝目錄]\x86_64-w64-mingw32\include
lib\*.a     -> 複製到 [MinGW-w64 安裝目錄]\x86_64-w64-mingw32\lib

Paho C++ Libraries 的部分(上述示範的安裝位置 C:\mqtt\Eclipse Paho CPP):
bin\*.dll(與*.exe) -> 複製到 [MinGW-w64 安裝目錄]\x86_64-w64-mingw32\bin
include\mqtt\*.h -> 複製到 [MinGW-w64 安裝目錄]\x86_64-w64-mingw32\include\mqtt
lib\*.a     -> 複製到 [MinGW-w64 安裝目錄]\x86_64-w64-mingw32\lib

注意:C++ 的 是 mqtt 目錄,要連同目錄一併複製過去。這些複製的動作,相當於 Linux 環境下把編譯結果安裝到 /usr/local/bin 、/usr/local/include、/usr/local/lib。後續在這個類 Linux 環境撰寫程式時,就能被直接使用。

檢視複製結果:

bin:

貼上的影像_2020_11_1_上午2_15.png

lib:

貼上的影像_2020_11_1_上午2_17.png

include:

貼上的影像_2020_11_1_上午2_18.png

至此,Windows 平台的「類 Linux 編譯環境」中,Paho MQTT Client C/C++ Library 的編譯與安裝工作就完成了。

6. 測試

在測試之前,若環境中沒有 MQTT Broker 服務的話,可以在 Windows 環境下快速建一個 MQTT Broker:

Windows 平台安裝完 mosquitto 之後並不會立刻被啟動,必須要重開機。若不想重開機,可以到「服務」(開始功能表 - Windows 系統管理工具 - 服務)把該項服務啟動。

貼上的影像_2020_11_1_上午2_35.png

下載我寫的 MQTT client for c++ Sample

測試編譯與執行:開啟命令提示字元,切換到範例的目錄,輸入指令:

make run

貼上的影像_2020_11_1_上午2_42.png

編譯成功之後自動運行

貼上的影像_2020_11_1_上午2_43.png

相同的一套 Mqtt Client C/C++ 程式碼,透過相同的 make run 編譯與執行指令,就可以在 Linux / macOS / Windows 上面編譯與原生運行。

當然了,也一樣可以透過微軟的 Visual Studio Code 對這個範例程式進行開發撰寫,操作方式幾乎一模一樣。

貼上的影像_2020_11_1_上午2_58.png

這個範例程式的程式 Makefile 與 .vscode 設定有做了一些調整,所以可跨平台使用相同的 make 編譯指令,也支援不同平台上的 Visual Studio Code (VSCode) 進行開發。有興趣的人可以參考看看。

最後再發個牢騷:實在不太想寫有關 Windows 的操作步驟。 Linux 大多用指令命令執行,操作步驟時把指令列出複製貼上即可,但 Windows 的操作步驟卻不能這麼搞,大多得圖文對照才能清楚表達操作方式,寫起來真的很累人。

補充說明:MSYS2 架設類 Linux 開發環境

上面提到使用 MinGW-w64 架設「 類 Linux 」環境,雖然是方便不少。不過倘若要開發別的套件,這玩意可能就苦手了。例如想要開發一個跨平台連結 MySQL 或 SQLite 資料庫的 C/C++ 程式,但 MinGW-w64 的預設安裝套件並未包含相關的 Lib 驅動函式庫,就會變得很麻煩,需下載驅動的原始碼自行在 MinGW-w64 環境下編譯,有時還不一定能編譯成功,因為還有可能又少了什麼套件。所以說 MinGW-w64 不一定好用。

所幸還有另一個「類 Linux」的套件:MSYS2。它提供了更接近 Linux 的環境。應該這麼說吧,上面 MinGW-w64 架構出來的環境,只能算是 MSYS2 的其中一部分而已。這篇文章有關於 MSYS2 更詳細易懂的說明。以下我只把重點挑出來寫。

安裝 MSYS2 之後,有三個子環境:

  • MSYS:這個就是類 Linux 的命令操作環境。它可以用來安裝設置自身(MSYS)、MinGW 32bit、MinGW 64bit 三種環境配置。
  • MinGW 32bit:類 Linux 的 32 位元版。
  • MinGW 64bit::類 Linux 的 64 位元版。上面提到的 MinGW-w64 就是這個部分。

所以,如果要更完整的「在 Windows 建置開發跨平台 C/C++ 方案」,使用 MSYS2 會是比較妥善且相對正確的方法。

1. 安裝 MSYS2:到官網下載,安裝後開始功能表會有三個項目。

貼上的影像_2021_1_15_下午3_57.png

安裝完之後,第一次執行要先做起始化與更新。

執行 MSYS2 MSYS,會出現命令列視窗,執行

$ pacman -Syu

更新完,重開 MSYS2 MSYS,再執行

$ pacman -Su

需要一些時間做下載與更新,之後便完成起始化 MSYS2 的動作。

pacman 的指令介紹

1. 安裝套件

$ pacman -S 套件名稱

例如:安裝 MySQL Client 套件(即 MariaDB Client)

$ pacman -S mingw-w64-x86_64-libmariadbclient

2. 移除套件

$ pacman -R 套件名稱

3. 搜尋套件

$ pacman -Ss 關鍵字

例如:搜尋 mariadb

$ pacman -Ss mariadb

回應

mingw32/mingw-w64-i686-libmariadbclient 3.1.11-1
    MariaDB client libraries (mingw-w64)
mingw64/mingw-w64-x86_64-libmariadbclient 3.1.11-1
    MariaDB client libraries (mingw-w64)

有兩個結果。

倘若不想用搜尋套件指令的話,這裡有 Web 版。其餘 pacman 的用法,可參考官方 Wiki

這裡提到的「套件」,其實也是前輩大大編譯過對應 Windows 版的套件檔。真的該感謝前輩大大們,花時間把 Linux 的套件一個一個編譯成 Windows 版,再發明了 MSYS2 讓更多碼農們方便安裝與佈屬,省去不少做苦工的時間。

僅憑藉 pacman 指令,就可以建構出更接近 Linux 的環境,例如安裝 git、openssl(mingw-w64-x86_64-openssl)、doxygen(mingw-w64-x86_64-doxygen),最後記得在 Windows 的 Path 環境變數把 C:\msys64\mingw64\bin 和 C:\msys64\usr\bin 加進去即可。

套件名稱

以上面 mingw64/mingw-w64-x86_64-libmariadbclient 3.1.11-1 為例,mingw64 是類別,表示這個套件是 MinGW 64-bit。而後面 mingw-w64-i686-libmariadbclient 是完整的套件名。3.1.11-1 是版本。

使用範例

再以本文內提到開發 MQTT for C/C++ 應用程式,所需要的 gcc/g++、make、cmake 等工具,使用 MSYS2 佈屬環境的方式如下:

1. 安裝 Toolchain 套件組

$ pacman -S mingw-w64-x86_64-toolchain

mingw-w64-x86_64-toolchain 其實是套件的群組名,會跑出一大堆名單

貼上的影像_2021_1_15_下午4_53.png

全部都安裝的話會消耗大量的硬碟空間與網路時間,所以輸入對應的號碼即可。gcc/g++ 是 3,make 是 15。

2. 安裝 cmake 與 cmake-gui

$ pacman -S mingw-w64-x86_64-cmake
$ pacman -S mingw-w64-x86_64-qt5

3. 工具的執行檔路徑 C:\msys64\mingw64\bin 加入 Windows 的環境變數 Path 中,以及 C:\msys64\mingw64\bin 底下的 mingw32-make.exe 複製為 make.exe。這樣 MQTT for C/C+ 的環境就弄好了。

後續可依照上文「Windows 平台的「類 Linux 」編譯環境下編譯 Paho MQTT Client C/C++ Library」的內容,在 Windows 環境開始進行編譯與開發 MQTT for C/C++ 應用程式。

 

 

 

arrow
arrow
    創作者介紹
    創作者 benjenq 的頭像
    benjenq

    -Ben's PHOTO-

    benjenq 發表在 痞客邦 留言(0) 人氣()