# cmake_path

New in version 3.19.

Filesystem path manipulation command.

This command is dedicated to the manipulation of objects of type path which represent paths on a filesystem. Only syntactic aspects of paths are handled: the pathname may represent a non-existing path or even one that is not allowed to exist on the current file system or OS.

For operations involving the filesystem, have a look at the `file()` command.

The path name has the following syntax:

1. `root-name` (optional): identifies the root on a filesystem with multiple roots (such as `"C:"` or `"//myserver"`).

2. `root-directory` (optional): a directory separator that, if present, marks this path as absolute. If it is missing (and the first element other than the `root-name` is a `item-name`), then the path is relative.

Zero or more of the following:

3. `item-name`: sequence of characters that aren’t directory separators. This name may identify a file, a hard link, a symbolic link, or a directory. Two special `item-names` are recognized:

   > - `dot`: the item name consisting of a single dot character `.` is a directory name that refers to the current directory.

   > - `dot-dot`: the item name consisting of two dot characters `..` is a directory name that refers to the parent directory.

4. `directory-separator`: the forward slash character `/`. If this character is repeated, it is treated as a single directory separator: `/usr///////lib` is the same as `/usr/lib`.

A path has a filename if it does not ends with a `directory-separator`. The filename is the last `item-name` of the path.

A filename can have an extension. By default, the extension is defined as the sub-string beginning at the leftmost period (including the period) and until the end of the pathname. When the option `LAST_ONLY` is specified, the extension is the sub-string beginning at the rightmost period.

The following exceptions apply:

> - If the first character in the filename is a period, that period is ignored (a filename like `".profile"` is not treated as an extension).

> - If the pathname is either `.` or `..`.

Note

`cmake_path` command handles paths in the format of the build system, not the target system. So this is not generally applicable to the target system in cross-compiling environment.

For all commands, `<path>` placeholder expect a variable name. An error will be raised if the variable does not exist, except for APPEND and CMAKE_PATH sub-commands. `<input>` placeholder expect a string literal. `[<input>...]` placeholder expect zero or more arguments. `<output>` placeholder expect a variable name.

Note

`cmake_path` command does not support list of paths. The `<path>` placeholder must store only one path name.

To initialize a path variable, three possibilities can be used:

1. `set()` command.

2. cmake_path(APPEND) command. Can be used to build a path from already available path fragments.

3. cmake_path(CMAKE_PATH) command. Mainly used to build a path variable from a native path.

>     # To build the path "${CMAKE_CURRENT_SOURCE_DIR}/data"

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

>     cmake_path(APPEND path2 "${CMAKE_CURRENT_SOURCE_DIR}" "data")

>     cmake_path(CMAKE_PATH path3 "${CMAKE_CURRENT_SOURCE_DIR}/data")

Modification and Generation sub-commands store the result in-place or in the variable specified by `OUTPUT_VARIABLE` option. All other sub-commands, except CMAKE_PATH, store the result in the required `<output>` variable.

Sub-commands supporting `NORMALIZE` option will normalize the path.

## Synopsis

    Decomposition
      cmake_path(GET <path> ROOT_NAME <output>)
      cmake_path(GET <path> ROOT_DIRECTORY <output>)
      cmake_path(GET <path> ROOT_PATH <output>)
      cmake_path(GET <path> FILENAME <output>)
      cmake_path(GET <path> EXTENSION [LAST_ONLY] <output>)
      cmake_path(GET <path> STEM [LAST_ONLY] <output>)
      cmake_path(GET <path> RELATIVE_PATH <output>)
      cmake_path(GET <path> PARENT_PATH <output>)

    Modification
      cmake_path(APPEND <path> [<input>...] [OUTPUT_VARIABLE <output>])
      cmake_path(CONCAT <path> [<input>...] [OUTPUT_VARIABLE <output>])
      cmake_path(REMOVE_FILENAME <path> [OUTPUT_VARIABLE <output>])
      cmake_path(REPLACE_FILENAME <path> <input> [OUTPUT_VARIABLE <output>])
      cmake_path(REMOVE_EXTENSION <path> [LAST_ONLY]
                                         [OUTPUT_VARIABLE <output>])
      cmake_path(REPLACE_EXTENSION <path> [LAST_ONLY] <input>
                                          [OUTPUT_VARIABLE <output>])

    Generation
      cmake_path(NORMAL_PATH <path> [OUTPUT_VARIABLE <output>])
      cmake_path(RELATIVE_PATH <path> [BASE_DIRECTORY <path>]
                                      [OUTPUT_VARIABLE <output>])
      cmake_path(PROXIMATE_PATH <path> [BASE_DIRECTORY <path>]
                                       [OUTPUT_VARIABLE <output>])
      cmake_path(ABSOLUTE_PATH <path> [BASE_DIRECTORY <path>] [NORMALIZE]
                                      [OUTPUT_VARIABLE <output>])

    Conversion
      cmake_path(CMAKE_PATH <path> [NORMALIZE] <input>)
      cmake_path(NATIVE_PATH <path> [NORMALIZE] <output>)
      cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <output>)
      cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <output>)

    Comparison
      cmake_path(COMPARE <path> <OP> <input> <output>)

    Query
      cmake_path(HAS_ROOT_NAME <path> <output>)
      cmake_path(HAS_ROOT_DIRECTORY <path> <output>)
      cmake_path(HAS_ROOT_PATH <path> <output>)
      cmake_path(HAS_FILENAME <path> <output>)
      cmake_path(HAS_EXTENSION <path> <output>)
      cmake_path(HAS_STEM <path> <output>)
      cmake_path(HAS_RELATIVE_PATH <path> <output>)
      cmake_path(HAS_PARENT_PATH <path> <output>)
      cmake_path(IS_ABSOLUTE <path> <output>)
      cmake_path(IS_RELATIVE <path> <output>)
      cmake_path(IS_PREFIX <path> <input> [NORMALIZE] <output>)

    Hashing
      cmake_path(HASH <path> [NORMALIZE] <output>)

## Decomposition

    cmake_path(GET <path> ROOT_NAME <output>)

Returns the root name of the path. If the path does not include a root name, returns an empty path.

Note

Only `Windows` system has the concept of `root-name`, so on all other systems, it is always an empty path.

For example:

>     set (path "c:/a")
>     cmake_path (GET path ROOT_NAME output)
>     message ("Root name is \"${output}\"")

> Will display:

>     Root name is "c:"

    cmake_path(GET <path> ROOT_DIRECTORY <output>)

Returns the root directory of the path. If the path does not include a root directory, returns an empty path.

For example:

>     set (path "c:/a")
>     cmake_path (GET path ROOT_DIRECTORY output)
>     message ("Root directory is \"${output}\"")

> Will display:

>     Root directory is "/"

    cmake_path(GET <path> ROOT_PATH <output>)

Returns the root path of the path. If the path does not include a root path, returns an empty path.

Effectively, returns the following: `root-name root-directory`.

For example:

>     set (path "c:/a")
>     cmake_path (GET path ROOT_PATH output)
>     message ("Root path is \"${output}\"")

> Will display:

>     Root path is "c:/"

    cmake_path(GET <path> FILENAME <output>)

Returns the filename component of the path. If the path ends with a `directory-separator`, there is no filename, so returns an empty path.

For example:

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

>     set (path "/a/")
>     cmake_path (GET path FILENAME output)
>     message ("Second filename is \"${output}\"")

> Will display:

>     First filename is "a"
>     Second filename is ""

    cmake_path(GET <path> EXTENSION [LAST_ONLY] <output>)

Returns the extension of the filename component.

If the filename component of the path contains a period (`.`), and is not one of the special filesystem elements `dot` or `dot-dot`, then the extension is returned.

For example:

>     set (path "name.ext1.ext2")
>     cmake_path (GET path EXTENSION result)
>     message ("Full extension is \"${result}\"")
>     cmake_path (GET path EXTENSION LAST_ONLY result)
>     message ("Last extension is \"${result}\"")

> Will display:

>     Full extension is ".ext1.ext2"
>     Last extension is ".ext2"

The following exceptions apply:

> - If the first character in the filename is a period, that period is ignored (a filename like `".profile"` is not treated as an extension).

> - If the pathname is either `.` or `..`, or if filename component does not contain the `.` character, then an empty path is returned.

    cmake_path(GET <path> STEM [LAST_ONLY] <output>)

Returns the filename component of the path stripped of its extension.

For Example:

>     set (path "name.ext1.ext2")
>     cmake_path (GET path STEM result)
>     message ("Filename without the extension is \"${result}\"")
>     cmake_path (GET path STEM LAST_ONLY result)
>     message ("Filename whiteout the last extension is \"${result}\"")

> Will display:

>     Filename without the extension is "name"
>     Filename without the last extension is "name.ext1"

The following exceptions apply:

> - If the first character in the filename is a period, that period is ignored (a filename like `".profile"` is not treated as an extension).

> - If the filename is one of the special filesystem components `dot` or `dot-dot`, or if it has no periods, the function returns the entire filename component.

    cmake_path(GET <path> RELATIVE_PATH <output>)

Returns path relative to `root-path`, that is, a pathname composed of every component of `<path>` after `root-path`. If `<path>` is an empty path, returns an empty path.

For Example:

>     set (path "/a/b")
>     cmake_path (GET path RELATIVE_PATH result)
>     message ("Relative path is \"${result}\"")

>     set (path "/")
>     cmake_path (GET path RELATIVE_PATH result)
>     message ("Relative path is \"${result}\"")

> Will display:

>     Relative path is "a/b"
>     Relative path is ""

    cmake_path(GET <path> PARENT_PATH <output>)

Returns the path to the parent directory.

If HAS_RELATIVE_PATH sub-command returns false, the result is a copy of `<path>`. Otherwise, the result is `<path>` with one fewer element.

For Example:

>     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}\"")

> Will display:

>     Parent path is "c:/a"
>     Relative path is "c:/"

## Modification

    cmake_path(APPEND <path> [<input>...] [OUTPUT_VARIABLE <output>])

Append all the `<input>` arguments to the `<path>` using `/` as `directory-separator`.

For each `<input>` argument, the following algorithm (pseudo-code) applies:

>     IF (<input>.is_absolute() OR
>          (<input>.has_root_name() AND
>           NOT <input>.root_name() STREQUAL <path>.root_name()))
>       replaces <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>.has_root_directory() OR <path>.is_absolute()))
>       appends directory-separator to <path>
>     ENDIF()

>     appends <input> omitting any root-name to <path>

    cmake_path(CONCAT <path> [<input>...] [OUTPUT_VARIABLE <output>])

Concatenates all the `<input>` arguments to the `<path>` without `directory-separator`.

    cmake_path(REMOVE_FILENAME <path> [OUTPUT_VARIABLE <output>])

Removes the filename component (as returned by GET … FILENAME) from `<path>`.

After this function returns, if change is done in-place, HAS_FILENAME returns false for `<path>`.

For Example:

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

>     cmake_path (REMOVE_FILENAME path)
>     message ("Second path is \"${result}\"")

> Will display:

>     First path is "/a/"
>     Second path is "/a/"

    cmake_path(REPLACE_FILENAME <path> <input> [OUTPUT_VARIABLE <output>])

Replaces the filename component from `<path>` with `<input>`.

If `<path>` has no filename component (HAS_FILENAME returns false), the path is unchanged.

Equivalent to the following:

>     cmake_path(HAS_FILENAME path has_filename)
>     if (has_filename)
>       cmake_path(REMOVE_FILENAME path)
>       cmake_path(APPEND path "replacement");
>     endif()

    cmake_path(REMOVE_EXTENSION <path> [LAST_ONLY] [OUTPUT_VARIABLE <output>])

Removes the extension, if any, from `<path>`.

    cmake_path(REPLACE_EXTENSION <path> [LAST_ONLY] <input>
                                 [OUTPUT_VARIABLE <output>])

Replaces the extension with `<input>`.

> 1. If `<path>` has an extension (HAS_EXTENSION is true), it is removed.

> 2. A `dot` character is appended to `<path>`, if `<input>` is not empty or does not begin with a `dot` character.

> 3. `<input>` is appended as if CONCAT was used.

Equivalent to the following:

>     cmake_path(REMOVE_EXTENSION path)
>     if (NOT "input" MATCHES "^\\.")
>       cmake_path(CONCAT path ".")
>     endif()
>     cmake_path(CONCAT path "input");

## Generation

    cmake_path(NORMAL_PATH <path> [OUTPUT_VARIABLE <output>])

Normalize `<path>`.

A path can be normalized by following this algorithm:

> 1. If the path is empty, stop (normal form of an empty path is an empty path).

> 2. Replace each `directory-separator` (which may consist of multiple separators) with a single `/`.

> 3. Replace each `directory-separator` character in the `root-name` with `/`.

> 4. Remove each `dot` and any immediately following `directory-separator`.

> 5. Remove each non-dot-dot filename immediately followed by a `directory-separator` and a `dot-dot`, along with any immediately following `directory-separator`.

> 6. If there is `root-directory`, remove all `dot-dots` and any `directory-separators` immediately following them.

> 7. If the last filename is `dot-dot`, remove any trailing `directory-separator`.

> 8. If the path is empty, add a `dot` (normal form of `./` is `.`).

    cmake_path(RELATIVE_PATH <path> [BASE_DIRECTORY <path>]
                             [OUTPUT_VARIABLE <output>])

Returns `<path>` made relative to `BASE_DIRECTORY` argument. If `BASE_DIRECTORY` is not specified, the default base directory will be `CMAKE_CURRENT_SOURCE_DIR`.

For reference, the algorithm used to compute the relative path is described here.

    cmake_path(PROXIMATE_PATH <path> [BASE_DIRECTORY <path>]
                              [OUTPUT_VARIABLE <output>])

If the value of RELATIVE_PATH is not an empty path, return it. Otherwise return `<path>`.

If `BASE_DIRECTORY` is not specified, the default base directory will be `CMAKE_CURRENT_SOURCE_DIR`.

    cmake_path(ABSOLUTE_PATH <path> [BASE_DIRECTORY <path>] [NORMALIZE]
                             [OUTPUT_VARIABLE <output>])

If `<path>` is a relative path (IS_RELATIVE is true), it is evaluated relative to the given base directory specified by `BASE_DIRECTORY` option.

If `BASE_DIRECTORY` is not specifired, the default base directory will be `CMAKE_CURRENT_SOURCE_DIR`.

When `NORMALIZE` option is specified, the path is normalized after the path computation.

Because `cmake_path` does not access to the filesystem, symbolic links are not resolved. To compute a real path, use `file(REAL_PATH)` command.

## Conversion

    cmake_path(CMAKE_PATH <path> [NORMALIZE] <input>)

Converts a native `<input>` path into cmake-style path with forward-slashes (`/`). On Windows, the long filename marker is taken into account.

When `NORMALIZE` option is specified, the path is normalized before the conversion.

For Example:

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

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

> Will display:

>     CMake path is "c:/a/b/../c"
>     Normalized CMake path is "c:/a/c"

    cmake_path(NATIVE_PATH <path> [NORMALIZE] <output>)

Converts a cmake-style `<path>` into a native path with platform-specific slashes (`\` on Windows and `/` elsewhere).

When `NORMALIZE` option is specified, the path is normalized before the conversion.

    cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <output> [NORMALIZE])

Converts a native `<input>` path into cmake-style path with forward-slashes (`/`). On Windows, the long filename marker is taken into account. The input can be a single path or a system search path like `$ENV{PATH}`. A search path will be converted to a cmake-style list separated by `;` characters. The result of the conversion is stored in the `<output>` variable.

When `NORMALIZE` option is specified, the path is normalized before the conversion.

    cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <output> [NORMALIZE])

Converts a cmake-style `<input>` path into a native path with platform-specific slashes (`\` on Windows and `/` elsewhere). The input can be a single path or a cmake-style list. A list will be converted into a native search path. The result of the conversion is stored in the `<output>` variable.

When `NORMALIZE` option is specified, the path is normalized before the conversion.

For Example:

>     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}\"")

> Will display, on Windows:

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

> And on the all other systems:

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

## Comparison

    cmake_path(COMPARE <path> EQUAL <input> <output>)
    cmake_path(COMPARE <path> NOT_EQUAL <input> <output>)

Compares the lexical representations of the path and another path.

For testing equality, the following algorithm (pseudo-code) apply:

>     IF (NOT <path>.root_name() STREQUAL <input>.root_name())
>       returns FALSE
>     ELSEIF (<path>.has_root_directory() XOR <input>.has_root_directory())
>       returns FALSE
>     ENDIF()

>     returns TRUE or FALSE if the relative portion of <path> is
>       lexicographically equal or not to the relative portion of <input>.
>       Comparison is performed path component-wise

## Query

    cmake_path(HAS_ROOT_NAME <path> <output>)

Checks if `<path>` has `root-name`.

    cmake_path(HAS_ROOT_DIRECTORY <path> <output>)

Checks if `<path>` has `root-directory`.

    cmake_path(HAS_ROOT_PATH <path> <output>)

Checks if `<path>` has root path.

Effectively, checks if `<path>` has `root-name` and `root-directory`.

    cmake_path(HAS_FILENAME <path> <output>)

Checks if `<path>` has a filename.

    cmake_path(HAS_EXTENSION <path> <output>)

Checks if `<path>` has an extension. If the first character in the filename is a period, it is not treated as an extension (for example “.profile”).

    cmake_path(HAS_STEM <path> <output>)

Checks if `<path>` has stem (GET … STEM returns a non empty path).

    cmake_path(HAS_RELATIVE_PATH <path> <output>)

Checks if `<path>` has relative path (GET_RELATIVE_PATH returns a non-empty path).

    cmake_path(HAS_PARENT_PATH <path> <output>)

Checks if `<path>` has parent path. The result is true except if the path is only composed of a filename.

    cmake_path(IS_ABSOLUTE <path> <output>)

Checks if `<path>` is absolute.

An absolute path is a path that unambiguously identifies the location of a file without reference to an additional starting location.

    cmake_path(IS_RELATIVE <path> <output>)

Checks if path is relative (i.e. not absolute).

    cmake_path(IS_PREFIX <path> <input> [NORMALIZE] <output>)

Checks if `<path>` is the prefix of `<input>`.

When `NORMALIZE` option is specified, the paths are normalized before the check.

## Hashing

    cmake_path(HASH <path> [NORMALIZE] <output>)

Compute hash value of `<path>` such that if for two paths (`p1` and `p2`) are equal (COMPARE … EQUAL) then hash value of p1 is equal to hash value of p2.

When `NORMALIZE` option is specified, the paths are normalized before the check.