Skip to content

Commit 7ef1a80

Browse files
committed
[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.
1 parent 515d3f7 commit 7ef1a80

19 files changed

+2230
-16
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ def warn_drv_darwin_sdk_invalid_settings : Warning<
663663
"SDK settings were ignored as 'SDKSettings.json' could not be parsed">,
664664
InGroup<DiagGroup<"darwin-sdk-settings">>;
665665

666+
def err_missing_sysroot : Error<"no such sysroot directory: '%0'">;
666667
def err_drv_darwin_sdk_missing_arclite : Error<
667668
"SDK does not contain 'libarclite' at the path '%0'; try increasing the minimum deployment target">;
668669

clang/include/clang/Basic/DiagnosticInstallAPIKinds.td

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ def err_no_such_header_file : Error<"no such %select{public|private|project}1 he
1919
def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup<InstallAPIViolation>;
2020
def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup<InstallAPIViolation>;
2121
def err_no_such_umbrella_header_file : Error<"%select{public|private|project}1 umbrella header file not found in input: '%0'">;
22+
def err_cannot_find_reexport : Error<"cannot find re-exported %select{framework|library}0: '%1'">;
2223
} // end of command line category.
2324

2425
let CategoryName = "Verification" in {
26+
// Diagnostics about symbols.
2527
def warn_target: Warning<"violations found for %0">, InGroup<InstallAPIViolation>;
2628
def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
2729
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 "
4345
"%select{weak defined|thread local}1, but its declaration is not">;
4446
def err_header_symbol_flags_mismatch : Error<"declaration '%0' is "
4547
"%select{weak defined|thread local}1, but symbol is not in dynamic library">;
48+
49+
// Diagnostics about load commands.
50+
def err_architecture_mismatch : Error<"architectures do not match: '%0' (provided) vs '%1' (found)">;
51+
def warn_platform_mismatch : Warning<"platform does not match: '%0' (provided) vs '%1' (found)">, InGroup<InstallAPIViolation>;
52+
def err_platform_mismatch : Error<"platform does not match: '%0' (provided) vs '%1' (found)">;
53+
def err_install_name_mismatch : Error<"install_name does not match: '%0' (provided) vs '%1' (found)">;
54+
def err_current_version_mismatch : Error<"current_version does not match: '%0' (provided) vs '%1' (found)">;
55+
def err_compatibility_version_mismatch : Error<"compatibility_version does not match: '%0' (provided) vs '%1' (found)">;
56+
def err_appextension_safe_mismatch : Error<"ApplicationExtensionSafe flag does not match: '%0' (provided) vs '%1' (found)">;
57+
def err_shared_cache_eligiblity_mismatch : Error<"NotForDyldSharedCache flag does not match: '%0' (provided) vs '%1' (found)">;
58+
def err_no_twolevel_namespace : Error<"flat namespace libraries are not supported">;
59+
def err_parent_umbrella_missing: Error<"parent umbrella missing from %0: '%1'">;
60+
def err_parent_umbrella_mismatch : Error<"parent umbrella does not match: '%0' (provided) vs '%1' (found)">;
61+
def err_reexported_libraries_missing : Error<"re-exported library missing from %0: '%1'">;
62+
def err_reexported_libraries_mismatch : Error<"re-exported libraries do not match: '%0' (provided) vs '%1' (found)">;
63+
def err_allowable_clients_missing : Error<"allowable client missing from %0: '%1'">;
64+
def err_allowable_clients_mismatch : Error<"allowable clients do not match: '%0' (provided) vs '%1' (found)">;
65+
def warn_rpaths_missing : Warning<"runpath search paths missing from %0: '%1'">, InGroup<InstallAPIViolation>;
66+
def warn_rpaths_mismatch : Warning<"runpath search paths do not match: '%0' (provided) vs '%1' (found)">, InGroup<InstallAPIViolation>;
4667
} // end of Verification category.
4768

4869
} // end of InstallAPI component

clang/include/clang/InstallAPI/Context.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ struct InstallAPIContext {
2828
/// Library attributes that are typically passed as linker inputs.
2929
BinaryAttrs BA;
3030

31+
/// Install names of reexported libraries of a library.
32+
LibAttrs Reexports;
33+
3134
/// All headers that represent a library.
3235
HeaderSeq InputHeaders;
3336

@@ -80,6 +83,20 @@ struct InstallAPIContext {
8083
llvm::DenseMap<StringRef, HeaderType> KnownIncludes;
8184
};
8285

86+
/// Lookup the dylib or TextAPI file location for a system library or framework.
87+
/// The search paths provided are searched in order.
88+
/// @rpath based libraries are not supported.
89+
///
90+
/// \param InstallName The install name for the library.
91+
/// \param FrameworkSearchPaths Search paths to look up frameworks with.
92+
/// \param LibrarySearchPaths Search paths to look up dylibs with.
93+
/// \param SearchPaths Fallback search paths if library was not found in earlier
94+
/// paths.
95+
/// \return The full path of the library.
96+
std::string findLibrary(StringRef InstallName, FileManager &FM,
97+
ArrayRef<std::string> FrameworkSearchPaths,
98+
ArrayRef<std::string> LibrarySearchPaths,
99+
ArrayRef<std::string> SearchPaths);
83100
} // namespace installapi
84101
} // namespace clang
85102

clang/include/clang/InstallAPI/DylibVerifier.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ enum class VerificationMode {
2424
Pedantic,
2525
};
2626

27+
using LibAttrs = llvm::StringMap<ArchitectureSet>;
28+
using ReexportedInterfaces = llvm::SmallVector<llvm::MachO::InterfaceFile, 8>;
29+
2730
/// Service responsible to tracking state of verification across the
2831
/// lifetime of InstallAPI.
2932
/// As declarations are collected during AST traversal, they are
@@ -63,11 +66,12 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
6366

6467
DylibVerifier() = default;
6568

66-
DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag,
67-
VerificationMode Mode, bool Demangle, StringRef DSYMPath)
68-
: Dylib(std::move(Dylib)), Mode(Mode), Demangle(Demangle),
69-
DSYMPath(DSYMPath), Exports(std::make_unique<SymbolSet>()),
70-
Ctx(VerifierContext{Diag}) {}
69+
DylibVerifier(llvm::MachO::Records &&Dylib, ReexportedInterfaces &&Reexports,
70+
DiagnosticsEngine *Diag, VerificationMode Mode, bool Demangle,
71+
StringRef DSYMPath)
72+
: Dylib(std::move(Dylib)), Reexports(std::move(Reexports)), Mode(Mode),
73+
Demangle(Demangle), DSYMPath(DSYMPath),
74+
Exports(std::make_unique<SymbolSet>()), Ctx(VerifierContext{Diag}) {}
7175

7276
Result verify(GlobalRecord *R, const FrontendAttrs *FA);
7377
Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA);
@@ -77,6 +81,14 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
7781
// Scan through dylib slices and report any remaining missing exports.
7882
Result verifyRemainingSymbols();
7983

84+
/// Compare and report the attributes represented as
85+
/// load commands in the dylib to the attributes provided via options.
86+
bool verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,
87+
const BinaryAttrs &ProvidedBA,
88+
const LibAttrs &ProvidedReexports,
89+
const LibAttrs &ProvidedClients,
90+
const LibAttrs &ProvidedRPaths, const FileType &FT);
91+
8092
/// Initialize target for verification.
8193
void setTarget(const Target &T);
8294

@@ -105,6 +117,10 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
105117
bool shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
106118
const Record *DR);
107119

120+
/// Check if declaration is exported from a reexported library. These
121+
/// symbols should be omitted from the text-api file.
122+
bool shouldIgnoreReexport(const Record *R, SymbolContext &SymCtx) const;
123+
108124
/// Compare the visibility declarations to the linkage of symbol found in
109125
/// dylib.
110126
Result compareVisibility(const Record *R, SymbolContext &SymCtx,
@@ -154,6 +170,9 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
154170
// Symbols in dylib.
155171
llvm::MachO::Records Dylib;
156172

173+
// Reexported interfaces apart of the library.
174+
ReexportedInterfaces Reexports;
175+
157176
// Controls what class of violations to report.
158177
VerificationMode Mode = VerificationMode::Invalid;
159178

clang/include/clang/InstallAPI/MachO.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "llvm/TextAPI/TextAPIWriter.h"
2424
#include "llvm/TextAPI/Utils.h"
2525

26+
using Architecture = llvm::MachO::Architecture;
27+
using ArchitectureSet = llvm::MachO::ArchitectureSet;
2628
using SymbolFlags = llvm::MachO::SymbolFlags;
2729
using RecordLinkage = llvm::MachO::RecordLinkage;
2830
using Record = llvm::MachO::Record;

clang/lib/InstallAPI/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
77
)
88

99
add_clang_library(clangInstallAPI
10+
DiagnosticBuilderWrappers.cpp
1011
DylibVerifier.cpp
1112
FileList.cpp
1213
Frontend.cpp
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//===- DiagnosticBuilderWrappers.cpp ----------------------------*- C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "DiagnosticBuilderWrappers.h"
10+
#include "llvm/ADT/SmallString.h"
11+
#include "llvm/Support/raw_ostream.h"
12+
#include "llvm/TextAPI/Platform.h"
13+
14+
using clang::DiagnosticBuilder;
15+
16+
namespace llvm {
17+
namespace MachO {
18+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
19+
const Architecture &Arch) {
20+
DB.AddString(getArchitectureName(Arch));
21+
return DB;
22+
}
23+
24+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
25+
const ArchitectureSet &ArchSet) {
26+
DB.AddString(std::string(ArchSet));
27+
return DB;
28+
}
29+
30+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
31+
const PlatformType &Platform) {
32+
DB.AddString(getPlatformName(Platform));
33+
return DB;
34+
}
35+
36+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
37+
const PlatformVersionSet &Platforms) {
38+
std::string PlatformAsString;
39+
raw_string_ostream Stream(PlatformAsString);
40+
41+
Stream << "[ ";
42+
bool NeedsComma = false;
43+
for (auto &[Platform, Version] : Platforms) {
44+
if (NeedsComma)
45+
Stream << ", ";
46+
else
47+
NeedsComma = true;
48+
Stream << getPlatformName(Platform);
49+
if (!Version.empty())
50+
Stream << Version.getAsString();
51+
}
52+
Stream << " ]";
53+
DB.AddString(Stream.str());
54+
return DB;
55+
}
56+
57+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
58+
const FileType &Type) {
59+
switch (Type) {
60+
case FileType::MachO_Bundle:
61+
DB.AddString("mach-o bundle");
62+
return DB;
63+
case FileType::MachO_DynamicLibrary:
64+
DB.AddString("mach-o dynamic library");
65+
return DB;
66+
case FileType::MachO_DynamicLibrary_Stub:
67+
DB.AddString("mach-o dynamic library stub");
68+
return DB;
69+
case FileType::TBD_V1:
70+
DB.AddString("tbd-v1");
71+
return DB;
72+
case FileType::TBD_V2:
73+
DB.AddString("tbd-v2");
74+
return DB;
75+
case FileType::TBD_V3:
76+
DB.AddString("tbd-v3");
77+
return DB;
78+
case FileType::TBD_V4:
79+
DB.AddString("tbd-v4");
80+
return DB;
81+
case FileType::TBD_V5:
82+
DB.AddString("tbd-v5");
83+
return DB;
84+
case FileType::Invalid:
85+
case FileType::All:
86+
llvm_unreachable("Unexpected file type for diagnostics.");
87+
}
88+
}
89+
90+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
91+
const PackedVersion &Version) {
92+
std::string VersionString;
93+
raw_string_ostream OS(VersionString);
94+
OS << Version;
95+
DB.AddString(OS.str());
96+
return DB;
97+
}
98+
99+
const clang::DiagnosticBuilder &
100+
operator<<(const clang::DiagnosticBuilder &DB,
101+
const StringMapEntry<ArchitectureSet> &LibAttr) {
102+
std::string IFAsString;
103+
raw_string_ostream OS(IFAsString);
104+
105+
OS << LibAttr.getKey() << " [ " << LibAttr.getValue() << " ]";
106+
DB.AddString(OS.str());
107+
return DB;
108+
}
109+
110+
} // namespace MachO
111+
} // namespace llvm
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===- DiagnosticBuilderWrappers.h -----------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
/// Diagnostic wrappers for TextAPI types for error reporting.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H
14+
#define LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H
15+
16+
#include "clang/Basic/Diagnostic.h"
17+
#include "llvm/TextAPI/Architecture.h"
18+
#include "llvm/TextAPI/ArchitectureSet.h"
19+
#include "llvm/TextAPI/InterfaceFile.h"
20+
#include "llvm/TextAPI/Platform.h"
21+
22+
namespace llvm {
23+
namespace MachO {
24+
25+
const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
26+
const PlatformType &Platform);
27+
28+
const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
29+
const PlatformVersionSet &Platforms);
30+
31+
const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
32+
const Architecture &Arch);
33+
34+
const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
35+
const ArchitectureSet &ArchSet);
36+
37+
const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
38+
const FileType &Type);
39+
40+
const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB,
41+
const PackedVersion &Version);
42+
43+
const clang::DiagnosticBuilder &
44+
operator<<(const clang::DiagnosticBuilder &DB,
45+
const StringMapEntry<ArchitectureSet> &LibAttr);
46+
47+
} // namespace MachO
48+
} // namespace llvm
49+
#endif // LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H

0 commit comments

Comments
 (0)