[#config_response_file_format]
*response_file_format* (*CCACHE_RESPONSE_FILE_FORMAT*)::
- Ccache normally guesses the response file format based on the compiler type. The
- *response_file_format* option lets you force the response file quoting behavior.
- This can be useful if the compiler supports both posix and windows response file
- quoting. Possible values are:
+ Ccache normally guesses the response file format based on the compiler type.
+ The *response_file_format* option lets you force the response file quoting
+ behavior. This can be useful if the compiler supports both POSIX and Windows
+ response file quoting. Possible values are:
+
--
*auto*::
- Guess one of the formats below based on the compiler type. This is the default.
+ Guess one of the formats below based on the compiler type. This is the
+ default.
*posix*::
- Posix quoting behavior.
+ POSIX quoting behavior.
*windows*::
Windows quoting behavior.
--
if (argpath[-1] == '-') {
++argpath;
}
- auto file_args = Args::from_atfile(argpath, config.atfile_format());
+ auto file_args =
+ Args::from_response_file(argpath, config.response_file_format());
if (!file_args) {
LOG("Couldn't read arg file {}", argpath);
return Statistic::bad_compiler_arguments;
// Argument is a comma-separated list of files.
auto paths = util::split_into_strings(args[i], ",");
for (auto it = paths.rbegin(); it != paths.rend(); ++it) {
- auto file_args = Args::from_atfile(*it, AtFileFormat::gcc);
+ auto file_args =
+ Args::from_response_file(*it, Args::ResponseFileFormat::posix);
if (!file_args) {
LOG("Couldn't read CUDA options file {}", *it);
return Statistic::bad_compiler_arguments;
}
std::optional<Args>
-Args::from_atfile(const std::string& filename, AtFileFormat format)
+Args::from_response_file(const std::string& filename, ResponseFileFormat format)
{
- ASSERT(format != AtFileFormat::auto_guess);
+ ASSERT(format != ResponseFileFormat::auto_guess);
const auto argtext = util::read_file<std::string>(filename);
if (!argtext) {
- LOG("Failed to read atfile {}: {}", filename, argtext.error());
+ LOG("Failed to read response file {}: {}", filename, argtext.error());
return std::nullopt;
}
switch (*pos) {
case '\\':
switch (format) {
- case AtFileFormat::auto_guess:
+ case ResponseFileFormat::auto_guess:
ASSERT(false); // Can't happen
break;
- case AtFileFormat::gcc:
+ case ResponseFileFormat::posix:
pos++;
if (*pos == '\0') {
continue;
}
break;
- case AtFileFormat::msvc:
+ case ResponseFileFormat::windows:
size_t count = 0;
while (*pos == '\\') {
count++;
break;
case '\'':
- if (format == AtFileFormat::msvc) {
+ if (format == ResponseFileFormat::windows) {
break;
}
[[fallthrough]];
if (quoting == *pos) {
quoting = '\0';
pos++;
- if (format == AtFileFormat::msvc && *pos == '"') {
+ if (format == ResponseFileFormat::windows && *pos == '"') {
// Any double-quote directly following a closing quote is treated as
// (or as part of) plain unwrapped text that is adjacent to the
// double-quoted group
#include <string_view>
#include <vector>
-enum class AtFileFormat;
-
class Args
{
public:
+ enum class ResponseFileFormat {
+ auto_guess,
+ posix, // '\'' and '"' quote, '\\' escapes any character
+ windows, // '"' quotes, '\\' escapes only '"' and '\\'
+ };
+
Args() = default;
Args(const Args& other) = default;
Args(Args&& other) noexcept;
static Args from_argv(int argc, const char* const* argv);
static Args from_string(std::string_view command);
- static std::optional<Args> from_atfile(const std::string& filename,
- AtFileFormat format);
+ static std::optional<Args> from_response_file(const std::string& filename,
+ ResponseFileFormat format);
Args& operator=(const Args& other) = default;
Args& operator=(Args&& other) noexcept;
{"UMASK", "umask"},
};
-AtFileFormat
+Args::ResponseFileFormat
parse_response_file_format(const std::string& value)
{
- if (value == "windows") {
- return AtFileFormat::msvc;
- } else if (value == "posix") {
- return AtFileFormat::gcc;
+ if (value == "posix") {
+ return Args::ResponseFileFormat::posix;
+ } else if (value == "windows") {
+ return Args::ResponseFileFormat::windows;
} else {
- return AtFileFormat::auto_guess;
+ return Args::ResponseFileFormat::auto_guess;
}
}
}
std::string
-atfile_format_to_string(AtFileFormat atfile_format)
+response_file_format_to_string(Args::ResponseFileFormat response_file_format)
{
- switch (atfile_format) {
- case AtFileFormat::auto_guess:
+ switch (response_file_format) {
+ case Args::ResponseFileFormat::auto_guess:
return "auto";
- case AtFileFormat::gcc:
+ case Args::ResponseFileFormat::posix:
return "posix";
- case AtFileFormat::msvc:
+ case Args::ResponseFileFormat::windows:
return "windows";
}
return format_bool(m_reshare);
case ConfigItem::response_file_format:
- return atfile_format_to_string(m_atfile_format);
+ return response_file_format_to_string(m_response_file_format);
case ConfigItem::run_second_cpp:
return format_bool(m_run_second_cpp);
break;
case ConfigItem::response_file_format:
- m_atfile_format = parse_response_file_format(value);
+ m_response_file_format = parse_response_file_format(value);
break;
case ConfigItem::run_second_cpp:
#pragma once
+#include <ccache/args.hpp>
#include <ccache/core/sloppiness.hpp>
#include <ccache/util/noncopyable.hpp>
#include <ccache/util/string.hpp>
other
};
-enum class AtFileFormat {
- gcc, // '\'' and '"' quote, '\\' escapes any character
- msvc, // '"' quotes, '\\' escapes only '"' and '\\'
- auto_guess,
-};
-
std::string compiler_type_to_string(CompilerType compiler_type);
class Config : util::NonCopyable
void read(const std::vector<std::string>& cmdline_config_settings = {});
bool absolute_paths_in_stderr() const;
- AtFileFormat atfile_format() const;
+ Args::ResponseFileFormat response_file_format() const;
const std::filesystem::path& base_dir() const;
const std::filesystem::path& cache_dir() const;
const std::string& compiler() const;
std::filesystem::path m_system_config_path;
bool m_absolute_paths_in_stderr = false;
- AtFileFormat m_atfile_format = AtFileFormat::auto_guess;
+ Args::ResponseFileFormat m_response_file_format =
+ Args::ResponseFileFormat::auto_guess;
std::filesystem::path m_base_dir;
std::filesystem::path m_cache_dir;
std::string m_compiler;
return m_absolute_paths_in_stderr;
}
-inline AtFileFormat
-Config::atfile_format() const
+inline Args::ResponseFileFormat
+Config::response_file_format() const
{
- if (m_atfile_format != AtFileFormat::auto_guess) {
- return m_atfile_format;
- }
-
- if (is_compiler_group_msvc()) {
- return AtFileFormat::msvc;
+ if (m_response_file_format != Args::ResponseFileFormat::auto_guess) {
+ return m_response_file_format;
}
- return AtFileFormat::gcc;
+ return is_compiler_group_msvc() ? Args::ResponseFileFormat::windows
+ : Args::ResponseFileFormat::posix;
}
inline const std::filesystem::path&
CHECK(args[3] == "f");
}
-TEST_CASE("Args::from_atfile")
+TEST_CASE("Args::from_response_file")
{
TestContext test_context;
+ using ResponseFileFormat = Args::ResponseFileFormat;
Args args;
SUBCASE("Nonexistent file")
{
- CHECK(Args::from_atfile("at_file", AtFileFormat::gcc) == std::nullopt);
+ CHECK(Args::from_response_file("rsp_file", ResponseFileFormat::posix)
+ == std::nullopt);
}
SUBCASE("Empty")
{
- util::write_file("at_file", "");
- args = *Args::from_atfile("at_file", AtFileFormat::gcc);
+ util::write_file("rsp_file", "");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::posix);
CHECK(args.size() == 0);
}
SUBCASE("One argument without newline")
{
- util::write_file("at_file", "foo");
- args = *Args::from_atfile("at_file", AtFileFormat::gcc);
+ util::write_file("rsp_file", "foo");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::posix);
CHECK(args.size() == 1);
CHECK(args[0] == "foo");
}
SUBCASE("One argument with newline")
{
- util::write_file("at_file", "foo\n");
- args = *Args::from_atfile("at_file", AtFileFormat::gcc);
+ util::write_file("rsp_file", "foo\n");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::posix);
CHECK(args.size() == 1);
CHECK(args[0] == "foo");
}
SUBCASE("Multiple simple arguments")
{
- util::write_file("at_file", "x y z\n");
- args = *Args::from_atfile("at_file", AtFileFormat::gcc);
+ util::write_file("rsp_file", "x y z\n");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::posix);
CHECK(args.size() == 3);
CHECK(args[0] == "x");
CHECK(args[1] == "y");
SUBCASE("Tricky quoting")
{
util::write_file(
- "at_file",
+ "rsp_file",
"first\rsec\\\tond\tthi\\\\rd\nfourth \tfif\\ th \"si'x\\\" th\""
" 'seve\nth'\\");
- args = *Args::from_atfile("at_file", AtFileFormat::gcc);
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::posix);
CHECK(args.size() == 7);
CHECK(args[0] == "first");
CHECK(args[1] == "sec\tond");
SUBCASE("Ignore single quote in MSVC format")
{
- util::write_file("at_file", "'a b'");
- args = *Args::from_atfile("at_file", AtFileFormat::msvc);
+ util::write_file("rsp_file", "'a b'");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::windows);
CHECK(args.size() == 2);
CHECK(args[0] == "'a");
CHECK(args[1] == "b'");
SUBCASE("Backslash as directory separator in MSVC format")
{
- util::write_file("at_file", R"("-DDIRSEP='A\B\C'")");
- args = *Args::from_atfile("at_file", AtFileFormat::msvc);
+ util::write_file("rsp_file", R"("-DDIRSEP='A\B\C'")");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::windows);
CHECK(args.size() == 1);
CHECK(args[0] == R"(-DDIRSEP='A\B\C')");
}
SUBCASE("Backslash before quote in MSVC format")
{
- util::write_file("at_file", R"(/Fo"N.dir\Release\\")");
- args = *Args::from_atfile("at_file", AtFileFormat::msvc);
+ util::write_file("rsp_file", R"(/Fo"N.dir\Release\\")");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::windows);
CHECK(args.size() == 1);
CHECK(args[0] == R"(/FoN.dir\Release\)");
}
SUBCASE("Arguments on multiple lines in MSVC format")
{
- util::write_file("at_file", "a\nb");
- args = *Args::from_atfile("at_file", AtFileFormat::msvc);
+ util::write_file("rsp_file", "a\nb");
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::windows);
CHECK(args.size() == 2);
CHECK(args[0] == "a");
CHECK(args[1] == "b");
SUBCASE("Tricky quoting in MSVC format (#1247)")
{
util::write_file(
- "at_file",
+ "rsp_file",
R"(\ \\ '\\' "\\" '"\\"' "'\\'" '''\\''' ''"\\"'' '"'\\'"' '""\\""' "''\\''" "'"\\"'" ""'\\'"" """\\""" )"
R"(\'\' '\'\'' "\'\'" ''\'\''' '"\'\'"' "'\'\''" ""\'\'"" '''\'\'''' ''"\'\'"'' '"'\'\''"' '""\'\'""' "''\'\'''" "'"\'\'"'" ""'\'\''"" """\'\'""" )"
R"(\"\" '\"\"' "\"\"" ''\"\"'' '"\"\""' "'\"\"'" ""\"\""" '''\"\"''' ''"\"\""'' '"'\"\"'"' '""\"\"""' "''\"\"''" "'"\"\""'" ""'\"\"'"" """\"\"""")");
- args = *Args::from_atfile("at_file", AtFileFormat::msvc);
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::windows);
CHECK(args.size() == 44);
CHECK(args[0] == R"(\)");
CHECK(args[1] == R"(\\)");
{
// See
// https://learn.microsoft.com/en-us/previous-versions//17w5ykft(v=vs.85)?redirectedfrom=MSDN
- util::write_file("at_file",
+ util::write_file("rsp_file",
R"("abc" d e )"
R"(a\\\b d"e f"g h )"
R"(a\\\"b c d )"
R"(a\\\\"b c" d e)");
- args = *Args::from_atfile("at_file", AtFileFormat::msvc);
+ args = *Args::from_response_file("rsp_file", ResponseFileFormat::windows);
CHECK(args.size() == 12);
CHECK(args[0] == R"(abc)");
CHECK(args[1] == R"(d)");
TEST_CASE("Config::response_file_format")
{
+ using ResponseFileFormat = Args::ResponseFileFormat;
+
Config config;
SUBCASE("from config gcc")
util::write_file("ccache.conf", "response_file_format = posix");
CHECK(config.update_from_file("ccache.conf"));
- CHECK(config.atfile_format() == AtFileFormat::gcc);
+ CHECK(config.response_file_format() == ResponseFileFormat::posix);
}
SUBCASE("from config msvc")
util::write_file("ccache.conf", "response_file_format = windows");
CHECK(config.update_from_file("ccache.conf"));
- CHECK(config.atfile_format() == AtFileFormat::msvc);
+ CHECK(config.response_file_format() == ResponseFileFormat::windows);
}
SUBCASE("from config msvc with clang compiler")
"response_file_format = windows\ncompiler_type = clang");
CHECK(config.update_from_file("ccache.conf"));
- CHECK(config.atfile_format() == AtFileFormat::msvc);
+ CHECK(config.response_file_format() == ResponseFileFormat::windows);
}
SUBCASE("guess from compiler gcc")
util::write_file("ccache.conf", "compiler_type = clang");
CHECK(config.update_from_file("ccache.conf"));
- CHECK(config.atfile_format() == AtFileFormat::gcc);
+ CHECK(config.response_file_format() == ResponseFileFormat::posix);
}
SUBCASE("guess from compiler msvc")
util::write_file("ccache.conf", "compiler_type = msvc");
CHECK(config.update_from_file("ccache.conf"));
- CHECK(config.atfile_format() == AtFileFormat::msvc);
+ CHECK(config.response_file_format() == ResponseFileFormat::windows);
}
}