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