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