Imported Upstream version 3.5
[platform/upstream/ccache.git] / src / compopt.c
1 // Copyright (C) 2010-2018 Joel Rosdahl
2 //
3 // This program is free software; you can redistribute it and/or modify it
4 // under the terms of the GNU General Public License as published by the Free
5 // Software Foundation; either version 3 of the License, or (at your option)
6 // any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but WITHOUT
9 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 // more details.
12 //
13 // You should have received a copy of the GNU General Public License along with
14 // this program; if not, write to the Free Software Foundation, Inc., 51
15 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17 #include "ccache.h"
18 #include "compopt.h"
19
20 #define TOO_HARD         (1 << 0)
21 #define TOO_HARD_DIRECT  (1 << 1)
22 #define TAKES_ARG        (1 << 2)
23 #define TAKES_CONCAT_ARG (1 << 3)
24 #define TAKES_PATH       (1 << 4)
25 #define AFFECTS_CPP      (1 << 5)
26
27 struct compopt {
28         const char *name;
29         int type;
30 };
31
32 static const struct compopt compopts[] = {
33         {"--compiler-bindir", AFFECTS_CPP | TAKES_ARG}, // nvcc
34         {"--libdevice-directory", AFFECTS_CPP | TAKES_ARG}, // nvcc
35         {"--output-directory", AFFECTS_CPP | TAKES_ARG}, // nvcc
36         {"--param",         TAKES_ARG},
37         {"--save-temps",    TOO_HARD},
38         {"--save-temps=cwd", TOO_HARD},
39         {"--save-temps=obj", TOO_HARD},
40         {"--serialize-diagnostics", TAKES_ARG | TAKES_PATH},
41         {"-A",              TAKES_ARG},
42         {"-B",              TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
43         {"-D",              AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
44         {"-E",              TOO_HARD},
45         {"-F",              AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
46         {"-G",              TAKES_ARG},
47         {"-I",              AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
48         {"-L",              TAKES_ARG},
49         {"-M",              TOO_HARD},
50         {"-MF",             TAKES_ARG},
51         {"-MJ",             TAKES_ARG | TOO_HARD},
52         {"-MM",             TOO_HARD},
53         {"-MQ",             TAKES_ARG},
54         {"-MT",             TAKES_ARG},
55         {"-P",              TOO_HARD},
56         {"-U",              AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG},
57         {"-V",              TAKES_ARG},
58         {"-Xassembler",     TAKES_ARG},
59         {"-Xclang",         TAKES_ARG},
60         {"-Xlinker",        TAKES_ARG},
61         {"-Xpreprocessor",  AFFECTS_CPP | TOO_HARD_DIRECT | TAKES_ARG},
62         {"-arch",           TAKES_ARG},
63         {"-aux-info",       TAKES_ARG},
64         {"-b",              TAKES_ARG},
65         {"-ccbin",          AFFECTS_CPP | TAKES_ARG}, // nvcc
66         {"-fmodules",       TOO_HARD},
67         {"-fno-working-directory", AFFECTS_CPP},
68         {"-fplugin=libcc1plugin", TOO_HARD}, // interaction with GDB
69         {"-frepo",          TOO_HARD},
70         {"-fworking-directory", AFFECTS_CPP},
71         {"-idirafter",      AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
72         {"-iframework",     AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
73         {"-imacros",        AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
74         {"-imultilib",      AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
75         {"-include",        AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
76         {"-include-pch",    AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
77         {"-install_name",   TAKES_ARG}, // Darwin linker option
78         {"-iprefix",        AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
79         {"-iquote",         AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
80         {"-isysroot",       AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
81         {"-isystem",        AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
82         {"-iwithprefix",    AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
83         {"-iwithprefixbefore",
84          AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
85         {"-ldir",           AFFECTS_CPP | TAKES_ARG}, // nvcc
86         {"-nostdinc",       AFFECTS_CPP},
87         {"-nostdinc++",     AFFECTS_CPP},
88         {"-odir",           AFFECTS_CPP | TAKES_ARG}, // nvcc
89         {"-remap",          AFFECTS_CPP},
90         {"-save-temps",     TOO_HARD},
91         {"-save-temps=cwd", TOO_HARD},
92         {"-save-temps=obj", TOO_HARD},
93         {"-stdlib=",        AFFECTS_CPP | TAKES_CONCAT_ARG},
94         {"-trigraphs",      AFFECTS_CPP},
95         {"-u",              TAKES_ARG | TAKES_CONCAT_ARG},
96 };
97
98
99 static int
100 compare_compopts(const void *key1, const void *key2)
101 {
102         const struct compopt *opt1 = (const struct compopt *)key1;
103         const struct compopt *opt2 = (const struct compopt *)key2;
104         return strcmp(opt1->name, opt2->name);
105 }
106
107 static int
108 compare_prefix_compopts(const void *key1, const void *key2)
109 {
110         const struct compopt *opt1 = (const struct compopt *)key1;
111         const struct compopt *opt2 = (const struct compopt *)key2;
112         return strncmp(opt1->name, opt2->name, strlen(opt2->name));
113 }
114
115 static const struct compopt *
116 find(const char *option)
117 {
118         struct compopt key;
119         key.name = option;
120         return bsearch(
121                 &key, compopts, ARRAY_SIZE(compopts), sizeof(compopts[0]),
122                 compare_compopts);
123 }
124
125 static const struct compopt *
126 find_prefix(const char *option)
127 {
128         struct compopt key;
129         key.name = option;
130         return bsearch(
131                 &key, compopts, ARRAY_SIZE(compopts), sizeof(compopts[0]),
132                 compare_prefix_compopts);
133 }
134
135 // Runs fn on the first two characters of option.
136 bool
137 compopt_short(bool (*fn)(const char *), const char *option)
138 {
139         char *short_opt = x_strndup(option, 2);
140         bool retval = fn(short_opt);
141         free(short_opt);
142         return retval;
143 }
144
145 // Used by unittest/test_compopt.c.
146 bool compopt_verify_sortedness(void);
147
148 // For test purposes.
149 bool
150 compopt_verify_sortedness(void)
151 {
152         for (size_t i = 1; i < ARRAY_SIZE(compopts); i++) {
153                 if (strcmp(compopts[i-1].name, compopts[i].name) >= 0) {
154                         fprintf(stderr,
155                                 "compopt_verify_sortedness: %s >= %s\n",
156                                 compopts[i-1].name,
157                                 compopts[i].name);
158                         return false;
159                 }
160         }
161         return true;
162 }
163
164 bool
165 compopt_affects_cpp(const char *option)
166 {
167         const struct compopt *co = find(option);
168         return co && (co->type & AFFECTS_CPP);
169 }
170
171 bool
172 compopt_too_hard(const char *option)
173 {
174         const struct compopt *co = find(option);
175         return co && (co->type & TOO_HARD);
176 }
177
178 bool
179 compopt_too_hard_for_direct_mode(const char *option)
180 {
181         const struct compopt *co = find(option);
182         return co && (co->type & TOO_HARD_DIRECT);
183 }
184
185 bool
186 compopt_takes_path(const char *option)
187 {
188         const struct compopt *co = find(option);
189         return co && (co->type & TAKES_PATH);
190 }
191
192 bool
193 compopt_takes_arg(const char *option)
194 {
195         const struct compopt *co = find(option);
196         return co && (co->type & TAKES_ARG);
197 }
198
199 bool
200 compopt_takes_concat_arg(const char *option)
201 {
202         const struct compopt *co = find(option);
203         return co && (co->type & TAKES_CONCAT_ARG);
204 }
205
206 // Determines if the prefix of the option matches any option and affects the
207 // preprocessor.
208 bool
209 compopt_prefix_affects_cpp(const char *option)
210 {
211         // Prefix options have to take concatentated args.
212         const struct compopt *co = find_prefix(option);
213         return co && (co->type & TAKES_CONCAT_ARG) && (co->type & AFFECTS_CPP);
214 }