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