1 //===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Unit tests for ToolChains. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Driver/ToolChain.h" 14 #include "clang/Basic/DiagnosticIDs.h" 15 #include "clang/Basic/DiagnosticOptions.h" 16 #include "clang/Basic/LLVM.h" 17 #include "clang/Driver/Compilation.h" 18 #include "clang/Driver/Driver.h" 19 #include "llvm/ADT/ArrayRef.h" 20 #include "llvm/MC/TargetRegistry.h" 21 #include "llvm/Support/Host.h" 22 #include "llvm/Support/TargetSelect.h" 23 #include "llvm/Support/VirtualFileSystem.h" 24 #include "llvm/Support/raw_ostream.h" 25 #include "gtest/gtest.h" 26 #include <memory> 27 using namespace clang; 28 using namespace clang::driver; 29 30 namespace { 31 32 TEST(ToolChainTest, VFSGCCInstallation) { 33 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 34 35 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 36 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 37 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 38 new llvm::vfs::InMemoryFileSystem); 39 40 const char *EmptyFiles[] = { 41 "foo.cpp", 42 "/bin/clang", 43 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o", 44 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o", 45 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o", 46 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o", 47 "/usr/lib/arm-linux-gnueabi/crt1.o", 48 "/usr/lib/arm-linux-gnueabi/crti.o", 49 "/usr/lib/arm-linux-gnueabi/crtn.o", 50 "/usr/lib/arm-linux-gnueabihf/crt1.o", 51 "/usr/lib/arm-linux-gnueabihf/crti.o", 52 "/usr/lib/arm-linux-gnueabihf/crtn.o", 53 "/usr/include/arm-linux-gnueabi/.keep", 54 "/usr/include/arm-linux-gnueabihf/.keep", 55 "/lib/arm-linux-gnueabi/.keep", 56 "/lib/arm-linux-gnueabihf/.keep", 57 58 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtbegin.o", 59 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtend.o", 60 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtbegin.o", 61 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtend.o", 62 "/sysroot/usr/lib/arm-linux-gnueabi/crt1.o", 63 "/sysroot/usr/lib/arm-linux-gnueabi/crti.o", 64 "/sysroot/usr/lib/arm-linux-gnueabi/crtn.o", 65 "/sysroot/usr/lib/arm-linux-gnueabihf/crt1.o", 66 "/sysroot/usr/lib/arm-linux-gnueabihf/crti.o", 67 "/sysroot/usr/lib/arm-linux-gnueabihf/crtn.o", 68 "/sysroot/usr/include/arm-linux-gnueabi/.keep", 69 "/sysroot/usr/include/arm-linux-gnueabihf/.keep", 70 "/sysroot/lib/arm-linux-gnueabi/.keep", 71 "/sysroot/lib/arm-linux-gnueabihf/.keep", 72 }; 73 74 for (const char *Path : EmptyFiles) 75 InMemoryFileSystem->addFile(Path, 0, 76 llvm::MemoryBuffer::getMemBuffer("\n")); 77 78 { 79 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 80 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags, 81 "clang LLVM compiler", InMemoryFileSystem); 82 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 83 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"})); 84 ASSERT_TRUE(C); 85 std::string S; 86 { 87 llvm::raw_string_ostream OS(S); 88 C->getDefaultToolChain().printVerboseInfo(OS); 89 } 90 if (is_style_windows(llvm::sys::path::Style::native)) 91 std::replace(S.begin(), S.end(), '\\', '/'); 92 EXPECT_EQ( 93 "Found candidate GCC installation: " 94 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" 95 "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" 96 "Candidate multilib: .;@m32\n" 97 "Selected multilib: .;@m32\n", 98 S); 99 } 100 101 { 102 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 103 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags, 104 "clang LLVM compiler", InMemoryFileSystem); 105 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 106 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=/sysroot", 107 "foo.cpp"})); 108 ASSERT_TRUE(C); 109 std::string S; 110 { 111 llvm::raw_string_ostream OS(S); 112 C->getDefaultToolChain().printVerboseInfo(OS); 113 } 114 if (is_style_windows(llvm::sys::path::Style::native)) 115 std::replace(S.begin(), S.end(), '\\', '/'); 116 // Test that 4.5.3 from --sysroot is not overridden by 4.6.3 (larger 117 // version) from /usr. 118 EXPECT_EQ("Found candidate GCC installation: " 119 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n" 120 "Selected GCC installation: " 121 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n" 122 "Candidate multilib: .;@m32\n" 123 "Selected multilib: .;@m32\n", 124 S); 125 } 126 } 127 128 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) { 129 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 130 131 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 132 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 133 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 134 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 135 new llvm::vfs::InMemoryFileSystem); 136 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 137 "clang LLVM compiler", InMemoryFileSystem); 138 139 const char *EmptyFiles[] = { 140 "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o", 141 "/home/test/include/arm-linux-gnueabi/.keep"}; 142 143 for (const char *Path : EmptyFiles) 144 InMemoryFileSystem->addFile(Path, 0, 145 llvm::MemoryBuffer::getMemBuffer("\n")); 146 147 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 148 {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"})); 149 EXPECT_TRUE(C); 150 151 std::string S; 152 { 153 llvm::raw_string_ostream OS(S); 154 C->getDefaultToolChain().printVerboseInfo(OS); 155 } 156 if (is_style_windows(llvm::sys::path::Style::native)) 157 std::replace(S.begin(), S.end(), '\\', '/'); 158 EXPECT_EQ("Found candidate GCC installation: " 159 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n" 160 "Selected GCC installation: " 161 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n" 162 "Candidate multilib: .;@m32\n" 163 "Selected multilib: .;@m32\n", 164 S); 165 } 166 167 TEST(ToolChainTest, DefaultDriverMode) { 168 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 169 170 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 171 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 172 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 173 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 174 new llvm::vfs::InMemoryFileSystem); 175 176 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 177 "clang LLVM compiler", InMemoryFileSystem); 178 CCDriver.setCheckInputsExist(false); 179 Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags, 180 "clang LLVM compiler", InMemoryFileSystem); 181 CXXDriver.setCheckInputsExist(false); 182 Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags, 183 "clang LLVM compiler", InMemoryFileSystem); 184 CLDriver.setCheckInputsExist(false); 185 186 std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation( 187 { "/home/test/bin/clang", "foo.cpp"})); 188 std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation( 189 { "/home/test/bin/clang++", "foo.cpp"})); 190 std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation( 191 { "/home/test/bin/clang-cl", "foo.cpp"})); 192 193 EXPECT_TRUE(CC); 194 EXPECT_TRUE(CXX); 195 EXPECT_TRUE(CL); 196 EXPECT_TRUE(CCDriver.CCCIsCC()); 197 EXPECT_TRUE(CXXDriver.CCCIsCXX()); 198 EXPECT_TRUE(CLDriver.IsCLMode()); 199 } 200 TEST(ToolChainTest, InvalidArgument) { 201 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 202 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 203 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 204 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 205 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags); 206 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 207 {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"})); 208 EXPECT_TRUE(C); 209 EXPECT_TRUE(C->containsError()); 210 } 211 212 TEST(ToolChainTest, ParsedClangName) { 213 ParsedClangName Empty; 214 EXPECT_TRUE(Empty.TargetPrefix.empty()); 215 EXPECT_TRUE(Empty.ModeSuffix.empty()); 216 EXPECT_TRUE(Empty.DriverMode == nullptr); 217 EXPECT_FALSE(Empty.TargetIsValid); 218 219 ParsedClangName DriverOnly("clang", nullptr); 220 EXPECT_TRUE(DriverOnly.TargetPrefix.empty()); 221 EXPECT_TRUE(DriverOnly.ModeSuffix == "clang"); 222 EXPECT_TRUE(DriverOnly.DriverMode == nullptr); 223 EXPECT_FALSE(DriverOnly.TargetIsValid); 224 225 ParsedClangName DriverOnly2("clang++", "--driver-mode=g++"); 226 EXPECT_TRUE(DriverOnly2.TargetPrefix.empty()); 227 EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++"); 228 EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++"); 229 EXPECT_FALSE(DriverOnly2.TargetIsValid); 230 231 ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true); 232 EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386"); 233 EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++"); 234 EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++"); 235 EXPECT_TRUE(TargetAndMode.TargetIsValid); 236 } 237 238 TEST(ToolChainTest, GetTargetAndMode) { 239 llvm::InitializeAllTargets(); 240 std::string IgnoredError; 241 if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError)) 242 return; 243 244 ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang"); 245 EXPECT_TRUE(Res.TargetPrefix.empty()); 246 EXPECT_TRUE(Res.ModeSuffix == "clang"); 247 EXPECT_TRUE(Res.DriverMode == nullptr); 248 EXPECT_FALSE(Res.TargetIsValid); 249 250 Res = ToolChain::getTargetAndModeFromProgramName("clang++"); 251 EXPECT_TRUE(Res.TargetPrefix.empty()); 252 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 253 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 254 EXPECT_FALSE(Res.TargetIsValid); 255 256 Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0"); 257 EXPECT_TRUE(Res.TargetPrefix.empty()); 258 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 259 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 260 EXPECT_FALSE(Res.TargetIsValid); 261 262 Res = ToolChain::getTargetAndModeFromProgramName("clang++-release"); 263 EXPECT_TRUE(Res.TargetPrefix.empty()); 264 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 265 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 266 EXPECT_FALSE(Res.TargetIsValid); 267 268 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++"); 269 EXPECT_TRUE(Res.TargetPrefix == "x86_64"); 270 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 271 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 272 EXPECT_TRUE(Res.TargetIsValid); 273 274 Res = ToolChain::getTargetAndModeFromProgramName( 275 "x86_64-linux-gnu-clang-c++"); 276 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu"); 277 EXPECT_TRUE(Res.ModeSuffix == "clang-c++"); 278 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 279 EXPECT_TRUE(Res.TargetIsValid); 280 281 Res = ToolChain::getTargetAndModeFromProgramName( 282 "x86_64-linux-gnu-clang-c++-tot"); 283 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu"); 284 EXPECT_TRUE(Res.ModeSuffix == "clang-c++"); 285 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 286 EXPECT_TRUE(Res.TargetIsValid); 287 288 Res = ToolChain::getTargetAndModeFromProgramName("qqq"); 289 EXPECT_TRUE(Res.TargetPrefix.empty()); 290 EXPECT_TRUE(Res.ModeSuffix.empty()); 291 EXPECT_TRUE(Res.DriverMode == nullptr); 292 EXPECT_FALSE(Res.TargetIsValid); 293 294 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq"); 295 EXPECT_TRUE(Res.TargetPrefix.empty()); 296 EXPECT_TRUE(Res.ModeSuffix.empty()); 297 EXPECT_TRUE(Res.DriverMode == nullptr); 298 EXPECT_FALSE(Res.TargetIsValid); 299 300 Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl"); 301 EXPECT_TRUE(Res.TargetPrefix == "qqq"); 302 EXPECT_TRUE(Res.ModeSuffix == "clang-cl"); 303 EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl"); 304 EXPECT_FALSE(Res.TargetIsValid); 305 306 Res = ToolChain::getTargetAndModeFromProgramName("clang-dxc"); 307 EXPECT_TRUE(Res.TargetPrefix.empty()); 308 EXPECT_TRUE(Res.ModeSuffix == "clang-dxc"); 309 EXPECT_STREQ(Res.DriverMode, "--driver-mode=dxc"); 310 EXPECT_FALSE(Res.TargetIsValid); 311 } 312 313 TEST(ToolChainTest, CommandOutput) { 314 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 315 316 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 317 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 318 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 319 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 320 new llvm::vfs::InMemoryFileSystem); 321 322 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 323 "clang LLVM compiler", InMemoryFileSystem); 324 CCDriver.setCheckInputsExist(false); 325 std::unique_ptr<Compilation> CC( 326 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"})); 327 const JobList &Jobs = CC->getJobs(); 328 329 const auto &CmdCompile = Jobs.getJobs().front(); 330 const auto &InFile = CmdCompile->getInputInfos().front().getFilename(); 331 EXPECT_STREQ(InFile, "foo.cpp"); 332 auto ObjFile = CmdCompile->getOutputFilenames().front(); 333 EXPECT_TRUE(StringRef(ObjFile).endswith(".o")); 334 335 const auto &CmdLink = Jobs.getJobs().back(); 336 const auto LinkInFile = CmdLink->getInputInfos().front().getFilename(); 337 EXPECT_EQ(ObjFile, LinkInFile); 338 auto ExeFile = CmdLink->getOutputFilenames().front(); 339 EXPECT_EQ("a.out", ExeFile); 340 } 341 342 TEST(ToolChainTest, PostCallback) { 343 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 344 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 345 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 346 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 347 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 348 new llvm::vfs::InMemoryFileSystem); 349 350 // The executable path must not exist. 351 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 352 "clang LLVM compiler", InMemoryFileSystem); 353 CCDriver.setCheckInputsExist(false); 354 std::unique_ptr<Compilation> CC( 355 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"})); 356 bool CallbackHasCalled = false; 357 CC->setPostCallback( 358 [&](const Command &C, int Ret) { CallbackHasCalled = true; }); 359 const JobList &Jobs = CC->getJobs(); 360 auto &CmdCompile = Jobs.getJobs().front(); 361 const Command *FailingCmd = nullptr; 362 CC->ExecuteCommand(*CmdCompile, FailingCmd); 363 EXPECT_TRUE(CallbackHasCalled); 364 } 365 366 TEST(GetDriverMode, PrefersLastDriverMode) { 367 static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo", 368 "--driver-mode=bar", "foo.cpp"}; 369 EXPECT_EQ(getDriverMode(Args[0], llvm::makeArrayRef(Args).slice(1)), "bar"); 370 } 371 372 struct SimpleDiagnosticConsumer : public DiagnosticConsumer { 373 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 374 const Diagnostic &Info) override { 375 if (DiagLevel == DiagnosticsEngine::Level::Error) { 376 Errors.emplace_back(); 377 Info.FormatDiagnostic(Errors.back()); 378 } else { 379 Msgs.emplace_back(); 380 Info.FormatDiagnostic(Msgs.back()); 381 } 382 } 383 void clear() override { 384 Msgs.clear(); 385 Errors.clear(); 386 DiagnosticConsumer::clear(); 387 } 388 std::vector<SmallString<32>> Msgs; 389 std::vector<SmallString<32>> Errors; 390 }; 391 392 static void validateTargetProfile( 393 StringRef TargetProfile, StringRef ExpectTriple, 394 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> &InMemoryFileSystem, 395 DiagnosticsEngine &Diags) { 396 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem); 397 std::unique_ptr<Compilation> C{TheDriver.BuildCompilation( 398 {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"})}; 399 EXPECT_TRUE(C); 400 EXPECT_STREQ(TheDriver.getTargetTriple().c_str(), ExpectTriple.data()); 401 EXPECT_EQ(Diags.getNumErrors(), 0u); 402 } 403 404 static void validateTargetProfile( 405 StringRef TargetProfile, StringRef ExpectError, 406 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> &InMemoryFileSystem, 407 DiagnosticsEngine &Diags, SimpleDiagnosticConsumer *DiagConsumer, 408 unsigned NumOfErrors) { 409 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem); 410 std::unique_ptr<Compilation> C{TheDriver.BuildCompilation( 411 {"clang", "--driver-mode=dxc", TargetProfile.data(), "foo.hlsl"})}; 412 EXPECT_TRUE(C); 413 EXPECT_EQ(Diags.getNumErrors(), NumOfErrors); 414 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), ExpectError.data()); 415 Diags.Clear(); 416 DiagConsumer->clear(); 417 } 418 419 TEST(DxcModeTest, TargetProfileValidation) { 420 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 421 422 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 423 new llvm::vfs::InMemoryFileSystem); 424 425 InMemoryFileSystem->addFile("foo.hlsl", 0, 426 llvm::MemoryBuffer::getMemBuffer("\n")); 427 428 auto *DiagConsumer = new SimpleDiagnosticConsumer; 429 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 430 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer); 431 432 validateTargetProfile("-Tvs_6_0", "dxil--shadermodel6.0-vertex", 433 InMemoryFileSystem, Diags); 434 validateTargetProfile("-Ths_6_1", "dxil--shadermodel6.1-hull", 435 InMemoryFileSystem, Diags); 436 validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain", 437 InMemoryFileSystem, Diags); 438 validateTargetProfile("-Tds_6_2", "dxil--shadermodel6.2-domain", 439 InMemoryFileSystem, Diags); 440 validateTargetProfile("-Tgs_6_3", "dxil--shadermodel6.3-geometry", 441 InMemoryFileSystem, Diags); 442 validateTargetProfile("-Tps_6_4", "dxil--shadermodel6.4-pixel", 443 InMemoryFileSystem, Diags); 444 validateTargetProfile("-Tcs_6_5", "dxil--shadermodel6.5-compute", 445 InMemoryFileSystem, Diags); 446 validateTargetProfile("-Tms_6_6", "dxil--shadermodel6.6-mesh", 447 InMemoryFileSystem, Diags); 448 validateTargetProfile("-Tas_6_7", "dxil--shadermodel6.7-amplification", 449 InMemoryFileSystem, Diags); 450 validateTargetProfile("-Tlib_6_x", "dxil--shadermodel6.15-library", 451 InMemoryFileSystem, Diags); 452 453 // Invalid tests. 454 validateTargetProfile("-Tpss_6_1", "invalid profile : pss_6_1", 455 InMemoryFileSystem, Diags, DiagConsumer, 1); 456 457 validateTargetProfile("-Tps_6_x", "invalid profile : ps_6_x", 458 InMemoryFileSystem, Diags, DiagConsumer, 2); 459 validateTargetProfile("-Tlib_6_1", "invalid profile : lib_6_1", 460 InMemoryFileSystem, Diags, DiagConsumer, 3); 461 validateTargetProfile("-Tfoo", "invalid profile : foo", InMemoryFileSystem, 462 Diags, DiagConsumer, 4); 463 validateTargetProfile("", "target profile option (-T) is missing", 464 InMemoryFileSystem, Diags, DiagConsumer, 5); 465 } 466 467 TEST(DxcModeTest, ValidatorVersionValidation) { 468 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 469 470 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 471 new llvm::vfs::InMemoryFileSystem); 472 473 InMemoryFileSystem->addFile("foo.hlsl", 0, 474 llvm::MemoryBuffer::getMemBuffer("\n")); 475 476 auto *DiagConsumer = new SimpleDiagnosticConsumer; 477 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 478 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer); 479 Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem); 480 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 481 {"clang", "--driver-mode=dxc", "-Tlib_6_7", "foo.hlsl"})); 482 EXPECT_TRUE(C); 483 EXPECT_TRUE(!C->containsError()); 484 485 auto &TC = C->getDefaultToolChain(); 486 bool ContainsError = false; 487 auto Args = TheDriver.ParseArgStrings({"-validator-version", "1.1"}, false, 488 ContainsError); 489 EXPECT_FALSE(ContainsError); 490 auto DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 491 for (auto *A : Args) 492 DAL->append(A); 493 494 std::unique_ptr<llvm::opt::DerivedArgList> TranslatedArgs{ 495 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None)}; 496 EXPECT_NE(TranslatedArgs, nullptr); 497 if (TranslatedArgs) { 498 auto *A = TranslatedArgs->getLastArg( 499 clang::driver::options::OPT_dxil_validator_version); 500 EXPECT_NE(A, nullptr); 501 if (A) 502 EXPECT_STREQ(A->getValue(), "1.1"); 503 } 504 EXPECT_EQ(Diags.getNumErrors(), 0u); 505 506 // Invalid tests. 507 Args = TheDriver.ParseArgStrings({"-validator-version", "0.1"}, false, 508 ContainsError); 509 EXPECT_FALSE(ContainsError); 510 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 511 for (auto *A : Args) 512 DAL->append(A); 513 514 TranslatedArgs.reset( 515 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None)); 516 EXPECT_EQ(Diags.getNumErrors(), 1u); 517 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), 518 "invalid validator version : 0.1\nIf validator major version is " 519 "0, minor version must also be 0."); 520 Diags.Clear(); 521 DiagConsumer->clear(); 522 523 Args = TheDriver.ParseArgStrings({"-validator-version", "1"}, false, 524 ContainsError); 525 EXPECT_FALSE(ContainsError); 526 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 527 for (auto *A : Args) 528 DAL->append(A); 529 530 TranslatedArgs.reset( 531 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None)); 532 EXPECT_EQ(Diags.getNumErrors(), 2u); 533 EXPECT_STREQ(DiagConsumer->Errors.back().c_str(), 534 "invalid validator version : 1\nFormat of validator version is " 535 "\"<major>.<minor>\" (ex:\"1.4\")."); 536 Diags.Clear(); 537 DiagConsumer->clear(); 538 539 Args = TheDriver.ParseArgStrings({"-validator-version", "-Tlib_6_7"}, false, 540 ContainsError); 541 EXPECT_FALSE(ContainsError); 542 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 543 for (auto *A : Args) 544 DAL->append(A); 545 546 TranslatedArgs.reset( 547 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None)); 548 EXPECT_EQ(Diags.getNumErrors(), 3u); 549 EXPECT_STREQ( 550 DiagConsumer->Errors.back().c_str(), 551 "invalid validator version : -Tlib_6_7\nFormat of validator version is " 552 "\"<major>.<minor>\" (ex:\"1.4\")."); 553 Diags.Clear(); 554 DiagConsumer->clear(); 555 556 Args = TheDriver.ParseArgStrings({"-validator-version", "foo"}, false, 557 ContainsError); 558 EXPECT_FALSE(ContainsError); 559 DAL = std::make_unique<llvm::opt::DerivedArgList>(Args); 560 for (auto *A : Args) 561 DAL->append(A); 562 563 TranslatedArgs.reset( 564 TC.TranslateArgs(*DAL, "0", Action::OffloadKind::OFK_None)); 565 EXPECT_EQ(Diags.getNumErrors(), 4u); 566 EXPECT_STREQ( 567 DiagConsumer->Errors.back().c_str(), 568 "invalid validator version : foo\nFormat of validator version is " 569 "\"<major>.<minor>\" (ex:\"1.4\")."); 570 Diags.Clear(); 571 DiagConsumer->clear(); 572 } 573 574 TEST(ToolChainTest, Toolsets) { 575 // Ignore this test on Windows hosts. 576 llvm::Triple Host(llvm::sys::getProcessTriple()); 577 if (Host.isOSWindows()) 578 GTEST_SKIP(); 579 580 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 581 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 582 583 // Check (newer) GCC toolset installation. 584 { 585 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 586 new llvm::vfs::InMemoryFileSystem); 587 588 // These should be ignored. 589 InMemoryFileSystem->addFile("/opt/rh/gcc-toolset-2", 0, 590 llvm::MemoryBuffer::getMemBuffer("\n")); 591 InMemoryFileSystem->addFile("/opt/rh/gcc-toolset-", 0, 592 llvm::MemoryBuffer::getMemBuffer("\n")); 593 InMemoryFileSystem->addFile("/opt/rh/gcc-toolset--", 0, 594 llvm::MemoryBuffer::getMemBuffer("\n")); 595 InMemoryFileSystem->addFile("/opt/rh/gcc-toolset--1", 0, 596 llvm::MemoryBuffer::getMemBuffer("\n")); 597 598 // File needed for GCC installation detection. 599 InMemoryFileSystem->addFile("/opt/rh/gcc-toolset-12/root/usr/lib/gcc/" 600 "x86_64-redhat-linux/11/crtbegin.o", 601 0, llvm::MemoryBuffer::getMemBuffer("\n")); 602 603 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new SimpleDiagnosticConsumer); 604 Driver TheDriver("/bin/clang", "x86_64-redhat-linux", Diags, 605 "clang LLVM compiler", InMemoryFileSystem); 606 std::unique_ptr<Compilation> C( 607 TheDriver.BuildCompilation({"clang", "--gcc-toolchain="})); 608 ASSERT_TRUE(C); 609 std::string S; 610 { 611 llvm::raw_string_ostream OS(S); 612 C->getDefaultToolChain().printVerboseInfo(OS); 613 } 614 EXPECT_EQ("Found candidate GCC installation: " 615 "/opt/rh/gcc-toolset-12/root/usr/lib/gcc/x86_64-redhat-linux/11\n" 616 "Selected GCC installation: " 617 "/opt/rh/gcc-toolset-12/root/usr/lib/gcc/x86_64-redhat-linux/11\n" 618 "Candidate multilib: .;@m64\n" 619 "Selected multilib: .;@m64\n", 620 S); 621 } 622 623 // And older devtoolset. 624 { 625 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 626 new llvm::vfs::InMemoryFileSystem); 627 628 // These should be ignored. 629 InMemoryFileSystem->addFile("/opt/rh/devtoolset-2", 0, 630 llvm::MemoryBuffer::getMemBuffer("\n")); 631 InMemoryFileSystem->addFile("/opt/rh/devtoolset-", 0, 632 llvm::MemoryBuffer::getMemBuffer("\n")); 633 InMemoryFileSystem->addFile("/opt/rh/devtoolset--", 0, 634 llvm::MemoryBuffer::getMemBuffer("\n")); 635 InMemoryFileSystem->addFile("/opt/rh/devtoolset--1", 0, 636 llvm::MemoryBuffer::getMemBuffer("\n")); 637 638 // File needed for GCC installation detection. 639 InMemoryFileSystem->addFile("/opt/rh/devtoolset-12/root/usr/lib/gcc/" 640 "x86_64-redhat-linux/11/crtbegin.o", 641 0, llvm::MemoryBuffer::getMemBuffer("\n")); 642 643 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new SimpleDiagnosticConsumer); 644 Driver TheDriver("/bin/clang", "x86_64-redhat-linux", Diags, 645 "clang LLVM compiler", InMemoryFileSystem); 646 std::unique_ptr<Compilation> C( 647 TheDriver.BuildCompilation({"clang", "--gcc-toolchain="})); 648 ASSERT_TRUE(C); 649 std::string S; 650 { 651 llvm::raw_string_ostream OS(S); 652 C->getDefaultToolChain().printVerboseInfo(OS); 653 } 654 EXPECT_EQ("Found candidate GCC installation: " 655 "/opt/rh/devtoolset-12/root/usr/lib/gcc/x86_64-redhat-linux/11\n" 656 "Selected GCC installation: " 657 "/opt/rh/devtoolset-12/root/usr/lib/gcc/x86_64-redhat-linux/11\n" 658 "Candidate multilib: .;@m64\n" 659 "Selected multilib: .;@m64\n", 660 S); 661 } 662 } 663 664 } // end anonymous namespace. 665