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/Support/TargetRegistry.h" 20 #include "llvm/Support/TargetSelect.h" 21 #include "llvm/Support/VirtualFileSystem.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include "gtest/gtest.h" 24 using namespace clang; 25 using namespace clang::driver; 26 27 namespace { 28 29 TEST(ToolChainTest, VFSGCCInstallation) { 30 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 31 32 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 33 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 34 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 35 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 36 new llvm::vfs::InMemoryFileSystem); 37 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags, 38 "clang LLVM compiler", 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 for (const char *Path : EmptyFiles) 59 InMemoryFileSystem->addFile(Path, 0, 60 llvm::MemoryBuffer::getMemBuffer("\n")); 61 62 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 63 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"})); 64 EXPECT_TRUE(C); 65 66 std::string S; 67 { 68 llvm::raw_string_ostream OS(S); 69 C->getDefaultToolChain().printVerboseInfo(OS); 70 } 71 #if _WIN32 72 std::replace(S.begin(), S.end(), '\\', '/'); 73 #endif 74 EXPECT_EQ( 75 "Found candidate GCC installation: " 76 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" 77 "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" 78 "Candidate multilib: .;@m32\n" 79 "Selected multilib: .;@m32\n", 80 S); 81 } 82 83 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) { 84 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 85 86 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 87 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 88 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 89 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 90 new llvm::vfs::InMemoryFileSystem); 91 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 92 "clang LLVM compiler", InMemoryFileSystem); 93 94 const char *EmptyFiles[] = { 95 "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o", 96 "/home/test/include/arm-linux-gnueabi/.keep"}; 97 98 for (const char *Path : EmptyFiles) 99 InMemoryFileSystem->addFile(Path, 0, 100 llvm::MemoryBuffer::getMemBuffer("\n")); 101 102 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 103 {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"})); 104 EXPECT_TRUE(C); 105 106 std::string S; 107 { 108 llvm::raw_string_ostream OS(S); 109 C->getDefaultToolChain().printVerboseInfo(OS); 110 } 111 #if _WIN32 112 std::replace(S.begin(), S.end(), '\\', '/'); 113 #endif 114 EXPECT_EQ("Found candidate GCC installation: " 115 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n" 116 "Selected GCC installation: " 117 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n" 118 "Candidate multilib: .;@m32\n" 119 "Selected multilib: .;@m32\n", 120 S); 121 } 122 123 TEST(ToolChainTest, DefaultDriverMode) { 124 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 125 126 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 127 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 128 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 129 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 130 new llvm::vfs::InMemoryFileSystem); 131 132 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 133 "clang LLVM compiler", InMemoryFileSystem); 134 CCDriver.setCheckInputsExist(false); 135 Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags, 136 "clang LLVM compiler", InMemoryFileSystem); 137 CXXDriver.setCheckInputsExist(false); 138 Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags, 139 "clang LLVM compiler", InMemoryFileSystem); 140 CLDriver.setCheckInputsExist(false); 141 142 std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation( 143 { "/home/test/bin/clang", "foo.cpp"})); 144 std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation( 145 { "/home/test/bin/clang++", "foo.cpp"})); 146 std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation( 147 { "/home/test/bin/clang-cl", "foo.cpp"})); 148 149 EXPECT_TRUE(CC); 150 EXPECT_TRUE(CXX); 151 EXPECT_TRUE(CL); 152 EXPECT_TRUE(CCDriver.CCCIsCC()); 153 EXPECT_TRUE(CXXDriver.CCCIsCXX()); 154 EXPECT_TRUE(CLDriver.IsCLMode()); 155 } 156 TEST(ToolChainTest, InvalidArgument) { 157 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 158 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 159 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 160 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 161 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags); 162 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( 163 {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"})); 164 EXPECT_TRUE(C); 165 EXPECT_TRUE(C->containsError()); 166 } 167 168 TEST(ToolChainTest, ParsedClangName) { 169 ParsedClangName Empty; 170 EXPECT_TRUE(Empty.TargetPrefix.empty()); 171 EXPECT_TRUE(Empty.ModeSuffix.empty()); 172 EXPECT_TRUE(Empty.DriverMode == nullptr); 173 EXPECT_FALSE(Empty.TargetIsValid); 174 175 ParsedClangName DriverOnly("clang", nullptr); 176 EXPECT_TRUE(DriverOnly.TargetPrefix.empty()); 177 EXPECT_TRUE(DriverOnly.ModeSuffix == "clang"); 178 EXPECT_TRUE(DriverOnly.DriverMode == nullptr); 179 EXPECT_FALSE(DriverOnly.TargetIsValid); 180 181 ParsedClangName DriverOnly2("clang++", "--driver-mode=g++"); 182 EXPECT_TRUE(DriverOnly2.TargetPrefix.empty()); 183 EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++"); 184 EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++"); 185 EXPECT_FALSE(DriverOnly2.TargetIsValid); 186 187 ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true); 188 EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386"); 189 EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++"); 190 EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++"); 191 EXPECT_TRUE(TargetAndMode.TargetIsValid); 192 } 193 194 TEST(ToolChainTest, GetTargetAndMode) { 195 llvm::InitializeAllTargets(); 196 std::string IgnoredError; 197 if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError)) 198 return; 199 200 ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang"); 201 EXPECT_TRUE(Res.TargetPrefix.empty()); 202 EXPECT_TRUE(Res.ModeSuffix == "clang"); 203 EXPECT_TRUE(Res.DriverMode == nullptr); 204 EXPECT_FALSE(Res.TargetIsValid); 205 206 Res = ToolChain::getTargetAndModeFromProgramName("clang++"); 207 EXPECT_TRUE(Res.TargetPrefix.empty()); 208 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 209 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 210 EXPECT_FALSE(Res.TargetIsValid); 211 212 Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0"); 213 EXPECT_TRUE(Res.TargetPrefix.empty()); 214 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 215 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 216 EXPECT_FALSE(Res.TargetIsValid); 217 218 Res = ToolChain::getTargetAndModeFromProgramName("clang++-release"); 219 EXPECT_TRUE(Res.TargetPrefix.empty()); 220 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 221 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 222 EXPECT_FALSE(Res.TargetIsValid); 223 224 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++"); 225 EXPECT_TRUE(Res.TargetPrefix == "x86_64"); 226 EXPECT_TRUE(Res.ModeSuffix == "clang++"); 227 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 228 EXPECT_TRUE(Res.TargetIsValid); 229 230 Res = ToolChain::getTargetAndModeFromProgramName( 231 "x86_64-linux-gnu-clang-c++"); 232 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu"); 233 EXPECT_TRUE(Res.ModeSuffix == "clang-c++"); 234 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 235 EXPECT_TRUE(Res.TargetIsValid); 236 237 Res = ToolChain::getTargetAndModeFromProgramName( 238 "x86_64-linux-gnu-clang-c++-tot"); 239 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu"); 240 EXPECT_TRUE(Res.ModeSuffix == "clang-c++"); 241 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++"); 242 EXPECT_TRUE(Res.TargetIsValid); 243 244 Res = ToolChain::getTargetAndModeFromProgramName("qqq"); 245 EXPECT_TRUE(Res.TargetPrefix.empty()); 246 EXPECT_TRUE(Res.ModeSuffix.empty()); 247 EXPECT_TRUE(Res.DriverMode == nullptr); 248 EXPECT_FALSE(Res.TargetIsValid); 249 250 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq"); 251 EXPECT_TRUE(Res.TargetPrefix.empty()); 252 EXPECT_TRUE(Res.ModeSuffix.empty()); 253 EXPECT_TRUE(Res.DriverMode == nullptr); 254 EXPECT_FALSE(Res.TargetIsValid); 255 256 Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl"); 257 EXPECT_TRUE(Res.TargetPrefix == "qqq"); 258 EXPECT_TRUE(Res.ModeSuffix == "clang-cl"); 259 EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl"); 260 EXPECT_FALSE(Res.TargetIsValid); 261 } 262 263 TEST(ToolChainTest, CommandOutput) { 264 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 265 266 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 267 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 268 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 269 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 270 new llvm::vfs::InMemoryFileSystem); 271 272 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 273 "clang LLVM compiler", InMemoryFileSystem); 274 CCDriver.setCheckInputsExist(false); 275 std::unique_ptr<Compilation> CC( 276 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"})); 277 const JobList &Jobs = CC->getJobs(); 278 279 const auto &CmdCompile = Jobs.getJobs().front(); 280 const auto &InFile = CmdCompile->getInputFilenames().front(); 281 EXPECT_STREQ(InFile, "foo.cpp"); 282 auto ObjFile = CmdCompile->getOutputFilenames().front(); 283 EXPECT_TRUE(StringRef(ObjFile).endswith(".o")); 284 285 const auto &CmdLink = Jobs.getJobs().back(); 286 const auto LinkInFile = CmdLink->getInputFilenames().front(); 287 EXPECT_EQ(ObjFile, LinkInFile); 288 auto ExeFile = CmdLink->getOutputFilenames().front(); 289 EXPECT_EQ("a.out", ExeFile); 290 } 291 292 TEST(ToolChainTest, PostCallback) { 293 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 294 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 295 struct TestDiagnosticConsumer : public DiagnosticConsumer {}; 296 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); 297 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( 298 new llvm::vfs::InMemoryFileSystem); 299 300 // The executable path must not exist. 301 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, 302 "clang LLVM compiler", InMemoryFileSystem); 303 CCDriver.setCheckInputsExist(false); 304 std::unique_ptr<Compilation> CC( 305 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"})); 306 bool CallbackHasCalled = false; 307 CC->setPostCallback( 308 [&](const Command &C, int Ret) { CallbackHasCalled = true; }); 309 const JobList &Jobs = CC->getJobs(); 310 auto &CmdCompile = Jobs.getJobs().front(); 311 const Command *FailingCmd = nullptr; 312 CC->ExecuteCommand(*CmdCompile, FailingCmd); 313 EXPECT_TRUE(CallbackHasCalled); 314 } 315 316 } // end anonymous namespace. 317