find_file命令按照全路徑查找指定的文件,并將查找的結(jié)果存儲在<VAR>中,如果指定了NO_CACHE選項,那么<VAR>是一個普通變量,否則<var>是一個緩存條目(會存儲在CMakeCache.txt文件中)。
??如果找到了指定的文件,那么結(jié)果存入<VAR>中,除非<VAR>被清空,否則后續(xù)繼續(xù)調(diào)用find_file也不會再繼續(xù)查找;如果沒有找到文件,那么<VAR>的值為<var>_NOTFOUND。
一、命令格式
find_file命令有兩種格式,速記的格式為:
find_file (<VAR> name1 [path1 path2 ...])
通用的格式為:
find_file (
<VAR>
name | NAMES name1 [name2 ...]
[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]
)
二、命令使用舉例
未指定NO_DEFAULT_PATH選項的情況下,find_file會以CMAKE_FIND_ROOT_PATH、CMAKE_SYSROOT等CMake變量(默認值為空)指定的路徑為根路徑,與PATHS或HINTS指定路徑拼接成全路徑的進行查找;若指定了NO_DEFAULT_PATH選項,查找路徑會稍微復雜一些,具體查找過程會在四、查找過程進行詳細介紹。
下面來看幾個例子(所有例子的運行環(huán)境為macOS),例子中使用的文件或目錄樹結(jié)構(gòu)為:
├── CMakeLists.txt
├── myfile1
└── path
└── myfile2
- 使用速記命令格式查找文件,注意指定查找路徑和未指定查找路徑的區(qū)別。
# CMakeLists.txt
find_file(result myfile1) # 未指定查找路徑,因為默認根路徑變量為空,因此無法找到
message("myfile1 find result: ${result}")
find_file(result2 myfile2) # 未指定查找路徑,因為默認根路徑變量為空,因此無法找到
message("myfile2 find result: ${result2}")
find_file(result3 myfile2 ./path) # 指定查找路徑,能查找到
message("myfile3 find result in ./path: ${result3}")
執(zhí)行
cmake .運行結(jié)果:
myfile1 find result: result-NOTFOUND
myfile2 find result: result2-NOTFOUND
myfile3 find result in ./path: /XXX/YYY/ZZZ/path/myfile2
- 使用通用命令格式查找文件,可以指定多個查找目標。當指定查找多個目標時,查找結(jié)果
<VAR>存儲的是第一個找到的文件,因此,只有當所有指定的文檔都無法找到,<VAR>的值才會賦值為<VAR>_NOTFOUND。
# CMakeLists.txt
find_file(find_result1 NAMES myfile1 myfile2)
message("find result: ${find_result1}")
find_file(find_result2 NAMES myfile1 myfile2 PATHS ./path NO_CACHE)
message("find result: ${find_result2}")
find_file(find_result3 NAMES myfile1 myfile2 PATHS . ./path NO_CACHE)
message("find result: ${find_result3}")
執(zhí)行
cmake .運行結(jié)果為:
find result: find_result1-NOTFOUND
find result: /XXX/YYY/ZZZ/path/myfile2
find result: /XXX/YYY/ZZZ/myfile1
三、更多命令參數(shù)詳解
-
<vAR>:存儲命令運行的結(jié)果,默認是緩存條目,當指定NO_CACHE選項時為普通變量。 -
NAMES:指定一個或多個待查找的文件。 -
<HINTS>、<PATHS>:添加搜索路徑,ENV var子選項將會從系統(tǒng)環(huán)境變量var獲取搜索路徑。
# CMakeLists.txt
find_file(find_from_env NAMES myfile2 PATHS ENV MY_TEST_PATH)
message("find file from $ENV{MY_TEST_PATH}: ${find_from_env}")
在運行
cmake .命令之前,我們先使用export MY_TEST_PATH=/XXX/YYY/ZZZ/path來添加一個臨時的環(huán)境變量,注意/XXX/YYY/ZZZ是我本地運行的路徑,需要根據(jù)實際情況指定。
export MY_TEST_PATH=/XXX/YYY/ZZZ/path
cmake .運行結(jié)果:
find file from /XXX/YYY/ZZZ/path: /XXX/YYY/ZZZ/path/myfile2
-
PATH_SUFFIXES:為每一個搜索路徑添加一個后綴的子目錄,在新生成的路徑下也進行查找,注意原有的搜索路徑也會進行查找。假定我們的搜索路徑是/XXX/YYY/ZZZ和/XXX/YYY/WWW,當指定PATH_SUFFIXES path后,搜索路徑就變?yōu)椋?code>/XXX/YYY/ZZZ、/XXX/YYY/WWW、/XXX/YYY/ZZZ/path、/XXX/YYY/WWW/path。
# CMakeLists.txt
find_file(find_result_suffix NAMES myfile2 PATHS . PATH_SUFFIXES path) # 本例中,如果不指定PATH_SUFFIXES,myfile2無法搜索到
message("find result: ${find_result_suffix}")
執(zhí)行
cmake .運行結(jié)果:
find result: /XXX/YYY/ZZZ/path/myfile2
-
DOC:為<VAR>緩存條目指定文檔字符串描述。注意,當<VAR>是普通變量時(指定了NO_CACHE選項),DOC選項沒有意義。
# CMakeLists.txt
find_file(find_result_doc NAMES myfile2 PATHS ./path DOC "myfile2 is a test file for find_file command")
message("find result: ${find_result_doc}")
執(zhí)行
cmake .后輸出結(jié)果為:
find result: /XXX/YYY/ZZZ/path/myfile2那么指定的文檔字符串描述在哪兒呢?結(jié)合
<VAR>必須是緩存條目才有效的信息,那么可以在執(zhí)行cmake .后,在CMakeCache.txt文件中找到它,我本地執(zhí)行cat CMakeCache.txt | grep "myfile2”的結(jié)果為:
//myfile2 is a test file for find_file command
find_result_doc:FILEPATH=/Users/shengyi/mycode/leetcode/mytest/find_file/path/myfile2
-
NO_CACHE:該選項在3.21版本引入。如果指定了NO_CACHE選項,那么<VAR>是普通變量,否則是緩存條目。
??1. 默認情況下(未指定NO_CACHE選項),命令執(zhí)行結(jié)果會緩存到CMakeCache.txt文件中,因此只要find_file找到了指定的文件,后續(xù)再次調(diào)用find_file不會再執(zhí)行查找過程,即使重新執(zhí)行cmake .,find_file也不會再執(zhí)行查找過程,而是從CMakeCache.txt文件中加載查找結(jié)果。
??2. 當指定了NO_CACHE選項,在本次構(gòu)建過程中,只要find_file找到了指定文件,后續(xù)的find_file的調(diào)用不會再執(zhí)行查找過程,但是重新執(zhí)行一次構(gòu)建,又會再次查找。
??需要注意的一點是,NO_CACHE會導致每次構(gòu)建都會重新查找,增加構(gòu)建時間消耗。
# CMakeLists.txt
# NO_CACHE的使用
find_file(result_no_cache NAMES myfile1 PATHS ./ NO_CACHE) # 首次查找myfile1
message("first find result: ${result_no_cache}")
find_file(result_no_cache NAMES myfile2 PATHS ./path NO_CACHE) # 在前面已經(jīng)查找到myfile1的情況下,再次調(diào)用,實際上不會執(zhí)行查找過程了
message("second find result: ${result_no_cache}")
執(zhí)行
cmake .的結(jié)果:
first find result: /XXX/YYY/ZZZ/myfile1
second find result: /XXX/YYY/ZZZ/myfile1
說明:只要找到了指定文件,后續(xù)調(diào)用find_file不會再執(zhí)行。
此時我們刪除myfile1文件,再次執(zhí)行cmake .:
rm myfile1
cmake .
運行結(jié)果為:
first find result: result_no_cache-NOTFOUND
second find result: /XXX/YYY/ZZZ/myfile2
說明:重新運行cmake .進行構(gòu)建,普通變量不會保存在CMakeCache.txt中,因此會重新執(zhí)行查找過程
# CMakeLists.txt
# 未使用NO_CACHE
find_file(result_cache NAMES myfile1 PATHS ./) # 首次查找myfile1
message("first find result: ${result_cache}")
find_file(result_cache NAMES myfile2 PATHS ./path) # 在前面已經(jīng)查找到myfile1的情況下,再次調(diào)用,實際上不會執(zhí)行查找過程了
message("second find result: ${result_cache}")
執(zhí)行
cmake .的結(jié)果:
first find result: /XXX/YYY/ZZZ/myfile1
second find result: /XXX/YYY/ZZZ/myfile1
說明:只要找到了指定文件,后續(xù)調(diào)用find_file不會再執(zhí)行。
此時我們刪除myfile1文件,再次執(zhí)行cmake .:
rm myfile1
cmake .
運行結(jié)果為:
****first find result: /XXX/YYY/ZZZ/myfile1
second find result: /XXX/YYY/ZZZ/myfile1***
說明:與第一次執(zhí)行結(jié)果一致,說明緩存條目會存儲在CMakeCache.txt中,即使重復執(zhí)行構(gòu)建過程,也不會再次執(zhí)行查找,除非刪除CMakeCache.txt文件,我們可以通過查看CMakeCache.txt文件,看到result_cache變量:
cat CMakeCache.txt | grep "result_cache"
result_cache:FILEPATH=/XXX/YYY/ZZZ/myfile1
-
REQUIRED:在3.18版本引入。當指定了該選項,如果未找到執(zhí)行的文件,那么構(gòu)建過程會終止,并輸出錯誤信息,否則會在再次調(diào)用find_file的時候重新查找指定文件。
# CMakeLists.txt
find_file(result NAMES noexistfile PATHS ./ REQUIRED)
message("result: ${result}")
執(zhí)行
cmake .運行結(jié)果:
CMake Error at CMakeLists.txt:6 (find_file):
Could not find result using the following files: noexistfile
四、查找過程
當沒有指定NO_DEFAULT選項時,搜索過程會按照如下順序進行:
如果是從
find模塊或者通過find_package<PackageName>命令調(diào)用進來,那么首先會在CMake變量<PackageName>_ROOT和環(huán)境變量<PackageName>_ROOT進行查找。如果find模塊的調(diào)用是嵌套的,那么會先在當前的模塊中的<PackageName>_ROOT和ENV{<PackageName>_ROOT}進行查找,然后在父模塊的<PackageName>_ROOT和ENV{<PackageName>_ROOT}進行查找。這個是隨著3.12版本中引入??梢酝ㄟ^NO_PACKAGE_ROOT_PATH選項或者將CMAKE_FIND_USE_PACKAGE_ROOT_PATH變量設(shè)置為FALSE來跳過這以查找過程。
對于每一個查找路徑<prefix>,還會添加include子目錄進行查找(也就是查找<prefix>/include)。此外如果設(shè)置了CMAKE_LIBRARY_ARCHITECTURE變量值為<arch>,也會將include/<arch>子目錄添加到查找路徑,也就是對<prefix>/include/<arch>進行查找。通過命令行傳入
CMake變量指定的路徑,一般是cmake . -DVAR=value這種形式傳入,如果有多個路徑,使用分號進行分隔??梢酝ㄟ^設(shè)置NO_CMAKE_PATH選項,或者將CMAKE_FIND_USE_CMAKE_PATH變量設(shè)置為FALSE來跳過這一查找過程。
VAR有如下幾個取值:
1)CMAKE_PREFIX_PATH:以CMAKE_PREFIX_PATH指定的路徑作為前綴<prefix>,include子目錄也會被添加到查找路徑中,也就是<prefix>/include;特別的,如果設(shè)置了CMAKE_LIBRARY_ARCHITECTURE變量<arch>,那么<prefix>/include/<arch>也會被添加到查找路徑中;
2)CMAKE_INCLUDE_PATH
3)CMAKE_FRAMEWORK_PATH
我們以CMAKE_PREFIX_PATH舉例說明,在CMakeLists.txt所在的目錄,新建文件myfile1,新建目錄include和目錄include/x64,并在這兩個目錄下分別建立文件include/myfile3和include/x64/myfile4,目錄結(jié)構(gòu)如下:
├── CMakeLists.txt
├── Makefile
├── include
│ ├── myfile3
│ └── x64
│ └── myfile4
├── myfile1
# CMakeLists.txt
find_file(result NAMES myfile1)
message("result: ${result}")
find_file(result2 NAMES myfile3)
message("result2: ${result2}")
find_file(result3 NAMES myfile4)
message("result3: ${result3}")
執(zhí)行
cmake . -DCMAKE_PREFIX_PATH=./結(jié)果如下,可以看到include子目錄也會被添加到查找路徑中:
result: /XXX/YYY/ZZZ/myfile1
result2: /XXX/YYY/ZZZ/include/myfile3
result3: result3-NOTFOUND
執(zhí)行
cmake . -DCMAKE_PREFIX_PATH=./ -DCMAKE_LIBRARY_ARCHITECTURE=x64,本次同時也傳遞了CMAKE_LIBRARY_ARCHITECTURE變量,結(jié)果如下,可以看到include子目錄和include/x64子目錄都被添加到了查找路徑:
result: /XXX/YYY/ZZZ/myfile1
result2: /XXX/YYY/ZZZ/include/myfile3
result3: /XXX/YYY/ZZZ/include/x64/myfile4
3. 查找CMake環(huán)境變量指定的路徑,如果要指定多個路徑,可以通過分號分隔。具體的環(huán)境變量取值和搜索方式與步驟2中一致,此處不在贅述,以CMAKE_INCLUDE_PATH包含當前目錄作為搜索目錄進行說明。
# CMakeLists.txt
find_file(result NAMES myfile1)
message("result: ${result}")
執(zhí)行如下命令:
export CMAKE_INCLUDE_PATH=./# 設(shè)置環(huán)境變量
cmake .執(zhí)行結(jié)果如下:
result: /XXX/YYY/ZZZ/myfile1
4. 搜索HINTS選項指定的路徑。
5. 搜索系統(tǒng)的標準環(huán)境變量??梢酝ㄟ^設(shè)置NO_SYSTEM_ENVIRONMENT_PATH選項或者將CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH變量設(shè)置為FALSE來跳過該搜索步驟。例如PATH環(huán)境變量,在我的macOS系統(tǒng)中,echo ${PATH}可以得到如下輸出:
/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
6. 搜索當前系統(tǒng)的平臺文件定義的CMake變量。包含CMAKE_SYSTEM_PREFIX_PATH、CMAKE_SYSTEM_INCLUDE_PATH、CMAKE_SYSTEM_FRAMEWORK_PATH三個。可以通過設(shè)置NO_CMAKE_SYSTEM_PATH選項或者將CMAKE_FIND_USE_CMAKE_SYSTEM_PATH變量設(shè)置為FALSE來跳過這一查找過程。在我的macOS系統(tǒng)中,CMake中打印出CMAKE_SYSTEM_FRAMEWORK_PATH的輸出如下:
# CMakeLists.txt
message("system: ${CMAKE_SYSTEM_FRAMEWORK_PATH}")
輸出:
system: ~/Library/Frameworks;/Applications/Xcode.app/Contents/Developer/Library/Frameworks;/Library/Frameworks;/Network/Library/Frameworks;/System/Library/Frameworks
7. 搜索PATHS選項指定的路徑。
最后對CMAKE_FIND_ROOT_PATH和CMAKE_SYSROOT兩個CMake變量做一個簡短的說明。這兩個變量都可以將指定的變量作為待搜索路徑的根目錄前綴,默認情況下CMAKE_FIND_ROOT_PATH為空。此外使用的默認順序為:優(yōu)先使用CMAKE_FIND_ROOT_PATH,然后使用CMAKE_SYSROOT??梢酝ㄟ^CMAKE_FIND_ROOT_PATH_MODE_INCLUDE變量進行調(diào)整:值為ONLY表明只使用CMAKE_FIND_ROOT_PATH;值為NEVER表明只使用CMAKE_SYSROOT;值為BOTH則會使用兩個變量。也可以通過find_file的三個選項進行調(diào)整:
-
CMAKE_FIND_ROOT_PATH_BOTH:按照上述的默認順序搜索。 -
NO_CMAKE_FIND_ROOT_PATH:不使用CMAKE_FIND_ROOT_PATH。 -
ONLY_CMAKE_FIND_ROOT_PATH:使用ONLY_CMAKE_FIND_ROOT_PATH(該變量指定的目錄及后綴目錄不會添加CMAKE_FIND_ROOT_PATH為根)下的目錄,以及以CMAKE_FIND_ROOT_PATH為根的目錄。