xref: /llvm-project/clang/unittests/Driver/ToolChainTest.cpp (revision c1728a40aae31abc0a5d4d07f6f6a6773d803f2c)
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/TargetOptions.h"
18 #include "clang/Driver/Compilation.h"
19 #include "clang/Driver/Driver.h"
20 #include "clang/Frontend/CompilerInstance.h"
21 #include "llvm/ADT/ArrayRef.h"
22 #include "llvm/MC/TargetRegistry.h"
23 #include "llvm/Support/TargetSelect.h"
24 #include "llvm/Support/VirtualFileSystem.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "gtest/gtest.h"
27 #include <memory>
28 
29 #include "SimpleDiagnosticConsumer.h"
30 
31 using namespace clang;
32 using namespace clang::driver;
33 
34 namespace {
35 
36 TEST(ToolChainTest, VFSGCCInstallation) {
37   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
38 
39   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
40   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
41   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
42       new llvm::vfs::InMemoryFileSystem);
43 
44   const char *EmptyFiles[] = {
45       "foo.cpp",
46       "/bin/clang",
47       "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
48       "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o",
49       "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o",
50       "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o",
51       "/usr/lib/arm-linux-gnueabi/crt1.o",
52       "/usr/lib/arm-linux-gnueabi/crti.o",
53       "/usr/lib/arm-linux-gnueabi/crtn.o",
54       "/usr/lib/arm-linux-gnueabihf/crt1.o",
55       "/usr/lib/arm-linux-gnueabihf/crti.o",
56       "/usr/lib/arm-linux-gnueabihf/crtn.o",
57       "/usr/include/arm-linux-gnueabi/.keep",
58       "/usr/include/arm-linux-gnueabihf/.keep",
59       "/lib/arm-linux-gnueabi/.keep",
60       "/lib/arm-linux-gnueabihf/.keep",
61 
62       "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtbegin.o",
63       "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtend.o",
64       "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtbegin.o",
65       "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtend.o",
66       "/sysroot/usr/lib/arm-linux-gnueabi/crt1.o",
67       "/sysroot/usr/lib/arm-linux-gnueabi/crti.o",
68       "/sysroot/usr/lib/arm-linux-gnueabi/crtn.o",
69       "/sysroot/usr/lib/arm-linux-gnueabihf/crt1.o",
70       "/sysroot/usr/lib/arm-linux-gnueabihf/crti.o",
71       "/sysroot/usr/lib/arm-linux-gnueabihf/crtn.o",
72       "/sysroot/usr/include/arm-linux-gnueabi/.keep",
73       "/sysroot/usr/include/arm-linux-gnueabihf/.keep",
74       "/sysroot/lib/arm-linux-gnueabi/.keep",
75       "/sysroot/lib/arm-linux-gnueabihf/.keep",
76   };
77 
78   for (const char *Path : EmptyFiles)
79     InMemoryFileSystem->addFile(Path, 0,
80                                 llvm::MemoryBuffer::getMemBuffer("\n"));
81 
82   {
83     DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
84     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
85                      "clang LLVM compiler", InMemoryFileSystem);
86     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
87         {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"}));
88     ASSERT_TRUE(C);
89     std::string S;
90     {
91       llvm::raw_string_ostream OS(S);
92       C->getDefaultToolChain().printVerboseInfo(OS);
93     }
94     if (is_style_windows(llvm::sys::path::Style::native))
95       std::replace(S.begin(), S.end(), '\\', '/');
96     EXPECT_EQ(
97         "Found candidate GCC installation: "
98         "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
99         "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
100         "Candidate multilib: .;@m32\n"
101         "Selected multilib: .;@m32\n",
102         S);
103   }
104 
105   {
106     DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
107     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
108                      "clang LLVM compiler", InMemoryFileSystem);
109     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
110         {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=/sysroot",
111          "foo.cpp"}));
112     ASSERT_TRUE(C);
113     std::string S;
114     {
115       llvm::raw_string_ostream OS(S);
116       C->getDefaultToolChain().printVerboseInfo(OS);
117     }
118     if (is_style_windows(llvm::sys::path::Style::native))
119       std::replace(S.begin(), S.end(), '\\', '/');
120     // Test that 4.5.3 from --sysroot is not overridden by 4.6.3 (larger
121     // version) from /usr.
122     EXPECT_EQ("Found candidate GCC installation: "
123               "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
124               "Selected GCC installation: "
125               "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
126               "Candidate multilib: .;@m32\n"
127               "Selected multilib: .;@m32\n",
128               S);
129   }
130 }
131 
132 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
133   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
134 
135   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
136   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
137   DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
138   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
139       new llvm::vfs::InMemoryFileSystem);
140   Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
141                    "clang LLVM compiler", InMemoryFileSystem);
142 
143   const char *EmptyFiles[] = {
144       "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
145       "/home/test/include/arm-linux-gnueabi/.keep"};
146 
147   for (const char *Path : EmptyFiles)
148     InMemoryFileSystem->addFile(Path, 0,
149                                 llvm::MemoryBuffer::getMemBuffer("\n"));
150 
151   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
152       {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
153   EXPECT_TRUE(C);
154 
155   std::string S;
156   {
157     llvm::raw_string_ostream OS(S);
158     C->getDefaultToolChain().printVerboseInfo(OS);
159   }
160   if (is_style_windows(llvm::sys::path::Style::native))
161     std::replace(S.begin(), S.end(), '\\', '/');
162   EXPECT_EQ("Found candidate GCC installation: "
163             "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
164             "Selected GCC installation: "
165             "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
166             "Candidate multilib: .;@m32\n"
167             "Selected multilib: .;@m32\n",
168             S);
169 }
170 
171 TEST(ToolChainTest, DefaultDriverMode) {
172   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
173 
174   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
175   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
176   DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
177   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
178       new llvm::vfs::InMemoryFileSystem);
179 
180   Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
181                   "clang LLVM compiler", InMemoryFileSystem);
182   CCDriver.setCheckInputsExist(false);
183   Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
184                    "clang LLVM compiler", InMemoryFileSystem);
185   CXXDriver.setCheckInputsExist(false);
186   Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
187                   "clang LLVM compiler", InMemoryFileSystem);
188   CLDriver.setCheckInputsExist(false);
189 
190   std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation(
191       { "/home/test/bin/clang", "foo.cpp"}));
192   std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation(
193       { "/home/test/bin/clang++", "foo.cpp"}));
194   std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation(
195       { "/home/test/bin/clang-cl", "foo.cpp"}));
196 
197   EXPECT_TRUE(CC);
198   EXPECT_TRUE(CXX);
199   EXPECT_TRUE(CL);
200   EXPECT_TRUE(CCDriver.CCCIsCC());
201   EXPECT_TRUE(CXXDriver.CCCIsCXX());
202   EXPECT_TRUE(CLDriver.IsCLMode());
203 }
204 TEST(ToolChainTest, InvalidArgument) {
205   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
206   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
207   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
208   DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
209   Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
210   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
211       {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
212   EXPECT_TRUE(C);
213   EXPECT_TRUE(C->containsError());
214 }
215 
216 TEST(ToolChainTest, ParsedClangName) {
217   ParsedClangName Empty;
218   EXPECT_TRUE(Empty.TargetPrefix.empty());
219   EXPECT_TRUE(Empty.ModeSuffix.empty());
220   EXPECT_TRUE(Empty.DriverMode == nullptr);
221   EXPECT_FALSE(Empty.TargetIsValid);
222 
223   ParsedClangName DriverOnly("clang", nullptr);
224   EXPECT_TRUE(DriverOnly.TargetPrefix.empty());
225   EXPECT_TRUE(DriverOnly.ModeSuffix == "clang");
226   EXPECT_TRUE(DriverOnly.DriverMode == nullptr);
227   EXPECT_FALSE(DriverOnly.TargetIsValid);
228 
229   ParsedClangName DriverOnly2("clang++", "--driver-mode=g++");
230   EXPECT_TRUE(DriverOnly2.TargetPrefix.empty());
231   EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++");
232   EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++");
233   EXPECT_FALSE(DriverOnly2.TargetIsValid);
234 
235   ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true);
236   EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386");
237   EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++");
238   EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++");
239   EXPECT_TRUE(TargetAndMode.TargetIsValid);
240 }
241 
242 TEST(ToolChainTest, GetTargetAndMode) {
243   llvm::InitializeAllTargets();
244   std::string IgnoredError;
245   if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError))
246     return;
247 
248   ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang");
249   EXPECT_TRUE(Res.TargetPrefix.empty());
250   EXPECT_TRUE(Res.ModeSuffix == "clang");
251   EXPECT_TRUE(Res.DriverMode == nullptr);
252   EXPECT_FALSE(Res.TargetIsValid);
253 
254   Res = ToolChain::getTargetAndModeFromProgramName("clang++");
255   EXPECT_TRUE(Res.TargetPrefix.empty());
256   EXPECT_TRUE(Res.ModeSuffix == "clang++");
257   EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
258   EXPECT_FALSE(Res.TargetIsValid);
259 
260   Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0");
261   EXPECT_TRUE(Res.TargetPrefix.empty());
262   EXPECT_TRUE(Res.ModeSuffix == "clang++");
263   EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
264   EXPECT_FALSE(Res.TargetIsValid);
265 
266   Res = ToolChain::getTargetAndModeFromProgramName("clang++-release");
267   EXPECT_TRUE(Res.TargetPrefix.empty());
268   EXPECT_TRUE(Res.ModeSuffix == "clang++");
269   EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
270   EXPECT_FALSE(Res.TargetIsValid);
271 
272   Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++");
273   EXPECT_TRUE(Res.TargetPrefix == "x86_64");
274   EXPECT_TRUE(Res.ModeSuffix == "clang++");
275   EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
276   EXPECT_TRUE(Res.TargetIsValid);
277 
278   Res = ToolChain::getTargetAndModeFromProgramName(
279       "x86_64-linux-gnu-clang-c++");
280   EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
281   EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
282   EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
283   EXPECT_TRUE(Res.TargetIsValid);
284 
285   Res = ToolChain::getTargetAndModeFromProgramName(
286       "x86_64-linux-gnu-clang-c++-tot");
287   EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
288   EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
289   EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
290   EXPECT_TRUE(Res.TargetIsValid);
291 
292   Res = ToolChain::getTargetAndModeFromProgramName("qqq");
293   EXPECT_TRUE(Res.TargetPrefix.empty());
294   EXPECT_TRUE(Res.ModeSuffix.empty());
295   EXPECT_TRUE(Res.DriverMode == nullptr);
296   EXPECT_FALSE(Res.TargetIsValid);
297 
298   Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq");
299   EXPECT_TRUE(Res.TargetPrefix.empty());
300   EXPECT_TRUE(Res.ModeSuffix.empty());
301   EXPECT_TRUE(Res.DriverMode == nullptr);
302   EXPECT_FALSE(Res.TargetIsValid);
303 
304   Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl");
305   EXPECT_TRUE(Res.TargetPrefix == "qqq");
306   EXPECT_TRUE(Res.ModeSuffix == "clang-cl");
307   EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl");
308   EXPECT_FALSE(Res.TargetIsValid);
309 
310   Res = ToolChain::getTargetAndModeFromProgramName("clang-dxc");
311   EXPECT_TRUE(Res.TargetPrefix.empty());
312   EXPECT_TRUE(Res.ModeSuffix == "clang-dxc");
313   EXPECT_STREQ(Res.DriverMode, "--driver-mode=dxc");
314   EXPECT_FALSE(Res.TargetIsValid);
315 }
316 
317 TEST(ToolChainTest, CommandOutput) {
318   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
319 
320   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
321   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
322   DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
323   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
324       new llvm::vfs::InMemoryFileSystem);
325 
326   Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
327                   "clang LLVM compiler", InMemoryFileSystem);
328   CCDriver.setCheckInputsExist(false);
329   std::unique_ptr<Compilation> CC(
330       CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"}));
331   const JobList &Jobs = CC->getJobs();
332 
333   const auto &CmdCompile = Jobs.getJobs().front();
334   const auto &InFile = CmdCompile->getInputInfos().front().getFilename();
335   EXPECT_STREQ(InFile, "foo.cpp");
336   auto ObjFile = CmdCompile->getOutputFilenames().front();
337   EXPECT_TRUE(StringRef(ObjFile).endswith(".o"));
338 
339   const auto &CmdLink = Jobs.getJobs().back();
340   const auto LinkInFile = CmdLink->getInputInfos().front().getFilename();
341   EXPECT_EQ(ObjFile, LinkInFile);
342   auto ExeFile = CmdLink->getOutputFilenames().front();
343   EXPECT_EQ("a.out", ExeFile);
344 }
345 
346 TEST(ToolChainTest, PostCallback) {
347   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
348   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
349   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
350   DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
351   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
352       new llvm::vfs::InMemoryFileSystem);
353 
354   // The executable path must not exist.
355   Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
356                   "clang LLVM compiler", InMemoryFileSystem);
357   CCDriver.setCheckInputsExist(false);
358   std::unique_ptr<Compilation> CC(
359       CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"}));
360   bool CallbackHasCalled = false;
361   CC->setPostCallback(
362       [&](const Command &C, int Ret) { CallbackHasCalled = true; });
363   const JobList &Jobs = CC->getJobs();
364   auto &CmdCompile = Jobs.getJobs().front();
365   const Command *FailingCmd = nullptr;
366   CC->ExecuteCommand(*CmdCompile, FailingCmd);
367   EXPECT_TRUE(CallbackHasCalled);
368 }
369 
370 TEST(GetDriverMode, PrefersLastDriverMode) {
371   static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo",
372                                          "--driver-mode=bar", "foo.cpp"};
373   EXPECT_EQ(getDriverMode(Args[0], llvm::makeArrayRef(Args).slice(1)), "bar");
374 }
375 
376 struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
377   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
378                         const Diagnostic &Info) override {
379     if (DiagLevel == DiagnosticsEngine::Level::Error) {
380       Errors.emplace_back();
381       Info.FormatDiagnostic(Errors.back());
382     } else {
383       Msgs.emplace_back();
384       Info.FormatDiagnostic(Msgs.back());
385     }
386   }
387   void clear() override {
388     Msgs.clear();
389     Errors.clear();
390     DiagnosticConsumer::clear();
391   }
392   std::vector<SmallString<32>> Msgs;
393   std::vector<SmallString<32>> Errors;
394 };
395 
396 TEST(ToolChainTest, ConfigFileSearch) {
397   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
398   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
399   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
400   DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
401   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
402       new llvm::vfs::InMemoryFileSystem);
403 
404 #ifdef _WIN32
405   const char *TestRoot = "C:\\";
406 #else
407   const char *TestRoot = "/";
408 #endif
409   FS->setCurrentWorkingDirectory(TestRoot);
410 
411   FS->addFile(
412       "/opt/sdk/root.cfg", 0,
413       llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform0\n"));
414   FS->addFile(
415       "/home/test/sdk/root.cfg", 0,
416       llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform1\n"));
417   FS->addFile(
418       "/home/test/bin/root.cfg", 0,
419       llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform2\n"));
420 
421   {
422     Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
423                      "clang LLVM compiler", FS);
424     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
425         {"/home/test/bin/clang", "--config", "root.cfg",
426          "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
427     ASSERT_TRUE(C);
428     ASSERT_FALSE(C->containsError());
429     EXPECT_EQ("/opt/sdk/platform1", TheDriver.SysRoot);
430   }
431   {
432     Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
433                      "clang LLVM compiler", FS);
434     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
435         {"/home/test/bin/clang", "--config", "root.cfg",
436          "--config-system-dir=/opt/sdk", "--config-user-dir="}));
437     ASSERT_TRUE(C);
438     ASSERT_FALSE(C->containsError());
439     EXPECT_EQ("/opt/sdk/platform0", TheDriver.SysRoot);
440   }
441   {
442     Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
443                      "clang LLVM compiler", FS);
444     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
445         {"/home/test/bin/clang", "--config", "root.cfg",
446          "--config-system-dir=", "--config-user-dir="}));
447     ASSERT_TRUE(C);
448     ASSERT_FALSE(C->containsError());
449     EXPECT_EQ("/opt/sdk/platform2", TheDriver.SysRoot);
450   }
451 }
452 
453 } // end anonymous namespace.
454