1//===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Unit tests for ToolChains.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Driver/ToolChain.h"
14#include "clang/Basic/DiagnosticIDs.h"
15#include "clang/Basic/DiagnosticOptions.h"
16#include "clang/Basic/LLVM.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Basic/TargetOptions.h"
19#include "clang/Driver/Compilation.h"
20#include "clang/Driver/Driver.h"
21#include "clang/Frontend/CompilerInstance.h"
22#include "llvm/ADT/ArrayRef.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/Frontend/Debug/Options.h"
25#include "llvm/MC/TargetRegistry.h"
26#include "llvm/Support/TargetSelect.h"
27#include "llvm/Support/VirtualFileSystem.h"
28#include "llvm/Support/raw_ostream.h"
29#include "gmock/gmock.h"
30#include "gtest/gtest.h"
31#include <memory>
32
33#include "SimpleDiagnosticConsumer.h"
34
35using namespace clang;
36using namespace clang::driver;
37
38namespace {
39
40TEST(ToolChainTest, VFSGCCInstallation) {
41 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
42
43 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
44 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
45 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
46 new llvm::vfs::InMemoryFileSystem);
47
48 const char *EmptyFiles[] = {
49 "foo.cpp",
50 "/bin/clang",
51 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
52 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o",
53 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o",
54 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o",
55 "/usr/lib/arm-linux-gnueabi/crt1.o",
56 "/usr/lib/arm-linux-gnueabi/crti.o",
57 "/usr/lib/arm-linux-gnueabi/crtn.o",
58 "/usr/lib/arm-linux-gnueabihf/crt1.o",
59 "/usr/lib/arm-linux-gnueabihf/crti.o",
60 "/usr/lib/arm-linux-gnueabihf/crtn.o",
61 "/usr/include/arm-linux-gnueabi/.keep",
62 "/usr/include/arm-linux-gnueabihf/.keep",
63 "/lib/arm-linux-gnueabi/.keep",
64 "/lib/arm-linux-gnueabihf/.keep",
65
66 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtbegin.o",
67 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtend.o",
68 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtbegin.o",
69 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtend.o",
70 "/sysroot/usr/lib/arm-linux-gnueabi/crt1.o",
71 "/sysroot/usr/lib/arm-linux-gnueabi/crti.o",
72 "/sysroot/usr/lib/arm-linux-gnueabi/crtn.o",
73 "/sysroot/usr/lib/arm-linux-gnueabihf/crt1.o",
74 "/sysroot/usr/lib/arm-linux-gnueabihf/crti.o",
75 "/sysroot/usr/lib/arm-linux-gnueabihf/crtn.o",
76 "/sysroot/usr/include/arm-linux-gnueabi/.keep",
77 "/sysroot/usr/include/arm-linux-gnueabihf/.keep",
78 "/sysroot/lib/arm-linux-gnueabi/.keep",
79 "/sysroot/lib/arm-linux-gnueabihf/.keep",
80 };
81
82 for (const char *Path : EmptyFiles)
83 InMemoryFileSystem->addFile(Path, ModificationTime: 0,
84 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n"));
85
86 {
87 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
88 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
89 "clang LLVM compiler", InMemoryFileSystem);
90 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
91 Args: {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"}));
92 ASSERT_TRUE(C);
93 std::string S;
94 {
95 llvm::raw_string_ostream OS(S);
96 C->getDefaultToolChain().printVerboseInfo(OS);
97 }
98 if (is_style_windows(S: llvm::sys::path::Style::native))
99 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
100 EXPECT_EQ(
101 "Found candidate GCC installation: "
102 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
103 "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
104 "Candidate multilib: .;@m32\n"
105 "Selected multilib: .;@m32\n",
106 S);
107 }
108
109 {
110 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
111 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
112 "clang LLVM compiler", InMemoryFileSystem);
113 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
114 Args: {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=/sysroot",
115 "foo.cpp"}));
116 ASSERT_TRUE(C);
117 std::string S;
118 {
119 llvm::raw_string_ostream OS(S);
120 C->getDefaultToolChain().printVerboseInfo(OS);
121 }
122 if (is_style_windows(S: llvm::sys::path::Style::native))
123 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
124 // Test that 4.5.3 from --sysroot is not overridden by 4.6.3 (larger
125 // version) from /usr.
126 EXPECT_EQ("Found candidate GCC installation: "
127 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
128 "Selected GCC installation: "
129 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
130 "Candidate multilib: .;@m32\n"
131 "Selected multilib: .;@m32\n",
132 S);
133 }
134}
135
136TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
137 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
138
139 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
140 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
141 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
142 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
143 new llvm::vfs::InMemoryFileSystem);
144 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
145 "clang LLVM compiler", InMemoryFileSystem);
146
147 const char *EmptyFiles[] = {
148 "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
149 "/home/test/include/arm-linux-gnueabi/.keep"};
150
151 for (const char *Path : EmptyFiles)
152 InMemoryFileSystem->addFile(Path, ModificationTime: 0,
153 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n"));
154
155 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
156 Args: {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
157 EXPECT_TRUE(C);
158
159 std::string S;
160 {
161 llvm::raw_string_ostream OS(S);
162 C->getDefaultToolChain().printVerboseInfo(OS);
163 }
164 if (is_style_windows(S: llvm::sys::path::Style::native))
165 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
166 EXPECT_EQ("Found candidate GCC installation: "
167 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
168 "Selected GCC installation: "
169 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
170 "Candidate multilib: .;@m32\n"
171 "Selected multilib: .;@m32\n",
172 S);
173}
174
175TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
176 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
177
178 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
179 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
180 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
181 new llvm::vfs::InMemoryFileSystem);
182
183 const char *EmptyFiles[] = {
184 // Sort entries so the latest version doesn't come first.
185 "/usr/gcc/7/lib/gcc/sparcv9-sun-solaris2.11/7.5.0/32/crtbegin.o",
186 "/usr/gcc/7/lib/gcc/sparcv9-sun-solaris2.11/7.5.0/crtbegin.o",
187 "/usr/gcc/7/lib/gcc/x86_64-pc-solaris2.11/7.5.0/32/crtbegin.o",
188 "/usr/gcc/7/lib/gcc/x86_64-pc-solaris2.11/7.5.0/crtbegin.o",
189 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0/crtbegin.o",
190 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0/sparcv8plus/crtbegin.o",
191 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0/32/crtbegin.o",
192 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0/crtbegin.o",
193 "/usr/gcc/4.7/lib/gcc/i386-pc-solaris2.11/4.7.3/amd64/crtbegin.o",
194 "/usr/gcc/4.7/lib/gcc/i386-pc-solaris2.11/4.7.3/crtbegin.o",
195 "/usr/gcc/4.7/lib/gcc/sparc-sun-solaris2.11/4.7.3/crtbegin.o",
196 "/usr/gcc/4.7/lib/gcc/sparc-sun-solaris2.11/4.7.3/sparcv9/crtbegin.o",
197 };
198
199 for (const char *Path : EmptyFiles)
200 InMemoryFileSystem->addFile(Path, ModificationTime: 0,
201 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n"));
202
203 {
204 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
205 Driver TheDriver("/bin/clang", "i386-pc-solaris2.11", Diags,
206 "clang LLVM compiler", InMemoryFileSystem);
207 std::unique_ptr<Compilation> C(
208 TheDriver.BuildCompilation(Args: {"-v", "--gcc-toolchain=", "--sysroot="}));
209 ASSERT_TRUE(C);
210 std::string S;
211 {
212 llvm::raw_string_ostream OS(S);
213 C->getDefaultToolChain().printVerboseInfo(OS);
214 }
215 if (is_style_windows(S: llvm::sys::path::Style::native))
216 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
217 EXPECT_EQ("Found candidate GCC installation: "
218 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
219 "Selected GCC installation: "
220 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
221 "Candidate multilib: .;@m64\n"
222 "Candidate multilib: 32;@m32\n"
223 "Selected multilib: 32;@m32\n",
224 S);
225 }
226
227 {
228 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
229 Driver TheDriver("/bin/clang", "amd64-pc-solaris2.11", Diags,
230 "clang LLVM compiler", InMemoryFileSystem);
231 std::unique_ptr<Compilation> C(
232 TheDriver.BuildCompilation(Args: {"-v", "--gcc-toolchain=", "--sysroot="}));
233 ASSERT_TRUE(C);
234 std::string S;
235 {
236 llvm::raw_string_ostream OS(S);
237 C->getDefaultToolChain().printVerboseInfo(OS);
238 }
239 if (is_style_windows(S: llvm::sys::path::Style::native))
240 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
241 EXPECT_EQ("Found candidate GCC installation: "
242 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
243 "Selected GCC installation: "
244 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
245 "Candidate multilib: .;@m64\n"
246 "Candidate multilib: 32;@m32\n"
247 "Selected multilib: .;@m64\n",
248 S);
249 }
250
251 {
252 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
253 Driver TheDriver("/bin/clang", "x86_64-pc-solaris2.11", Diags,
254 "clang LLVM compiler", InMemoryFileSystem);
255 std::unique_ptr<Compilation> C(
256 TheDriver.BuildCompilation(Args: {"-v", "--gcc-toolchain=", "--sysroot="}));
257 ASSERT_TRUE(C);
258 std::string S;
259 {
260 llvm::raw_string_ostream OS(S);
261 C->getDefaultToolChain().printVerboseInfo(OS);
262 }
263 if (is_style_windows(S: llvm::sys::path::Style::native))
264 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
265 EXPECT_EQ("Found candidate GCC installation: "
266 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
267 "Selected GCC installation: "
268 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
269 "Candidate multilib: .;@m64\n"
270 "Candidate multilib: 32;@m32\n"
271 "Selected multilib: .;@m64\n",
272 S);
273 }
274
275 {
276 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
277 Driver TheDriver("/bin/clang", "sparc-sun-solaris2.11", Diags,
278 "clang LLVM compiler", InMemoryFileSystem);
279 std::unique_ptr<Compilation> C(
280 TheDriver.BuildCompilation(Args: {"-v", "--gcc-toolchain=", "--sysroot="}));
281 ASSERT_TRUE(C);
282 std::string S;
283 {
284 llvm::raw_string_ostream OS(S);
285 C->getDefaultToolChain().printVerboseInfo(OS);
286 }
287 if (is_style_windows(S: llvm::sys::path::Style::native))
288 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
289 EXPECT_EQ("Found candidate GCC installation: "
290 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
291 "Selected GCC installation: "
292 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
293 "Candidate multilib: .;@m64\n"
294 "Candidate multilib: sparcv8plus;@m32\n"
295 "Selected multilib: sparcv8plus;@m32\n",
296 S);
297 }
298 {
299 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
300 Driver TheDriver("/bin/clang", "sparcv9-sun-solaris2.11", Diags,
301 "clang LLVM compiler", InMemoryFileSystem);
302 std::unique_ptr<Compilation> C(
303 TheDriver.BuildCompilation(Args: {"-v", "--gcc-toolchain=", "--sysroot="}));
304 ASSERT_TRUE(C);
305 std::string S;
306 {
307 llvm::raw_string_ostream OS(S);
308 C->getDefaultToolChain().printVerboseInfo(OS);
309 }
310 if (is_style_windows(S: llvm::sys::path::Style::native))
311 std::replace(first: S.begin(), last: S.end(), old_value: '\\', new_value: '/');
312 EXPECT_EQ("Found candidate GCC installation: "
313 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
314 "Selected GCC installation: "
315 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
316 "Candidate multilib: .;@m64\n"
317 "Candidate multilib: sparcv8plus;@m32\n"
318 "Selected multilib: .;@m64\n",
319 S);
320 }
321}
322
323MATCHER_P(jobHasArgs, Substr, "") {
324 const driver::Command &C = arg;
325 std::string Args = "";
326 llvm::ListSeparator Sep(" ");
327 for (const char *Arg : C.getArguments()) {
328 Args += Sep;
329 Args += Arg;
330 }
331 if (is_style_windows(S: llvm::sys::path::Style::native))
332 std::replace(first: Args.begin(), last: Args.end(), old_value: '\\', new_value: '/');
333 if (llvm::StringRef(Args).contains(Substr))
334 return true;
335 *result_listener << "whose args are '" << Args << "'";
336 return false;
337}
338
339TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
340 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
341
342 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
343 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
344 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
345 new llvm::vfs::InMemoryFileSystem);
346
347 const char *EmptyFiles[] = {
348 "foo.cpp",
349 "/bin/clang",
350 "/usr/include/c++/v1/cstdio",
351 };
352
353 for (const char *Path : EmptyFiles)
354 InMemoryFileSystem->addFile(Path, ModificationTime: 0,
355 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "\n"));
356
357 {
358 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
359 Driver TheDriver("/bin/clang", "x86_64-unknown-linux-gnu", Diags,
360 "clang LLVM compiler", InMemoryFileSystem);
361 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
362 Args: {"/bin/clang", "-fsyntax-only", "-stdlib=libc++",
363 "--sysroot=", "foo.cpp"}));
364 ASSERT_TRUE(C);
365 EXPECT_THAT(C->getJobs(), testing::ElementsAre(jobHasArgs(
366 "-internal-isystem /usr/include/c++/v1")));
367 }
368}
369
370TEST(ToolChainTest, DefaultDriverMode) {
371 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
372
373 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
374 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
375 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
376 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
377 new llvm::vfs::InMemoryFileSystem);
378
379 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
380 "clang LLVM compiler", InMemoryFileSystem);
381 CCDriver.setCheckInputsExist(false);
382 Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
383 "clang LLVM compiler", InMemoryFileSystem);
384 CXXDriver.setCheckInputsExist(false);
385 Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
386 "clang LLVM compiler", InMemoryFileSystem);
387 CLDriver.setCheckInputsExist(false);
388
389 std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation(
390 Args: { "/home/test/bin/clang", "foo.cpp"}));
391 std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation(
392 Args: { "/home/test/bin/clang++", "foo.cpp"}));
393 std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation(
394 Args: { "/home/test/bin/clang-cl", "foo.cpp"}));
395
396 EXPECT_TRUE(CC);
397 EXPECT_TRUE(CXX);
398 EXPECT_TRUE(CL);
399 EXPECT_TRUE(CCDriver.CCCIsCC());
400 EXPECT_TRUE(CXXDriver.CCCIsCXX());
401 EXPECT_TRUE(CLDriver.IsCLMode());
402}
403TEST(ToolChainTest, InvalidArgument) {
404 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
405 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
406 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
407 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
408 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
409 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
410 Args: {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
411 EXPECT_TRUE(C);
412 EXPECT_TRUE(C->containsError());
413}
414
415TEST(ToolChainTest, ParsedClangName) {
416 ParsedClangName Empty;
417 EXPECT_TRUE(Empty.TargetPrefix.empty());
418 EXPECT_TRUE(Empty.ModeSuffix.empty());
419 EXPECT_TRUE(Empty.DriverMode == nullptr);
420 EXPECT_FALSE(Empty.TargetIsValid);
421
422 ParsedClangName DriverOnly("clang", nullptr);
423 EXPECT_TRUE(DriverOnly.TargetPrefix.empty());
424 EXPECT_TRUE(DriverOnly.ModeSuffix == "clang");
425 EXPECT_TRUE(DriverOnly.DriverMode == nullptr);
426 EXPECT_FALSE(DriverOnly.TargetIsValid);
427
428 ParsedClangName DriverOnly2("clang++", "--driver-mode=g++");
429 EXPECT_TRUE(DriverOnly2.TargetPrefix.empty());
430 EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++");
431 EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++");
432 EXPECT_FALSE(DriverOnly2.TargetIsValid);
433
434 ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true);
435 EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386");
436 EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++");
437 EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++");
438 EXPECT_TRUE(TargetAndMode.TargetIsValid);
439}
440
441TEST(ToolChainTest, GetTargetAndMode) {
442 llvm::InitializeAllTargets();
443 std::string IgnoredError;
444 if (!llvm::TargetRegistry::lookupTarget(Triple: "x86_64", Error&: IgnoredError))
445 GTEST_SKIP();
446
447 ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "clang");
448 EXPECT_TRUE(Res.TargetPrefix.empty());
449 EXPECT_TRUE(Res.ModeSuffix == "clang");
450 EXPECT_TRUE(Res.DriverMode == nullptr);
451 EXPECT_FALSE(Res.TargetIsValid);
452
453 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "clang++");
454 EXPECT_TRUE(Res.TargetPrefix.empty());
455 EXPECT_TRUE(Res.ModeSuffix == "clang++");
456 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
457 EXPECT_FALSE(Res.TargetIsValid);
458
459 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "clang++6.0");
460 EXPECT_TRUE(Res.TargetPrefix.empty());
461 EXPECT_TRUE(Res.ModeSuffix == "clang++");
462 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
463 EXPECT_FALSE(Res.TargetIsValid);
464
465 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "clang++-release");
466 EXPECT_TRUE(Res.TargetPrefix.empty());
467 EXPECT_TRUE(Res.ModeSuffix == "clang++");
468 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
469 EXPECT_FALSE(Res.TargetIsValid);
470
471 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "x86_64-clang++");
472 EXPECT_TRUE(Res.TargetPrefix == "x86_64");
473 EXPECT_TRUE(Res.ModeSuffix == "clang++");
474 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
475 EXPECT_TRUE(Res.TargetIsValid);
476
477 Res = ToolChain::getTargetAndModeFromProgramName(
478 ProgName: "x86_64-linux-gnu-clang-c++");
479 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
480 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
481 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
482 EXPECT_TRUE(Res.TargetIsValid);
483
484 Res = ToolChain::getTargetAndModeFromProgramName(
485 ProgName: "x86_64-linux-gnu-clang-c++-tot");
486 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
487 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
488 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
489 EXPECT_TRUE(Res.TargetIsValid);
490
491 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "qqq");
492 EXPECT_TRUE(Res.TargetPrefix.empty());
493 EXPECT_TRUE(Res.ModeSuffix.empty());
494 EXPECT_TRUE(Res.DriverMode == nullptr);
495 EXPECT_FALSE(Res.TargetIsValid);
496
497 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "x86_64-qqq");
498 EXPECT_TRUE(Res.TargetPrefix.empty());
499 EXPECT_TRUE(Res.ModeSuffix.empty());
500 EXPECT_TRUE(Res.DriverMode == nullptr);
501 EXPECT_FALSE(Res.TargetIsValid);
502
503 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "qqq-clang-cl");
504 EXPECT_TRUE(Res.TargetPrefix == "qqq");
505 EXPECT_TRUE(Res.ModeSuffix == "clang-cl");
506 EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl");
507 EXPECT_FALSE(Res.TargetIsValid);
508
509 Res = ToolChain::getTargetAndModeFromProgramName(ProgName: "clang-dxc");
510 EXPECT_TRUE(Res.TargetPrefix.empty());
511 EXPECT_TRUE(Res.ModeSuffix == "clang-dxc");
512 EXPECT_STREQ(Res.DriverMode, "--driver-mode=dxc");
513 EXPECT_FALSE(Res.TargetIsValid);
514}
515
516TEST(ToolChainTest, CommandOutput) {
517 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
518
519 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
520 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
521 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
522 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
523 new llvm::vfs::InMemoryFileSystem);
524
525 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
526 "clang LLVM compiler", InMemoryFileSystem);
527 CCDriver.setCheckInputsExist(false);
528 std::unique_ptr<Compilation> CC(
529 CCDriver.BuildCompilation(Args: {"/home/test/bin/clang", "foo.cpp"}));
530 const JobList &Jobs = CC->getJobs();
531
532 const auto &CmdCompile = Jobs.getJobs().front();
533 const auto &InFile = CmdCompile->getInputInfos().front().getFilename();
534 EXPECT_STREQ(InFile, "foo.cpp");
535 auto ObjFile = CmdCompile->getOutputFilenames().front();
536 EXPECT_TRUE(StringRef(ObjFile).ends_with(".o"));
537
538 const auto &CmdLink = Jobs.getJobs().back();
539 const auto LinkInFile = CmdLink->getInputInfos().front().getFilename();
540 EXPECT_EQ(ObjFile, LinkInFile);
541 auto ExeFile = CmdLink->getOutputFilenames().front();
542 EXPECT_EQ("a.out", ExeFile);
543}
544
545TEST(ToolChainTest, PostCallback) {
546 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
547 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
548 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
549 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
550 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
551 new llvm::vfs::InMemoryFileSystem);
552
553 // The executable path must not exist.
554 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
555 "clang LLVM compiler", InMemoryFileSystem);
556 CCDriver.setCheckInputsExist(false);
557 std::unique_ptr<Compilation> CC(
558 CCDriver.BuildCompilation(Args: {"/home/test/bin/clang", "foo.cpp"}));
559 bool CallbackHasCalled = false;
560 CC->setPostCallback(
561 [&](const Command &C, int Ret) { CallbackHasCalled = true; });
562 const JobList &Jobs = CC->getJobs();
563 auto &CmdCompile = Jobs.getJobs().front();
564 const Command *FailingCmd = nullptr;
565 CC->ExecuteCommand(C: *CmdCompile, FailingCommand&: FailingCmd);
566 EXPECT_TRUE(CallbackHasCalled);
567}
568
569TEST(CompilerInvocation, SplitSwarfSingleCrash) {
570 static constexpr const char *Args[] = {
571 "clang", "--target=arm-linux-gnueabi",
572 "-gdwarf-4", "-gsplit-dwarf=single",
573 "-c", "foo.cpp"};
574 CreateInvocationOptions CIOpts;
575 std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, Opts: CIOpts);
576 EXPECT_TRUE(CI); // no-crash
577}
578
579TEST(ToolChainTest, UEFICallingConventionTest) {
580 clang::CompilerInstance compiler;
581 compiler.createDiagnostics(VFS&: *llvm::vfs::getRealFileSystem());
582
583 std::string TrStr = "x86_64-unknown-uefi";
584 llvm::Triple Tr(TrStr);
585 Tr.setOS(llvm::Triple::OSType::UEFI);
586 Tr.setVendor(llvm::Triple::VendorType::UnknownVendor);
587 Tr.setEnvironment(llvm::Triple::EnvironmentType::UnknownEnvironment);
588 Tr.setArch(Kind: llvm::Triple::ArchType::x86_64);
589
590 compiler.getTargetOpts().Triple = Tr.getTriple();
591 compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
592 Diags&: compiler.getDiagnostics(),
593 Opts: std::make_shared<clang::TargetOptions>(args&: compiler.getTargetOpts())));
594
595 EXPECT_EQ(compiler.getTarget().getCallingConvKind(true),
596 TargetInfo::CallingConvKind::CCK_MicrosoftWin64);
597}
598
599TEST(ToolChainTest, UEFIDefaultDebugFormatTest) {
600 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
601 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
602 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
603 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
604 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
605 new llvm::vfs::InMemoryFileSystem);
606 Driver CCDriver("/home/test/bin/clang", "x86_64-unknown-uefi", Diags,
607 "clang LLVM compiler", InMemoryFileSystem);
608 CCDriver.setCheckInputsExist(false);
609 std::unique_ptr<Compilation> CC(
610 CCDriver.BuildCompilation(Args: {"/home/test/bin/clang", "foo.cpp"}));
611 EXPECT_EQ(CC->getDefaultToolChain().getDefaultDebugFormat(),
612 llvm::codegenoptions::DIF_CodeView);
613}
614
615TEST(GetDriverMode, PrefersLastDriverMode) {
616 static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo",
617 "--driver-mode=bar", "foo.cpp"};
618 EXPECT_EQ(getDriverMode(Args[0], llvm::ArrayRef(Args).slice(1)), "bar");
619}
620
621struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
622 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
623 const Diagnostic &Info) override {
624 if (DiagLevel == DiagnosticsEngine::Level::Error) {
625 Errors.emplace_back();
626 Info.FormatDiagnostic(OutStr&: Errors.back());
627 } else {
628 Msgs.emplace_back();
629 Info.FormatDiagnostic(OutStr&: Msgs.back());
630 }
631 }
632 void clear() override {
633 Msgs.clear();
634 Errors.clear();
635 DiagnosticConsumer::clear();
636 }
637 std::vector<SmallString<32>> Msgs;
638 std::vector<SmallString<32>> Errors;
639};
640
641TEST(ToolChainTest, ConfigFileSearch) {
642 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
643 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
644 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
645 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
646 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
647 new llvm::vfs::InMemoryFileSystem);
648
649#ifdef _WIN32
650 const char *TestRoot = "C:\\";
651#else
652 const char *TestRoot = "/";
653#endif
654 FS->setCurrentWorkingDirectory(TestRoot);
655
656 FS->addFile(
657 Path: "/opt/sdk/root.cfg", ModificationTime: 0,
658 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "--sysroot=/opt/sdk/platform0\n"));
659 FS->addFile(
660 Path: "/home/test/sdk/root.cfg", ModificationTime: 0,
661 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "--sysroot=/opt/sdk/platform1\n"));
662 FS->addFile(
663 Path: "/home/test/bin/root.cfg", ModificationTime: 0,
664 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "--sysroot=/opt/sdk/platform2\n"));
665
666 {
667 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
668 "clang LLVM compiler", FS);
669 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
670 Args: {"/home/test/bin/clang", "--config", "root.cfg",
671 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
672 ASSERT_TRUE(C);
673 ASSERT_FALSE(C->containsError());
674 EXPECT_EQ("/opt/sdk/platform1", TheDriver.SysRoot);
675 }
676 {
677 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
678 "clang LLVM compiler", FS);
679 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
680 Args: {"/home/test/bin/clang", "--config", "root.cfg",
681 "--config-system-dir=/opt/sdk", "--config-user-dir="}));
682 ASSERT_TRUE(C);
683 ASSERT_FALSE(C->containsError());
684 EXPECT_EQ("/opt/sdk/platform0", TheDriver.SysRoot);
685 }
686 {
687 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
688 "clang LLVM compiler", FS);
689 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
690 Args: {"/home/test/bin/clang", "--config", "root.cfg",
691 "--config-system-dir=", "--config-user-dir="}));
692 ASSERT_TRUE(C);
693 ASSERT_FALSE(C->containsError());
694 EXPECT_EQ("/opt/sdk/platform2", TheDriver.SysRoot);
695 }
696}
697
698struct FileSystemWithError : public llvm::vfs::FileSystem {
699 llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
700 return std::make_error_code(e: std::errc::no_such_file_or_directory);
701 }
702 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
703 openFileForRead(const Twine &Path) override {
704 return std::make_error_code(e: std::errc::permission_denied);
705 }
706 llvm::vfs::directory_iterator dir_begin(const Twine &Dir,
707 std::error_code &EC) override {
708 return llvm::vfs::directory_iterator();
709 }
710 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
711 return std::make_error_code(e: std::errc::permission_denied);
712 }
713 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
714 return std::make_error_code(e: std::errc::permission_denied);
715 }
716};
717
718TEST(ToolChainTest, ConfigFileError) {
719 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
720 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
721 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
722 new SimpleDiagnosticConsumer());
723 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
724 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS(new FileSystemWithError);
725
726 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
727 "clang LLVM compiler", FS);
728 std::unique_ptr<Compilation> C(
729 TheDriver.BuildCompilation(Args: {"/home/test/bin/clang", "--no-default-config",
730 "--config", "./root.cfg", "--version"}));
731 ASSERT_TRUE(C);
732 ASSERT_TRUE(C->containsError());
733 EXPECT_EQ(1U, Diags.getNumErrors());
734 EXPECT_STREQ("configuration file './root.cfg' cannot be opened: cannot get "
735 "absolute path",
736 DiagConsumer->Errors[0].c_str());
737}
738
739TEST(ToolChainTest, BadConfigFile) {
740 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
741 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
742 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
743 new SimpleDiagnosticConsumer());
744 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
745 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
746 new llvm::vfs::InMemoryFileSystem);
747
748#ifdef _WIN32
749 const char *TestRoot = "C:\\";
750#define FILENAME "C:/opt/root.cfg"
751#define DIRNAME "C:/opt"
752#else
753 const char *TestRoot = "/";
754#define FILENAME "/opt/root.cfg"
755#define DIRNAME "/opt"
756#endif
757 // UTF-16 string must be aligned on 2-byte boundary. Strings and char arrays
758 // do not provide necessary alignment, so copy constant string into properly
759 // allocated memory in heap.
760 llvm::BumpPtrAllocator Alloc;
761 char *StrBuff = (char *)Alloc.Allocate(Size: 16, Alignment: 4);
762 std::memset(s: StrBuff, c: 0, n: 16);
763 std::memcpy(dest: StrBuff, src: "\xFF\xFE\x00\xD8\x00\x00", n: 6);
764 StringRef BadUTF(StrBuff, 6);
765 FS->setCurrentWorkingDirectory(TestRoot);
766 FS->addFile(Path: "/opt/root.cfg", ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: BadUTF));
767 FS->addFile(Path: "/home/user/test.cfg", ModificationTime: 0,
768 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "@file.rsp"));
769
770 {
771 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
772 "clang LLVM compiler", FS);
773 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
774 Args: {"/home/test/bin/clang", "--config", "/opt/root.cfg", "--version"}));
775 ASSERT_TRUE(C);
776 ASSERT_TRUE(C->containsError());
777 EXPECT_EQ(1U, DiagConsumer->Errors.size());
778 EXPECT_STREQ("cannot read configuration file '" FILENAME
779 "': Could not convert UTF16 to UTF8",
780 DiagConsumer->Errors[0].c_str());
781 }
782 DiagConsumer->clear();
783 {
784 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
785 "clang LLVM compiler", FS);
786 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
787 Args: {"/home/test/bin/clang", "--config", "/opt", "--version"}));
788 ASSERT_TRUE(C);
789 ASSERT_TRUE(C->containsError());
790 EXPECT_EQ(1U, DiagConsumer->Errors.size());
791 EXPECT_STREQ("configuration file '" DIRNAME
792 "' cannot be opened: not a regular file",
793 DiagConsumer->Errors[0].c_str());
794 }
795 DiagConsumer->clear();
796 {
797 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
798 "clang LLVM compiler", FS);
799 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
800 Args: {"/home/test/bin/clang", "--config", "root",
801 "--config-system-dir=", "--config-user-dir=", "--version"}));
802 ASSERT_TRUE(C);
803 ASSERT_TRUE(C->containsError());
804 EXPECT_EQ(1U, DiagConsumer->Errors.size());
805 EXPECT_STREQ("configuration file 'root' cannot be found",
806 DiagConsumer->Errors[0].c_str());
807 }
808
809#undef FILENAME
810#undef DIRNAME
811}
812
813TEST(ToolChainTest, ConfigInexistentInclude) {
814 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
815 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
816 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
817 new SimpleDiagnosticConsumer());
818 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
819 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
820 new llvm::vfs::InMemoryFileSystem);
821
822#ifdef _WIN32
823 const char *TestRoot = "C:\\";
824#define USERCONFIG "C:\\home\\user\\test.cfg"
825#define UNEXISTENT "C:\\home\\user\\file.rsp"
826#else
827 const char *TestRoot = "/";
828#define USERCONFIG "/home/user/test.cfg"
829#define UNEXISTENT "/home/user/file.rsp"
830#endif
831 FS->setCurrentWorkingDirectory(TestRoot);
832 FS->addFile(Path: "/home/user/test.cfg", ModificationTime: 0,
833 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "@file.rsp"));
834
835 {
836 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
837 "clang LLVM compiler", FS);
838 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
839 Args: {"/home/test/bin/clang", "--config", "test.cfg",
840 "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
841 ASSERT_TRUE(C);
842 ASSERT_TRUE(C->containsError());
843 EXPECT_EQ(1U, DiagConsumer->Errors.size());
844 EXPECT_STRCASEEQ("cannot read configuration file '" USERCONFIG
845 "': cannot not open file '" UNEXISTENT
846 "': no such file or directory",
847 DiagConsumer->Errors[0].c_str());
848 }
849
850#undef USERCONFIG
851#undef UNEXISTENT
852}
853
854TEST(ToolChainTest, ConfigRecursiveInclude) {
855 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
856 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
857 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
858 new SimpleDiagnosticConsumer());
859 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
860 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
861 new llvm::vfs::InMemoryFileSystem);
862
863#ifdef _WIN32
864 const char *TestRoot = "C:\\";
865#define USERCONFIG "C:\\home\\user\\test.cfg"
866#define INCLUDED1 "C:\\home\\user\\file1.cfg"
867#else
868 const char *TestRoot = "/";
869#define USERCONFIG "/home/user/test.cfg"
870#define INCLUDED1 "/home/user/file1.cfg"
871#endif
872 FS->setCurrentWorkingDirectory(TestRoot);
873 FS->addFile(Path: "/home/user/test.cfg", ModificationTime: 0,
874 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "@file1.cfg"));
875 FS->addFile(Path: "/home/user/file1.cfg", ModificationTime: 0,
876 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "@file2.cfg"));
877 FS->addFile(Path: "/home/user/file2.cfg", ModificationTime: 0,
878 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "@file3.cfg"));
879 FS->addFile(Path: "/home/user/file3.cfg", ModificationTime: 0,
880 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "@file1.cfg"));
881
882 {
883 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
884 "clang LLVM compiler", FS);
885 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
886 Args: {"/home/test/bin/clang", "--config", "test.cfg",
887 "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
888 ASSERT_TRUE(C);
889 ASSERT_TRUE(C->containsError());
890 EXPECT_EQ(1U, DiagConsumer->Errors.size());
891 EXPECT_STREQ("cannot read configuration file '" USERCONFIG
892 "': recursive expansion of: '" INCLUDED1 "'",
893 DiagConsumer->Errors[0].c_str());
894 }
895
896#undef USERCONFIG
897#undef INCLUDED1
898}
899
900TEST(ToolChainTest, NestedConfigFile) {
901 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
902 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
903 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
904 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
905 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
906 new llvm::vfs::InMemoryFileSystem);
907
908#ifdef _WIN32
909 const char *TestRoot = "C:\\";
910#else
911 const char *TestRoot = "/";
912#endif
913 FS->setCurrentWorkingDirectory(TestRoot);
914
915 FS->addFile(Path: "/opt/sdk/root.cfg", ModificationTime: 0,
916 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "--config=platform.cfg\n"));
917 FS->addFile(Path: "/opt/sdk/platform.cfg", ModificationTime: 0,
918 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "--sysroot=/platform-sys\n"));
919 FS->addFile(Path: "/home/test/bin/platform.cfg", ModificationTime: 0,
920 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "--sysroot=/platform-bin\n"));
921
922 SmallString<128> ClangExecutable("/home/test/bin/clang");
923 FS->makeAbsolute(Path&: ClangExecutable);
924
925 // User file is absent - use system definitions.
926 {
927 Driver TheDriver(ClangExecutable, "arm-linux-gnueabi", Diags,
928 "clang LLVM compiler", FS);
929 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
930 Args: {"/home/test/bin/clang", "--config", "root.cfg",
931 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
932 ASSERT_TRUE(C);
933 ASSERT_FALSE(C->containsError());
934 EXPECT_EQ("/platform-sys", TheDriver.SysRoot);
935 }
936
937 // User file overrides system definitions.
938 FS->addFile(Path: "/home/test/sdk/platform.cfg", ModificationTime: 0,
939 Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "--sysroot=/platform-user\n"));
940 {
941 Driver TheDriver(ClangExecutable, "arm-linux-gnueabi", Diags,
942 "clang LLVM compiler", FS);
943 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
944 Args: {"/home/test/bin/clang", "--config", "root.cfg",
945 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
946 ASSERT_TRUE(C);
947 ASSERT_FALSE(C->containsError());
948 EXPECT_EQ("/platform-user", TheDriver.SysRoot);
949 }
950}
951
952} // end anonymous namespace.
953