mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-04 05:10:10 -05:00
Merge topic 'cmake_path'
eb583b0a66cmake_path command: path management212e953d35cmCMakePath: Class for path handling Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Ben Boeckel <ben.boeckel@kitware.com> Acked-by: Raul Tambre <raul@tambre.ee> Merge-request: !5158
This commit is contained in:
@@ -182,6 +182,8 @@ set(SRCS
|
||||
cmCheckCustomOutputs.cxx
|
||||
cmCLocaleEnvironmentScope.h
|
||||
cmCLocaleEnvironmentScope.cxx
|
||||
cmCMakePath.h
|
||||
cmCMakePath.cxx
|
||||
cmCommandArgumentParserHelper.cxx
|
||||
cmCommonTargetGenerator.cxx
|
||||
cmCommonTargetGenerator.h
|
||||
@@ -498,6 +500,8 @@ set(SRCS
|
||||
cmCMakeLanguageCommand.h
|
||||
cmCMakeMinimumRequired.cxx
|
||||
cmCMakeMinimumRequired.h
|
||||
cmCMakePathCommand.h
|
||||
cmCMakePathCommand.cxx
|
||||
cmCMakePolicyCommand.cxx
|
||||
cmCMakePolicyCommand.h
|
||||
cmConditionEvaluator.cxx
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
|
||||
|
||||
function(cm_check_cxx_feature name)
|
||||
set(TRY_RUN_FEATURE "${ARGN}")
|
||||
string(TOUPPER ${name} FEATURE)
|
||||
if(NOT DEFINED CMake_HAVE_CXX_${FEATURE})
|
||||
cm_message_checks_compat(
|
||||
@@ -12,12 +13,26 @@ function(cm_check_cxx_feature name)
|
||||
else()
|
||||
set(maybe_cxx_standard "")
|
||||
endif()
|
||||
try_compile(CMake_HAVE_CXX_${FEATURE}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/cm_cxx_${name}.cxx
|
||||
CMAKE_FLAGS ${maybe_cxx_standard}
|
||||
OUTPUT_VARIABLE OUTPUT
|
||||
)
|
||||
if (TRY_RUN_FEATURE)
|
||||
try_run(CMake_RUN_CXX_${FEATURE} CMake_COMPILE_CXX_${FEATURE}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/cm_cxx_${name}.cxx
|
||||
CMAKE_FLAGS ${maybe_cxx_standard}
|
||||
OUTPUT_VARIABLE OUTPUT
|
||||
)
|
||||
if (CMake_RUN_CXX_${FEATURE} EQUAL "0" AND CMake_COMPILE_CXX_${FEATURE})
|
||||
set(CMake_HAVE_CXX_${FEATURE} ON CACHE INTERNAL "TRY_RUN" FORCE)
|
||||
else()
|
||||
set(CMake_HAVE_CXX_${FEATURE} OFF CACHE INTERNAL "TRY_RUN" FORCE)
|
||||
endif()
|
||||
else()
|
||||
try_compile(CMake_HAVE_CXX_${FEATURE}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/cm_cxx_${name}.cxx
|
||||
CMAKE_FLAGS ${maybe_cxx_standard}
|
||||
OUTPUT_VARIABLE OUTPUT
|
||||
)
|
||||
endif()
|
||||
set(check_output "${OUTPUT}")
|
||||
# Filter out MSBuild output that looks like a warning.
|
||||
string(REGEX REPLACE " +0 Warning\\(s\\)" "" check_output "${check_output}")
|
||||
@@ -64,7 +79,7 @@ if(CMake_HAVE_CXX_MAKE_UNIQUE)
|
||||
endif()
|
||||
cm_check_cxx_feature(unique_ptr)
|
||||
if (NOT CMAKE_CXX_STANDARD LESS "17")
|
||||
cm_check_cxx_feature(filesystem)
|
||||
cm_check_cxx_feature(filesystem TRY_RUN)
|
||||
else()
|
||||
set(CMake_HAVE_CXX_FILESYSTEM FALSE)
|
||||
endif()
|
||||
|
||||
@@ -3,8 +3,25 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
std::filesystem::path p0(L"/a/b/c");
|
||||
|
||||
std::filesystem::path p1("/a/b/c");
|
||||
std::filesystem::path p2("/a/b/c");
|
||||
if (p1 != p2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return p1 == p2 ? 0 : 1;
|
||||
#if defined(_WIN32)
|
||||
std::filesystem::path p3("//host/a/b/../c");
|
||||
if (p3.lexically_normal().generic_string() != "//host/a/c") {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::filesystem::path p4("c://a/.///b/../");
|
||||
if (p4.lexically_normal().generic_string() != "c:/a/") {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include "cmCMakePath.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include <cm/filesystem>
|
||||
#include <cm/string_view>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include "cmStringAlgorithms.h"
|
||||
#endif
|
||||
|
||||
cmCMakePath& cmCMakePath::ReplaceWideExtension(cm::string_view extension)
|
||||
{
|
||||
auto file = this->Path.filename().string();
|
||||
if (!file.empty() && file != "." && file != "..") {
|
||||
auto pos = file.find('.', file[0] == '.' ? 1 : 0);
|
||||
if (pos != std::string::npos) {
|
||||
file.erase(pos);
|
||||
}
|
||||
}
|
||||
if (!extension.empty()) {
|
||||
if (extension[0] != '.') {
|
||||
file += '.';
|
||||
}
|
||||
file.append(std::string(extension));
|
||||
}
|
||||
this->Path.replace_filename(file);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmCMakePath cmCMakePath::GetWideExtension() const
|
||||
{
|
||||
auto file = this->Path.filename().string();
|
||||
if (file.empty() || file == "." || file == "..") {
|
||||
return cmCMakePath{};
|
||||
}
|
||||
|
||||
auto pos = file.find('.', file[0] == '.' ? 1 : 0);
|
||||
if (pos != std::string::npos) {
|
||||
return cm::string_view(file.data() + pos, file.length() - pos);
|
||||
}
|
||||
|
||||
return cmCMakePath{};
|
||||
}
|
||||
|
||||
cmCMakePath cmCMakePath::GetNarrowStem() const
|
||||
{
|
||||
auto stem = this->Path.stem().string();
|
||||
if (!stem.empty()) {
|
||||
auto pos = stem.find('.', stem[0] == '.' ? 1 : 0);
|
||||
if (pos != std::string::npos) {
|
||||
return stem.substr(0, pos);
|
||||
}
|
||||
}
|
||||
return stem;
|
||||
}
|
||||
|
||||
cmCMakePath cmCMakePath::Absolute(const cm::filesystem::path& base) const
|
||||
{
|
||||
if (this->Path.is_relative()) {
|
||||
auto path = base;
|
||||
path /= this->Path;
|
||||
// filesystem::path::operator/= use preferred_separator ('\' on Windows)
|
||||
// so converts back to '/'
|
||||
return path.generic_string();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool cmCMakePath::IsPrefix(const cmCMakePath& path) const
|
||||
{
|
||||
auto prefix_it = this->Path.begin();
|
||||
auto prefix_end = this->Path.end();
|
||||
auto path_it = path.Path.begin();
|
||||
auto path_end = path.Path.end();
|
||||
|
||||
while (prefix_it != prefix_end && path_it != path_end &&
|
||||
*prefix_it == *path_it) {
|
||||
++prefix_it;
|
||||
++path_it;
|
||||
}
|
||||
return prefix_it == prefix_end;
|
||||
}
|
||||
|
||||
std::string cmCMakePath::FormatPath(std::string path, format fmt)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (fmt == auto_format || fmt == native_format) {
|
||||
auto prefix = path.substr(0, 4);
|
||||
for (auto& c : prefix) {
|
||||
if (c == '\\') {
|
||||
c = '/';
|
||||
}
|
||||
}
|
||||
// remove Windows long filename marker
|
||||
if (prefix == "//?/"_s) {
|
||||
path.erase(0, 4);
|
||||
}
|
||||
if (cmHasPrefix(path, "UNC/"_s) || cmHasPrefix(path, "UNC\\"_s)) {
|
||||
path.erase(0, 2);
|
||||
path[0] = '/';
|
||||
}
|
||||
}
|
||||
#else
|
||||
static_cast<void>(fmt);
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
|
||||
void cmCMakePath::GetNativePath(std::string& path) const
|
||||
{
|
||||
cm::filesystem::path tmp(this->Path);
|
||||
tmp.make_preferred();
|
||||
|
||||
path = tmp.string();
|
||||
}
|
||||
void cmCMakePath::GetNativePath(std::wstring& path) const
|
||||
{
|
||||
cm::filesystem::path tmp(this->Path);
|
||||
tmp.make_preferred();
|
||||
|
||||
path = tmp.wstring();
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Windows long filename
|
||||
static std::wstring UNC(L"\\\\?\\UNC");
|
||||
static std::wstring PREFIX(L"\\\\?\\");
|
||||
|
||||
if (this->IsAbsolute() && path.length() > _MAX_PATH - 12) {
|
||||
if (this->HasRootName() && path[0] == L'\\') {
|
||||
path = UNC + path.substr(1);
|
||||
} else {
|
||||
path = PREFIX + path;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,571 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <cm/filesystem>
|
||||
#include <cm/string_view>
|
||||
#include <cm/type_traits>
|
||||
#include <cmext/string_view>
|
||||
|
||||
namespace detail {
|
||||
#if defined(__SUNPRO_CC) && defined(__sparc)
|
||||
// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
|
||||
// the full 'is_pathable' and 'is_move_pathable' checks. We use it only to
|
||||
// improve error messages via 'enable_if' when calling methods with incorrect
|
||||
// types. Just pretend all types are allowed so we can at least compile valid
|
||||
// code.
|
||||
template <typename T>
|
||||
struct is_pathable : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_move_pathable : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
#else
|
||||
template <typename T, typename = void>
|
||||
struct is_pathable : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_pathable<cm::filesystem::path> : std::true_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_pathable<std::string> : std::true_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_pathable<cm::string_view> : std::true_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_pathable<cm::static_string_view> : std::true_type
|
||||
{
|
||||
};
|
||||
template <typename T>
|
||||
struct is_pathable<
|
||||
T,
|
||||
cm::enable_if_t<std::is_same<char*, typename std::decay<T>::type>::value,
|
||||
void>>
|
||||
: cm::bool_constant<std::is_same<char*, typename std::decay<T>::type>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_move_pathable : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_move_pathable<cm::filesystem::path> : std::true_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_move_pathable<std::string> : std::true_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
class cmCMakePath
|
||||
{
|
||||
private:
|
||||
template <typename Source>
|
||||
using enable_if_move_pathable =
|
||||
cm::enable_if_t<detail::is_move_pathable<Source>::value, cmCMakePath&>;
|
||||
|
||||
template <typename Source>
|
||||
using enable_if_pathable =
|
||||
cm::enable_if_t<detail::is_pathable<Source>::value, cmCMakePath&>;
|
||||
|
||||
public:
|
||||
using value_type = cm::filesystem::path::value_type;
|
||||
using string_type = cm::filesystem::path::string_type;
|
||||
|
||||
enum format : unsigned char
|
||||
{
|
||||
auto_format =
|
||||
static_cast<unsigned char>(cm::filesystem::path::format::auto_format),
|
||||
native_format =
|
||||
static_cast<unsigned char>(cm::filesystem::path::format::native_format),
|
||||
generic_format =
|
||||
static_cast<unsigned char>(cm::filesystem::path::format::generic_format)
|
||||
};
|
||||
|
||||
class iterator;
|
||||
using const_iterator = iterator;
|
||||
|
||||
cmCMakePath() noexcept = default;
|
||||
|
||||
cmCMakePath(const cmCMakePath&) = default;
|
||||
|
||||
cmCMakePath(cmCMakePath&& path) noexcept
|
||||
: Path(std::forward<cm::filesystem::path>(path.Path))
|
||||
{
|
||||
}
|
||||
|
||||
cmCMakePath(cm::filesystem::path path) noexcept
|
||||
: Path(std::move(path))
|
||||
{
|
||||
}
|
||||
cmCMakePath(cm::string_view source, format fmt = generic_format) noexcept
|
||||
: Path(FormatPath(source, fmt))
|
||||
{
|
||||
}
|
||||
template <typename Source, typename = enable_if_move_pathable<Source>>
|
||||
cmCMakePath(Source source, format fmt = generic_format)
|
||||
: Path(FormatPath(std::move(source), fmt))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Source, typename = enable_if_move_pathable<Source>>
|
||||
cmCMakePath& Assign(Source&& source)
|
||||
{
|
||||
this->Path = std::forward<Source>(source);
|
||||
return *this;
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& Assign(const Source& source)
|
||||
{
|
||||
this->Path = source;
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmCMakePath& operator=(const cmCMakePath& path)
|
||||
{
|
||||
if (this != &path) {
|
||||
this->Path = path.Path;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
cmCMakePath& operator=(cmCMakePath&& path) noexcept
|
||||
{
|
||||
if (this != &path) {
|
||||
this->Path = std::move(path.Path);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename Source, typename = enable_if_move_pathable<Source>>
|
||||
cmCMakePath& operator=(Source&& source)
|
||||
{
|
||||
this->Assign(std::forward<Source>(source));
|
||||
return *this;
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& operator=(const Source& source)
|
||||
{
|
||||
this->Assign(source);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Concatenation
|
||||
cmCMakePath& Append(const cmCMakePath& path)
|
||||
{
|
||||
return this->Append(path.Path);
|
||||
}
|
||||
cmCMakePath& Append(const cm::filesystem::path& path)
|
||||
{
|
||||
this->Path /= path;
|
||||
// filesystem::path::append use preferred_separator ('\' on Windows)
|
||||
// so convert back to '/'
|
||||
this->Path = this->Path.generic_string();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& Append(const Source& source)
|
||||
{
|
||||
return this->Append(cm::filesystem::path(source));
|
||||
}
|
||||
|
||||
cmCMakePath& operator/=(const cmCMakePath& path)
|
||||
{
|
||||
return this->Append(path);
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& operator/=(const Source& source)
|
||||
{
|
||||
return this->Append(source);
|
||||
}
|
||||
|
||||
cmCMakePath& Concat(const cmCMakePath& path)
|
||||
{
|
||||
this->Path += path.Path;
|
||||
return *this;
|
||||
}
|
||||
cmCMakePath& Concat(cm::static_string_view source)
|
||||
{
|
||||
this->Path.concat(std::string(source));
|
||||
return *this;
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& Concat(const Source& source)
|
||||
{
|
||||
this->Path.concat(source);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmCMakePath& operator+=(const cmCMakePath& path)
|
||||
{
|
||||
return this->Concat(path);
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& operator+=(const Source& source)
|
||||
{
|
||||
return this->Concat(source);
|
||||
}
|
||||
|
||||
// Manipulation
|
||||
void Clear() noexcept { this->Path.clear(); }
|
||||
|
||||
cmCMakePath& RemoveFileName()
|
||||
{
|
||||
this->Path.remove_filename();
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmCMakePath& ReplaceFileName(const cmCMakePath& filename)
|
||||
{
|
||||
if (this->Path.has_filename()) {
|
||||
this->Path.replace_filename(filename.Path);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& ReplaceFileName(const Source& filename)
|
||||
{
|
||||
if (this->Path.has_filename()) {
|
||||
this->Path.replace_filename(filename);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmCMakePath& ReplaceExtension(const cmCMakePath& extension = cmCMakePath())
|
||||
{
|
||||
this->Path.replace_extension(extension.Path);
|
||||
return *this;
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& ReplaceExtension(const Source& extension)
|
||||
{
|
||||
this->Path.replace_extension(extension);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmCMakePath& ReplaceWideExtension(
|
||||
const cmCMakePath& extension = cmCMakePath())
|
||||
{
|
||||
return this->ReplaceWideExtension(
|
||||
static_cast<cm::string_view>(extension.Path.string()));
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath& ReplaceWideExtension(const Source& extension)
|
||||
{
|
||||
return this->ReplaceWideExtension(cm::string_view(extension));
|
||||
}
|
||||
cmCMakePath& ReplaceWideExtension(cm::string_view extension);
|
||||
|
||||
cmCMakePath& RemoveExtension()
|
||||
{
|
||||
if (this->Path.has_extension()) {
|
||||
this->ReplaceExtension(cm::string_view(""));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
cmCMakePath& RemoveWideExtension()
|
||||
{
|
||||
if (this->Path.has_extension()) {
|
||||
this->ReplaceWideExtension(cm::string_view(""));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(cmCMakePath& other) noexcept { this->Path.swap(other.Path); }
|
||||
|
||||
// Observers
|
||||
std::string String() const { return this->Path.string(); }
|
||||
std::wstring WString() const { return this->Path.wstring(); }
|
||||
|
||||
string_type Native() const
|
||||
{
|
||||
string_type path;
|
||||
this->GetNativePath(path);
|
||||
|
||||
return path;
|
||||
}
|
||||
std::string NativeString() const
|
||||
{
|
||||
std::string path;
|
||||
this->GetNativePath(path);
|
||||
|
||||
return path;
|
||||
}
|
||||
std::wstring NativeWString() const
|
||||
{
|
||||
std::wstring path;
|
||||
this->GetNativePath(path);
|
||||
|
||||
return path;
|
||||
}
|
||||
std::string GenericString() const { return this->Path.generic_string(); }
|
||||
std::wstring GenericWString() const { return this->Path.generic_wstring(); }
|
||||
|
||||
// Decomposition
|
||||
cmCMakePath GetRootName() const { return this->Path.root_name(); }
|
||||
cmCMakePath GetRootDirectory() const { return this->Path.root_directory(); }
|
||||
cmCMakePath GetRootPath() const { return this->Path.root_path(); }
|
||||
cmCMakePath GetFileName() const { return this->Path.filename(); }
|
||||
cmCMakePath GetExtension() const { return this->Path.extension(); }
|
||||
cmCMakePath GetWideExtension() const;
|
||||
cmCMakePath GetStem() const { return this->Path.stem(); }
|
||||
cmCMakePath GetNarrowStem() const;
|
||||
|
||||
cmCMakePath GetRelativePath() const { return this->Path.relative_path(); }
|
||||
cmCMakePath GetParentPath() const { return this->Path.parent_path(); }
|
||||
|
||||
// Generation
|
||||
cmCMakePath Normal() const
|
||||
{
|
||||
auto path = this->Path.lexically_normal();
|
||||
// filesystem::path:lexically_normal use preferred_separator ('\') on
|
||||
// Windows) so convert back to '/'
|
||||
return path.generic_string();
|
||||
}
|
||||
|
||||
cmCMakePath Relative(const cmCMakePath& base) const
|
||||
{
|
||||
return this->Relative(base.Path);
|
||||
}
|
||||
cmCMakePath Relative(const cm::filesystem::path& base) const
|
||||
{
|
||||
auto path = this->Path.lexically_relative(base);
|
||||
// filesystem::path:lexically_relative use preferred_separator ('\') on
|
||||
// Windows) so convert back to '/'
|
||||
return path.generic_string();
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath Relative(const Source& base) const
|
||||
{
|
||||
return this->Relative(cm::filesystem::path(base));
|
||||
}
|
||||
|
||||
cmCMakePath Proximate(const cmCMakePath& base) const
|
||||
{
|
||||
return this->Proximate(base.Path);
|
||||
}
|
||||
cmCMakePath Proximate(const cm::filesystem::path& base) const
|
||||
{
|
||||
auto path = this->Path.lexically_proximate(base);
|
||||
// filesystem::path::lexically_proximate use preferred_separator ('\') on
|
||||
// Windows) so convert back to '/'
|
||||
return path.generic_string();
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath Proximate(const Source& base) const
|
||||
{
|
||||
return this->Proximate(cm::filesystem::path(base));
|
||||
}
|
||||
|
||||
cmCMakePath Absolute(const cmCMakePath& base) const
|
||||
{
|
||||
return this->Absolute(base.Path);
|
||||
}
|
||||
template <typename Source, typename = enable_if_pathable<Source>>
|
||||
cmCMakePath Absolute(const Source& base) const
|
||||
{
|
||||
return this->Absolute(cm::filesystem::path(base));
|
||||
}
|
||||
cmCMakePath Absolute(const cm::filesystem::path& base) const;
|
||||
|
||||
// Comparison
|
||||
int Compare(const cmCMakePath& path) const noexcept
|
||||
{
|
||||
return this->Path.compare(path.Path);
|
||||
}
|
||||
|
||||
// Query
|
||||
bool IsEmpty() const noexcept { return this->Path.empty(); }
|
||||
|
||||
bool HasRootPath() const { return this->Path.has_root_path(); }
|
||||
bool HasRootName() const { return this->Path.has_root_name(); }
|
||||
bool HasRootDirectory() const { return this->Path.has_root_directory(); }
|
||||
bool HasRelativePath() const { return this->Path.has_relative_path(); }
|
||||
bool HasParentPath() const { return this->Path.has_parent_path(); }
|
||||
bool HasFileName() const { return this->Path.has_filename(); }
|
||||
bool HasStem() const { return this->Path.has_stem(); }
|
||||
bool HasExtension() const { return this->Path.has_extension(); }
|
||||
|
||||
bool IsAbsolute() const { return this->Path.is_absolute(); }
|
||||
bool IsRelative() const { return this->Path.is_relative(); }
|
||||
bool IsPrefix(const cmCMakePath& path) const;
|
||||
|
||||
// Iterators
|
||||
// =========
|
||||
inline iterator begin() const;
|
||||
inline iterator end() const;
|
||||
|
||||
// Non-members
|
||||
// ===========
|
||||
friend inline bool operator==(const cmCMakePath& lhs,
|
||||
const cmCMakePath& rhs) noexcept
|
||||
{
|
||||
return lhs.Compare(rhs) == 0;
|
||||
}
|
||||
friend inline bool operator!=(const cmCMakePath& lhs,
|
||||
const cmCMakePath& rhs) noexcept
|
||||
{
|
||||
return lhs.Compare(rhs) != 0;
|
||||
}
|
||||
|
||||
friend inline cmCMakePath operator/(const cmCMakePath& lhs,
|
||||
const cmCMakePath& rhs)
|
||||
{
|
||||
cmCMakePath result(lhs);
|
||||
result /= rhs;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
friend std::size_t hash_value(const cmCMakePath& path) noexcept;
|
||||
|
||||
static std::string FormatPath(std::string path, format fmt = generic_format);
|
||||
static std::string FormatPath(cm::string_view path,
|
||||
format fmt = generic_format)
|
||||
{
|
||||
return FormatPath(std::string(path), fmt);
|
||||
}
|
||||
|
||||
void GetNativePath(std::string& path) const;
|
||||
void GetNativePath(std::wstring& path) const;
|
||||
|
||||
cm::filesystem::path Path;
|
||||
};
|
||||
|
||||
class cmCMakePath::iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = cm::filesystem::path::iterator::iterator_category;
|
||||
|
||||
using value_type = cmCMakePath;
|
||||
using difference_type = cm::filesystem::path::iterator::difference_type;
|
||||
using pointer = const cmCMakePath*;
|
||||
using reference = const cmCMakePath&;
|
||||
|
||||
iterator() = default;
|
||||
|
||||
iterator(const iterator& other)
|
||||
: Iterator(other.Iterator)
|
||||
, Path(other.Path)
|
||||
, PathElement(*this->Iterator)
|
||||
{
|
||||
}
|
||||
|
||||
~iterator() = default;
|
||||
|
||||
iterator& operator=(const iterator& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
this->Iterator = other.Iterator;
|
||||
this->Path = other.Path;
|
||||
this->PathElement = *this->Iterator;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator*() const { return this->PathElement; }
|
||||
|
||||
pointer operator->() const { return &this->PathElement; }
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
++this->Iterator;
|
||||
this->PathElement = *this->Iterator;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator it(*this);
|
||||
this->operator++();
|
||||
return it;
|
||||
}
|
||||
|
||||
iterator& operator--()
|
||||
{
|
||||
--this->Iterator;
|
||||
this->PathElement = *this->Iterator;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator--(int)
|
||||
{
|
||||
iterator it(*this);
|
||||
this->operator--();
|
||||
return it;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cmCMakePath;
|
||||
friend bool operator==(const iterator&, const iterator&);
|
||||
|
||||
iterator(const cmCMakePath* path, const cm::filesystem::path::iterator& it)
|
||||
: Iterator(it)
|
||||
, Path(path)
|
||||
, PathElement(*this->Iterator)
|
||||
{
|
||||
}
|
||||
|
||||
cm::filesystem::path::iterator Iterator;
|
||||
const cmCMakePath* Path = nullptr;
|
||||
cmCMakePath PathElement;
|
||||
};
|
||||
|
||||
inline cmCMakePath::iterator cmCMakePath::begin() const
|
||||
{
|
||||
return iterator(this, this->Path.begin());
|
||||
}
|
||||
inline cmCMakePath::iterator cmCMakePath::end() const
|
||||
{
|
||||
return iterator(this, this->Path.end());
|
||||
}
|
||||
|
||||
// Non-member functions
|
||||
// ====================
|
||||
inline bool operator==(const cmCMakePath::iterator& lhs,
|
||||
const cmCMakePath::iterator& rhs)
|
||||
{
|
||||
return lhs.Path == rhs.Path && lhs.Path != nullptr &&
|
||||
lhs.Iterator == rhs.Iterator;
|
||||
}
|
||||
|
||||
inline bool operator!=(const cmCMakePath::iterator& lhs,
|
||||
const cmCMakePath::iterator& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline void swap(cmCMakePath& lhs, cmCMakePath& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(const cmCMakePath& path) noexcept
|
||||
{
|
||||
return cm::filesystem::hash_value(path.Path);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class cmExecutionStatus;
|
||||
|
||||
bool cmCMakePathCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status);
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "cmBreakCommand.h"
|
||||
#include "cmBuildCommand.h"
|
||||
#include "cmCMakeMinimumRequired.h"
|
||||
#include "cmCMakePathCommand.h"
|
||||
#include "cmCMakePolicyCommand.h"
|
||||
#include "cmCommand.h"
|
||||
#include "cmConfigureFileCommand.h"
|
||||
@@ -120,6 +121,7 @@ void GetScriptingCommands(cmState* state)
|
||||
{
|
||||
state->AddBuiltinCommand("break", cmBreakCommand);
|
||||
state->AddBuiltinCommand("cmake_minimum_required", cmCMakeMinimumRequired);
|
||||
state->AddBuiltinCommand("cmake_path", cmCMakePathCommand);
|
||||
state->AddBuiltinCommand("cmake_policy", cmCMakePolicyCommand);
|
||||
state->AddBuiltinCommand("configure_file", cmConfigureFileCommand);
|
||||
state->AddBuiltinCommand("continue", cmContinueCommand);
|
||||
|
||||
Reference in New Issue
Block a user