Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/Utils.cpp
35262 views
1
//===- Utils.cpp ----------------------------------------------------------===//
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
// Implements utility functions for TextAPI Darwin operations.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/TextAPI/Utils.h"
14
#include "llvm/ADT/StringExtras.h"
15
#include "llvm/TextAPI/TextAPIError.h"
16
17
using namespace llvm;
18
using namespace llvm::MachO;
19
20
void llvm::MachO::replace_extension(SmallVectorImpl<char> &Path,
21
const Twine &Extension) {
22
StringRef P(Path.begin(), Path.size());
23
auto ParentPath = sys::path::parent_path(P);
24
auto Filename = sys::path::filename(P);
25
26
if (!ParentPath.ends_with(Filename.str() + ".framework")) {
27
sys::path::replace_extension(Path, Extension);
28
return;
29
}
30
// Framework dylibs do not have a file extension, in those cases the new
31
// extension is appended. e.g. given Path: "Foo.framework/Foo" and Extension:
32
// "tbd", the result is "Foo.framework/Foo.tbd".
33
SmallString<8> Storage;
34
StringRef Ext = Extension.toStringRef(Storage);
35
36
// Append '.' if needed.
37
if (!Ext.empty() && Ext[0] != '.')
38
Path.push_back('.');
39
40
// Append extension.
41
Path.append(Ext.begin(), Ext.end());
42
}
43
44
std::error_code llvm::MachO::shouldSkipSymLink(const Twine &Path,
45
bool &Result) {
46
Result = false;
47
SmallString<PATH_MAX> Storage;
48
auto P = Path.toNullTerminatedStringRef(Storage);
49
sys::fs::file_status Stat1;
50
auto EC = sys::fs::status(P.data(), Stat1);
51
if (EC == std::errc::too_many_symbolic_link_levels) {
52
Result = true;
53
return {};
54
}
55
56
if (EC)
57
return EC;
58
59
StringRef Parent = sys::path::parent_path(P);
60
while (!Parent.empty()) {
61
sys::fs::file_status Stat2;
62
if (auto ec = sys::fs::status(Parent, Stat2))
63
return ec;
64
65
if (sys::fs::equivalent(Stat1, Stat2)) {
66
Result = true;
67
return {};
68
}
69
70
Parent = sys::path::parent_path(Parent);
71
}
72
return {};
73
}
74
75
std::error_code
76
llvm::MachO::make_relative(StringRef From, StringRef To,
77
SmallVectorImpl<char> &RelativePath) {
78
SmallString<PATH_MAX> Src = From;
79
SmallString<PATH_MAX> Dst = To;
80
if (auto EC = sys::fs::make_absolute(Src))
81
return EC;
82
83
if (auto EC = sys::fs::make_absolute(Dst))
84
return EC;
85
86
SmallString<PATH_MAX> Result;
87
Src = sys::path::parent_path(From);
88
auto IT1 = sys::path::begin(Src), IT2 = sys::path::begin(Dst),
89
IE1 = sys::path::end(Src), IE2 = sys::path::end(Dst);
90
// Ignore the common part.
91
for (; IT1 != IE1 && IT2 != IE2; ++IT1, ++IT2) {
92
if (*IT1 != *IT2)
93
break;
94
}
95
96
for (; IT1 != IE1; ++IT1)
97
sys::path::append(Result, "../");
98
99
for (; IT2 != IE2; ++IT2)
100
sys::path::append(Result, *IT2);
101
102
if (Result.empty())
103
Result = ".";
104
105
RelativePath.swap(Result);
106
107
return {};
108
}
109
110
bool llvm::MachO::isPrivateLibrary(StringRef Path, bool IsSymLink) {
111
// Remove the iOSSupport and DriverKit prefix to identify public locations.
112
Path.consume_front(MACCATALYST_PREFIX_PATH);
113
Path.consume_front(DRIVERKIT_PREFIX_PATH);
114
// Also /Library/Apple prefix for ROSP.
115
Path.consume_front("/Library/Apple");
116
117
if (Path.starts_with("/usr/local/lib"))
118
return true;
119
120
if (Path.starts_with("/System/Library/PrivateFrameworks"))
121
return true;
122
123
// Everything in /usr/lib/swift (including sub-directories) are considered
124
// public.
125
if (Path.consume_front("/usr/lib/swift/"))
126
return false;
127
128
// Only libraries directly in /usr/lib are public. All other libraries in
129
// sub-directories are private.
130
if (Path.consume_front("/usr/lib/"))
131
return Path.contains('/');
132
133
// "/System/Library/Frameworks/" is a public location.
134
if (Path.starts_with("/System/Library/Frameworks/")) {
135
StringRef Name, Rest;
136
std::tie(Name, Rest) =
137
Path.drop_front(sizeof("/System/Library/Frameworks")).split('.');
138
139
// Allow symlinks to top-level frameworks.
140
if (IsSymLink && Rest == "framework")
141
return false;
142
143
// Only top level framework are public.
144
// /System/Library/Frameworks/Foo.framework/Foo ==> true
145
// /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true
146
// /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false
147
// /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar
148
// ==> false
149
// /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo
150
// ==> false
151
return !(Rest.starts_with("framework/") &&
152
(Rest.ends_with(Name) || Rest.ends_with((Name + ".tbd").str()) ||
153
(IsSymLink && Rest.ends_with("Current"))));
154
}
155
return false;
156
}
157
158
static StringLiteral RegexMetachars = "()^$|+.[]\\{}";
159
160
llvm::Expected<Regex> llvm::MachO::createRegexFromGlob(StringRef Glob) {
161
SmallString<128> RegexString("^");
162
unsigned NumWildcards = 0;
163
for (unsigned i = 0; i < Glob.size(); ++i) {
164
char C = Glob[i];
165
switch (C) {
166
case '?':
167
RegexString += '.';
168
break;
169
case '*': {
170
const char *PrevChar = i > 0 ? Glob.data() + i - 1 : nullptr;
171
NumWildcards = 1;
172
++i;
173
while (i < Glob.size() && Glob[i] == '*') {
174
++NumWildcards;
175
++i;
176
}
177
const char *NextChar = i < Glob.size() ? Glob.data() + i : nullptr;
178
179
if ((NumWildcards > 1) && (PrevChar == nullptr || *PrevChar == '/') &&
180
(NextChar == nullptr || *NextChar == '/')) {
181
RegexString += "(([^/]*(/|$))*)";
182
} else
183
RegexString += "([^/]*)";
184
break;
185
}
186
default:
187
if (RegexMetachars.contains(C))
188
RegexString.push_back('\\');
189
RegexString.push_back(C);
190
}
191
}
192
RegexString.push_back('$');
193
if (NumWildcards == 0)
194
return make_error<StringError>("not a glob", inconvertibleErrorCode());
195
196
llvm::Regex Rule = Regex(RegexString);
197
std::string Error;
198
if (!Rule.isValid(Error))
199
return make_error<StringError>(Error, inconvertibleErrorCode());
200
201
return std::move(Rule);
202
}
203
204
Expected<AliasMap>
205
llvm::MachO::parseAliasList(std::unique_ptr<llvm::MemoryBuffer> &Buffer) {
206
SmallVector<StringRef, 16> Lines;
207
AliasMap Aliases;
208
Buffer->getBuffer().split(Lines, "\n", /*MaxSplit=*/-1,
209
/*KeepEmpty=*/false);
210
for (const StringRef Line : Lines) {
211
StringRef L = Line.trim();
212
if (L.empty())
213
continue;
214
// Skip comments.
215
if (L.starts_with("#"))
216
continue;
217
StringRef Symbol, Remain, Alias;
218
// Base symbol is separated by whitespace.
219
std::tie(Symbol, Remain) = getToken(L);
220
// The Alias symbol ends before a comment or EOL.
221
std::tie(Alias, Remain) = getToken(Remain, "#");
222
Alias = Alias.trim();
223
if (Alias.empty())
224
return make_error<TextAPIError>(
225
TextAPIError(TextAPIErrorCode::InvalidInputFormat,
226
("missing alias for: " + Symbol).str()));
227
SimpleSymbol AliasSym = parseSymbol(Alias);
228
SimpleSymbol BaseSym = parseSymbol(Symbol);
229
Aliases[{AliasSym.Name.str(), AliasSym.Kind}] = {BaseSym.Name.str(),
230
BaseSym.Kind};
231
}
232
233
return Aliases;
234
}
235
236
PathSeq llvm::MachO::getPathsForPlatform(const PathToPlatformSeq &Paths,
237
PlatformType Platform) {
238
PathSeq Result;
239
for (const auto &[Path, CurrP] : Paths) {
240
if (!CurrP.has_value() || CurrP.value() == Platform)
241
Result.push_back(Path);
242
}
243
return Result;
244
}
245
246