从Target 角度看 CMake (三)find_package 都找到了什么

        除了 add_library() 与 add_executable(),创建Target 最多的方式可能就是find_package 了。几乎所有cmake 的入门资料都会包含 find_packge的基础功能介绍,这里不在赘述,只是列出几个要点来。

        find_package有两种工作模式:module 模式与config 模式。module 模式通常是通过调用Find.cmake 来实现,而 package 模式则是通过查找并调用Config.cmake 或 Config-version.cmake 来实现。

        CMake 内置了常用的 Find.cmake 文件,对于不同的系统存贮位置也不相同,下面列几个例子:

macOS:/Applications/CMake.app/Contents/share/cmake-3.16/Modules
ubuntu:
windows:C:\Program Files\CMake\share\cmake-3.23\Modules

find_package 都找到了什么

        显然不同的外部模块/包,FindPackage找到的东西是不相同的,多数情况下我们也并不需要详细了解FindPackage 都找到了哪些信息,只要FindPackage运行正常,后面就全交给cmake了,因为cmake 会自动根据需要去使用FindPackage 找到的信息。就我自己的工作经验来看,有两种情况我们需要了解FindPackage 到底都(需要)找到了哪些信息。

        一个是我们需要对包中的文件进行特殊操作,比如把找到的包中的文件复制到指定的目录下,这时就需要知道文件的二进制库的名称与位置;另一种情况是我们自己要开发供别人使用的 .cmake文件,此时就必须要按cmake 的要求返回尽可能多的信息,以供调用者使用。

        find_package 会通过两种方法返回查找结果,一种是直接定义好的变量,比如:xxx_FOUND、xxx_INCLUDE_DIR。另一种则是要通过get_target_property() 取属性的方法来取得的信息。

        property 也分为两种,一种是 CMake 预定义的Target 属性 另一种是通过 set_target_properties()  自己设置的属性。

CMake 预定义的Target 属性https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#target-properties        简单分析一下cmake 3.24 关于target 的 property 有328个,具体内容就看cmake 文档吧。仅举一个例子说明一下 INTERFACE_LINK_LIBRARIES:

find_package(Boost COMPONENTS log)
get_target_property(BOOST_LOG_ILL Boost::log INTERFACE_LINK_LIBRARIES)
message("INTERFACE_LINK_LIBRARIES :${BOOST_LOG_ILL}")

运行结果:
INTERFACE_LINK_LIBRARIES :Boost::atomic;Boost::chrono;Boost::filesystem;Boost::regex;Boost::thread;Boost::headers

        在find_package 中只查找了log 一个组件,通过INTERFACE_LINK_LIBRARIES 属性,可以获取所有它依赖的组件。

        是否有简单办法列出一个Target 的所有属性,包括预定义的属性以及自定义的属性?至本文写作时为止,答案是不行!StackOverflow 上有一些方法,但是很丑。

How to print all the properties of a target in cmake?https://stackoverflow.com/questions/32183975/how-to-print-all-the-properties-of-a-target-in-cmake

典型应用

        在CMake 找到Target后,经常会提示库文件不在PATH路径中的问题,例如boost_xxx.dll 或 opencv_xxx.dll 不在PATH 中,在程序运行的时候可能找不到对应的.dll

        通常在调试程序的时候,只要将其路径加入到PATH 路径中就可以了。

        但是在某些情况下,还是需要找到这些dll 的具体位置的,制作安装程序的时候就是如此。

        此时可以使用IMPORTED_LOCATION_RELEASE 得到文件的路径,再把它复制到对应的目录下就可以了。

get_target_property(boost_log_dll Boost::log IMPORTED_LOCATION_RELEASE)
message(${boost_log_dll})

运行结果
C:/Boost/lib/boost_log-vc143-mt-x64-1_79.dll

:: Alias 与 Imported Target

        :: 代表别名或是引用的目标(Imported Target)。无论是别名还是引用的库都是指读的。

       先看下面的例子,使用boost log 库的时候可以有两种写法

target_link_libraries(${TargetName} boost_log)

        或者写成下面这样:

target_link_libraries(${TargetName} Boost::log)

        第一种写法,在Linux 下多数情况下是可以了,因为连接的时候会自动连接 libboost_log.lib 而在Windows 下则相当麻烦,在我的机器上要连接的文件是 boost_log-vc143-mt-x64-1_79.lib 

        如果考虑 release 版与 debug 版要连接不同的库的情况,那要更复杂一些:对于boost debug版是加 -gd 而对于 opencv 则是在库文件名上加d

        第二种写法使用了:: 代表此处是一个引用的Target,或者只是一个别名。具体使用的时候,cmake会自动根据编译选项选择对应的库文件,编写CMakeLists 时就不用为不同的编译环境以及外部库的版本而操心了。

        

你可能感兴趣的:(CMake,windows,opencv,人工智能)