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…
  • Loading branch information
cristianadam committed Feb 11, 2021
1 parent 3c3fb22 commit 8e7e086
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,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 @@ -30,7 +30,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
19 changes: 14 additions & 5 deletions src/argprocessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ process_arg(Context& ctx,
}

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

Expand Down Expand Up @@ -364,11 +364,17 @@ process_arg(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 @@ -477,7 +483,8 @@ process_arg(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 @@ -790,7 +797,8 @@ process_arg(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 @@ -828,7 +836,8 @@ process_arg(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
67 changes: 64 additions & 3 deletions src/ccache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
#include <algorithm>
#include <cmath>
#include <limits>
#include <fstream>

#ifndef MYNAME
# define MYNAME "ccache"
Expand Down Expand Up @@ -342,6 +343,9 @@ 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
|| name.find("clang-cl") != nonstd::string_view::npos) {
return CompilerType::cl;
} else {
return CompilerType::other;
}
Expand Down Expand Up @@ -958,8 +962,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 @@ -1034,9 +1042,62 @@ to_cache(Context& ctx,
throw Failure(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) {
std::string tmp_stderr2 = fmt::format("{}.2", tmp_stderr_path);
Util::rename(tmp_stderr_path, tmp_stderr2);

std::ofstream result_stream;

std::vector<char> output_buffer(READ_BUFFER_SIZE);
result_stream.rdbuf()->pubsetbuf(output_buffer.data(), output_buffer.size());

result_stream.open(tmp_stderr_path, std::ios_base::binary);
if (!result_stream.is_open()) {
LOG("Failed opening {}: {}", tmp_stderr_path, strerror(errno));
throw Failure(Statistic::no_input_file);
}

std::ostreambuf_iterator<char> to(result_stream);
for (auto& file : {tmp_stdout_path, tmp_stderr2}) {
std::ifstream file_stream;

std::vector<char> read_buffer(READ_BUFFER_SIZE);
file_stream.rdbuf()->pubsetbuf(read_buffer.data(), read_buffer.size());

file_stream.open(file, std::ios_base::binary);
if (!file_stream.is_open()) {
LOG("Failed opening {}: {}", file, strerror(errno));
throw Failure(Statistic::no_input_file);
}

std::istreambuf_iterator<char> from(file_stream);
for (; from != std::istreambuf_iterator<char>(); ++from, ++to) {
if (*from != '\r') {
*to = *from;
} else if (++from != std::istreambuf_iterator<char>()) {
*to = (*from == '\n') ? '\n' : '\r';
}
}
}

result_stream.close();
if (!result_stream.good()) {
LOG("Failed at writing data into {}: {}", tmp_stderr_path, strerror(errno));
throw Failure(Statistic::bad_output_file);
}

Util::unlink_tmp(tmp_stderr2);
}

// 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");
throw Failure(Statistic::compiler_produced_stdout);
}
Expand Down
11 changes: 11 additions & 0 deletions src/compopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,17 @@ 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
{"/u", AFFECTS_CPP}, // msvc
};

static int
Expand Down

0 comments on commit 8e7e086

Please sign in to comment.