util::Bytes cpp_stderr_data;
// Headers (or directories with headers) to ignore in manifest mode.
- std::vector<std::string> ignore_header_paths;
+ std::vector<std::filesystem::path> ignore_header_paths;
// Storage (fronting local and remote storage backends).
storage::Storage storage;
ctx.config.base_dir(), ctx.actual_cwd, ctx.apparent_cwd, path);
}
-bool
-matches_dir_prefix_or_file(std::string_view dir_prefix_or_file,
- std::string_view path)
-{
- return !dir_prefix_or_file.empty() && !path.empty()
- && dir_prefix_or_file.length() <= path.length()
- && util::starts_with(path, dir_prefix_or_file)
- && (dir_prefix_or_file.length() == path.length()
- || is_dir_separator(path[dir_prefix_or_file.length()])
- || is_dir_separator(dir_prefix_or_file.back()));
-}
-
static std::string
do_normalize_abstract_absolute_path(std::string_view path)
{
// Like above but with base directory and apparent/actual CWD taken from `ctx`.
std::string make_relative_path(const Context& ctx, std::string_view path);
-// Return whether `path` is equal to `dir_prefix_or_file` or if
-// `dir_prefix_or_file` is a directory prefix of `path`.
-bool matches_dir_prefix_or_file(std::string_view dir_prefix_or_file,
- std::string_view path);
-
// Normalize absolute path `path`, not taking symlinks into account.
//
// Normalization here means syntactically removing redundant slashes and
}
for (const auto& ignore_header_path : ctx.ignore_header_paths) {
- if (Util::matches_dir_prefix_or_file(ignore_header_path, path)) {
+ if (file_path_matches_dir_prefix_or_file(ignore_header_path, path)) {
return true;
}
}
}
if (!ctx.config.extra_files_to_hash().empty()) {
- for (const std::string& path :
+ for (const auto& path :
util::split_path_list(ctx.config.extra_files_to_hash())) {
LOG("Hashing extra file {}", path);
hash.hash_delimiter("extrafile");
- if (!hash_binary_file(ctx, hash, path)) {
+ if (!hash_binary_file(ctx, hash, path.string())) {
return tl::unexpected(Statistic::error_hashing_extra_file);
}
}
return util::starts_with(name, "ccache");
}
+bool
+file_path_matches_dir_prefix_or_file(const fs::path& dir_prefix_or_file,
+ const fs::path& file_path)
+{
+ DEBUG_ASSERT(!dir_prefix_or_file.empty());
+ DEBUG_ASSERT(!file_path.filename().empty());
+
+ auto end = std::mismatch(dir_prefix_or_file.begin(),
+ dir_prefix_or_file.end(),
+ file_path.begin(),
+ file_path.end())
+ .first;
+ return end == dir_prefix_or_file.end() || end->empty();
+}
+
int
ccache_main(int argc, const char* const* argv)
{
void find_compiler(Context& ctx,
const FindExecutableFunction& find_executable_function,
bool masquerading_as_compiler);
+
CompilerType guess_compiler(std::string_view path);
+
bool is_ccache_executable(const std::filesystem::path& path);
+
+bool file_path_matches_dir_prefix_or_file(
+ const std::filesystem::path& dir_prefix_or_file,
+ const std::filesystem::path& file_path);
#include <fmtmacros.hpp>
#include <util/DirEntry.hpp>
#include <util/file.hpp>
+#include <util/filesystem.hpp>
#include <util/path.hpp>
#include <util/string.hpp>
#include <util/wincompat.hpp>
# include "Finalizer.hpp"
#endif
+namespace fs = util::filesystem;
+
#ifdef _WIN32
static int win32execute(const char* path,
const char* const* argv,
const char* path_list = getenv("PATH");
std::string sh;
if (util::to_lowercase(Util::get_extension(path)) == ".sh" && path_list) {
- sh = find_executable_in_path("sh.exe", path_list);
+ sh = find_executable_in_path("sh.exe", path_list).string();
}
if (sh.empty() && getenv("CCACHE_DETECT_SHEBANG")) {
// Detect shebang.
char buf[10] = {0};
fgets(buf, sizeof(buf) - 1, fp.get());
if (std::string(buf) == "#!/bin/sh" && path_list) {
- sh = find_executable_in_path("sh.exe", path_list);
+ sh = find_executable_in_path("sh.exe", path_list).string();
}
}
}
return {};
}
- return find_executable_in_path(name, path_list, exclude_path);
+ return find_executable_in_path(name, path_list, exclude_path).string();
}
-std::string
+fs::path
find_executable_in_path(const std::string& name,
const std::string& path_list,
- std::optional<std::string> exclude_path)
+ const std::optional<fs::path>& exclude_path)
{
if (path_list.empty()) {
return {};
}
- const auto real_exclude_path =
- exclude_path ? util::real_path(*exclude_path) : "";
+ auto real_exclude_path =
+ exclude_path ? fs::canonical(*exclude_path).value_or("") : "";
// Search the path list looking for the first compiler of the right name that
// isn't us.
- for (const std::string& dir : util::split_path_list(path_list)) {
- const std::vector<std::string> candidates = {
- FMT("{}/{}", dir, name),
+ for (const auto& dir : util::split_path_list(path_list)) {
+ const std::vector<fs::path> candidates = {
+ dir / name,
#ifdef _WIN32
- FMT("{}/{}.exe", dir, name),
+ dir / FMT("{}.exe", name),
#endif
};
for (const auto& candidate : candidates) {
access(candidate.c_str(), X_OK) == 0;
#endif
if (candidate_exists) {
- const auto real_candidate = util::real_path(candidate);
- if ((real_exclude_path.empty() || real_candidate != real_exclude_path)
- && !is_ccache_executable(real_candidate)) {
+ auto real_candidate = fs::canonical(candidate);
+ if (real_candidate && *real_candidate != real_exclude_path
+ && !is_ccache_executable(*real_candidate)) {
return candidate;
}
}
-// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2023 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
#include "Fd.hpp"
+#include <filesystem>
#include <optional>
#include <string>
const std::string& name,
const std::string& exclude_path);
-std::string
-find_executable_in_path(const std::string& name,
- const std::string& path_list,
- std::optional<std::string> exclude_path = std::nullopt);
+std::filesystem::path find_executable_in_path(
+ const std::string& name,
+ const std::string& path_list,
+ const std::optional<std::filesystem::path>& exclude_path = std::nullopt);
#ifdef _WIN32
std::string win32getshell(const std::string& path);
STARTUPINFO si;
memset(&si, 0x00, sizeof(si));
- std::string path = find_executable_in_path(args[0], getenv("PATH"));
+ auto path = find_executable_in_path(args[0], getenv("PATH")).string();
if (path.empty()) {
path = args[0];
}
#ifdef _WIN32
const char k_dev_null_path[] = "nul:";
-const char k_path_delimiter[] = ";";
#else
const char k_dev_null_path[] = "/dev/null";
-const char k_path_delimiter[] = ":";
#endif
namespace fs = util::filesystem;
return real_path ? real_path->string() : std::string(path);
}
-std::vector<std::string>
-split_path_list(std::string_view path_list)
-{
- return split_into_strings(path_list, k_path_delimiter);
-}
-
std::string
to_absolute_path(std::string_view path)
{
// doesn't exist) path is returned unmodified.
std::string real_path(std::string_view path);
-// Split a list of paths (such as the content of $PATH on Unix platforms or
-// %PATH% on Windows platforms) into paths.
-std::vector<std::string> split_path_list(std::string_view path_list);
-
// Make `path` an absolute path.
std::string to_absolute_path(std::string_view path);
}
}
+std::vector<std::filesystem::path>
+split_path_list(std::string_view path_list)
+{
+#ifdef _WIN32
+ const char path_delimiter[] = ";";
+#else
+ const char path_delimiter[] = ":";
+#endif
+ auto strings = split_into_views(path_list, path_delimiter);
+ std::vector<std::filesystem::path> paths;
+ std::copy(strings.cbegin(), strings.cend(), std::back_inserter(paths));
+ return paths;
+}
+
std::string
strip_whitespace(const std::string_view string)
{
#include <cstdint>
#include <cstring>
+#include <filesystem>
#include <optional>
#include <string>
#include <string_view>
std::pair<std::string_view, std::optional<std::string_view>>
split_once(std::string_view string, char split_char);
+// Split a list of paths (such as the content of $PATH on Unix platforms or
+// %PATH% on Windows platforms) into paths.
+std::vector<std::filesystem::path> split_path_list(std::string_view path_list);
+
// Return true if `prefix` is a prefix of `string`.
bool starts_with(const char* string, std::string_view prefix);
#endif
}
-TEST_CASE("Util::matches_dir_prefix_or_file")
-{
- CHECK(!Util::matches_dir_prefix_or_file("", ""));
- CHECK(!Util::matches_dir_prefix_or_file("/", ""));
- CHECK(!Util::matches_dir_prefix_or_file("", "/"));
-
- CHECK(Util::matches_dir_prefix_or_file("aa", "aa"));
- CHECK(!Util::matches_dir_prefix_or_file("aaa", "aa"));
- CHECK(!Util::matches_dir_prefix_or_file("aa", "aaa"));
- CHECK(!Util::matches_dir_prefix_or_file("aa/", "aa"));
-
- CHECK(Util::matches_dir_prefix_or_file("/aa/bb", "/aa/bb"));
- CHECK(!Util::matches_dir_prefix_or_file("/aa/b", "/aa/bb"));
- CHECK(!Util::matches_dir_prefix_or_file("/aa/bbb", "/aa/bb"));
-
- CHECK(Util::matches_dir_prefix_or_file("/aa", "/aa/bb"));
- CHECK(Util::matches_dir_prefix_or_file("/aa/", "/aa/bb"));
- CHECK(!Util::matches_dir_prefix_or_file("/aa/bb", "/aa"));
- CHECK(!Util::matches_dir_prefix_or_file("/aa/bb", "/aa/"));
-
-#ifdef _WIN32
- CHECK(Util::matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
- CHECK(Util::matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
-#else
- CHECK(!Util::matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
- CHECK(!Util::matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
-#endif
-}
-
TEST_CASE("Util::normalize_abstract_absolute_path")
{
CHECK(Util::normalize_abstract_absolute_path("") == "");
#endif
}
+TEST_CASE("file_path_matches_dir_prefix_or_file")
+{
+ CHECK(file_path_matches_dir_prefix_or_file("aa", "aa"));
+ CHECK(!file_path_matches_dir_prefix_or_file("aaa", "aa"));
+ CHECK(!file_path_matches_dir_prefix_or_file("aa", "aaa"));
+ CHECK(file_path_matches_dir_prefix_or_file("aa/", "aa"));
+
+ CHECK(file_path_matches_dir_prefix_or_file("/aa/bb", "/aa/bb"));
+ CHECK(!file_path_matches_dir_prefix_or_file("/aa/b", "/aa/bb"));
+ CHECK(!file_path_matches_dir_prefix_or_file("/aa/bbb", "/aa/bb"));
+
+ CHECK(file_path_matches_dir_prefix_or_file("/aa", "/aa/bb"));
+ CHECK(file_path_matches_dir_prefix_or_file("/aa/", "/aa/bb"));
+ CHECK(!file_path_matches_dir_prefix_or_file("/aa/bb", "/aa"));
+
+#ifdef _WIN32
+ CHECK(file_path_matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
+ CHECK(file_path_matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
+#else
+ CHECK(!file_path_matches_dir_prefix_or_file("\\aa", "\\aa\\bb"));
+ CHECK(!file_path_matches_dir_prefix_or_file("\\aa\\", "\\aa\\bb"));
+#endif
+}
+
TEST_SUITE_END();
#endif
}
-TEST_CASE("util::split_path_list")
-{
- CHECK(util::split_path_list("").empty());
- {
- const auto v = util::split_path_list("a");
- REQUIRE(v.size() == 1);
- CHECK(v[0] == "a");
- }
- {
- const auto v = util::split_path_list("a/b");
- REQUIRE(v.size() == 1);
- CHECK(v[0] == "a/b");
- }
- {
-#ifdef _WIN32
- const auto v = util::split_path_list("a/b;c");
-#else
- const auto v = util::split_path_list("a/b:c");
-#endif
- REQUIRE(v.size() == 2);
- CHECK(v[0] == "a/b");
- CHECK(v[1] == "c");
- }
-}
-
TEST_CASE("util::to_absolute_path")
{
CHECK(util::to_absolute_path("/foo/bar") == "/foo/bar");
}
}
+TEST_CASE("util::split_path_list")
+{
+ CHECK(util::split_path_list("").empty());
+ {
+ const auto v = util::split_path_list("a");
+ REQUIRE(v.size() == 1);
+ CHECK(v[0] == "a");
+ }
+ {
+ const auto v = util::split_path_list("a/b");
+ REQUIRE(v.size() == 1);
+ CHECK(v[0] == "a/b");
+ }
+ {
+#ifdef _WIN32
+ const auto v = util::split_path_list("a/b;c");
+#else
+ const auto v = util::split_path_list("a/b:c");
+#endif
+ REQUIRE(v.size() == 2);
+ CHECK(v[0] == "a/b");
+ CHECK(v[1] == "c");
+ }
+}
+
TEST_CASE("util::starts_with")
{
// starts_with(const char*, string_view)