CMake 常用命令和变量
前言
前面的文章介紹了一個最簡單的CMake工程,這篇文章將介紹一個稍微復雜一些的CMake工程,結合這個工程總結一下在組織一個C/C++工程時最為常用的一些CMake命令和變量。對于涉及到的命令和變量,介紹的原則是點到即止,先僅需掌握基本用法即可,讓工程跑起來。
上一篇文章中那個最簡單的CMake Hello World工程,在其CMake腳本文件CMakeLists.txt中,僅有一句話:
add_executable(hello hello.cpp)這里面的add_executable就是一個CMake命令,它的作用是添加一個可執行文件構建目標。
下面從一個C++應用程序的編譯過程為脈絡對涉及到的命令和變量進行說明。
為了讓下面的說明舉例更加容易理解,先給出本文的示例工程目錄結構:
? /Users/sunyongjian1/codes/local_codes/cmake_test tree . ├── CMakeLists.txt ├── include │?? └── util.h ├── lib │?? └── libutil.a └── src└── main.cpp三個文件夾: include, lib, src分別存放包含文件,庫文件,源文件;一個CMakeLists.txt腳本。下面我的任務是編寫這個腳本,使得工程包含util.h頭文件,編譯main.cpp, 鏈接libutil.a, 最終生成一個可執行文件hello.
給工程起個名字
加上這句:project(hello)
解釋
命令:project(<PROJECT-NAME> [LANGUAGES] [<language-name>...])
作用:定義工程名稱, 設置幾個變量的名字:?PROJECT_NAME, PROJECT_SOURCE_DIR, <PROJECT-NAME>_SOURCE_DIR, PROJECT_BINARY_DIR, <PROJECT-NAME>_BINARY_DIR, 高級用法請見參考鏈接2:CMake命令
讓CMake找到我的頭文件
加上這句:include_directories(./include)
作用:把當前目錄(CMakeLists.txt所在目錄)下的include文件夾加入到包含路徑
我習慣這樣寫:include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
解釋
命令:?include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
作用:
-
把dir1, [dir2 …]這(些)個路徑添加到當前CMakeLists及其子CMakeLists的頭文件包含路徑中;
-
AFTER 或者 BEFORE 指定了要添加的路徑是添加到原有包含列表之前或之后
-
若指定 SYSTEM 參數,則把被包含的路徑當做系統包含路徑來處理
第二種寫法里用到了CMAKE_CURRENT_LIST_DIR這個變量,它表示當前CMakeLists所在的路徑.
讓CMake找到我的源文件
加上:?aux_source_directory(./src ${hello_src})
作用: 把當前路徑下src目錄下的所有源文件路徑放到變量hello_src中
解釋
命令:aux_source_directory(<dir> <variable>)
作用:查找dir路徑下的所有源文件,保存到variable變量中.
上面的例子中,hello_src是一個自定義變量,在執行了aux_source_directory(./src ${hello_src})之后,我就可以像這樣來添加一個可執行文件:add_executable(hello ${hello_src}), 意思是用hello_src里面的所有源文件來構建hello可執行程序, 不用手動列出src目錄下的所有源文件了。
注意:
-
aux_source_directory 不會遞歸包含子目錄,僅包含指定的dir目錄
-
CMake官方不推薦使用aux_source_directory及其類似命令(file(GLOB_RECURSE …))來搜索源文件,原因是這樣包含的話,如果我再在被搜索的路徑下添加源文件,我不需要修改CMakeLists腳本,也就是說,源文件多了,而CMakeLists并不需要(沒有)變化,也就使得構建系統不能察覺到新加的文件,除非手動重新運行cmake,否則新添加的文件就不會被編譯到項目結果中。
-
類似include_directories()中CMAKE_CURRENT_LIST_DIR的用法,也可以寫成:aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src ${hello_src})
讓CMake找到我的庫文件
加上:link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
解釋
命令:link_directories(directory1 directory2 ...)
作用:不必細說,與include_directories()類似,這個命令添加了庫包含路徑。
告訴CMake我的構建目標
加上:add_executable(${PROJECT_NAME} ${hello_src})
解釋
命令:add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 [source2 ...])
作用:目前僅需知道,其作用是使用${hello_src}里面的源文件來生成一個可執行文件,起名叫${PROJECT_NAME}, 即hello. 在一開始定義的那個project(hello)中的hello。
告訴CMake我要鏈接哪個庫文件
加上:target_link_libraries(${PROJECT_NAME} util)
解釋
命令:target_link_libraries(<target> [item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)
作用:僅需知道,名字叫${PROJECT_NAME}這個target需要鏈接util這個庫,會優先搜索libutil.a(windows上就是util.lib), 如果沒有就搜索libutil.so(util.dll, util.dylib)’
上面的例子意思是,讓hello去鏈接util這個庫。
傳遞FLAGS給C++編譯器
如果我的main.cpp里面用到了C++11,那么我需要告訴CMake在生成的Makefile里告訴編譯器啟用C++11。與此類似,我可能也要傳遞其他FLAGS給編譯器,怎么辦?
答案是:設置CMAKE_CXX_FLAGS變量
加上:
set(CMAKE_CXX_COMPILER "clang++" ) # 顯示指定使用的C++編譯器set(CMAKE_CXX_FLAGS "-std=c++11") # c++11 set(CMAKE_CXX_FLAGS "-g") # 調試信息 set(CMAKE_CXX_FLAGS "-Wall") # 開啟所有警告set(CMAKE_CXX_FLAGS_DEBUG "-O0" ) # 調試包不優化 set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG " ) # release包優化解釋
-
CMAKE_CXX_FLAGS?是CMake傳給C++編譯器的編譯選項,通過設置這個值就好比?g++ -std=c++11 -g -Wall
-
CMAKE_CXX_FLAGS_DEBUG?是除了CMAKE_CXX_FLAGS外,在Debug配置下,額外的參數
-
CMAKE_CXX_FLAGS_RELEASE?同理,是除了CMAKE_CXX_FLAGS外,在Release配置下,額外的參數
開始構建
通過以上步驟, 最后,在文件頭部添加CMake版本檢查,以我的電腦上的環境為例,我的CMake版本是3.0,那么我在腳本最開始加上:
cmake_minimum_required ( VERSION 3.0)
完整的CMakeLists.txt如下所示:
cmake_minimum_required ( VERSION 3.0)project(hello)include_directories(${CMAKE_CURRENT_LIST_DIR}/include)link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src ${hello_src})add_executable(${PROJECT_NAME} ${hello_src})target_link_libraries(${PROJECT_NAME} util)set(CMAKE_CXX_COMPILER "clang++" ) # 顯示指定使用的C++編譯器set(CMAKE_CXX_FLAGS "-std=c++11") # c++11 set(CMAKE_CXX_FLAGS "-g") # 調試信息 set(CMAKE_CXX_FLAGS "-Wall") # 開啟所有警告set(CMAKE_CXX_FLAGS_DEBUG "-O0" ) # 調試包不優化 set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG " ) # release包優化在CMakeLists.txt所在目錄,新建build目錄,并切換進build進行構建即可. 具體構建方法參見上一篇CMake Hello World的構建。
注意:生成的可執行文件路徑會在build/src目錄下,如需修改生成位置,請參考CMake變量EXECUTABLE_OUTPUT_PATH。
總結
本文通過一個C++工程實例,介紹了構建過程中用到的一些CMake命令和變量.
后面的文章將會講解如何構建更加復雜的C++工程,會用到CMake里的function和其他命令和變量。
參考鏈接
-
CMake Documentation(V3.0為例)
-
CMake 變量
-
CMake菜譜(CMake Cookbook中文版)?較為全面
轉載自:https://elloop.github.io/tools/2016-04-10/learning-cmake-2-commands
其他關于 Cmake 的簡單使用教程可參考:?http://walkerdu.com/2020/10/27/cmake/
總結
以上是生活随笔為你收集整理的CMake 常用命令和变量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java】深入理解Java随机数
- 下一篇: 理解 C++ 的 Memory Orde