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