From f11e66670ba9716f45cf757285a77b937dce420b Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Wed, 18 May 2022 11:15:10 +0200 Subject: Genex-PATH: path handling Fixes: #23498 --- Help/command/cmake_path.rst | 12 +- Help/manual/cmake-generator-expressions.7.rst | 212 ++++++++++ Help/release/dev/Genex-PATH.rst | 4 + Source/cmGeneratorExpressionNode.cxx | 436 +++++++++++++++++++++ Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/GenEx-PATH/ABSOLUTE_PATH.cmake.in | 34 ++ Tests/RunCMake/GenEx-PATH/APPEND.cmake.in | 68 ++++ Tests/RunCMake/GenEx-PATH/CMAKE_PATH.cmake.in | 53 +++ Tests/RunCMake/GenEx-PATH/CMakeLists.txt | 5 + Tests/RunCMake/GenEx-PATH/GET_ITEM.cmake.in | 311 +++++++++++++++ Tests/RunCMake/GenEx-PATH/HAS_ITEM.cmake.in | 199 ++++++++++ Tests/RunCMake/GenEx-PATH/IS_ABSOLUTE.cmake.in | 44 +++ Tests/RunCMake/GenEx-PATH/IS_PREFIX.cmake.in | 25 ++ Tests/RunCMake/GenEx-PATH/IS_RELATIVE.cmake.in | 45 +++ Tests/RunCMake/GenEx-PATH/NORMAL_PATH.cmake.in | 43 ++ Tests/RunCMake/GenEx-PATH/RELATIVE_PATH.cmake.in | 64 +++ Tests/RunCMake/GenEx-PATH/REMOVE_ITEM.cmake.in | 65 +++ Tests/RunCMake/GenEx-PATH/REPLACE_ITEM.cmake.in | 73 ++++ Tests/RunCMake/GenEx-PATH/RunCMakeTest.cmake | 68 ++++ Tests/RunCMake/GenEx-PATH/bad-option-result.txt | 1 + Tests/RunCMake/GenEx-PATH/bad-option-stderr.txt | 8 + Tests/RunCMake/GenEx-PATH/bad-option.cmake | 2 + Tests/RunCMake/GenEx-PATH/check_errors.cmake | 13 + Tests/RunCMake/GenEx-PATH/generate.cmake | 2 + Tests/RunCMake/GenEx-PATH/no-arguments-result.txt | 1 + Tests/RunCMake/GenEx-PATH/no-arguments-stderr.txt | 8 + Tests/RunCMake/GenEx-PATH/no-arguments.cmake | 2 + .../RunCMake/GenEx-PATH/unexpected-arg-result.txt | 1 + .../RunCMake/GenEx-PATH/unexpected-arg-stderr.txt | 8 + Tests/RunCMake/GenEx-PATH/unexpected-arg.cmake | 2 + .../RunCMake/GenEx-PATH/unexpected-arg2-stderr.txt | 9 + 31 files changed, 1818 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/Genex-PATH.rst create mode 100644 Tests/RunCMake/GenEx-PATH/ABSOLUTE_PATH.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/APPEND.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/CMAKE_PATH.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/CMakeLists.txt create mode 100644 Tests/RunCMake/GenEx-PATH/GET_ITEM.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/HAS_ITEM.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/IS_ABSOLUTE.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/IS_PREFIX.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/IS_RELATIVE.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/NORMAL_PATH.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/RELATIVE_PATH.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/REMOVE_ITEM.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/REPLACE_ITEM.cmake.in create mode 100644 Tests/RunCMake/GenEx-PATH/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/GenEx-PATH/bad-option-result.txt create mode 100644 Tests/RunCMake/GenEx-PATH/bad-option-stderr.txt create mode 100644 Tests/RunCMake/GenEx-PATH/bad-option.cmake create mode 100644 Tests/RunCMake/GenEx-PATH/check_errors.cmake create mode 100644 Tests/RunCMake/GenEx-PATH/generate.cmake create mode 100644 Tests/RunCMake/GenEx-PATH/no-arguments-result.txt create mode 100644 Tests/RunCMake/GenEx-PATH/no-arguments-stderr.txt create mode 100644 Tests/RunCMake/GenEx-PATH/no-arguments.cmake create mode 100644 Tests/RunCMake/GenEx-PATH/unexpected-arg-result.txt create mode 100644 Tests/RunCMake/GenEx-PATH/unexpected-arg-stderr.txt create mode 100644 Tests/RunCMake/GenEx-PATH/unexpected-arg.cmake create mode 100644 Tests/RunCMake/GenEx-PATH/unexpected-arg2-stderr.txt 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 -` before the conversion. +` 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 ``$`` generator expression offers the same capabilities as the +:command:`cmake_path` command, for the :ref:`Query ` options. + +For all ``$`` generator expressions, paths are expected in cmake-style +format. The :ref:`$\ ` generator +expression can be used to convert a native path to a cmake-style one. + +The ``$`` generator expression can also be used for path +:ref:`Decomposition ` and +:ref:`Transformations `. + +.. genex:: $ + + .. 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. + + :: + + $ + $ + $ + $ + $ + $ + $ + $ + + 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 `. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``1`` if the path is :ref:`absolute `, ``0`` otherwise. + +.. genex:: $ + + .. versionadded:: 3.24 + + This will return the opposite of ``IS_ABSOLUTE``. + +.. genex:: $ + + .. 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 ` before the check. + Variable Queries ---------------- @@ -668,6 +733,153 @@ String Transformations echo $> ) +.. _GenEx Path Decomposition: + +Path Decomposition +------------------ + +The ``$`` generator expression offers the same capabilities as the +:command:`cmake_path` command, for the +:ref:`Decomposition ` options. + +For all ``$`` generator expressions, paths are expected in cmake-style +format. The :ref:`$\ ` generator +expression can be used to convert a native path to a cmake-style one. + +The ``$`` generator expression can also be used for path +:ref:`Queries ` and +:ref:`Transformations `. + +.. genex:: $ + + .. 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. + + :: + + $ + $ + $ + $ + $ + $ + $ + $ + + If a requested component is not present in the path, an empty string is + returned. + +.. _GenEx Path Transformations: + +Path Transformations +-------------------- + +The ``$`` generator expression offers the same capabilities as the +:command:`cmake_path` command, for the +:ref:`Modification ` and +:ref:`Generation ` options. + +For all ``$`` generator expressions, paths are expected in cmake-style +format. The :ref:`$\ ` generator +expression can be used to convert a native path to a cmake-style one. + +The ``$`` generator expression can also be used for path +:ref:`Queries ` and +:ref:`Decomposition `. + +.. _GenEx PATH-CMAKE_PATH: + +.. genex:: $ + + .. 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 + ` after the conversion. + +.. genex:: $ + + .. 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) ` for more details. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``path`` with filename component (as returned by + ``$``) removed. After removal, any trailing + ``directory-separator`` is left alone, if present. + + See :ref:`cmake_path(REMOVE_FILENAME) ` for more details. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``path`` with the filename component replaced by ``input``. If + ``path`` has no filename component (i.e. ``$`` returns + ``0``), ``path`` is unchanged. + + See :ref:`cmake_path(REPLACE_FILENAME) ` for more details. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``path`` with the :ref:`extension ` removed, if any. + + See :ref:`cmake_path(REMOVE_EXTENSION) ` for more details. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``path`` with the :ref:`extension ` replaced by + ``input``, if any. + + See :ref:`cmake_path(REPLACE_EXTENSION) ` for more details. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``path`` normalized according to the steps described in + :ref:`Normalization`. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``path``, modified to make it relative to the ``base_directory`` + argument. + + See :ref:`cmake_path(RELATIVE_PATH) ` for more + details. + +.. genex:: $ + + .. versionadded:: 3.24 + + Returns ``path`` as absolute. If ``path`` is a relative path + (``$`` 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 ` after the path computation. + + See :ref:`cmake_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 #include #include +#include #include #include #include #include +#include #include #include @@ -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 +class Range : public cmRange +{ +private: + using Base = cmRange; + +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>; + +bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + cm::string_view option, std::size_t count, + int required = 1, bool exactly = true) +{ + if (static_cast(count) < required || + (exactly && static_cast(count) > required)) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("$ 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& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + static std::unordered_map< + cm::string_view, + std::function> + 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 "$") +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 "$") +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 "$") +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 "$") +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 "$") +if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") +endif() + +set (path "a") +cmake_path (APPEND path "") +set(output "$") +if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") +endif() + +cmake_path (APPEND path "/b") +set(output "$") +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 "$") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "a") + cmake_path (APPEND path "c:") + set(output "$") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "c:a") + cmake_path (APPEND path "/b") + set(output "$") + 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 "$") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "//host") + cmake_path (APPEND path "b") + set(output "$") + if (NOT output STREQUAL path) + list (APPEND errors "'${output}' instead of '${path}'") + endif() + + set (path "//host/") + cmake_path (APPEND path "b") + set(output "$") + 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 "$") +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 "$") +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 "$") + 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 "$") + 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 "$") + 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 "$") + 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 "$") + 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 "$") + 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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +else() + set (output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_NAME returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_DIRECTORY reference) +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_PATH returns bad data: ${output}") +endif() + +cmake_path(GET path FILENAME reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() + +cmake_path(GET path RELATIVE_PART reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "RELATIVE_PART returns bad data: ${output}") +endif() + +cmake_path(GET path PARENT_PATH reference) +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_NAME returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_DIRECTORY reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_DIRECTORY returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_PATH reference) +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_NAME returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_DIRECTORY reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_DIRECTORY returns bad data: ${output}") +endif() + +cmake_path(GET path ROOT_PATH reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "ROOT_PATH returns bad data: ${output}") +endif() + +cmake_path(GET path FILENAME reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "STEM returns bad data: ${output}") +endif() + +cmake_path(GET path RELATIVE_PART reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "RELATIVE_PART returns bad data: ${output}") +endif() + +cmake_path(GET path PARENT_PATH reference) +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() +cmake_path(GET path EXTENSION LAST_ONLY reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME returns bad data: ${output}") +endif() + +cmake_path(GET path EXTENSION reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() +cmake_path(GET path EXTENSION LAST_ONLY reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION returns bad data: ${output}") +endif() + +cmake_path(GET path STEM reference) +set(output "$") +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 "$") +if (output) + list (APPEND errors "ROOT_NAME: '/a/b' has root name") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "ROOT_DIRECTORY: '/a/b' does not have root directory") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "ROOT_PATH: '/a/b' does not have root path") +endif() + +set(output "$") +if (output) + list (APPEND errors "ROOT_PATH: 'a/b' has root path") +endif() + +set(output "$") +if (NOT output) + list (APPEND errors "FILENAME: '/a/b' does not have filename") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "FILENAME: 'a.b' does not have filename") +endif() +set(output "$") +if (output) + list (APPEND errors "FILENAME: '/a/b/' has filename") +endif() +set(output "$") +if (output) + list (APPEND errors "FILENAME: '/' has filename") +endif() + +set(output "$") +if (NOT output) + list (APPEND errors "STEM: '/a/b' does not have stem") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "STEM: 'a.b' does not have stem") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "STEM: '.a'} does not have stem") +endif() +set(output "$") +if (output) + list (APPEND errors "STEM: '/a/' has stem") +endif() +set(output "$") +if (output) + list (APPEND errors "STEM: '/' has stem") +endif() + +set(output "$") +if (NOT output) + list (APPEND errors "EXTENSION: '/a/b.c' does not have extension") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "EXTENSION: 'b.c' does not have extension") +endif() +set(output "$") +if (output) + list (APPEND errors "EXTENSION: '/.a' has extension") +endif() +set(output "$") +if (output) + list (APPEND errors "EXTENSION: '/a/' has extension") +endif() +set(output "$") +if (output) + list (APPEND errors "EXTENSION: '/' has extension") +endif() + +set(output "$") +if (NOT output) + list (APPEND errors "RELATIVE_PART: '/a/b' does not have relative part") +endif() +set(output "$") +if (output) + list (APPEND errors "RELATIVE_PART: '/' has relative part") +endif() + +set(output "$") +if (NOT output) + list (APPEND errors "PARENT_PATH: '/a/b' does not have parent path") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "PARENT_PATH: '/' does not have parent path") +endif() +set(output "$") +if (output) + list (APPEND errors "PARENT_PATH: 'a' has parent path") +endif() + +if (WIN32) + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_NAME: 'c:/a/b' does not have root name") + endif() + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_DIRECTORY: 'c:/a/b' does not have root directory") + endif() + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_PATH: 'c:/a/b' does not have root path") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_NAME: 'c:a/b' does not have root name") + endif() + set(output "$") + if (output) + list (APPEND errors "ROOT_DIRECTORY: 'c:a/b' has root directory") + endif() + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_PATH: 'c:a/b' does not have root path") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_NAME: '//host/b' does not have root name") + endif() + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_DIRECTORY: '//host/b' does not have root directory") + endif() + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_PATH: '//host/b' does not have root path") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_NAME: '//host' does not have root name") + endif() + set(output "$") + if (output) + list (APPEND errors "ROOT_DIRECTORY: '//host' has root directory") + endif() + set(output "$") + if (NOT output) + list (APPEND errors "ROOT_PATH: '//host' does not have root path") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "RELATIVE_PART: 'c:/a/b' does not have relative part") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "RELATIVE_PART: 'c:a/b' does not have relative part") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "RELATIVE_PART: '//host/b' does not have relative part") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "PARENT_PATH: 'c:/a/b' does not have parent path") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "PARENT_PATH: 'c:/' does not have parent path") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "PARENT_PATH: 'c:' does not have parent path") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "PARENT_PATH: '//host/' does not have parent path") + endif() + + set(output "$") + 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 "$") +else() + set(path "/a") + set(output "$") +endif() +if (NOT output) + list (APPEND errors "'${path}' is not absolute") +endif() + +set(output "$") +if (output) + list (APPEND errors "'a/b' is absolute") +endif() + +if (WIN32) + set(output "$") + if (NOT output) + list (APPEND errors "'c:/a/b' is not absolute") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "'//host/b' is not absolute") + endif() + + set(output "$") + if (output) + list (APPEND errors "'/a' is absolute") + endif() + + set(output "$") + 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 "$") +if (NOT output) + list (APPEND errors "'a///b/c' is not prefix of 'a/b/c/d'") +endif() + +set(output "$") +if (output) + list (APPEND errors "'a///b/c/../d' is prefix of 'a/b/d/e'") +endif() +set(output "$") +if (NOT output) + list (APPEND errors "'a///b/c/../d' is not prefix of 'a/b/d/e'") +endif() + +set(output "$") +else() + set(path "/a") + set(output "$") +endif() +if (output) + list (APPEND errors "'${path} is relative") +endif() + +set(output "$") +if (NOT output) + list (APPEND errors "'a/b' is not relative") +endif() + +if (WIN32) + set(output "$") + if (output) + list (APPEND errors "'c:/a/b' is relative") + endif() + + set(output "$") + if (output) + list (APPEND errors "'//host/b' is relative") + endif() + + set(output "$") + if (NOT output) + list (APPEND errors "'/a' is not relative") + endif() + + set(output "$") + 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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") +endif() + +set (reference "a/.///b/../") +cmake_path(NORMAL_PATH reference) +set(output "$") +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 "$") + if (NOT output STREQUAL reference) + list (APPEND errors "'${output}' instead of '${reference}'") + endif() + + set (reference "//host/./b/../") + cmake_path(NORMAL_PATH reference) + set(output "$") + 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 "$") + 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 "$") +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 "$") +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 "$") +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 "$") +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 "$") +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 "$") +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 "$") +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 "$") + 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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "FILENAME: '${output}' instead of '${reference}'") +endif() + +cmake_path (REMOVE_FILENAME reference) +set(output "$") +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 "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REMOVE_EXTENSION reference) +set(output "$") +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 "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REMOVE_EXTENSION reference LAST_ONLY) +set(output "$") +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 "$") +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 "$") +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 "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference ".y") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference "") +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference ".y" LAST_ONLY) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference "" LAST_ONLY) +set(output "$") +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 "$") +if (NOT output STREQUAL reference) + list (APPEND errors "EXTENSION: '${output}' instead of '/${reference}'") +endif() +cmake_path (REPLACE_EXTENSION reference ".x" LAST_ONLY) +set(output "$") +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 "$") +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: + + \$ + + 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 "$") 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: + + \$ + + \$ 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 "$") 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: + + \$ + + \$ 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 "$") 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: + + \$ + + \$ expression requires exactly (one|two) + parameters?. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) -- cgit v0.12