xref: /llvm-project/clang/lib/Driver/Multilib.cpp (revision d30bc9e91241d69410fe1a878a66438dd752014f)
1 //===- Multilib.cpp - Multilib 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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Driver/Multilib.h"
10 #include "clang/Basic/LLVM.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/ADT/StringMap.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/Support/Compiler.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/Support/Regex.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include <algorithm>
21 #include <cassert>
22 #include <string>
23 
24 using namespace clang;
25 using namespace driver;
26 using namespace llvm::sys;
27 
28 Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
29                    StringRef IncludeSuffix, const flags_list &Flags)
30     : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),
31       Flags(Flags) {
32   assert(GCCSuffix.empty() ||
33          (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));
34   assert(OSSuffix.empty() ||
35          (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1));
36   assert(IncludeSuffix.empty() ||
37          (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1));
38 }
39 
40 LLVM_DUMP_METHOD void Multilib::dump() const {
41   print(llvm::errs());
42 }
43 
44 void Multilib::print(raw_ostream &OS) const {
45   if (GCCSuffix.empty())
46     OS << ".";
47   else {
48     OS << StringRef(GCCSuffix).drop_front();
49   }
50   OS << ";";
51   for (StringRef Flag : Flags) {
52     if (Flag.front() == '+')
53       OS << "@" << Flag.substr(1);
54   }
55 }
56 
57 bool Multilib::operator==(const Multilib &Other) const {
58   // Check whether the flags sets match
59   // allowing for the match to be order invariant
60   llvm::StringSet<> MyFlags;
61   for (const auto &Flag : Flags)
62     MyFlags.insert(Flag);
63 
64   for (const auto &Flag : Other.Flags)
65     if (!MyFlags.contains(Flag))
66       return false;
67 
68   if (osSuffix() != Other.osSuffix())
69     return false;
70 
71   if (gccSuffix() != Other.gccSuffix())
72     return false;
73 
74   if (includeSuffix() != Other.includeSuffix())
75     return false;
76 
77   return true;
78 }
79 
80 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
81   M.print(OS);
82   return OS;
83 }
84 
85 MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
86   llvm::erase_if(Multilibs, F);
87   return *this;
88 }
89 
90 void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
91 
92 MultilibSet::multilib_list
93 MultilibSet::select(const Multilib::flags_list &Flags) const {
94   llvm::StringSet<> FlagSet;
95   for (const auto &Flag : Flags)
96     FlagSet.insert(Flag);
97 
98   multilib_list Result;
99   llvm::copy_if(Multilibs, std::back_inserter(Result),
100                 [&FlagSet](const Multilib &M) {
101                   for (const std::string &F : M.flags())
102                     if (!FlagSet.contains(F))
103                       return false;
104                   return true;
105                 });
106   return Result;
107 }
108 
109 bool MultilibSet::select(const Multilib::flags_list &Flags,
110                          Multilib &Selected) const {
111   multilib_list Result = select(Flags);
112   if (Result.empty())
113     return false;
114   Selected = Result.back();
115   return true;
116 }
117 
118 LLVM_DUMP_METHOD void MultilibSet::dump() const {
119   print(llvm::errs());
120 }
121 
122 void MultilibSet::print(raw_ostream &OS) const {
123   for (const auto &M : *this)
124     OS << M << "\n";
125 }
126 
127 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
128   MS.print(OS);
129   return OS;
130 }
131