Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/Utils.cpp
35262 views
//===- Utils.cpp ----------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Implements utility functions for TextAPI Darwin operations.9//10//===----------------------------------------------------------------------===//1112#include "llvm/TextAPI/Utils.h"13#include "llvm/ADT/StringExtras.h"14#include "llvm/TextAPI/TextAPIError.h"1516using namespace llvm;17using namespace llvm::MachO;1819void llvm::MachO::replace_extension(SmallVectorImpl<char> &Path,20const Twine &Extension) {21StringRef P(Path.begin(), Path.size());22auto ParentPath = sys::path::parent_path(P);23auto Filename = sys::path::filename(P);2425if (!ParentPath.ends_with(Filename.str() + ".framework")) {26sys::path::replace_extension(Path, Extension);27return;28}29// Framework dylibs do not have a file extension, in those cases the new30// extension is appended. e.g. given Path: "Foo.framework/Foo" and Extension:31// "tbd", the result is "Foo.framework/Foo.tbd".32SmallString<8> Storage;33StringRef Ext = Extension.toStringRef(Storage);3435// Append '.' if needed.36if (!Ext.empty() && Ext[0] != '.')37Path.push_back('.');3839// Append extension.40Path.append(Ext.begin(), Ext.end());41}4243std::error_code llvm::MachO::shouldSkipSymLink(const Twine &Path,44bool &Result) {45Result = false;46SmallString<PATH_MAX> Storage;47auto P = Path.toNullTerminatedStringRef(Storage);48sys::fs::file_status Stat1;49auto EC = sys::fs::status(P.data(), Stat1);50if (EC == std::errc::too_many_symbolic_link_levels) {51Result = true;52return {};53}5455if (EC)56return EC;5758StringRef Parent = sys::path::parent_path(P);59while (!Parent.empty()) {60sys::fs::file_status Stat2;61if (auto ec = sys::fs::status(Parent, Stat2))62return ec;6364if (sys::fs::equivalent(Stat1, Stat2)) {65Result = true;66return {};67}6869Parent = sys::path::parent_path(Parent);70}71return {};72}7374std::error_code75llvm::MachO::make_relative(StringRef From, StringRef To,76SmallVectorImpl<char> &RelativePath) {77SmallString<PATH_MAX> Src = From;78SmallString<PATH_MAX> Dst = To;79if (auto EC = sys::fs::make_absolute(Src))80return EC;8182if (auto EC = sys::fs::make_absolute(Dst))83return EC;8485SmallString<PATH_MAX> Result;86Src = sys::path::parent_path(From);87auto IT1 = sys::path::begin(Src), IT2 = sys::path::begin(Dst),88IE1 = sys::path::end(Src), IE2 = sys::path::end(Dst);89// Ignore the common part.90for (; IT1 != IE1 && IT2 != IE2; ++IT1, ++IT2) {91if (*IT1 != *IT2)92break;93}9495for (; IT1 != IE1; ++IT1)96sys::path::append(Result, "../");9798for (; IT2 != IE2; ++IT2)99sys::path::append(Result, *IT2);100101if (Result.empty())102Result = ".";103104RelativePath.swap(Result);105106return {};107}108109bool llvm::MachO::isPrivateLibrary(StringRef Path, bool IsSymLink) {110// Remove the iOSSupport and DriverKit prefix to identify public locations.111Path.consume_front(MACCATALYST_PREFIX_PATH);112Path.consume_front(DRIVERKIT_PREFIX_PATH);113// Also /Library/Apple prefix for ROSP.114Path.consume_front("/Library/Apple");115116if (Path.starts_with("/usr/local/lib"))117return true;118119if (Path.starts_with("/System/Library/PrivateFrameworks"))120return true;121122// Everything in /usr/lib/swift (including sub-directories) are considered123// public.124if (Path.consume_front("/usr/lib/swift/"))125return false;126127// Only libraries directly in /usr/lib are public. All other libraries in128// sub-directories are private.129if (Path.consume_front("/usr/lib/"))130return Path.contains('/');131132// "/System/Library/Frameworks/" is a public location.133if (Path.starts_with("/System/Library/Frameworks/")) {134StringRef Name, Rest;135std::tie(Name, Rest) =136Path.drop_front(sizeof("/System/Library/Frameworks")).split('.');137138// Allow symlinks to top-level frameworks.139if (IsSymLink && Rest == "framework")140return false;141142// Only top level framework are public.143// /System/Library/Frameworks/Foo.framework/Foo ==> true144// /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true145// /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false146// /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar147// ==> false148// /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo149// ==> false150return !(Rest.starts_with("framework/") &&151(Rest.ends_with(Name) || Rest.ends_with((Name + ".tbd").str()) ||152(IsSymLink && Rest.ends_with("Current"))));153}154return false;155}156157static StringLiteral RegexMetachars = "()^$|+.[]\\{}";158159llvm::Expected<Regex> llvm::MachO::createRegexFromGlob(StringRef Glob) {160SmallString<128> RegexString("^");161unsigned NumWildcards = 0;162for (unsigned i = 0; i < Glob.size(); ++i) {163char C = Glob[i];164switch (C) {165case '?':166RegexString += '.';167break;168case '*': {169const char *PrevChar = i > 0 ? Glob.data() + i - 1 : nullptr;170NumWildcards = 1;171++i;172while (i < Glob.size() && Glob[i] == '*') {173++NumWildcards;174++i;175}176const char *NextChar = i < Glob.size() ? Glob.data() + i : nullptr;177178if ((NumWildcards > 1) && (PrevChar == nullptr || *PrevChar == '/') &&179(NextChar == nullptr || *NextChar == '/')) {180RegexString += "(([^/]*(/|$))*)";181} else182RegexString += "([^/]*)";183break;184}185default:186if (RegexMetachars.contains(C))187RegexString.push_back('\\');188RegexString.push_back(C);189}190}191RegexString.push_back('$');192if (NumWildcards == 0)193return make_error<StringError>("not a glob", inconvertibleErrorCode());194195llvm::Regex Rule = Regex(RegexString);196std::string Error;197if (!Rule.isValid(Error))198return make_error<StringError>(Error, inconvertibleErrorCode());199200return std::move(Rule);201}202203Expected<AliasMap>204llvm::MachO::parseAliasList(std::unique_ptr<llvm::MemoryBuffer> &Buffer) {205SmallVector<StringRef, 16> Lines;206AliasMap Aliases;207Buffer->getBuffer().split(Lines, "\n", /*MaxSplit=*/-1,208/*KeepEmpty=*/false);209for (const StringRef Line : Lines) {210StringRef L = Line.trim();211if (L.empty())212continue;213// Skip comments.214if (L.starts_with("#"))215continue;216StringRef Symbol, Remain, Alias;217// Base symbol is separated by whitespace.218std::tie(Symbol, Remain) = getToken(L);219// The Alias symbol ends before a comment or EOL.220std::tie(Alias, Remain) = getToken(Remain, "#");221Alias = Alias.trim();222if (Alias.empty())223return make_error<TextAPIError>(224TextAPIError(TextAPIErrorCode::InvalidInputFormat,225("missing alias for: " + Symbol).str()));226SimpleSymbol AliasSym = parseSymbol(Alias);227SimpleSymbol BaseSym = parseSymbol(Symbol);228Aliases[{AliasSym.Name.str(), AliasSym.Kind}] = {BaseSym.Name.str(),229BaseSym.Kind};230}231232return Aliases;233}234235PathSeq llvm::MachO::getPathsForPlatform(const PathToPlatformSeq &Paths,236PlatformType Platform) {237PathSeq Result;238for (const auto &[Path, CurrP] : Paths) {239if (!CurrP.has_value() || CurrP.value() == Platform)240Result.push_back(Path);241}242return Result;243}244245246