Skip to content

Commit

Permalink
Visual C/C++ compiler support
Browse files Browse the repository at this point in the history
I picked only the compiler commits from:
ccache#162

The following commits I've adapted to the latest ccache C++ code:

375fe24: Add compiler_is_msvc() and MSVC specific option table.
7e01763: Add handling of /Fo option (replaces -o, but shall have no space)
0c5cd25: Manage /E, /c equivalence. -g is gcc only. -O or /O is msvc only.
4f61b59: MSVC send part of the error/warning messages to STDOUT, so concat wit…
64449d6: use common code for gcc an cl response files.
  • Loading branch information
cristianadam committed Nov 14, 2021
1 parent 5f7c811 commit 2214090
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 21 deletions.
1 change: 1 addition & 0 deletions misc/codespell-allowlist.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
fo
copyable
creat
files'
Expand Down
5 changes: 4 additions & 1 deletion src/Args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Args::from_string(const std::string& command)
}

optional<Args>
Args::from_gcc_atfile(const std::string& filename)
Args::from_atfile(const std::string& filename, bool ignore_backslash)
{
std::string argtext;
try {
Expand All @@ -72,6 +72,9 @@ Args::from_gcc_atfile(const std::string& filename)
while (true) {
switch (*pos) {
case '\\':
if (ignore_backslash) {
break;
}
pos++;
if (*pos == '\0') {
continue;
Expand Down
3 changes: 2 additions & 1 deletion src/Args.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class Args

static Args from_argv(int argc, const char* const* argv);
static Args from_string(const std::string& command);
static nonstd::optional<Args> from_gcc_atfile(const std::string& filename);
static nonstd::optional<Args> from_atfile(const std::string& filename,
bool ignore_backslash = false);

Args& operator=(const Args& other) = default;
Args& operator=(Args&& other) noexcept;
Expand Down
1 change: 1 addition & 0 deletions src/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ compiler_type_to_string(CompilerType compiler_type)
CASE(nvcc);
CASE(other);
CASE(pump);
CASE(cl);
}
#undef CASE

Expand Down
2 changes: 1 addition & 1 deletion src/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <string>
#include <unordered_map>

enum class CompilerType { auto_guess, clang, gcc, nvcc, other, pump };
enum class CompilerType { auto_guess, clang, gcc, nvcc, other, pump, cl };

std::string compiler_type_to_string(CompilerType compiler_type);

Expand Down
29 changes: 21 additions & 8 deletions src/argprocessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ process_arg(const Context& ctx,
}

// Special case for -E.
if (args[i] == "-E") {
if (args[i] == "-E" || args[i] == "/E") {
return Statistic::called_for_preprocessing;
}

Expand All @@ -263,7 +263,8 @@ process_arg(const Context& ctx,
if (argpath[-1] == '-') {
++argpath;
}
auto file_args = Args::from_gcc_atfile(argpath);
auto file_args =
Args::from_atfile(argpath, config.compiler_type() == CompilerType::cl);
if (!file_args) {
LOG("Couldn't read arg file {}", argpath);
return Statistic::bad_compiler_arguments;
Expand All @@ -286,7 +287,7 @@ process_arg(const Context& ctx,
// 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_gcc_atfile(*it);
auto file_args = Args::from_atfile(*it);
if (!file_args) {
LOG("Couldn't read CUDA options file {}", *it);
return Statistic::bad_compiler_arguments;
Expand All @@ -300,7 +301,8 @@ process_arg(const Context& ctx,

// These are always too hard.
if (compopt_too_hard(args[i]) || util::starts_with(args[i], "-fdump-")
|| util::starts_with(args[i], "-MJ")) {
|| util::starts_with(args[i], "-MJ") || util::starts_with(args[i], "-Yc")
|| util::starts_with(args[i], "/Yc")) {
LOG("Compiler option {} is unsupported", args[i]);
return Statistic::unsupported_compiler_option;
}
Expand Down Expand Up @@ -398,11 +400,19 @@ process_arg(const Context& ctx,
}

// We must have -c.
if (args[i] == "-c") {
if (args[i] == "-c" || args[i] == "/c") {
state.found_c_opt = true;
return nullopt;
}

// MSVC /Fo with no space.
if (util::starts_with(args[i], "/Fo")
&& config.compiler_type() == CompilerType::cl) {
args_info.output_obj =
Util::make_relative_path(ctx, string_view(args[i]).substr(3));
return nullopt;
}

// when using nvcc with separable compilation, -dc implies -c
if ((args[i] == "-dc" || args[i] == "--device-c")
&& config.compiler_type() == CompilerType::nvcc) {
Expand Down Expand Up @@ -511,7 +521,8 @@ process_arg(const Context& ctx,

// These options require special handling, because they behave differently
// with gcc -E, when the output file is not specified.
if (args[i] == "-MD" || args[i] == "-MMD") {
if ((args[i] == "-MD" || args[i] == "-MMD")
&& config.compiler_type() != CompilerType::cl) {
args_info.generating_dependencies = true;
args_info.seen_MD_MMD = true;
state.dep_args.push_back(args[i]);
Expand Down Expand Up @@ -845,7 +856,8 @@ process_arg(const Context& ctx,

// Same as above but options with concatenated argument beginning with a
// slash.
if (args[i][0] == '-') {
if (args[i][0] == '-'
|| (config.compiler_type() == CompilerType::cl && args[i][0] == '/')) {
size_t slash_pos = args[i].find('/');
if (slash_pos != std::string::npos) {
std::string option = args[i].substr(0, slash_pos);
Expand Down Expand Up @@ -883,7 +895,8 @@ process_arg(const Context& ctx,
}

// Other options.
if (args[i][0] == '-') {
if (args[i][0] == '-'
|| (config.compiler_type() == CompilerType::cl && args[i][0] == '/')) {
if (compopt_affects_cpp_output(args[i])
|| compopt_prefix_affects_cpp_output(args[i])) {
state.cpp_args.push_back(args[i]);
Expand Down
31 changes: 28 additions & 3 deletions src/ccache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ guess_compiler(string_view path)
return CompilerType::nvcc;
} else if (name == "pump" || name == "distcc-pump") {
return CompilerType::pump;
} else if (name.find("cl") != nonstd::string_view::npos) {
return CompilerType::cl;
} else {
return CompilerType::other;
}
Expand Down Expand Up @@ -850,8 +852,12 @@ to_cache(Context& ctx,
const Args& depend_extra_args,
Hash* depend_mode_hash)
{
args.push_back("-o");
args.push_back(ctx.args_info.output_obj);
if (ctx.config.compiler_type() == CompilerType::cl) {
args.push_back(fmt::format("-Fo{}", ctx.args_info.output_obj));
} else {
args.push_back("-o");
args.push_back(ctx.args_info.output_obj);
}

if (ctx.config.hard_link() && ctx.args_info.output_obj != "/dev/null") {
// Workaround for Clang bug where it overwrites an existing object file
Expand Down Expand Up @@ -930,9 +936,28 @@ to_cache(Context& ctx,
return nonstd::make_unexpected(Statistic::missing_cache_file);
}

// MSVC compiler always print the input file name to stdout,
// plus parts of the warnings/error messages.
// So we have to fusion that into stderr...
// Transform \r\n into \n. This way ninja won't produce empty newlines
// for the /showIncludes argument.
if (ctx.config.compiler_type() == CompilerType::cl) {
const std::string merged_output =
Util::read_file(tmp_stdout_path) + Util::read_file(tmp_stderr_path);
const std::string merged_output_with_unix_line_endings =
util::replace_all(merged_output, "\r\n", "\n");
try {
Util::write_file(tmp_stderr_path, merged_output_with_unix_line_endings);
} catch (const core::Error& e) {
LOG("Failed writing to {}: {}", tmp_stderr_path, e.what());
return nonstd::make_unexpected(Statistic::internal_error);
}
}

// distcc-pump outputs lines like this:
// __________Using # distcc servers in pump mode
if (st.size() != 0 && ctx.config.compiler_type() != CompilerType::pump) {
if (st.size() != 0 && ctx.config.compiler_type() != CompilerType::pump
&& ctx.config.compiler_type() != CompilerType::cl) {
LOG_RAW("Compiler produced stdout");
return nonstd::make_unexpected(Statistic::compiler_produced_stdout);
}
Expand Down
14 changes: 14 additions & 0 deletions src/compopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ const CompOpt compopts[] = {
{"-stdlib=", AFFECTS_CPP | TAKES_CONCAT_ARG},
{"-trigraphs", AFFECTS_CPP},
{"-u", TAKES_ARG | TAKES_CONCAT_ARG},
{"/AI", TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
{"/D", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG}, // msvc
{"/E", TOO_HARD}, // msvc
{"/EP", TOO_HARD}, // msvc
{"/FI", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
{"/FU", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
{"/I", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
{"/L", TAKES_ARG}, // msvc
{"/P", TOO_HARD}, // msvc
{"/U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG}, // msvc
{"/Yc", TAKES_ARG | TOO_HARD}, // msvc
{"/ZI", TOO_HARD}, // msvc
{"/Zi", TOO_HARD}, // msvc
{"/u", AFFECTS_CPP}, // msvc
};

static int
Expand Down
14 changes: 7 additions & 7 deletions unittest/test_Args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,44 +76,44 @@ TEST_CASE("Args::from_string")
CHECK(args[3] == "f");
}

TEST_CASE("Args::from_gcc_atfile")
TEST_CASE("Args::from_atfile")
{
TestContext test_context;

Args args;

SUBCASE("Nonexistent file")
{
CHECK(Args::from_gcc_atfile("at_file") == nonstd::nullopt);
CHECK(Args::from_atfile("at_file") == nonstd::nullopt);
}

SUBCASE("Empty")
{
Util::write_file("at_file", "");
args = *Args::from_gcc_atfile("at_file");
args = *Args::from_atfile("at_file");
CHECK(args.size() == 0);
}

SUBCASE("One argument without newline")
{
Util::write_file("at_file", "foo");
args = *Args::from_gcc_atfile("at_file");
args = *Args::from_atfile("at_file");
CHECK(args.size() == 1);
CHECK(args[0] == "foo");
}

SUBCASE("One argument with newline")
{
Util::write_file("at_file", "foo\n");
args = *Args::from_gcc_atfile("at_file");
args = *Args::from_atfile("at_file");
CHECK(args.size() == 1);
CHECK(args[0] == "foo");
}

SUBCASE("Multiple simple arguments")
{
Util::write_file("at_file", "x y z\n");
args = *Args::from_gcc_atfile("at_file");
args = *Args::from_atfile("at_file");
CHECK(args.size() == 3);
CHECK(args[0] == "x");
CHECK(args[1] == "y");
Expand All @@ -126,7 +126,7 @@ TEST_CASE("Args::from_gcc_atfile")
"at_file",
"first\rsec\\\tond\tthi\\\\rd\nfourth \tfif\\ th \"si'x\\\" th\""
" 'seve\nth'\\");
args = *Args::from_gcc_atfile("at_file");
args = *Args::from_atfile("at_file");
CHECK(args.size() == 7);
CHECK(args[0] == "first");
CHECK(args[1] == "sec\tond");
Expand Down

0 comments on commit 2214090

Please sign in to comment.