diff options
author | Marc Chevrier <marc.chevrier@gmail.com> | 2022-05-18 09:15:10 (GMT) |
---|---|---|
committer | Marc Chevrier <marc.chevrier@gmail.com> | 2022-05-31 13:39:51 (GMT) |
commit | f11e66670ba9716f45cf757285a77b937dce420b (patch) | |
tree | c18b78f99b1bdcc7b36ebbab43727816a07803ed | |
parent | 9f4aec6d61f0c4f91cae8f35c5b514d456fba8ff (diff) | |
download | CMake-f11e66670ba9716f45cf757285a77b937dce420b.zip CMake-f11e66670ba9716f45cf757285a77b937dce420b.tar.gz CMake-f11e66670ba9716f45cf757285a77b937dce420b.tar.bz2 |
Genex-PATH: path handling
Fixes: #23498
31 files changed, 1818 insertions, 1 deletions
diff --git a/Help/command/cmake_path.rst b/Help/command/cmake_path.rst index 454c860..77525ed 100644 --- a/Help/command/cmake_path.rst +++ b/Help/command/cmake_path.rst @@ -96,6 +96,8 @@ The following conventions are used in this command's documentation: The name of a variable into which the result of a command will be written. +.. _Path Structure And Terminology: + Path Structure And Terminology ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -216,6 +218,8 @@ normalize a path is as follows: is ``.``). +.. _Path Decomposition: + Decomposition ^^^^^^^^^^^^^ @@ -385,6 +389,8 @@ Path traversal examples Parent path is "c:/" +.. _Path Query: + Query ^^^^^ @@ -495,6 +501,8 @@ according to the following pseudo-code logic: takes literal strings as input, not the names of variables. +.. _Path Modification: + Modification ^^^^^^^^^^^^ @@ -509,7 +517,7 @@ path, it is converted into a cmake-style path with forward-slashes (``/``). On Windows, the long filename marker is taken into account. When the ``NORMALIZE`` option is specified, the path is :ref:`normalized -<Normalization>` before the conversion. +<Normalization>` after the conversion. For example: @@ -644,6 +652,8 @@ is equivalent to the following: cmake_path(APPEND_STRING path "input") +.. _Path Generation: + Generation ^^^^^^^^^^ diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 848a133..1f0dd59 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -123,6 +123,71 @@ String Comparisons ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``. +.. _GenEx Path Queries: + +Path Queries +------------ + +The ``$<PATH>`` generator expression offers the same capabilities as the +:command:`cmake_path` command, for the :ref:`Query <Path Query>` options. + +For all ``$<PATH>`` generator expressions, paths are expected in cmake-style +format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>` generator +expression can be used to convert a native path to a cmake-style one. + +The ``$<PATH>`` generator expression can also be used for path +:ref:`Decomposition <GenEx Path Decomposition>` and +:ref:`Transformations <GenEx Path Transformations>`. + +.. genex:: $<PATH:HAS_*,path> + + .. versionadded:: 3.24 + + The following operations return ``1`` if the particular path component is + present, ``0`` otherwise. See :ref:`Path Structure And Terminology` for the + meaning of each path component. + + :: + + $<PATH:HAS_ROOT_NAME,path> + $<PATH:HAS_ROOT_DIRECTORY,path> + $<PATH:HAS_ROOT_PATH,path> + $<PATH:HAS_FILENAME,path> + $<PATH:HAS_EXTENSION,path> + $<PATH:HAS_STEM,path> + $<PATH:HAS_RELATIVE_PART,path> + $<PATH:HAS_PARENT_PATH,path> + + Note the following special cases: + + * For ``HAS_ROOT_PATH``, a true result will only be returned if at least one + of ``root-name`` or ``root-directory`` is non-empty. + + * For ``HAS_PARENT_PATH``, the root directory is also considered to have a + parent, which will be itself. The result is true except if the path + consists of just a :ref:`filename <FILENAME_DEF>`. + +.. genex:: $<PATH:IS_ABSOLUTE,path> + + .. versionadded:: 3.24 + + Returns ``1`` if the path is :ref:`absolute <IS_ABSOLUTE>`, ``0`` otherwise. + +.. genex:: $<PATH:IS_RELATIVE,path> + + .. versionadded:: 3.24 + + This will return the opposite of ``IS_ABSOLUTE``. + +.. genex:: $<PATH:IS_PREFIX[,NORMALIZE],path,input> + + .. versionadded:: 3.24 + + Returns ``1`` if ``path`` is the prefix of ``input``,``0`` otherwise. + + When the ``NORMALIZE`` option is specified, ``path`` and ``input`` are + :ref:`normalized <Normalization>` before the check. + Variable Queries ---------------- @@ -668,6 +733,153 @@ String Transformations echo $<TARGET_GENEX_EVAL:foo,$<TARGET_PROPERTY:foo,CUSTOM_KEYS>> ) +.. _GenEx Path Decomposition: + +Path Decomposition +------------------ + +The ``$<PATH>`` generator expression offers the same capabilities as the +:command:`cmake_path` command, for the +:ref:`Decomposition <Path Decomposition>` options. + +For all ``$<PATH>`` generator expressions, paths are expected in cmake-style +format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>` generator +expression can be used to convert a native path to a cmake-style one. + +The ``$<PATH>`` generator expression can also be used for path +:ref:`Queries <GenEx Path Queries>` and +:ref:`Transformations <GenEx Path Transformations>`. + +.. genex:: $<PATH:GET_*,...> + + .. versionadded:: 3.24 + + The following operations retrieve a different component or group of + components from a path. See :ref:`Path Structure And Terminology` for the + meaning of each path component. + + :: + + $<PATH:GET_ROOT_NAME,path> + $<PATH:GET_ROOT_DIRECTORY,path> + $<PATH:GET_ROOT_PATH,path> + $<PATH:GET_FILENAME,path> + $<PATH:GET_EXTENSION[,LAST_ONLY],path> + $<PATH:GET_STEM[,LAST_ONLY],path> + $<PATH:GET_RELATIVE_PART,path> + $<PATH:GET_PARENT_PATH,path> + + If a requested component is not present in the path, an empty string is + returned. + +.. _GenEx Path Transformations: + +Path Transformations +-------------------- + +The ``$<PATH>`` generator expression offers the same capabilities as the +:command:`cmake_path` command, for the +:ref:`Modification <Path Modification>` and +:ref:`Generation <Path Generation>` options. + +For all ``$<PATH>`` generator expressions, paths are expected in cmake-style +format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>` generator +expression can be used to convert a native path to a cmake-style one. + +The ``$<PATH>`` generator expression can also be used for path +:ref:`Queries <GenEx Path Queries>` and +:ref:`Decomposition <GenEx Path Decomposition>`. + +.. _GenEx PATH-CMAKE_PATH: + +.. genex:: $<PATH:CMAKE_PATH[,NORMALIZE],path> + + .. versionadded:: 3.24 + + Returns ``path``. If ``path`` is a native path, it is converted into a + cmake-style path with forward-slashes (``/``). On Windows, the long filename + marker is taken into account. + + When the ``NORMALIZE`` option is specified, the path is :ref:`normalized + <Normalization>` after the conversion. + +.. genex:: $<PATH:APPEND,path,input,...> + + .. versionadded:: 3.24 + + Returns all the ``input`` arguments appended to ``path`` using ``/`` as the + ``directory-separator``. Depending on the ``input``, the value of ``path`` + may be discarded. + + See :ref:`cmake_path(APPEND) <APPEND>` for more details. + +.. genex:: $<PATH:REMOVE_FILENAME,path> + + .. versionadded:: 3.24 + + Returns ``path`` with filename component (as returned by + ``$<PATH:GET_FILENAME>``) removed. After removal, any trailing + ``directory-separator`` is left alone, if present. + + See :ref:`cmake_path(REMOVE_FILENAME) <REMOVE_FILENAME>` for more details. + +.. genex:: $<PATH:REPLACE_FILENAME,path,input> + + .. versionadded:: 3.24 + + Returns ``path`` with the filename component replaced by ``input``. If + ``path`` has no filename component (i.e. ``$<PATH:HAS_FILENAME>`` returns + ``0``), ``path`` is unchanged. + + See :ref:`cmake_path(REPLACE_FILENAME) <REPLACE_FILENAME>` for more details. + +.. genex:: $<PATH:REMOVE_EXTENSION[,LAST_ONLY],path> + + .. versionadded:: 3.24 + + Returns ``path`` with the :ref:`extension <EXTENSION_DEF>` removed, if any. + + See :ref:`cmake_path(REMOVE_EXTENSION) <REMOVE_EXTENSION>` for more details. + +.. genex:: $<PATH:REPLACE_EXTENSION[,LAST_ONLY],path> + + .. versionadded:: 3.24 + + Returns ``path`` with the :ref:`extension <EXTENSION_DEF>` replaced by + ``input``, if any. + + See :ref:`cmake_path(REPLACE_EXTENSION) <REPLACE_EXTENSION>` for more details. + +.. genex:: $<PATH:NORMAL_PATH,path> + + .. versionadded:: 3.24 + + Returns ``path`` normalized according to the steps described in + :ref:`Normalization`. + +.. genex:: $<PATH:RELATIVE_PATH,path,base_directory> + + .. versionadded:: 3.24 + + Returns ``path``, modified to make it relative to the ``base_directory`` + argument. + + See :ref:`cmake_path(RELATIVE_PATH) <cmake_path-RELATIVE_PATH>` for more + details. + +.. genex:: $<PATH:ABSOLUTE_PATH[,NORMALIZE],path,base_directory> + + .. versionadded:: 3.24 + + Returns ``path`` as absolute. If ``path`` is a relative path + (``$<PATH:IS_RELATIVE>`` returns ``1``), it is evaluated relative to the + given base directory specified by ``base_directory`` argument. + + When the ``NORMALIZE`` option is specified, the path is + :ref:`normalized <Normalization>` after the path computation. + + See :ref:`cmake_path(ABSOLUTE_PATH) <ABSOLUTE_PATH>` for more details. + Variable Queries ---------------- diff --git a/Help/release/dev/Genex-PATH.rst b/Help/release/dev/Genex-PATH.rst new file mode 100644 index 0000000..870ee23 --- /dev/null +++ b/Help/release/dev/Genex-PATH.rst @@ -0,0 +1,4 @@ +Genex-PATH +---------- + +* The :genex:`PATH` generator expression was added to manage paths. diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index beb623f..52b771a 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -7,10 +7,12 @@ #include <cerrno> #include <cstdlib> #include <cstring> +#include <functional> #include <map> #include <memory> #include <set> #include <sstream> +#include <unordered_map> #include <utility> #include <cm/iterator> @@ -24,6 +26,7 @@ #include "cmsys/String.h" #include "cmAlgorithms.h" +#include "cmCMakePath.h" #include "cmComputeLinkInformation.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionContext.h" @@ -599,6 +602,438 @@ static const struct UpperCaseNode : public cmGeneratorExpressionNode } } upperCaseNode; +namespace { +template <typename Container> +class Range : public cmRange<typename Container::const_iterator> +{ +private: + using Base = cmRange<typename Container::const_iterator>; + +public: + using const_iterator = typename Container::const_iterator; + using value_type = typename Container::value_type; + using size_type = typename Container::size_type; + using difference_type = typename Container::difference_type; + using const_reference = typename Container::const_reference; + + Range(const Container& container) + : Base(container.begin(), container.end()) + { + } + + const_reference operator[](size_type pos) const + { + return *(this->begin() + pos); + } + + const_reference front() const { return *this->begin(); } + const_reference back() const { return *std::prev(this->end()); } + + Range& advance(difference_type amount) & + { + Base::advance(amount); + return *this; + } + Range advance(difference_type amount) && + { + Base::advance(amount); + return std::move(*this); + } +}; + +using Arguments = Range<std::vector<std::string>>; + +bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + cm::string_view option, std::size_t count, + int required = 1, bool exactly = true) +{ + if (static_cast<int>(count) < required || + (exactly && static_cast<int>(count) > required)) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("$<PATH:", option, "> expression requires ", + (exactly ? "exactly" : "at least"), ' ', + (required == 1 ? "one parameter" : "two parameters"), + '.')); + return false; + } + return true; +}; +bool CheckPathParameters(cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + cm::string_view option, const Arguments& args, + int required = 1) +{ + return CheckPathParametersEx(ctx, cnt, option, args.size(), required); +}; +std::string ToString(bool isTrue) +{ + return isTrue ? "1" : "0"; +}; +} + +static const struct PathNode : public cmGeneratorExpressionNode +{ + PathNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return TwoOrMoreParameters; } + + bool AcceptsArbitraryContentParameter() const override { return true; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + static std::unordered_map< + cm::string_view, + std::function<std::string(cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + Arguments&)>> + pathCommands{ + { "GET_ROOT_NAME"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "GET_ROOT_NAME"_s, args) && + !args.front().empty() + ? cmCMakePath{ args.front() }.GetRootName().String() + : std::string{}; + } }, + { "GET_ROOT_DIRECTORY"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "GET_ROOT_DIRECTORY"_s, + args) && + !args.front().empty() + ? cmCMakePath{ args.front() }.GetRootDirectory().String() + : std::string{}; + } }, + { "GET_ROOT_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "GET_ROOT_PATH"_s, args) && + !args.front().empty() + ? cmCMakePath{ args.front() }.GetRootPath().String() + : std::string{}; + } }, + { "GET_FILENAME"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "GET_FILENAME"_s, args) && + !args.front().empty() + ? cmCMakePath{ args.front() }.GetFileName().String() + : std::string{}; + } }, + { "GET_EXTENSION"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + bool lastOnly = args.front() == "LAST_ONLY"_s; + if (lastOnly) { + args.advance(1); + } + if (CheckPathParametersEx(ctx, cnt, + lastOnly ? "GET_EXTENSION,LAST_ONLY"_s + : "GET_EXTENSION"_s, + args.size())) { + if (args.front().empty()) { + return std::string{}; + } + return lastOnly + ? cmCMakePath{ args.front() }.GetExtension().String() + : cmCMakePath{ args.front() }.GetWideExtension().String(); + } + return std::string{}; + } }, + { "GET_STEM"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + bool lastOnly = args.front() == "LAST_ONLY"_s; + if (lastOnly) { + args.advance(1); + } + if (CheckPathParametersEx( + ctx, cnt, lastOnly ? "GET_STEM,LAST_ONLY"_s : "GET_STEM"_s, + args.size())) { + if (args.front().empty()) { + return std::string{}; + } + return lastOnly + ? cmCMakePath{ args.front() }.GetStem().String() + : cmCMakePath{ args.front() }.GetNarrowStem().String(); + } + return std::string{}; + } }, + { "GET_RELATIVE_PART"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "GET_RELATIVE_PART"_s, + args) && + !args.front().empty() + ? cmCMakePath{ args.front() }.GetRelativePath().String() + : std::string{}; + } }, + { "GET_PARENT_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "GET_PARENT_PATH"_s, args) + ? cmCMakePath{ args.front() }.GetParentPath().String() + : std::string{}; + } }, + { "HAS_ROOT_NAME"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_ROOT_NAME"_s, args) + ? ToString(cmCMakePath{ args.front() }.HasRootName()) + : std::string{ "0" }; + } }, + { "HAS_ROOT_DIRECTORY"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_ROOT_DIRECTORY"_s, args) + ? ToString(cmCMakePath{ args.front() }.HasRootDirectory()) + : std::string{ "0" }; + } }, + { "HAS_ROOT_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_ROOT_PATH"_s, args) + ? ToString(cmCMakePath{ args.front() }.HasRootPath()) + : std::string{ "0" }; + } }, + { "HAS_FILENAME"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_FILENAME"_s, args) + ? ToString(cmCMakePath{ args.front() }.HasFileName()) + : std::string{ "0" }; + } }, + { "HAS_EXTENSION"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_EXTENSION"_s, args) && + !args.front().empty() + ? ToString(cmCMakePath{ args.front() }.HasExtension()) + : std::string{ "0" }; + } }, + { "HAS_STEM"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_STEM"_s, args) + ? ToString(cmCMakePath{ args.front() }.HasStem()) + : std::string{ "0" }; + } }, + { "HAS_RELATIVE_PART"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_RELATIVE_PART"_s, args) + ? ToString(cmCMakePath{ args.front() }.HasRelativePath()) + : std::string{ "0" }; + } }, + { "HAS_PARENT_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "HAS_PARENT_PATH"_s, args) + ? ToString(cmCMakePath{ args.front() }.HasParentPath()) + : std::string{ "0" }; + } }, + { "IS_ABSOLUTE"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "IS_ABSOLUTE"_s, args) + ? ToString(cmCMakePath{ args.front() }.IsAbsolute()) + : std::string{ "0" }; + } }, + { "IS_RELATIVE"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "IS_RELATIVE"_s, args) + ? ToString(cmCMakePath{ args.front() }.IsRelative()) + : std::string{ "0" }; + } }, + { "IS_PREFIX"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + bool normalize = args.front() == "NORMALIZE"_s; + if (normalize) { + args.advance(1); + } + if (CheckPathParametersEx(ctx, cnt, + normalize ? "IS_PREFIX,NORMALIZE"_s + : "IS_PREFIX"_s, + args.size(), 2)) { + if (normalize) { + return ToString(cmCMakePath{ args[0] }.Normal().IsPrefix( + cmCMakePath{ args[1] }.Normal())); + } + return ToString( + cmCMakePath{ args[0] }.IsPrefix(cmCMakePath{ args[1] })); + } + return std::string{}; + } }, + { "CMAKE_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + bool normalize = args.front() == "NORMALIZE"_s; + if (normalize) { + args.advance(1); + } + if (CheckPathParametersEx(ctx, cnt, + normalize ? "CMAKE_PATH,NORMALIZE"_s + : "CMAKE_PATH"_s, + args.size(), 1)) { + auto path = + cmCMakePath{ args.front(), cmCMakePath::auto_format }; + return normalize ? path.Normal().GenericString() + : path.GenericString(); + } + return std::string{}; + } }, + { "APPEND"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckPathParametersEx(ctx, cnt, "APPEND"_s, args.size(), 1, + false)) { + cmCMakePath path; + for (const auto& p : args) { + path /= p; + } + return path.String(); + } + return std::string{}; + } }, + { "REMOVE_FILENAME"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "REMOVE_FILENAME"_s, args) && + !args.front().empty() + ? cmCMakePath{ args.front() }.RemoveFileName().String() + : std::string{}; + } }, + { "REPLACE_FILENAME"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "REPLACE_FILENAME"_s, args, 2) + ? cmCMakePath{ args[0] } + .ReplaceFileName(cmCMakePath{ args[1] }) + .String() + : std::string{}; + } }, + { "REMOVE_EXTENSION"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + bool lastOnly = args.front() == "LAST_ONLY"_s; + if (lastOnly) { + args.advance(1); + } + if (CheckPathParametersEx(ctx, cnt, + lastOnly ? "REMOVE_EXTENSION,LAST_ONLY"_s + : "REMOVE_EXTENSION"_s, + args.size())) { + if (args.front().empty()) { + return std::string{}; + } + return lastOnly + ? cmCMakePath{ args.front() }.RemoveExtension().String() + : cmCMakePath{ args.front() }.RemoveWideExtension().String(); + } + return std::string{}; + } }, + { "REPLACE_EXTENSION"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + bool lastOnly = args.front() == "LAST_ONLY"_s; + if (lastOnly) { + args.advance(1); + } + if (CheckPathParametersEx(ctx, cnt, + lastOnly + ? "REPLACE_EXTENSION,LAST_ONLY"_s + : "REPLACE_EXTENSION"_s, + args.size(), 2)) { + if (lastOnly) { + return cmCMakePath{ args[0] } + .ReplaceExtension(cmCMakePath{ args[1] }) + .String(); + } + return cmCMakePath{ args[0] } + .ReplaceWideExtension(cmCMakePath{ args[1] }) + .String(); + } + return std::string{}; + } }, + { "NORMAL_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "NORMAL_PATH"_s, args) && + !args.front().empty() + ? cmCMakePath{ args.front() }.Normal().String() + : std::string{}; + } }, + { "RELATIVE_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + return CheckPathParameters(ctx, cnt, "RELATIVE_PATH"_s, args, 2) + ? cmCMakePath{ args[0] }.Relative(args[1]).String() + : std::string{}; + } }, + { "ABSOLUTE_PATH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + bool normalize = args.front() == "NORMALIZE"_s; + if (normalize) { + args.advance(1); + } + if (CheckPathParametersEx(ctx, cnt, + normalize ? "ABSOLUTE_PATH,NORMALIZE"_s + : "ABSOLUTE_PATH"_s, + args.size(), 2)) { + auto path = cmCMakePath{ args[0] }.Absolute(args[1]); + return normalize ? path.Normal().String() : path.String(); + } + return std::string{}; + } } + }; + + if (cm::contains(pathCommands, parameters.front())) { + auto args = Arguments{ parameters }.advance(1); + return pathCommands[parameters.front()](context, content, args); + } + + reportError(context, content->GetOriginalExpression(), + cmStrCat(parameters.front(), ": invalid option.")); + return std::string{}; + } +} pathNode; + static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode { MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default) @@ -2829,6 +3264,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "REMOVE_DUPLICATES", &removeDuplicatesNode }, { "LOWER_CASE", &lowerCaseNode }, { "UPPER_CASE", &upperCaseNode }, + { "PATH", &pathNode }, { "MAKE_C_IDENTIFIER", &makeCIdentifierNode }, { "BOOL", &boolNode }, { "IF", &ifNode }, diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 6f90bf7..a94cf21 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -330,6 +330,7 @@ add_RunCMake_test(GenEx-LINK_GROUP) add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB}) add_RunCMake_test(GenEx-GENEX_EVAL) add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS) +add_RunCMake_test(GenEx-PATH) add_RunCMake_test(GeneratorExpression) add_RunCMake_test(GeneratorInstance) add_RunCMake_test(GeneratorPlatform) diff --git a/Tests/RunCMake/GenEx-PATH/ABSOLUTE_PATH.cmake.in b/Tests/RunCMake/GenEx-PATH/ABSOLUTE_PATH.cmake.in new file mode 100644 index 0000000..cc5ff54 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/ABSOLUTE_PATH.cmake.in @@ -0,0 +1,34 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set (reference "../../a/d") +cmake_path(ABSOLUTE_PATH reference BASE_DIRECTORY "/x/y/a/f") +set(output "$<PATH:ABSOLUTE_PATH,../../a/d,/x/y/a/f>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "../../a/d") +cmake_path(ABSOLUTE_PATH reference BASE_DIRECTORY "/x/y/a/f" NORMALIZE) +set(output "$<PATH:ABSOLUTE_PATH,NORMALIZE,../../a/d,/x/y/a/f>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "/a/d/../e") +cmake_path(ABSOLUTE_PATH reference BASE_DIRECTORY "/x/y/a/f") +set(output "$<PATH:ABSOLUTE_PATH,/a/d/../e,/x/y/a/f>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "/a/d/../e") +cmake_path(ABSOLUTE_PATH reference BASE_DIRECTORY "/x/y/a/f" NORMALIZE) +set(output "$<PATH:ABSOLUTE_PATH,NORMALIZE,/a/d/../e,/x/y/a/f>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + + +check_errors("PATH:ABSOLUTE_PATH" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/APPEND.cmake.in b/Tests/RunCMake/GenEx-PATH/APPEND.cmake.in new file mode 100644 index 0000000..ab967a2 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/APPEND.cmake.in @@ -0,0 +1,68 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +cmake_path (APPEND path "/a/b" "c") +set(output "$<PATH:APPEND,/a/b,c>") +if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") +endif() + +set (path "a") +cmake_path (APPEND path "") +set(output "$<PATH:APPEND,a,>") +if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") +endif() + +cmake_path (APPEND path "/b") +set(output "$<PATH:APPEND,a/,/b>") +if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") +endif() + +if (WIN32) + set (path "a") + cmake_path (APPEND path "c:/b") + set(output "$<PATH:APPEND,a,c:/b>") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "a") + cmake_path (APPEND path "c:") + set(output "$<PATH:APPEND,a,c:>") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "c:a") + cmake_path (APPEND path "/b") + set(output "$<PATH:APPEND,c:a,/b>") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "c:a") + cmake_path (APPEND path "c:b") + set(output "$<PATH:APPEND,c:a,c:b>") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "//host") + cmake_path (APPEND path "b") + set(output "$<PATH:APPEND,//host,b>") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "//host/") + cmake_path (APPEND path "b") + set(output "$<PATH:APPEND,//host/,b>") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() +endif() + +check_errors ("PATH:APPEND" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/CMAKE_PATH.cmake.in b/Tests/RunCMake/GenEx-PATH/CMAKE_PATH.cmake.in new file mode 100644 index 0000000..41205fa --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/CMAKE_PATH.cmake.in @@ -0,0 +1,53 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + + +cmake_path(SET reference "/x/y/z/../../a/d") +set(output "$<PATH:CMAKE_PATH,/x/y/z/../../a/d>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() +cmake_path(SET reference NORMALIZE "/x/y/z/../../a/d") +set(output "$<PATH:CMAKE_PATH,NORMALIZE,/x/y/z/../../a/d>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +if (WIN32) + cmake_path(SET reference "/x\\y/z\\..\\../a/d") + set(output "$<PATH:CMAKE_PATH,/x\y/z\..\../a/d>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + cmake_path(SET reference NORMALIZE "/x\\y/z\\..\\../a/d") + set(output "$<PATH:CMAKE_PATH,NORMALIZE,/x\y/z\..\../a/d>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + + cmake_path(SET reference "//?/c:/x\\y/z\\..\\../a/d") + set(output "$<PATH:CMAKE_PATH,//?/c:/x\y/z\..\../a/d>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + cmake_path(SET reference NORMALIZE "//?/c:/x\\y/z\\..\\../a/d") + set(output "$<PATH:CMAKE_PATH,NORMALIZE,//?/c:/x\y/z\..\../a/d>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + + cmake_path(SET reference "\\\\?\\UNC/host/x\\y/z\\..\\../a/d") + set(output "$<PATH:CMAKE_PATH,\\?\UNC/host/x\y/z\..\../a/d>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + cmake_path(SET reference NORMALIZE "\\\\?\\UNC\\host/x\\y/z\\..\\../a/d") + set(output "$<PATH:CMAKE_PATH,NORMALIZE,\\?\UNC/host/x\y/z\..\../a/d>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() +endif() + + +check_errors("PATH:CMAKE_PATH" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/CMakeLists.txt b/Tests/RunCMake/GenEx-PATH/CMakeLists.txt new file mode 100644 index 0000000..f9748e9 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.18...3.24) + +project(${RunCMake_TEST} NONE) + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/GenEx-PATH/GET_ITEM.cmake.in b/Tests/RunCMake/GenEx-PATH/GET_ITEM.cmake.in new file mode 100644 index 0000000..b58998c --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/GET_ITEM.cmake.in @@ -0,0 +1,311 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +############################################### +## First test with a path defining all elements +############################################### +if (WIN32) + set (path "C:/aa/bb/cc.ext1.ext2") +else() + set (path "/aa/bb/cc.ext1.ext2") +endif() + +cmake_path(GET path ROOT_NAME reference) +if (WIN32) + set(output "$<PATH:GET_ROOT_NAME,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_ROOT_NAME,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_NAME returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_DIRECTORY reference) +if (WIN32) + set(output "$<PATH:GET_ROOT_DIRECTORY,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_ROOT_DIRECTORY,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_DIRECTORY returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_PATH reference) +if (WIN32) + set(output "$<PATH:GET_ROOT_PATH,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_ROOT_PATH,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_PATH returns bad data: ${output}") +endif() + +cmake_path(GET path FILENAME reference) +if (WIN32) + set(output "$<PATH:GET_FILENAME,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_FILENAME,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +if (WIN32) + set(output "$<PATH:GET_EXTENSION,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_EXTENSION,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() +cmake_path(GET path EXTENSION LAST_ONLY reference) +if (WIN32) + set(output "$<PATH:GET_EXTENSION,LAST_ONLY,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_EXTENSION,LAST_ONLY,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION LAST_ONLY returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +if (WIN32) + set(output "$<PATH:GET_STEM,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_STEM,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() +cmake_path(GET path STEM LAST_ONLY reference) +if (WIN32) + set(output "$<PATH:GET_STEM,LAST_ONLY,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_STEM,LAST_ONLY,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "STEM LAST_ONLY returns bad data: ${reference}") +endif() + +cmake_path(GET path RELATIVE_PART reference) +if (WIN32) + set(output "$<PATH:GET_RELATIVE_PART,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_RELATIVE_PART,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "RELATIVE_PART returns bad data: ${output}") +endif() + +cmake_path(GET path PARENT_PATH reference) +if (WIN32) + set(output "$<PATH:GET_PARENT_PATH,C:/aa/bb/cc.ext1.ext2>") +else() + set (output "$<PATH:GET_PARENT_PATH,/aa/bb/cc.ext1.ext2>") +endif() +if (NOT output STREQUAL reference) + list (APPEND errors "PARENT_PATH returns bad data: ${output}") +endif() + +###################################### +## second, tests with missing elements +###################################### +set (path "aa/bb/") + +cmake_path(GET path ROOT_NAME reference) +set(output "$<PATH:GET_ROOT_NAME,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_NAME returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_DIRECTORY reference) +set(output "$<PATH:GET_ROOT_DIRECTORY,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_DIRECTORY returns bad data: >${output}<, >${reference}<") +endif() + +cmake_path(GET path ROOT_PATH reference) +set(output "$<PATH:GET_ROOT_PATH,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_PATH returns bad data: ${output}") +endif() + +cmake_path(GET path FILENAME reference) +set(output "$<PATH:GET_FILENAME,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$<PATH:GET_EXTENSION,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$<PATH:GET_STEM,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() + +cmake_path(GET path RELATIVE_PART reference) +set(output "$<PATH:GET_RELATIVE_PART,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "RELATIVE_PART returns bad data: ${output}") +endif() + +cmake_path(GET path PARENT_PATH reference) +set(output "$<PATH:GET_PARENT_PATH,aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "PARENT_PATH returns bad data: ${output}") +endif() + +################################## +set (path "/aa/bb/") + +cmake_path(GET path ROOT_NAME reference) +set(output "$<PATH:GET_ROOT_NAME,/aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_NAME returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_DIRECTORY reference) +set(output "$<PATH:GET_ROOT_DIRECTORY,/aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_DIRECTORY returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_PATH reference) +set(output "$<PATH:GET_ROOT_PATH,/aa/bb/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_PATH returns bad data: ${output}") +endif() + +################################### +set (path "/") + +cmake_path(GET path ROOT_NAME reference) +set(output "$<PATH:GET_ROOT_NAME,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_NAME returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_DIRECTORY reference) +set(output "$<PATH:GET_ROOT_DIRECTORY,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_DIRECTORY returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_PATH reference) +set(output "$<PATH:GET_ROOT_PATH,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_PATH returns bad data: ${output}") +endif() + +cmake_path(GET path FILENAME reference) +set(output "$<PATH:GET_FILENAME,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$<PATH:GET_EXTENSION,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$<PATH:GET_STEM,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() + +cmake_path(GET path RELATIVE_PART reference) +set(output "$<PATH:GET_RELATIVE_PART,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "RELATIVE_PART returns bad data: ${output}") +endif() + +cmake_path(GET path PARENT_PATH reference) +set(output "$<PATH:GET_PARENT_PATH,/>") +if (NOT output STREQUAL reference) + list (APPEND errors "PARENT_PATH returns bad data: ${output}") +endif() + +################################### +set (path ".file") + +cmake_path(GET path FILENAME reference) +set(output "$<PATH:GET_FILENAME,.file>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$<PATH:GET_EXTENSION,.file>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$<PATH:GET_STEM,.file>") +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() + +################################### +set (path ".file.ext") + +cmake_path(GET path FILENAME reference) +set(output "$<PATH:GET_FILENAME,.file.ext>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$<PATH:GET_EXTENSION,.file.ext>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() +cmake_path(GET path EXTENSION LAST_ONLY reference) +set(output "$<PATH:GET_EXTENSION,LAST_ONLY,.file.ext>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$<PATH:GET_STEM,.file.ext>") +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() + +################################### +set (path ".file.ext1.ext2") + +cmake_path(GET path FILENAME reference) +set(output "$<PATH:GET_FILENAME,.file.ext1.ext2>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$<PATH:GET_EXTENSION,.file.ext1.ext2>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() +cmake_path(GET path EXTENSION LAST_ONLY reference) +set(output "$<PATH:GET_EXTENSION,LAST_ONLY,.file.ext1.ext2>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$<PATH:GET_STEM,.file.ext1.ext2>") +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() + + +check_errors("PATH:GET..." ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/HAS_ITEM.cmake.in b/Tests/RunCMake/GenEx-PATH/HAS_ITEM.cmake.in new file mode 100644 index 0000000..fab9bd6 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/HAS_ITEM.cmake.in @@ -0,0 +1,199 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set(output "$<PATH:HAS_ROOT_NAME,/a/b>") +if (output) + list (APPEND errors "ROOT_NAME: '/a/b' has root name") +endif() +set(output "$<PATH:HAS_ROOT_DIRECTORY,/a/b>") +if (NOT output) + list (APPEND errors "ROOT_DIRECTORY: '/a/b' does not have root directory") +endif() +set(output "$<PATH:HAS_ROOT_PATH,/a/b>") +if (NOT output) + list (APPEND errors "ROOT_PATH: '/a/b' does not have root path") +endif() + +set(output "$<PATH:HAS_ROOT_PATH,a/b>") +if (output) + list (APPEND errors "ROOT_PATH: 'a/b' has root path") +endif() + +set(output "$<PATH:HAS_FILENAME,/a/b>") +if (NOT output) + list (APPEND errors "FILENAME: '/a/b' does not have filename") +endif() +set(output "$<PATH:HAS_FILENAME,a.b>") +if (NOT output) + list (APPEND errors "FILENAME: 'a.b' does not have filename") +endif() +set(output "$<PATH:HAS_FILENAME,/a/b/>") +if (output) + list (APPEND errors "FILENAME: '/a/b/' has filename") +endif() +set(output "$<PATH:HAS_FILENAME,/>") +if (output) + list (APPEND errors "FILENAME: '/' has filename") +endif() + +set(output "$<PATH:HAS_STEM,/a/b>") +if (NOT output) + list (APPEND errors "STEM: '/a/b' does not have stem") +endif() +set(output "$<PATH:HAS_STEM,a.b>") +if (NOT output) + list (APPEND errors "STEM: 'a.b' does not have stem") +endif() +set(output "$<PATH:HAS_STEM,.a>") +if (NOT output) + list (APPEND errors "STEM: '.a'} does not have stem") +endif() +set(output "$<PATH:HAS_STEM,/a/>") +if (output) + list (APPEND errors "STEM: '/a/' has stem") +endif() +set(output "$<PATH:HAS_STEM,/>") +if (output) + list (APPEND errors "STEM: '/' has stem") +endif() + +set(output "$<PATH:HAS_EXTENSION,/a/b.c>") +if (NOT output) + list (APPEND errors "EXTENSION: '/a/b.c' does not have extension") +endif() +set(output "$<PATH:HAS_EXTENSION,b.c>") +if (NOT output) + list (APPEND errors "EXTENSION: 'b.c' does not have extension") +endif() +set(output "$<PATH:HAS_EXTENSION,/.a>") +if (output) + list (APPEND errors "EXTENSION: '/.a' has extension") +endif() +set(output "$<PATH:HAS_EXTENSION,/a/>") +if (output) + list (APPEND errors "EXTENSION: '/a/' has extension") +endif() +set(output "$<PATH:HAS_EXTENSION,/>") +if (output) + list (APPEND errors "EXTENSION: '/' has extension") +endif() + +set(output "$<PATH:HAS_RELATIVE_PART,/a/b>") +if (NOT output) + list (APPEND errors "RELATIVE_PART: '/a/b' does not have relative part") +endif() +set(output "$<PATH:HAS_RELATIVE_PART,/>") +if (output) + list (APPEND errors "RELATIVE_PART: '/' has relative part") +endif() + +set(output "$<PATH:HAS_PARENT_PATH,/a/b>") +if (NOT output) + list (APPEND errors "PARENT_PATH: '/a/b' does not have parent path") +endif() +set(output "$<PATH:HAS_PARENT_PATH,/>") +if (NOT output) + list (APPEND errors "PARENT_PATH: '/' does not have parent path") +endif() +set(output "$<PATH:HAS_PARENT_PATH,a>") +if (output) + list (APPEND errors "PARENT_PATH: 'a' has parent path") +endif() + +if (WIN32) + set(output "$<PATH:HAS_ROOT_NAME,c:/a/b>") + if (NOT output) + list (APPEND errors "ROOT_NAME: 'c:/a/b' does not have root name") + endif() + set(output "$<PATH:HAS_ROOT_DIRECTORY,c:/a/b>") + if (NOT output) + list (APPEND errors "ROOT_DIRECTORY: 'c:/a/b' does not have root directory") + endif() + set(output "$<PATH:HAS_ROOT_PATH,c:/a/b>") + if (NOT output) + list (APPEND errors "ROOT_PATH: 'c:/a/b' does not have root path") + endif() + + set(output "$<PATH:HAS_ROOT_NAME,c:a/b>") + if (NOT output) + list (APPEND errors "ROOT_NAME: 'c:a/b' does not have root name") + endif() + set(output "$<PATH:HAS_ROOT_DIRECTORY,c:a/b>") + if (output) + list (APPEND errors "ROOT_DIRECTORY: 'c:a/b' has root directory") + endif() + set(output "$<PATH:HAS_ROOT_PATH,c:a/b>") + if (NOT output) + list (APPEND errors "ROOT_PATH: 'c:a/b' does not have root path") + endif() + + set(output "$<PATH:HAS_ROOT_NAME,//host/b>") + if (NOT output) + list (APPEND errors "ROOT_NAME: '//host/b' does not have root name") + endif() + set(output "$<PATH:HAS_ROOT_DIRECTORY,//host/b>") + if (NOT output) + list (APPEND errors "ROOT_DIRECTORY: '//host/b' does not have root directory") + endif() + set(output "$<PATH:HAS_ROOT_PATH,//host/b>") + if (NOT output) + list (APPEND errors "ROOT_PATH: '//host/b' does not have root path") + endif() + + set(output "$<PATH:HAS_ROOT_NAME,//host>") + if (NOT output) + list (APPEND errors "ROOT_NAME: '//host' does not have root name") + endif() + set(output "$<PATH:HAS_ROOT_DIRECTORY,//host>") + if (output) + list (APPEND errors "ROOT_DIRECTORY: '//host' has root directory") + endif() + set(output "$<PATH:HAS_ROOT_PATH,//host>") + if (NOT output) + list (APPEND errors "ROOT_PATH: '//host' does not have root path") + endif() + + set(output "$<PATH:HAS_RELATIVE_PART,c:/a/b>") + if (NOT output) + list (APPEND errors "RELATIVE_PART: 'c:/a/b' does not have relative part") + endif() + + set(output "$<PATH:HAS_RELATIVE_PART,c:a/b>") + if (NOT output) + list (APPEND errors "RELATIVE_PART: 'c:a/b' does not have relative part") + endif() + + set(output "$<PATH:HAS_RELATIVE_PART,//host/b>") + if (NOT output) + list (APPEND errors "RELATIVE_PART: '//host/b' does not have relative part") + endif() + + set(output "$<PATH:HAS_PARENT_PATH,c:/a/b>") + if (NOT output) + list (APPEND errors "PARENT_PATH: 'c:/a/b' does not have parent path") + endif() + + set(output "$<PATH:HAS_PARENT_PATH,c:/>") + if (NOT output) + list (APPEND errors "PARENT_PATH: 'c:/' does not have parent path") + endif() + + set(output "$<PATH:HAS_PARENT_PATH,c:>") + if (NOT output) + list (APPEND errors "PARENT_PATH: 'c:' does not have parent path") + endif() + + set(output "$<PATH:HAS_PARENT_PATH,//host/>") + if (NOT output) + list (APPEND errors "PARENT_PATH: '//host/' does not have parent path") + endif() + + set(output "$<PATH:HAS_PARENT_PATH,//host>") + if (NOT output) + list (APPEND errors "PARENT_PATH: '//host' does not have parent path") + endif() +endif() + + +check_errors ("PATH:HAS..." ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/IS_ABSOLUTE.cmake.in b/Tests/RunCMake/GenEx-PATH/IS_ABSOLUTE.cmake.in new file mode 100644 index 0000000..872dae4 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/IS_ABSOLUTE.cmake.in @@ -0,0 +1,44 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +if (WIN32) + set(path "c:/a") + set(output "$<PATH:IS_ABSOLUTE,c:/a>") +else() + set(path "/a") + set(output "$<PATH:IS_ABSOLUTE,/a>") +endif() +if (NOT output) + list (APPEND errors "'${path}' is not absolute") +endif() + +set(output "$<PATH:IS_ABSOLUTE,a/b>") +if (output) + list (APPEND errors "'a/b' is absolute") +endif() + +if (WIN32) + set(output "$<PATH:IS_ABSOLUTE,c:/a/b>") + if (NOT output) + list (APPEND errors "'c:/a/b' is not absolute") + endif() + + set(output "$<PATH:IS_ABSOLUTE,//host/b>") + if (NOT output) + list (APPEND errors "'//host/b' is not absolute") + endif() + + set(output "$<PATH:IS_ABSOLUTE,/a>") + if (output) + list (APPEND errors "'/a' is absolute") + endif() + + set(output "$<PATH:IS_ABSOLUTE,c:a>") + if (output) + list (APPEND errors "'c:a' is absolute") + endif() +endif() + + +check_errors("PATH:IS_ABSOLUTE" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/IS_PREFIX.cmake.in b/Tests/RunCMake/GenEx-PATH/IS_PREFIX.cmake.in new file mode 100644 index 0000000..98b7ff8 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/IS_PREFIX.cmake.in @@ -0,0 +1,25 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set(output "$<PATH:IS_PREFIX,a///b/c,a/b/c/d>") +if (NOT output) + list (APPEND errors "'a///b/c' is not prefix of 'a/b/c/d'") +endif() + +set(output "$<PATH:IS_PREFIX,a///b/c/../d,a/b/d/e>") +if (output) + list (APPEND errors "'a///b/c/../d' is prefix of 'a/b/d/e'") +endif() +set(output "$<PATH:IS_PREFIX,NORMALIZE,a///b/c/../d,a/b/d/e>") +if (NOT output) + list (APPEND errors "'a///b/c/../d' is not prefix of 'a/b/d/e'") +endif() + +set(output "$<PATH:IS_PREFIX,NORMALIZE,/a/b/..,/a/c/../b") +if (NOT output) + list (APPEND errors "'/a/b/..' is not prefix of '/a/c/../b'") +endif() + + +check_errors("PATH:IS_PREFIX" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/IS_RELATIVE.cmake.in b/Tests/RunCMake/GenEx-PATH/IS_RELATIVE.cmake.in new file mode 100644 index 0000000..6d36581 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/IS_RELATIVE.cmake.in @@ -0,0 +1,45 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + + +if (WIN32) + set(path "c:/a") + set(output "$<PATH:IS_RELATIVE,c:/a>") +else() + set(path "/a") + set(output "$<PATH:IS_RELATIVE,/a>") +endif() +if (output) + list (APPEND errors "'${path} is relative") +endif() + +set(output "$<PATH:IS_RELATIVE,a/b>") +if (NOT output) + list (APPEND errors "'a/b' is not relative") +endif() + +if (WIN32) + set(output "$<PATH:IS_RELATIVE,c:/a/b>") + if (output) + list (APPEND errors "'c:/a/b' is relative") + endif() + + set(output "$<PATH:IS_RELATIVE,//host/b>") + if (output) + list (APPEND errors "'//host/b' is relative") + endif() + + set(output "$<PATH:IS_RELATIVE,/a>") + if (NOT output) + list (APPEND errors "'/a' is not relative") + endif() + + set(output "$<PATH:IS_RELATIVE,c:a>") + if (NOT output) + list (APPEND errors "'c:a' is not relative") + endif() +endif() + + +check_errors("PATH:IS_RELATIVE" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/NORMAL_PATH.cmake.in b/Tests/RunCMake/GenEx-PATH/NORMAL_PATH.cmake.in new file mode 100644 index 0000000..e6cc4a3 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/NORMAL_PATH.cmake.in @@ -0,0 +1,43 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set (reference "a/./b/..") +cmake_path(NORMAL_PATH reference) +set(output "$<PATH:NORMAL_PATH,a/./b/..>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "a/.///b/../") +cmake_path(NORMAL_PATH reference) +set(output "$<PATH:NORMAL_PATH,a/.///b/../>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +if (WIN32) + set (reference "//host/./b/..") + cmake_path(NORMAL_PATH reference) + set(output "$<PATH:NORMAL_PATH,//host/./b/..>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + + set (reference "//host/./b/../") + cmake_path(NORMAL_PATH reference) + set(output "$<PATH:NORMAL_PATH,//host/./b/../>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + + set (reference "c://a/.///b/../") + cmake_path(NORMAL_PATH reference) + set(output "$<PATH:NORMAL_PATH,c://a/.///b/../>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() +endif() + + +check_errors("PATH:NORMAL_PATH" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/RELATIVE_PATH.cmake.in b/Tests/RunCMake/GenEx-PATH/RELATIVE_PATH.cmake.in new file mode 100644 index 0000000..11d73ad --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/RELATIVE_PATH.cmake.in @@ -0,0 +1,64 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set (reference "/a//d") +cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "/a/b/c") +set(output "$<PATH:RELATIVE_PATH,/a//d,/a/b/c>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "/a//b///c") +cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "/a/d") +set(output "$<PATH:RELATIVE_PATH,/a/b///c,/a/d>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "a/b/c") +cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "a") +set(output "$<PATH:RELATIVE_PATH,a/b/c,a>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "a/b/c") +cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "a/b/c/x/y") +set(output "$<PATH:RELATIVE_PATH,a/b/c,a/b/c/x/y>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "a/b/c") +cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "a/b/c") +set(output "$<PATH:RELATIVE_PATH,a/b/c,a/b/c>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "a/b") +cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "c/d") +set(output "$<PATH:RELATIVE_PATH,a/b,c/d>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "/a/d") +cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "e/d/c") +set(output "$<PATH:RELATIVE_PATH,/a/d,e/d/c>") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +if (WIN32) + set (reference "c:/a/d") + cmake_path(RELATIVE_PATH reference BASE_DIRECTORY "e/d/c") + set(output "$<PATH:RELATIVE_PATH,c:/a/d,e/d/c>") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() +endif() + + +check_errors("PATH:RELATIVE_PATH" ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/REMOVE_ITEM.cmake.in b/Tests/RunCMake/GenEx-PATH/REMOVE_ITEM.cmake.in new file mode 100644 index 0000000..cce4143 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/REMOVE_ITEM.cmake.in @@ -0,0 +1,65 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set (reference "a/b/c.e.f") +cmake_path (REMOVE_FILENAME reference) +set(output "$<PATH:REMOVE_FILENAME,a/b/c.e.f>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME: '${output}' instead of '${reference}'") +endif() + +cmake_path (REMOVE_FILENAME reference) +set(output "$<PATH:REMOVE_FILENAME,a/b/>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME: '${output}' instead of '${reference}'") +endif() + + +set (reference "a/b/c.e.f") +cmake_path (REMOVE_EXTENSION reference) +set(output "$<PATH:REMOVE_EXTENSION,a/b/c.e.f>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + +set (reference "a/b/c.e.f") +cmake_path (REMOVE_EXTENSION reference LAST_ONLY) +set(output "$<PATH:REMOVE_EXTENSION,LAST_ONLY,a/b/c.e.f>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REMOVE_EXTENSION reference) +set(output "$<PATH:REMOVE_EXTENSION,a/b/c.e>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + +set (reference "a/b/c") +cmake_path (REMOVE_EXTENSION reference) +set(output "$<PATH:REMOVE_EXTENSION,a/b/c>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + +set (reference "a/b/.c") +cmake_path (REMOVE_EXTENSION reference) +set(output "$<PATH:REMOVE_EXTENSION,a/b/.c>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REMOVE_EXTENSION reference LAST_ONLY) +set(output "$<PATH:REMOVE_EXTENSION,LAST_ONLY,a/b/.c>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + +set (reference "a/b/.") +cmake_path (REMOVE_EXTENSION reference LAST_ONLY) +set(output "$<PATH:REMOVE_EXTENSION,LAST_ONLY,a/b/.>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + + +check_errors("PATH:REMOVE..." ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/REPLACE_ITEM.cmake.in b/Tests/RunCMake/GenEx-PATH/REPLACE_ITEM.cmake.in new file mode 100644 index 0000000..5bb04c3 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/REPLACE_ITEM.cmake.in @@ -0,0 +1,73 @@ + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set (reference "a/b/c.e.f") +cmake_path (REPLACE_FILENAME reference "x.y") +set(output "$<PATH:REPLACE_FILENAME,a/b/c.e.f,x.y>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME: '${output}' instead of '${reference}'") +endif() + +set (reference "a/b/") +cmake_path (REPLACE_FILENAME reference "x.y") +set(output "$<PATH:REPLACE_FILENAME,a/b/,x.y>") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME: '${output}' instead of '${reference}'") +endif() + +set (reference "a/b/c.e.f") +cmake_path (REPLACE_EXTENSION reference ".x") +set(output "$<PATH:REPLACE_EXTENSION,a/b/c.e.f,.x>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference ".y") +set(output "$<PATH:REPLACE_EXTENSION,a/b/c.x,.y>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference "") +set(output "$<PATH:REPLACE_EXTENSION,a/b/c.y,>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + +set (reference "a/b/c.e.f") +cmake_path (REPLACE_EXTENSION reference ".x" LAST_ONLY) +set(output "$<PATH:REPLACE_EXTENSION,LAST_ONLY,a/b/c.e.f,.x>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference ".y" LAST_ONLY) +set(output "$<PATH:REPLACE_EXTENSION,LAST_ONLY,a/b/c.e.x,.y>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference "" LAST_ONLY) +set(output "$<PATH:REPLACE_EXTENSION,LAST_ONLY,a/b/c.e.y,>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + +set (reference "/a/.b") +cmake_path (REPLACE_EXTENSION reference ".x") +set(output "$<PATH:REPLACE_EXTENSION,/a/.b,.x>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '/${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference ".x" LAST_ONLY) +set(output "$<PATH:REPLACE_EXTENSION,LAST_ONLY,/a/.b.x,.x>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + +set (reference "/a/b") +cmake_path (REPLACE_EXTENSION reference ".x") +set(output "$<PATH:REPLACE_EXTENSION,/a/b,.x>") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() + + +check_errors("PATH:REPLACE..." ${errors}) diff --git a/Tests/RunCMake/GenEx-PATH/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-PATH/RunCMakeTest.cmake new file mode 100644 index 0000000..a93777a --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/RunCMakeTest.cmake @@ -0,0 +1,68 @@ + +include(RunCMake) + +run_cmake(no-arguments) +run_cmake(bad-option) + +function(check_path_syntax name test) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-${test}-build) + set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}") + run_cmake_with_options(${test} ${ARGN}) +endfunction() + +## Unexpected arguments +### sub-commands with one argument +foreach (subcommand IN ITEMS GET_ROOT_NAME GET_ROOT_DIRECTORY GET_ROOT_PATH GET_FILENAME + GET_EXTENSION GET_STEM GET_RELATIVE_PART GET_PARENT_PATH + HAS_ROOT_NAME HAS_ROOT_DIRECTORY HAS_ROOT_PATH HAS_FILENAME + HAS_EXTENSION HAS_STEM HAS_RELATIVE_PART HAS_PARENT_PATH + IS_ABSOLUTE IS_RELATIVE CMAKE_PATH REMOVE_FILENAME REMOVE_EXTENSION + NORMAL_PATH) + check_path_syntax (${subcommand} unexpected-arg "-DPATH_ARGUMENTS=${subcommand},ARG1,ARG2") +endforeach() +foreach (subcommand IN ITEMS GET_EXTENSION GET_STEM REMOVE_EXTENSION) + if (subcommand STREQUAL "REMOVE_EXTENSION") + set(RunCMake-stderr-file "unexpected-arg2-stderr.txt") + endif() + check_path_syntax ("${subcommand}[LAST_ONLY]" unexpected-arg "-DPATH_ARGUMENTS=${subcommand},LAST_ONLY,ARG1,ARG2") + unset(RunCMake-stderr-file) +endforeach() +foreach (subcommand IN ITEMS CMAKE_PATH) + check_path_syntax ("${subcommand}[NORMALIZE]" unexpected-arg "-DPATH_ARGUMENTS=${subcommand},NORMALIZE,ARG1,ARG2") +endforeach() + +### sub-commands with two arguments +foreach (subcommand IN ITEMS IS_PREFIX REPLACE_FILENAME REPLACE_EXTENSION RELATIVE_PATH ABSOLUTE_PATH) + check_path_syntax (${subcommand} unexpected-arg "-DPATH_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3") +endforeach() +foreach (subcommand IN ITEMS IS_PREFIX ABSOLUTE_PATH) + check_path_syntax ("${subcommand}[NORMALIZE]" unexpected-arg "-DPATH_ARGUMENTS=${subcommand},NORMALIZE,ARG1,ARG2,ARG3") +endforeach() +foreach (subcommand IN ITEMS REPLACE_EXTENSION) + set(RunCMake-stderr-file "unexpected-arg2-stderr.txt") + check_path_syntax ("${subcommand}[LAST_ONLY]" unexpected-arg "-DPATH_ARGUMENTS=${subcommand},LAST_ONLY,ARG1,ARG2,ARG3") + unset(RunCMake-stderr-file) +endforeach() +unset (RunCMake-stderr-file) + + +function(check_path_execution name) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}") + run_cmake_with_options(generate -DPATH_TEST=${name}) + run_cmake_command(check "${CMAKE_COMMAND}" "-DRunCMake_SOURCE_DIR=${RunCMake_SOURCE_DIR}" -P "${RunCMake_TEST_BINARY_DIR}/${name}.cmake") +endfunction() + +check_path_execution (GET_ITEM) +check_path_execution (HAS_ITEM) +check_path_execution (CMAKE_PATH) +check_path_execution (APPEND) +check_path_execution (REMOVE_ITEM) +check_path_execution (REPLACE_ITEM) +check_path_execution (NORMAL_PATH) +check_path_execution (RELATIVE_PATH) +check_path_execution (ABSOLUTE_PATH) +check_path_execution (IS_RELATIVE) +check_path_execution (IS_ABSOLUTE) +check_path_execution (IS_PREFIX) diff --git a/Tests/RunCMake/GenEx-PATH/bad-option-result.txt b/Tests/RunCMake/GenEx-PATH/bad-option-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/bad-option-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-PATH/bad-option-stderr.txt b/Tests/RunCMake/GenEx-PATH/bad-option-stderr.txt new file mode 100644 index 0000000..0a9584d --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/bad-option-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at bad-option.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$<PATH:BAD_OPTION,ARG> + + BAD_OPTION: invalid option. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-PATH/bad-option.cmake b/Tests/RunCMake/GenEx-PATH/bad-option.cmake new file mode 100644 index 0000000..c9bfd4a --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/bad-option.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT result.txt CONTENT "$<PATH:BAD_OPTION,ARG>") diff --git a/Tests/RunCMake/GenEx-PATH/check_errors.cmake b/Tests/RunCMake/GenEx-PATH/check_errors.cmake new file mode 100644 index 0000000..7e60fc7 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/check_errors.cmake @@ -0,0 +1,13 @@ + +function (CHECK_ERRORS command) + set (errors ${ARGN}) + set (command "$<${command}>") + if (errors) + string (LENGTH "${command}" length) + math (EXPR count "${length} + 2") + string (REPEAT " " ${count} shift) + list (TRANSFORM errors PREPEND "${shift}") + list (JOIN errors "\n" msg) + message (FATAL_ERROR "${command}: ${msg}") + endif() +endfunction() diff --git a/Tests/RunCMake/GenEx-PATH/generate.cmake b/Tests/RunCMake/GenEx-PATH/generate.cmake new file mode 100644 index 0000000..4bd5f3b --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/generate.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT "${PATH_TEST}.cmake" INPUT "${PATH_TEST}.cmake.in") diff --git a/Tests/RunCMake/GenEx-PATH/no-arguments-result.txt b/Tests/RunCMake/GenEx-PATH/no-arguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/no-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-PATH/no-arguments-stderr.txt b/Tests/RunCMake/GenEx-PATH/no-arguments-stderr.txt new file mode 100644 index 0000000..d1e534f --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/no-arguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at no-arguments.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$<PATH:> + + \$<PATH> expression requires at least two parameters. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-PATH/no-arguments.cmake b/Tests/RunCMake/GenEx-PATH/no-arguments.cmake new file mode 100644 index 0000000..5164339 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/no-arguments.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT result.txt CONTENT "$<PATH:>") diff --git a/Tests/RunCMake/GenEx-PATH/unexpected-arg-result.txt b/Tests/RunCMake/GenEx-PATH/unexpected-arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/unexpected-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-PATH/unexpected-arg-stderr.txt b/Tests/RunCMake/GenEx-PATH/unexpected-arg-stderr.txt new file mode 100644 index 0000000..afc0026 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/unexpected-arg-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at unexpected-arg.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$<PATH:[A-Z_]+,.+> + + \$<PATH:[A-Z_]+(,[A-Z_]+)?> expression requires exactly (one|two) parameters?. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-PATH/unexpected-arg.cmake b/Tests/RunCMake/GenEx-PATH/unexpected-arg.cmake new file mode 100644 index 0000000..4625f04 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/unexpected-arg.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT result.txt CONTENT "$<PATH:${PATH_ARGUMENTS}>") diff --git a/Tests/RunCMake/GenEx-PATH/unexpected-arg2-stderr.txt b/Tests/RunCMake/GenEx-PATH/unexpected-arg2-stderr.txt new file mode 100644 index 0000000..a38a795 --- /dev/null +++ b/Tests/RunCMake/GenEx-PATH/unexpected-arg2-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at unexpected-arg.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$<PATH:[A-Z_]+,.+> + + \$<PATH:[A-Z_]+(,[A-Z_]+)?> expression requires exactly (one|two) + parameters?. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) |