# 使用CMake建置C++環境 碩漢的OOP是用Makefile的方式自動化編譯流程,但這樣有很多指令要自己寫,第三方套件設定環境也麻煩很多,因此我用CMake作為替代方案,如果不在乎CMake如何運作可以跳下面。CMake會透過寫好的設定檔產生出Makefile,除了新增依賴套件比較簡單,他也會自動產生出`.o`檔減少重複編譯沒有更改的檔案 ## 注意事項 <span style="color:red"> 1. 請把碩漢的PPT關掉,這篇教學跟碩漢的教學<b>完全</b>沒有關係<br> 2. 請仔細閱讀我辛苦寫出來的文字,我花了很多時間,請不要直接跳到指令部份複製貼上,你會失敗<br> 3. 請先瀏覽大綱跟FAQ </span> ## 聲明 雖然不同的Linux發行版之間理論上可以相容,但可能因為不同版本的問題導致一些我無法還原的錯誤或沒有考慮的邊緣測試狀況,所以在這裡提供我的系統資訊參考 ``` CPU: Intel i7-1165G7 Distro: Arch Linux Kernel: 5.19.9 Compiler: clang 14.0.6 CMake: 3.24.2 Generator: ninja 1.11.1 ``` ## tl;dr git clone cmake -B build cmake --build build OR 用VSCode打開,Shift + F5 ## 安裝套件 首先要在系統安裝以下套件 ``` cmake git gcc # 這不是指令請不要執行他 ``` 以下是各發行版的安裝指令(WSL預設是Ubuntu) ### Debian/Ubuntu/Linux Mint/Pop!_OS ``` sudo apt update sudo apt install git cmake build-essential ``` ### Arch Linux/Manjaro/EndeavourOS ``` sudo pacman -Syu sudo pacman -S cmake git base-devel ``` ### Fedora/RHEL/CentOS ``` sudo dnf update sudo dnf install cmake git gcc ``` > 其他發行版我沒用過自己Google ## 編譯/開發 到我的[Github Repo](https://github.com/NOOBDY/OOP)複製我的專案 ``` git clone https://github.com/NOOBDY/OOP.git ``` > 如果你是Garry,請不要`sudo git clone` 接著有兩種我常用編譯專案的方式可以任選 ### VSCode 用VSCode開啟專案資料夾(如果用WSL記得要安裝並用WSL模式開啟資料夾) 安裝[CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools)插件並啟用,如果偵測到檔案夾中有設定檔會選擇編譯器的視窗,點選想要的編譯器之後插件就會自動設定好所有需要的環境。 > 如果需要好的自動提示我個人推薦[clangd](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd)但詳細設定在這裡就不多提 如果一切進展順利畫面下方會出現如下圖的欄位  這時可以點選"Build"和執行icon旁邊"\[\<target>]"中的選項,選擇要編譯/執行哪個目標程式,OOP是在`./src/main.cpp:main()`中的主程式;ut_all是`./test`中的單元測試 選擇好了執行目標之後就可以按執行的icon(播放按鍵)或是<kbd>Shift</kbd>+<kbd>F5</kbd>快捷鍵,接著程式就會開始自動編譯,編譯完之後會將執行結果顯示在畫面下方的terminal當中  如果有更改程式,也只要重新按 <kbd>Shift</kbd>+<kbd>F5</kbd> 就可以看到更改後的結果 如果更改`CMakeLists.txt`,插件會自動偵測更新並更新環境,因此不需要多餘的動作,但如果需要手動更新,可以按 <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> 再搜尋"CMake: Delete Cache and Reconfigure" ### 指令行 `cd`進入資料夾並輸入 ``` cmake -B build cmake --build build ```   第一行指令會產生出編譯需要的檔案,第二行指令則是編譯專案並產生出執行檔 這時在專案中會出現`build`的資料夾,進去後會看到很多編譯用到的中繼檔案,此外還有兩個執行檔就編譯好的檔案  ``` ./OOP --- or --- ./ut_all ``` `OOP`是主程式的執行檔,他會執行在`./src/main.cpp:main()`裡的程式流程 `ut_all`是執行單元測試的執行檔,他會執行在`./test/`裡面所有的單元測試  > `--gtest_color=yes`只是讓他有漂亮的綠色輸出,他不是必要的flag --- 如果對專案程式進行更改要在回到專案根目錄執行 ``` cmake --build build ``` 如果對`CMakeLists.txt`進行更改則要輸入 ``` cmake -B build cmake --build build ``` > 如果想要使用`ninja`取代`make`可以打`cmake -B build -G Ninja` ## 更改CMakeLists.txt 在專案當中可以看到`CMakeLists.txt`的設定檔,這就是讓cmake知道如何編譯專案的設定檔,裡面大部分的設定都不需要更改(如果你不知道你在幹嘛你也不該更改),但如果有增加`.cpp`檔需要手動更改,讓cmake知道有新增檔案 用喜歡的編輯器打開檔案,到 ```cmake # CMakeLists.txt ... set(SRC src/HelloWorld.cpp include/HelloWorld.hpp ) set(INCLUDE_DIRS include/ ) ... ``` 的位置,在SRC下方的欄位輸入新增原始碼檔案的**相對路徑** 以VSCode為例  `Demo.cpp`和`Demo.hpp`是這次新增的檔案 CMakeLists.txt則應該改為如下 ```cmake # CMakeLists.txt ... set(SRC src/HelloWorld.cpp src/Demo.cpp include/HelloWorld.hpp include/Demo.hpp ) set(INCLUDE_DIRS include/ ) ... ``` 加入檔案的順序並不重要,但必須確認加入檔案的路徑正確,如果路徑錯誤cmake會無法設定 ## FAQ 我遇到XX錯誤,要怎麼解決? > ***請先閱讀錯誤訊息***,先試圖研究他錯在哪裡,如果真的遇到無法理解的問題我很樂意解決,但請不要出了任何錯誤都跑去找 厲害的同學™ 那碩漢要我們做的`sudo apt install libgtest-dev`呢? > ~~因為我覺得那個方式很破而且很容易出錯,~~ 基本上可以直接跳過那個步驟開始寫程式,畢竟這是OOP程式設計不是C\++環境架設課程,想理解細節的可以繼續往下讀,我的設定方式會把Google Test的程式複製到專案內部,編譯`*.a`檔案的流程也會包含在專案的編譯過程中,如此一來就不用在`/usr/src`中做一些危險的`sudo`操作 這在Windows/MacOS上可以用嗎? > 我沒有Windows電腦所以我不能確定,我也不想處理Windows環境問題,如果可以的話可以跟我說一聲,但不行的話請使用WSL;~~雖然我不能測試MacOS,但據我所知MacOS應該除了預設編譯器是`clang`以外環境跟Linux差不多,相容性應該不會有太大的問題~~ > 更:MacOS可以正常使用 為什麼專案裡的檔案架構跟碩漢教的不一樣? > 我猜碩漢目前可能為了簡化教學所以把函式定義寫到標頭檔裡面,但這在C/C\++是錯誤的使用方式(有的編譯器甚至會跳警告),因為我已經比較習慣C\++的開發,因此我使用我開發專案習慣的檔案架構,不過如果把碩漢寫的程式架構放進去也是可以運行的 我可以使用XX編譯器嗎? > 如果想要使用其他的編譯器(例如clang)也可以安裝,使用指令行時要先宣告環境變數`C=clang CXX=clang++ cmake -B build`;此外如果聽過`ninja`並想要使用可以執行`cmake -B build -G Ninja` 之後的自動作業檢查能用嗎? > 目前我還不確定碩漢的Jenkins如何設定,如果是呼叫寫死的`make`指令,我可以另外寫一個Makefile想辦法繞過他,但我可以找時間直接跟他討論看看能不能用我的替代方案 > 更:碩漢說如果想要可以安裝cmake環境,但檔案位置跟架構必須要跟作業要求一模一樣 為什麼你的指令行跟我的不一樣? > 因為我覺得預設的很醜,如果你想要加入Linux邪教歡迎找我
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up