ccache.c mdfour.c hash.c execute.c util.c args.c stats.c version.c \
cleanup.c snprintf.c unify.c manifest.c hashtable.c hashtable_itr.c \
murmurhashneutral2.c hashutil.c getopt_long.c exitfn.c lockfile.c \
- counters.c language.c
+ counters.c language.c compopt.c
base_objs = $(base_sources:.c=.o)
ccache_sources = main.c $(base_sources)
*/
#include "ccache.h"
+#include "compopt.h"
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
the output of -E if they are going to have any effect at
all. For precompiled headers this might not be the case. */
if (!direct_mode && !output_is_precompiled_header) {
- if (i < args->argc-1) {
- if (str_eq(args->argv[i], "-D") ||
- str_eq(args->argv[i], "-I") ||
- str_eq(args->argv[i], "-U") ||
- str_eq(args->argv[i], "-idirafter") ||
- str_eq(args->argv[i], "-imacros") ||
- str_eq(args->argv[i], "-imultilib") ||
- str_eq(args->argv[i], "-include") ||
- str_eq(args->argv[i], "-iprefix") ||
- str_eq(args->argv[i], "-iquote") ||
- str_eq(args->argv[i], "-isysroot") ||
- str_eq(args->argv[i], "-isystem") ||
- str_eq(args->argv[i], "-iwithprefix") ||
- str_eq(args->argv[i], "-iwithprefixbefore") ||
- str_eq(args->argv[i], "-nostdinc") ||
- str_eq(args->argv[i], "-nostdinc++")) {
- /* Skip from hash. */
- i++;
- continue;
- }
+ if (compopt_affects_cpp(args->argv[i])) {
+ i++;
+ continue;
}
- if (str_startswith(args->argv[i], "-D") ||
- str_startswith(args->argv[i], "-I") ||
- str_startswith(args->argv[i], "-U")) {
- /* Skip from hash. */
+ if (compopt_short(compopt_affects_cpp, args->argv[i])) {
continue;
}
}
}
/* these are too hard */
- if (str_startswith(argv[i], "@") ||
- str_eq(argv[i], "--coverage") ||
- str_eq(argv[i], "-M") ||
- str_eq(argv[i], "-MM") ||
- str_eq(argv[i], "-fbranch-probabilities") ||
- str_eq(argv[i], "-fprofile-arcs") ||
- str_eq(argv[i], "-fprofile-generate") ||
- str_eq(argv[i], "-fprofile-use") ||
- str_eq(argv[i], "-frepo") ||
- str_eq(argv[i], "-ftest-coverage") ||
- str_eq(argv[i], "-save-temps")) {
+ if (compopt_too_hard(argv[i]) || str_startswith(argv[i], "@")) {
cc_log("Compiler option %s is unsupported", argv[i]);
stats_update(STATS_UNSUPPORTED);
result = false;
/* These are too hard in direct mode. */
if (enable_direct) {
- if (str_eq(argv[i], "-Xpreprocessor")) {
+ if (compopt_too_hard_for_direct_mode(argv[i])) {
cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
enable_direct = false;
}
* is that paths in the standard error output produced by the
* compiler will be normalized.
*/
- {
- const char *opts[] = {
- "-I", "-idirafter", "-imacros", "-include",
- "-iprefix", "-isystem", NULL
- };
- int j;
+ if (compopt_takes_path(argv[i])) {
char *relpath;
char *pchpath;
- for (j = 0; opts[j]; j++) {
- if (str_eq(argv[i], opts[j])) {
- if (i == argc-1) {
- cc_log("Missing argument to %s", argv[i]);
- stats_update(STATS_ARGS);
- result = false;
- goto out;
- }
-
- args_add(stripped_args, argv[i]);
- relpath = make_relative_path(x_strdup(argv[i+1]));
- args_add(stripped_args, relpath);
-
- /* Try to be smart about detecting precompiled headers */
- pchpath = format("%s.gch", argv[i+1]);
- if (stat(pchpath, &st) == 0) {
- found_pch = true;
- }
-
- free(pchpath);
- free(relpath);
- i++;
- break;
- }
+ if (i == argc-1) {
+ cc_log("Missing argument to %s", argv[i]);
+ stats_update(STATS_ARGS);
+ result = false;
+ goto out;
}
- if (opts[j]) {
- continue;
+
+ args_add(stripped_args, argv[i]);
+ relpath = make_relative_path(x_strdup(argv[i+1]));
+ args_add(stripped_args, relpath);
+
+ /* Try to be smart about detecting precompiled headers */
+ pchpath = format("%s.gch", argv[i+1]);
+ if (stat(pchpath, &st) == 0) {
+ found_pch = true;
}
+
+ free(pchpath);
+ free(relpath);
+ i++;
+ continue;
}
/* Same as above but options with concatenated argument. */
- {
- const char *opts[] = {"-I", NULL};
- int j;
+ if (compopt_short(compopt_takes_path, argv[i])) {
char *relpath;
char *option;
- for (j = 0; opts[j]; j++) {
- if (str_startswith(argv[i], opts[j])) {
- relpath = make_relative_path(x_strdup(argv[i] + strlen(opts[j])));
- option = format("%s%s", opts[j], relpath);
- args_add(stripped_args, option);
- free(relpath);
- free(option);
- break;
- }
- }
- if (opts[j]) {
- continue;
- }
+ relpath = make_relative_path(x_strdup(argv[i] + 2));
+ option = format("-%c%s", argv[i][1], relpath);
+ args_add(stripped_args, option);
+ free(relpath);
+ free(option);
+ continue;
}
/* options that take an argument */
- {
- const char *opts[] = {
- "--param",
- "-A",
- "-D",
- "-G",
- "-L",
- "-MF",
- "-MQ",
- "-MT",
- "-U",
- "-V",
- "-Xassembler",
- "-Xlinker",
- "-aux-info",
- "-b",
- "-install_name", /* Darwin linker option */
- "-iwithprefix",
- "-iwithprefixbefore",
- "-u",
- NULL
- };
- int j;
- for (j = 0; opts[j]; j++) {
- if (str_eq(argv[i], opts[j])) {
- if (i == argc-1) {
- cc_log("Missing argument to %s", argv[i]);
- stats_update(STATS_ARGS);
- result = false;
- goto out;
- }
-
- args_add(stripped_args, argv[i]);
- args_add(stripped_args, argv[i+1]);
- i++;
- break;
- }
+ 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;
}
- if (opts[j]) continue;
+ args_add(stripped_args, argv[i]);
+ args_add(stripped_args, argv[i+1]);
+ i++;
+ continue;
}
/* other options */
--- /dev/null
+/*
+ * Copyright (C) 2010 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
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ccache.h"
+#include "compopt.h"
+
+#define TOO_HARD (1 << 0)
+#define TOO_HARD_DIRECT (1 << 1)
+#define TAKES_ARG (1 << 2)
+#define TAKES_CONCAT_ARG (1 << 3)
+#define TAKES_PATH (1 << 4)
+#define AFFECTS_CPP (1 << 5)
+
+struct compopt {
+ const char *name;
+ int type;
+};
+
+static const struct compopt compopts[] = {
+ {"--coverage", TOO_HARD},
+ {"--param", TAKES_ARG},
+ {"-A", TAKES_ARG},
+ {"-D", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
+ {"-G", TAKES_ARG},
+ {"-I", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
+ {"-L", TAKES_ARG},
+ {"-M", TOO_HARD},
+ {"-MF", TAKES_ARG},
+ {"-MM", TOO_HARD},
+ {"-MQ", TAKES_ARG},
+ {"-MT", TAKES_ARG},
+ {"-U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
+ {"-V", TAKES_ARG},
+ {"-Xassembler", TAKES_ARG},
+ {"-Xlinker", TAKES_ARG},
+ {"-Xpreprocessor", TOO_HARD_DIRECT | TAKES_ARG},
+ {"-aux-info", TAKES_ARG},
+ {"-b", TAKES_ARG},
+ {"-fbranch-probabilities", TOO_HARD},
+ {"-fprofile-arcs", TOO_HARD},
+ {"-fprofile-generate", TOO_HARD},
+ {"-fprofile-use", TOO_HARD},
+ {"-frepo", TOO_HARD},
+ {"-ftest-coverage", TOO_HARD},
+ {"-idirafter", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-imacros", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-imultilib", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-include", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-install_name", TAKES_ARG}, /* Darwin linker option */
+ {"-iprefix", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-iquote", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-isysroot", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-isystem", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-iwithprefix", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-iwithprefixbefore", AFFECTS_CPP | TAKES_ARG | TAKES_PATH},
+ {"-nostdinc", AFFECTS_CPP},
+ {"-nostdinc++", AFFECTS_CPP},
+ {"-save-temps", TOO_HARD},
+ {"-u", TAKES_ARG},
+};
+
+static int
+compare_compopts(const void *key1, const void *key2)
+{
+ const struct compopt *opt1 = (const struct compopt *)key1;
+ const struct compopt *opt2 = (const struct compopt *)key2;
+ return strcmp(opt1->name, opt2->name);
+}
+
+static const struct compopt *
+find(const char *option)
+{
+ struct compopt key;
+ key.name = option;
+ return bsearch(
+ &key, compopts, sizeof(compopts) / sizeof(compopts[0]),
+ sizeof(compopts[0]), compare_compopts);
+}
+
+/* Runs fn on the first two characters of option. */
+bool
+compopt_short(bool (*fn)(const char *), const char *option)
+{
+ char *short_opt = x_strndup(option, 2);
+ bool retval = fn(short_opt);
+ free(short_opt);
+ return retval;
+}
+
+/* For test purposes. */
+bool
+compopt_verify_sortedness(void)
+{
+ size_t i;
+ for (i = 1; i < sizeof(compopts)/sizeof(compopts[0]); i++) {
+ if (strcmp(compopts[i-1].name, compopts[i].name) >= 0) {
+ fprintf(stderr,
+ "compopt_verify_sortedness: %s >= %s\n",
+ compopts[i-1].name,
+ compopts[i].name);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+compopt_affects_cpp(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & AFFECTS_CPP);
+}
+
+bool
+compopt_too_hard(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TOO_HARD);
+}
+
+bool
+compopt_too_hard_for_direct_mode(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TOO_HARD_DIRECT);
+}
+
+bool
+compopt_takes_path(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TAKES_PATH);
+}
+
+bool
+compopt_takes_arg(const char *option)
+{
+ const struct compopt *co = find(option);
+ return co && (co->type & TAKES_ARG);
+}
--- /dev/null
+#ifndef CCACHE_COMPOPT_H
+#define CCACHE_COMPOPT_H
+
+#include "system.h"
+
+bool compopt_short(bool (*fn)(const char *option), const char *option);
+bool compopt_affects_cpp(const char *option);
+bool compopt_too_hard(const char *option);
+bool compopt_too_hard_for_direct_mode(const char *option);
+bool compopt_takes_path(const char *option);
+bool compopt_takes_arg(const char *option);
+
+#endif /* CCACHE_COMPOPT_H */
headers = \
ccache.h hashtable.h hashtable_itr.h hashtable_private.h hashutil.h \
manifest.h mdfour.h counters.h murmurhashneutral2.h getopt_long.h \
- language.h system.h \
+ language.h system.h compopt.h \
test/framework.h test/suites.h test/util.h
files_to_clean += *.tar.bz2 *.tar.gz *.xml .deps/*
--- /dev/null
+/*
+ * Copyright (C) 2010 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
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This file contains tests for the compopt_* functions.
+ */
+
+#include "ccache.h"
+#include "compopt.h"
+#include "test/framework.h"
+
+TEST_SUITE(compopt)
+
+TEST(option_table_should_be_sorted)
+{
+ bool compopt_verify_sortedness();
+ CHECK(compopt_verify_sortedness());
+}
+
+TEST(dash_I_affects_cpp)
+{
+ CHECK(compopt_affects_cpp("-I"));
+ CHECK(!compopt_affects_cpp("-Ifoo"));
+}
+
+TEST(compopt_short)
+{
+ CHECK(compopt_short(compopt_affects_cpp, "-Ifoo"));
+ CHECK(!compopt_short(compopt_affects_cpp, "-include"));
+}
+
+TEST(dash_V_doesnt_affect_cpp)
+{
+ CHECK(!compopt_affects_cpp("-V"));
+}
+
+TEST(dash_doesnexist_doesnt_affect_cpp)
+{
+ CHECK(!compopt_affects_cpp("-doesntexist"));
+}
+
+TEST(dash_MM_too_hard)
+{
+ CHECK(compopt_too_hard("-MM"));
+}
+
+TEST(dash_MD_not_too_hard)
+{
+ CHECK(!compopt_too_hard("-MD"));
+}
+
+TEST(dash_doesnexist_not_too_hard)
+{
+ CHECK(!compopt_too_hard("-doesntexist"));
+}
+
+TEST(dash_Xpreprocessor_too_hard_for_direct_mode)
+{
+ CHECK(compopt_too_hard_for_direct_mode("-Xpreprocessor"));
+}
+
+TEST(dash_nostdinc_not_too_hard_for_direct_mode)
+{
+ CHECK(!compopt_too_hard_for_direct_mode("-nostdinc"));
+}
+
+TEST(dash_I_takes_path)
+{
+ CHECK(compopt_takes_path("-I"));
+}
+
+TEST(dash_Xlinker_takes_arg)
+{
+ CHECK(compopt_takes_arg("-Xlinker"));
+}
+
+TEST(dash_xxx_doesnt_take_arg)
+{
+ CHECK(!compopt_takes_arg("-xxx"));
+}
+
+TEST_SUITE_END