1 //===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Unit tests for ToolChains.
11 //===----------------------------------------------------------------------===//
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"
31 #include "SimpleDiagnosticConsumer.h"
33 using namespace clang
;
34 using namespace clang::driver
;
38 TEST(ToolChainTest
, VFSGCCInstallation
) {
39 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
41 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
42 struct TestDiagnosticConsumer
: public DiagnosticConsumer
{};
43 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> InMemoryFileSystem(
44 new llvm::vfs::InMemoryFileSystem
);
46 const char *EmptyFiles
[] = {
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",
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",
80 for (const char *Path
: EmptyFiles
)
81 InMemoryFileSystem
->addFile(Path
, 0,
82 llvm::MemoryBuffer::getMemBuffer("\n"));
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 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"}));
93 llvm::raw_string_ostream
OS(S
);
94 C
->getDefaultToolChain().printVerboseInfo(OS
);
96 if (is_style_windows(llvm::sys::path::Style::native
))
97 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
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 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=/sysroot",
117 llvm::raw_string_ostream
OS(S
);
118 C
->getDefaultToolChain().printVerboseInfo(OS
);
120 if (is_style_windows(llvm::sys::path::Style::native
))
121 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
134 TEST(ToolChainTest
, VFSGCCInstallationRelativeDir
) {
135 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
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
);
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"};
149 for (const char *Path
: EmptyFiles
)
150 InMemoryFileSystem
->addFile(Path
, 0,
151 llvm::MemoryBuffer::getMemBuffer("\n"));
153 std::unique_ptr
<Compilation
> C(TheDriver
.BuildCompilation(
154 {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
159 llvm::raw_string_ostream
OS(S
);
160 C
->getDefaultToolChain().printVerboseInfo(OS
);
162 if (is_style_windows(llvm::sys::path::Style::native
))
163 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
173 TEST(ToolChainTest
, VFSSolarisMultiGCCInstallation
) {
174 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
176 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
177 struct TestDiagnosticConsumer
: public DiagnosticConsumer
{};
178 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> InMemoryFileSystem(
179 new llvm::vfs::InMemoryFileSystem
);
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",
197 for (const char *Path
: EmptyFiles
)
198 InMemoryFileSystem
->addFile(Path
, 0,
199 llvm::MemoryBuffer::getMemBuffer("\n"));
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({"-v", "--gcc-toolchain=", "--sysroot="}));
210 llvm::raw_string_ostream
OS(S
);
211 C
->getDefaultToolChain().printVerboseInfo(OS
);
213 if (is_style_windows(llvm::sys::path::Style::native
))
214 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
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({"-v", "--gcc-toolchain=", "--sysroot="}));
234 llvm::raw_string_ostream
OS(S
);
235 C
->getDefaultToolChain().printVerboseInfo(OS
);
237 if (is_style_windows(llvm::sys::path::Style::native
))
238 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
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({"-v", "--gcc-toolchain=", "--sysroot="}));
258 llvm::raw_string_ostream
OS(S
);
259 C
->getDefaultToolChain().printVerboseInfo(OS
);
261 if (is_style_windows(llvm::sys::path::Style::native
))
262 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
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({"-v", "--gcc-toolchain=", "--sysroot="}));
282 llvm::raw_string_ostream
OS(S
);
283 C
->getDefaultToolChain().printVerboseInfo(OS
);
285 if (is_style_windows(llvm::sys::path::Style::native
))
286 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
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({"-v", "--gcc-toolchain=", "--sysroot="}));
305 llvm::raw_string_ostream
OS(S
);
306 C
->getDefaultToolChain().printVerboseInfo(OS
);
308 if (is_style_windows(llvm::sys::path::Style::native
))
309 std::replace(S
.begin(), S
.end(), '\\', '/');
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",
321 MATCHER_P(jobHasArgs
, Substr
, "") {
322 const driver::Command
&C
= arg
;
323 std::string Args
= "";
324 llvm::ListSeparator
Sep(" ");
325 for (const char *Arg
: C
.getArguments()) {
329 if (is_style_windows(llvm::sys::path::Style::native
))
330 std::replace(Args
.begin(), Args
.end(), '\\', '/');
331 if (llvm::StringRef(Args
).contains(Substr
))
333 *result_listener
<< "whose args are '" << Args
<< "'";
337 TEST(ToolChainTest
, VFSGnuLibcxxPathNoSysroot
) {
338 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
340 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
341 struct TestDiagnosticConsumer
: public DiagnosticConsumer
{};
342 IntrusiveRefCntPtr
<llvm::vfs::InMemoryFileSystem
> InMemoryFileSystem(
343 new llvm::vfs::InMemoryFileSystem
);
345 const char *EmptyFiles
[] = {
348 "/usr/include/c++/v1/cstdio",
351 for (const char *Path
: EmptyFiles
)
352 InMemoryFileSystem
->addFile(Path
, 0,
353 llvm::MemoryBuffer::getMemBuffer("\n"));
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 {"/bin/clang", "-fsyntax-only", "-stdlib=libc++",
361 "--sysroot=", "foo.cpp"}));
363 EXPECT_THAT(C
->getJobs(), testing::ElementsAre(jobHasArgs(
364 "-internal-isystem /usr/include/c++/v1")));
368 TEST(ToolChainTest
, DefaultDriverMode
) {
369 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
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
);
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);
387 std::unique_ptr
<Compilation
> CC(CCDriver
.BuildCompilation(
388 { "/home/test/bin/clang", "foo.cpp"}));
389 std::unique_ptr
<Compilation
> CXX(CXXDriver
.BuildCompilation(
390 { "/home/test/bin/clang++", "foo.cpp"}));
391 std::unique_ptr
<Compilation
> CL(CLDriver
.BuildCompilation(
392 { "/home/test/bin/clang-cl", "foo.cpp"}));
397 EXPECT_TRUE(CCDriver
.CCCIsCC());
398 EXPECT_TRUE(CXXDriver
.CCCIsCXX());
399 EXPECT_TRUE(CLDriver
.IsCLMode());
401 TEST(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 {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
410 EXPECT_TRUE(C
->containsError());
413 TEST(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
);
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
);
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
);
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
);
439 TEST(ToolChainTest
, GetTargetAndMode
) {
440 llvm::InitializeAllTargets();
441 std::string IgnoredError
;
442 if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError
))
445 ParsedClangName Res
= ToolChain::getTargetAndModeFromProgramName("clang");
446 EXPECT_TRUE(Res
.TargetPrefix
.empty());
447 EXPECT_TRUE(Res
.ModeSuffix
== "clang");
448 EXPECT_TRUE(Res
.DriverMode
== nullptr);
449 EXPECT_FALSE(Res
.TargetIsValid
);
451 Res
= ToolChain::getTargetAndModeFromProgramName("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
);
457 Res
= ToolChain::getTargetAndModeFromProgramName("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
);
463 Res
= ToolChain::getTargetAndModeFromProgramName("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
);
469 Res
= ToolChain::getTargetAndModeFromProgramName("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
);
475 Res
= ToolChain::getTargetAndModeFromProgramName(
476 "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
);
482 Res
= ToolChain::getTargetAndModeFromProgramName(
483 "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
);
489 Res
= ToolChain::getTargetAndModeFromProgramName("qqq");
490 EXPECT_TRUE(Res
.TargetPrefix
.empty());
491 EXPECT_TRUE(Res
.ModeSuffix
.empty());
492 EXPECT_TRUE(Res
.DriverMode
== nullptr);
493 EXPECT_FALSE(Res
.TargetIsValid
);
495 Res
= ToolChain::getTargetAndModeFromProgramName("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
);
501 Res
= ToolChain::getTargetAndModeFromProgramName("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
);
507 Res
= ToolChain::getTargetAndModeFromProgramName("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
);
514 TEST(ToolChainTest
, CommandOutput
) {
515 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
= new DiagnosticOptions();
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
);
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({"/home/test/bin/clang", "foo.cpp"}));
528 const JobList
&Jobs
= CC
->getJobs();
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
).endswith(".o"));
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
);
543 TEST(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
);
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({"/home/test/bin/clang", "foo.cpp"}));
557 bool CallbackHasCalled
= false;
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(*CmdCompile
, FailingCmd
);
564 EXPECT_TRUE(CallbackHasCalled
);
567 TEST(CompilerInvocation
, SplitSwarfSingleCrash
) {
568 static constexpr const char *Args
[] = {
569 "clang", "--target=arm-linux-gnueabi",
570 "-gdwarf-4", "-gsplit-dwarf=single",
572 CreateInvocationOptions CIOpts
;
573 std::unique_ptr
<CompilerInvocation
> CI
= createInvocation(Args
, CIOpts
);
574 EXPECT_TRUE(CI
); // no-crash
577 TEST(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");
583 struct 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(Errors
.back());
591 Info
.FormatDiagnostic(Msgs
.back());
594 void clear() override
{
597 DiagnosticConsumer::clear();
599 std::vector
<SmallString
<32>> Msgs
;
600 std::vector
<SmallString
<32>> Errors
;
603 TEST(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
);
612 const char *TestRoot
= "C:\\";
614 const char *TestRoot
= "/";
616 FS
->setCurrentWorkingDirectory(TestRoot
);
619 "/opt/sdk/root.cfg", 0,
620 llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform0\n"));
622 "/home/test/sdk/root.cfg", 0,
623 llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform1\n"));
625 "/home/test/bin/root.cfg", 0,
626 llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform2\n"));
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 {"/home/test/bin/clang", "--config", "root.cfg",
633 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
635 ASSERT_FALSE(C
->containsError());
636 EXPECT_EQ("/opt/sdk/platform1", TheDriver
.SysRoot
);
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 {"/home/test/bin/clang", "--config", "root.cfg",
643 "--config-system-dir=/opt/sdk", "--config-user-dir="}));
645 ASSERT_FALSE(C
->containsError());
646 EXPECT_EQ("/opt/sdk/platform0", TheDriver
.SysRoot
);
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 {"/home/test/bin/clang", "--config", "root.cfg",
653 "--config-system-dir=", "--config-user-dir="}));
655 ASSERT_FALSE(C
->containsError());
656 EXPECT_EQ("/opt/sdk/platform2", TheDriver
.SysRoot
);
660 struct FileSystemWithError
: public llvm::vfs::FileSystem
{
661 llvm::ErrorOr
<llvm::vfs::Status
> status(const Twine
&Path
) override
{
662 return std::make_error_code(std::errc::no_such_file_or_directory
);
664 llvm::ErrorOr
<std::unique_ptr
<llvm::vfs::File
>>
665 openFileForRead(const Twine
&Path
) override
{
666 return std::make_error_code(std::errc::permission_denied
);
668 llvm::vfs::directory_iterator
dir_begin(const Twine
&Dir
,
669 std::error_code
&EC
) override
{
670 return llvm::vfs::directory_iterator();
672 std::error_code
setCurrentWorkingDirectory(const Twine
&Path
) override
{
673 return std::make_error_code(std::errc::permission_denied
);
675 llvm::ErrorOr
<std::string
> getCurrentWorkingDirectory() const override
{
676 return std::make_error_code(std::errc::permission_denied
);
680 TEST(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
);
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({"/home/test/bin/clang", "--no-default-config",
692 "--config", "./root.cfg", "--version"}));
694 ASSERT_TRUE(C
->containsError());
695 EXPECT_EQ(1U, Diags
.getNumErrors());
696 EXPECT_STREQ("configuration file './root.cfg' cannot be opened: cannot get "
698 DiagConsumer
->Errors
[0].c_str());
701 TEST(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
);
711 const char *TestRoot
= "C:\\";
712 #define FILENAME "C:/opt/root.cfg"
713 #define DIRNAME "C:/opt"
715 const char *TestRoot
= "/";
716 #define FILENAME "/opt/root.cfg"
717 #define DIRNAME "/opt"
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(16, 4);
724 std::memset(StrBuff
, 0, 16);
725 std::memcpy(StrBuff
, "\xFF\xFE\x00\xD8\x00\x00", 6);
726 StringRef
BadUTF(StrBuff
, 6);
727 FS
->setCurrentWorkingDirectory(TestRoot
);
728 FS
->addFile("/opt/root.cfg", 0, llvm::MemoryBuffer::getMemBuffer(BadUTF
));
729 FS
->addFile("/home/user/test.cfg", 0,
730 llvm::MemoryBuffer::getMemBuffer("@file.rsp"));
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 {"/home/test/bin/clang", "--config", "/opt/root.cfg", "--version"}));
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());
744 DiagConsumer
->clear();
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 {"/home/test/bin/clang", "--config", "/opt", "--version"}));
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());
757 DiagConsumer
->clear();
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 {"/home/test/bin/clang", "--config", "root",
763 "--config-system-dir=", "--config-user-dir=", "--version"}));
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());
775 TEST(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
);
785 const char *TestRoot
= "C:\\";
786 #define USERCONFIG "C:\\home\\user\\test.cfg"
787 #define UNEXISTENT "C:\\home\\user\\file.rsp"
789 const char *TestRoot
= "/";
790 #define USERCONFIG "/home/user/test.cfg"
791 #define UNEXISTENT "/home/user/file.rsp"
793 FS
->setCurrentWorkingDirectory(TestRoot
);
794 FS
->addFile("/home/user/test.cfg", 0,
795 llvm::MemoryBuffer::getMemBuffer("@file.rsp"));
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 {"/home/test/bin/clang", "--config", "test.cfg",
802 "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
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());
816 TEST(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
);
826 const char *TestRoot
= "C:\\";
827 #define USERCONFIG "C:\\home\\user\\test.cfg"
828 #define INCLUDED1 "C:\\home\\user\\file1.cfg"
830 const char *TestRoot
= "/";
831 #define USERCONFIG "/home/user/test.cfg"
832 #define INCLUDED1 "/home/user/file1.cfg"
834 FS
->setCurrentWorkingDirectory(TestRoot
);
835 FS
->addFile("/home/user/test.cfg", 0,
836 llvm::MemoryBuffer::getMemBuffer("@file1.cfg"));
837 FS
->addFile("/home/user/file1.cfg", 0,
838 llvm::MemoryBuffer::getMemBuffer("@file2.cfg"));
839 FS
->addFile("/home/user/file2.cfg", 0,
840 llvm::MemoryBuffer::getMemBuffer("@file3.cfg"));
841 FS
->addFile("/home/user/file3.cfg", 0,
842 llvm::MemoryBuffer::getMemBuffer("@file1.cfg"));
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 {"/home/test/bin/clang", "--config", "test.cfg",
849 "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
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());
862 TEST(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
);
871 const char *TestRoot
= "C:\\";
873 const char *TestRoot
= "/";
875 FS
->setCurrentWorkingDirectory(TestRoot
);
877 FS
->addFile("/opt/sdk/root.cfg", 0,
878 llvm::MemoryBuffer::getMemBuffer("--config=platform.cfg\n"));
879 FS
->addFile("/opt/sdk/platform.cfg", 0,
880 llvm::MemoryBuffer::getMemBuffer("--sysroot=/platform-sys\n"));
881 FS
->addFile("/home/test/bin/platform.cfg", 0,
882 llvm::MemoryBuffer::getMemBuffer("--sysroot=/platform-bin\n"));
884 SmallString
<128> ClangExecutable("/home/test/bin/clang");
885 FS
->makeAbsolute(ClangExecutable
);
887 // User file is absent - use system definitions.
889 Driver
TheDriver(ClangExecutable
, "arm-linux-gnueabi", Diags
,
890 "clang LLVM compiler", FS
);
891 std::unique_ptr
<Compilation
> C(TheDriver
.BuildCompilation(
892 {"/home/test/bin/clang", "--config", "root.cfg",
893 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
895 ASSERT_FALSE(C
->containsError());
896 EXPECT_EQ("/platform-sys", TheDriver
.SysRoot
);
899 // User file overrides system definitions.
900 FS
->addFile("/home/test/sdk/platform.cfg", 0,
901 llvm::MemoryBuffer::getMemBuffer("--sysroot=/platform-user\n"));
903 Driver
TheDriver(ClangExecutable
, "arm-linux-gnueabi", Diags
,
904 "clang LLVM compiler", FS
);
905 std::unique_ptr
<Compilation
> C(TheDriver
.BuildCompilation(
906 {"/home/test/bin/clang", "--config", "root.cfg",
907 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
909 ASSERT_FALSE(C
->containsError());
910 EXPECT_EQ("/platform-user", TheDriver
.SysRoot
);
914 } // end anonymous namespace.