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