Ubuntu20使用CMake源码编译安装OpenCV
安装OpenCV4,记录一下问题和经验
过程
克隆源码
编译安装
|
|
问题解决
-
找不到
openjpeg.h
- 【原因】CMake默认的搜索路径是
/usr/include
,但是这个头文件实际上在子目录/usr/include/openjpeg
里,而CMake不会递归搜索 - 【解决】我把整个文件夹里的4个头文件从子目录移到了
/usr/include
里;第二种解决方法是配置OpenCV的CMake的搜索路径
- 【原因】CMake默认的搜索路径是
-
undefined reference to TIFFIsTiled@LIBTIFF_4.0
- 链接问题,上网搜索后得知需要在CMake的时候打开
DBUILD_TIFF=ON
选项,就会编译这个库
- 链接问题,上网搜索后得知需要在CMake的时候打开
-
Conda导致库混淆
- 事实证明,在zshrc里预先初始化Conda会导致很多问题……这个是会导致库混乱。
1 2 3 4 5 6 7 8 9
CMake Warning at src/CMakeLists.txt:255 (add_executable): Cannot generate a safe runtime search path for target bedrough_test because files in some directories may conflict with libraries in implicit directories: runtime library [LIBRARY] in /usr/lib/[PATH] may be hidden by files in: /home/[USER]/anaconda3/lib Some of these libraries may not be found correctly.
1
- 【解决】想办法让CMake在编译的时候看不到conda。`conda deactivate`不行,似乎不能改掉一些环境变量的设置,所以先在zshrc里注释掉conda的初始化代码,再开一个终端,在新终端里编译
疑惑
- 有个问题,虽然安装的是opencv4,但文件目录是
opencv4/opencv2/xxx.h
,怪哉
OpenCV HelloWorld
安装完后,就是跑一个小例子试验一下咯
代码
|
|
CMake配置
- 添加这三行,其中YourProject改为自己工程的名字
|
|
后记:CMake拾遗
系统指令**不区分大小写,变量和字符串区分**大小写 CMake本身不做构建,它的generator做构建,这个generator可以是make/ninja等
CMake命令行
cmake -S -B build
,-B
是指定构建目录,-S
是指定代码目录
CMake默认变量
- TODO
Find_Package的工作机理
它是去指定路径搜索某个cmake脚本,然后这个脚本再去具体找某个库,有两种搜索模式。找完后,通过设置一些变量来给调用它的父脚本使用,比如是否找到,头文件和二进制文件路径等。
- Module Mode
- 搜索路径:
CMAKE_MODULE_PATH
,一般为空,而找的是Find<PackageName>.cmake
这个脚本。值得注意的是,此脚本一般并不是库自己提供的,而是操作系统、CMake自己等,因此常常会找到旧版的库。 - 《Modern CMake》里提到这种一般是适用于非原生支持CMake的项目的,(如果你是库的开发者)不推荐用这种
- 搜索路径:
- Config Mode
- 找
<lowercasePackageName>-config.cmake
or<PackageName>Config.cmake
脚本,如果指定了版本,还会找<lowercasePackageName>-config-version.cmake
or<PackageName>ConfigVersion.cmake
这俩。 - 搜索路径是一系列路径的集合,在不同操作系统略有不同
- 通常,原生支持cmake的项目库安装时会拷贝一份XXXConfig.cmake到系统目录中
- 找
将会设置的变量
<PackageName>_FOUND
表示是否找到<LibaryName>_INCLUDE_DIR
或者<LibaryName>_INCLUDES
,库的头文件所在<LibaryName>_LIBRARY
或者<LibaryName>_LIBRARIES
,库的二进制文件所在
函数签名
|
|
REQUIRED
表示这个库是必要的,如果找不到就会fatal error
终止编译MODULE
表示仅使用Module方法。默认地,CMake会先用Module Mode,如果找不到再用Config Mode
target_include_directories
-
关于
target_include_directories
和include_directories
的区别,见StackOverFlow -
概括来说就是,前者只是为指定目标添加包含目录,有着
tareget scope
,而后者对整个文件都有影响,有着全局作用域,所以推荐用前者 -
还有一个是与Public/Private连用的时候作用域扩展的区别,先不看了,如果用到了再看
-
关于关键字public/interface/private,参考这里 ,讲的清楚。概括来说就是如果你这个库只给自己用,在对外的头文件不包含,外界不知道这个库的存在,就private;如果只给外界用,内部不用库(可能只用了头文件里的东西),那么就interface。如果都有那么就public。原文转述一下:
实际上,这三个关键字指定的是目标文件依赖项的使用范围(scope)或者一种传递(propagate)。官方说明
可执行文件依赖 libhello-world.so, libhello-world.so 依赖 libhello.so 和 libworld.so。
- main.c 不使用 libhello.so 的任何功能,因此 libhello-world.so 不需要将其依赖—— libhello.so 传递给 main.c,hello-world/CMakeLists.txt 中使用 PRIVATE 关键字;
- main.c 使用 libhello.so 的功能,但是libhello-world.so 不使用,hello-world/CMakeLists.txt 中使用 INTERFACE 关键字;
- main.c 和 libhello-world.so 都使用 libhello.so 的功能,hello-world/CMakeLists.txt 中使用 PUBLIC 关键字;
参考资料
- CMake官方文档 ,以及稀土掘金的中文翻译 ,和一篇知乎 。
- 好东西,More modern CMake