Подтвердить что ты не робот

В CMake, как я могу найти каталог включенного файла?

Предположим, что в моем проекте CMakeLists.txt есть foo.cmake:

include(foo)

В foo.cmake, я хочу знать путь foo.cmake.
Как я могу это сделать?

Обратите внимание, что CMAKE_CURRENT_LIST_DIR предоставляет каталог включения CMakeLists.txt, а не входящего в него foo.cmake, и, следовательно, это не то, что я хочу.

Конечно, foo.cmake может быть включен несколькими проектами (т.е. несколькими CMakeLists.txt файлами).

4b9b3361

Ответ 1

Люди сообщали, казалось бы, противоречивые факты о том, как ведет себя CMAKE_CURRENT_LIST_DIR. Теперь я знаю причину путаницы:

Во-первых, в моей Linux-среде:

$ cd /path/to/home  
$ mkdir cmake-test  
$ cd cmake-test  
$ mkdir source  
$ mkdir source/subdirectory  
$ mkdir build  

Я создаю эти два файла:

$ cat source/CMakeLists.txt  
include(subdirectory/foo.cmake)  

$ cat source/subdirectory/foo.cmake  
message("CMAKE_CURRENT_LIST_DIR is ${CMAKE_CURRENT_LIST_DIR}")  

CMake работает, как сообщает Фрейзер и Роберт Дайли:

$ cd build  
$ cmake ../source  
CMAKE_CURRENT_LIST_DIR is /path/to/home/cmake-test/source/subdirectory  
[...]  

Однако я добавляю функцию к foo.cmake, которую я вызываю из CMakeLists.txt:

$ cat ../source/subdirectory/foo.cmake  
message("CMAKE_CURRENT_LIST_DIR is ${CMAKE_CURRENT_LIST_DIR}")  
function(bar)  
    message("CMAKE_CURRENT_LIST_DIR in bar() is ${CMAKE_CURRENT_LIST_DIR}")  
endfunction()  

$ cat ../source/CMakeLists.txt  
include(subdirectory/foo.cmake)  
bar()  

Тогда:

$ cmake ../source  
CMAKE_CURRENT_LIST_DIR is /path/to/home/cmake-test/source/subdirectory  
CMAKE_CURRENT_LIST_DIR in bar() is /path/to/home/cmake-test/source  
[...]  

Итак, значение CMAKE_CURRENT_LIST_DIR в foo.cmake не совпадает с моментом foo.cmake включен и когда вызывается bar(). Это соответствует спецификации CMAKE_CURRENT_LIST_DIR.

Вот одно из возможных решений для доступа к каталогу foo.cmake изнутри bar():

$ cat ../source/subdirectory/foo.cmake  
set(DIR_OF_FOO_CMAKE ${CMAKE_CURRENT_LIST_DIR})  
function(bar)  
    message("DIR_OF_FOO_CMAKE in bar() is ${DIR_OF_FOO_CMAKE}")  
endfunction()  

после чего я получаю поведение, которое я искал:

$ cmake ../source  
DIR_OF_FOO_CMAKE in bar() is /path/to/home/cmake-test/source/subdirectory  
[...]  

Ответ 2

См. CMAKE_CURRENT_LIST_DIR:

Полный каталог обрабатываемого списка.

Поскольку CMake обрабатывает список файлов в вашем проекте, эта переменная будет всегда устанавливается в каталог, в котором находится текущий список обрабатывается (CMAKE_CURRENT_LIST_FILE). Значение имеет динамический охват. Когда CMake начинает обработку команд в исходном файле он устанавливает эту переменную в каталог, в котором находится этот файл. Когда CMake завершает обработку команд из файла, он восстанавливает предыдущее значение. Поэтому значение переменной внутри макроса или function - это каталог файла, вызывающего самую нижнюю запись в стеке вызовов, а не в каталоге файла, содержащего макрос или определение функции.

Пример

У меня есть следующая структура:

C:\Work\cmake-test\CMakeLists.txt
C:\Work\cmake-test\subfolder\test.cmake

В моем CMakeLists.txt:

include( subfolder/test.cmake )

В моем test.cmake:

message( "Current dir: ${CMAKE_CURRENT_LIST_DIR}" )

Результат, который я получаю при запуске CMake из C:\Work\cmake-test:

Текущий каталог: C:/Work/cmake-test/подпапка

Ответ 3

Команда include() сначала ищет модули в ${CMAKE_MODULE_PATH}, а затем в CMake Modules dir.

Итак, вы можете просто проверить наличие файла с помощью if(EXISTS ${CMAKE_MODULE_PATH}/foo.cmake) и if(EXISTS ${CMAKE_ROOT}/Modules/foo.cmake).