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