【问题标题】:Using CMake to find dependencies in an application-specific subfolder使用 CMake 在特定于应用程序的子文件夹中查找依赖项
【发布时间】:2016-07-20 21:11:19
【问题描述】:

尽管多年编写大型 C++ 应用程序,我不明白 find_package 应该如何在中型 CMake 项目中工作,假设我想自己构建依赖包的源而不是简单地依赖在诸如 opencv、pcl 或 boost 之类的大型系统上安装在系统文件夹中的某处。我不敢相信我是世界上唯一一个发布过多个 OpenCV 和其他开源应用程序、在大型游戏项目中使用元构建系统(如 NAnt 和 SCons)的人,但我不能了解有关 CMake 工作原理的最基本知识或查找回答这些问题的教程。

过去,我基本上是通过手动设置所有 foo_DIR 值来解决不理解 find_package 的问题,因为 CMake 会抱怨,直到我得到一个工作文件夹。

我想通过一个我现在正在研究的简单示例来运行,并非常希望有人能解释我做错了什么。

首先,一些假设: 我想为 MacOS 和 Windows 构建所有东西,最好是通过 CMakeGUI。 MacOS 应该构建 XCodeProjects,Windows 应该构建 Visual Studio 解决方案。

有依赖的地方,我想自己编译,所以我有调试符号,可以修改依赖源(或者至少调试进去。) 不将预构建的二进制文件安装到系统文件夹中,即在 mac 上不使用 sudo port install opencv/pcl 等。 我有多个项目,并且更喜欢将一个项目及其依赖项保存在一个文件夹中。 出于具体示例的目的,假设我正在构建这个项目,尽管它是一个任意选择来说明我所遭受的过程和困惑:

https://github.com/krips89/opendetection

这列出了依赖项,我特意在此处重新排序,以便我可以按顺序排列它们,如下所示:

find_package(OpenCV REQUIRED)
find_package(Eigen REQUIRED)
find_package(Boost 1.40 COMPONENTS program_options REQUIRED )
find_package(PCL REQUIRED)
find_package(VTK REQUIRED)

我希望将所有这些依赖项下载并配置在单个路径中(假设为 Windows 上的 c:\src 和 Mac 上的 ~\src),而不是系统路径。假设实际文件夹是该项目的子文件夹,而不是所有项目的子文件夹。这也应该允许在同一台计算机上并行安装多个项目。

一步一个脚印:

(1) 我从https://github.com/opencv/opencv 克隆openCV,同步到标签3.1,配置到opencv_build 文件夹中,构建并安装到opencv_install 中。我已经这样做了很多次,这很简单。 (2) 同上,但对于 eigen(虽然为 eigen 构建实际上并没有做任何事情,因为它是一个模板库。我安装到一个文件夹 eigen_install

Taking 目录显示了一系列用于下载依赖项的文件夹。我假设了一个约定 where 和 是源代码库,它们下面的 _build 文件夹是 CMakeGui 中的“WHere to build the binaries”文件夹。

$ ls
boost_1_40_0    opencv  opendetection_build
eigen   opencv-build    opendetection_data
eigen_build opencv_contrib  pcl
eigen_install   opendetection

到目前为止一切顺利,现在让我们尝试配置 opendetection 并在 opendetection_build 中生成解决方案,并在 ~/src 文件夹中找到 pendetection 的依赖项,即前两个依赖项,我希望在 opencv-build 和 eigen-build 文件夹中找到 opencv 和 eigen。

OpenCV 立即失败,正如预期的那样:

Could not find a package configuration file provided by "OpenCV" with any of the following names:

OpenCVConfig.cmake
opencv-config.cmake

Add the installation prefix of "OpenCV" to CMAKE_PREFIX_PATH or set "OpenCV_DIR" to a directory containing one of the above files. If "OpenCV" provides a separate development package or SDK, be sure it has been installed.

很好,因为我想明确告诉 CMake 在我的 ~/src 文件夹下查找依赖包。问题:使用 CMAKE_PREFIX_PATH=/users/foo/src 是否是完成我想要的推荐方式 - 在特定路径下查找所有子包?

之后,CMake 找到 OpenCV(良好),并设置 OpenCV_DIR = /Users/foo/src/opencv-build。

问题:鉴于我已经对 opencv-install 进行了“安装”(使用 CMAKE_INSTALL_PREFIX 并构建 OpenCV 的安装目标,它不应该在 opencv-install 文件夹中找到 OpenCV 而不是 opencv-build 吗?

继续 eigen,我已经配置并构建了 eigen,并将其安装到 ~/src/eigen-install,因为它是 CMAKE_PREFIX_PATH (~/src) 的子文件夹,我可能希望找到它。但似乎并非如此。有人可以向我解释我不明白的地方吗?特别是考虑到模板库中的 Eigen,并且在 CMAKE_PREFIX_PATH 下至少有三个文件夹(eigen、eigen_build 和 eigen_install),我认为 CMake 会在其中找到一些东西,我想我一定是在这里做错了。我从过去的经验中知道,我可以在 CMakeGUI 中手动设置 EIGEN_INCLUDE_DIR,然后继续破解,但这似乎是错误的。

我非常愿意为未来像我一样愚蠢的人写一个网页来解释这一点,如果还没有的话,虽然我不明白如何使用 CMake 进行基本项目配置和生成显然如此对每个人都很明显,但对我来说却很不透明。我实际上已经使用 CMake 几年了,通常只是手动设置 Boost_INCLUDE_Dir、Foo_INCLUDE_PATH 等,但显然这不是正确的解决方案。通常,在花费几天时间通过各种包通过手动设置 INCLUDE PATHS、LIBRARY PATHS 和其他选项来生成解决方案后,我只是处理解决方案,不再接触 CMake。但是我很想了解我对 find_package 的遗漏,因为我想要控制我的项目依赖项的(当然并不少见)用例,而不仅仅是使用 sudo port install * 并将随机版本的项目安装到我的全局系统文件夹中。

【问题讨论】:

    标签: c++ opencv image-processing boost cmake


    【解决方案1】:

    如错误消息所述,CMAKE_PREFIX_PATH 应设置为软件包的安装前缀。例如,如果包是使用 CMake 构建的,则这是 CMAKE_INSTALL_PREFIX 变量的值,如果包是使用 Autotools 构建的,则这是用于配置它的 --prefix 选项的值,等等。

    CMake 不会搜索 CMAKE_PREFIX_PATH 下的每个目录。这就是为什么如果您在/users/foo/src/eigen-install 安装了软件包,将其指定为/users/foo/src 是没有用的。

    相反,您可以将所有 3d 方包安装到/users/foo/src/install,并在您的主项目中将该路径用作CMAKE_PREFIX_PATH

    【讨论】:

    • 这是我听过的最清晰的评论,并且充分解释了这种行为。但要澄清一下,CMake 中是否有 no 方法可以通过干净分离的安装来实现我想要的?诚然,我现在可以清楚地创建自己的“安装”子文件夹,但我不明白为什么我要这样做并安装所有内容以“安装”。一个包含 VTK、opencv、pcl 等的文件夹都转储到其中是一个相当重要的文件夹,如果我选择更新它,那么就没有办法清理重建子包。
    • is there no way in CMake to achieve what I want, with cleanly separated installations? - 这是可能的,但在这种情况下您需要明确指定所有安装前缀。例如,您可以将它们全部收集到CMAKE_PREFIX_PATH(这个变量实际上可能是一个list)。 there's then no way to clean-rebuild a sub-package if I, for example, choose to update it. - 通常,make uninstall 会从安装目录中干净地删除包的文件,并且不会触及同一目录中的其他包。因此,具有单个安装前缀并不能阻止重新构建单独的包。
    • 谢谢。一般来说,我相信人们编写的卸载脚本不如我相信吹走他们写的文件夹,但你的建议给了我工作所需的一切。我对为什么找到 OpenCV 有点困惑(尽管在任意子文件夹中)。这是否意味着 OpenCV 已经覆盖了 find_package 的行为,并且这种覆盖很常见吗?
    猜你喜欢
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    • 2015-06-11
    • 2017-02-11
    • 1970-01-01
    • 2021-01-17
    相关资源
    最近更新 更多