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/Driver/Compilation.h"
18 #include "clang/Driver/Driver.h"
19 #include "llvm/Support/TargetRegistry.h"
20 #include "llvm/Support/TargetSelect.h"
21 #include "llvm/Support/VirtualFileSystem.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "gtest/gtest.h"
24 using namespace clang;
25 using namespace clang::driver;
26
27 namespace {
28
TEST(ToolChainTest,VFSGCCInstallation)29 TEST(ToolChainTest, VFSGCCInstallation) {
30 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
31
32 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
33 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
34 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
35 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
36 new llvm::vfs::InMemoryFileSystem);
37 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
38 InMemoryFileSystem);
39
40 const char *EmptyFiles[] = {
41 "foo.cpp",
42 "/bin/clang",
43 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
44 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o",
45 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o",
46 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o",
47 "/usr/lib/arm-linux-gnueabi/crt1.o",
48 "/usr/lib/arm-linux-gnueabi/crti.o",
49 "/usr/lib/arm-linux-gnueabi/crtn.o",
50 "/usr/lib/arm-linux-gnueabihf/crt1.o",
51 "/usr/lib/arm-linux-gnueabihf/crti.o",
52 "/usr/lib/arm-linux-gnueabihf/crtn.o",
53 "/usr/include/arm-linux-gnueabi/.keep",
54 "/usr/include/arm-linux-gnueabihf/.keep",
55 "/lib/arm-linux-gnueabi/.keep",
56 "/lib/arm-linux-gnueabihf/.keep"};
57
58 for (const char *Path : EmptyFiles)
59 InMemoryFileSystem->addFile(Path, 0,
60 llvm::MemoryBuffer::getMemBuffer("\n"));
61
62 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
63 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"}));
64 EXPECT_TRUE(C);
65
66 std::string S;
67 {
68 llvm::raw_string_ostream OS(S);
69 C->getDefaultToolChain().printVerboseInfo(OS);
70 }
71 #if _WIN32
72 std::replace(S.begin(), S.end(), '\\', '/');
73 #endif
74 EXPECT_EQ(
75 "Found candidate GCC installation: "
76 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
77 "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
78 "Candidate multilib: .;@m32\n"
79 "Selected multilib: .;@m32\n",
80 S);
81 }
82
TEST(ToolChainTest,VFSGCCInstallationRelativeDir)83 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
84 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
85
86 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
87 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
88 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
89 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
90 new llvm::vfs::InMemoryFileSystem);
91 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
92 InMemoryFileSystem);
93
94 const char *EmptyFiles[] = {
95 "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
96 "/home/test/include/arm-linux-gnueabi/.keep"};
97
98 for (const char *Path : EmptyFiles)
99 InMemoryFileSystem->addFile(Path, 0,
100 llvm::MemoryBuffer::getMemBuffer("\n"));
101
102 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
103 {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
104 EXPECT_TRUE(C);
105
106 std::string S;
107 {
108 llvm::raw_string_ostream OS(S);
109 C->getDefaultToolChain().printVerboseInfo(OS);
110 }
111 #if _WIN32
112 std::replace(S.begin(), S.end(), '\\', '/');
113 #endif
114 EXPECT_EQ("Found candidate GCC installation: "
115 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
116 "Selected GCC installation: "
117 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
118 "Candidate multilib: .;@m32\n"
119 "Selected multilib: .;@m32\n",
120 S);
121 }
122
TEST(ToolChainTest,DefaultDriverMode)123 TEST(ToolChainTest, DefaultDriverMode) {
124 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
125
126 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
127 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
128 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
129 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
130 new llvm::vfs::InMemoryFileSystem);
131
132 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
133 InMemoryFileSystem);
134 CCDriver.setCheckInputsExist(false);
135 Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
136 InMemoryFileSystem);
137 CXXDriver.setCheckInputsExist(false);
138 Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
139 InMemoryFileSystem);
140 CLDriver.setCheckInputsExist(false);
141
142 std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation(
143 { "/home/test/bin/clang", "foo.cpp"}));
144 std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation(
145 { "/home/test/bin/clang++", "foo.cpp"}));
146 std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation(
147 { "/home/test/bin/clang-cl", "foo.cpp"}));
148
149 EXPECT_TRUE(CC);
150 EXPECT_TRUE(CXX);
151 EXPECT_TRUE(CL);
152 EXPECT_TRUE(CCDriver.CCCIsCC());
153 EXPECT_TRUE(CXXDriver.CCCIsCXX());
154 EXPECT_TRUE(CLDriver.IsCLMode());
155 }
TEST(ToolChainTest,InvalidArgument)156 TEST(ToolChainTest, InvalidArgument) {
157 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
158 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
159 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
160 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
161 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
162 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
163 {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
164 EXPECT_TRUE(C);
165 EXPECT_TRUE(C->containsError());
166 }
167
TEST(ToolChainTest,ParsedClangName)168 TEST(ToolChainTest, ParsedClangName) {
169 ParsedClangName Empty;
170 EXPECT_TRUE(Empty.TargetPrefix.empty());
171 EXPECT_TRUE(Empty.ModeSuffix.empty());
172 EXPECT_TRUE(Empty.DriverMode == nullptr);
173 EXPECT_FALSE(Empty.TargetIsValid);
174
175 ParsedClangName DriverOnly("clang", nullptr);
176 EXPECT_TRUE(DriverOnly.TargetPrefix.empty());
177 EXPECT_TRUE(DriverOnly.ModeSuffix == "clang");
178 EXPECT_TRUE(DriverOnly.DriverMode == nullptr);
179 EXPECT_FALSE(DriverOnly.TargetIsValid);
180
181 ParsedClangName DriverOnly2("clang++", "--driver-mode=g++");
182 EXPECT_TRUE(DriverOnly2.TargetPrefix.empty());
183 EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++");
184 EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++");
185 EXPECT_FALSE(DriverOnly2.TargetIsValid);
186
187 ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true);
188 EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386");
189 EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++");
190 EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++");
191 EXPECT_TRUE(TargetAndMode.TargetIsValid);
192 }
193
TEST(ToolChainTest,GetTargetAndMode)194 TEST(ToolChainTest, GetTargetAndMode) {
195 llvm::InitializeAllTargets();
196 std::string IgnoredError;
197 if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError))
198 return;
199
200 ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang");
201 EXPECT_TRUE(Res.TargetPrefix.empty());
202 EXPECT_TRUE(Res.ModeSuffix == "clang");
203 EXPECT_TRUE(Res.DriverMode == nullptr);
204 EXPECT_FALSE(Res.TargetIsValid);
205
206 Res = ToolChain::getTargetAndModeFromProgramName("clang++");
207 EXPECT_TRUE(Res.TargetPrefix.empty());
208 EXPECT_TRUE(Res.ModeSuffix == "clang++");
209 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
210 EXPECT_FALSE(Res.TargetIsValid);
211
212 Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0");
213 EXPECT_TRUE(Res.TargetPrefix.empty());
214 EXPECT_TRUE(Res.ModeSuffix == "clang++");
215 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
216 EXPECT_FALSE(Res.TargetIsValid);
217
218 Res = ToolChain::getTargetAndModeFromProgramName("clang++-release");
219 EXPECT_TRUE(Res.TargetPrefix.empty());
220 EXPECT_TRUE(Res.ModeSuffix == "clang++");
221 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
222 EXPECT_FALSE(Res.TargetIsValid);
223
224 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++");
225 EXPECT_TRUE(Res.TargetPrefix == "x86_64");
226 EXPECT_TRUE(Res.ModeSuffix == "clang++");
227 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
228 EXPECT_TRUE(Res.TargetIsValid);
229
230 Res = ToolChain::getTargetAndModeFromProgramName(
231 "x86_64-linux-gnu-clang-c++");
232 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
233 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
234 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
235 EXPECT_TRUE(Res.TargetIsValid);
236
237 Res = ToolChain::getTargetAndModeFromProgramName(
238 "x86_64-linux-gnu-clang-c++-tot");
239 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
240 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
241 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
242 EXPECT_TRUE(Res.TargetIsValid);
243
244 Res = ToolChain::getTargetAndModeFromProgramName("qqq");
245 EXPECT_TRUE(Res.TargetPrefix.empty());
246 EXPECT_TRUE(Res.ModeSuffix.empty());
247 EXPECT_TRUE(Res.DriverMode == nullptr);
248 EXPECT_FALSE(Res.TargetIsValid);
249
250 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq");
251 EXPECT_TRUE(Res.TargetPrefix.empty());
252 EXPECT_TRUE(Res.ModeSuffix.empty());
253 EXPECT_TRUE(Res.DriverMode == nullptr);
254 EXPECT_FALSE(Res.TargetIsValid);
255
256 Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl");
257 EXPECT_TRUE(Res.TargetPrefix == "qqq");
258 EXPECT_TRUE(Res.ModeSuffix == "clang-cl");
259 EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl");
260 EXPECT_FALSE(Res.TargetIsValid);
261 }
262 } // end anonymous namespace.
263