namespace fs = util::filesystem;
+namespace {
+
+fs::path
+lexically_relative_case_aware(const fs::path& path, const fs::path& base)
+{
+#ifdef _WIN32
+ // Note: Case-folding might in theory lead to an incorrect path on Windows
+ // since not all filesystems are case-insensitive, but this is only done to
+ // produce a candidate path that will be verified by the caller later.
+ fs::path p = util::to_lowercase(path.string());
+ fs::path b = util::to_lowercase(base.string());
+ return p.lexically_relative(b);
+#else
+ return path.lexically_relative(base);
+#endif
+}
+
+} // namespace
+
namespace util {
fs::path
}
}
- relpath_candidates.push_back(closest_existing_path.lexically_relative(dir1));
+ relpath_candidates.push_back(
+ lexically_relative_case_aware(closest_existing_path, dir1));
if (dir2 != dir1) {
- relpath_candidates.emplace_back(
- closest_existing_path.lexically_relative(dir2));
+ relpath_candidates.push_back(
+ lexically_relative_case_aware(closest_existing_path, dir2));
}
// Find best (i.e. shortest existing) match:
}
}
+#ifdef _WIN32
+// The test uses absolute paths and will typically fail on macOS since
+// /Users/... will then be treated as -U/... and not an input file, so just run
+// it on Windows.
TEST_CASE("MSVC /Yc in response file disables base_dir rewriting")
{
TestContext test_context;
CHECK(result->preprocessor_args.to_string()
== FMT("cl.exe /Yc -Fp{} -FI{}", pch_path, include_path));
}
+#endif
TEST_CASE("MSVC /Yc with base_dir preserves later argument errors")
{
#include <ccache/util/filesystem.hpp>
#include <ccache/util/format.hpp>
#include <ccache/util/path.hpp>
+#include <ccache/util/string.hpp>
#include <doctest/doctest.h>
#endif
}
+#ifdef _WIN32
+ SUBCASE("Case-insensitive match on Windows")
+ {
+ REQUIRE(fs::create_directory("casedir"));
+
+ // Construct variants with guaranteed drive-letter case difference.
+ // Windows drive letters are ASCII, so to_upper/to_lower always toggles
+ // case.
+ std::string upper_drive_cwd = actual_cwd;
+ upper_drive_cwd[0] = util::to_upper(actual_cwd[0]);
+ std::string lower_drive_cwd = actual_cwd;
+ lower_drive_cwd[0] = util::to_lower(actual_cwd[0]);
+
+ // dir1/dir2 with uppercase drive letter, path with lowercase drive letter.
+ CHECK(make_relative_path(
+ upper_drive_cwd, upper_drive_cwd, lower_drive_cwd + "/casedir")
+ == "casedir");
+
+ // dir1/dir2 with lowercase drive letter, path with uppercase drive letter.
+ CHECK(make_relative_path(
+ lower_drive_cwd, lower_drive_cwd, upper_drive_cwd + "/casedir")
+ == "casedir");
+
+ // Non-existing child: relative path also returned with drive-letter
+ // mismatch.
+ CHECK(make_relative_path(
+ upper_drive_cwd, upper_drive_cwd, lower_drive_cwd + "/nonexistent")
+ == "nonexistent");
+ CHECK(make_relative_path(
+ lower_drive_cwd, lower_drive_cwd, upper_drive_cwd + "/nonexistent")
+ == "nonexistent");
+ }
+#endif
+
#ifndef _WIN32
SUBCASE("Match of apparent CWD")
{