Cmake命令之find_library介绍

2022-03-02  本文已影响0人  Domibaba

一、命令格式

  该命令用于查找库(动态库或者静态库),当构建依赖于第三方库/系统库,可以使用该命令来查找并使用库(Cmake中有另外一个命令find_package,能获取库的更多信息,具体可以参考Cmake命令之find_package介绍

find_library (<VAR> name [path1 path2 ...])

find_library ( <VAR> name | NAMES name1 [name2 ...] [NAMES_PER_DIR] [HINTS [path | ENV var]... ] [PATHS [path | ENV var]... ] [PATH_SUFFIXES suffix1 [suffix2 ...]] [DOC "cache documentation string"] [NO_CACHE] [REQUIRED] [NO_DEFAULT_PATH] [NO_PACKAGE_ROOT_PATH] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [NO_SYSTEM_ENVIRONMENT_PATH] [NO_CMAKE_SYSTEM_PATH] [CMAKE_FIND_ROOT_PATH_BOTH | ONLY_CMAKE_FIND_ROOT_PATH | NO_CMAKE_FIND_ROOT_PATH] )

  几个基本参数的解析

二、命令解析

  通过一个例子来看下基本的使用,假设我们目录和文件树如下,:

CMakeLists.txt    顶层目录的cmake
test.cpp          顶层目录测试文件
mylib             库文件所在目录
--- CMakeLists.txt 子目录cmake
--- mymath.h       头文件
--- mymath.cpp     实现文件
--- libmymath.a    库文件

  我们在mylib中生成最终的库libmymath.a,然后在顶层的CMakeLists.txt中查找这个库文件,几个文件的具体内容如下:

// 顶层CMakeLists.txt
cmake_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath ./mymath)
add_executable (test test.cpp)
target_link_libraries (test ${libvar})
// test.cpp
#include "./mylib/mymath.h"
int main(int argc, char **argv)
{
    int sum = mymath::add(1, 2);
    return 0;
}
// mylib/CMakeLists.txt
cmake_minimum_required (VERSION 3.21)
project (mymath)
add_library (mymath mymath.cpp)
// mylib/mymath.h
namespace mymath {
    int add(int a, int b);
};
// mylib/mymath.cpp
#include "mymath.h"
#include <iostream>
namespace mymath {
    int add(int a, int b)
    {
        std::cout << "Add " << a << " and " << b << " is " << a + b << std::endl;
        return a + b;
    }
};

  在./mylib/下执行cmake .make以便生成库libmymath.a,然后在./目录下执行cmake .make,得到可执行文件test,运行test的结果为:

./test
Add 1 and 2 is 3

三、更多细节

3.1 库的搜索路径

  库的搜索路径分为两大类:默认搜索路径附加搜索路径
  默认搜索路径包含cmake定义的以CMAKE开头的一些变量(例如CMAKE_LIBRARY_ARCHITECTURECMAKE_PREFIX_PATHCMAKE_LIBRARY_PATHCMAKE_FRAMEWORK_PATH)、标准的系统环境变量(例如系统环境变量LIBPATH定义的路径)、系统的默认的库安装路径(例如/usr/usr/lib等);
  附加搜索路径find_library命令中通过HINTSPATHS指定的路径;

// 顶层CMakeLists.txt
set (CMAKE_LIBRARY_PATH "./mylib")
find_library (libvar mymath ./mylib2 NO_DEFAULT_PATH)
// 执行"cmake ."后的提示
CMake Error at CMakeLists.txt:23 (message):
  required mymath library but not found!

 1) 通过命令行使用-D指定的CMAKE_XXX_PATH变量,也就是形如cmake . -DCMAKE_XXX_PATH=paths的格式。其中CMAKE_XXX_PATH包含如下几个:
  CMAKE_PREFIX_PATH:指定搜索目录的前缀,如果前缀有多个,需要以分号分割的列表方式提供,该变量默认为空,一旦该变量非空,那么会搜索该变量提供的目录,以及${CMAKE_PREFIX_PATH}/lib;例如CMAKE_PREFIX_PATH=A;B,那么find_library会从AB以及A/libB/lib中搜索库是否存在;
  
CMAKE_LIBRARY_ARCHITECTURE:如果该变量被设置,那么会搜索目录${CMAKE_PREFIX_PATH}/lib/${CMAKE_LIBRARY_ARCHITECTURE};
  
CMAKE_LIBRARY_PATH:指定find_library的库查找目录,默认值为空,多个值时需要以分号分割列表指定;
  
CMAKE_FRAMEWORK_PATH*:指定macOS的框架作为搜索路径。

// 顶层CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath)
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()
> cmake . -DCMAKE_LIBRARY_PATH=./mylib
-- mymath library found in /XXX/mylib/libmymath.a

 2) 通过在环境变量中指定CMAKE_XXX_PATH变量,例如在window的环境变量中增加CMAKE_XXX_PATH(以;分割多个路径)、Linuxshell配置文件中添加(以:分割多个路径)。用法和cmake -D指定类似,例如在我的机器中(macOS),在.zshrc(我的命令行配置文件)中增加export CMAKE_LIBRARY_PATH="/XXX/……/mylib",即可在将该目录加入到搜索路径中。
 3) HINTS选项指定的路径。
 4) 系统环境变量指定的目录,默认是LIBPATH指定的路径。例如在PATH中指定库搜索目录;

// 顶层CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath)
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()
// 命令行中执行
export PATH=$PATH:./mylib
cmake .

// 执行结果
-- mymath library found in /XXX/mylib/libmymath.a

 也可以通过find_library中的PATHS ENV 环境变量名称cmake中使用环境变量名称的格式为$ENV{环境变量名称})来指定从哪个环境变量名称中获取路径,例如定义一个TESTPATH环境变量并赋值为./mylib,并在find_library命令中指定使用该环境变量:

// 顶层CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath PATHS ENV TESTPATH)
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()
// 命令行中执行
export TESTPATH=./mylib
cmake .

// 执行结果
-- mymath library found in /XXX/mylib/libmymath.a

 5)跟当前系统相关的平台文件路径,一般来说指的是当前系统安装软件的标准目录,不同的操作系统对应的路径有所不同。camkefind_library与此相关的也有如下几个,CMAKE_SYSTEM_XXX_PATH变量,这些:
  CMAKE_SYSTEM_PREFIX_PATH:指定安装目录的前缀,例如在Windows下的/XXXX/Program FilesLinux下的/usr/usr/local等。find_library命令会搜索这些前缀目录,也会以这些目录加上lib进行搜索,例如搜索/usr/local/lib
  CMAKE_SYSTEM_LIBRARY_PATH:默认是当前系统的标准目录,不建议修改它;例如在我的系统,这个变量的值是/usr/lib/X11
  CMAKE_SYSTEM_FRAMEWORK_PATH:macOS框架路径,默认是当前系统的标准目录,不建议修改它;例如在我的系统,这个变量的值包含了路径/Library/Frameworks
 6)PATHS选项指定的路径。

3.2 find_library命令中的部分选项

// 顶层CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath PATHS ./ PATH_SUFFIXES mylib) # 会从./以及./mylib中搜索指定的mymath库是否存在
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()
// 命令行中执行
cmake .

// 执行结果
-- mymath library found in /XXX/mylib/libmymath.a
// 顶层CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath PATHS ./mylib NO_CACHE)
find_library (libvar mymath PATHS ./lib NO_CACHE) # 即使./lib中也存在mymath库,由于在上一步的./mylib中已经找到,因此本条命令不会执行查找
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()

// 命令行中执行
cmake .

// 执行结果
-- mymath library found in /XXX/mylib/libmymath.a
// 顶层CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath PATHS ./mylib) # libvar是缓存条目,会存入`CMakeCache.txt`,后续即使把PATHS ./mylib改成PATHS ./mylib2(不存在库mymath),也不会保存,因为libvar变量已经从缓存中载入
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()

// 命令行中执行
cmake .

// 执行结果
-- mymath library found in /XXX/mylib/libmymath.a

// 可以在CMakeCache.txt中找到libvar,命令行中执行cat命令查看一下
> cat CMakeCache.txt | grep "libvar"
libvar:FILEPATH=/XXX/mylib/libmymath.a

// 即使此时把顶层CMakeLists.txt中的PATHS修改为不包含mymath库的路径,执行结果也能找到
find_library (libvar mymath PATHS ./mylib2)

// cmake .执行结果
-- mymath library found in /XXX/mylib/libmymath.a
// 顶层CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath PATHS ./mylib REQUIRED)
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()

// 命令行中执行
cmake .

// 执行结果
CMake Error at CMakeLists.txt:4 (find_library):
  Could not find libvar using the following names: mymath
-- Configuring incomplete, errors occurred!
// 顶层CMakeLists.txt
cmake_minimum_required (VERSION 3.21)
project (fl)

find_library (libvar mymath PATHS ./mylib2) # 没有指定REQUIRED选项,即使当时没有找到,会继续往下执行
find_library (libvar mymath PATHS ./mylib)
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()

// 命令行中执行
cmake .

// 执行结果
-- mymath library found in /XXX/mylib/libmymath.a
// 顶层CMakeLists.txt
cmake_minimum_required (VERSION 3.21)
project (fl)

find_library (libvar mymath PATHS ./lib) # 假设lib目录不存在但是lib64目录存在
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()

// 命令行中执行
cmake .

// 执行结果
-- mymath library found in /XXX/lib64/libmymath.a


附录:参考资料

  1. https://cmake.org/cmake/help/latest/command/find_library.html#find-library
上一篇 下一篇

猜你喜欢

热点阅读