cmake工程导入pkg-config(opencv为例),实现三方库的编译链接;OpnCV非默认安装(非ROOT),cmake ..找不到opencv.pc?

1 什么是pkg-config?

在之前我假定你已经熟悉一些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都不需要了,那么对于大工程呢?

2 cmake导入pkg-config?

在了解了上面的一些细节后,接下来就分析opencv安装在默认路径和非默认路径下的情况,当然有很多都是通过pkg-config管理的,这里以opencv为例。

2.1 安装非默认路径下

下面是完成这个任务的核心代码
(1):找到PkgConfig包,即/usr/bin/pkg-config
(2):导入需要的模块,如opencv,这是opencv.pc的文件名,不要乱填。如果不知道,搜索下:find / -name *.pc -print
(3):加入头文件:PKG_OPENCV_INCLUDE_DIRS,宏名是 <prefix>_INCLUDE_DIRS
(4):加入动态库:PKG_OPENCV_LDFLAGS,宏名是 <prefix>_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(<PREFIX> [REQUIRED] [QUIET]
                  [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH]
                  <MODULE> [<MODULE>]*)

(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})

2.2 安装默认路径下

这个就十分简单了,因为能搜索到你的头文件、动态库文件,甚至我连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})

3 OpnCV非默认安装(非ROOT执行cmake . .),cmake找不到opencv.pc?

CMake相对简单,用SET命令添加PKG_CONFIG_PATH即可

SET(ENV{PKG_CONFIG_PATH} /home/topeet/programfile/opencv2/lib/pkgconfig)

4 源代码

工程是利用opencv做一个多边形中心点的提取,用c++写成一个类,感兴趣可以研究下。
链接: https://pan.baidu.com/s/1JMPyU0Jf-itd69lU0dlGxg 提取码: tebs

参考:
https://www.cnblogs.com/the-capricornus/p/5619884.html

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值