1 //===- Multilib.h -----------------------------------------------*- C++ -*-===//
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 #ifndef LLVM_CLANG_DRIVER_MULTILIB_H
10 #define LLVM_CLANG_DRIVER_MULTILIB_H
11 
12 #include "clang/Basic/LLVM.h"
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/ADT/StringSet.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/SourceMgr.h"
19 #include <cassert>
20 #include <functional>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 namespace clang {
26 namespace driver {
27 
28 /// This corresponds to a single GCC Multilib, or a segment of one controlled
29 /// by a command line flag.
30 /// See also MultilibBuilder for building a multilib by mutating it
31 /// incrementally.
32 class Multilib {
33 public:
34   using flags_list = std::vector<std::string>;
35 
36 private:
37   std::string GCCSuffix;
38   std::string OSSuffix;
39   std::string IncludeSuffix;
40   flags_list Flags;
41 
42 public:
43   /// GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the
44   /// sysroot string so they must either be empty or begin with a '/' character.
45   /// This is enforced with an assert in the constructor.
46   Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {},
47            StringRef IncludeSuffix = {},
48            const flags_list &Flags = flags_list());
49 
50   /// Get the detected GCC installation path suffix for the multi-arch
51   /// target variant. Always starts with a '/', unless empty
52   const std::string &gccSuffix() const { return GCCSuffix; }
53 
54   /// Get the detected os path suffix for the multi-arch
55   /// target variant. Always starts with a '/', unless empty
56   const std::string &osSuffix() const { return OSSuffix; }
57 
58   /// Get the include directory suffix. Always starts with a '/', unless
59   /// empty
60   const std::string &includeSuffix() const { return IncludeSuffix; }
61 
62   /// Get the flags that indicate or contraindicate this multilib's use
63   /// All elements begin with either '-' or '!'
64   const flags_list &flags() const { return Flags; }
65 
66   LLVM_DUMP_METHOD void dump() const;
67   /// print summary of the Multilib
68   void print(raw_ostream &OS) const;
69 
70   /// Check whether the default is selected
71   bool isDefault() const
72   { return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); }
73 
74   bool operator==(const Multilib &Other) const;
75 };
76 
77 raw_ostream &operator<<(raw_ostream &OS, const Multilib &M);
78 
79 /// See also MultilibSetBuilder for combining multilibs into a set.
80 class MultilibSet {
81 public:
82   using multilib_list = std::vector<Multilib>;
83   using const_iterator = multilib_list::const_iterator;
84   using IncludeDirsFunc =
85       std::function<std::vector<std::string>(const Multilib &M)>;
86   using FilterCallback = llvm::function_ref<bool(const Multilib &)>;
87 
88   /// Uses regular expressions to simplify flags used for multilib selection.
89   /// For example, we may wish both -mfloat-abi=soft and -mfloat-abi=softfp to
90   /// be treated as -mfloat-abi=soft.
91   struct FlagMatcher {
92     std::string Match;
93     std::vector<std::string> Flags;
94   };
95 
96 private:
97   multilib_list Multilibs;
98   std::vector<FlagMatcher> FlagMatchers;
99   IncludeDirsFunc IncludeCallback;
100   IncludeDirsFunc FilePathsCallback;
101 
102 public:
103   MultilibSet() = default;
104   MultilibSet(multilib_list &&Multilibs,
105               std::vector<FlagMatcher> &&FlagMatchers = {})
106       : Multilibs(Multilibs), FlagMatchers(FlagMatchers) {}
107 
108   const multilib_list &getMultilibs() { return Multilibs; }
109 
110   /// Filter out some subset of the Multilibs using a user defined callback
111   MultilibSet &FilterOut(FilterCallback F);
112 
113   /// Add a completed Multilib to the set
114   void push_back(const Multilib &M);
115 
116   const_iterator begin() const { return Multilibs.begin(); }
117   const_iterator end() const { return Multilibs.end(); }
118 
119   /// Select compatible variants, \returns false if none are compatible
120   bool select(const Multilib::flags_list &Flags,
121               llvm::SmallVector<Multilib> &) const;
122 
123   unsigned size() const { return Multilibs.size(); }
124 
125   /// Get the given flags plus flags found by matching them against the
126   /// FlagMatchers and choosing the Flags of each accordingly. The select method
127   /// calls this method so in most cases it's not necessary to call it directly.
128   llvm::StringSet<> expandFlags(const Multilib::flags_list &) const;
129 
130   LLVM_DUMP_METHOD void dump() const;
131   void print(raw_ostream &OS) const;
132 
133   MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) {
134     IncludeCallback = std::move(F);
135     return *this;
136   }
137 
138   const IncludeDirsFunc &includeDirsCallback() const { return IncludeCallback; }
139 
140   MultilibSet &setFilePathsCallback(IncludeDirsFunc F) {
141     FilePathsCallback = std::move(F);
142     return *this;
143   }
144 
145   const IncludeDirsFunc &filePathsCallback() const { return FilePathsCallback; }
146 
147   static llvm::ErrorOr<MultilibSet>
148   parseYaml(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy = nullptr,
149             void *DiagHandlerCtxt = nullptr);
150 };
151 
152 raw_ostream &operator<<(raw_ostream &OS, const MultilibSet &MS);
153 
154 } // namespace driver
155 } // namespace clang
156 
157 #endif // LLVM_CLANG_DRIVER_MULTILIB_H
158