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-exception
6//
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(path: seg);
26 if (last != ".")
27 break;
28 seg = llvm::sys::path::parent_path(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(Segment&: GCCSuffix);
47 normalizePathSegment(Segment&: OSSuffix);
48 normalizePathSegment(Segment&: 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(Segment&: GCCSuffix);
57 return *this;
58}
59
60MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) {
61 OSSuffix = std::string(S);
62 normalizePathSegment(Segment&: OSSuffix);
63 return *this;
64}
65
66MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) {
67 IncludeSuffix = std::string(S);
68 normalizePathSegment(Segment&: 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(Key: Flag.substr(Start: 1), Args&: 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(Enabled: !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 flags
98 for (StringRef Flag : M.flags()) {
99 if (Flag.front() == '-')
100 Opposite.flag(Flag, /*Disallow=*/true);
101 }
102 return Either(M1: M, M2: Opposite);
103}
104
105MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
106 const MultilibBuilder &M2) {
107 return Either(Ms: {M1, M2});
108}
109
110MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
111 const MultilibBuilder &M2,
112 const MultilibBuilder &M3) {
113 return Either(Ms: {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(Ms: {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(Ms: {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(path&: GCCSuffix, a: "/", b: Base.gccSuffix(), c: New.gccSuffix());
135 SmallString<128> OSSuffix;
136 llvm::sys::path::append(path&: OSSuffix, a: "/", b: Base.osSuffix(), c: New.osSuffix());
137 SmallString<128> IncludeSuffix;
138 llvm::sys::path::append(path&: IncludeSuffix, a: "/", b: Base.includeSuffix(),
139 c: New.includeSuffix());
140
141 MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix);
142
143 MultilibBuilder::flags_list &Flags = Composed.flags();
144
145 llvm::append_range(C&: Flags, R: Base.flags());
146 llvm::append_range(C&: Flags, R: 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(C&: Multilibs, R&: 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(x: 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 NDEBUG
175 std::string Error;
176 if (!R.isValid(Error)) {
177 llvm::errs() << Error;
178 llvm_unreachable("Invalid regex!");
179 }
180#endif
181 llvm::erase_if(C&: Multilibs, P: [&R](const MultilibBuilder &M) {
182 return R.match(String: 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: M.makeMultilib());
191 }
192 return Result;
193}
194

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/Driver/MultilibBuilder.cpp