1 //===- unittests/Driver/MultilibBuilderTest.cpp --- MultilibBuilder tests 2 //---------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Unit tests for MultilibBuilder and MultilibSetBuilder 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Driver/MultilibBuilder.h" 15 #include "../../lib/Driver/ToolChains/CommonArgs.h" 16 #include "SimpleDiagnosticConsumer.h" 17 #include "clang/Basic/LLVM.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/ADT/StringSwitch.h" 21 #include "gtest/gtest.h" 22 23 using llvm::is_contained; 24 using namespace clang; 25 using namespace driver; 26 27 TEST(MultilibBuilderTest, MultilibValidity) { 28 29 ASSERT_TRUE(MultilibBuilder().isValid()) << "Empty multilib is not valid"; 30 31 ASSERT_TRUE(MultilibBuilder().flag("-foo").isValid()) 32 << "Single indicative flag is not valid"; 33 34 ASSERT_TRUE(MultilibBuilder().flag("-foo", /*Disallow=*/true).isValid()) 35 << "Single contraindicative flag is not valid"; 36 37 ASSERT_FALSE( 38 MultilibBuilder().flag("-foo").flag("-foo", /*Disallow=*/true).isValid()) 39 << "Conflicting flags should invalidate the Multilib"; 40 41 ASSERT_TRUE(MultilibBuilder().flag("-foo").flag("-foo").isValid()) 42 << "Multilib should be valid even if it has the same flag " 43 "twice"; 44 45 ASSERT_TRUE(MultilibBuilder() 46 .flag("-foo") 47 .flag("-foobar", /*Disallow=*/true) 48 .isValid()) 49 << "Seemingly conflicting prefixes shouldn't actually conflict"; 50 } 51 52 TEST(MultilibBuilderTest, Construction1) { 53 MultilibBuilder M("gcc64", "os64", "inc64"); 54 ASSERT_TRUE(M.gccSuffix() == "/gcc64"); 55 ASSERT_TRUE(M.osSuffix() == "/os64"); 56 ASSERT_TRUE(M.includeSuffix() == "/inc64"); 57 } 58 59 TEST(MultilibBuilderTest, Construction3) { 60 MultilibBuilder M = 61 MultilibBuilder().flag("-f1").flag("-f2").flag("-f3", /*Disallow=*/true); 62 for (const std::string &A : M.flags()) { 63 ASSERT_TRUE(llvm::StringSwitch<bool>(A) 64 .Cases("-f1", "-f2", "!f3", true) 65 .Default(false)); 66 } 67 } 68 69 TEST(MultilibBuilderTest, SetConstruction1) { 70 // Single maybe 71 MultilibSet MS = MultilibSetBuilder() 72 .Maybe(MultilibBuilder("64").flag("-m64")) 73 .makeMultilibSet(); 74 ASSERT_TRUE(MS.size() == 2); 75 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 76 if (I->gccSuffix() == "/64") 77 ASSERT_TRUE(*I->flags().begin() == "-m64"); 78 else if (I->gccSuffix() == "") 79 ASSERT_TRUE(*I->flags().begin() == "!m64"); 80 else 81 FAIL() << "Unrecognized gccSufix: " << I->gccSuffix(); 82 } 83 } 84 85 TEST(MultilibBuilderTest, SetConstruction2) { 86 // Double maybe 87 MultilibSet MS = MultilibSetBuilder() 88 .Maybe(MultilibBuilder("sof").flag("-sof")) 89 .Maybe(MultilibBuilder("el").flag("-EL")) 90 .makeMultilibSet(); 91 ASSERT_TRUE(MS.size() == 4); 92 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 93 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) 94 .Cases("", "/sof", "/el", "/sof/el", true) 95 .Default(false)) 96 << "Multilib " << *I << " wasn't expected"; 97 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) 98 .Case("", is_contained(I->flags(), "!sof")) 99 .Case("/sof", is_contained(I->flags(), "-sof")) 100 .Case("/el", is_contained(I->flags(), "!sof")) 101 .Case("/sof/el", is_contained(I->flags(), "-sof")) 102 .Default(false)) 103 << "Multilib " << *I << " didn't have the appropriate {-,!}sof flag"; 104 ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix()) 105 .Case("", is_contained(I->flags(), "!EL")) 106 .Case("/sof", is_contained(I->flags(), "!EL")) 107 .Case("/el", is_contained(I->flags(), "-EL")) 108 .Case("/sof/el", is_contained(I->flags(), "-EL")) 109 .Default(false)) 110 << "Multilib " << *I << " didn't have the appropriate {-,!}EL flag"; 111 } 112 } 113 114 TEST(MultilibBuilderTest, SetRegexFilter) { 115 MultilibSetBuilder MB; 116 MB.Maybe(MultilibBuilder("one")) 117 .Maybe(MultilibBuilder("two")) 118 .Maybe(MultilibBuilder("three")) 119 .makeMultilibSet(); 120 MultilibSet MS = MB.makeMultilibSet(); 121 ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2) 122 << "Size before filter was incorrect. Contents:\n" 123 << MS; 124 MB.FilterOut("/one/two/three"); 125 MS = MB.makeMultilibSet(); 126 ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1) 127 << "Size after filter was incorrect. Contents:\n" 128 << MS; 129 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 130 ASSERT_TRUE(I->gccSuffix() != "/one/two/three") 131 << "The filter should have removed " << *I; 132 } 133 } 134 135 TEST(MultilibBuilderTest, SetFilterObject) { 136 MultilibSet MS = MultilibSetBuilder() 137 .Maybe(MultilibBuilder("orange")) 138 .Maybe(MultilibBuilder("pear")) 139 .Maybe(MultilibBuilder("plum")) 140 .makeMultilibSet(); 141 ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* pear */ + 1 /* plum */ + 142 1 /* pear/plum */ + 1 /* orange */ + 143 1 /* orange/pear */ + 1 /* orange/plum */ + 144 1 /* orange/pear/plum */) 145 << "Size before filter was incorrect. Contents:\n" 146 << MS; 147 MS.FilterOut([](const Multilib &M) { 148 return StringRef(M.gccSuffix()).starts_with("/p"); 149 }); 150 ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* orange */ + 151 1 /* orange/pear */ + 1 /* orange/plum */ + 152 1 /* orange/pear/plum */) 153 << "Size after filter was incorrect. Contents:\n" 154 << MS; 155 for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { 156 ASSERT_FALSE(StringRef(I->gccSuffix()).starts_with("/p")) 157 << "The filter should have removed " << *I; 158 } 159 } 160 161 TEST(MultilibBuilderTest, SetSelection1) { 162 MultilibSet MS1 = MultilibSetBuilder() 163 .Maybe(MultilibBuilder("64").flag("-m64")) 164 .makeMultilibSet(); 165 166 Multilib::flags_list FlagM64 = {"-m64"}; 167 llvm::SmallVector<Multilib> SelectionM64; 168 Driver TheDriver = diagnostic_test_driver(); 169 ASSERT_TRUE(MS1.select(TheDriver, FlagM64, SelectionM64)) 170 << "Flag set was {\"-m64\"}, but selection not found"; 171 ASSERT_TRUE(SelectionM64.back().gccSuffix() == "/64") 172 << "Selection picked " << SelectionM64.back() 173 << " which was not expected"; 174 175 Multilib::flags_list FlagNoM64 = {"!m64"}; 176 llvm::SmallVector<Multilib> SelectionNoM64; 177 ASSERT_TRUE(MS1.select(TheDriver, FlagNoM64, SelectionNoM64)) 178 << "Flag set was {\"!m64\"}, but selection not found"; 179 ASSERT_TRUE(SelectionNoM64.back().gccSuffix() == "") 180 << "Selection picked " << SelectionNoM64.back() 181 << " which was not expected"; 182 } 183 184 TEST(MultilibBuilderTest, SetSelection2) { 185 MultilibSet MS2 = MultilibSetBuilder() 186 .Maybe(MultilibBuilder("el").flag("-EL")) 187 .Maybe(MultilibBuilder("sf").flag("-SF")) 188 .makeMultilibSet(); 189 190 for (unsigned I = 0; I < 4; ++I) { 191 bool IsEL = I & 0x1; 192 bool IsSF = I & 0x2; 193 Multilib::flags_list Flags; 194 if (IsEL) 195 Flags.push_back("-EL"); 196 else 197 Flags.push_back("!EL"); 198 199 if (IsSF) 200 Flags.push_back("-SF"); 201 else 202 Flags.push_back("!SF"); 203 204 llvm::SmallVector<Multilib> Selection; 205 Driver TheDriver = diagnostic_test_driver(); 206 ASSERT_TRUE(MS2.select(TheDriver, Flags, Selection)) 207 << "Selection failed for " << (IsEL ? "-EL" : "!EL") << " " 208 << (IsSF ? "-SF" : "!SF"); 209 210 std::string Suffix; 211 if (IsEL) 212 Suffix += "/el"; 213 if (IsSF) 214 Suffix += "/sf"; 215 216 ASSERT_EQ(Selection.back().gccSuffix(), Suffix) 217 << "Selection picked " << Selection.back() 218 << " which was not expected "; 219 } 220 } 221