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 Jan 23, 2020
1 parent 2482434 commit 7470f8c
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/Util.cpp
Expand Up @@ -81,7 +81,7 @@ base_name(string_view path)
size_t n = path.rfind('/');
#ifdef _WIN32
size_t n2 = path.rfind('\\');
if (n2 != std::string::npos && n2 > n) {
if (n2 != std::string::npos && (n == std::string::npos || n2 > n)) {
n = n2;
}
#endif
Expand Down
103 changes: 93 additions & 10 deletions src/ccache.cpp
Expand Up @@ -568,14 +568,19 @@ guess_compiler(const char* path)
{
string_view name = Util::base_name(path);
enum guessed_compiler result = GUESSED_UNKNOWN;
if (name == "clang") {
if (name == "clang" || name == "clang.exe" ||
name == "clang++" || name == "clang++.exe") {
result = GUESSED_CLANG;
} else if (name == "gcc" || name == "g++") {
} else if (name == "gcc" || name == "gcc.exe" ||
name == "g++" || name == "g++.exe") {
result = GUESSED_GCC;
} else if (name == "nvcc") {
result = GUESSED_NVCC;
} else if (name == "pump" || name == "distcc-pump") {
result = GUESSED_PUMP;
} else if (name == "cl" || name == "cl.exe" ||
name == "clang-cl" || name == "clang-cl.exe") {
result = GUESSED_MSVC;
}
return result;
}
Expand Down Expand Up @@ -1289,8 +1294,14 @@ create_cachedir_tag(const std::string& dir)
static void
to_cache(struct args* args, struct hash* depend_mode_hash)
{
args_add(args, "-o");
args_add(args, output_obj);
if (guessed_compiler == GUESSED_MSVC) {
char *fo = format("-Fo%s", output_obj);
args_add(args, fo);
free(fo);
} else {
args_add(args, "-o");
args_add(args, output_obj);
}

if (g_config.hard_link()) {
// Workaround for Clang bug where it overwrites an existing object file
Expand Down Expand Up @@ -1375,9 +1386,72 @@ to_cache(struct args* args, struct hash* depend_mode_hash)
failed();
}

// 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 (guessed_compiler == GUESSED_MSVC) {
char *tmp_stderr2 = format("%s.2", tmp_stderr);
if (x_rename(tmp_stderr, tmp_stderr2)) {
cc_log("Failed to rename %s to %s: %s", tmp_stderr, tmp_stderr2,
strerror(errno));
stats_update(STATS_ERROR);
failed();
}

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, std::ios_base::binary);
if (!result_stream.is_open()) {
cc_log("Failed opening %s: %s", tmp_stderr, strerror(errno));
stats_update(STATS_ERROR);
failed();
}

std::ostreambuf_iterator<char> to(result_stream);
for (char* file : {tmp_stdout, 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()) {
cc_log("Failed opening %s: %s", file, strerror(errno));
stats_update(STATS_ERROR);
failed();
}

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()) {
cc_log("Failed at writing data into %s: %s", tmp_stderr, strerror(errno));
stats_update(STATS_ERROR);
failed();
}

tmp_unlink(tmp_stderr2);
free(tmp_stderr2);
}

// distcc-pump outputs lines like this:
// __________Using # distcc servers in pump mode
if (st.size() != 0 && guessed_compiler != GUESSED_PUMP) {
if (st.size() != 0 &&
guessed_compiler != GUESSED_PUMP &&
guessed_compiler != GUESSED_MSVC) {
cc_log("Compiler produced stdout");
stats_update(STATS_STDOUT);
tmp_unlink(tmp_stdout);
Expand Down Expand Up @@ -2455,7 +2529,7 @@ cc_process_args(struct args* args,
}

// Special case for -E.
if (str_eq(argv[i], "-E")) {
if (str_eq(argv[i], "-E") || str_eq(argv[i], "/E")) {
stats_update(STATS_PREPROCESSING);
result = false;
goto out;
Expand Down Expand Up @@ -2618,7 +2692,7 @@ cc_process_args(struct args* args,
}

// We must have -c.
if (str_eq(argv[i], "-c")) {
if (str_eq(argv[i], "-c") || str_eq(argv[i], "/c")) {
found_c_opt = true;
continue;
}
Expand Down Expand Up @@ -2678,6 +2752,12 @@ cc_process_args(struct args* args,
continue;
}

// MSVC /Fo with no space.
if (str_startswith(argv[i], "/Fo") && guessed_compiler == GUESSED_MSVC) {
output_obj = make_relative_path(x_strdup(&argv[i][3]));
continue;
}

if (str_startswith(argv[i], "-fdebug-prefix-map=")
|| str_startswith(argv[i], "-ffile-prefix-map=")) {
debug_prefix_maps = static_cast<char**>(x_realloc(
Expand Down Expand Up @@ -2724,7 +2804,8 @@ cc_process_args(struct args* args,

// These options require special handling, because they behave differently
// with gcc -E, when the output file is not specified.
if (str_eq(argv[i], "-MD") || str_eq(argv[i], "-MMD")) {
if ((str_eq(argv[i], "-MD") || str_eq(argv[i], "-MMD")) &&
guessed_compiler != GUESSED_MSVC) {
generating_dependencies = true;
args_add(dep_args, argv[i]);
continue;
Expand Down Expand Up @@ -3068,7 +3149,8 @@ cc_process_args(struct args* args,

// Same as above but options with concatenated argument beginning with a
// slash.
if (argv[i][0] == '-') {
if (argv[i][0] == '-' ||
(guessed_compiler == GUESSED_MSVC && argv[i][0] == '/')) {
char* slash_pos = strchr(argv[i], '/');
if (slash_pos) {
char* option = x_strndup(argv[i], slash_pos - argv[i]);
Expand Down Expand Up @@ -3112,7 +3194,8 @@ cc_process_args(struct args* args,
}

// Other options.
if (argv[i][0] == '-') {
if (argv[i][0] == '-' ||
(guessed_compiler == GUESSED_MSVC && argv[i][0] == '/')) {
if (compopt_affects_cpp(argv[i]) || compopt_prefix_affects_cpp(argv[i])) {
args_add(cpp_args, argv[i]);
} else {
Expand Down
1 change: 1 addition & 0 deletions src/ccache.hpp
Expand Up @@ -87,6 +87,7 @@ enum guessed_compiler {
GUESSED_GCC,
GUESSED_NVCC,
GUESSED_PUMP,
GUESSED_MSVC,
GUESSED_UNKNOWN
};

Expand Down
11 changes: 11 additions & 0 deletions src/compopt.cpp
Expand Up @@ -128,6 +128,17 @@ static const struct 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 7470f8c

Please sign in to comment.