Coverage Report

Created: 2024-01-17 10:31

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