Imported Upstream version 3.3.5
[platform/upstream/ccache.git] / test / test_argument_processing.c
1 // Copyright (C) 2010-2017 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 // This file contains tests for the processing of compiler arguments.
18
19 #include "../ccache.h"
20 #include "../conf.h"
21 #include "framework.h"
22 #include "util.h"
23
24 extern struct conf *conf;
25
26 static char *
27 get_root(void)
28 {
29 #ifndef _WIN32
30         return x_strdup("/");
31 #else
32         char volume[4]; // "C:\"
33         GetVolumePathName(get_cwd(), volume, sizeof(volume));
34         return x_strdup(volume);
35 #endif
36 }
37
38 static char *
39 get_posix_path(char *path)
40 {
41 #ifndef _WIN32
42         return x_strdup(path);
43 #else
44         char *posix;
45         char *p;
46
47         // /-escape volume.
48         if (path[0] >= 'A' && path[0] <= 'Z' && path[1] == ':') {
49                 posix = format("/%s", path);
50         } else {
51                 posix = x_strdup(path);
52         }
53         // Convert slashes.
54         for (p = posix; *p; p++) {
55                 if (*p == '\\') {
56                         *p = '/';
57                 }
58         }
59         return posix;
60 #endif
61 }
62
63 TEST_SUITE(argument_processing)
64
65 TEST(dash_E_should_result_in_called_for_preprocessing)
66 {
67         struct args *orig = args_init_from_string("cc -c foo.c -E");
68         struct args *preprocessed, *compiler;
69
70         create_file("foo.c", "");
71         CHECK(!cc_process_args(orig, &preprocessed, &compiler));
72         CHECK_INT_EQ(1, stats_get_pending(STATS_PREPROCESSING));
73
74         args_free(orig);
75 }
76
77 TEST(dash_M_should_be_unsupported)
78 {
79         struct args *orig = args_init_from_string("cc -c foo.c -M");
80         struct args *preprocessed, *compiler;
81
82         create_file("foo.c", "");
83         CHECK(!cc_process_args(orig, &preprocessed, &compiler));
84         CHECK_INT_EQ(1, stats_get_pending(STATS_UNSUPPORTED_OPTION));
85
86         args_free(orig);
87 }
88
89 TEST(dependency_flags_should_only_be_sent_to_the_preprocessor)
90 {
91 #define CMD \
92         "cc -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2" \
93         " -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
94         struct args *orig = args_init_from_string(CMD " -c foo.c -o foo.o");
95         struct args *exp_cpp = args_init_from_string(CMD);
96 #undef CMD
97         struct args *exp_cc = args_init_from_string("cc -c");
98         struct args *act_cpp = NULL, *act_cc = NULL;
99         create_file("foo.c", "");
100
101         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
102         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
103         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
104
105         args_free(orig);
106 }
107
108 TEST(cpp_only_flags_to_preprocessor_if_run_second_cpp_is_false)
109 {
110 #define CMD \
111         "cc -I. -idirafter . -iframework. -imacros . -imultilib ." \
112         " -include test.h -include-pch test.pch -iprefix . -iquote ." \
113         " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ." \
114         " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory" \
115         " -fno-working-directory -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2" \
116         " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt" \
117         " -Wp,-MQ,wpmq -Wp,-MF,wpf"
118         struct args *orig = args_init_from_string(CMD " -c foo.c -o foo.o");
119         struct args *exp_cpp = args_init_from_string(CMD);
120 #undef CMD
121         struct args *exp_cc = args_init_from_string("cc -c");
122         struct args *act_cpp = NULL, *act_cc = NULL;
123         create_file("foo.c", "");
124
125         conf->run_second_cpp = false;
126         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
127         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
128         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
129
130         args_free(orig);
131 }
132
133 TEST(cpp_only_flags_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
134 {
135 #define CMD \
136         "cc -I. -idirafter . -iframework. -imacros . -imultilib ." \
137         " -include test.h -include-pch test.pch -iprefix . -iquote ." \
138         " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ." \
139         " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory" \
140         " -fno-working-directory"
141 #define DEP_OPTS \
142         " -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 " \
143         " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd"
144         struct args *orig = args_init_from_string(CMD DEP_OPTS " -c foo.c -o foo.o");
145         struct args *exp_cpp = args_init_from_string(CMD DEP_OPTS);
146         struct args *exp_cc = args_init_from_string(CMD " -c");
147 #undef CMD
148         struct args *act_cpp = NULL, *act_cc = NULL;
149         create_file("foo.c", "");
150
151         conf->run_second_cpp = true;
152         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
153         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
154         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
155
156         args_free(orig);
157 }
158
159 TEST(dependency_flags_that_take_an_argument_should_not_require_space_delimiter)
160 {
161         struct args *orig = args_init_from_string(
162           "cc -c -MMD -MFfoo.d -MT mt -MTmt -MQmq foo.c -o foo.o");
163         struct args *exp_cpp = args_init_from_string(
164           "cc -MMD -MFfoo.d -MT mt -MTmt -MQmq");
165         struct args *exp_cc = args_init_from_string("cc -c");
166         struct args *act_cpp = NULL, *act_cc = NULL;
167         create_file("foo.c", "");
168
169         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
170         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
171         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
172
173         args_free(orig);
174 }
175
176 TEST(sysroot_should_be_rewritten_if_basedir_is_used)
177 {
178         extern char *current_working_dir;
179         char *arg_string;
180         struct args *orig;
181         struct args *act_cpp = NULL, *act_cc = NULL;
182
183         create_file("foo.c", "");
184         free(conf->base_dir);
185         conf->base_dir = get_root();
186         current_working_dir = get_cwd();
187         arg_string = format("cc --sysroot=%s/foo -c foo.c", current_working_dir);
188         orig = args_init_from_string(arg_string);
189         free(arg_string);
190
191         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
192         CHECK_STR_EQ(act_cpp->argv[1], "--sysroot=./foo");
193
194         args_free(orig);
195         args_free(act_cpp);
196         args_free(act_cc);
197 }
198
199 TEST(MF_flag_with_immediate_argument_should_work_as_last_argument)
200 {
201         struct args *orig = args_init_from_string(
202           "cc -c foo.c -o foo.o -MMD -MT bar -MFfoo.d");
203         struct args *exp_cpp = args_init_from_string(
204           "cc -MMD -MT bar -MFfoo.d");
205         struct args *exp_cc = args_init_from_string("cc -c");
206         struct args *act_cpp = NULL, *act_cc = NULL;
207         create_file("foo.c", "");
208
209         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
210         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
211         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
212
213         args_free(orig);
214 }
215
216 TEST(MT_flag_with_immediate_argument_should_work_as_last_argument)
217 {
218         struct args *orig = args_init_from_string(
219           "cc -c foo.c -o foo.o -MMD -MFfoo.d -MT foo -MTbar");
220         struct args *exp_cpp = args_init_from_string(
221           "cc -MMD -MFfoo.d -MT foo -MTbar");
222         struct args *exp_cc = args_init_from_string("cc -c");
223         struct args *act_cpp = NULL, *act_cc = NULL;
224         create_file("foo.c", "");
225
226         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
227         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
228         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
229
230         args_free(orig);
231 }
232
233 TEST(MQ_flag_with_immediate_argument_should_work_as_last_argument)
234 {
235         struct args *orig = args_init_from_string(
236           "cc -c foo.c -o foo.o -MMD -MFfoo.d -MQ foo -MQbar");
237         struct args *exp_cpp = args_init_from_string(
238           "cc -MMD -MFfoo.d -MQ foo -MQbar");
239         struct args *exp_cc = args_init_from_string("cc -c");
240         struct args *act_cpp = NULL, *act_cc = NULL;
241         create_file("foo.c", "");
242
243         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
244         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
245         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
246
247         args_free(orig);
248 }
249
250 TEST(MQ_flag_without_immediate_argument_should_not_add_MQobj)
251 {
252         struct args *orig = args_init_from_string(
253           "gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
254         struct args *exp_cpp = args_init_from_string(
255           "gcc -MD -MP -MFfoo.d -MQ foo.d");
256         struct args *exp_cc = args_init_from_string("gcc -c");
257         struct args *act_cpp = NULL, *act_cc = NULL;
258         create_file("foo.c", "");
259
260         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
261         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
262         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
263
264         args_free(orig);
265 }
266
267 TEST(MT_flag_without_immediate_argument_should_not_add_MTobj)
268 {
269         struct args *orig = args_init_from_string(
270           "gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
271         struct args *exp_cpp = args_init_from_string(
272           "gcc -MD -MP -MFfoo.d -MT foo.d");
273         struct args *exp_cc = args_init_from_string("gcc -c");
274         struct args *act_cpp = NULL, *act_cc = NULL;
275         create_file("foo.c", "");
276
277         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
278         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
279         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
280
281         args_free(orig);
282 }
283
284 TEST(MQ_flag_with_immediate_argument_should_not_add_MQobj)
285 {
286         struct args *orig = args_init_from_string(
287           "gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
288         struct args *exp_cpp = args_init_from_string(
289           "gcc -MD -MP -MFfoo.d -MQfoo.d");
290         struct args *exp_cc = args_init_from_string("gcc -c");
291         struct args *act_cpp = NULL, *act_cc = NULL;
292         create_file("foo.c", "");
293
294         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
295         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
296         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
297
298         args_free(orig);
299 }
300
301 TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
302 {
303         struct args *orig = args_init_from_string(
304           "gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
305         struct args *exp_cpp = args_init_from_string(
306           "gcc -MD -MP -MFfoo.d -MTfoo.d");
307         struct args *exp_cc = args_init_from_string("gcc -c");
308         struct args *act_cpp = NULL, *act_cc = NULL;
309         create_file("foo.c", "");
310
311         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
312         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
313         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
314
315         args_free(orig);
316 }
317
318 TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path)
319 {
320         struct args *orig = args_init_from_string(
321           "gcc -c -fprofile-generate=some/dir foo.c");
322         struct args *exp_cpp = args_init_from_string("gcc");
323         struct args *exp_cc = args_init_from_string("gcc");
324         struct args *act_cpp = NULL, *act_cc = NULL;
325         char *s, *path;
326
327         create_file("foo.c", "");
328         mkdir("some", 0777);
329         mkdir("some/dir", 0777);
330         path = x_realpath("some/dir");
331         s = format("-fprofile-generate=%s", path);
332         free(path);
333         args_add(exp_cpp, s);
334         args_add(exp_cc, s);
335         args_add(exp_cc, "-c");
336         free(s);
337
338         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
339         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
340         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
341
342         args_free(orig);
343 }
344
345 TEST(fprofile_flag_with_nonexisting_dir_should_not_be_rewritten)
346 {
347         struct args *orig = args_init_from_string(
348           "gcc -c -fprofile-generate=some/dir foo.c");
349         struct args *exp_cpp = args_init_from_string(
350           "gcc -fprofile-generate=some/dir");
351         struct args *exp_cc = args_init_from_string(
352           "gcc -fprofile-generate=some/dir -c");
353         struct args *act_cpp = NULL, *act_cc = NULL;
354
355         create_file("foo.c", "");
356
357         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
358         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
359         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
360
361         args_free(orig);
362 }
363
364 TEST(isystem_flag_with_separate_arg_should_be_rewritten_if_basedir_is_used)
365 {
366         extern char *current_working_dir;
367         char *arg_string;
368         struct args *orig;
369         struct args *act_cpp = NULL, *act_cc = NULL;
370
371         create_file("foo.c", "");
372         free(conf->base_dir);
373         conf->base_dir = get_root();
374         current_working_dir = get_cwd();
375         arg_string = format("cc -isystem %s/foo -c foo.c", current_working_dir);
376         orig = args_init_from_string(arg_string);
377         free(arg_string);
378
379         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
380         CHECK_STR_EQ("./foo", act_cpp->argv[2]);
381
382         args_free(orig);
383         args_free(act_cpp);
384         args_free(act_cc);
385 }
386
387 TEST(isystem_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
388 {
389         extern char *current_working_dir;
390         char *cwd;
391         char *arg_string;
392         struct args *orig;
393         struct args *act_cpp = NULL, *act_cc = NULL;
394
395         create_file("foo.c", "");
396         free(conf->base_dir);
397         conf->base_dir = x_strdup("/"); // posix
398         current_working_dir = get_cwd();
399         // Windows path doesn't work concatenated.
400         cwd = get_posix_path(current_working_dir);
401         arg_string = format("cc -isystem%s/foo -c foo.c", cwd);
402         orig = args_init_from_string(arg_string);
403         free(arg_string);
404
405         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
406         CHECK_STR_EQ("-isystem./foo", act_cpp->argv[1]);
407
408         free(cwd);
409         args_free(orig);
410         args_free(act_cpp);
411         args_free(act_cc);
412 }
413
414 TEST(I_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
415 {
416         extern char *current_working_dir;
417         char *cwd;
418         char *arg_string;
419         struct args *orig;
420         struct args *act_cpp = NULL, *act_cc = NULL;
421
422         create_file("foo.c", "");
423         free(conf->base_dir);
424         conf->base_dir = x_strdup("/"); // posix
425         current_working_dir = get_cwd();
426         // Windows path doesn't work concatenated.
427         cwd = get_posix_path(current_working_dir);
428         arg_string = format("cc -I%s/foo -c foo.c", cwd);
429         orig = args_init_from_string(arg_string);
430         free(arg_string);
431
432         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
433         CHECK_STR_EQ("-I./foo", act_cpp->argv[1]);
434
435         free(cwd);
436         args_free(orig);
437         args_free(act_cpp);
438         args_free(act_cc);
439 }
440
441 TEST(debug_flag_order_with_known_option_first)
442 {
443         struct args *orig = args_init_from_string("cc -g1 -gsplit-dwarf foo.c -c");
444         struct args *exp_cpp = args_init_from_string("cc -g1 -gsplit-dwarf");
445         struct args *exp_cc = args_init_from_string("cc -g1 -gsplit-dwarf -c");
446         struct args *act_cpp = NULL;
447         struct args *act_cc = NULL;
448
449         create_file("foo.c", "");
450         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
451         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
452         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
453
454         args_free(orig);
455 }
456
457 TEST(debug_flag_order_with_known_option_last)
458 {
459         struct args *orig = args_init_from_string("cc -gsplit-dwarf -g1 foo.c -c");
460         struct args *exp_cpp = args_init_from_string("cc -gsplit-dwarf -g1");
461         struct args *exp_cc = args_init_from_string("cc -gsplit-dwarf -g1 -c");
462         struct args *act_cpp = NULL;
463         struct args *act_cc = NULL;
464
465         create_file("foo.c", "");
466         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
467         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
468         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
469
470         args_free(orig);
471 }
472
473 TEST_SUITE_END