CMake指令入门 ——以构建OpenCV项目为例
CMake指令入門 ——以構建OpenCV項目為例
轉自:https://blog.csdn.net/sandalphon4869/article/details/100589747
一、安裝
sudo apt-get install cmake安裝好后,輸入
cmake -version如果出現了cmake的版本顯示,那么說明安裝成功
二、cmake編譯
cmake的作用就是將在IDE編譯器中的編譯功能拿出來,可以在終端上完成。類似于vim和文本編輯器。
cmake的編譯方式:
-
內部構建(in-source-build)
-
外部構建(out-of-source-build)
兩者的區別僅僅是前者將生成的編譯文件和源代碼、CMakeLists.txt 混雜在一起,后者就只是創建了一個文件夾 build 存儲生成的編譯文件,更好刪除編譯生成的文件而已(直接刪文件夾)。
三、語法
1. 基本語法
-
指令是大小寫無關的,參數和變量是大小寫相關的。但推薦你全部使用大寫指令。
-
變量使用 ${}方式取值,但是在 IF 控制語句中是直接使用變量名。如:${SRC_LIST}
-
指令(參數 1 參數 2…) 參數使用括弧括起,參數之間使用空格或分號分開。
如:ADD_EXECUTABLE(hello main.c func.c) 或者 ADD_EXECUTABLE(hello main.c;func.c) 。
-
注釋:# comment
2. 指令
搞清當前目錄的意思:
-
CMakeLists.txt 中的 . 表示當前目錄是CMakeLists.txt文件所在的目錄,而非執行時終端的當前目錄。
-
cmake . 這條終端命令是執行時終端的當前目錄。
(1) PROJECT()
PROJECT(projectname [CXX] [C] [Java])總結:定義工程名稱,并可指定工程支持的語言。
-
定義工程名稱:如 PROJECT(HELLO) ,那么工程的名稱就是 HELLO
-
支持的語言列表:支持的語言列表是可以忽略的, 默認情況表示支持所有語言。
如指定C++:PROJECT(HELLO CXX) -
這個指令隱式的定義了四個 cmake 變量:
- <projectname>_BINARY_DIR 以及 <projectname>_SOURCE_DIR(格式,并非實際的變量)。對于這個工程就是 HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR (之后就可以直接使用了這兩個變量),使用 <projectname>_BINARY_DIR 這個是無效的。
PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR 變量。 - 他們的值分別跟 HELLO_BINARY_DIR 與 HELLO_SOURCE_DIR 一致。區別是這兩個會自動根據工程名字的變化而變化。
- 建議以后直接使用 PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名稱,也不會影響這兩個變量。如:從HELLO該為WORLD,那么前者就得寫成WORLD_BINARY_DIR 和 WORLD_SOURCE_DIR,但后者還是 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。
- <projectname>_BINARY_DIR 以及 <projectname>_SOURCE_DIR(格式,并非實際的變量)。對于這個工程就是 HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR (之后就可以直接使用了這兩個變量),使用 <projectname>_BINARY_DIR 這個是無效的。
(2) CMAKE_MINIMUM_REQUIRED()
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)cmake最低版本
(3) SET()
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])作用:定義變量的值
比如:
-
如果有多個源文件,也可以定義成:SET(SRC_LIST main.c t1.c t2.c)
-
可以用 "" 來處理包含空格的文件名:SET(SRC_LIST "hello world.cpp")(建議使用方式)
-
使用c++11特性:set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -std=c++11"),防止出現因為c++11才有的編譯錯誤,比如 error: ‘to_string’ is not a member of ‘std’
-
設置編譯模式 Build Type,要加引號,不加可能報錯。
- Debug模式:set(CMAKE_BUILD_TYPE "Debug")
- Release模式:set(CMAKE_BUILD_TYPE "Release"),更快。
(4) MESSAGE()
MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display")作用:在cmake編譯過程中向終端輸出用戶定義的信息。
三種信息類型:
-
SEND_ERROR:產生錯誤,生成過程被跳過
-
STATUS:輸出前綴為 -- 的信息。
-
FATAL_ERROR:立即終止所有 cmake 過程
輸出內容:"hello ${<variant name>}"
比如:
PROJECT(HELLO) SET(SRC_LIST main.cpp) MESSAGE(STATUS "The value of HELLO_SOURCE_DIR is${HELLO_SOURCE_DIR}" ) ADD_EXECUTABLE(hello ${SRC_LIST})輸出:
... The value of HELLO_SOURCE_DIR is/home/song/code ...ps:引號的作用是保留空格
-
"hello world ${HELLO_SOURCE_DIR}":輸出為 hello world /home
-
hello world ${HELLO_SOURCE_DIR}:輸出為 helloworld/home
(5) AUX_SOURCE_DIRECTORY()
①基本含義
AUX_SOURCE_DIRECTORY(dir VARIABLE)作用是發現一個目錄 dir 下所有的源代碼文件并將列表存儲在一個變量中,這個指令臨時被用來自動構建源文件列表。因為目前 cmake 還不能自動發現新添加的源文件。 (本目錄為CMakeLists.txt所在的目錄)
比如:
AUX_SOURCE_DIRECTORY(. SRC_LIST) ADD_EXECUTABLE(main ${SRC_LIST})將本目錄下的源代碼文件添加到SRC_LIST變量中,再將這些文件編譯成生成文件。
②子目錄
注意:如果本目錄下有子目錄,是不會將子目錄下的源代碼文件添加進去的,得手動打出來。比如:
# 本目錄下的子目錄subDir AUX_SOURCE_DIRECTORY(./subDir SRC_LIST)③可添加多個
這兩個一起添加進入 SRL_LIST,并不是后者覆蓋前者。
AUX_SOURCE_DIRECTORY(./src/text SRC_LIST) AUX_SOURCE_DIRECTORY(./src/serial SRC_LIST)(6) ADD_SUBDIRECTORY
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])這個指令用于向當前工程添加存放源文件的子目錄,并可以指定中間二進制和目標二進制存放的位置。
EXCLUDE_FROM_ALL參數的含義:將這個目錄從編譯過程中排除,比如,工程 的 example,可能就需要工程構建完成后,再進入 example 目錄單獨進行構建(當然,你 也可以通過定義依賴來解決此類問題)。
比如:
將 src 子目錄加入工程,并指定編譯輸出(包含編譯中間結果)路徑為bin 目錄。
(7) FIND_PACKAGE()
FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS] [componets...]])參數:
REQUIRED 參數:如果使用了這個參數,說明這 個鏈接庫是必備庫,如果找不到這個鏈接庫,則工程不能編譯。
功能:只找一個名為 name 的包(后面都是修飾條件),所以如果要找多個包,要分多個FIND_PACKAGE() 寫。
比如:
-
OpenCV3:
find_package(OpenCV REQUIRED) -
ROS:
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs)
(8) INCLUDE_DIRECTORIES()
include_directories()功能:鏈接頭文件
描述:可以將要鏈接的頭文件都寫在括號里,不用分成多個 INCLUDE_DIRECTORIES()寫。
比如:
- OpenCV3:${OpenCV_INCLUDE_DIRS}
- ROS:${catkin_INCLUDE_DIRS}
(9) ADD_EXECUTABLE()
ADD_EXECUTABLE(hello ${SRC_LIST})生成可執行文件。
-
相關的源文件是SRC_LIST 中 定義的源文件列表, 你也可以直接寫成ADD_EXECUTABLE(hello main.c ti.c)。
-
可以寫成 ADD_EXECUTABLE(hello main) cmake 會自動的在本目錄查找 main.c 或者 main.cpp等,當然,最好不要偷這個懶,以免這個目錄確實存在一個 main.c 和一個 main.cpp
-
hello是最終要執行的可執行文件:./hello
(10) TARGET_LINK_LIBRARIES()
TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2...)功能:這個必須寫在 ADD_EXECUTABLE() 之后,為生成文件target添加庫。
比如:
- OpenCV3:${OpenCV_LIBS}
- ROS:${catkin_LIBRARIES}
3. 總結
添加文件的方式
-
手動添加:set()
SET(SRC_LIST "main.cpp forest.hpp") ADD_EXECUTABLE(main ${SRC_LIST}) -
自動添加:AUX_SOURCE_DIRECTORY()
AUX_SOURCE_DIRECTORY(. SRC_LIST) ADD_EXECUTABLE(main ${SRC_LIST})
四、構建OpenCV項目
項目結構
為了使整個項目更加條理,我們的文件夾采用如下組織方式:
bin build src CMakeLists.txt其中bin目錄用于放編譯生成的可執行文件,build目錄用于cmake構建項目,src用于放源代碼。
OpenCV源文件
下面是我們寫的一個OpenCV示例代碼:
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream>using namespace std; using namespace cv;int main(int argc, char** argv) {if (argc != 2){cout << "Usage: opencv_test <image path>" << endl;return -1;}char *imgName = argv[1];Mat image;image = imread(imgName, 1);if (!image.data){cout << "No image data" << endl;return -1;}Mat gray_img;cvtColor(image, gray_img, CV_BGR2GRAY);imwrite("images/result.jpg", gray_img);return 0; }這是一個很簡單的例子:讀取圖片然后轉化成灰度圖。
編寫CMakeLists.txt
CMake文件的文件名CMakeLists.txt有嚴格的大小寫要求,注意不要寫錯。
# project name PROJECT(HELLO)# using C++11 set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -std=c++11 ")# cmake version CMAKE_MINIMUM_REQUIRED(VERSION 3.10)# find OpenCV FIND_PACKAGE(OpenCV REQUIRED)# show the message of OpenCV message(STATUS "OpenCV library status:") message(STATUS " version: ${OpenCV_VERSION}") message(STATUS " headers: ${OpenCV_INCLUDE_DIRS}") message(STATUS " libraries: ${OpenCV_LIBS}")# link headers INCLUDE_DIRECTORIES({OpenCV_INCLUDE_DIRS})# 添加源代碼文件到SRC_LIST變量中 AUX_SOURCE_DIRECTORY(. SRC_LIST)# 生成可執行文件 ADD_EXECUTABLE(hello ${SRC_LIST})# after ADD_EXECUTABLE,為生成文件target添加庫 TARGET_LINK_LIBRARIES(hello ${OpenCV_LIBS})PROJECT指令的語法是:
PROJECT(projectname [CXX] [C] [Java])你可以用這個指令定義工程名稱,并可指定工程支持的語言,支持的語言列表是可以忽略的,這個指令隱式的定義了兩個cmake變量: <projectname>_BINARY_DIR 以及<projectname>_SOURCE_DIR。前者指構建路徑,后者指工程路徑,即 CMakeLists.txt 所在的路徑。
同時cmake系統也幫助我們預定義了 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR 變量,他們的值分別跟 opencv_test_BINARY_DIR 與 opencv_test_SOURCE_DIR 一致。
為了統一起見,建議以后直接使用 PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名稱,也不會影響這兩個變量。如果使用了<projectname>_SOURCE_DIR,修改工程名稱后,需要同時修改這些變量。
接下來是設置cmake要求的最低版本號:
cmake_minimum_required(VERSION 3.5)SET指令的語法是:
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])現階段,你只需要了解SET指令可以用來顯式的定義變量即可。這里我們將變量CMAKE_RUNTIME_OUTPUT_DIRECTORY定義為${opencv_test_SOURCE_DIR}/bin也就是工程路徑下的bin目錄。
下面介紹一個很重要的指令:find_package 這個指令以被用來在系統中自動查找配置構建工程所需的程序庫。在linux和unix類系統下這個命令尤其有用。CMake自帶的模塊文件里有大半是對各種常見開源庫的 find_package 支持,支持庫的種類非常多。
當它找到OpenCV程序庫之后,就會幫助我們預定義幾個變量,OpenCV_FOUND、OpenCV_INCLUDE_DIRS、OpenCV_LIBRARY_DIRS、OpenCV_LIBRARIES,它們分別指是否找到OpenCV,OpenCV的頭文件目錄,OpenCV的庫文件目錄,OpenCV的所有庫文件列表。接著我們就可以使用這些變量來配置了:
include_directories(${OpenCV_INCLUDE_DIRS})上面這個指令用來設置包含的頭文件的路徑。
link_directories(${OpenCV_LIBRARY_DIRS})上面這個指令用來設置庫文件的路徑。
target_link_libraries(opencv_test ${OpenCV_LIBS})上面這個指令用來設置需要的庫文件,它的語法是:
TARGET_LINK_LIBRARIES(target library1<debug | optimized> library2...)其中的target就是前面設置生成的目標文件(可執行文件):
add_executable(opencv_test src/opencv_test.cpp)這個命令很好理解,首先是可執行文件的名字,然后是源碼的名字。因此,這個命令一定要在TARGET_LINK_LIBRARIES之前使用。
現在我們的CMakeLists.txt就介紹完了。
構建項目并運行
mkdir build && cd build cmake .. make # 至此構建完成,下面運行 ./opencv_test總結
以上是生活随笔為你收集整理的CMake指令入门 ——以构建OpenCV项目为例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4.0丰田FJ自动熄火是什么毛病?
- 下一篇: rasa算法_(十八)基于RASA开始中