// used as a temporary data structure to loop over.
struct args *expanded_args = args_copy(args);
- // common_args essentially contains all original arguments except those that
- // only should be passed to the preprocessor (if run_second_cpp is false) and
- // except dependency options (like -MD and friends).
+ // common_args contains all original arguments except:
+ // * those that never should be passed to the preprocessor,
+ // * those that only should be passed to the preprocessor (if run_second_cpp
+ // is false), and
+ // * dependency options (like -MD and friends).
struct args *common_args = args_init(0, NULL);
// cpp_args contains arguments that were not added to common_args, i.e. those
// If run_second_cpp is true, they will be passed to the compiler as well.
struct args *cpp_args = args_init(0, NULL);
- // dep_args contains dependency options like -MD. They only passed to the
+ // dep_args contains dependency options like -MD. They are only passed to the
// preprocessor, never to the compiler.
struct args *dep_args = args_init(0, NULL);
- bool found_color_diagnostics = false;
+ // compiler_only_args contains arguments that should only be passed to the
+ // compiler, not the preprocessor.
+ struct args *compiler_only_args = args_init(0, NULL);
+ bool found_color_diagnostics = false;
bool found_directives_only = false;
bool found_rewrite_includes = false;
continue;
}
+ // Handle options that should not be passed to the preprocessor.
+ if (compopt_affects_comp(argv[i])) {
+ args_add(compiler_only_args, argv[i]);
+ if (compopt_takes_arg(argv[i])) {
+ if (i == argc - 1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
+ }
+ args_add(compiler_only_args, argv[i + 1]);
+ ++i;
+ }
+ continue;
+ }
+ if (compopt_prefix_affects_comp(argv[i])) {
+ args_add(compiler_only_args, argv[i]);
+ continue;
+ }
+
if (str_eq(argv[i], "-fpch-preprocess")
|| str_eq(argv[i], "-emit-pch")
|| str_eq(argv[i], "-emit-pth")) {
}
*compiler_args = args_copy(common_args);
+ args_extend(*compiler_args, compiler_only_args);
+
if (conf->run_second_cpp) {
args_extend(*compiler_args, cpp_args);
} else if (found_directives_only || found_rewrite_includes) {
#include "ccache.h"
#include "compopt.h"
+// The option it too hard to handle at all.
#define TOO_HARD (1 << 0)
+
+// The option it too hard for the direct mode.
#define TOO_HARD_DIRECT (1 << 1)
+
+// The option takes a separate argument, e.g. "-D FOO=1".
#define TAKES_ARG (1 << 2)
+
+// The option takes a concatenated argument, e.g. "-DFOO=1".
#define TAKES_CONCAT_ARG (1 << 3)
+
+// The argument to the option is a path that may be rewritten if base_dir is
+// used.
#define TAKES_PATH (1 << 4)
+
+// The option only affects preprocessing; not passed to the compiler if
+// run_second_cpp is false.
#define AFFECTS_CPP (1 << 5)
+// The option only affects compilation; not passed to the preprocesor.
+#define AFFECTS_COMP (1 << 6)
+
struct compopt {
const char *name;
int type;
{"-P", TOO_HARD},
{"-U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
{"-V", TAKES_ARG},
- {"-Xassembler", TAKES_ARG},
+ {"-Wa,", TAKES_CONCAT_ARG | AFFECTS_COMP},
+ {"-Werror", AFFECTS_COMP}, // don't exit with error when preprocessing
+ {"-Wl,", TAKES_CONCAT_ARG | AFFECTS_COMP},
+ {"-Xassembler", TAKES_ARG | TAKES_CONCAT_ARG | AFFECTS_COMP},
{"-Xclang", TAKES_ARG},
- {"-Xlinker", TAKES_ARG},
+ {"-Xlinker", TAKES_ARG | TAKES_CONCAT_ARG | AFFECTS_COMP},
{"-Xpreprocessor", AFFECTS_CPP | TOO_HARD_DIRECT | TAKES_ARG},
+ {"-all_load", AFFECTS_COMP},
{"-analyze", TOO_HARD}, // clang
{"-arch", TAKES_ARG},
{"-aux-info", TAKES_ARG},
{"-b", TAKES_ARG},
+ {"-bind_at_load", AFFECTS_COMP},
+ {"-bundle", AFFECTS_COMP},
{"-ccbin", AFFECTS_CPP | TAKES_ARG}, // nvcc
{"-fmodules", TOO_HARD},
{"-fno-working-directory", AFFECTS_CPP},
{"-iwithprefixbefore",
AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
{"-ldir", AFFECTS_CPP | TAKES_ARG}, // nvcc
+ {"-nolibc", AFFECTS_COMP},
{"-nostdinc", AFFECTS_CPP},
{"-nostdinc++", AFFECTS_CPP},
{"-odir", AFFECTS_CPP | TAKES_ARG}, // nvcc
+ {"-pie", AFFECTS_COMP},
+ {"-prebind", AFFECTS_COMP},
+ {"-preload", AFFECTS_COMP},
+ {"-rdynamic", AFFECTS_COMP},
{"-remap", AFFECTS_CPP},
{"-save-temps", TOO_HARD},
{"-save-temps=cwd", TOO_HARD},
return co && (co->type & AFFECTS_CPP);
}
+bool
+compopt_affects_comp(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & AFFECTS_COMP);
+}
+
bool
compopt_too_hard(const char *option)
{
const struct compopt *co = find_prefix(option);
return co && (co->type & TAKES_CONCAT_ARG) && (co->type & AFFECTS_CPP);
}
+
+// Determines if the prefix of the option matches any option and affects the
+// preprocessor.
+bool
+compopt_prefix_affects_comp(const char *option)
+{
+ // Prefix options have to take concatenated args.
+ const struct compopt *co = find_prefix(option);
+ return co && (co->type & TAKES_CONCAT_ARG) && (co->type & AFFECTS_COMP);
+}
-// Copyright (C) 2010-2018 Joel Rosdahl
+// Copyright (C) 2010-2019 Joel Rosdahl
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
args_free(orig);
}
+TEST(options_not_to_be_passed_to_the_preprocesor)
+{
+ struct args *orig = args_init_from_string(
+ "cc -Wa,foo foo.c -g -Xlinker fie -Xlinker,fum -c -Werror");
+ struct args *exp_cpp = args_init_from_string("cc -g");
+ struct args *exp_cc = args_init_from_string(
+ "cc -g -Wa,foo -Xlinker fie -Xlinker,fum -Werror -c");
+ struct args *act_cpp = NULL;
+ struct args *act_cc = NULL;
+
+ create_file("foo.c", "");
+ CHECK(cc_process_args(orig, &act_cpp, &act_cc));
+ CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+ CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+ args_free(orig);
+}
+
TEST_SUITE_END