Cmake命令之find_library介紹

一、命令格式

??該命令用于查找?guī)欤▌?dòng)態(tài)庫(kù)或者靜態(tài)庫(kù)),當(dāng)構(gòu)建依賴(lài)于第三方庫(kù)/系統(tǒng)庫(kù),可以使用該命令來(lái)查找并使用庫(kù)(Cmake中有另外一個(gè)命令find_package,能獲取庫(kù)的更多信息,具體可以參考Cmake命令之find_package介紹

  • 簡(jiǎn)潔的格式

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] )

??幾個(gè)基本參數(shù)的解析
  • <var>用于存儲(chǔ)該命令執(zhí)行的結(jié)果,也就是找到的庫(kù)的全路徑(包含庫(kù)名):
    ?1. <var>可以是普通變量(需要指定NO_CACHE選項(xiàng)),也可以是緩存條目(意味著會(huì)存放在CMakeCache.txt中,不刪除該文件或者用set重新設(shè)置該變量,其存儲(chǔ)的值不會(huì)再刷新);
    ?2. 當(dāng)庫(kù)能被找到,<var>會(huì)被存放正常的庫(kù)路徑,當(dāng)庫(kù)未被找到,<var>中存放的值為"<var>-NOTFOUND"。只要<var>中的值不是"<var>-NOTFOUND",那么即使多次調(diào)用find_library,<var>也不會(huì)再刷新;
  • name用于指定待查找的庫(kù)名稱(chēng),庫(kù)名稱(chēng)可以使用全稱(chēng),例如libmymath.a(優(yōu)先會(huì)當(dāng)成全名搜索);也可以不帶前綴(例如前綴lib)和后綴(例如Linux中的.so、.a,Mac中的.dylib等),直接使用mymath;
  • path用于指定庫(kù)的查找的路徑;

二、命令解析

??通過(guò)一個(gè)例子來(lái)看下基本的使用,假設(shè)我們目錄和文件樹(shù)如下,:

CMakeLists.txt    頂層目錄的cmake
test.cpp          頂層目錄測(cè)試文件
mylib             庫(kù)文件所在目錄
--- CMakeLists.txt 子目錄cmake
--- mymath.h       頭文件
--- mymath.cpp     實(shí)現(xiàn)文件
--- libmymath.a    庫(kù)文件

??我們?cè)?code>mylib中生成最終的庫(kù)libmymath.a,然后在頂層的CMakeLists.txt中查找這個(gè)庫(kù)文件,幾個(gè)文件的具體內(nèi)容如下:

// 頂層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/下執(zhí)行cmake .make以便生成庫(kù)libmymath.a,然后在./目錄下執(zhí)行cmake .make,得到可執(zhí)行文件test,運(yùn)行test的結(jié)果為:

./test
Add 1 and 2 is 3

三、更多細(xì)節(jié)

3.1 庫(kù)的搜索路徑

??庫(kù)的搜索路徑分為兩大類(lèi):默認(rèn)搜索路徑附加搜索路徑。
??默認(rèn)搜索路徑包含cmake定義的以CMAKE開(kāi)頭的一些變量(例如CMAKE_LIBRARY_ARCHITECTURE、CMAKE_PREFIX_PATH、CMAKE_LIBRARY_PATHCMAKE_FRAMEWORK_PATH)、標(biāo)準(zhǔn)的系統(tǒng)環(huán)境變量(例如系統(tǒng)環(huán)境變量LIBPATH定義的路徑)、系統(tǒng)的默認(rèn)的庫(kù)安裝路徑(例如/usr、/usr/lib等);
??附加搜索路徑find_library命令中通過(guò)HINTSPATHS指定的路徑;

  • 當(dāng)指定NO_DEFAULT_PATH選項(xiàng)時(shí),默認(rèn)搜索路徑不會(huì)生效,只會(huì)用到附加搜索路徑。修改頂層的CMakeLists.txt,在find_library中指定選項(xiàng)NO_DEFAULT_PATH,可以看到即使指定了CMAKE_XXX_PATH的值,也會(huì)被忽略,下面的代碼執(zhí)行cmake .(建議在執(zhí)行之前rm CMakeCache.txt刪除)會(huì)提示錯(cuò)誤,而去除NO_DEFAULT_PATH選項(xiàng)后能正常找到庫(kù)的路徑。
// 頂層CMakeLists.txt
set (CMAKE_LIBRARY_PATH "./mylib")
find_library (libvar mymath ./mylib2 NO_DEFAULT_PATH)
// 執(zhí)行"cmake ."后的提示
CMake Error at CMakeLists.txt:23 (message):
  required mymath library but not found!
  • 當(dāng)未指定NO_DEFAULT_PATH選項(xiàng)時(shí),搜索路徑按照優(yōu)先級(jí)從高到低依次是:

?1) 通過(guò)命令行使用-D指定的CMAKE_XXX_PATH變量,也就是形如cmake . -DCMAKE_XXX_PATH=paths的格式。其中CMAKE_XXX_PATH包含如下幾個(gè):
??CMAKE_PREFIX_PATH:指定搜索目錄的前綴,如果前綴有多個(gè),需要以分號(hào)分割的列表方式提供,該變量默認(rèn)為空,一旦該變量非空,那么會(huì)搜索該變量提供的目錄,以及${CMAKE_PREFIX_PATH}/lib;例如CMAKE_PREFIX_PATH=A;B,那么find_library會(huì)從A、B以及A/libB/lib中搜索庫(kù)是否存在;
??
CMAKE_LIBRARY_ARCHITECTURE:如果該變量被設(shè)置,那么會(huì)搜索目錄${CMAKE_PREFIX_PATH}/lib/${CMAKE_LIBRARY_ARCHITECTURE};
??
CMAKE_LIBRARY_PATH:指定find_library的庫(kù)查找目錄,默認(rèn)值為空,多個(gè)值時(shí)需要以分號(hào)分割列表指定;
??
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) 通過(guò)在環(huán)境變量中指定CMAKE_XXX_PATH變量,例如在window的環(huán)境變量中增加CMAKE_XXX_PATH(以;分割多個(gè)路徑)、Linuxshell配置文件中添加(以:分割多個(gè)路徑)。用法和cmake -D指定類(lèi)似,例如在我的機(jī)器中(macOS),在.zshrc(我的命令行配置文件)中增加export CMAKE_LIBRARY_PATH="/XXX/……/mylib",即可在將該目錄加入到搜索路徑中。
?3) HINTS選項(xiàng)指定的路徑。
?4) 系統(tǒng)環(huán)境變量指定的目錄,默認(rèn)是LIBPATH指定的路徑。例如在PATH中指定庫(kù)搜索目錄;

// 頂層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()
// 命令行中執(zhí)行
export PATH=$PATH:./mylib
cmake .

// 執(zhí)行結(jié)果
-- mymath library found in /XXX/mylib/libmymath.a

?也可以通過(guò)find_library中的PATHS ENV 環(huán)境變量名稱(chēng)cmake中使用環(huán)境變量名稱(chēng)的格式為$ENV{環(huán)境變量名稱(chēng)})來(lái)指定從哪個(gè)環(huán)境變量名稱(chēng)中獲取路徑,例如定義一個(gè)TESTPATH環(huán)境變量并賦值為./mylib,并在find_library命令中指定使用該環(huán)境變量:

// 頂層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()
// 命令行中執(zhí)行
export TESTPATH=./mylib
cmake .

// 執(zhí)行結(jié)果
-- mymath library found in /XXX/mylib/libmymath.a

?5)跟當(dāng)前系統(tǒng)相關(guān)的平臺(tái)文件路徑,一般來(lái)說(shuō)指的是當(dāng)前系統(tǒng)安裝軟件的標(biāo)準(zhǔn)目錄,不同的操作系統(tǒng)對(duì)應(yīng)的路徑有所不同。camkefind_library與此相關(guān)的也有如下幾個(gè),CMAKE_SYSTEM_XXX_PATH變量,這些:
??CMAKE_SYSTEM_PREFIX_PATH:指定安裝目錄的前綴,例如在Windows下的/XXXX/Program Files,Linux下的/usr/usr/local等。find_library命令會(huì)搜索這些前綴目錄,也會(huì)以這些目錄加上lib進(jìn)行搜索,例如搜索/usr/local/lib;
??CMAKE_SYSTEM_LIBRARY_PATH:默認(rèn)是當(dāng)前系統(tǒng)的標(biāo)準(zhǔn)目錄,不建議修改它;例如在我的系統(tǒng),這個(gè)變量的值是/usr/lib/X11
??CMAKE_SYSTEM_FRAMEWORK_PATH:macOS框架路徑,默認(rèn)是當(dāng)前系統(tǒng)的標(biāo)準(zhǔn)目錄,不建議修改它;例如在我的系統(tǒng),這個(gè)變量的值包含了路徑/Library/Frameworks;
?6)PATHS選項(xiàng)指定的路徑。

3.2 find_library命令中的部分選項(xiàng)

  • PATH_SUFFIXES:為每個(gè)搜索目錄添加變量PATH_SUFFIXES指定的后綴目錄,假設(shè)當(dāng)前搜索的目錄為/A;/C/D,PATH_SUFFIXES指定的后綴目錄為PS(當(dāng)前可以指定多個(gè),以分號(hào)分割開(kāi)即可),那么除了/A;/C/D之外,/A/PS;/C/D/PS也會(huì)被搜索。
// 頂層CMakeLists.txt
make_minimum_required (VERSION 3.21)
project (fl)
find_library (libvar mymath PATHS ./ PATH_SUFFIXES mylib) # 會(huì)從./以及./mylib中搜索指定的mymath庫(kù)是否存在
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()
// 命令行中執(zhí)行
cmake .

// 執(zhí)行結(jié)果
-- mymath library found in /XXX/mylib/libmymath.a
  • NO_CACHE:該選項(xiàng)將<var>變量當(dāng)成一個(gè)普通變量而不是一個(gè)緩存條目,需要cmake 3.21及以上的版本支持。
    默認(rèn)find_library命令最終存儲(chǔ)結(jié)果的變量<var>是一個(gè)緩存條目(可以理解為全局變量,且會(huì)寫(xiě)入CMakeCache.txt文件,在不清除CMakeCache.txt文件的情況下,每次執(zhí)行cmake都會(huì)先從CMakeCache.txt載入該變量的值),而且find_library命令只要檢查到<var>有值(<var>不為空且<var>不為<var>-NOTFOUND),是不會(huì)執(zhí)行實(shí)際查找?guī)斓膭?dòng)作。因此多次對(duì)同一個(gè)變量<var>執(zhí)行find_library命令,在第一次<var>被賦值后,后續(xù)的find_library命令不會(huì)被執(zhí)行。結(jié)合緩存條目變量,那么只要找到一個(gè)<var>,后續(xù)每次執(zhí)行cmake命令得到的<var>都是首次找到的<var>值(除非清除CMakeCache.txt文件)
    因此NO_CACHE選項(xiàng)要謹(jǐn)慎使用,它會(huì)使得每次cmake命令都會(huì)重新調(diào)用find_library查找,增加cmake的開(kāi)銷(xiāo)。
// 頂層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庫(kù),由于在上一步的./mylib中已經(jīng)找到,因此本條命令不會(huì)執(zhí)行查找
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()

// 命令行中執(zhí)行
cmake .

// 執(zhí)行結(jié)果
-- 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是緩存條目,會(huì)存入`CMakeCache.txt`,后續(xù)即使把PATHS ./mylib改成PATHS ./mylib2(不存在庫(kù)mymath),也不會(huì)保存,因?yàn)閘ibvar變量已經(jīng)從緩存中載入
if (${libvar} STREQUAL "libvar-NOTFOUND")
    message (FATAL_ERROR "required mymath library but not found!")
else()
    message (STATUS "mymath library found in ${libvar}")
endif()

// 命令行中執(zhí)行
cmake .

// 執(zhí)行結(jié)果
-- mymath library found in /XXX/mylib/libmymath.a

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

// 即使此時(shí)把頂層CMakeLists.txt中的PATHS修改為不包含mymath庫(kù)的路徑,執(zhí)行結(jié)果也能找到
find_library (libvar mymath PATHS ./mylib2)

// cmake .執(zhí)行結(jié)果
-- mymath library found in /XXX/mylib/libmymath.a
  • REQUIRED:指定該選項(xiàng)后,當(dāng)找不到庫(kù),會(huì)輸出一條錯(cuò)誤信息并終止cmake處理過(guò)程;未指定REQUIRED選項(xiàng),當(dāng)find_library未找到庫(kù)時(shí),后續(xù)find_library有針對(duì)<var>的調(diào)用會(huì)繼續(xù)查找。該選項(xiàng)需要cmake 3.18及以上的版本支持。
// 頂層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()

// 命令行中執(zhí)行
cmake .

// 執(zhí)行結(jié)果
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) # 沒(méi)有指定REQUIRED選項(xiàng),即使當(dāng)時(shí)沒(méi)有找到,會(huì)繼續(xù)往下執(zhí)行
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()

// 命令行中執(zhí)行
cmake .

// 執(zhí)行結(jié)果
-- mymath library found in /XXX/mylib/libmymath.a
  • NO_XXX_PATH3.1節(jié)介紹了關(guān)于搜索路徑的查找順序,NO_XXX_PATH選項(xiàng)用于跳過(guò)指定的搜索路徑。
    NO_CMAKE_PATH:指定該選項(xiàng)會(huì)忽略cmake -DCMAKE_XXX_PATH=paths的路徑;
    NO_CMAKE_ENVIRONMENT_PATH:指定該選項(xiàng)會(huì)忽略環(huán)境變量指定的CMAKE_XXX_PATH路徑;
    NO_SYSTEM_ENVIRONMENT_PATH:指定該選項(xiàng)會(huì)忽略系統(tǒng)標(biāo)準(zhǔn)環(huán)境變量指定的路徑;
    NO_CMAKE_SYSTEM_PATH:指定該選項(xiàng)會(huì)忽略平臺(tái)路徑指定的CMAKE_SYSTEM_XXX_PATH路徑;

  • CMAKE_FIND_ROOT_PATH:指定搜索的根路徑。

  • CMAKE_SYSROOT:該選項(xiàng)的值會(huì)傳遞給編譯器的--sysroot標(biāo)記(備注:--sysroot用于指定編譯搜索庫(kù)和頭文件的根目的,例如編譯器原本搜搜索/A/include/A/lib,使用--sysroot=DIR后,編譯器搜索的庫(kù)和頭文件目錄變成/DIR/A/include/DIR/A/lib)。

  • FIND_LIBRARY_USE_LIB32_PATHSFIND_LIBRARY_USE_LIBX32_PATHS、FIND_LIBRARY_USE_LIB64_PATHS:這三個(gè)屬性指明了要在搜索路徑中匹配到lib/后,會(huì)為這個(gè)目錄添加一個(gè)后綴,然后在添加后綴后的目錄中搜索庫(kù)。三個(gè)屬性添加后的值為lib32/、libx32/、lib64/,這個(gè)是根據(jù)平臺(tái)(32位或64位自動(dòng)添加的),例如在我的系統(tǒng)中,除了搜索lib/外,也會(huì)搜索lib64/

// 頂層CMakeLists.txt
cmake_minimum_required (VERSION 3.21)
project (fl)

find_library (libvar mymath PATHS ./lib) # 假設(shè)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()

// 命令行中執(zhí)行
cmake .

// 執(zhí)行結(jié)果
-- mymath library found in /XXX/lib64/libmymath.a

?


附錄:參考資料

  1. https://cmake.org/cmake/help/latest/command/find_library.html#find-library
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容