bool found_wp_md_or_mmd_opt = false;
bool found_md_or_mmd_opt = false;
bool found_Wa_a_opt = false;
+ bool rewrite_FI_args = false;
std::string explicit_language; // As specified with -x.
std::string input_charset_option; // -finput-charset=...
m_native_args.push_back(std::forward<T>(arg));
}
+ util::Args&
+ get_preprocessor_args()
+ {
+ return m_preprocessor_args;
+ }
+
+ util::Args&
+ get_compiler_args()
+ {
+ return m_compiler_args;
+ }
+
ProcessArgsResult
to_result()
{
return Statistic::none;
}
+ if (config.is_compiler_group_msvc() && arg.starts_with("-FI")
+ && !ctx.config.base_dirs().empty()) {
+ // /FI is special in that the compiler looks up a relative file relative to
+ // the source file instead of CWD, so we need to special-case it. However,
+ // to do that we need to know the source code location, so we have to
+ // rewrite the /FI argument after we have processed all arguments.
+ state.rewrite_FI_args = true;
+
+ // Need to remember the path in raw form (not rewritten relative to CWD).
+ state.add_common_arg(args[i]);
+ if (arg.length() == 3) {
+ if (i == args.size() - 1) {
+ LOG("Missing argument to {}", args[i]);
+ return Statistic::bad_compiler_arguments;
+ }
+ state.add_common_arg(args[i + 1]);
+ ++i;
+ }
+ return Statistic::none;
+ }
+
if (compopt_takes_arg(arg) && compopt_takes_path(arg)) {
if (i == args.size() - 1) {
LOG("Missing argument to {}", args[i]);
return tl::unexpected(Statistic::unsupported_compiler_option);
}
+ // Special case: rewrite /FI arguments relative to the input file.
+ if (state.rewrite_FI_args) {
+ auto r = fs::canonical(args_info.input_file.parent_path());
+ if (!r) {
+ LOG("Failed to convert {} to absolute: {}",
+ args_info.input_file.parent_path(),
+ r.error());
+ return tl::unexpected(Statistic::internal_error);
+ }
+ const auto& abs_input_file_dir = *r;
+ auto rewrite = [&](util::Args& arglist, size_t& i) {
+ if (arglist[i].starts_with("/FI") || arglist[i].starts_with("-FI")) {
+ if (arglist[i].length() > 3) {
+ arglist[i] = FMT("{}{}",
+ arglist[i].substr(0, 3),
+ core::make_relative_path(
+ ctx, arglist[i].substr(3), abs_input_file_dir));
+ } else if (i + 1 < arglist.size()) {
+ arglist[i + 1] = util::pstr(
+ core::make_relative_path(ctx, arglist[i + 1], abs_input_file_dir));
+ ++i;
+ }
+ }
+ };
+
+ auto& preprocessor_args = state.get_preprocessor_args();
+ for (size_t i = 0; i < preprocessor_args.size(); ++i) {
+ rewrite(preprocessor_args, i);
+ }
+ auto& compiler_args = state.get_compiler_args();
+ for (size_t i = 0; i < compiler_args.size(); ++i) {
+ rewrite(compiler_args, i);
+ }
+ }
+
// Don't try to second guess the compiler's heuristics for stdout handling.
if (args_info.output_obj == "-") {
LOG("Output file is -");
-// Copyright (C) 2023-2025 Joel Rosdahl and other contributors
+// Copyright (C) 2023-2026 Joel Rosdahl and other contributors
//
// See doc/authors.adoc for a complete list of contributors.
//
}
fs::path
-make_relative_path(const Context& ctx, const fs::path& path)
+make_relative_path(const Context& ctx,
+ const std::filesystem::path& path,
+ const std::filesystem::path& dir1,
+ const std::optional<std::filesystem::path>& dir2)
{
+ DEBUG_ASSERT(dir1.is_absolute());
+ DEBUG_ASSERT(!dir2 || dir2->is_absolute());
if (!ctx.config.base_dirs().empty() && path.is_absolute()
&& util::path_starts_with(path, ctx.config.base_dirs())) {
- return util::make_relative_path(ctx.actual_cwd, ctx.apparent_cwd, path);
+ return util::make_relative_path(dir1, dir2.value_or(dir1), path);
} else {
return path;
}
}
+fs::path
+make_relative_path(const Context& ctx, const fs::path& path)
+{
+ return make_relative_path(ctx, path, ctx.actual_cwd, ctx.apparent_cwd);
+}
+
inline bool
parse_inlined_from_msg(std::string_view& line, std::string& result)
{
-// Copyright (C) 2023-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2023-2026 Joel Rosdahl and other contributors
//
// See doc/authors.adoc for a complete list of contributors.
//
#pragma once
#include <filesystem>
+#include <optional>
#include <string>
#include <string_view>
// Like std::filesystem::create_directories but throws core::Fatal on error.
void ensure_dir_exists(const std::filesystem::path& dir);
-// Make a `path` relative to CWD if it's under base_dir.
+// Make a `path` relative to `dir1` or `dir2` if the path is under base_dir.
+std::filesystem::path make_relative_path(
+ const Context& ctx,
+ const std::filesystem::path& path,
+ const std::filesystem::path& dir1,
+ const std::optional<std::filesystem::path>& dir2 = std::nullopt);
+
+// Make a `path` relative to actual/apparent CWD if the path is under base_dir.
std::filesystem::path make_relative_path(const Context& ctx,
const std::filesystem::path& path);
}
fs::path
-make_relative_path(const fs::path& actual_cwd,
- const fs::path& apparent_cwd,
+make_relative_path(const fs::path& dir1,
+ const fs::path& dir2,
const fs::path& path)
{
- DEBUG_ASSERT(actual_cwd.is_absolute());
- DEBUG_ASSERT(apparent_cwd.is_absolute());
+ DEBUG_ASSERT(dir1.is_absolute());
+ DEBUG_ASSERT(dir2.is_absolute());
DEBUG_ASSERT(path.is_absolute());
fs::path normalized_path = util::lexically_normal(path);
path_suffix = closest_existing_path.filename() / path_suffix;
}
closest_existing_path = closest_existing_path.parent_path();
+ if (closest_existing_path == closest_existing_path.root_path()) {
+ break;
+ }
}
- relpath_candidates.push_back(
- closest_existing_path.lexically_relative(actual_cwd));
- if (apparent_cwd != actual_cwd) {
+ relpath_candidates.push_back(closest_existing_path.lexically_relative(dir1));
+ if (dir2 != dir1) {
relpath_candidates.emplace_back(
- closest_existing_path.lexically_relative(apparent_cwd));
+ closest_existing_path.lexically_relative(dir2));
}
// Find best (i.e. shortest existing) match:
< util::pstr(path2).str().length();
});
for (const auto& relpath : relpath_candidates) {
- if (fs::equivalent(relpath, closest_existing_path)) {
+ if (fs::equivalent(dir1 / relpath, closest_existing_path)) {
return path_suffix.empty() ? relpath
: (relpath / path_suffix).lexically_normal();
}
// Return whether `path` includes at least one directory separator.
bool is_full_path(std::string_view path);
-// Make a relative path from current working directory (either `actual_cwd` or
-// `apparent_cwd`) to `path` if `path` is under `base_dir`.
-std::filesystem::path
-make_relative_path(const std::filesystem::path& actual_cwd,
- const std::filesystem::path& apparent_cwd,
- const std::filesystem::path& path);
+// Make a relative path from `dir1` or `dir2` to `path`.
+std::filesystem::path make_relative_path(const std::filesystem::path& dir1,
+ const std::filesystem::path& dir2,
+ const std::filesystem::path& path);
// Construct a normalized native path.
//
-// Copyright (C) 2021-2025 Joel Rosdahl and other contributors
+// Copyright (C) 2021-2026 Joel Rosdahl and other contributors
//
// See doc/authors.adoc for a complete list of contributors.
//
SUBCASE("Path matches neither actual nor apparent CWD")
{
#ifdef _WIN32
- CHECK(make_relative_path("C:/a", "C:/b", "C:/x") == "C:/x");
+ CHECK(make_relative_path("C:/a", "D:/b", "E:/x") == "E:/x");
#else
CHECK(make_relative_path("/a", "/b", "/x") == "/x");
#endif