Visual C++ 的 Linux MSBuild 專案

| | 0 Comments| 13:13
Categories:

之前已經大致上介紹了在 Visual Studio 中要開發 Linux 上的 C++ 程式的概念,接下來就先來針對最基本的、MSBuild 形式的專案來介紹一下吧。

首先,這邊在要建立專案的時候,建議把上面的過濾器切換成「C++」、「Linux」,然後可以選擇「主控台應用程式」或是「空白專案」來開始。

這兩者的差別,其實就只是「主控台應用程式」會多建立一個 hello world 等級的 main.cpp 而已。

下面就是「主控台應用程式」建立出來的專案:

而這樣建立出來的專案基本上會滿接近本來 Visual C++ 的專案的,實際上也會有對應的方案檔(solution、.sln)和專案檔(project、.vcxproj);而在方案總管裡面、在專案後面也會特別標註是 Linux 用的。

不過在專案中,預設不會在方案總管裡面建立出把 .h.cpp 分開管理的樹狀結構,所以不會有 .filter 檔,有需要的話可以自己建立。


設定專案使用的建置環境

專案建立好了之後,他預設會是使用遠端 Linux 的 g++ 環境來做開發,如果想要修改設定的話,就需要在方案總管中、選取專案後點選滑鼠右鍵、然後選「屬性」、進去調整了。

在屬性視窗中,點選左邊的「一般」後,可以找到「平台工具組」(platform toolset)的選項,它裡面會有六種不同的設定可以使用:

平台的部分分成 Remote Linux、WSL2、Windows Subsystem for Linux 三種;每種平台都可以選擇要使用 GCC 或 Clang 來作為建置工具。

如果平台是選擇 Remote Linux 的話,就是使用 SSH 連線到遠端電腦,這時候就要在下面的「遠端組建電腦」中、選擇要使用的 Linux 伺服器了。

此外,下方也還有一個「遠端根目錄」,預設是「~/projects」,它代表的就是 Visual Studio 會把專案複製到 Linux 的使用者目錄下的「projects」目錄裡面,如果不想放在這邊的話也要記得修改。

在這樣設定後,工具列偵錯的部分,就會顯示遠端電腦的資訊了。

而如果選擇 WSL2 和 Windows Subsystem for Linux(這個應該是 WSL1)的話,下面的選項則會變成「WSL Distro 名稱」,如果系統上有多個 WSL 實體的話,則可以在這邊選擇。

在選擇使用 WSL 或 WSL2 的話,工具列的偵錯部分會變成顯示「GDB 偵錯工具」。

比較基本的建置環境大概就是這樣了,還有一些比較細節的,有的就等到之後再講了。


偵錯環境

前面講的是程式建置(編譯)的部分,而實際上 Visual Studio 是允許建置環境和偵錯環境採用不同的設定的。

實際上,如果「平台工具組」選擇的是 Remote Linux 的話,那在專案的「屬性」視窗中的「偵錯」裡面,偵錯工具會是「遠端 GDB 偵錯工具」。

這邊有一個「遠端偵錯電腦」的選項、可以選擇要用哪台 Linux Server 來偵錯;而選擇的電腦可以和前面用來建置的電腦不相同,這時候,他會把建置出來的檔案複製到這台電腦來執行、並進行偵錯。

此外,這也可以選擇「偵錯模式」,這邊有 gdb 和 gdbserver 兩個選項,根據官方文件的說法,gdb 應該會比較好。

而如果是使用 WSL 來建置的話,那偵錯工具會變成是「GDB 偵錯工具」,預設的「遠端偵錯電腦」會是「使用 WSL 進行偵錯」。

比較有趣的,是這個方案還是可以把要進行偵錯的遠端電腦修改成其他設定好的 Linux 伺服器。

這樣做主要的好處,應該是可以在比較高階的電腦上面進行建置、然後自動佈署到比較低階的目標機器(例如 IoT)來進行偵錯。


開始使用

經過上面的設定後,理論上對於比較簡單的應用程式行專案(建置出可執行檔),應該就可以使用了!而使用的方法,也會和一般 Windows 的專案一下,可以透過 F5 來執行建置、偵錯,同時,中斷點、監看值、呼叫堆疊等功能,也都是可以使用的!

下面就是一個偵錯時、停在中斷點的示意圖:

這邊和一般 Windows 程式不同的地方、是 Visual Studio 不會開一個 console 視窗(現在應該都是「終端機」)來顯示輸出的結果、而是會把標準輸出(std::cout)的東西透過一個「Linux 主控台」來輸出;而如果有要透過標準輸入(std::cin)來輸入的話,也是要在這個「Linux 主控台」輸入。

在 Heresy 這邊測試的話,以 WSL 來開發的話應該沒什麼大問題;但是如果是 Remote Linux 的話,不確定是什麼問題,但是應該是在建置完要部屬的時候、會卡在那邊一段時間、Visual Studio 會沒有反應,有點討厭。


其他編譯參數

上面都是先採用 Visual Studio 給的預設值來跑,而如果想要調整建置的參數的話,則是和 Windows 專案一樣、可以透過修改專案「屬性」裡面的「C/C++」與「連結器」的設定來進行。

像是以要修改使用的 C++ 標準的版本來說,可以「C/C++」下的「語言」找到;他預設會是使用 C++11,還滿舊的。

而像是 include 目錄、或是要 link 的函式庫這類的設定,基本上也就是和本來 Visual Studio 的 Windows C++ 設定方法幾乎一樣,只是要記得使用 Linux 的路徑形式(/)、同時要連結的 lib 檔案也會變成 Linux 的形式了~(例如 libpng 用來連結的檔案是「libpng.a」、只需要給「png」就可以)

其他像是最佳化參數的部分,Debug 版預設會是「-O0」、Release 版則是「-O3」,都可以自己根據需要修改。

而如果要看 Visual Studio 最後使用的編譯命令的話,則也可以透過「C/C++」的「命令列」來確認。

此外,在「C/C++」的「一般」中,還有一個「平行編譯作業數上限」,應該是用來設定要開幾個執行序來進行平行編譯的;他預設只給 1,如果是大型專案的話,應該是得調高一點來加速編譯?


函式庫型專案

按照前面的方法建立的專案基本上都會是應用程式、也就是可執行檔。而如果是要建立一個函式庫型的專案的話,則建議可以先建立一個「空白專案」來調整。

要改的東西也很簡單,就是在專案「屬性」的「一般」裡面,找到「組態類型」來做切換就可以了。

這邊預設會是「應用程式 (.out)」,如果要改成函式庫的話則可以選擇「動態程式庫 (.so)」或「靜態程式庫 (.a)」;這兩者對應的基本上就是 Windows 上的 .dll 和 .lib 了~

而同一個方案裡的應用程式要使用這個函式庫專案也很簡單,和 Windows 的專案一樣,只要在應用程式的專案上面點選滑鼠右鍵、然後按「加入」、「參考」,然後把要使用的專案勾起來就好了。

這樣一來,Visual Studio 就會針對程式碼的變動,自動去更新、建置了!

至於 Makefile 這個組態的部分,預計是之後會另外整理一篇。


IntelliSense 處理 Linux 端的 header 的機制

要使用 Visual Studio 來進行開發,主要是為了他的 IDE 提供的各項輔助功能,比如說自動完成、錯誤提示之類的。

而實際上,為了讓 Visual Studio 的 IntelliSense 能在開發 Linux 程式的時候也能正確運作,他會將 Linux 主機標準的 include 資料夾複製一分到 Windows 這邊來,以作為 IntelliSense 分析之用、或是讓使用者可以打開來看。

這邊他使用的路徑是:C:\Users\Heresy\AppData\Local\Microsoft\Linux\HeaderCache (使用者名稱請自行更換),底下每一個資料夾是對應不同的系統。

這邊他預設會複製的資料夾,應該是:

  • /home/USERNAME/projectes:遠端根目錄,在屬性中更改
  • /usr/include:系統預設的 header 檔案位置
  • /usr/local/include:使用者自己的 header 檔案位置
  • /usr/lib/gcc/x86_64-linux-gnu/11/include:gcc 的 header 檔,會因為版本而不同

理論上,如果是透過 apt 安裝、或是有按照標準來寫安裝腳本的第三方函式庫,他們的 header 檔應該都會在 /usr/include/usr/local/include 裡面、不需要另外處理。

像是如果透過「apt install libmsgsl-dev」安裝微軟提供的 GSL 實作的話,他的 header 會被安裝在「/usr/include/gsl」裡,理論上會是在 Visual Studio 的處理範圍內。

而如果是自己建置的函式庫、檔案不是放在上面的預設目錄的話,則可以在專案「屬性」的「一般」裡面,找到「遠端複製包含路徑」、在裡面加上要額外複製的路徑:

不過這邊要注意,在中文版的 Visual Studio 裡面應該是自動翻譯的錯誤,所以會有兩個「遠端複製包含路徑」;第一個是包含(include)、第二的則是「排除」(exclude),要確認的話可以仔細確認該視窗下面的說明。

如此一來,他就會把這邊指定路徑下的檔案也複製一份到 Visual Studio 的快取裡面來做分析之用了。

而感覺上 Visual Studio 本身不會自動更新這部分的檔案,所以如果遠端 Linux 的檔案有新增、更新的話,則可以透過專案右鍵選單裡的「重新掃描解決方案」來強制更新。

或者,在 Visual Studio 的設定裡面,找到「跨平台」、「連線管理員」、「遠端標頭 IntelliSense 管理工具」裡面,也可以針對指定的遠端 Linux 機器要求更新。(不過 WSL 不能用這個方法)


一些碰到的問題

這邊 Heresy 在使用上,也有碰到一些問題,這邊也稍微紀錄一下。

「平台工具組」切換到 WSL 後再切回 Remote Linux 會不能偵錯

原因不清楚,感覺是切過去後再切回來的時候,偵錯工具會被卡死、沒有更新,導致沒辦法進行偵錯。

解決方法:重新開啟方案。

方案中的跨專案 include

在 Windows 專案的時候,如果一個方案有多個專案的情況下,Heresy 個人是習慣透過 Visual Studio 提供的「$(SolutionDir)」這個巨集(代表 .sln 的位置)、來設定專案間相對的路徑;在設定 include 路徑的時候,用這個巨集會滿方便的。

不過在 Linux 專案上,透過 $(SolutionDir) 來設定 include 路徑雖然在 IDE 裡面看起來是能正確找到檔案,但是在建置時會出現找不到 header 檔的問題。

這邊的解決方法是除了加入 $(SolutionDir) 外,另外再加入 $(RemoteRootDir) 給 Linux 環境使用。

不過這個解法其實有點微妙。因為如果是 remote Linux 的環境下,在 Visual Studio 裡面在程式碼裡面去開啟檔案的話,可能會變成是打開從遠端撈回來的檔案;這個時候如果需要編輯的話,可能會因為編輯到錯誤的檔案造成混淆。(WSL 似乎沒這個問題)

同名專案的問題

個人覺得有點微妙的問題。由於 Visual Studio 在將專案複製到遠端的時候,並沒有方案這一層的資料夾,而是把專案都放在 ~/projects 下,所以如果有兩個方案裡面有同樣名稱的專案,那遠端電腦的專案資料夾可能會出現打架的問題。


這邊基本上就先寫到這樣了~理論上,這樣已經可以透過 Visual Studio 在 Linux 上開發程式了~

不過 Heresy 個人這邊還有幾點沒能找到答案:

  • 有沒有辦法在不透過 Visual Studio 的狀況下、直接在 Linux 環境下建置?如果可以的話,其實會滿方便的?
  • 這種類型的專案感覺在架構上,Windows / Linux 的差異不大、頂多就是設定插了比較多而已。不知道有沒有可能在兩者皆轉換、或是直接把兩種專案的組態合併成單一專案?這樣要開發跨平台專案會更方便,不需要維護兩種平台。

本系列目錄:

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *