轉自:https://blog.csdn.net/haluoluo211/article/details/80559341
本文主要內容如下:
1. cmake find_package的基本原理
2. 如何編寫自己的 cmake module模塊
3. 使用cmake find_package 使用不同版本的opencv lib問題(opencv 安裝在指定的目錄,不是系統的目錄)
1. cmake find_package的基本原理
當編譯一個需要使用第三方庫的軟件時,我們需要知道:
去哪兒找頭文件 .h 對比GCC的 -I 參數
去哪兒找庫文件 (.so/.dll/.lib/.dylib/…) 對比GCC的 -L 參數
需要鏈接的庫文件的名字 對比GCC的 -l 參數
比如說,我們需要一個第三方庫 curl,那麼我們的 CMakeLists.txt 需要指定頭文件目錄,和庫文件,類似:
include_directiories(/usr/include/curl)
target_link_libraries(myprogram path/curl.so)
1
2
如果藉助於cmake提供的finder會怎麼樣呢?使用cmake的Modules目錄下的FindCURL.cmake,相應的CMakeList.txt 文件:
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIR})
target_link_libraries(curltest ${CURL_LIBRARY})
1
2
3
那麼cmake是如何查找的呢?
find_package()命令首先會在模塊路徑中尋找Find.cmake,這是查找庫的一個典型方式。具體查找路徑依次爲CMake:變量${CMAKE_MODULE_PATH}中的所有目錄。如果沒有,然後再查看它自己的模塊目錄/share/cmake-x.y/Modules/($CMAKE_ROOT的具體值可以通過CMake中message命令輸出)。這稱爲模塊模式。
爲了能支持各種常見的庫和包,CMake自帶了很多模塊。可以通過命令 cmake –help-module-list (輸入cmake –help,然後雙擊Tab會有命令提示)得到你的CMake支持的模塊的列表: 直接查看模塊路徑。比如Ubuntu linux上,模塊的路徑是 ls /usr/share/cmake/Modules/:
ll -th /usr/share/cmake-3.5/Modules/
......
-rw-r--r-- 1 root root 76K Sep 27 2016 FindBoost.cmake
-rw-r--r-- 1 root root 2.7K Mar 24 2016 FindCoin3D.cmake
-rw-r--r-- 1 root root 77K Mar 24 2016 FindCUDA.cmake
-rw-r--r-- 1 root root 3.1K Mar 24 2016 FindCups.cmake
-rw-r--r-- 1 root root 2.4K Mar 24 2016 FindCURL.cmake
........
1
2
3
4
5
6
7
8
讓我們以bzip2庫爲例。CMake中有個 FindBZip2.cmake 模塊。只要使用 find_package(BZip2) 調用這個模塊,cmake會自動給一些變量賦值,然後就可以在CMake腳本中使用它們了。變量的列表可以查看cmake模塊文件,或者使用命令:
root@xy:~/cmake_practice/cmake_build/build_demo10# cmake --help-module FindBZip2
FindBZip2
---------
Try to find BZip2
Once done this will define
::
BZIP2_FOUND - system has BZip2
BZIP2_INCLUDE_DIR - the BZip2 include directory
BZIP2_LIBRARIES - Link these to use BZip2
BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)
1
2
3
4
5
6
7
8
9
10
11
12
13
cmake 會將路徑賦值給對應的變量,我們以curl的cmake爲例,其部分內容如下:
find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
mark_as_advanced(CURL_INCLUDE_DIR)
# Look for the library (sorted from most current/relevant entry to least).
find_library(CURL_LIBRARY NAMES
curl
# Windows MSVC prebuilts:
curllib
libcurl_imp
curllib_static
# Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip):
libcurl
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
比如一個使用bzip2的簡單程序,編譯器需要知道 bzlib.h 的位置,鏈接器需要找到bzip2庫(動態鏈接的話,Unix上是 libbz2.so 類似的文件,Windows上是 libbz2.dll )
project(helloworld)
add_executable(helloworld hello.c)
find_package (BZip2)
if (BZIP2_FOUND)
include_directories(${BZIP_INCLUDE_DIRS})
target_link_libraries (helloworld ${BZIP2_LIBRARIES})
endif (BZIP2_FOUND)
1
2
3
4
5
6
7
2. 如何編寫自己的 cmake module模塊
下面以工程demo9爲示例, 項目目錄結構如下:
├── cmake
│ └── FindDEMO9LIB.cmake
├── CMakeLists.txt
├── demo9.cpp
├── demo9.h
└── demo9_main.cpp
1
2
3
4
5
6
其中demo9.h和demo9.cpp生成lib, demo9_main.cpp link對應的lib生成可執行文件
文件內容如下:
//=========================demo9.h===================
#ifndef PROJECT_DEMO9_H
#define PROJECT_DEMO9_H
namespace demo9{
void print_demo9();
}
#endif //PROJECT_DEMO3_H_H
//======================demo9.cpp==================
#include "demo9.h"
#include <iostream>
namespace demo9{
void print_demo9(){
std::cout<<"this is demo9"<<std::endl;
}
}
//======================demo9_main.cpp==================
#include "demo9.h"
int main(){
demo9::print_demo9();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
首先我們使用demo9.h and demo9.cpp 生成靜態lib,並安裝:
-- Installing: /usr/local/demo9/lib/libdemo9_lib.a
-- Installing: /usr/local/demo9/include/demo9.h
1
2
FindDEMO9LIB.cmake的內容如下(精簡版本):
# 輔助輸出信息
message("now using FindDEMO9LIB.cmake find demo9 lib")
# 將demo9.h文件路徑賦值給DEMO9LIB_INCLUDE_DIR
FIND_PATH(DEMO9LIB_INCLUDE_DIR demo9.h /usr/include/demo9/
/usr/local/demo9/include/)
message("./h dir ${DEMO9LIB_INCLUDE_DIR}")
# 將libdemo9_lib.a文件路徑賦值給DEMO9LIB_LIBRARY
FIND_LIBRARY(DEMO9LIB_LIBRARY libdemo9_lib.a /usr/local/demo9/lib/)
message("lib dir: ${DEMO9LIB_LIBRARY}")
if(DEMO9LIB_INCLUDE_DIR AND DEMO9LIB_LIBRARY)
# 設置變量結果
set(DEMO9LIB_FOUND TRUE)
endif(DEMO9LIB_INCLUDE_DIR AND DEMO9LIB_LIBRARY)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
主CMakeLists.txt內容如下:
cmake_minimum_required(VERSION 3.5)
project(demo9)
# create libdemo9_lib.a
set(SRC_LIB demo9.cpp)
add_library(demo9_lib STATIC ${SRC_LIB})
# install it
install(TARGETS demo9_lib DESTINATION demo9/lib)
install(FILES demo9.h DESTINATION demo9/include)
# create demo9_main exectuable
set(SRC_EXE demo9_main.cpp)
# set demo9_lib cmake module path
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
message("cmake_module_path: ${CMAKE_MODULE_PATH}")
find_package(DEMO9LIB)
if(DEMO9LIB_FOUND)
add_executable(demo9_main ${SRC_EXE})
message("found demo9 ${DEMO9LIB_INCLUDE_DIR} ${DEMO9LIB_LIBRARY}")
include_directories(${DEMO9LIB_INCLUDE_DIR})
target_link_libraries(demo9_main ${DEMO9LIB_LIBRARY})
else()
message("not found DEMO9LIB_FOUND")
endif(DEMO9LIB_FOUND)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
編譯輸出信息如下:
root@xy:~/cmake_practice/cmake_build/build_demo9# cmake ../../cmake_tuorial/demo9/
cmake_module_path: /home/xy/cmake_practice/cmake_tuorial/demo9/cmake
now using FindDEMO9LIB.cmake find demo9 lib
./h dir /usr/local/demo9/include
lib dir: /usr/local/demo9/lib/libdemo9_lib.a
found demo9 /usr/local/demo9/include /usr/local/demo9/lib/libdemo9_lib.a
1
2
3
4
5
6
make
root@xy:~/cmake_practice/cmake_build/build_demo9# make -j10
cmake_module_path: /home/xy/cmake_practice/cmake_tuorial/demo9/cmake
now using FindDEMO9LIB.cmake find demo9 lib
./h dir /usr/local/demo9/include
lib dir: /usr/local/demo9/lib/libdemo9_lib.a
found demo9 /usr/local/demo9/include /usr/local/demo9/lib/libdemo9_lib.a
-- Configuring done
.......................................
1
2
3
4
5
6
7
8
運行:
root@xy:~/cmake_practice/cmake_build/build_demo9# ./demo9_main
this is demo9
1
2
3. 使用cmake find_package 使用不同版本的opencv lib問題(opencv 安裝在指定的目錄,不是系統的目錄)
下面在給出一個opencv的示例,opencv3.1安裝在/home/xy/opencv3.1_install/lib/目錄下(可以參考這篇英文blog安裝)。
最終安裝完成會有對應的cmake文件,查看如下:
xy@xy:~/opencv_demo/demo1$ ll -th ~/opencv3.1_install/lib/share/OpenCV/
total 60K
drwxrwxr-x 5 xy xy 4.0K May 28 19:00 ./
......
-rw-r--r-- 1 xy xy 16K May 28 18:56 OpenCVConfig.cmake
-rw-r--r-- 1 xy xy 418 May 28 18:56 OpenCVConfig-version.cmake
-rw-r--r-- 1 xy xy 4.5K May 28 18:56 OpenCVModules.cmake
-rw-r--r-- 1 xy xy 11K May 28 18:56 OpenCVModules-release.cmake
1
2
3
4
5
6
7
8
測試代碼如下:
#include <stdio.h>
#include "opencv2/opencv.hpp"
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv )
{
cout << "OpenCV version : " << CV_VERSION << endl;
cout << "Major version : " << CV_MAJOR_VERSION << endl;
cout << "Minor version : " << CV_MINOR_VERSION << endl;
if ( argc != 2 )
{
printf("usage: DisplayImage.out <Image_Path>\n");
return -1;
}
Mat image;
image = imread( argv[1], 1 );
if ( !image.data )
{
printf("No image data \n");
return -1;
}
cout<<image.size()<<endl;
cout<<image.size().width<<endl;
cout<<image.size().height<<endl;
namedWindow("Display Image", WINDOW_AUTOSIZE );
imshow("Display Image", image);
waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
對應的cmake 如下:
cmake_minimum_required(VERSION 3.5.0)
project(demo1)
//set cmake module path
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"~/opencv3.1_install/lib/share/OpenCV/"
)
find_package( OpenCV 3.1.0 REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
message("OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
message("OpenCV_LIBS: ${OpenCV_LIBS}")
add_executable( demo1 demo.cpp )
target_link_libraries( demo1 ${OpenCV_LIBS} )
1
2
3
4
5
6
7
8
9
10
11
12
13
cmake build輸出如下:
xy@xy:~/opencv_demo/demo1$ cmake .
OpenCV_INCLUDE_DIRS: /home/xy/opencv3.1_install/lib/include/opencv;/home/xy/opencv3.1_install/lib/include
OpenCV_LIBS: opencv_videostab;opencv_videoio;.....
1
2
3
程序運行如下: