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

source code of clang/unittests/Driver/ToolChainTest.cpp