1 | //===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Unit tests for ToolChains. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/Driver/ToolChain.h" |
14 | #include "clang/Basic/DiagnosticIDs.h" |
15 | #include "clang/Basic/DiagnosticOptions.h" |
16 | #include "clang/Basic/LLVM.h" |
17 | #include "clang/Basic/TargetOptions.h" |
18 | #include "clang/Driver/Compilation.h" |
19 | #include "clang/Driver/Driver.h" |
20 | #include "clang/Frontend/CompilerInstance.h" |
21 | #include "llvm/ADT/ArrayRef.h" |
22 | #include "llvm/MC/TargetRegistry.h" |
23 | #include "llvm/Support/TargetSelect.h" |
24 | #include "llvm/Support/VirtualFileSystem.h" |
25 | #include "llvm/Support/raw_ostream.h" |
26 | #include "gtest/gtest.h" |
27 | #include <memory> |
28 | |
29 | #include "SimpleDiagnosticConsumer.h" |
30 | |
31 | using namespace clang; |
32 | using namespace clang::driver; |
33 | |
34 | namespace { |
35 | |
36 | TEST(ToolChainTest, VFSGCCInstallation) { |
37 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
38 | |
39 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
40 | struct TestDiagnosticConsumer : public DiagnosticConsumer {}; |
41 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
42 | new llvm::vfs::InMemoryFileSystem); |
43 | |
44 | const char *EmptyFiles[] = { |
45 | "foo.cpp" , |
46 | "/bin/clang" , |
47 | "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o" , |
48 | "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o" , |
49 | "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o" , |
50 | "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o" , |
51 | "/usr/lib/arm-linux-gnueabi/crt1.o" , |
52 | "/usr/lib/arm-linux-gnueabi/crti.o" , |
53 | "/usr/lib/arm-linux-gnueabi/crtn.o" , |
54 | "/usr/lib/arm-linux-gnueabihf/crt1.o" , |
55 | "/usr/lib/arm-linux-gnueabihf/crti.o" , |
56 | "/usr/lib/arm-linux-gnueabihf/crtn.o" , |
57 | "/usr/include/arm-linux-gnueabi/.keep" , |
58 | "/usr/include/arm-linux-gnueabihf/.keep" , |
59 | "/lib/arm-linux-gnueabi/.keep" , |
60 | "/lib/arm-linux-gnueabihf/.keep" , |
61 | |
62 | "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtbegin.o" , |
63 | "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtend.o" , |
64 | "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtbegin.o" , |
65 | "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtend.o" , |
66 | "/sysroot/usr/lib/arm-linux-gnueabi/crt1.o" , |
67 | "/sysroot/usr/lib/arm-linux-gnueabi/crti.o" , |
68 | "/sysroot/usr/lib/arm-linux-gnueabi/crtn.o" , |
69 | "/sysroot/usr/lib/arm-linux-gnueabihf/crt1.o" , |
70 | "/sysroot/usr/lib/arm-linux-gnueabihf/crti.o" , |
71 | "/sysroot/usr/lib/arm-linux-gnueabihf/crtn.o" , |
72 | "/sysroot/usr/include/arm-linux-gnueabi/.keep" , |
73 | "/sysroot/usr/include/arm-linux-gnueabihf/.keep" , |
74 | "/sysroot/lib/arm-linux-gnueabi/.keep" , |
75 | "/sysroot/lib/arm-linux-gnueabihf/.keep" , |
76 | }; |
77 | |
78 | for (const char *Path : EmptyFiles) |
79 | InMemoryFileSystem->addFile(Path, 0, |
80 | llvm::MemoryBuffer::getMemBuffer("\n" )); |
81 | |
82 | { |
83 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); |
84 | Driver TheDriver("/bin/clang" , "arm-linux-gnueabihf" , Diags, |
85 | "clang LLVM compiler" , InMemoryFileSystem); |
86 | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( |
87 | {"-fsyntax-only" , "--gcc-toolchain=" , "--sysroot=" , "foo.cpp" })); |
88 | ASSERT_TRUE(C); |
89 | std::string S; |
90 | { |
91 | llvm::raw_string_ostream OS(S); |
92 | C->getDefaultToolChain().printVerboseInfo(OS); |
93 | } |
94 | if (is_style_windows(llvm::sys::path::Style::native)) |
95 | std::replace(S.begin(), S.end(), '\\', '/'); |
96 | EXPECT_EQ( |
97 | "Found candidate GCC installation: " |
98 | "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" |
99 | "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" |
100 | "Candidate multilib: .;@m32\n" |
101 | "Selected multilib: .;@m32\n" , |
102 | S); |
103 | } |
104 | |
105 | { |
106 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); |
107 | Driver TheDriver("/bin/clang" , "arm-linux-gnueabihf" , Diags, |
108 | "clang LLVM compiler" , InMemoryFileSystem); |
109 | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( |
110 | {"-fsyntax-only" , "--gcc-toolchain=" , "--sysroot=/sysroot" , |
111 | "foo.cpp" })); |
112 | ASSERT_TRUE(C); |
113 | std::string S; |
114 | { |
115 | llvm::raw_string_ostream OS(S); |
116 | C->getDefaultToolChain().printVerboseInfo(OS); |
117 | } |
118 | if (is_style_windows(llvm::sys::path::Style::native)) |
119 | std::replace(S.begin(), S.end(), '\\', '/'); |
120 | // Test that 4.5.3 from --sysroot is not overridden by 4.6.3 (larger |
121 | // version) from /usr. |
122 | EXPECT_EQ("Found candidate GCC installation: " |
123 | "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n" |
124 | "Selected GCC installation: " |
125 | "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n" |
126 | "Candidate multilib: .;@m32\n" |
127 | "Selected multilib: .;@m32\n" , |
128 | S); |
129 | } |
130 | } |
131 | |
132 | TEST(ToolChainTest, VFSGCCInstallationRelativeDir) { |
133 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
134 | |
135 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
136 | struct TestDiagnosticConsumer : public DiagnosticConsumer {}; |
137 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); |
138 | IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
139 | new llvm::vfs::InMemoryFileSystem); |
140 | Driver TheDriver("/home/test/bin/clang" , "arm-linux-gnueabi" , Diags, |
141 | "clang LLVM compiler" , InMemoryFileSystem); |
142 | |
143 | const char *EmptyFiles[] = { |
144 | "foo.cpp" , "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o" , |
145 | "/home/test/include/arm-linux-gnueabi/.keep" }; |
146 | |
147 | for (const char *Path : EmptyFiles) |
148 | InMemoryFileSystem->addFile(Path, 0, |
149 | llvm::MemoryBuffer::getMemBuffer("\n" )); |
150 | |
151 | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( |
152 | {"-fsyntax-only" , "--gcc-toolchain=" , "foo.cpp" })); |
153 | EXPECT_TRUE(C); |
154 | |
155 | std::string S; |
156 | { |
157 | llvm::raw_string_ostream OS(S); |
158 | C->getDefaultToolChain().printVerboseInfo(OS); |
159 | } |
160 | if (is_style_windows(llvm::sys::path::Style::native)) |
161 | std::replace(S.begin(), S.end(), '\\', '/'); |
162 | EXPECT_EQ("Found candidate GCC installation: " |
163 | "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n" |
164 | "Selected GCC installation: " |
165 | "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n" |
166 | "Candidate multilib: .;@m32\n" |
167 | "Selected multilib: .;@m32\n" , |
168 | S); |
169 | } |
170 | |
171 | TEST(ToolChainTest, 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 | |
319 | TEST(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 | } |
352 | TEST(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 | |
364 | TEST(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 | |
390 | TEST(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 | |
465 | TEST(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 | |
494 | TEST(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 | |
518 | TEST(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 | |
528 | TEST(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 | |
534 | struct 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 | |
554 | TEST(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 | |
611 | struct 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 | |
631 | TEST(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 | |
652 | TEST(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 | |
726 | TEST(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 | |
767 | TEST(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 | |
813 | TEST(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 | |