Imported Upstream version 3.4
[platform/upstream/ccache.git] / unittest / test_argument_processing.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 // This file contains tests for the processing of compiler arguments.
18
19 #include "../src/ccache.h"
20 #include "../src/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(sysroot_with_separate_argument_should_be_rewritten_if_basedir_is_used)
200 {
201         extern char *current_working_dir;
202         char *arg_string;
203         struct args *orig;
204         struct args *act_cpp = NULL, *act_cc = NULL;
205
206         create_file("foo.c", "");
207         free(conf->base_dir);
208         conf->base_dir = get_root();
209         current_working_dir = get_cwd();
210         arg_string = format("cc --sysroot %s/foo -c foo.c", current_working_dir);
211         orig = args_init_from_string(arg_string);
212         free(arg_string);
213
214         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
215         CHECK_STR_EQ(act_cpp->argv[1], "--sysroot");
216         CHECK_STR_EQ(act_cpp->argv[2], "./foo");
217
218         args_free(orig);
219         args_free(act_cpp);
220         args_free(act_cc);
221 }
222
223 TEST(MF_flag_with_immediate_argument_should_work_as_last_argument)
224 {
225         struct args *orig = args_init_from_string(
226           "cc -c foo.c -o foo.o -MMD -MT bar -MFfoo.d");
227         struct args *exp_cpp = args_init_from_string(
228           "cc -MMD -MT bar -MFfoo.d");
229         struct args *exp_cc = args_init_from_string("cc -c");
230         struct args *act_cpp = NULL, *act_cc = NULL;
231         create_file("foo.c", "");
232
233         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
234         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
235         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
236
237         args_free(orig);
238 }
239
240 TEST(MT_flag_with_immediate_argument_should_work_as_last_argument)
241 {
242         struct args *orig = args_init_from_string(
243           "cc -c foo.c -o foo.o -MMD -MFfoo.d -MT foo -MTbar");
244         struct args *exp_cpp = args_init_from_string(
245           "cc -MMD -MFfoo.d -MT foo -MTbar");
246         struct args *exp_cc = args_init_from_string("cc -c");
247         struct args *act_cpp = NULL, *act_cc = NULL;
248         create_file("foo.c", "");
249
250         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
251         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
252         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
253
254         args_free(orig);
255 }
256
257 TEST(MQ_flag_with_immediate_argument_should_work_as_last_argument)
258 {
259         struct args *orig = args_init_from_string(
260           "cc -c foo.c -o foo.o -MMD -MFfoo.d -MQ foo -MQbar");
261         struct args *exp_cpp = args_init_from_string(
262           "cc -MMD -MFfoo.d -MQ foo -MQbar");
263         struct args *exp_cc = args_init_from_string("cc -c");
264         struct args *act_cpp = NULL, *act_cc = NULL;
265         create_file("foo.c", "");
266
267         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
268         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
269         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
270
271         args_free(orig);
272 }
273
274 TEST(MQ_flag_without_immediate_argument_should_not_add_MQobj)
275 {
276         struct args *orig = args_init_from_string(
277           "gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
278         struct args *exp_cpp = args_init_from_string(
279           "gcc -MD -MP -MFfoo.d -MQ foo.d");
280         struct args *exp_cc = args_init_from_string("gcc -c");
281         struct args *act_cpp = NULL, *act_cc = NULL;
282         create_file("foo.c", "");
283
284         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
285         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
286         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
287
288         args_free(orig);
289 }
290
291 TEST(MT_flag_without_immediate_argument_should_not_add_MTobj)
292 {
293         struct args *orig = args_init_from_string(
294           "gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
295         struct args *exp_cpp = args_init_from_string(
296           "gcc -MD -MP -MFfoo.d -MT foo.d");
297         struct args *exp_cc = args_init_from_string("gcc -c");
298         struct args *act_cpp = NULL, *act_cc = NULL;
299         create_file("foo.c", "");
300
301         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
302         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
303         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
304
305         args_free(orig);
306 }
307
308 TEST(MQ_flag_with_immediate_argument_should_not_add_MQobj)
309 {
310         struct args *orig = args_init_from_string(
311           "gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
312         struct args *exp_cpp = args_init_from_string(
313           "gcc -MD -MP -MFfoo.d -MQfoo.d");
314         struct args *exp_cc = args_init_from_string("gcc -c");
315         struct args *act_cpp = NULL, *act_cc = NULL;
316         create_file("foo.c", "");
317
318         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
319         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
320         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
321
322         args_free(orig);
323 }
324
325 TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
326 {
327         struct args *orig = args_init_from_string(
328           "gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
329         struct args *exp_cpp = args_init_from_string(
330           "gcc -MD -MP -MFfoo.d -MTfoo.d");
331         struct args *exp_cc = args_init_from_string("gcc -c");
332         struct args *act_cpp = NULL, *act_cc = NULL;
333         create_file("foo.c", "");
334
335         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
336         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
337         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
338
339         args_free(orig);
340 }
341
342 TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path)
343 {
344         struct args *orig = args_init_from_string(
345           "gcc -c -fprofile-generate=some/dir foo.c");
346         struct args *exp_cpp = args_init_from_string("gcc");
347         struct args *exp_cc = args_init_from_string("gcc");
348         struct args *act_cpp = NULL, *act_cc = NULL;
349         char *s, *path;
350
351         create_file("foo.c", "");
352         mkdir("some", 0777);
353         mkdir("some/dir", 0777);
354         path = x_realpath("some/dir");
355         s = format("-fprofile-generate=%s", path);
356         free(path);
357         args_add(exp_cpp, s);
358         args_add(exp_cc, s);
359         args_add(exp_cc, "-c");
360         free(s);
361
362         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
363         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
364         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
365
366         args_free(orig);
367 }
368
369 TEST(fprofile_flag_with_nonexisting_dir_should_not_be_rewritten)
370 {
371         struct args *orig = args_init_from_string(
372           "gcc -c -fprofile-generate=some/dir foo.c");
373         struct args *exp_cpp = args_init_from_string(
374           "gcc -fprofile-generate=some/dir");
375         struct args *exp_cc = args_init_from_string(
376           "gcc -fprofile-generate=some/dir -c");
377         struct args *act_cpp = NULL, *act_cc = NULL;
378
379         create_file("foo.c", "");
380
381         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
382         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
383         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
384
385         args_free(orig);
386 }
387
388 TEST(isystem_flag_with_separate_arg_should_be_rewritten_if_basedir_is_used)
389 {
390         extern char *current_working_dir;
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 = get_root();
398         current_working_dir = get_cwd();
399         arg_string = format("cc -isystem %s/foo -c foo.c", current_working_dir);
400         orig = args_init_from_string(arg_string);
401         free(arg_string);
402
403         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
404         CHECK_STR_EQ("./foo", act_cpp->argv[2]);
405
406         args_free(orig);
407         args_free(act_cpp);
408         args_free(act_cc);
409 }
410
411 TEST(isystem_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
412 {
413         extern char *current_working_dir;
414         char *cwd;
415         char *arg_string;
416         struct args *orig;
417         struct args *act_cpp = NULL, *act_cc = NULL;
418
419         create_file("foo.c", "");
420         free(conf->base_dir);
421         conf->base_dir = x_strdup("/"); // posix
422         current_working_dir = get_cwd();
423         // Windows path doesn't work concatenated.
424         cwd = get_posix_path(current_working_dir);
425         arg_string = format("cc -isystem%s/foo -c foo.c", cwd);
426         orig = args_init_from_string(arg_string);
427         free(arg_string);
428
429         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
430         CHECK_STR_EQ("-isystem./foo", act_cpp->argv[1]);
431
432         free(cwd);
433         args_free(orig);
434         args_free(act_cpp);
435         args_free(act_cc);
436 }
437
438 TEST(I_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
439 {
440         extern char *current_working_dir;
441         char *cwd;
442         char *arg_string;
443         struct args *orig;
444         struct args *act_cpp = NULL, *act_cc = NULL;
445
446         create_file("foo.c", "");
447         free(conf->base_dir);
448         conf->base_dir = x_strdup("/"); // posix
449         current_working_dir = get_cwd();
450         // Windows path doesn't work concatenated.
451         cwd = get_posix_path(current_working_dir);
452         arg_string = format("cc -I%s/foo -c foo.c", cwd);
453         orig = args_init_from_string(arg_string);
454         free(arg_string);
455
456         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
457         CHECK_STR_EQ("-I./foo", act_cpp->argv[1]);
458
459         free(cwd);
460         args_free(orig);
461         args_free(act_cpp);
462         args_free(act_cc);
463 }
464
465 TEST(debug_flag_order_with_known_option_first)
466 {
467         struct args *orig = args_init_from_string("cc -g1 -gsplit-dwarf foo.c -c");
468         struct args *exp_cpp = args_init_from_string("cc -g1 -gsplit-dwarf");
469         struct args *exp_cc = args_init_from_string("cc -g1 -gsplit-dwarf -c");
470         struct args *act_cpp = NULL;
471         struct args *act_cc = NULL;
472
473         create_file("foo.c", "");
474         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
475         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
476         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
477
478         args_free(orig);
479 }
480
481 TEST(debug_flag_order_with_known_option_last)
482 {
483         struct args *orig = args_init_from_string("cc -gsplit-dwarf -g1 foo.c -c");
484         struct args *exp_cpp = args_init_from_string("cc -gsplit-dwarf -g1");
485         struct args *exp_cc = args_init_from_string("cc -gsplit-dwarf -g1 -c");
486         struct args *act_cpp = NULL;
487         struct args *act_cc = NULL;
488
489         create_file("foo.c", "");
490         CHECK(cc_process_args(orig, &act_cpp, &act_cc));
491         CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
492         CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
493
494         args_free(orig);
495 }
496
497 TEST_SUITE_END