#include "hashutil.h"
#include "language.h"
#include "manifest.h"
-#include "unify.h"
#define STRINGIFY(x) #x
#define TO_STRING(x) STRINGIFY(x)
failed();
}
- if (conf->unify) {
- // When we are doing the unifying tricks we need to include the input file
- // name in the hash to get the warnings right.
- hash_delimiter(hash, "unifyfilename");
- hash_string(hash, input_file);
-
- hash_delimiter(hash, "unifycpp");
-
- bool debug_unify = getenv("CCACHE_DEBUG_UNIFY");
- if (unify_hash(hash, path_stdout, debug_unify) != 0) {
- stats_update(STATS_ERROR);
- cc_log("Failed to unify %s", path_stdout);
- failed();
- }
- } else {
- hash_delimiter(hash, "cpp");
- if (!process_preprocessed_file(hash, path_stdout,
- guessed_compiler == GUESSED_PUMP)) {
- stats_update(STATS_ERROR);
- failed();
- }
+ hash_delimiter(hash, "cpp");
+ if (!process_preprocessed_file(hash, path_stdout,
+ guessed_compiler == GUESSED_PUMP)) {
+ stats_update(STATS_ERROR);
+ failed();
}
hash_delimiter(hash, "cppstderr");
}
} // for
- if (generating_debuginfo && conf->unify) {
- cc_log("Generating debug info; disabling unify mode");
- conf->unify = false;
- }
-
if (generating_debuginfo_level_3 && !conf->run_second_cpp) {
cc_log("Generating debug info level 3; not compiling preprocessed code");
conf->run_second_cpp = true;
if (conf->depend_mode
&& (!generating_dependencies || str_eq(output_dep, "/dev/null")
- || !conf->run_second_cpp || conf->unify)) {
+ || !conf->run_second_cpp)) {
cc_log("Disabling depend mode");
conf->depend_mode = false;
}
+++ /dev/null
-// Copyright (C) 2002 Andrew Tridgell
-// Copyright (C) 2009-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
-// 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
-
-// C/C++ unifier
-//
-// The idea is that changes that don't affect the resulting C code should not
-// change the hash. This is achieved by folding white-space and other
-// non-semantic fluff in the input into a single unified format.
-//
-// This unifier was design to match the output of the unifier in compilercache,
-// which is flex based. The major difference is that this unifier is much
-// faster (about 2x) and more forgiving of syntactic errors. Continuing on
-// syntactic errors is important to cope with C/C++ extensions in the local
-// compiler (for example, inline assembly systems).
-
-#include "ccache.h"
-#include "hash.h"
-#include "unify.h"
-
-static bool print_unified = true;
-
-static const char *const s_tokens[] = {
- "...", ">>=", "<<=", "+=", "-=", "*=", "/=", "%=", "&=", "^=",
- "|=", ">>", "<<", "++", "--", "->", "&&", "||", "<=", ">=",
- "==", "!=", ";", "{", "<%", "}", "%>", ",", ":", "=",
- "(", ")", "[", "<:", "]", ":>", ".", "&", "!", "~",
- "-", "+", "*", "/", "%", "<", ">", "^", "|", "?",
- 0
-};
-
-#define C_ALPHA 1
-#define C_SPACE 2
-#define C_TOKEN 4
-#define C_QUOTE 8
-#define C_DIGIT 16
-#define C_HEX 32
-#define C_FLOAT 64
-#define C_SIGN 128
-
-static struct {
- unsigned char type;
- unsigned char num_toks;
- const char *toks[7];
-} tokens[256];
-
-// Build up the table used by the unifier.
-static void
-build_table(void)
-{
- static bool done;
- if (done) {
- return;
- }
- done = true;
-
- memset(tokens, 0, sizeof(tokens));
- for (unsigned char c = 0; c < 128; c++) {
- if (isalpha(c) || c == '_') {
- tokens[c].type |= C_ALPHA;
- }
- if (isdigit(c)) {
- tokens[c].type |= C_DIGIT;
- }
- if (isspace(c)) {
- tokens[c].type |= C_SPACE;
- }
- if (isxdigit(c)) {
- tokens[c].type |= C_HEX;
- }
- }
- tokens['\''].type |= C_QUOTE;
- tokens['"'].type |= C_QUOTE;
- tokens['l'].type |= C_FLOAT;
- tokens['L'].type |= C_FLOAT;
- tokens['f'].type |= C_FLOAT;
- tokens['F'].type |= C_FLOAT;
- tokens['U'].type |= C_FLOAT;
- tokens['u'].type |= C_FLOAT;
-
- tokens['-'].type |= C_SIGN;
- tokens['+'].type |= C_SIGN;
-
- for (int i = 0; s_tokens[i]; i++) {
- unsigned char c = s_tokens[i][0];
- tokens[c].type |= C_TOKEN;
- tokens[c].toks[tokens[c].num_toks] = s_tokens[i];
- tokens[c].num_toks++;
- }
-}
-
-// Buffer up characters before hashing them.
-static void
-pushchar(struct hash *hash, unsigned char c)
-{
- static unsigned char buf[64];
- static size_t len;
-
- if (c == 0) {
- if (len > 0) {
- hash_buffer(hash, (char *)buf, len);
- if (print_unified) {
- printf("%.*s", (int) len, buf);
- }
- len = 0;
- }
- return;
- }
-
- buf[len++] = c;
- if (len == 64) {
- hash_buffer(hash, (char *)buf, len);
- if (print_unified) {
- printf("%.*s", (int) len, buf);
- }
- len = 0;
- }
-}
-
-// Hash some C/C++ code after unifying.
-static void
-unify(struct hash *hash, unsigned char *p, size_t size)
-{
- build_table();
-
- for (size_t ofs = 0; ofs < size;) {
- if (p[ofs] == '#') {
- if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) {
- do {
- ofs++;
- } while (ofs < size && p[ofs] != '\n');
- ofs++;
- } else {
- do {
- pushchar(hash, p[ofs]);
- ofs++;
- } while (ofs < size && p[ofs] != '\n');
- pushchar(hash, '\n');
- ofs++;
- }
- continue;
- }
-
- if (tokens[p[ofs]].type & C_ALPHA) {
- do {
- pushchar(hash, p[ofs]);
- ofs++;
- } while (ofs < size && (tokens[p[ofs]].type & (C_ALPHA|C_DIGIT)));
- pushchar(hash, '\n');
- continue;
- }
-
- if (tokens[p[ofs]].type & C_DIGIT) {
- do {
- pushchar(hash, p[ofs]);
- ofs++;
- } while (ofs < size &&
- ((tokens[p[ofs]].type & C_DIGIT) || p[ofs] == '.'));
- if (ofs < size && (p[ofs] == 'x' || p[ofs] == 'X')) {
- do {
- pushchar(hash, p[ofs]);
- ofs++;
- } while (ofs < size && (tokens[p[ofs]].type & C_HEX));
- }
- if (ofs < size && (p[ofs] == 'E' || p[ofs] == 'e')) {
- pushchar(hash, p[ofs]);
- ofs++;
- while (ofs < size && (tokens[p[ofs]].type & (C_DIGIT|C_SIGN))) {
- pushchar(hash, p[ofs]);
- ofs++;
- }
- }
- while (ofs < size && (tokens[p[ofs]].type & C_FLOAT)) {
- pushchar(hash, p[ofs]);
- ofs++;
- }
- pushchar(hash, '\n');
- continue;
- }
-
- if (tokens[p[ofs]].type & C_SPACE) {
- do {
- ofs++;
- } while (ofs < size && (tokens[p[ofs]].type & C_SPACE));
- continue;
- }
-
- if (tokens[p[ofs]].type & C_QUOTE) {
- unsigned char q = p[ofs];
- pushchar(hash, p[ofs]);
- do {
- ofs++;
- while (ofs < size-1 && p[ofs] == '\\') {
- pushchar(hash, p[ofs]);
- pushchar(hash, p[ofs+1]);
- ofs += 2;
- }
- pushchar(hash, p[ofs]);
- } while (ofs < size && p[ofs] != q);
- pushchar(hash, '\n');
- ofs++;
- continue;
- }
-
- if (tokens[p[ofs]].type & C_TOKEN) {
- unsigned char q = p[ofs];
- int i;
- for (i = 0; i < tokens[q].num_toks; i++) {
- const unsigned char *s = (const unsigned char *)tokens[q].toks[i];
- int len = strlen((const char *)s);
- if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) {
- int j;
- for (j = 0; s[j]; j++) {
- pushchar(hash, s[j]);
- ofs++;
- }
- pushchar(hash, '\n');
- break;
- }
- }
- if (i < tokens[q].num_toks) {
- continue;
- }
- }
-
- pushchar(hash, p[ofs]);
- pushchar(hash, '\n');
- ofs++;
- }
- pushchar(hash, 0);
-}
-
-
-// Hash a file that consists of preprocessor output, but remove any line number
-// information from the hash.
-int
-unify_hash(struct hash *hash, const char *fname, bool debug)
-{
- char *data;
- size_t size;
- if (!read_file(fname, 0, &data, &size)) {
- stats_update(STATS_PREPROCESSOR);
- return -1;
- }
- print_unified = debug;
- unify(hash, (unsigned char *)data, size);
- free(data);
- return 0;
-}