1850dab0fSMichael Platings //===- MultilibBuilder.cpp - MultilibBuilder Implementation -===// 2850dab0fSMichael Platings // 3850dab0fSMichael Platings // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4850dab0fSMichael Platings // See https://llvm.org/LICENSE.txt for license information. 5850dab0fSMichael Platings // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6850dab0fSMichael Platings // 7850dab0fSMichael Platings //===----------------------------------------------------------------------===// 8850dab0fSMichael Platings 9850dab0fSMichael Platings #include "clang/Driver/MultilibBuilder.h" 1047b431d6SMichael Platings #include "ToolChains/CommonArgs.h" 11850dab0fSMichael Platings #include "llvm/ADT/StringMap.h" 12850dab0fSMichael Platings #include "llvm/Support/Path.h" 13850dab0fSMichael Platings #include "llvm/Support/Regex.h" 14850dab0fSMichael Platings #include "llvm/Support/raw_ostream.h" 15850dab0fSMichael Platings 16850dab0fSMichael Platings using namespace clang; 17850dab0fSMichael Platings using namespace driver; 18850dab0fSMichael Platings 19850dab0fSMichael Platings /// normalize Segment to "/foo/bar" or "". 20850dab0fSMichael Platings static void normalizePathSegment(std::string &Segment) { 21850dab0fSMichael Platings StringRef seg = Segment; 22850dab0fSMichael Platings 23850dab0fSMichael Platings // Prune trailing "/" or "./" 24850dab0fSMichael Platings while (true) { 25850dab0fSMichael Platings StringRef last = llvm::sys::path::filename(seg); 26850dab0fSMichael Platings if (last != ".") 27850dab0fSMichael Platings break; 28850dab0fSMichael Platings seg = llvm::sys::path::parent_path(seg); 29850dab0fSMichael Platings } 30850dab0fSMichael Platings 31850dab0fSMichael Platings if (seg.empty() || seg == "/") { 32850dab0fSMichael Platings Segment.clear(); 33850dab0fSMichael Platings return; 34850dab0fSMichael Platings } 35850dab0fSMichael Platings 36850dab0fSMichael Platings // Add leading '/' 37850dab0fSMichael Platings if (seg.front() != '/') { 38850dab0fSMichael Platings Segment = "/" + seg.str(); 39850dab0fSMichael Platings } else { 40850dab0fSMichael Platings Segment = std::string(seg); 41850dab0fSMichael Platings } 42850dab0fSMichael Platings } 43850dab0fSMichael Platings 44d30bc9e9SMichael Platings MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include) 45d30bc9e9SMichael Platings : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) { 46850dab0fSMichael Platings normalizePathSegment(GCCSuffix); 47850dab0fSMichael Platings normalizePathSegment(OSSuffix); 48850dab0fSMichael Platings normalizePathSegment(IncludeSuffix); 49850dab0fSMichael Platings } 50850dab0fSMichael Platings 51850dab0fSMichael Platings MultilibBuilder::MultilibBuilder(StringRef Suffix) 52850dab0fSMichael Platings : MultilibBuilder(Suffix, Suffix, Suffix) {} 53850dab0fSMichael Platings 54850dab0fSMichael Platings MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) { 55850dab0fSMichael Platings GCCSuffix = std::string(S); 56850dab0fSMichael Platings normalizePathSegment(GCCSuffix); 57850dab0fSMichael Platings return *this; 58850dab0fSMichael Platings } 59850dab0fSMichael Platings 60850dab0fSMichael Platings MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) { 61850dab0fSMichael Platings OSSuffix = std::string(S); 62850dab0fSMichael Platings normalizePathSegment(OSSuffix); 63850dab0fSMichael Platings return *this; 64850dab0fSMichael Platings } 65850dab0fSMichael Platings 66850dab0fSMichael Platings MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) { 67850dab0fSMichael Platings IncludeSuffix = std::string(S); 68850dab0fSMichael Platings normalizePathSegment(IncludeSuffix); 69850dab0fSMichael Platings return *this; 70850dab0fSMichael Platings } 71850dab0fSMichael Platings 72850dab0fSMichael Platings bool MultilibBuilder::isValid() const { 73850dab0fSMichael Platings llvm::StringMap<int> FlagSet; 74850dab0fSMichael Platings for (unsigned I = 0, N = Flags.size(); I != N; ++I) { 75850dab0fSMichael Platings StringRef Flag(Flags[I]); 76*dec641e4SKazu Hirata auto [SI, Inserted] = FlagSet.try_emplace(Flag.substr(1), I); 77850dab0fSMichael Platings 78ce8fa36eSMichael Platings assert(StringRef(Flag).front() == '-' || StringRef(Flag).front() == '!'); 79850dab0fSMichael Platings 80*dec641e4SKazu Hirata if (!Inserted && Flags[I] != Flags[SI->getValue()]) 81850dab0fSMichael Platings return false; 82850dab0fSMichael Platings } 83850dab0fSMichael Platings return true; 84850dab0fSMichael Platings } 85850dab0fSMichael Platings 86b4507dcaSMichael Platings MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) { 87b4507dcaSMichael Platings tools::addMultilibFlag(!Disallow, Flag, Flags); 8847b431d6SMichael Platings return *this; 8947b431d6SMichael Platings } 9047b431d6SMichael Platings 91850dab0fSMichael Platings Multilib MultilibBuilder::makeMultilib() const { 92d30bc9e9SMichael Platings return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags); 93850dab0fSMichael Platings } 94850dab0fSMichael Platings 95850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) { 96850dab0fSMichael Platings MultilibBuilder Opposite; 97ce8fa36eSMichael Platings // Negate positive flags 98850dab0fSMichael Platings for (StringRef Flag : M.flags()) { 99ce8fa36eSMichael Platings if (Flag.front() == '-') 100b4507dcaSMichael Platings Opposite.flag(Flag, /*Disallow=*/true); 101850dab0fSMichael Platings } 102850dab0fSMichael Platings return Either(M, Opposite); 103850dab0fSMichael Platings } 104850dab0fSMichael Platings 105850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 106850dab0fSMichael Platings const MultilibBuilder &M2) { 107850dab0fSMichael Platings return Either({M1, M2}); 108850dab0fSMichael Platings } 109850dab0fSMichael Platings 110850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 111850dab0fSMichael Platings const MultilibBuilder &M2, 112850dab0fSMichael Platings const MultilibBuilder &M3) { 113850dab0fSMichael Platings return Either({M1, M2, M3}); 114850dab0fSMichael Platings } 115850dab0fSMichael Platings 116850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 117850dab0fSMichael Platings const MultilibBuilder &M2, 118850dab0fSMichael Platings const MultilibBuilder &M3, 119850dab0fSMichael Platings const MultilibBuilder &M4) { 120850dab0fSMichael Platings return Either({M1, M2, M3, M4}); 121850dab0fSMichael Platings } 122850dab0fSMichael Platings 123850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 124850dab0fSMichael Platings const MultilibBuilder &M2, 125850dab0fSMichael Platings const MultilibBuilder &M3, 126850dab0fSMichael Platings const MultilibBuilder &M4, 127850dab0fSMichael Platings const MultilibBuilder &M5) { 128850dab0fSMichael Platings return Either({M1, M2, M3, M4, M5}); 129850dab0fSMichael Platings } 130850dab0fSMichael Platings 131850dab0fSMichael Platings static MultilibBuilder compose(const MultilibBuilder &Base, 132850dab0fSMichael Platings const MultilibBuilder &New) { 133850dab0fSMichael Platings SmallString<128> GCCSuffix; 134850dab0fSMichael Platings llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); 135850dab0fSMichael Platings SmallString<128> OSSuffix; 136850dab0fSMichael Platings llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); 137850dab0fSMichael Platings SmallString<128> IncludeSuffix; 138850dab0fSMichael Platings llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), 139850dab0fSMichael Platings New.includeSuffix()); 140850dab0fSMichael Platings 141850dab0fSMichael Platings MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix); 142850dab0fSMichael Platings 143850dab0fSMichael Platings MultilibBuilder::flags_list &Flags = Composed.flags(); 144850dab0fSMichael Platings 145850dab0fSMichael Platings Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); 146850dab0fSMichael Platings Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); 147850dab0fSMichael Platings 148850dab0fSMichael Platings return Composed; 149850dab0fSMichael Platings } 150850dab0fSMichael Platings 151850dab0fSMichael Platings MultilibSetBuilder & 152850dab0fSMichael Platings MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) { 153850dab0fSMichael Platings multilib_list Composed; 154850dab0fSMichael Platings 155850dab0fSMichael Platings if (Multilibs.empty()) 156850dab0fSMichael Platings Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), 157850dab0fSMichael Platings MultilibSegments.end()); 158850dab0fSMichael Platings else { 159850dab0fSMichael Platings for (const auto &New : MultilibSegments) { 160850dab0fSMichael Platings for (const auto &Base : Multilibs) { 161850dab0fSMichael Platings MultilibBuilder MO = compose(Base, New); 162850dab0fSMichael Platings if (MO.isValid()) 163850dab0fSMichael Platings Composed.push_back(MO); 164850dab0fSMichael Platings } 165850dab0fSMichael Platings } 166850dab0fSMichael Platings 167850dab0fSMichael Platings Multilibs = Composed; 168850dab0fSMichael Platings } 169850dab0fSMichael Platings 170850dab0fSMichael Platings return *this; 171850dab0fSMichael Platings } 172850dab0fSMichael Platings 173850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) { 174850dab0fSMichael Platings llvm::Regex R(Regex); 175850dab0fSMichael Platings #ifndef NDEBUG 176850dab0fSMichael Platings std::string Error; 177850dab0fSMichael Platings if (!R.isValid(Error)) { 178850dab0fSMichael Platings llvm::errs() << Error; 179850dab0fSMichael Platings llvm_unreachable("Invalid regex!"); 180850dab0fSMichael Platings } 181850dab0fSMichael Platings #endif 182850dab0fSMichael Platings llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) { 183850dab0fSMichael Platings return R.match(M.gccSuffix()); 184850dab0fSMichael Platings }); 185850dab0fSMichael Platings return *this; 186850dab0fSMichael Platings } 187850dab0fSMichael Platings 188850dab0fSMichael Platings MultilibSet MultilibSetBuilder::makeMultilibSet() const { 189850dab0fSMichael Platings MultilibSet Result; 190850dab0fSMichael Platings for (const auto &M : Multilibs) { 191850dab0fSMichael Platings Result.push_back(M.makeMultilib()); 192850dab0fSMichael Platings } 193850dab0fSMichael Platings return Result; 194850dab0fSMichael Platings } 195