查找库

查找路径

CMAKE_PREFIX_PATH 定义了查找 cmake 库的路径, 可以在编译时指定这个选项, 比如, 在使接非系统目录中安装的 Qt5.12 时, 可以写成:

cmake -DCMAKE_PREFIX_PATH=/path/to/qt5.12/cmake ..

find_package()

最常用的引入第三方库的方式就是使用 find_package() 命令:

find_package(Foo 2.0 REQUIRED)
...
target_link_libraries(Bar Foo::Foo ...)

cmake 项目本身提供了很多常用第三方库的查找脚本, 我们也可以自定义这类脚本. 将这些 脚本放在项目的 cmake 目录, 然后引入整个目录:

set(CMAKE_MODULE_PATH
    ${CMAKE_SOURCE_DIR}/cmake
    ${CMAKE_MODULE_PATH})

自定义查找模块

以查找 Foo 库为例, 提供一个基本的模板:

find_path(Foo_INCLUDE_DIR foo.h)
find_library(Foo_LIBRARY foo)
# 将这两个选项标记为高级选项, 让该库默认不在 cmake gui 工具中显示.
mark_as_advanced(Foo_INCLUDE_DIR Foo_LIBRARY)

# 用于提供 Foo_FOUND 变量, 也处理 QUITE/REQUIRED 等选项, 以及库的版本号.
# 比如: find_package(Foo 2.0 REQUIRED)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Foo
    REQUIRED_VARS Foo_LIBRARY FOO_INCLUDE_DIR
    )

# 添加一个自定义的 target
if(Foo_FOUND AND NOT TARGET Foo::Foo)
    add_library(Foo::Foo UNKNOWN IMPORTED)
    set_target_properties(Foo::Foo PROPERTIES
        IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
        IMPORTED_LOCATION "${Foo_LIBRARY}"
        INTERFACE_INCLUDE_DIRECTORIES "${Foo_INCLUDE_DIR}"
        )
endif()

依赖关系

如果引入的模块比较多的话,相互间的依赖关系就容易复杂,可以使用 cmake 自带的 命令来生成依赖关系图:

cmake --graphviz=foo.dot

生成的 dot 文件可以再转为一般的图片格式。

我们可以将这个步骤固化下来,形成一个 cmake 模块,比如就叫 GeneriteDeps.cmake

add_custom_target(generate_deps
    COMMAND cmake --graphviz=deps.dot .
    COMMAND dot -Tsvg -o deps.svg deps.dot
    COMMAND setsid xdg-open deps.svg
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    )

这样可以在命令行生成:

cmake --build . --target generate_deps

但方便的是,可以直接在 IDE 里触发它。

比如,libuv 库的依赖图是这样的: libuv-deps