# CMake ## References + 🎬 [**奇乐编程学院 - CMake软件构建实战**](https://youtu.be/dIs7TFBDbIw) + 🔗 [**Wikipedia 教科書 - CMake**](https://zh.wikibooks.org/wiki/CMake_%E5%85%A5%E9%96%80) + 🔗 [**HackMD - CMake 專案建置**](https://hackmd.io/@kogiokka/ntou-cse-cpp-tutorial-02) ## Note |📘 <span class="note">NOTE</span>| |:---| |case insensitive| |📘 <span class="note">NOTE</span>| |:---| |CMake 所產生出來的 Makefile 無法獨立運作,建置過程仍然必須依賴 CMake,因此無法直接將 makefile 搬移到沒有 CMake 的環境中使用。事實上,只要更換環境就應該重新執行 CMake,針對目前環境配置產生 Makefile。| ## VScode Setting ```json= { "cmake.configureOnEdit": false, // CMake Tools 禁止 CMakeLists.txt 存檔自動構建 } ``` ## Configure 配置 CMake。\ 配置完後,你可以在 CMakeCache.txt 可找到一些配置的相關資訊。\ 一般而言,<mark>編譯器、Makefile 產生器會自動選擇全域可見的那些</mark>。 ### GUI 在 VScode 按 F7 自動構建。 ### CLI ```c cmake -S <專案目錄> -B <建置目錄> -G <Makefile 產生器> -D <變數>=<值> ``` ``` cmake -S . -B build -G "Unix Makefiles" ``` + `-S`:指定原始碼目錄(通常是專案的跟目錄) + `-B`:指定建置目錄(產生 Makefile 與執行檔的目錄) + `-G`:指定 Makefile 產生器 + `"Ninja"`:ninja + `"Unix Makefiles"`:make + `"NMake Makefiles"`:nmake + `"MinGW Makefiles"`:mingw32-make + `"Visual Studio 17 2022"`:MSVC (🚨 預設) + `-D`:設定變數 可於 CMakeLists.txt 中使用 `set` 指定。 + `CMAKE_C_COMPILER=gcc`:C 編譯器(gcc) + `CMAKE_CXX_COMPILER=g++`:C++ 編譯器(g++) + `CMAKE_BUILD_TYPE=Release`:建構型態(Release, Debug...) + `CMAKE_TOOLCHAIN_FILE=.../vcpkg.cmake`:套件管理器(vcpkg...) ```c cmake -P <腳本名稱> ``` + `-P`:將 CMake 檔案當成腳本執行 > 可單純作為試驗邏輯使用 ## Build 執行檔應位於 build 目錄頂層 ### CLI ``` cmake --build build ``` ## Example ### 範例 0 [單檔案](https://hackmd.io/@kogiokka/ntou-cse-cpp-tutorial-02#%E7%AF%84%E4%BE%8B%E3%80%87%E3%80%81%E7%B0%A1%E5%96%AE%E7%9A%84CMake%E5%B0%88%E6%A1%88) ### 範例 1 [多檔案](https://hackmd.io/@kogiokka/ntou-cse-cpp-tutorial-02#%E7%AF%84%E4%BE%8B%E4%B8%80%E3%80%81%E5%A4%9A%E5%80%8B%E5%8E%9F%E5%A7%8B%E7%A2%BC%E6%AA%94%E6%A1%88%E7%9A%84CMake%E5%B0%88%E6%A1%88) ### 範例 2 [靜態鏈結函式庫](https://hackmd.io/@kogiokka/ntou-cse-cpp-tutorial-02#%E7%AF%84%E4%BE%8B%E4%BA%8C%E3%80%81%E5%BB%BA%E7%AB%8B%E5%92%8C%E4%BD%BF%E7%94%A8%E9%9D%9C%E6%85%8B%E5%87%BD%E5%BC%8F%E5%BA%AB) ### 範例 3 [動態鏈結函式庫](https://jasonkayzk.github.io/2021/01/27/cmake%E7%94%9F%E6%88%90%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93dll/) 專案目錄結構 ``` Project3 ├── CMakeLists.txt ├── lib │ ├── CMakeLists.txt │ ├── my_dll.cpp │ └── my_dll.h └── main.cpp ``` CMakeLists.txt ```= cmake_minimum_required(VERSION 3.16) project(Project3) add_subdirectory(lib) ``` lib/CMakeLists.txt ```= set(LIBHELLO_SRC ./my_dll.h ./my_dll.cpp) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ../lib_out) # 動態鏈結函式庫 add_library(my_dll SHARED ${LIBHELLO_SRC}) install(TARGETS my_dll) set_target_properties(my_dll PROPERTIES LINKER_LANGUAGE C RUNTIME_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_NAME "my_dll" PREFIX "" ) ``` lib/my_dll.h ```cpp= #ifndef CPP_LEARN_MY_DLL_H #define CPP_LEARN_MY_DLL_H #define EXPORT_DLL __declspec(dllexport) extern "C" EXPORT_DLL int add(int a, int b); #endif // CPP_LEARN_MY_DLL_H ``` lib/my_dll.cpp ```cpp= #include "my_dll.h" int add(int a, int b) { return (a + b); } ``` run_dll.cpp ```cpp= #include <windows.h> #include <iostream> typedef int (*add)(int, int); int main() { HINSTANCE handle = LoadLibrary("./my_dll.dll"); auto f = (add) GetProcAddress(handle, "add"); std::cout << f(1, 32) << std::endl; FreeLibrary(handle); return 0; } ``` ## Commands ### basic + `set`:變數 ```= set(var hello) ``` ✅:foo 變數為 string list ```= set(foo this is a list) set(foo this;is;a;list) ``` + `messages`:標準輸出 ```= message(${var}) ``` + `math`:數學計算 ```= math(EXPR var "1 + 2 * 3") message("var = ${var}") # var = 7 ``` + `if` / `elseif` / `else` / `endif`:條件邏輯 ```= if(expr) command1(arg) elseif() command2(arg) else() command3(arg) endif() ``` + `foreach` / `endforeach`:迴圈 ```= set(V alpha beta gamma) message(${V}) # alphabetagamma foreach(i ${V}) message(${i}) endforeach() # alpha # beta # gamma ``` + `macro` / `endmacro` / function / `endfunction`:函式、巨集 ✅:function 會建立 local 變數,而 macro 則會影響 global 變數 ```= set(k 5) macro(mprint MESSAGE) set(k ${MESSAGE}) message(${MESSAGE}) endmacro(mprint) function(fprint MESSAGE) set(k ${MESSAGE}) message(${MESSAGE}) endfunction(fprint) message("k=${k}") # k=5 mprint("from mprint") # from mprint fprint("from fprint") # from fprint message("k=${k}") # k=from mprint ``` ### build + `add_subdirectory`:將指定目錄的 CMake 專案(內含 CMakeLists.txt)一起加入建置 ```= add_subdirectory(libstatic1/) ``` + `add_executable`:新增一個 CMake 目標,其為<mark>執行檔</mark> ```= add_executable(project-01) ``` + `add_library`:新增一個 CMake 目標,其為<mark>鏈結函式庫</mark> 靜態鏈結函式庫 ```= add_library(libstatic1 STATIC) ``` 動態鏈結函式庫 ```= add_library(my_dll SHARED ./my_dll.h ./my_dll.cpp) ``` + `add_definitions`:構建時,加入 preprocessor 定義 ```= add_definitions("-DFOO -DBAR") ``` + `target_sources`:構建 CMake 目標時,需要哪些源代碼(無須標頭檔) ```= target_sources(project-01 PRIVATE main.cpp f1.cpp f2.cpp ) ``` + `include_directories` / `target_include_directories`:添加<mark>標頭檔</mark>目錄 target 是針對特定 CMake 目標,現代較推薦後者。 ```= include_directories(${PROJECT_SOURCE_DIR}/external/headers) # 2. 再搜索一般情況 include_directories(BEFORE ${PROJECT_SOURCE_DIR}/include) # 1. 先搜索 BEFORE include_directories(AFTER /usr/local/include) # 3. 再搜索 AFTER ``` + `link_libraries` / `target_link_libraries`:添加<mark>鏈結函式庫</mark>目錄 target 是針對特定 CMake 目標,現代較推薦後者。\ 通常來自 `find_package` 或 `add_subdirectory`。 ```= target_link_libraries(project-02 PRIVATE libstatic1 ) ``` + `set_target_properties`:屬性控制編譯選項(若無給定,則採用全域預設值) ```= set_target_properties(my_dll PROPERTIES LINKER_LANGUAGE C RUNTIME_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_NAME "my_dll" PREFIX "" ) ``` + `include`:執行另一個 CMake 腳本 ``` include($ENV{IDF_PATH}/tools/cmake/project.cmake) ``` + [`find_package`](https://blog.csdn.net/zhanghm1995/article/details/105466372) ...
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.