在之前我假定你已经熟悉一些cmake的语法,不会也没关系,百度一下就好了。
如果你对pkg-config这种方式管理工程很熟悉,你可以跳到第二部分,或者你也可以参考我的一些想法。
最后我会给出源代码和一些资料,希望对你有所帮助。
下面就简要扼要介绍pkg-config
pkg-config:Linux下的一个命令, 获得某一个库/模块的所有编译相关的信息
(1):既然是一个命令,那么自然就可以直接运行,对于一个陌生的shell命令,我希望你可以pkg-config --help
,如果有帮助信息,可以直接分析,毕竟一手资料是最好的。
(2):帮助信息有一些参数解释,或许你还不清楚怎么回事?下面用opencv来分析:
pkg-config的路径(是一个二进制文件):
/usr/bin/pkg-config
帮助文档:
pkg-config --help
pkg-config的版本号:
pkg-config --version
0.29.1
列出系统所有的pkg-config管理的工程(很明显opencv也在里面,比如还有protobuf,hdf等):
pkg-config --list-all
eg:
opencv OpenCV - Open Source Computer Vision Library #对应opencv.pc文件的Description项
hdf5 HDF5 - Hierarchical Data Format 5 (HDF5)
openssl OpenSSL - Secure Sockets Layer and cryptography libraries and tools
.......
查看pkg-config管理的opencv版本:
pkg-config opencv --modversion
2.4.13.6 #对应opencv.pc文件的Version项
当然这只是一些无关紧要的东西,下面看看如何和cmake扯上关系:
## 分析参数--libs、--libs-only-L、--libs-only-l各自的含义(--libs = --libs-only-L + --libs-only-l)
pkg-config opencv --libs: #对应opencv.pc文件的Libs项
-L/home/topeet/programfile/opencv2/lib -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_nonfree -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab -lrt -lpthread -lm -ldl
pkg-config opencv --libs-only-L:
-L/home/topeet/programfile/opencv2/lib
pkg-config opencv --libs-only-l:
-lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_nonfree -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab -lrt -lpthread -lm -ldl
## 再看一组,分析参数--cflags、-cflags-only-I各自的含义
pkg-config opencv --cflags: #对应opencv.pc文件的Cflags项
-I/home/topeet/programfile/opencv2/include/opencv -I/home/topeet/programfile/opencv2/include
pkg-config opencv --cflags-only-I
-I/home/topeet/programfile/opencv2/include/opencv -I/home/topeet/programfile/opencv2/include
(2):上面的那些输出是怎么来的呢?其实源于opencv.pc文件,这里面有所有的信息,当然.pc
文件有特定的语法,pkg-config是专门解析系统的所有.pc文件的,特别是大型工程。
了解opencv.pc文件的一些内容:
(3):从下面的图中我们可以清楚的知道opencv.pc,主要包含opencv的头文件路径,链接库参数。这正是我们所需要编译的参数啊?假如没有这个,想必你只能-I.....-I...../-l... -l.....
,你得很清楚的知道程序里用了哪些动态库?,头文件在哪?我的opencv是apt-get的?那么就在系统搜索路径中,不是呢?比如我所有软件都装在自己的一个地方中,那么除非你增加系统搜索路径,否则系统是不会去搜索的。而且有时你会发现,程序编译生成了可执行程序,一运行就报动态库的问题(从侧面我们也知道编译、链接是不同两个问题,即有时候要export LIBRARY_PATH
),当然源文件少了,直接gcc/g++ 就好了。cmake/Makefile都不需要了,那么对于大工程呢?
在了解了上面的一些细节后,接下来就分析opencv安装在默认路径和非默认路径下的情况,当然有很多都是通过pkg-config管理的,这里以opencv为例。
下面是完成这个任务的核心代码
(1):找到PkgConfig包,即/usr/bin/pkg-config
(2):导入需要的模块,如opencv,这是opencv.pc的文件名,不要乱填。如果不知道,搜索下:find / -name *.pc -print
(3):加入头文件:PKG_OPENCV_INCLUDE_DIRS,宏名是
(4):加入动态库:PKG_OPENCV_LDFLAGS,宏名是
#通过pkg-config管理的三方库
SET(ENV{PKG_CONFIG_PATH} /home/topeet/programfile/opencv2/lib/pkgconfig)
FIND_PACKAGE(PkgConfig REQUIRED) #PkgConfig名字是固定的,代表准备加入pkg-config模块,即查找/usr/bin/pkg-config
#eg: -- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1")
PKG_SEARCH_MODULE(PKG_OPENCV REQUIRED opencv) #通过执行pkg-config程序,并指定我需要的模块是opencv,注意opencv名字固定,是源于安装OpenCV生成的opencv.pc,PKG_OPENCV是前缀(观察下面),
#eg: -- Checking for one of the modules 'opencv'
# 添加三方opencv的头文件路径-- -I/home/topeet/programfile/opencv2/include/opencv -I/home/topeet/programfile/opencv2/include
INCLUDE_DIRECTORIES(${PKG_OPENCV_INCLUDE_DIRS})
# 为指定的bin文件添加三方链接库
TARGET_LINK_LIBRARIES(main detect ${PKG_OPENCV_LDFLAGS}) #其他参数可以吗?不行的,为什么?
(5):下面列出了常见的cmake的pkg-config的宏,大部分是前缀+固定标识。
注意:PKG_OPENCV_LDFLAGS、PKG_OPENCV_LIBRARY_DIRS、PKG_OPENCV_LIBRARIES三个的区别,不然你编译不出来的,因为现在系统搜索不到你的opencv在哪。
#PKG_OPENCV相关头文件/库的输出
MESSAGE(STATUS "PKG_OPENCV_FOUND: ${PKG_OPENCV_FOUND}") #有没有找到 eg: -- PKG_OPENCV_FOUND: 1
MESSAGE(STATUS "PKG_CONFIG_EXECUTABLE: ${PKG_CONFIG_EXECUTABLE}") #pkg-config脚本路径 eg: /usr/bin/pkg-config
MESSAGE(STATUS "PKG_CONFIG_VERSION_STRING: ${PKG_CONFIG_VERSION_STRING}") #pkg-config版本号 相当于执行: pkg-config --version
MESSAGE(STATUS "PKG_OPENCV_VERSION: ${PKG_OPENCV_VERSION}") #opencv的版本 相当于执行: pkg-config opencv --modversion
MESSAGE(STATUS "PKG_OPENCV_PREFIX: ${PKG_OPENCV_PREFIX}") #opencv的安装路径PREFIX
MESSAGE(STATUS "PKG_OPENCV_INCLUDE_DIRS: ${PKG_OPENCV_INCLUDE_DIRS}") #头文件路径 include路径,多个,分开
MESSAGE(STATUS "PKG_OPENCV_LIBRARY_DIRS: ${PKG_OPENCV_LIBRARY_DIRS}") #动态库路径 lib路径,多个,分开
MESSAGE(STATUS "PKG_OPENCV_LIBRARIES: ${PKG_OPENCV_LIBRARIES}") #有那些动态库? 相当于执行: pkg-config opencv --libs-only-l,只列出库名字
MESSAGE(STATUS "PKG_OPENCV_LDFLAGS: ${PKG_OPENCV_LDFLAGS}") #所有需要链接的标志 相当于执行: pkg-config opencv --libs,不仅有库名字,还有其路径
MESSAGE(STATUS "PKG_OPENCV_LDFLAGS_OTHER: ${PKG_OPENCV_LDFLAGS_OTHER}") #其他需要链接的标志 相当于执行: pkg-config opencv --libs-only-other
MESSAGE(STATUS "PKG_OPENCV_CFLAGS: ${PKG_OPENCV_CFLAGS}") #cflag可以指头文件 相当于执行: pkg-config opencv --cflags,多个,分开
MESSAGE(STATUS "PKG_OPENCV_CFLAGS_OTHER: ${PKG_OPENCV_CFLAGS_OTHER}") #其他cflag标志 相当于执行: pkg-config opencv --libs-only-other
输出案例:
(6):pkg_search_module函数用法,其中REQUIRED指该步骤出问题,结束当前cmake
pkg_search_module( [REQUIRED] [QUIET]
[NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH]
[]*)
(6):这些内容均在根目录的CmakeLists.txt里面,下面是一个完整的过程。
# 编译该工程CMAKE最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.2 FATAL_ERROR)
# 工程名字
PROJECT(MAIN)
# 注意下面只适合opencv在系统/usr/local/下面,若在其他位置,需要做相应修改
# 处理默认位置的opencv库
#FIND_PACKAGE(OpenCV REQUIRED)
#通过pkg-config管理的三方库
# 非root下需要自己加入PKG_CONFIG_PATH,不然报错!!!
SET(ENV{PKG_CONFIG_PATH} /home/topeet/programfile/opencv2/lib/pkgconfig)
FIND_PACKAGE(PkgConfig REQUIRED) #PkgConfig名字是固定的,代表准备加入pkg-config模块,即查找/usr/bin/pkg-config
#eg: -- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1")
PKG_SEARCH_MODULE(PKG_OPENCV REQUIRED opencv) #通过执行pkg-config程序,并指定我需要的模块是opencv,注意opencv名字固定,是源于安装OpenCV生成的opencv.pc,PKG_OPENCV是前缀(观察下面),
#eg: -- Checking for one of the modules 'opencv'
#PKG_OPENCV相关头文件/库的输出
MESSAGE(STATUS "PKG_OPENCV_FOUND: ${PKG_OPENCV_FOUND}") #有没有找到 eg: -- PKG_OPENCV_FOUND: 1
MESSAGE(STATUS "PKG_CONFIG_EXECUTABLE: ${PKG_CONFIG_EXECUTABLE}") #pkg-config脚本路径 eg: /usr/bin/pkg-config
MESSAGE(STATUS "PKG_CONFIG_VERSION_STRING: ${PKG_CONFIG_VERSION_STRING}") #pkg-config版本号 相当于执行: pkg-config --version
MESSAGE(STATUS "PKG_OPENCV_VERSION: ${PKG_OPENCV_VERSION}") #opencv的版本 相当于执行: pkg-config opencv --modversion
MESSAGE(STATUS "PKG_OPENCV_PREFIX: ${PKG_OPENCV_PREFIX}") #opencv的安装路径PREFIX
MESSAGE(STATUS "PKG_OPENCV_INCLUDE_DIRS: ${PKG_OPENCV_INCLUDE_DIRS}") #头文件路径 include路径,多个,分开
MESSAGE(STATUS "PKG_OPENCV_LIBRARY_DIRS: ${PKG_OPENCV_LIBRARY_DIRS}") #动态库路径 lib路径,多个,分开
MESSAGE(STATUS "PKG_OPENCV_LIBRARIES: ${PKG_OPENCV_LIBRARIES}") #有那些动态库? 相当于执行: pkg-config opencv --libs-only-l,只列出库名字
MESSAGE(STATUS "PKG_OPENCV_LDFLAGS: ${PKG_OPENCV_LDFLAGS}") #所有需要链接的标志 相当于执行: pkg-config opencv --libs,不仅有库名字,还有其路径
MESSAGE(STATUS "PKG_OPENCV_LDFLAGS_OTHER: ${PKG_OPENCV_LDFLAGS_OTHER}") #其他需要链接的标志 相当于执行: pkg-config opencv --libs-only-other
MESSAGE(STATUS "PKG_OPENCV_CFLAGS: ${PKG_OPENCV_CFLAGS}") #cflag可以指头文件 相当于执行: pkg-config opencv --cflags,多个,分开
MESSAGE(STATUS "PKG_OPENCV_CFLAGS_OTHER: ${PKG_OPENCV_CFLAGS_OTHER}") #其他cflag标志 相当于执行: pkg-config opencv --libs-only-other
# 查找当前目录下的所有源文件并将名称保存到DIR_SRCS变量
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
# 添加头文件detect.hpp路径
INCLUDE_DIRECTORIES("${PROJECT_SOURCE_DIR}/DetectorClass")
# 添加三方opencv的头文件路径-- -I/home/topeet/programfile/opencv2/include/opencv -I/home/topeet/programfile/opencv2/include
INCLUDE_DIRECTORIES(${PKG_OPENCV_INCLUDE_DIRS})
# 触发寻找下一级CMakeLists.txt,即指向DetectorClass子目录下的CMakeLists.txt,这时会把libdetect.so编译出来
ADD_SUBDIRECTORY(DetectorClass) #注意下面的语句不能和上面的INCLUDE_DIRECTORIES交换,否则头文件找不到,是个顺序过程
# 指定生成目标
ADD_EXECUTABLE(main main.cpp)
# 为指定的bin文件添加三方链接库
TARGET_LINK_LIBRARIES(main detect ${PKG_OPENCV_LDFLAGS})
这个就十分简单了,因为能搜索到你的头文件、动态库文件,甚至我连pkg-config都不需要了。
# 编译该工程CMAKE最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.2 FATAL_ERROR)
# 工程名字
PROJECT(MAIN)
# 处理opencv库
FIND_PACKAGE(OpenCV REQUIRED)
# 查找当前目录下的所有源文件并将名称保存到DIR_SRCS变量
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
# 添加头文件-detect.hpp
INCLUDE_DIRECTORIES("${PROJECT_SOURCE_DIR}/DetectorClass")
# 触发寻找下一级CMakeLists.txt,即指向DetectorClass子目录下的CMakeLists.txt
ADD_SUBDIRECTORY(DetectorClass)
# 指定生成目标
ADD_EXECUTABLE(main main.cpp)
# 为指定的bin文件添加三方链接库
TARGET_LINK_LIBRARIES(main detect ${OpenCV_LIBS})
CMake相对简单,用SET命令添加PKG_CONFIG_PATH即可
SET(ENV{PKG_CONFIG_PATH} /home/topeet/programfile/opencv2/lib/pkgconfig)
工程是利用opencv做一个多边形中心点的提取,用c++写成一个类,感兴趣可以研究下。
链接: https://pan.baidu.com/s/1JMPyU0Jf-itd69lU0dlGxg 提取码: tebs
参考:
https://www.cnblogs.com/the-capricornus/p/5619884.html