194 lines · cpp
1//===- MultilibBuilder.cpp - MultilibBuilder Implementation -===//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#include "clang/Driver/MultilibBuilder.h"10#include "clang/Driver/CommonArgs.h"11#include "llvm/ADT/StringMap.h"12#include "llvm/Support/Path.h"13#include "llvm/Support/Regex.h"14#include "llvm/Support/raw_ostream.h"15 16using namespace clang;17using namespace driver;18 19/// normalize Segment to "/foo/bar" or "".20static void normalizePathSegment(std::string &Segment) {21 StringRef seg = Segment;22 23 // Prune trailing "/" or "./"24 while (true) {25 StringRef last = llvm::sys::path::filename(seg);26 if (last != ".")27 break;28 seg = llvm::sys::path::parent_path(seg);29 }30 31 if (seg.empty() || seg == "/") {32 Segment.clear();33 return;34 }35 36 // Add leading '/'37 if (seg.front() != '/') {38 Segment = "/" + seg.str();39 } else {40 Segment = std::string(seg);41 }42}43 44MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include)45 : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) {46 normalizePathSegment(GCCSuffix);47 normalizePathSegment(OSSuffix);48 normalizePathSegment(IncludeSuffix);49}50 51MultilibBuilder::MultilibBuilder(StringRef Suffix)52 : MultilibBuilder(Suffix, Suffix, Suffix) {}53 54MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) {55 GCCSuffix = std::string(S);56 normalizePathSegment(GCCSuffix);57 return *this;58}59 60MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) {61 OSSuffix = std::string(S);62 normalizePathSegment(OSSuffix);63 return *this;64}65 66MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) {67 IncludeSuffix = std::string(S);68 normalizePathSegment(IncludeSuffix);69 return *this;70}71 72bool MultilibBuilder::isValid() const {73 llvm::StringMap<int> FlagSet;74 for (unsigned I = 0, N = Flags.size(); I != N; ++I) {75 StringRef Flag(Flags[I]);76 auto [SI, Inserted] = FlagSet.try_emplace(Flag.substr(1), I);77 78 assert(StringRef(Flag).front() == '-' || StringRef(Flag).front() == '!');79 80 if (!Inserted && Flags[I] != Flags[SI->getValue()])81 return false;82 }83 return true;84}85 86MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) {87 tools::addMultilibFlag(!Disallow, Flag, Flags);88 return *this;89}90 91Multilib MultilibBuilder::makeMultilib() const {92 return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags);93}94 95MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) {96 MultilibBuilder Opposite;97 // Negate positive flags98 for (StringRef Flag : M.flags()) {99 if (Flag.front() == '-')100 Opposite.flag(Flag, /*Disallow=*/true);101 }102 return Either(M, Opposite);103}104 105MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,106 const MultilibBuilder &M2) {107 return Either({M1, M2});108}109 110MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,111 const MultilibBuilder &M2,112 const MultilibBuilder &M3) {113 return Either({M1, M2, M3});114}115 116MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,117 const MultilibBuilder &M2,118 const MultilibBuilder &M3,119 const MultilibBuilder &M4) {120 return Either({M1, M2, M3, M4});121}122 123MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,124 const MultilibBuilder &M2,125 const MultilibBuilder &M3,126 const MultilibBuilder &M4,127 const MultilibBuilder &M5) {128 return Either({M1, M2, M3, M4, M5});129}130 131static MultilibBuilder compose(const MultilibBuilder &Base,132 const MultilibBuilder &New) {133 SmallString<128> GCCSuffix;134 llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());135 SmallString<128> OSSuffix;136 llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());137 SmallString<128> IncludeSuffix;138 llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),139 New.includeSuffix());140 141 MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix);142 143 MultilibBuilder::flags_list &Flags = Composed.flags();144 145 llvm::append_range(Flags, Base.flags());146 llvm::append_range(Flags, New.flags());147 148 return Composed;149}150 151MultilibSetBuilder &152MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) {153 multilib_list Composed;154 155 if (Multilibs.empty())156 llvm::append_range(Multilibs, MultilibSegments);157 else {158 for (const auto &New : MultilibSegments) {159 for (const auto &Base : Multilibs) {160 MultilibBuilder MO = compose(Base, New);161 if (MO.isValid())162 Composed.push_back(MO);163 }164 }165 166 Multilibs = Composed;167 }168 169 return *this;170}171 172MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) {173 llvm::Regex R(Regex);174#ifndef NDEBUG175 std::string Error;176 if (!R.isValid(Error)) {177 llvm::errs() << Error;178 llvm_unreachable("Invalid regex!");179 }180#endif181 llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) {182 return R.match(M.gccSuffix());183 });184 return *this;185}186 187MultilibSet MultilibSetBuilder::makeMultilibSet() const {188 MultilibSet Result;189 for (const auto &M : Multilibs) {190 Result.push_back(M.makeMultilib());191 }192 return Result;193}194