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