Spec-Zone.ru › CMake 3.24

cmake_path

Новое в версии 3.20.

Эта команда предназначена для манипулирования путями. Обрабатываются только синтаксические аспекты путей, никакого взаимодействия с файловой системой нет. Путь может представлять несуществующий путь или путь, который не может существовать в текущей файловой системе или платформе. Для операций, взаимодействующих с файловой системой, см. команду file().

Примечание

Команда cmake_path обрабатывает пути в формате системы сборки (т.е. хостовой платформы), а не целевой системы. При кросс-компиляции, если путь содержит элементы, которые не могут быть представлены на хостовой платформе (например, букву диска, если хост не Windows), результаты будут непредсказуемыми.

Синтаксис

Conventions

Path Structure And Terminology

Normalization

Decomposition
  cmake_path(GET <path-var> ROOT_NAME <out-var>)
  cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
  cmake_path(GET <path-var> ROOT_PATH <out-var>)
  cmake_path(GET <path-var> FILENAME <out-var>)
  cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
  cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
  cmake_path(GET <path-var> RELATIVE_PART <out-var>)
  cmake_path(GET <path-var> PARENT_PATH <out-var>)

Query
  cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
  cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
  cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
  cmake_path(HAS_FILENAME <path-var> <out-var>)
  cmake_path(HAS_EXTENSION <path-var> <out-var>)
  cmake_path(HAS_STEM <path-var> <out-var>)
  cmake_path(HAS_RELATIVE_PART <path-var> <out-var>)
  cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
  cmake_path(IS_ABSOLUTE <path-var> <out-var>)
  cmake_path(IS_RELATIVE <path-var> <out-var>)
  cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
  cmake_path(COMPARE <input1> <OP> <input2> <out-var>)

Modification
  cmake_path(SET <path-var> [NORMALIZE] <input>)
  cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
  cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
  cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
  cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
  cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>])
  cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>])

Generation
  cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
  cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>])
  cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>])

Native Conversion
  cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
  cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
  cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])

Hashing
  cmake_path(HASH <path-var> <out-var>)

Условности

В документации по этой команде используются следующие условности:

<path-var>

Всегда имя переменной. Для команд, которые ожидают <path-var> в качестве входных данных, переменная должна существовать и содержать единственный путь.

<input>

Строковый литерал, который может содержать путь, фрагмент пути или несколько путей со специальным разделителем, зависящим от команды. См. описание каждой команды, чтобы понять, как это интерпретируется.

<input>...

Ноль или более строковых литералов-аргументов.

<out-var>

Имя переменной, в которую будет записан результат команды.

Структура и терминология путей

Путь имеет следующую структуру (все компоненты необязательны, с некоторыми ограничениями):

root-name root-directory-separator (item-name directory-separator)* filename
root-name

Идентифицирует корень в файловой системе с несколькими корнями (например, "C:" или "//myserver"). Необязательно.

root-directory-separator

Разделитель каталогов, который, если присутствует, указывает, что этот путь является абсолютным. Если его нет, и первый элемент, отличный от root-name, является item-name, то путь является относительным.

item-name

Последовательность символов, которые не являются разделителями каталогов. Это имя может идентифицировать файл, жёсткую ссылку, символическую ссылку или каталог. Распознаются два специальных случая:

  • Имя элемента, состоящее из одного символа точки ., — это имя каталога, которое ссылается на текущий каталог.
  • Имя элемента, состоящее из двух символов точки .., — это имя каталога, которое ссылается на родительский каталог.

Вышеприведённая схема (...)* указывает, что может быть ноль или более имён элементов, причём несколько элементов разделены символом directory-separator. Символы ()* не являются частью пути.

directory-separator

Единственным распознаваемым разделителем каталогов является символ слэша /. Если этот символ повторяется, он обрабатывается как один разделитель каталогов. Иными словами, /usr///////lib равно /usr/lib.

filename

Путь имеет filename если он не заканчивается на directory-separator. filename фактически является последним item-name пути, поэтому он также может быть жёсткой ссылкой, символической ссылкой или каталогом.

filename может иметь расширение. По умолчанию расширение определяется как подстрока, начинающаяся с левой точки (включая точку) и продолжающаяся до конца filename. В командах, принимающих ключевое слово LAST_ONLY, LAST_ONLY изменяет интерпретацию на подстроку, начинающуюся с правой точки.

К вышеупомянутой интерпретации применяются следующие исключения:

  • Если первый символ в filename — точка, эта точка игнорируется (т.е. filename подобный ".profile" обрабатывается как не имеющий расширения).
  • Если filename — это . или .., у него нет расширения.

Основа — это часть filename перед расширением.

Некоторые команды ссылаются на root-path. Это конкатенация root-name и root-directory-separator, причём одна или обе могут быть пустыми. relative-part ссылается на полный путь с удалёнными root-path.

Создание переменной пути

Хотя путь можно создать с помощью обычной команды set(), рекомендуется использовать cmake_path(SET), так как он автоматически преобразует путь в требуемый формат, где это необходимо. Команда cmake_path(APPEND) может быть ещё одним подходящим вариантом, когда путь нужно построить, соединив фрагменты. Следующий пример сравнивает три метода построения одного и того же пути:

set(path1 "${CMAKE_CURRENT_SOURCE_DIR}/data")

cmake_path(SET path2 "${CMAKE_CURRENT_SOURCE_DIR}/data")

cmake_path(APPEND path3 "${CMAKE_CURRENT_SOURCE_DIR}" "data")

Подкоманды Modification и Generation могут сохранять результат на месте или в отдельной переменной, названной по ключевому слову OUTPUT_VARIABLE. Все остальные подкоманды сохраняют результат в обязательной переменной <out-var>.

Нормализация

Некоторые подкоманды поддерживают нормализацию пути. Алгоритм нормализации пути следующий:

  1. Если путь пустой, остановиться (нормализованная форма пустого пути также является пустым путём).
  2. Заменить каждый directory-separator, который может состоять из нескольких разделителей, на один / (/a///b  --> /a/b).
  3. Удалить каждую одиночную точку (.) и любой directory-separator сразу после неё (/a/./b/. --> /a/b).
  4. Удалить каждый item-name (кроме .. ), который сразу следует за directory-separator и .., вместе с любыми directory-separator , которые сразу следуют за ними (/a/b/../c --> a/c).
  5. Если есть root-directory, удалить любые .. и любые directory-separators , которые сразу следуют за ними. Родитель корневого каталога обрабатывается как все ещё корневой каталог (/../a --> /a).
  6. Если последний item-name — .., удалить все trailing directory-separator (../ --> ..).
  7. Если путь пустой на этом этапе, добавить dot (нормальная форма ./ — .).

Разложение

Следующие формы подкоманды GET каждый извлекает различный компонент или группу компонентов из пути. Смотрите Структуру и терминологию путей для значения каждого компонента пути.

cmake_path(GET <path-var> ROOT_NAME <out-var>)
cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
cmake_path(GET <path-var> ROOT_PATH <out-var>)
cmake_path(GET <path-var> FILENAME <out-var>)
cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> RELATIVE_PART <out-var>)
cmake_path(GET <path-var> PARENT_PATH <out-var>)

Если запрашиваемый компонент отсутствует в пути, в <out-var> будет храниться пустая строка. Например, только системы Windows имеют понятие root-name, поэтому, когда хост-машина не Windows, подкоманда ROOT_NAME всегда возвращает пустую строку.

Для PARENT_PATH, если подкоманда HAS_RELATIVE_PART возвращает false, результат — копия <path-var>. Обратите внимание, что это означает, что корневой каталог считается имеющим родителя, который является самим собой. Когда HAS_RELATIVE_PART возвращает true, результат фактически будет <path-var> с одним элементом меньше.

Примеры корней

set(path "c:/a")

cmake_path(GET path ROOT_NAME rootName)
cmake_path(GET path ROOT_DIRECTORY rootDir)
cmake_path(GET path ROOT_PATH rootPath)

message("Root name is \"${rootName}\"")
message("Root directory is \"${rootDir}\"")
message("Root path is \"${rootPath}\"")
Root name is "c:"
Root directory is "/"
Root path is "c:/"

Примеры имён файлов

set(path "/a/b")
cmake_path(GET path FILENAME filename)
message("First filename is \"${filename}\"")

# Trailing slash means filename is empty
set(path "/a/b/")
cmake_path(GET path FILENAME filename)
message("Second filename is \"${filename}\"")
First filename is "b"
Second filename is ""

Примеры расширений и основы

set(path "name.ext1.ext2")

cmake_path(GET path EXTENSION fullExt)
cmake_path(GET path STEM fullStem)
message("Full extension is \"${fullExt}\"")
message("Full stem is \"${fullStem}\"")

# Effect of LAST_ONLY
cmake_path(GET path EXTENSION LAST_ONLY lastExt)
cmake_path(GET path STEM LAST_ONLY lastStem)
message("Last extension is \"${lastExt}\"")
message("Last stem is \"${lastStem}\"")

# Special cases
set(dotPath "/a/.")
set(dotDotPath "/a/..")
set(someMorePath "/a/.some.more")
cmake_path(GET dotPath EXTENSION dotExt)
cmake_path(GET dotPath STEM dotStem)
cmake_path(GET dotDotPath EXTENSION dotDotExt)
cmake_path(GET dotDotPath STEM dotDotStem)
cmake_path(GET dotMorePath EXTENSION someMoreExt)
cmake_path(GET dotMorePath STEM someMoreStem)
message("Dot extension is \"${dotExt}\"")
message("Dot stem is \"${dotStem}\"")
message("Dot-dot extension is \"${dotDotExt}\"")
message("Dot-dot stem is \"${dotDotStem}\"")
message(".some.more extension is \"${someMoreExt}\"")
message(".some.more stem is \"${someMoreStem}\"")
Full extension is ".ext1.ext2"
Full stem is "name"
Last extension is ".ext2"
Last stem is "name.ext1"
Dot extension is ""
Dot stem is "."
Dot-dot extension is ""
Dot-dot stem is ".."
.some.more extension is ".more"
.some.more stem is ".some"

Примеры относительной части

set(path "c:/a/b")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")

set(path "c/d")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")

set(path "/")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")
Relative part is "a/b"
Relative part is "c/d"
Relative part is ""

Примеры обхода каталогов

set(path "c:/a/b")
cmake_path(GET path PARENT_PATH result)
message("Parent path is \"${result}\"")

set(path "c:/")
cmake_path(GET path PARENT_PATH result)
message("Parent path is \"${result}\"")
Parent path is "c:/a"
Parent path is "c:/"

Запрос

Каждая из подкоманд GET имеет соответствующую подкоманду HAS_..., которая может использоваться для определения наличия конкретного компонента пути. Смотрите Структуру и терминологию путей для значения каждого компонента пути.

cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
cmake_path(HAS_FILENAME <path-var> <out-var>)
cmake_path(HAS_EXTENSION <path-var> <out-var>)
cmake_path(HAS_STEM <path-var> <out-var>)
cmake_path(HAS_RELATIVE_PART <path-var> <out-var>)
cmake_path(HAS_PARENT_PATH <path-var> <out-var>)

Каждая из вышеперечисленных подкоманд следует предсказуемой схеме, устанавливая <out-var> в true, если путь имеет соответствующий компонент, или в false в противном случае. Обратите внимание на следующие специальные случаи:

  • Для HAS_ROOT_PATH, истинное значение будет возвращено только в том случае, если хотя бы один из root-name или root-directory не пуст.
  • Для HAS_PARENT_PATH, корневой каталог также считается имеющим родительский каталог, который будет самим собой. Результат — истина, за исключением случая, когда путь состоит только из имени файла.
cmake_path(IS_ABSOLUTE <path-var> <out-var>)

Устанавливает <out-var> в true, если <path-var> является абсолютным. Абсолютный путь — это путь, однозначно определяющий местоположение файла без ссылки на дополнительное начальное расположение. В Windows это означает, что путь должен иметь как root-name, так и root-directory-separator, чтобы считаться абсолютным. На других платформах достаточно только root-directory-separator. Обратите внимание, что это означает, что в Windows IS_ABSOLUTE может быть false, в то время как HAS_ROOT_DIRECTORY может быть true.

cmake_path(IS_RELATIVE <path-var> <out-var>)

Это сохранит обратное значение IS_ABSOLUTE в <out-var>.

cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)

Проверяет, является ли <path-var> префиксом <input>.

При указании опции NORMALIZE <path-var> и <input> нормализуются перед проверкой.

set(path "/a/b/c")
cmake_path(IS_PREFIX path "/a/b/c/d" result) # result = true
cmake_path(IS_PREFIX path "/a/b" result)     # result = false
cmake_path(IS_PREFIX path "/x/y/z" result)   # result = false

set(path "/a/b")
cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE result)   # result = true
cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)

Сравнивает лексические представления двух путей, предоставленных в виде строковых литералов. Никакая нормализация не выполняется для ни одного пути, за исключением того, что несколько последовательных разделителей каталогов эффективно сводятся к одному разделителю. Равенство определяется согласно следующей логике псевдокода:

if(NOT <input1>.root_name() STREQUAL <input2>.root_name())
  return FALSE

if(<input1>.has_root_directory() XOR <input2>.has_root_directory())
  return FALSE

Return FALSE if a relative portion of <input1> is not lexicographically
equal to the relative portion of <input2>. This comparison is performed path
component-wise. If all of the components compare equal, then return TRUE.

Примечание

В отличие от большинства других cmake_path() подкоманд, подкоманда COMPARE принимает на вход строковые литералы, а не имена переменных.

Модификация

cmake_path(SET <path-var> [NORMALIZE] <input>)

Присвойте <input> путь <path-var>. Если <input> является собственным путём, он преобразуется в путь в стиле CMake с прямыми слешами (/). В Windows учитывается маркер длинного имени файла.

Если указан параметр NORMALIZE, путь нормализуется после преобразования.

Например:

set(native_path "c:\\a\\b/..\\c")
cmake_path(SET path "${native_path}")
message("CMake path is \"${path}\"")

cmake_path(SET path NORMALIZE "${native_path}")
message("Normalized CMake path is \"${path}\"")

Вывод:

CMake path is "c:/a/b/../c"
Normalized CMake path is "c:/a/c"
cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])

Добавьте все <input> аргументы к <path-var> используя / в качестве directory-separator. В зависимости от <input>, предыдущее содержимое <path-var> может быть удалено. Для каждого <input> аргумента применяется следующий алгоритм (псевдокод):

# <path> is the contents of <path-var>

if(<input>.is_absolute() OR
   (<input>.has_root_name() AND
    NOT <input>.root_name() STREQUAL <path>.root_name()))
  replace <path> with <input>
  return()
endif()

if(<input>.has_root_directory())
  remove any root-directory and the entire relative path from <path>
elseif(<path>.has_filename() OR
       (NOT <path-var>.has_root_directory() OR <path>.is_absolute()))
  append directory-separator to <path>
endif()

append <input> omitting any root-name to <path>
cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])

Добавьте все <input> аргументы к <path-var> без добавления directory-separator.

cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])

Удаляет компонент имя файла (как возвращается GET ... FILENAME) из <path-var>. После удаления любые хвостовые directory-separator остаются на своих местах, если они есть.

Если OUTPUT_VARIABLE не указан, то после возврата этой функции HAS_FILENAME возвращает false для <path-var>.

Например:

set(path "/a/b")
cmake_path(REMOVE_FILENAME path)
message("First path is \"${path}\"")

# filename is now already empty, the following removes nothing
cmake_path(REMOVE_FILENAME path)
message("Second path is \"${result}\"")

Вывод:

First path is "/a/"
Second path is "/a/"
cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])

Заменяет компонент имя файла в <path-var> на <input>. Если <path-var> не имеет компонента имени файла (т.е. HAS_FILENAME возвращает false), путь не изменяется. Операция эквивалентна следующему:

cmake_path(HAS_FILENAME path has_filename)
if(has_filename)
  cmake_path(REMOVE_FILENAME path)
  cmake_path(APPEND path input);
endif()
cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
                                       [OUTPUT_VARIABLE <out-var>])

Удаляет расширение, если оно есть, из <path-var>.

cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
                             [OUTPUT_VARIABLE <out-var>])

Заменяет расширение на <input>. Его действие эквивалентно следующему:

cmake_path(REMOVE_EXTENSION path)
if(NOT "input" MATCHES "^\\.")
  cmake_path(APPEND_STRING path ".")
endif()
cmake_path(APPEND_STRING path "input")

Генерация

cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])

Нормализуйте <path-var> в соответствии с шагами, описанными в Нормализации.

cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
                                    [OUTPUT_VARIABLE <out-var>])

Изменяет <path-var> так, чтобы он был относительным к аргументу BASE_DIRECTORY. Если BASE_DIRECTORY не указан, то базовым каталогом по умолчанию будет CMAKE_CURRENT_SOURCE_DIR.

Для справки, алгоритм вычисления относительного пути такой же, как у C++ std::filesystem::path::lexically_relative.

cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
                                    [OUTPUT_VARIABLE <out-var>])

Если <path-var> является относительным путём (IS_RELATIVE истинно), он оценивается относительно заданного базового каталога, указанного параметром BASE_DIRECTORY . Если BASE_DIRECTORY не указан, то базовым каталогом по умолчанию будет CMAKE_CURRENT_SOURCE_DIR.

Если указан параметр NORMALIZE, путь нормализуется после вычисления пути.

Поскольку cmake_path() не обращается к файловой системе, символьные ссылки не разрешаются, а любые ведущие тильды не расширяются. Чтобы вычислить реальный путь с разрешёнными символьными ссылками и расширенными ведущими тильдами, используйте команду file(REAL_PATH) вместо этого.

Преобразование в собственный формат

Для команд в этом разделе собственный относится к платформе хоста, а не к целевой платформе при кросс-компиляции.

cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)

Преобразует путь в стиле CMake <path-var> в собственный путь с платформенно-специфическими слешами (\ на Windows-хостах и / в других случаях).

Если указан параметр NORMALIZE, путь нормализуется перед преобразованием.

cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])

Преобразует собственный <input> путь в путь в стиле CMake с прямыми слешами (/). На Windows-хостах учитывается маркер длинного имени файла. Вход может быть единственным путём или системным путём поиска, как $ENV{PATH}. Путь поиска преобразуется в список в стиле CMake, разделённый символами ; (на платформах, не являющихся Windows, это означает, что разделители : заменяются на разделители ;). Результат преобразования хранится в переменной <out-var>.

Если указан параметр NORMALIZE, путь нормализуется перед преобразованием.

Примечание

В отличие от большинства других cmake_path() подкоманд, подкоманда CONVERT принимает на вход строковый литерал, а не имя переменной.

cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])

Преобразует путь в стиле CMake <input> в собственный путь с платформенно-специфическими слешами (\ на Windows-хостах и / в других случаях). Вход может быть единственным путём или списком в стиле CMake. Список будет преобразован в собственный путь поиска (;-разделённый на Windows, :-разделённый на других платформах). Результат преобразования сохраняется в переменной <out-var>.

Если указан параметр NORMALIZE, путь нормализуется перед преобразованием.

Примечание

В отличие от большинства других cmake_path() подкоманд, подкоманда CONVERT принимает на вход строковый литерал, а не имя переменной.

Например:

set(paths "/a/b/c" "/x/y/z")
cmake_path(CONVERT "${paths}" TO_NATIVE_PATH_LIST native_paths)
message("Native path list is \"${native_paths}\"")

Вывод на Windows:

Native path list is "\a\b\c;\x\y\z"

Вывод на всех остальных платформах:

Native path list is "/a/b/c:/x/y/z"

Хэширование

cmake_path(HASH <path-var> <out-var>)

Вычислить хэш-значение <path-var> таким образом, чтобы для двух путей p1 и p2, которые сравниваются как равные (COMPARE ... EQUAL), хэш-значение p1 было равно хэш-значению p2. Путь всегда нормализуется перед вычислением хэша.

© 2000–2022 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.24/command/cmake_path.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API