[clang] [InstallAPI] Capture & compare load commands that may differ per arch slice (PR #87674)
Cyndy Ishida via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 4 19:12:41 PDT 2024
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/87674
>From 7ef1a803c10cfef8f577a4e439221d778215464a Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Wed, 27 Mar 2024 12:17:01 -0400
Subject: [PATCH] [InstallAPI] Capture and compare load commands that may
differ per arch slice
* Capture reexported libraries, allowable clients, rpaths, shared cache
eligiblity.
* Add support for select Xarch options.
* Add diagnostics related to capturing these options.
* Add support for verifying these attributes against what is encoded in
the dylib.
---
.../clang/Basic/DiagnosticDriverKinds.td | 1 +
.../clang/Basic/DiagnosticInstallAPIKinds.td | 21 +
clang/include/clang/InstallAPI/Context.h | 17 +
.../include/clang/InstallAPI/DylibVerifier.h | 29 +-
clang/include/clang/InstallAPI/MachO.h | 2 +
clang/lib/InstallAPI/CMakeLists.txt | 1 +
.../InstallAPI/DiagnosticBuilderWrappers.cpp | 111 +++
.../InstallAPI/DiagnosticBuilderWrappers.h | 49 ++
clang/lib/InstallAPI/DylibVerifier.cpp | 196 ++++++
clang/lib/InstallAPI/Frontend.cpp | 54 ++
clang/test/InstallAPI/binary-attributes.test | 70 ++
.../InstallAPI/driver-invalid-options.test | 6 +
.../InstallAPI/reexported-frameworks.test | 638 +++++++++++++++++
clang/test/InstallAPI/rpath.test | 663 ++++++++++++++++++
clang/tools/clang-installapi/CMakeLists.txt | 1 +
.../clang-installapi/ClangInstallAPI.cpp | 27 +-
.../tools/clang-installapi/InstallAPIOpts.td | 40 +-
clang/tools/clang-installapi/Options.cpp | 277 +++++++-
clang/tools/clang-installapi/Options.h | 43 +-
19 files changed, 2230 insertions(+), 16 deletions(-)
create mode 100644 clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
create mode 100644 clang/lib/InstallAPI/DiagnosticBuilderWrappers.h
create mode 100644 clang/test/InstallAPI/binary-attributes.test
create mode 100644 clang/test/InstallAPI/reexported-frameworks.test
create mode 100644 clang/test/InstallAPI/rpath.test
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 3d86f7510bde20..fdce4f3f9d9a60 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -663,6 +663,7 @@ def warn_drv_darwin_sdk_invalid_settings : Warning<
"SDK settings were ignored as 'SDKSettings.json' could not be parsed">,
InGroup<DiagGroup<"darwin-sdk-settings">>;
+def err_missing_sysroot : Error<"no such sysroot directory: '%0'">;
def err_drv_darwin_sdk_missing_arclite : Error<
"SDK does not contain 'libarclite' at the path '%0'; try increasing the minimum deployment target">;
diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
index e3263fe9ccb9d4..0a477da7186b09 100644
--- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
+++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
@@ -19,9 +19,11 @@ def err_no_such_header_file : Error<"no such %select{public|private|project}1 he
def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup<InstallAPIViolation>;
def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup<InstallAPIViolation>;
def err_no_such_umbrella_header_file : Error<"%select{public|private|project}1 umbrella header file not found in input: '%0'">;
+def err_cannot_find_reexport : Error<"cannot find re-exported %select{framework|library}0: '%1'">;
} // end of command line category.
let CategoryName = "Verification" in {
+// Diagnostics about symbols.
def warn_target: Warning<"violations found for %0">, InGroup<InstallAPIViolation>;
def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">, InGroup<InstallAPIViolation>;
@@ -43,6 +45,25 @@ def err_dylib_symbol_flags_mismatch : Error<"dynamic library symbol '%0' is "
"%select{weak defined|thread local}1, but its declaration is not">;
def err_header_symbol_flags_mismatch : Error<"declaration '%0' is "
"%select{weak defined|thread local}1, but symbol is not in dynamic library">;
+
+// Diagnostics about load commands.
+def err_architecture_mismatch : Error<"architectures do not match: '%0' (provided) vs '%1' (found)">;
+def warn_platform_mismatch : Warning<"platform does not match: '%0' (provided) vs '%1' (found)">, InGroup<InstallAPIViolation>;
+def err_platform_mismatch : Error<"platform does not match: '%0' (provided) vs '%1' (found)">;
+def err_install_name_mismatch : Error<"install_name does not match: '%0' (provided) vs '%1' (found)">;
+def err_current_version_mismatch : Error<"current_version does not match: '%0' (provided) vs '%1' (found)">;
+def err_compatibility_version_mismatch : Error<"compatibility_version does not match: '%0' (provided) vs '%1' (found)">;
+def err_appextension_safe_mismatch : Error<"ApplicationExtensionSafe flag does not match: '%0' (provided) vs '%1' (found)">;
+def err_shared_cache_eligiblity_mismatch : Error<"NotForDyldSharedCache flag does not match: '%0' (provided) vs '%1' (found)">;
+def err_no_twolevel_namespace : Error<"flat namespace libraries are not supported">;
+def err_parent_umbrella_missing: Error<"parent umbrella missing from %0: '%1'">;
+def err_parent_umbrella_mismatch : Error<"parent umbrella does not match: '%0' (provided) vs '%1' (found)">;
+def err_reexported_libraries_missing : Error<"re-exported library missing from %0: '%1'">;
+def err_reexported_libraries_mismatch : Error<"re-exported libraries do not match: '%0' (provided) vs '%1' (found)">;
+def err_allowable_clients_missing : Error<"allowable client missing from %0: '%1'">;
+def err_allowable_clients_mismatch : Error<"allowable clients do not match: '%0' (provided) vs '%1' (found)">;
+def warn_rpaths_missing : Warning<"runpath search paths missing from %0: '%1'">, InGroup<InstallAPIViolation>;
+def warn_rpaths_mismatch : Warning<"runpath search paths do not match: '%0' (provided) vs '%1' (found)">, InGroup<InstallAPIViolation>;
} // end of Verification category.
} // end of InstallAPI component
diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h
index 54e517544b8edf..8f88331a2803fc 100644
--- a/clang/include/clang/InstallAPI/Context.h
+++ b/clang/include/clang/InstallAPI/Context.h
@@ -28,6 +28,9 @@ struct InstallAPIContext {
/// Library attributes that are typically passed as linker inputs.
BinaryAttrs BA;
+ /// Install names of reexported libraries of a library.
+ LibAttrs Reexports;
+
/// All headers that represent a library.
HeaderSeq InputHeaders;
@@ -80,6 +83,20 @@ struct InstallAPIContext {
llvm::DenseMap<StringRef, HeaderType> KnownIncludes;
};
+/// Lookup the dylib or TextAPI file location for a system library or framework.
+/// The search paths provided are searched in order.
+/// @rpath based libraries are not supported.
+///
+/// \param InstallName The install name for the library.
+/// \param FrameworkSearchPaths Search paths to look up frameworks with.
+/// \param LibrarySearchPaths Search paths to look up dylibs with.
+/// \param SearchPaths Fallback search paths if library was not found in earlier
+/// paths.
+/// \return The full path of the library.
+std::string findLibrary(StringRef InstallName, FileManager &FM,
+ ArrayRef<std::string> FrameworkSearchPaths,
+ ArrayRef<std::string> LibrarySearchPaths,
+ ArrayRef<std::string> SearchPaths);
} // namespace installapi
} // namespace clang
diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h
index 22cdc234486cf3..07dbd3bf5f2b10 100644
--- a/clang/include/clang/InstallAPI/DylibVerifier.h
+++ b/clang/include/clang/InstallAPI/DylibVerifier.h
@@ -24,6 +24,9 @@ enum class VerificationMode {
Pedantic,
};
+using LibAttrs = llvm::StringMap<ArchitectureSet>;
+using ReexportedInterfaces = llvm::SmallVector<llvm::MachO::InterfaceFile, 8>;
+
/// Service responsible to tracking state of verification across the
/// lifetime of InstallAPI.
/// As declarations are collected during AST traversal, they are
@@ -63,11 +66,12 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
DylibVerifier() = default;
- DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag,
- VerificationMode Mode, bool Demangle, StringRef DSYMPath)
- : Dylib(std::move(Dylib)), Mode(Mode), Demangle(Demangle),
- DSYMPath(DSYMPath), Exports(std::make_unique<SymbolSet>()),
- Ctx(VerifierContext{Diag}) {}
+ DylibVerifier(llvm::MachO::Records &&Dylib, ReexportedInterfaces &&Reexports,
+ DiagnosticsEngine *Diag, VerificationMode Mode, bool Demangle,
+ StringRef DSYMPath)
+ : Dylib(std::move(Dylib)), Reexports(std::move(Reexports)), Mode(Mode),
+ Demangle(Demangle), DSYMPath(DSYMPath),
+ Exports(std::make_unique<SymbolSet>()), Ctx(VerifierContext{Diag}) {}
Result verify(GlobalRecord *R, const FrontendAttrs *FA);
Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA);
@@ -77,6 +81,14 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
// Scan through dylib slices and report any remaining missing exports.
Result verifyRemainingSymbols();
+ /// Compare and report the attributes represented as
+ /// load commands in the dylib to the attributes provided via options.
+ bool verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,
+ const BinaryAttrs &ProvidedBA,
+ const LibAttrs &ProvidedReexports,
+ const LibAttrs &ProvidedClients,
+ const LibAttrs &ProvidedRPaths, const FileType &FT);
+
/// Initialize target for verification.
void setTarget(const Target &T);
@@ -105,6 +117,10 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
bool shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
const Record *DR);
+ /// Check if declaration is exported from a reexported library. These
+ /// symbols should be omitted from the text-api file.
+ bool shouldIgnoreReexport(const Record *R, SymbolContext &SymCtx) const;
+
/// Compare the visibility declarations to the linkage of symbol found in
/// dylib.
Result compareVisibility(const Record *R, SymbolContext &SymCtx,
@@ -154,6 +170,9 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
// Symbols in dylib.
llvm::MachO::Records Dylib;
+ // Reexported interfaces apart of the library.
+ ReexportedInterfaces Reexports;
+
// Controls what class of violations to report.
VerificationMode Mode = VerificationMode::Invalid;
diff --git a/clang/include/clang/InstallAPI/MachO.h b/clang/include/clang/InstallAPI/MachO.h
index 827220dbf39fb8..854399f54ba6c8 100644
--- a/clang/include/clang/InstallAPI/MachO.h
+++ b/clang/include/clang/InstallAPI/MachO.h
@@ -23,6 +23,8 @@
#include "llvm/TextAPI/TextAPIWriter.h"
#include "llvm/TextAPI/Utils.h"
+using Architecture = llvm::MachO::Architecture;
+using ArchitectureSet = llvm::MachO::ArchitectureSet;
using SymbolFlags = llvm::MachO::SymbolFlags;
using RecordLinkage = llvm::MachO::RecordLinkage;
using Record = llvm::MachO::Record;
diff --git a/clang/lib/InstallAPI/CMakeLists.txt b/clang/lib/InstallAPI/CMakeLists.txt
index e0bc8d969ecb3a..b36493942300b6 100644
--- a/clang/lib/InstallAPI/CMakeLists.txt
+++ b/clang/lib/InstallAPI/CMakeLists.txt
@@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangInstallAPI
+ DiagnosticBuilderWrappers.cpp
DylibVerifier.cpp
FileList.cpp
Frontend.cpp
diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
new file mode 100644
index 00000000000000..9ab221040a56bf
--- /dev/null
+++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
@@ -0,0 +1,111 @@
+//===- DiagnosticBuilderWrappers.cpp ----------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagnosticBuilderWrappers.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TextAPI/Platform.h"
+
+using clang::DiagnosticBuilder;
+
+namespace llvm {
+namespace MachO {
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const Architecture &Arch) {
+ DB.AddString(getArchitectureName(Arch));
+ return DB;
+}
+
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const ArchitectureSet &ArchSet) {
+ DB.AddString(std::string(ArchSet));
+ return DB;
+}
+
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const PlatformType &Platform) {
+ DB.AddString(getPlatformName(Platform));
+ return DB;
+}
+
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const PlatformVersionSet &Platforms) {
+ std::string PlatformAsString;
+ raw_string_ostream Stream(PlatformAsString);
+
+ Stream << "[ ";
+ bool NeedsComma = false;
+ for (auto &[Platform, Version] : Platforms) {
+ if (NeedsComma)
+ Stream << ", ";
+ else
+ NeedsComma = true;
+ Stream << getPlatformName(Platform);
+ if (!Version.empty())
+ Stream << Version.getAsString();
+ }
+ Stream << " ]";
+ DB.AddString(Stream.str());
+ return DB;
+}
+
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const FileType &Type) {
+ switch (Type) {
+ case FileType::MachO_Bundle:
+ DB.AddString("mach-o bundle");
+ return DB;
+ case FileType::MachO_DynamicLibrary:
+ DB.AddString("mach-o dynamic library");
+ return DB;
+ case FileType::MachO_DynamicLibrary_Stub:
+ DB.AddString("mach-o dynamic library stub");
+ return DB;
+ case FileType::TBD_V1:
+ DB.AddString("tbd-v1");
+ return DB;
+ case FileType::TBD_V2:
+ DB.AddString("tbd-v2");
+ return DB;
+ case FileType::TBD_V3:
+ DB.AddString("tbd-v3");
+ return DB;
+ case FileType::TBD_V4:
+ DB.AddString("tbd-v4");
+ return DB;
+ case FileType::TBD_V5:
+ DB.AddString("tbd-v5");
+ return DB;
+ case FileType::Invalid:
+ case FileType::All:
+ llvm_unreachable("Unexpected file type for diagnostics.");
+ }
+}
+
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const PackedVersion &Version) {
+ std::string VersionString;
+ raw_string_ostream OS(VersionString);
+ OS << Version;
+ DB.AddString(OS.str());
+ return DB;
+}
+
+const clang::DiagnosticBuilder &
+operator<<(const clang::DiagnosticBuilder &DB,
+ const StringMapEntry<ArchitectureSet> &LibAttr) {
+ std::string IFAsString;
+ raw_string_ostream OS(IFAsString);
+
+ OS << LibAttr.getKey() << " [ " << LibAttr.getValue() << " ]";
+ DB.AddString(OS.str());
+ return DB;
+}
+
+} // namespace MachO
+} // namespace llvm
diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h
new file mode 100644
index 00000000000000..48cfefbf65e6bc
--- /dev/null
+++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h
@@ -0,0 +1,49 @@
+//===- DiagnosticBuilderWrappers.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// Diagnostic wrappers for TextAPI types for error reporting.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H
+#define LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/TextAPI/Architecture.h"
+#include "llvm/TextAPI/ArchitectureSet.h"
+#include "llvm/TextAPI/InterfaceFile.h"
+#include "llvm/TextAPI/Platform.h"
+
+namespace llvm {
+namespace MachO {
+
+const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
+ const PlatformType &Platform);
+
+const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
+ const PlatformVersionSet &Platforms);
+
+const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
+ const Architecture &Arch);
+
+const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
+ const ArchitectureSet &ArchSet);
+
+const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
+ const FileType &Type);
+
+const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
+ const PackedVersion &Version);
+
+const clang::DiagnosticBuilder &
+operator<<(const clang::DiagnosticBuilder &DB,
+ const StringMapEntry<ArchitectureSet> &LibAttr);
+
+} // namespace MachO
+} // namespace llvm
+#endif // LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H
diff --git a/clang/lib/InstallAPI/DylibVerifier.cpp b/clang/lib/InstallAPI/DylibVerifier.cpp
index c0eda1d81b9b98..014b43dac6cf33 100644
--- a/clang/lib/InstallAPI/DylibVerifier.cpp
+++ b/clang/lib/InstallAPI/DylibVerifier.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/InstallAPI/DylibVerifier.h"
+#include "DiagnosticBuilderWrappers.h"
#include "clang/InstallAPI/FrontendRecords.h"
#include "clang/InstallAPI/InstallAPIDiagnostic.h"
#include "llvm/Demangle/Demangle.h"
@@ -178,6 +179,22 @@ bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
return SymCtx.FA->Avail.isObsoleted();
}
+bool DylibVerifier::shouldIgnoreReexport(const Record *R,
+ SymbolContext &SymCtx) const {
+ if (Reexports.empty())
+ return false;
+
+ for (const InterfaceFile &Lib : Reexports) {
+ if (!Lib.hasTarget(Ctx.Target))
+ continue;
+ if (auto Sym =
+ Lib.getSymbol(SymCtx.Kind, SymCtx.SymbolName, SymCtx.ObjCIFKind))
+ if ((*Sym)->hasTarget(Ctx.Target))
+ return true;
+ }
+ return false;
+}
+
bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R,
SymbolContext &SymCtx,
const ObjCInterfaceRecord *DR) {
@@ -383,6 +400,11 @@ DylibVerifier::Result DylibVerifier::verifyImpl(Record *R,
return Ctx.FrontendState;
}
+ if (shouldIgnoreReexport(R, SymCtx)) {
+ updateState(Result::Ignore);
+ return Ctx.FrontendState;
+ }
+
Record *DR =
findRecordFromSlice(Ctx.DylibSlice, SymCtx.SymbolName, SymCtx.Kind);
if (DR)
@@ -702,5 +724,179 @@ DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() {
return getState();
}
+bool DylibVerifier::verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,
+ const BinaryAttrs &ProvidedBA,
+ const LibAttrs &ProvidedReexports,
+ const LibAttrs &ProvidedClients,
+ const LibAttrs &ProvidedRPaths,
+ const FileType &FT) {
+ assert(!Dylib.empty() && "Need dylib to verify.");
+
+ // Pickup any load commands that can differ per slice to compare.
+ TargetList DylibTargets;
+ LibAttrs DylibReexports;
+ LibAttrs DylibClients;
+ LibAttrs DylibRPaths;
+ for (const std::shared_ptr<RecordsSlice> &RS : Dylib) {
+ DylibTargets.push_back(RS->getTarget());
+ const BinaryAttrs &BinInfo = RS->getBinaryAttrs();
+ for (const StringRef LibName : BinInfo.RexportedLibraries)
+ DylibReexports[LibName].set(DylibTargets.back().Arch);
+ for (const StringRef LibName : BinInfo.AllowableClients)
+ DylibClients[LibName].set(DylibTargets.back().Arch);
+ // Compare attributes that are only representable in >= TBD_V5.
+ if (FT >= FileType::TBD_V5)
+ for (const StringRef Name : BinInfo.RPaths)
+ DylibRPaths[Name].set(DylibTargets.back().Arch);
+ }
+
+ // Check targets first.
+ ArchitectureSet ProvidedArchs = mapToArchitectureSet(ProvidedTargets);
+ ArchitectureSet DylibArchs = mapToArchitectureSet(DylibTargets);
+ if (ProvidedArchs != DylibArchs) {
+ Ctx.Diag->Report(diag::err_architecture_mismatch)
+ << ProvidedArchs << DylibArchs;
+ return false;
+ }
+ auto ProvidedPlatforms = mapToPlatformVersionSet(ProvidedTargets);
+ auto DylibPlatforms = mapToPlatformVersionSet(DylibTargets);
+ if (ProvidedPlatforms != DylibPlatforms) {
+ const bool DiffMinOS =
+ mapToPlatformSet(ProvidedTargets) == mapToPlatformSet(DylibTargets);
+ if (DiffMinOS)
+ Ctx.Diag->Report(diag::warn_platform_mismatch)
+ << ProvidedPlatforms << DylibPlatforms;
+ else {
+ Ctx.Diag->Report(diag::err_platform_mismatch)
+ << ProvidedPlatforms << DylibPlatforms;
+ return false;
+ }
+ }
+
+ // Because InstallAPI requires certain attributes to match across architecture
+ // slices, take the first one to compare those with.
+ const BinaryAttrs &DylibBA = (*Dylib.begin())->getBinaryAttrs();
+
+ if (ProvidedBA.InstallName != DylibBA.InstallName) {
+ Ctx.Diag->Report(diag::err_install_name_mismatch)
+ << ProvidedBA.InstallName << DylibBA.InstallName;
+ return false;
+ }
+
+ if (ProvidedBA.CurrentVersion != DylibBA.CurrentVersion) {
+ Ctx.Diag->Report(diag::err_current_version_mismatch)
+ << ProvidedBA.CurrentVersion << DylibBA.CurrentVersion;
+ return false;
+ }
+
+ if (ProvidedBA.CompatVersion != DylibBA.CompatVersion) {
+ Ctx.Diag->Report(diag::err_compatibility_version_mismatch)
+ << ProvidedBA.CompatVersion << DylibBA.CompatVersion;
+ return false;
+ }
+
+ if (ProvidedBA.AppExtensionSafe != DylibBA.AppExtensionSafe) {
+ Ctx.Diag->Report(diag::err_appextension_safe_mismatch)
+ << (ProvidedBA.AppExtensionSafe ? "true" : "false")
+ << (DylibBA.AppExtensionSafe ? "true" : "false");
+ return false;
+ }
+
+ if (!DylibBA.TwoLevelNamespace) {
+ Ctx.Diag->Report(diag::err_no_twolevel_namespace);
+ return false;
+ }
+
+ if (ProvidedBA.OSLibNotForSharedCache != DylibBA.OSLibNotForSharedCache) {
+ Ctx.Diag->Report(diag::err_shared_cache_eligiblity_mismatch)
+ << (ProvidedBA.OSLibNotForSharedCache ? "true" : "false")
+ << (DylibBA.OSLibNotForSharedCache ? "true" : "false");
+ return false;
+ }
+
+ if (ProvidedBA.ParentUmbrella.empty() && !DylibBA.ParentUmbrella.empty()) {
+ Ctx.Diag->Report(diag::err_parent_umbrella_missing)
+ << "installAPI option" << DylibBA.ParentUmbrella;
+ return false;
+ }
+
+ if (!ProvidedBA.ParentUmbrella.empty() && !DylibBA.ParentUmbrella.empty()) {
+ Ctx.Diag->Report(diag::err_parent_umbrella_missing)
+ << "binary file" << ProvidedBA.ParentUmbrella;
+ return false;
+ }
+
+ if ((!ProvidedBA.ParentUmbrella.empty()) &&
+ (ProvidedBA.ParentUmbrella != DylibBA.ParentUmbrella)) {
+ Ctx.Diag->Report(diag::err_parent_umbrella_mismatch)
+ << ProvidedBA.ParentUmbrella << DylibBA.ParentUmbrella;
+ return false;
+ }
+
+ auto CompareLibraries = [&](const LibAttrs &Provided, const LibAttrs &Dylib,
+ unsigned DiagID_missing, unsigned DiagID_mismatch,
+ bool Fatal = true) {
+ if (Provided == Dylib)
+ return true;
+
+ for (const llvm::StringMapEntry<ArchitectureSet> &PAttr : Provided) {
+ const auto DAttrIt = Dylib.find(PAttr.getKey());
+ if (DAttrIt == Dylib.end()) {
+ Ctx.Diag->Report(DiagID_missing) << "binary file" << PAttr;
+ if (Fatal)
+ return false;
+ }
+
+ if (PAttr.getValue() != DAttrIt->getValue()) {
+ Ctx.Diag->Report(DiagID_mismatch) << PAttr << *DAttrIt;
+ if (Fatal)
+ return false;
+ }
+ }
+
+ for (const llvm::StringMapEntry<ArchitectureSet> &DAttr : Dylib) {
+ const auto PAttrIt = Provided.find(DAttr.getKey());
+ if (PAttrIt == Provided.end()) {
+ Ctx.Diag->Report(DiagID_missing) << "installAPI option" << DAttr;
+ if (!Fatal)
+ continue;
+ return false;
+ }
+
+ if (PAttrIt->getValue() != DAttr.getValue()) {
+ if (Fatal)
+ llvm_unreachable("this case was already covered above.");
+ }
+ }
+ return true;
+ };
+
+ if (!CompareLibraries(ProvidedReexports, DylibReexports,
+ diag::err_reexported_libraries_missing,
+ diag::err_reexported_libraries_mismatch))
+ return false;
+
+ if (!CompareLibraries(ProvidedClients, DylibClients,
+ diag::err_allowable_clients_missing,
+ diag::err_allowable_clients_mismatch))
+ return false;
+
+ if (FT >= FileType::TBD_V5) {
+ // Ignore rpath differences if building an asan variant, since the
+ // compiler injects additional paths.
+ // FIXME: Building with sanitizers does not always change the install
+ // name, so this is not a foolproof solution.
+ if (!ProvidedBA.InstallName.ends_with("_asan")) {
+ if (!CompareLibraries(ProvidedRPaths, DylibRPaths,
+ diag::warn_rpaths_missing,
+ diag::warn_rpaths_mismatch,
+ /*Fatal=*/false))
+ return true;
+ }
+ }
+
+ return true;
+}
+
} // namespace installapi
} // namespace clang
diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp
index e07ccb14e0b80a..bd7589c13e043f 100644
--- a/clang/lib/InstallAPI/Frontend.cpp
+++ b/clang/lib/InstallAPI/Frontend.cpp
@@ -162,4 +162,58 @@ std::unique_ptr<MemoryBuffer> createInputBuffer(InstallAPIContext &Ctx) {
return llvm::MemoryBuffer::getMemBufferCopy(Contents, BufferName);
}
+std::string findLibrary(StringRef InstallName, FileManager &FM,
+ ArrayRef<std::string> FrameworkSearchPaths,
+ ArrayRef<std::string> LibrarySearchPaths,
+ ArrayRef<std::string> SearchPaths) {
+ auto getLibrary =
+ [&](const StringRef FullPath) -> std::optional<std::string> {
+ // Prefer TextAPI files when possible.
+ SmallString<PATH_MAX> TextAPIFilePath = FullPath;
+ replace_extension(TextAPIFilePath, ".tbd");
+
+ if (FM.getOptionalFileRef(TextAPIFilePath))
+ return std::string(TextAPIFilePath);
+
+ if (FM.getOptionalFileRef(FullPath))
+ return std::string(FullPath);
+
+ return std::nullopt;
+ };
+
+ const StringRef Filename = sys::path::filename(InstallName);
+ const bool IsFramework = sys::path::parent_path(InstallName)
+ .ends_with((Filename + ".framework").str());
+ if (IsFramework) {
+ for (const StringRef Path : FrameworkSearchPaths) {
+ SmallString<PATH_MAX> FullPath(Path);
+ sys::path::append(FullPath, Filename + StringRef(".framework"), Filename);
+ if (auto LibOrNull = getLibrary(FullPath))
+ return *LibOrNull;
+ }
+ } else {
+ // Copy Apple's linker behavior: If this is a .dylib inside a framework, do
+ // not search -L paths.
+ bool IsEmbeddedDylib = (sys::path::extension(InstallName) == ".dylib") &&
+ InstallName.contains(".framework/");
+ if (!IsEmbeddedDylib) {
+ for (const StringRef Path : LibrarySearchPaths) {
+ SmallString<PATH_MAX> FullPath(Path);
+ sys::path::append(FullPath, Filename);
+ if (auto LibOrNull = getLibrary(FullPath))
+ return *LibOrNull;
+ }
+ }
+ }
+
+ for (const StringRef Path : SearchPaths) {
+ SmallString<PATH_MAX> FullPath(Path);
+ sys::path::append(FullPath, InstallName);
+ if (auto LibOrNull = getLibrary(FullPath))
+ return *LibOrNull;
+ }
+
+ return {};
+}
+
} // namespace clang::installapi
diff --git a/clang/test/InstallAPI/binary-attributes.test b/clang/test/InstallAPI/binary-attributes.test
new file mode 100644
index 00000000000000..c141211912f2cf
--- /dev/null
+++ b/clang/test/InstallAPI/binary-attributes.test
@@ -0,0 +1,70 @@
+; RUN: rm -rf %t
+; RUN: split-file %s %t
+; RUN: mkdir -p %t/System/Library/Frameworks
+; RUN: cp -r %S/Inputs/Simple/Simple.framework %t/System/Library/Frameworks/
+; RUN: yaml2obj %S/Inputs/Simple/Simple.yaml -o %t/Simple
+
+; RUN: not clang-installapi -target x86_64h-apple-macos10.12 \
+; RUN: -install_name Simple -current_version 3 -compatibility_version 2 \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=ARCHITECTURE %s
+; ARCHITECTURE: error: architectures do not match: 'x86_64h' (provided) vs 'x86_64' (found)
+
+; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
+; RUN: -install_name Simple -current_version 3 -compatibility_version 2 \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=INSTALL_NAME %s
+; INSTALL_NAME: error: install_name does not match: 'Simple' (provided) vs '/System/Library/Frameworks/Simple.framework/Versions/A/Simple' (found)
+
+; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
+; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
+; RUN: -current_version 3 -compatibility_version 2 \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=CURRENT_VERSION %s
+; CURRENT_VERSION: error: current_version does not match: '3' (provided) vs '1.2.3' (found)
+
+; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
+; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
+; RUN: -current_version 1.2.3 -compatibility_version 2 \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=COMPATIBILITY_VERSION %s
+; COMPATIBILITY_VERSION: error: compatibility_version does not match: '2' (provided) vs '1' (found)
+
+; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
+; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
+; RUN: -current_version 1.2.3 -compatibility_version 1 -fapplication-extension \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=APPEXTSAFE %s
+; APPEXTSAFE: error: ApplicationExtensionSafe flag does not match: 'true' (provided) vs 'false' (found)
+
+; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
+; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
+; RUN: -current_version 1.2.3 -compatibility_version 1 -not_for_dyld_shared_cache \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=SHARED_CACHE %s
+; SHARED_CACHE: error: NotForDyldSharedCache flag does not match: 'true' (provided) vs 'false' (found)
+
+; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
+; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
+; RUN: -current_version 1.2.3 -compatibility_version 1 \
+; RUN: -allowable_client Foo -allowable_client Bar \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=ALLOWABLE %s
+; ALLOWABLE: error: allowable client missing from binary file: 'Foo [ x86_64 ]'
+
+; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
+; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
+; RUN: -current_version 1.2.3 -compatibility_version 1 -reexport_library %t/Foo.tbd \
+; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=REEXPORT %s
+; REEXPORT: error: re-exported library missing from binary file: 'Foo [ x86_64 ]'
+
+;--- Foo.tbd
+{
+ "main_library": {
+ "install_names": [
+ {
+ "name": "Foo"
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13.0",
+ "target": "arm64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
diff --git a/clang/test/InstallAPI/driver-invalid-options.test b/clang/test/InstallAPI/driver-invalid-options.test
index 0c630eacd18368..2b2c551fca2025 100644
--- a/clang/test/InstallAPI/driver-invalid-options.test
+++ b/clang/test/InstallAPI/driver-invalid-options.test
@@ -13,3 +13,9 @@
// RUN: --verify-mode=Invalid -o tmp.tbd 2> %t
// RUN: FileCheck --check-prefix INVALID_VERIFY_MODE -input-file %t %s
// INVALID_VERIFY_MODE: error: invalid value 'Invalid' in '--verify-mode=Invalid'
+
+/// Check that invalid sysroot is fatal.
+// RUN: not clang-installapi -install_name Foo -target arm64-apple-ios13 \
+// RUN: -isysroot /no/such/path -o tmp.tbd 2> %t
+// RUN: FileCheck --check-prefix INVALID_ISYSROOT -input-file %t %s
+// INVALID_ISYSROOT: error: no such sysroot directory: {{.*}}no/such/path'
diff --git a/clang/test/InstallAPI/reexported-frameworks.test b/clang/test/InstallAPI/reexported-frameworks.test
new file mode 100644
index 00000000000000..41c4f539c0b1fd
--- /dev/null
+++ b/clang/test/InstallAPI/reexported-frameworks.test
@@ -0,0 +1,638 @@
+; RUN: rm -rf %t
+; RUN: split-file %s %t
+; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
+
+; RUN: yaml2obj %t/Umbrella.yaml -o %t/Umbrella
+; RUN: mkdir -p %t/System/Library/Frameworks/Bar.framework
+; RUN: yaml2obj %t/Bar.yaml -o %t/System/Library/Frameworks/Bar.framework/Bar
+
+; RUN: clang-installapi -target x86_64-apple-macosx13 -install_name \
+; RUN: /System/Library/Frameworks/Umbrella3.framework/Versions/A/Umbrella3 \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: --verify-against=%t/Umbrella \
+; RUN: -F %t/System/Library/Frameworks -L %t/usr/lib \
+; RUN: %t/inputs.json --verify-mode=Pedantic \
+; RUN: -reexport_framework Foo -reexport_framework Bar -reexport-lBaz \
+; RUN: -o %t/Umbrella.tbd 2>&1 | FileCheck -allow-empty %s
+; RUN: llvm-readtapi -compare %t/Umbrella.tbd %t/expected.tbd 2>&1 | FileCheck -allow-empty %s
+
+// Checks that one of the reexported frameworks found earlier doesn't resolve
+// a missing export from a declaration.
+; RUN: not clang-installapi -target x86_64-apple-macosx13 -install_name \
+; RUN: /System/Library/Frameworks/Umbrella3.framework/Versions/A/Umbrella3 \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: --verify-against=%t/Umbrella \
+; RUN: %t/inputs.json -F %t/BadFoo \
+; RUN: -F %t/System/Library/Frameworks -L %t/usr/lib \
+; RUN: --verify-mode=ErrorsOnly \
+; RUN: -reexport_framework Foo -reexport_framework Bar -reexport-lBaz \
+; RUN: -o %t/Umbrella.tbd 2>&1 | FileCheck %s --check-prefix MISSING_SYMBOL
+
+; MISSING_SYMBOL: error: declaration has external linkage, but dynamic library doesn't have symbol 'foo'
+; MISSING_SYMBOL-NEXT: extern int foo();
+
+
+; CHECK-NOT: error
+; CHECK-NOT: warning
+
+;--- System/Library/Frameworks/Umbrella.framework/Headers/Bar.h
+extern int bar();
+
+;--- System/Library/Frameworks/Umbrella.framework/Headers/Baz.h
+extern int baz();
+
+;--- System/Library/Frameworks/Umbrella.framework/Headers/Foo.h
+extern int foo();
+
+;--- System/Library/Frameworks/Umbrella.framework/Headers/Umbrella.h
+#import <Umbrella/Bar.h>
+#import <Umbrella/Baz.h>
+#import <Umbrella/Foo.h>
+
+;--- inputs.json.in
+{
+ "headers": [ {
+ "path" : "DSTROOT/System/Library/Frameworks/Umbrella.framework/Headers/Bar.h",
+ "type" : "public"
+ },
+ {
+ "path" : "DSTROOT/System/Library/Frameworks/Umbrella.framework/Headers/Baz.h",
+ "type" : "public"
+ },
+ {
+ "path" : "DSTROOT/System/Library/Frameworks/Umbrella.framework/Headers/Umbrella.h",
+ "type" : "public"
+ },
+ {
+ "path" : "DSTROOT/System/Library/Frameworks/Umbrella.framework/Headers/Foo.h",
+ "type" : "public"
+ }
+ ],
+ "version": "3"
+}
+
+;--- Umbrella.yaml
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x1000007
+ cpusubtype: 0x3
+ filetype: 0x6
+ ncmds: 18
+ sizeofcmds: 1184
+ flags: 0x85
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __TEXT
+ vmaddr: 0
+ vmsize: 12288
+ fileoff: 0
+ filesize: 12288
+ maxprot: 5
+ initprot: 5
+ nsects: 1
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x24C0
+ size: 0
+ offset: 0x24C0
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000000
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: ''
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA_CONST
+ vmaddr: 12288
+ vmsize: 4096
+ fileoff: 12288
+ filesize: 4096
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 16
+ Sections:
+ - sectname: __objc_imageinfo
+ segname: __DATA_CONST
+ addr: 0x3000
+ size: 8
+ offset: 0x3000
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000040000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 16384
+ vmsize: 48
+ fileoff: 16384
+ filesize: 48
+ maxprot: 1
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 0
+ rebase_size: 0
+ bind_off: 0
+ bind_size: 0
+ weak_bind_off: 0
+ weak_bind_size: 0
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 0
+ export_size: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 16392
+ nsyms: 1
+ stroff: 16408
+ strsize: 24
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 0
+ iextdefsym: 0
+ nextdefsym: 0
+ iundefsym: 0
+ nundefsym: 1
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 0
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_ID_DYLIB
+ cmdsize: 96
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/System/Library/Frameworks/Umbrella3.framework/Versions/A/Umbrella3'
+ ZeroPadBytes: 5
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 4C4C44AE-5555-3144-A1D3-33A5C6F7B36A
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 4
+ version: 1245184
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 80
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/System/Library/Frameworks/Foo.framework/Versions/A/Foo'
+ ZeroPadBytes: 1
+ - cmd: LC_REEXPORT_DYLIB
+ cmdsize: 80
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 0
+ compatibility_version: 0
+ Content: '/System/Library/Frameworks/Foo.framework/Versions/A/Foo'
+ ZeroPadBytes: 1
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 80
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/System/Library/Frameworks/Bar.framework/Versions/A/Bar'
+ ZeroPadBytes: 1
+ - cmd: LC_REEXPORT_DYLIB
+ cmdsize: 80
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 0
+ compatibility_version: 0
+ Content: '/System/Library/Frameworks/Bar.framework/Versions/A/Bar'
+ ZeroPadBytes: 1
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 48
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/usr/lib/libBaz.1.dylib'
+ ZeroPadBytes: 1
+ - cmd: LC_REEXPORT_DYLIB
+ cmdsize: 48
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 0
+ compatibility_version: 0
+ Content: '/usr/lib/libBaz.1.dylib'
+ ZeroPadBytes: 1
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 88539136
+ compatibility_version: 65536
+ Content: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 16384
+ datasize: 8
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 16392
+ datasize: 0
+LinkEditData:
+ NameList:
+ - n_strx: 2
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 1024
+ n_value: 0
+ StringTable:
+ - ' '
+ - dyld_stub_binder
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+...
+
+;--- System/Library/Frameworks/Foo.framework/Foo.tbd
+{
+ "main_library": {
+ "exported_symbols": [
+ {
+ "text": {
+ "global": [
+ "_foo"
+ ]
+ }
+ }
+ ],
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/System/Library/Frameworks/Foo.framework/Versions/A/Foo"
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13",
+ "target": "x86_64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
+
+;--- Bar.yaml
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x1000007
+ cpusubtype: 0x3
+ filetype: 0x6
+ ncmds: 12
+ sizeofcmds: 912
+ flags: 0x100085
+ reserved: 0x0
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 312
+ segname: __TEXT
+ vmaddr: 0
+ vmsize: 8192
+ fileoff: 0
+ filesize: 8192
+ maxprot: 5
+ initprot: 5
+ nsects: 3
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0xBB0
+ size: 8
+ offset: 0xBB0
+ align: 4
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000400
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 554889E531C05DC3
+ - sectname: __unwind_info
+ segname: __TEXT
+ addr: 0xBB8
+ size: 4152
+ offset: 0xBB8
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 010000001C000000010000002000000000000000200000000200000000000001B00B00003800000038000000B80B00000000000038000000030000000C0001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ - sectname: __eh_frame
+ segname: __TEXT
+ addr: 0x1BF0
+ size: 24
+ offset: 0x1BF0
+ align: 3
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x6000000B
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: 1400000000000000017A520001781001100C070890010000
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA_CONST
+ vmaddr: 8192
+ vmsize: 4096
+ fileoff: 8192
+ filesize: 4096
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 16
+ Sections:
+ - sectname: __objc_imageinfo
+ segname: __DATA_CONST
+ addr: 0x2000
+ size: 8
+ offset: 0x2000
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000040000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 12288
+ vmsize: 80
+ fileoff: 12288
+ filesize: 80
+ maxprot: 1
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 0
+ rebase_size: 0
+ bind_off: 0
+ bind_size: 0
+ weak_bind_off: 0
+ weak_bind_size: 0
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 12288
+ export_size: 16
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 12312
+ nsyms: 2
+ stroff: 12344
+ strsize: 24
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 0
+ iextdefsym: 0
+ nextdefsym: 1
+ iundefsym: 1
+ nundefsym: 1
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 0
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_ID_DYLIB
+ cmdsize: 80
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '/System/Library/Frameworks/Bar.framework/Versions/A/Bar'
+ ZeroPadBytes: 1
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 4C4C4415-5555-3144-A11E-3C68D85CC061
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 4
+ version: 1245184
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 88539136
+ compatibility_version: 65536
+ Content: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 12304
+ datasize: 8
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 12312
+ datasize: 0
+LinkEditData:
+ ExportTrie:
+ TerminalSize: 0
+ NodeOffset: 0
+ Name: ''
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 3
+ NodeOffset: 8
+ Name: _bar
+ Flags: 0x0
+ Address: 0xBB0
+ Other: 0x0
+ ImportName: ''
+ NameList:
+ - n_strx: 2
+ n_type: 0xF
+ n_sect: 1
+ n_desc: 0
+ n_value: 2992
+ - n_strx: 7
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 256
+ n_value: 0
+ StringTable:
+ - ' '
+ - _bar
+ - dyld_stub_binder
+ FunctionStarts: [ 0xBB0 ]
+...
+
+;--- usr/lib/libBaz.tbd
+{
+ "main_library": {
+ "exported_symbols": [
+ {
+ "text": {
+ "global": [
+ "_baz"
+ ]
+ }
+ }
+ ],
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/usr/lib/libBaz.1.dylib"
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13",
+ "target": "x86_64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
+
+;--- BadFoo/Foo.framework/Foo.tbd
+{
+ "main_library": {
+ "exported_symbols": [
+ {
+ "text": {
+ "global": [
+ "_not_so_foo"
+ ]
+ }
+ }
+ ],
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/System/Library/Frameworks/Foo.framework/Versions/A/Foo"
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13",
+ "target": "x86_64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
+
+;--- expected.tbd
+{
+ "main_library": {
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/System/Library/Frameworks/Umbrella3.framework/Versions/A/Umbrella3"
+ }
+ ],
+ "reexported_libraries": [
+ {
+ "names": [
+ "/System/Library/Frameworks/Bar.framework/Versions/A/Bar",
+ "/System/Library/Frameworks/Foo.framework/Versions/A/Foo",
+ "/usr/lib/libBaz.1.dylib"
+ ]
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13",
+ "target": "x86_64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
diff --git a/clang/test/InstallAPI/rpath.test b/clang/test/InstallAPI/rpath.test
new file mode 100644
index 00000000000000..083a15419abaab
--- /dev/null
+++ b/clang/test/InstallAPI/rpath.test
@@ -0,0 +1,663 @@
+; RUN: rm -rf %t
+; RUN: split-file %s %t
+; RUN: yaml2obj %t/RPath.yaml -o %t/RPath
+
+; RUN: clang-installapi --filetype=tbd-v5 \
+; RUN: -target arm64-apple-macos13.0 -target x86_64-apple-macos13.0 \
+; RUN: -install_name @rpath/Frameworks/RPath.framework/Versions/A/RPath \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: --extra-public-header=%t/public.h \
+; RUN: -o %t/RPath_warnings.tbd \
+; RUN: --verify-against=%t/RPath \
+; RUN: --verify-mode=Pedantic 2>&1 | FileCheck %s --check-prefix=MISSING
+; RUN: llvm-readtapi --compare %t/RPath_warnings.tbd %t/expected_no_rpaths.tbd
+
+; MISSING: warning: runpath search paths missing from installAPI option: '@loader_path/../../../SharedFrameworks/ [ x86_64 arm64 ]'
+; MISSING: warning: runpath search paths missing from installAPI option: '@loader_path/../../PrivateFrameworks/ [ x86_64 arm64 ]'
+
+; RUN: clang-installapi --filetype=tbd-v5 \
+; RUN: -target arm64-apple-macos13.0 -target x86_64-apple-macos13.0 \
+; RUN: -install_name @rpath/Frameworks/RPath.framework/Versions/A/RPath \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: --extra-public-header=%t/public.h \
+; RUN: -Xarch_arm64 -rpath @loader_path/../../../SharedFrameworks/ \
+; RUN: -o %t/RPath_Xarch.tbd \
+; RUN: --verify-against=%t/RPath \
+; RUN: --verify-mode=Pedantic 2>&1 | FileCheck %s --check-prefix=XARCH
+; RUN: llvm-readtapi --compare %t/RPath_Xarch.tbd %t/expected_xarch_rpaths.tbd
+
+; XARCH: warning: runpath search paths do not match: '@loader_path/../../../SharedFrameworks/ [ arm64 ]' (provided) vs '@loader_path/../../../SharedFrameworks/ [ x86_64 arm64 ]'
+; XARCH: warning: runpath search paths missing from installAPI option: '@loader_path/../../PrivateFrameworks/ [ x86_64 arm64 ]'
+
+; RUN: clang-installapi --filetype=tbd-v5 \
+; RUN: -target arm64-apple-macos13.0 -target x86_64-apple-macos13.0 \
+; RUN: -install_name @rpath/Frameworks/RPath.framework/Versions/A/RPath \
+; RUN: -current_version 1 -compatibility_version 1 \
+; RUN: --extra-public-header=%t/public.h \
+; RUN: -rpath @loader_path/../../../SharedFrameworks/ \
+; RUN: -rpath @loader_path/../../PrivateFrameworks/ \
+; RUN: --verify-against=%t/RPath --verify-mode=Pedantic \
+; RUN: -o %t/RPath.tbd 2>&1 | FileCheck -allow-empty %s
+; RUN: llvm-readtapi --compare %t/RPath.tbd %t/expected.tbd
+
+CHECK-NOT: error
+CHECK-NOT: warning
+
+;--- public.h
+extern int publicGlobalVariable;
+
+;--- expected.tbd
+{
+ "main_library": {
+ "exported_symbols": [
+ {
+ "data": {
+ "global": [
+ "_publicGlobalVariable"
+ ]
+ }
+ }
+ ],
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "@rpath/Frameworks/RPath.framework/Versions/A/RPath"
+ }
+ ],
+ "rpaths": [
+ {
+ "paths": [
+ "@loader_path/../../../SharedFrameworks/",
+ "@loader_path/../../PrivateFrameworks/"
+ ]
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13.0",
+ "target": "x86_64-macos"
+ },
+ {
+ "min_deployment": "13.0",
+ "target": "arm64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
+
+;--- expected_no_rpaths.tbd
+{
+ "main_library": {
+ "exported_symbols": [
+ {
+ "data": {
+ "global": [
+ "_publicGlobalVariable"
+ ]
+ }
+ }
+ ],
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "@rpath/Frameworks/RPath.framework/Versions/A/RPath"
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13.0",
+ "target": "x86_64-macos"
+ },
+ {
+ "min_deployment": "13.0",
+ "target": "arm64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
+
+;--- expected_xarch_rpaths.tbd
+{
+ "main_library": {
+ "exported_symbols": [
+ {
+ "data": {
+ "global": [
+ "_publicGlobalVariable"
+ ]
+ }
+ }
+ ],
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "@rpath/Frameworks/RPath.framework/Versions/A/RPath"
+ }
+ ],
+ "rpaths": [
+ {
+ "paths": [
+ "@loader_path/../../../SharedFrameworks/"
+ ],
+ "targets": [
+ "arm64-macos"
+ ]
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13.0",
+ "target": "x86_64-macos"
+ },
+ {
+ "min_deployment": "13.0",
+ "target": "arm64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
+
+;--- RPath.yaml
+--- !fat-mach-o
+FatHeader:
+ magic: 0xCAFEBABE
+ nfat_arch: 2
+FatArchs:
+ - cputype: 0x1000007
+ cpusubtype: 0x3
+ offset: 0x1000
+ size: 12408
+ align: 12
+ - cputype: 0x100000C
+ cpusubtype: 0x0
+ offset: 0x8000
+ size: 33312
+ align: 14
+Slices:
+ - !mach-o
+ FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x1000007
+ cpusubtype: 0x3
+ filetype: 0x6
+ ncmds: 16
+ sizeofcmds: 1072
+ flags: 0x100085
+ reserved: 0x0
+ LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __TEXT
+ vmaddr: 0
+ vmsize: 8192
+ fileoff: 0
+ filesize: 8192
+ maxprot: 5
+ initprot: 5
+ nsects: 1
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x1050
+ size: 0
+ offset: 0x1050
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000000
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: ''
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA_CONST
+ vmaddr: 8192
+ vmsize: 4096
+ fileoff: 8192
+ filesize: 4096
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 16
+ Sections:
+ - sectname: __objc_imageinfo
+ segname: __DATA_CONST
+ addr: 0x2000
+ size: 8
+ offset: 0x2000
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000040000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA
+ vmaddr: 12288
+ vmsize: 4096
+ fileoff: 12288
+ filesize: 0
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 0
+ Sections:
+ - sectname: __common
+ segname: __DATA
+ addr: 0x3000
+ size: 4
+ offset: 0x0
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x1
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 16384
+ vmsize: 120
+ fileoff: 12288
+ filesize: 120
+ maxprot: 1
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 0
+ rebase_size: 0
+ bind_off: 0
+ bind_size: 0
+ weak_bind_off: 0
+ weak_bind_size: 0
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 12288
+ export_size: 32
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 12328
+ nsyms: 2
+ stroff: 12360
+ strsize: 48
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 0
+ iextdefsym: 0
+ nextdefsym: 1
+ iundefsym: 1
+ nundefsym: 1
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 0
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_RPATH
+ cmdsize: 56
+ path: 12
+ Content: '@loader_path/../../../SharedFrameworks/'
+ ZeroPadBytes: 5
+ - cmd: LC_RPATH
+ cmdsize: 56
+ path: 12
+ Content: '@loader_path/../../PrivateFrameworks/'
+ ZeroPadBytes: 7
+ - cmd: LC_ID_DYLIB
+ cmdsize: 80
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '@rpath/Frameworks/RPath.framework/Versions/A/RPath'
+ ZeroPadBytes: 6
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 4C4C4489-5555-3144-A1D1-28C8EA66FB24
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 4
+ version: 1245184
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 14942208
+ compatibility_version: 65536
+ Content: '/usr/lib/libobjc.A.dylib'
+ ZeroPadBytes: 8
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 88539136
+ compatibility_version: 65536
+ Content: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 12320
+ datasize: 8
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 12328
+ datasize: 0
+ LinkEditData:
+ ExportTrie:
+ TerminalSize: 0
+ NodeOffset: 0
+ Name: ''
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 3
+ NodeOffset: 25
+ Name: _publicGlobalVariable
+ Flags: 0x0
+ Address: 0x3000
+ Other: 0x0
+ ImportName: ''
+ NameList:
+ - n_strx: 2
+ n_type: 0xF
+ n_sect: 3
+ n_desc: 0
+ n_value: 12288
+ - n_strx: 24
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 512
+ n_value: 0
+ StringTable:
+ - ' '
+ - _publicGlobalVariable
+ - dyld_stub_binder
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - !mach-o
+ FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x100000C
+ cpusubtype: 0x0
+ filetype: 0x6
+ ncmds: 17
+ sizeofcmds: 1088
+ flags: 0x100085
+ reserved: 0x0
+ LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __TEXT
+ vmaddr: 0
+ vmsize: 16384
+ fileoff: 0
+ filesize: 16384
+ maxprot: 5
+ initprot: 5
+ nsects: 1
+ flags: 0
+ Sections:
+ - sectname: __text
+ segname: __TEXT
+ addr: 0x1060
+ size: 0
+ offset: 0x1060
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x80000000
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: ''
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA_CONST
+ vmaddr: 16384
+ vmsize: 16384
+ fileoff: 16384
+ filesize: 16384
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 16
+ Sections:
+ - sectname: __objc_imageinfo
+ segname: __DATA_CONST
+ addr: 0x4000
+ size: 8
+ offset: 0x4000
+ align: 0
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x0
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ content: '0000000040000000'
+ - cmd: LC_SEGMENT_64
+ cmdsize: 152
+ segname: __DATA
+ vmaddr: 32768
+ vmsize: 16384
+ fileoff: 32768
+ filesize: 0
+ maxprot: 3
+ initprot: 3
+ nsects: 1
+ flags: 0
+ Sections:
+ - sectname: __common
+ segname: __DATA
+ addr: 0x8000
+ size: 4
+ offset: 0x0
+ align: 2
+ reloff: 0x0
+ nreloc: 0
+ flags: 0x1
+ reserved1: 0x0
+ reserved2: 0x0
+ reserved3: 0x0
+ - cmd: LC_SEGMENT_64
+ cmdsize: 72
+ segname: __LINKEDIT
+ vmaddr: 49152
+ vmsize: 544
+ fileoff: 32768
+ filesize: 544
+ maxprot: 1
+ initprot: 1
+ nsects: 0
+ flags: 0
+ - cmd: LC_DYLD_INFO_ONLY
+ cmdsize: 48
+ rebase_off: 0
+ rebase_size: 0
+ bind_off: 0
+ bind_size: 0
+ weak_bind_off: 0
+ weak_bind_size: 0
+ lazy_bind_off: 0
+ lazy_bind_size: 0
+ export_off: 32768
+ export_size: 32
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 32808
+ nsyms: 2
+ stroff: 32840
+ strsize: 48
+ - cmd: LC_DYSYMTAB
+ cmdsize: 80
+ ilocalsym: 0
+ nlocalsym: 0
+ iextdefsym: 0
+ nextdefsym: 1
+ iundefsym: 1
+ nundefsym: 1
+ tocoff: 0
+ ntoc: 0
+ modtaboff: 0
+ nmodtab: 0
+ extrefsymoff: 0
+ nextrefsyms: 0
+ indirectsymoff: 0
+ nindirectsyms: 0
+ extreloff: 0
+ nextrel: 0
+ locreloff: 0
+ nlocrel: 0
+ - cmd: LC_RPATH
+ cmdsize: 56
+ path: 12
+ Content: '@loader_path/../../../SharedFrameworks/'
+ ZeroPadBytes: 5
+ - cmd: LC_RPATH
+ cmdsize: 56
+ path: 12
+ Content: '@loader_path/../../PrivateFrameworks/'
+ ZeroPadBytes: 7
+ - cmd: LC_ID_DYLIB
+ cmdsize: 80
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 65536
+ compatibility_version: 65536
+ Content: '@rpath/Frameworks/RPath.framework/Versions/A/RPath'
+ ZeroPadBytes: 6
+ - cmd: LC_UUID
+ cmdsize: 24
+ uuid: 4C4C440D-5555-3144-A18B-DB67A0A12202
+ - cmd: LC_BUILD_VERSION
+ cmdsize: 32
+ platform: 1
+ minos: 851968
+ sdk: 983040
+ ntools: 1
+ Tools:
+ - tool: 4
+ version: 1245184
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 14942208
+ compatibility_version: 65536
+ Content: '/usr/lib/libobjc.A.dylib'
+ ZeroPadBytes: 8
+ - cmd: LC_LOAD_DYLIB
+ cmdsize: 56
+ dylib:
+ name: 24
+ timestamp: 0
+ current_version: 88539136
+ compatibility_version: 65536
+ Content: '/usr/lib/libSystem.B.dylib'
+ ZeroPadBytes: 6
+ - cmd: LC_FUNCTION_STARTS
+ cmdsize: 16
+ dataoff: 32800
+ datasize: 8
+ - cmd: LC_DATA_IN_CODE
+ cmdsize: 16
+ dataoff: 32808
+ datasize: 0
+ - cmd: LC_CODE_SIGNATURE
+ cmdsize: 16
+ dataoff: 32896
+ datasize: 416
+ LinkEditData:
+ ExportTrie:
+ TerminalSize: 0
+ NodeOffset: 0
+ Name: ''
+ Flags: 0x0
+ Address: 0x0
+ Other: 0x0
+ ImportName: ''
+ Children:
+ - TerminalSize: 4
+ NodeOffset: 25
+ Name: _publicGlobalVariable
+ Flags: 0x0
+ Address: 0x8000
+ Other: 0x0
+ ImportName: ''
+ NameList:
+ - n_strx: 2
+ n_type: 0xF
+ n_sect: 3
+ n_desc: 0
+ n_value: 32768
+ - n_strx: 24
+ n_type: 0x1
+ n_sect: 0
+ n_desc: 512
+ n_value: 0
+ StringTable:
+ - ' '
+ - _publicGlobalVariable
+ - dyld_stub_binder
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ - ''
+ FunctionStarts: [ 0x1060 ]
+...
diff --git a/clang/tools/clang-installapi/CMakeLists.txt b/clang/tools/clang-installapi/CMakeLists.txt
index b90ffc847b1558..9c0d9dff7dc7f2 100644
--- a/clang/tools/clang-installapi/CMakeLists.txt
+++ b/clang/tools/clang-installapi/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
+ BinaryFormat
Support
TargetParser
TextAPI
diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp
index 13061cfa36eeb0..0c1980ba5d6280 100644
--- a/clang/tools/clang-installapi/ClangInstallAPI.cpp
+++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp
@@ -101,6 +101,16 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
if (Diag->hasErrorOccurred())
return EXIT_FAILURE;
+ if (!Opts.DriverOpts.DylibToVerify.empty()) {
+ TargetList Targets;
+ llvm::for_each(Opts.DriverOpts.Targets,
+ [&](const auto &T) { Targets.push_back(T.first); });
+ if (!Ctx.Verifier->verifyBinaryAttrs(Targets, Ctx.BA, Ctx.Reexports,
+ Opts.LinkerOpts.AllowableClients,
+ Opts.LinkerOpts.RPaths, Ctx.FT))
+ return EXIT_FAILURE;
+ };
+
// Set up compilation.
std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
CI->setFileManager(FM.get());
@@ -108,7 +118,7 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
if (!CI->hasDiagnostics())
return EXIT_FAILURE;
- // Execute and gather AST results.
+ // Execute, verify and gather AST results.
// An invocation is ran for each unique target triple and for each header
// access level.
for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) {
@@ -136,10 +146,25 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
// Assign attributes for serialization.
InterfaceFile IF(Ctx.Verifier->getExports());
+ // Assign attributes that are the same per slice first.
for (const auto &TargetInfo : Opts.DriverOpts.Targets) {
IF.addTarget(TargetInfo.first);
IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first);
}
+ // Then assign potentially different attributes per slice after.
+ auto assignLibAttrs =
+ [&IF](
+ const auto &Attrs,
+ std::function<void(InterfaceFile *, StringRef, const Target &)> Add) {
+ for (const auto &Lib : Attrs)
+ for (const auto &T : IF.targets(Lib.getValue()))
+ Add(&IF, Lib.getKey(), T);
+ };
+
+ assignLibAttrs(Opts.LinkerOpts.AllowableClients,
+ &InterfaceFile::addAllowableClient);
+ assignLibAttrs(Opts.LinkerOpts.RPaths, &InterfaceFile::addRPath);
+ assignLibAttrs(Ctx.Reexports, &InterfaceFile::addReexportedLibrary);
// Write output file and perform CI cleanup.
if (auto Err = TextAPIWriter::writeToStream(*Out, IF, Ctx.FT)) {
diff --git a/clang/tools/clang-installapi/InstallAPIOpts.td b/clang/tools/clang-installapi/InstallAPIOpts.td
index 010f2507a1d1f3..8b1998c280dd69 100644
--- a/clang/tools/clang-installapi/InstallAPIOpts.td
+++ b/clang/tools/clang-installapi/InstallAPIOpts.td
@@ -17,11 +17,23 @@ include "llvm/Option/OptParser.td"
/////////
// Options
-// TextAPI options.
+//
+/// TextAPI options.
+//
def filetype : Joined<["--"], "filetype=">,
HelpText<"Specify the output file type (tbd-v4 or tbd-v5)">;
+def not_for_dyld_shared_cache : Joined<["-"], "not_for_dyld_shared_cache">,
+ HelpText<"Mark library as shared cache ineligible">;
+
+//
+/// Debugging or logging options.
+//
+def t: Flag<["-"], "t">,
+ HelpText<"Logs each dylib loaded for InstallAPI. Useful for debugging problems with search paths where the wrong library is loaded.">;
-// Verification options.
+//
+/// Verification options.
+//
def verify_against : Separate<["-"], "verify-against">,
HelpText<"Verify the specified dynamic library/framework against the headers">;
def verify_against_EQ : Joined<["--"], "verify-against=">, Alias<verify_against>;
@@ -32,7 +44,9 @@ def demangle : Flag<["--", "-"], "demangle">,
def dsym: Joined<["--"], "dsym=">,
MetaVarName<"<path>">, HelpText<"Specify dSYM path for enriched diagnostics.">;
-// Additional input options.
+//
+/// Additional input options.
+//
def extra_project_header : Separate<["-"], "extra-project-header">,
MetaVarName<"<path>">,
HelpText<"Add additional project header location for parsing">;
@@ -75,3 +89,23 @@ def project_umbrella_header : Separate<["-"], "project-umbrella-header">,
MetaVarName<"<path>">, HelpText<"Specify the project umbrella header location">;
def project_umbrella_header_EQ : Joined<["--"], "project-umbrella-header=">,
Alias<project_umbrella_header>;
+
+//
+/// Overidden clang options for different behavior.
+//
+
+// Clang's Xarch does not support options that require arguments.
+// But is supported for InstallAPI generation.
+def Xarch__ : Joined<["-"], "Xarch_">;
+def allowable_client : Separate<["-"], "allowable_client">,
+ HelpText<"Restricts what can link against the dynamic library being created">;
+def rpath: Separate<["-"], "rpath">,
+ HelpText<"Add path to the runpath search path list for the dynamic library being created.">;
+def reexport_l : Joined<["-"], "reexport-l">,
+ HelpText<"Re-export the specified library">;
+def reexport_library : Separate<["-"], "reexport_library">, MetaVarName<"<path>">,
+ HelpText<"Re-export the specified library">;
+def reexport_framework : Separate<["-"], "reexport_framework">,
+ HelpText<"Re-export the specified framework">;
+
+
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index c4f39b7c841742..410740a59c0262 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -7,14 +7,17 @@
//===----------------------------------------------------------------------===//
#include "Options.h"
+#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Driver/Driver.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/InstallAPI/FileList.h"
#include "clang/InstallAPI/HeaderFile.h"
#include "clang/InstallAPI/InstallAPIDiagnostic.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TextAPI/DylibReader.h"
+#include "llvm/TextAPI/TextAPIError.h"
+#include "llvm/TextAPI/TextAPIReader.h"
#include "llvm/TextAPI/TextAPIWriter.h"
using namespace llvm;
@@ -125,6 +128,56 @@ bool Options::processDriverOptions(InputArgList &Args) {
return true;
}
+bool Options::processInstallAPIXOptions(InputArgList &Args) {
+ for (arg_iterator It = Args.begin(), End = Args.end(); It != End; ++It) {
+ if ((*It)->getOption().matches(OPT_Xarch__)) {
+ if (!processXarchOption(Args, It))
+ return false;
+ }
+ }
+ // TODO: Add support for the all of the X* options installapi supports.
+
+ return true;
+}
+
+bool Options::processXarchOption(InputArgList &Args, arg_iterator Curr) {
+ Arg *CurrArg = *Curr;
+ Architecture Arch = getArchitectureFromName(CurrArg->getValue(0));
+ if (Arch == AK_unknown) {
+ Diags->Report(diag::err_drv_invalid_arch_name)
+ << CurrArg->getAsString(Args);
+ return false;
+ }
+
+ auto NextIt = std::next(Curr);
+ if (NextIt == Args.end()) {
+ Diags->Report(diag::err_drv_missing_argument)
+ << CurrArg->getAsString(Args) << 1;
+ return false;
+ }
+
+ // InstallAPI has a limited understanding of supported Xarch options.
+ // Currently this is restricted to linker inputs.
+ const Arg *NextArg = *NextIt;
+ switch (NextArg->getOption().getID()) {
+ case OPT_allowable_client:
+ case OPT_reexport_l:
+ case OPT_reexport_framework:
+ case OPT_reexport_library:
+ case OPT_rpath:
+ break;
+ default:
+ Diags->Report(diag::err_drv_invalid_argument_to_option)
+ << NextArg->getAsString(Args) << CurrArg->getAsString(Args);
+ return false;
+ }
+
+ ArgToArchMap[NextArg] = Arch;
+ CurrArg->claim();
+
+ return true;
+}
+
bool Options::processLinkerOptions(InputArgList &Args) {
// Handle required arguments.
if (const Arg *A = Args.getLastArg(drv::OPT_install__name))
@@ -141,6 +194,12 @@ bool Options::processLinkerOptions(InputArgList &Args) {
if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
LinkerOpts.CompatVersion.parse64(Arg->getValue());
+ if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
+ LinkerOpts.CompatVersion.parse64(Arg->getValue());
+
+ if (auto *Arg = Args.getLastArg(drv::OPT_umbrella))
+ LinkerOpts.ParentUmbrella = Arg->getValue();
+
LinkerOpts.IsDylib = Args.hasArg(drv::OPT_dynamiclib);
LinkerOpts.AppExtensionSafe = Args.hasFlag(
@@ -152,12 +211,24 @@ bool Options::processLinkerOptions(InputArgList &Args) {
if (::getenv("LD_APPLICATION_EXTENSION_SAFE") != nullptr)
LinkerOpts.AppExtensionSafe = true;
+
+ // Capture library paths.
+ PathSeq LibraryPaths;
+ for (const Arg *A : Args.filtered(drv::OPT_L)) {
+ LibraryPaths.emplace_back(A->getValue());
+ A->claim();
+ }
+
+ if (!LibraryPaths.empty())
+ LinkerOpts.LibPaths = std::move(LibraryPaths);
+
return true;
}
+// NOTE: Do not claim any arguments, as they will be passed along for CC1
+// invocations.
bool Options::processFrontendOptions(InputArgList &Args) {
- // Do not claim any arguments, as they will be passed along for CC1
- // invocations.
+ // Capture language mode.
if (auto *A = Args.getLastArgNoClaim(drv::OPT_x)) {
FEOpts.LangMode = llvm::StringSwitch<clang::Language>(A->getValue())
.Case("c", clang::Language::C)
@@ -179,6 +250,54 @@ bool Options::processFrontendOptions(InputArgList &Args) {
FEOpts.LangMode = clang::Language::ObjCXX;
}
+ // Capture Sysroot.
+ if (const Arg *A = Args.getLastArgNoClaim(drv::OPT_isysroot)) {
+ SmallString<PATH_MAX> Path(A->getValue());
+ FM->makeAbsolutePath(Path);
+ if (!FM->getOptionalDirectoryRef(Path)) {
+ Diags->Report(diag::err_missing_sysroot) << Path;
+ return false;
+ }
+ FEOpts.ISysroot = std::string(Path);
+ } else if (FEOpts.ISysroot.empty()) {
+ // Mirror CLANG and obtain the isysroot from the SDKROOT environment
+ // variable, if it wasn't defined by the command line.
+ if (auto *Env = ::getenv("SDKROOT")) {
+ if (StringRef(Env) != "/" && llvm::sys::path::is_absolute(Env) &&
+ FM->getOptionalFileRef(Env))
+ FEOpts.ISysroot = Env;
+ }
+ }
+
+ // Capture system frameworks.
+ // TODO: Support passing framework paths per platform.
+ for (const Arg *A : Args.filtered(drv::OPT_iframework))
+ FEOpts.SystemFwkPaths.emplace_back(A->getValue());
+
+ // Capture framework paths.
+ PathSeq FrameworkPaths;
+ for (const Arg *A : Args.filtered(drv::OPT_F))
+ FrameworkPaths.emplace_back(A->getValue());
+
+ if (!FrameworkPaths.empty())
+ FEOpts.FwkPaths = std::move(FrameworkPaths);
+
+ // Add default framework/library paths.
+ PathSeq DefaultLibraryPaths = {"/usr/lib", "/usr/local/lib"};
+ PathSeq DefaultFrameworkPaths = {"/Library/Frameworks",
+ "/System/Library/Frameworks"};
+
+ for (const StringRef LibPath : DefaultLibraryPaths) {
+ SmallString<PATH_MAX> Path(FEOpts.ISysroot);
+ sys::path::append(Path, LibPath);
+ LinkerOpts.LibPaths.emplace_back(Path.str());
+ }
+ for (const StringRef FwkPath : DefaultFrameworkPaths) {
+ SmallString<PATH_MAX> Path(FEOpts.ISysroot);
+ sys::path::append(Path, FwkPath);
+ FEOpts.SystemFwkPaths.emplace_back(Path.str());
+ }
+
return true;
}
@@ -212,6 +331,9 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
MissingArgCount, Visibility());
// Capture InstallAPI only driver options.
+ if (!processInstallAPIXOptions(ParsedArgs))
+ return {};
+
DriverOpts.Demangle = ParsedArgs.hasArg(OPT_demangle);
if (auto *A = ParsedArgs.getLastArg(OPT_filetype)) {
@@ -244,6 +366,42 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
if (const Arg *A = ParsedArgs.getLastArg(OPT_dsym))
DriverOpts.DSYMPath = A->getValue();
+ DriverOpts.TraceLibraryLocation = ParsedArgs.hasArg(OPT_t);
+
+ // Linker options not handled by clang driver.
+ LinkerOpts.OSLibNotForSharedCache =
+ ParsedArgs.hasArg(OPT_not_for_dyld_shared_cache);
+
+ for (const Arg *A : ParsedArgs.filtered(OPT_allowable_client)) {
+ LinkerOpts.AllowableClients[A->getValue()] =
+ ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
+ A->claim();
+ }
+
+ for (const Arg *A : ParsedArgs.filtered(OPT_reexport_l)) {
+ LinkerOpts.ReexportedLibraries[A->getValue()] =
+ ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
+ A->claim();
+ }
+
+ for (const Arg *A : ParsedArgs.filtered(OPT_reexport_library)) {
+ LinkerOpts.ReexportedLibraryPaths[A->getValue()] =
+ ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
+ A->claim();
+ }
+
+ for (const Arg *A : ParsedArgs.filtered(OPT_reexport_framework)) {
+ LinkerOpts.ReexportedFrameworks[A->getValue()] =
+ ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
+ A->claim();
+ }
+
+ for (const Arg *A : ParsedArgs.filtered(OPT_rpath)) {
+ LinkerOpts.RPaths[A->getValue()] =
+ ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
+ A->claim();
+ }
+
// Handle exclude & extra header directories or files.
auto handleAdditionalInputArgs = [&](PathSeq &Headers,
clang::installapi::ID OptID) {
@@ -324,6 +482,22 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
if (!processFrontendOptions(ArgList))
return;
+ // After all InstallAPI necessary arguments have been collected. Go back and
+ // assign values that were unknown before the clang driver opt table was used.
+ ArchitectureSet AllArchs;
+ llvm::for_each(DriverOpts.Targets,
+ [&AllArchs](const auto &T) { AllArchs.set(T.first.Arch); });
+ auto assignDefaultLibAttrs = [&AllArchs](LibAttrs &Attrs) {
+ for (StringMapEntry<ArchitectureSet> &Entry : Attrs)
+ if (Entry.getValue().empty())
+ Entry.setValue(AllArchs);
+ };
+ assignDefaultLibAttrs(LinkerOpts.AllowableClients);
+ assignDefaultLibAttrs(LinkerOpts.ReexportedFrameworks);
+ assignDefaultLibAttrs(LinkerOpts.ReexportedLibraries);
+ assignDefaultLibAttrs(LinkerOpts.ReexportedLibraryPaths);
+ assignDefaultLibAttrs(LinkerOpts.RPaths);
+
/// Force cc1 options that should always be on.
FrontendArgs = {"-fsyntax-only", "-Wprivate-extern"};
@@ -345,6 +519,89 @@ static StringRef getFrameworkNameFromInstallName(StringRef InstallName) {
return Match.back();
}
+static Expected<std::unique_ptr<InterfaceFile>>
+getInterfaceFile(const StringRef Filename) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ MemoryBuffer::getFile(Filename);
+ if (auto Err = BufferOrErr.getError())
+ return errorCodeToError(std::move(Err));
+
+ auto Buffer = std::move(*BufferOrErr);
+ std::unique_ptr<InterfaceFile> IF;
+ switch (identify_magic(Buffer->getBuffer())) {
+ case file_magic::macho_dynamically_linked_shared_lib:
+ LLVM_FALLTHROUGH;
+ case file_magic::macho_dynamically_linked_shared_lib_stub:
+ LLVM_FALLTHROUGH;
+ case file_magic::macho_universal_binary:
+ return DylibReader::get(Buffer->getMemBufferRef());
+ break;
+ case file_magic::tapi_file:
+ return TextAPIReader::get(Buffer->getMemBufferRef());
+ default:
+ return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
+ "unsupported library file format");
+ }
+ llvm_unreachable("unexpected failure in getInterface");
+}
+
+std::pair<LibAttrs, ReexportedInterfaces> Options::getReexportedLibraries() {
+ LibAttrs Reexports;
+ ReexportedInterfaces ReexportIFs;
+ auto AccumulateReexports = [&](StringRef Path, const ArchitectureSet &Archs) {
+ auto ReexportIFOrErr = getInterfaceFile(Path);
+ if (!ReexportIFOrErr)
+ return false;
+ std::unique_ptr<InterfaceFile> Reexport = std::move(*ReexportIFOrErr);
+ StringRef InstallName = Reexport->getInstallName();
+ assert(!InstallName.empty() && "Parse error for install name");
+ Reexports.insert({InstallName, Archs});
+ ReexportIFs.emplace_back(std::move(*Reexport));
+ return true;
+ };
+
+ // Populate search paths by looking at user paths before system ones.
+ PathSeq FwkSearchPaths(FEOpts.FwkPaths.begin(), FEOpts.FwkPaths.end());
+ // FIXME: System framework paths need to reset if installapi is invoked with
+ // different platforms.
+ FwkSearchPaths.insert(FwkSearchPaths.end(), FEOpts.SystemFwkPaths.begin(),
+ FEOpts.SystemFwkPaths.end());
+
+ for (const StringMapEntry<ArchitectureSet> &Lib :
+ LinkerOpts.ReexportedLibraries) {
+ std::string Name = "lib" + Lib.getKey().str() + ".dylib";
+ std::string Path = findLibrary(Name, *FM, {}, LinkerOpts.LibPaths, {});
+ if (Path.empty()) {
+ Diags->Report(diag::err_cannot_find_reexport) << true << Lib.getKey();
+ return {};
+ }
+ if (DriverOpts.TraceLibraryLocation)
+ errs() << Path << "\n";
+
+ AccumulateReexports(Path, Lib.getValue());
+ }
+
+ for (const StringMapEntry<ArchitectureSet> &Lib :
+ LinkerOpts.ReexportedLibraryPaths)
+ AccumulateReexports(Lib.getKey(), Lib.getValue());
+
+ for (const StringMapEntry<ArchitectureSet> &Lib :
+ LinkerOpts.ReexportedFrameworks) {
+ std::string Name = (Lib.getKey() + ".framework/" + Lib.getKey()).str();
+ std::string Path = findLibrary(Name, *FM, FwkSearchPaths, {}, {});
+ if (Path.empty()) {
+ Diags->Report(diag::err_cannot_find_reexport) << false << Lib.getKey();
+ return {};
+ }
+ if (DriverOpts.TraceLibraryLocation)
+ errs() << Path << "\n";
+
+ AccumulateReexports(Path, Lib.getValue());
+ }
+
+ return {std::move(Reexports), std::move(ReexportIFs)};
+}
+
InstallAPIContext Options::createContext() {
InstallAPIContext Ctx;
Ctx.FM = FM;
@@ -357,10 +614,17 @@ InstallAPIContext Options::createContext() {
Ctx.BA.CurrentVersion = LinkerOpts.CurrentVersion;
Ctx.BA.CompatVersion = LinkerOpts.CompatVersion;
Ctx.BA.AppExtensionSafe = LinkerOpts.AppExtensionSafe;
+ Ctx.BA.ParentUmbrella = LinkerOpts.ParentUmbrella;
+ Ctx.BA.OSLibNotForSharedCache = LinkerOpts.OSLibNotForSharedCache;
Ctx.FT = DriverOpts.OutFT;
Ctx.OutputLoc = DriverOpts.OutputPath;
Ctx.LangMode = FEOpts.LangMode;
+ auto [Reexports, ReexportedIFs] = getReexportedLibraries();
+ if (Diags->hasErrorOccurred())
+ return Ctx;
+ Ctx.Reexports = Reexports;
+
// Attempt to find umbrella headers by capturing framework name.
StringRef FrameworkName;
if (!LinkerOpts.IsDylib)
@@ -520,13 +784,14 @@ InstallAPIContext Options::createContext() {
Expected<Records> Slices =
DylibReader::readFile((*Buffer)->getMemBufferRef(), PO);
if (auto Err = Slices.takeError()) {
- Diags->Report(diag::err_cannot_open_file) << DriverOpts.DylibToVerify;
+ Diags->Report(diag::err_cannot_open_file)
+ << DriverOpts.DylibToVerify << std::move(Err);
return Ctx;
}
Ctx.Verifier = std::make_unique<DylibVerifier>(
- std::move(*Slices), Diags, DriverOpts.VerifyMode, DriverOpts.Demangle,
- DriverOpts.DSYMPath);
+ std::move(*Slices), std::move(ReexportedIFs), Diags,
+ DriverOpts.VerifyMode, DriverOpts.Demangle, DriverOpts.DSYMPath);
return Ctx;
}
diff --git a/clang/tools/clang-installapi/Options.h b/clang/tools/clang-installapi/Options.h
index 82e04b49d12596..8bee7e182137ac 100644
--- a/clang/tools/clang-installapi/Options.h
+++ b/clang/tools/clang-installapi/Options.h
@@ -20,7 +20,6 @@
#include "llvm/Option/Option.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Triple.h"
-#include <set>
#include <string>
#include <vector>
@@ -81,9 +80,30 @@ struct DriverOptions {
/// \brief Print verbose output.
bool Verbose = false;
+
+ /// \brief Log libraries loaded.
+ bool TraceLibraryLocation = false;
};
struct LinkerOptions {
+ /// \brief List of allowable clients to use for the dynamic library.
+ LibAttrs AllowableClients;
+
+ /// \brief List of reexported libraries to use for the dynamic library.
+ LibAttrs ReexportedLibraries;
+
+ /// \brief List of reexported libraries to use for the dynamic library.
+ LibAttrs ReexportedLibraryPaths;
+
+ /// \brief List of reexported frameworks to use for the dynamic library.
+ LibAttrs ReexportedFrameworks;
+
+ /// \brief List of rpaths to use for the dynamic library.
+ LibAttrs RPaths;
+
+ /// \brief Additional library search paths.
+ PathSeq LibPaths;
+
/// \brief The install name to use for the dynamic library.
std::string InstallName;
@@ -93,18 +113,34 @@ struct LinkerOptions {
/// \brief The compatibility version to use for the dynamic library.
PackedVersion CompatVersion;
+ /// \brief Name of the umbrella library.
+ std::string ParentUmbrella;
+
/// \brief Is application extension safe.
bool AppExtensionSafe = false;
/// \brief Set if we should scan for a dynamic library and not a framework.
bool IsDylib = false;
+
+ /// \brief Is an OS library that is not shared cache eligible.
+ bool OSLibNotForSharedCache = false;
};
struct FrontendOptions {
/// \brief The language mode to parse headers in.
Language LangMode = Language::ObjC;
+
+ /// \brief The sysroot to search for SDK headers or libraries.
+ std::string ISysroot;
+
+ /// \brief Additional framework search paths.
+ PathSeq FwkPaths;
+
+ /// \brief Additional SYSTEM framework search paths.
+ PathSeq SystemFwkPaths;
};
+using arg_iterator = llvm::opt::arg_iterator<llvm::opt::Arg **>;
class Options {
private:
bool processDriverOptions(llvm::opt::InputArgList &Args);
@@ -112,6 +148,8 @@ class Options {
bool processFrontendOptions(llvm::opt::InputArgList &Args);
std::vector<const char *>
processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args);
+ bool processInstallAPIXOptions(llvm::opt::InputArgList &Args);
+ bool processXarchOption(llvm::opt::InputArgList &Args, arg_iterator Curr);
public:
/// The various options grouped together.
@@ -136,9 +174,12 @@ class Options {
bool addFilePaths(llvm::opt::InputArgList &Args, PathSeq &Headers,
llvm::opt::OptSpecifier ID);
+ std::pair<LibAttrs, ReexportedInterfaces> getReexportedLibraries();
+
DiagnosticsEngine *Diags;
FileManager *FM;
std::vector<std::string> FrontendArgs;
+ llvm::DenseMap<const llvm::opt::Arg *, Architecture> ArgToArchMap;
};
enum ID {
More information about the cfe-commits
mailing list