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