Merge abi diffs, improve linking performance.
Bug: 38325544 Test: As shown by out/build.trace.gz when using built header-abi-linker to link .sdump files produced by header-abi-linker. Without fix: Time taken to produce libc.so.lsdump by header-abi-linker => ~51 sec With fix: Time taken to produce libc.so.lsdump by header-abi-linker => ~3 sec Bug: 38325929 Test: merged abiff reports of libjpeg, libc. Change-Id: Iae54f4754d8b0407fabdb8bc8550a7f7b3479f8f
This commit is contained in:
@@ -212,6 +212,38 @@ cc_binary_host {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cc_binary_host {
|
||||||
|
name: "merge-abi-diff",
|
||||||
|
|
||||||
|
defaults: [
|
||||||
|
"header-checker-defaults",
|
||||||
|
"header-abi-linker-lib-defaults",
|
||||||
|
],
|
||||||
|
|
||||||
|
srcs: [
|
||||||
|
"merge-abi-diff/src/*.cpp",
|
||||||
|
],
|
||||||
|
|
||||||
|
static_libs: [
|
||||||
|
"libheader-checker-proto",
|
||||||
|
],
|
||||||
|
|
||||||
|
target: {
|
||||||
|
linux: {
|
||||||
|
host_ldlibs: [
|
||||||
|
"-ldl",
|
||||||
|
"-lpthread",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
darwin: {
|
||||||
|
host_ldlibs: [
|
||||||
|
"-ldl",
|
||||||
|
"-lpthread",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
cc_library_static {
|
cc_library_static {
|
||||||
name: "libheader-abi-util",
|
name: "libheader-abi-util",
|
||||||
defaults: [
|
defaults: [
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
Status HeaderAbiDiff::GenerateCompatibilityReport() {
|
CompatibilityStatus HeaderAbiDiff::GenerateCompatibilityReport() {
|
||||||
abi_dump::TranslationUnit old_tu;
|
abi_dump::TranslationUnit old_tu;
|
||||||
abi_dump::TranslationUnit new_tu;
|
abi_dump::TranslationUnit new_tu;
|
||||||
std::ifstream old_input(old_dump_);
|
std::ifstream old_input(old_dump_);
|
||||||
@@ -37,41 +37,51 @@ Status HeaderAbiDiff::GenerateCompatibilityReport() {
|
|||||||
|
|
||||||
if (!google::protobuf::TextFormat::Parse(&text_iso, &old_tu) ||
|
if (!google::protobuf::TextFormat::Parse(&text_iso, &old_tu) ||
|
||||||
!google::protobuf::TextFormat::Parse(&text_isn, &new_tu)) {
|
!google::protobuf::TextFormat::Parse(&text_isn, &new_tu)) {
|
||||||
llvm::errs() << "Failed to Parse Input\n";
|
llvm::errs() << "Failed to generate compatibility report\n";
|
||||||
::exit(1);
|
::exit(1);
|
||||||
}
|
}
|
||||||
return CompareTUs(old_tu, new_tu);
|
return CompareTUs(old_tu, new_tu);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status HeaderAbiDiff::CompareTUs(const abi_dump::TranslationUnit &old_tu,
|
CompatibilityStatus HeaderAbiDiff::CompareTUs(
|
||||||
|
const abi_dump::TranslationUnit &old_tu,
|
||||||
const abi_dump::TranslationUnit &new_tu) {
|
const abi_dump::TranslationUnit &new_tu) {
|
||||||
std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu(
|
std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu(
|
||||||
new abi_diff::TranslationUnitDiff);
|
new abi_diff::TranslationUnitDiff);
|
||||||
|
CompatibilityStatus record_status = Collect<abi_dump::RecordDecl>(
|
||||||
Status record_status = Collect<abi_dump::RecordDecl>(
|
|
||||||
diff_tu->mutable_records_added(), diff_tu->mutable_records_removed(),
|
diff_tu->mutable_records_added(), diff_tu->mutable_records_removed(),
|
||||||
diff_tu->mutable_records_diff(), old_tu.records(), new_tu.records(),
|
diff_tu->mutable_records_diff(), old_tu.records(), new_tu.records(),
|
||||||
ignored_symbols_);
|
ignored_symbols_);
|
||||||
|
|
||||||
Status function_status = Collect<abi_dump::FunctionDecl>(
|
CompatibilityStatus function_status = Collect<abi_dump::FunctionDecl>(
|
||||||
diff_tu->mutable_functions_added(), diff_tu->mutable_functions_removed(),
|
diff_tu->mutable_functions_added(), diff_tu->mutable_functions_removed(),
|
||||||
diff_tu->mutable_functions_diff(), old_tu.functions(),
|
diff_tu->mutable_functions_diff(), old_tu.functions(),
|
||||||
new_tu.functions(), ignored_symbols_);
|
new_tu.functions(), ignored_symbols_);
|
||||||
|
|
||||||
Status enum_status = Collect<abi_dump::EnumDecl>(
|
CompatibilityStatus enum_status = Collect<abi_dump::EnumDecl>(
|
||||||
diff_tu->mutable_enums_added(), diff_tu->mutable_enums_removed(),
|
diff_tu->mutable_enums_added(), diff_tu->mutable_enums_removed(),
|
||||||
diff_tu->mutable_enums_diff(), old_tu.enums(), new_tu.enums(),
|
diff_tu->mutable_enums_diff(), old_tu.enums(), new_tu.enums(),
|
||||||
ignored_symbols_);
|
ignored_symbols_);
|
||||||
|
|
||||||
Status global_var_status = Collect<abi_dump::GlobalVarDecl>(
|
CompatibilityStatus global_var_status = Collect<abi_dump::GlobalVarDecl>(
|
||||||
diff_tu->mutable_global_vars_added(),
|
diff_tu->mutable_global_vars_added(),
|
||||||
diff_tu->mutable_global_vars_removed(),
|
diff_tu->mutable_global_vars_removed(),
|
||||||
diff_tu->mutable_global_vars_diff(), old_tu.global_vars(),
|
diff_tu->mutable_global_vars_diff(), old_tu.global_vars(),
|
||||||
new_tu.global_vars(), ignored_symbols_);
|
new_tu.global_vars(), ignored_symbols_);
|
||||||
|
|
||||||
Status combined_status =
|
CompatibilityStatus combined_status =
|
||||||
record_status | function_status | enum_status | global_var_status;
|
record_status | function_status | enum_status | global_var_status;
|
||||||
|
|
||||||
|
if (combined_status & CompatibilityStatus::INCOMPATIBLE) {
|
||||||
|
combined_status = CompatibilityStatus::INCOMPATIBLE;
|
||||||
|
} else if (combined_status & CompatibilityStatus::EXTENSION) {
|
||||||
|
combined_status = CompatibilityStatus::EXTENSION;
|
||||||
|
} else {
|
||||||
|
combined_status = CompatibilityStatus::COMPATIBLE;
|
||||||
|
}
|
||||||
|
diff_tu->set_compatibility_status(combined_status);
|
||||||
|
diff_tu->set_lib_name(lib_name_);
|
||||||
|
diff_tu->set_arch(arch_);
|
||||||
std::ofstream text_output(cr_);
|
std::ofstream text_output(cr_);
|
||||||
google::protobuf::io::OstreamOutputStream text_os(&text_output);
|
google::protobuf::io::OstreamOutputStream text_os(&text_output);
|
||||||
|
|
||||||
@@ -79,17 +89,11 @@ Status HeaderAbiDiff::CompareTUs(const abi_dump::TranslationUnit &old_tu,
|
|||||||
llvm::errs() << "Unable to dump report\n";
|
llvm::errs() << "Unable to dump report\n";
|
||||||
::exit(1);
|
::exit(1);
|
||||||
}
|
}
|
||||||
if (combined_status & INCOMPATIBLE) {
|
return combined_status;
|
||||||
return INCOMPATIBLE;
|
|
||||||
}
|
|
||||||
if (combined_status & EXTENSION) {
|
|
||||||
return EXTENSION;
|
|
||||||
}
|
|
||||||
return COMPATIBLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename TDiff>
|
template <typename T, typename TDiff>
|
||||||
Status HeaderAbiDiff::Collect(
|
abi_diff::CompatibilityStatus HeaderAbiDiff::Collect(
|
||||||
google::protobuf::RepeatedPtrField<T> *elements_added,
|
google::protobuf::RepeatedPtrField<T> *elements_added,
|
||||||
google::protobuf::RepeatedPtrField<T> *elements_removed,
|
google::protobuf::RepeatedPtrField<T> *elements_removed,
|
||||||
google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
|
google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
|
||||||
@@ -115,12 +119,12 @@ Status HeaderAbiDiff::Collect(
|
|||||||
::exit(1);
|
::exit(1);
|
||||||
}
|
}
|
||||||
if (elements_diff->size() || elements_removed->size()) {
|
if (elements_diff->size() || elements_removed->size()) {
|
||||||
return INCOMPATIBLE;
|
return CompatibilityStatus::INCOMPATIBLE;
|
||||||
}
|
}
|
||||||
if (elements_added->size()) {
|
if (elements_added->size()) {
|
||||||
return EXTENSION;
|
return CompatibilityStatus::EXTENSION;
|
||||||
}
|
}
|
||||||
return COMPATIBLE;
|
return CompatibilityStatus::COMPATIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@@ -28,29 +28,26 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
typedef abi_diff::CompatibilityStatus CompatibilityStatus;
|
||||||
|
|
||||||
class HeaderAbiDiff {
|
class HeaderAbiDiff {
|
||||||
public:
|
public:
|
||||||
enum Status {
|
HeaderAbiDiff(const std::string &lib_name, const std::string &arch,
|
||||||
COMPATIBLE = 1 << 0,
|
const std::string &old_dump, const std::string &new_dump,
|
||||||
EXTENSION = 1 << 1,
|
|
||||||
INCOMPATIBLE = 1 << 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
HeaderAbiDiff(const std::string &old_dump, const std::string &new_dump,
|
|
||||||
const std::string &compatibility_report,
|
const std::string &compatibility_report,
|
||||||
const std::set<std::string> &ignored_symbols)
|
const std::set<std::string> &ignored_symbols)
|
||||||
: old_dump_(old_dump), new_dump_(new_dump), cr_(compatibility_report),
|
: lib_name_(lib_name), arch_(arch), old_dump_(old_dump),
|
||||||
|
new_dump_(new_dump), cr_(compatibility_report),
|
||||||
ignored_symbols_(ignored_symbols) { }
|
ignored_symbols_(ignored_symbols) { }
|
||||||
|
|
||||||
Status GenerateCompatibilityReport();
|
CompatibilityStatus GenerateCompatibilityReport();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Status CompareTUs(const abi_dump::TranslationUnit &old_tu,
|
CompatibilityStatus CompareTUs(const abi_dump::TranslationUnit &old_tu,
|
||||||
const abi_dump::TranslationUnit &new_tu);
|
const abi_dump::TranslationUnit &new_tu);
|
||||||
// Collect* methods fill in the diff_tu.
|
// Collect* methods fill in the diff_tu.
|
||||||
template <typename T, typename TDiff>
|
template <typename T, typename TDiff>
|
||||||
static Status Collect(
|
static CompatibilityStatus Collect(
|
||||||
google::protobuf::RepeatedPtrField<T> *elements_added,
|
google::protobuf::RepeatedPtrField<T> *elements_added,
|
||||||
google::protobuf::RepeatedPtrField<T> *elements_removed,
|
google::protobuf::RepeatedPtrField<T> *elements_removed,
|
||||||
google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
|
google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
|
||||||
@@ -88,14 +85,14 @@ class HeaderAbiDiff {
|
|||||||
const std::set<std::string> &ignored_symbols);
|
const std::set<std::string> &ignored_symbols);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const std::string &lib_name_;
|
||||||
|
const std::string &arch_;
|
||||||
const std::string &old_dump_;
|
const std::string &old_dump_;
|
||||||
const std::string &new_dump_;
|
const std::string &new_dump_;
|
||||||
const std::string &cr_;
|
const std::string &cr_;
|
||||||
const std::set<std::string> &ignored_symbols_;
|
const std::set<std::string> &ignored_symbols_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef HeaderAbiDiff::Status Status;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void HeaderAbiDiff::AddToMap(
|
inline void HeaderAbiDiff::AddToMap(
|
||||||
std::map<std::string, const T *> *dst,
|
std::map<std::string, const T *> *dst,
|
||||||
@@ -105,14 +102,16 @@ inline void HeaderAbiDiff::AddToMap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Status operator|(Status f, Status s) {
|
static inline CompatibilityStatus operator|(CompatibilityStatus f,
|
||||||
return static_cast<Status>(
|
CompatibilityStatus s) {
|
||||||
static_cast<std::underlying_type<Status>::type>(f) |
|
return static_cast<CompatibilityStatus>(
|
||||||
static_cast<std::underlying_type<Status>::type>(s));
|
static_cast<std::underlying_type<CompatibilityStatus>::type>(f) |
|
||||||
|
static_cast<std::underlying_type<CompatibilityStatus>::type>(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Status operator&(Status f, Status s) {
|
static inline CompatibilityStatus operator&(
|
||||||
return static_cast<Status>(
|
CompatibilityStatus f, CompatibilityStatus s) {
|
||||||
static_cast<std::underlying_type<Status>::type>(f) &
|
return static_cast<CompatibilityStatus>(
|
||||||
static_cast<std::underlying_type<Status>::type>(s));
|
static_cast<std::underlying_type<CompatibilityStatus>::type>(f) &
|
||||||
|
static_cast<std::underlying_type<CompatibilityStatus>::type>(s));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
|
|||||||
google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *fdiffs =
|
google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *fdiffs =
|
||||||
enum_diff->mutable_field_diffs();
|
enum_diff->mutable_field_diffs();
|
||||||
assert(fdiffs != nullptr);
|
assert(fdiffs != nullptr);
|
||||||
|
enum_diff->set_name(oldp_->basic_abi().name());
|
||||||
if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) ||
|
if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) ||
|
||||||
DiffBasicNamedAndTypedDecl(
|
DiffBasicNamedAndTypedDecl(
|
||||||
enum_diff->mutable_type_diff()->mutable_old(),
|
enum_diff->mutable_type_diff()->mutable_old(),
|
||||||
|
|||||||
@@ -25,6 +25,14 @@ static llvm::cl::opt<std::string> compatibility_report(
|
|||||||
"o", llvm::cl::desc("<compatibility report>"), llvm::cl::Required,
|
"o", llvm::cl::desc("<compatibility report>"), llvm::cl::Required,
|
||||||
llvm::cl::cat(header_checker_category));
|
llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
|
static llvm::cl::opt<std::string> lib_name(
|
||||||
|
"lib", llvm::cl::desc("<lib name>"), llvm::cl::Required,
|
||||||
|
llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
|
static llvm::cl::opt<std::string> arch(
|
||||||
|
"arch", llvm::cl::desc("<arch>"), llvm::cl::Required,
|
||||||
|
llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
static llvm::cl::opt<std::string> new_dump(
|
static llvm::cl::opt<std::string> new_dump(
|
||||||
"new", llvm::cl::desc("<new dump>"), llvm::cl::Required,
|
"new", llvm::cl::desc("<new dump>"), llvm::cl::Required,
|
||||||
llvm::cl::cat(header_checker_category));
|
llvm::cl::cat(header_checker_category));
|
||||||
@@ -33,13 +41,18 @@ static llvm::cl::opt<std::string> old_dump(
|
|||||||
"old", llvm::cl::desc("<old dump>"), llvm::cl::Required,
|
"old", llvm::cl::desc("<old dump>"), llvm::cl::Required,
|
||||||
llvm::cl::cat(header_checker_category));
|
llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
|
static llvm::cl::opt<std::string> ignore_symbol_list(
|
||||||
|
"ignore-symbols", llvm::cl::desc("ignore symbols"), llvm::cl::Optional,
|
||||||
|
llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
static llvm::cl::opt<bool> advice_only(
|
static llvm::cl::opt<bool> advice_only(
|
||||||
"advice-only", llvm::cl::desc("Advisory mode only"), llvm::cl::Optional,
|
"advice-only", llvm::cl::desc("Advisory mode only"), llvm::cl::Optional,
|
||||||
llvm::cl::cat(header_checker_category));
|
llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
static llvm::cl::opt<std::string> ignore_symbol_list(
|
static llvm::cl::opt<bool> allow_extensions(
|
||||||
"ignore-symbols", llvm::cl::desc("ignore symbols"), llvm::cl::Optional,
|
"allow-extensions",
|
||||||
llvm::cl::cat(header_checker_category));
|
llvm::cl::desc("Do not return a non zero status on extensions"),
|
||||||
|
llvm::cl::Optional, llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
static std::set<std::string> LoadIgnoredSymbols(std::string &symbol_list_path) {
|
static std::set<std::string> LoadIgnoredSymbols(std::string &symbol_list_path) {
|
||||||
std::ifstream symbol_ifstream(symbol_list_path);
|
std::ifstream symbol_ifstream(symbol_list_path);
|
||||||
@@ -58,32 +71,21 @@ static std::set<std::string> LoadIgnoredSymbols(std::string &symbol_list_path) {
|
|||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||||
llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");
|
llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");
|
||||||
uint8_t extension_or_incompatible = 0;
|
|
||||||
std::set<std::string> ignored_symbols;
|
std::set<std::string> ignored_symbols;
|
||||||
if (llvm::sys::fs::exists(ignore_symbol_list)) {
|
if (llvm::sys::fs::exists(ignore_symbol_list)) {
|
||||||
ignored_symbols = LoadIgnoredSymbols(ignore_symbol_list);
|
ignored_symbols = LoadIgnoredSymbols(ignore_symbol_list);
|
||||||
}
|
}
|
||||||
HeaderAbiDiff judge(old_dump, new_dump, compatibility_report,
|
HeaderAbiDiff judge(lib_name, arch, old_dump, new_dump, compatibility_report,
|
||||||
ignored_symbols);
|
ignored_symbols);
|
||||||
switch (judge.GenerateCompatibilityReport()) {
|
|
||||||
case HeaderAbiDiff::COMPATIBLE:
|
CompatibilityStatus status = judge.GenerateCompatibilityReport();
|
||||||
break;
|
|
||||||
case HeaderAbiDiff::EXTENSION:
|
if (advice_only) {
|
||||||
extension_or_incompatible = 1;
|
return CompatibilityStatus::COMPATIBLE;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
extension_or_incompatible = 2;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (extension_or_incompatible) {
|
|
||||||
llvm::errs() << "******************************************************\n"
|
if (allow_extensions && status == CompatibilityStatus::EXTENSION) {
|
||||||
<< "VNDK Abi Compliance breakage:"
|
return CompatibilityStatus::COMPATIBLE;
|
||||||
<< " Please check compatiblity report at : "
|
|
||||||
<< compatibility_report << "\n"
|
|
||||||
<< "*****************************************************\n";
|
|
||||||
if (!advice_only) {
|
|
||||||
return extension_or_incompatible;
|
|
||||||
}
|
}
|
||||||
}
|
return status;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ class HeaderAbiLinker {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool LinkDecl(google::protobuf::RepeatedPtrField<T> *dst,
|
inline bool LinkDecl(google::protobuf::RepeatedPtrField<T> *dst,
|
||||||
std::set<std::string> *link_set,
|
std::set<std::string> *link_set,
|
||||||
|
std::set<std::string> *regex_matched_link_set,
|
||||||
|
const std::regex *vs_regex,
|
||||||
const google::protobuf::RepeatedPtrField<T> &src,
|
const google::protobuf::RepeatedPtrField<T> &src,
|
||||||
bool use_version_script);
|
bool use_version_script);
|
||||||
|
|
||||||
@@ -104,13 +106,18 @@ class HeaderAbiLinker {
|
|||||||
const std::string &out_dump_name_;
|
const std::string &out_dump_name_;
|
||||||
const std::string &arch_;
|
const std::string &arch_;
|
||||||
const std::string &api_;
|
const std::string &api_;
|
||||||
|
// TODO: Add to a map of std::sets instead.
|
||||||
std::set<std::string> exported_headers_;
|
std::set<std::string> exported_headers_;
|
||||||
std::set<std::string> record_decl_set_;
|
std::set<std::string> record_decl_set_;
|
||||||
std::set<std::string> function_decl_set_;
|
std::set<std::string> function_decl_set_;
|
||||||
std::set<std::string> enum_decl_set_;
|
std::set<std::string> enum_decl_set_;
|
||||||
std::set<std::string> globvar_decl_set_;
|
std::set<std::string> globvar_decl_set_;
|
||||||
// Version Script regex matched link set.
|
// Version Script Regex Matching.
|
||||||
std::set<std::string> vs_regex_matched_link_set_;
|
std::set<std::string> functions_regex_matched_set;
|
||||||
|
std::regex functions_vs_regex_;
|
||||||
|
// Version Script Regex Matching.
|
||||||
|
std::set<std::string> globvars_regex_matched_set;
|
||||||
|
std::regex globvars_vs_regex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HeaderAbiLinker::LinkAndDump() {
|
bool HeaderAbiLinker::LinkAndDump() {
|
||||||
@@ -164,32 +171,44 @@ static std::string GetSymbol(const abi_dump::GlobalVarDecl &element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool QueryRegexMatches(std::set<std::string> *regex_matched_link_set,
|
static bool QueryRegexMatches(std::set<std::string> *regex_matched_link_set,
|
||||||
const std::set<std::string> &link_set,
|
const std::regex *vs_regex,
|
||||||
const std::string &symbol) {
|
const std::string &symbol) {
|
||||||
|
assert(regex_matched_link_set != nullptr);
|
||||||
|
assert(vs_regex != nullptr);
|
||||||
if (regex_matched_link_set->find(symbol) != regex_matched_link_set->end()) {
|
if (regex_matched_link_set->find(symbol) != regex_matched_link_set->end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Go through each element in link_set, if there is a regex match, add the
|
if (std::regex_search(symbol, *vs_regex)) {
|
||||||
// symbol to regex_matched_link_set and return true;
|
|
||||||
for (auto &®ex_match_str : link_set) {
|
|
||||||
std::smatch matcher;
|
|
||||||
std::string regex_match_str_find_glob =
|
|
||||||
abi_util::FindAndReplace(regex_match_str, "\\*", ".*");
|
|
||||||
std::regex match_clause("\\b" + regex_match_str_find_glob + "\\b");
|
|
||||||
if (std::regex_search(symbol, matcher, match_clause)) {
|
|
||||||
regex_matched_link_set->insert(symbol);
|
regex_matched_link_set->insert(symbol);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::regex CreateRegexMatchExprFromSet(
|
||||||
|
const std::set<std::string> &link_set) {
|
||||||
|
std::string all_regex_match_str = "";
|
||||||
|
std::set<std::string>::iterator it = link_set.begin();
|
||||||
|
while (it != link_set.end()) {
|
||||||
|
std::string regex_match_str_find_glob =
|
||||||
|
abi_util::FindAndReplace(*it, "\\*", ".*");
|
||||||
|
all_regex_match_str += "(\\b" + regex_match_str_find_glob + "\\b)";
|
||||||
|
if (++it != link_set.end()) {
|
||||||
|
all_regex_match_str += "|";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_regex_match_str == "") {
|
||||||
|
return std::regex();
|
||||||
|
}
|
||||||
|
return std::regex(all_regex_match_str);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool HeaderAbiLinker::LinkDecl(
|
inline bool HeaderAbiLinker::LinkDecl(
|
||||||
google::protobuf::RepeatedPtrField<T> *dst,
|
google::protobuf::RepeatedPtrField<T> *dst,
|
||||||
std::set<std::string> *link_set,
|
std::set<std::string> *link_set,
|
||||||
const google::protobuf::RepeatedPtrField<T> &src,
|
std::set<std::string> *regex_matched_link_set, const std::regex *vs_regex,
|
||||||
bool use_version_script) {
|
const google::protobuf::RepeatedPtrField<T> &src, bool use_version_script) {
|
||||||
assert(dst != nullptr);
|
assert(dst != nullptr);
|
||||||
assert(link_set != nullptr);
|
assert(link_set != nullptr);
|
||||||
for (auto &&element : src) {
|
for (auto &&element : src) {
|
||||||
@@ -210,8 +229,7 @@ inline bool HeaderAbiLinker::LinkDecl(
|
|||||||
std::set<std::string>::iterator it =
|
std::set<std::string>::iterator it =
|
||||||
link_set->find(element_str);
|
link_set->find(element_str);
|
||||||
if (it == link_set->end()) {
|
if (it == link_set->end()) {
|
||||||
if (!QueryRegexMatches(&vs_regex_matched_link_set_, *link_set,
|
if (!QueryRegexMatches(regex_matched_link_set, vs_regex, element_str)) {
|
||||||
element_str)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -234,14 +252,15 @@ bool HeaderAbiLinker::LinkRecords(const abi_dump::TranslationUnit &dump_tu,
|
|||||||
assert(linked_tu != nullptr);
|
assert(linked_tu != nullptr);
|
||||||
// Even if version scripts are available we take in records, since the symbols
|
// Even if version scripts are available we take in records, since the symbols
|
||||||
// in the version script might reference a record exposed by the library.
|
// in the version script might reference a record exposed by the library.
|
||||||
return LinkDecl(linked_tu->mutable_records(), &record_decl_set_,
|
return LinkDecl(linked_tu->mutable_records(), &record_decl_set_, nullptr,
|
||||||
dump_tu.records(), false);
|
nullptr, dump_tu.records(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeaderAbiLinker::LinkFunctions(const abi_dump::TranslationUnit &dump_tu,
|
bool HeaderAbiLinker::LinkFunctions(const abi_dump::TranslationUnit &dump_tu,
|
||||||
abi_dump::TranslationUnit *linked_tu) {
|
abi_dump::TranslationUnit *linked_tu) {
|
||||||
assert(linked_tu != nullptr);
|
assert(linked_tu != nullptr);
|
||||||
return LinkDecl(linked_tu->mutable_functions(), &function_decl_set_,
|
return LinkDecl(linked_tu->mutable_functions(), &function_decl_set_,
|
||||||
|
&functions_regex_matched_set, &functions_vs_regex_,
|
||||||
dump_tu.functions(), (!version_script_.empty()));
|
dump_tu.functions(), (!version_script_.empty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,14 +269,15 @@ bool HeaderAbiLinker::LinkEnums(const abi_dump::TranslationUnit &dump_tu,
|
|||||||
assert(linked_tu != nullptr);
|
assert(linked_tu != nullptr);
|
||||||
// Even if version scripts are available we take in records, since the symbols
|
// Even if version scripts are available we take in records, since the symbols
|
||||||
// in the version script might reference an enum exposed by the library.
|
// in the version script might reference an enum exposed by the library.
|
||||||
return LinkDecl(linked_tu->mutable_enums(), &enum_decl_set_,
|
return LinkDecl(linked_tu->mutable_enums(), &enum_decl_set_, nullptr,
|
||||||
dump_tu.enums(), false);
|
nullptr, dump_tu.enums(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeaderAbiLinker::LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
|
bool HeaderAbiLinker::LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
|
||||||
abi_dump::TranslationUnit *linked_tu) {
|
abi_dump::TranslationUnit *linked_tu) {
|
||||||
assert(linked_tu != nullptr);
|
assert(linked_tu != nullptr);
|
||||||
return LinkDecl(linked_tu->mutable_global_vars(), &globvar_decl_set_,
|
return LinkDecl(linked_tu->mutable_global_vars(), &globvar_decl_set_,
|
||||||
|
&globvars_regex_matched_set, &globvars_vs_regex_,
|
||||||
dump_tu.global_vars(), (!version_script.empty()));
|
dump_tu.global_vars(), (!version_script.empty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +289,12 @@ bool HeaderAbiLinker::ParseVersionScriptFiles() {
|
|||||||
}
|
}
|
||||||
function_decl_set_ = version_script_parser.GetFunctions();
|
function_decl_set_ = version_script_parser.GetFunctions();
|
||||||
globvar_decl_set_ = version_script_parser.GetGlobVars();
|
globvar_decl_set_ = version_script_parser.GetGlobVars();
|
||||||
|
std::set<std::string> function_regexs =
|
||||||
|
version_script_parser.GetFunctionRegexs();
|
||||||
|
std::set<std::string> globvar_regexs =
|
||||||
|
version_script_parser.GetGlobVarRegexs();
|
||||||
|
functions_vs_regex_ = CreateRegexMatchExprFromSet(function_regexs);
|
||||||
|
globvars_vs_regex_ = CreateRegexMatchExprFromSet(globvar_regexs);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace abi_util {
|
|||||||
|
|
||||||
std::set<std::string> CollectAllExportedHeaders(
|
std::set<std::string> CollectAllExportedHeaders(
|
||||||
const std::vector<std::string> &exported_header_dirs);
|
const std::vector<std::string> &exported_header_dirs);
|
||||||
|
|
||||||
class VersionScriptParser {
|
class VersionScriptParser {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -38,6 +39,10 @@ class VersionScriptParser {
|
|||||||
|
|
||||||
const std::set<std::string> &GetGlobVars();
|
const std::set<std::string> &GetGlobVars();
|
||||||
|
|
||||||
|
const std::set<std::string> &GetFunctionRegexs();
|
||||||
|
|
||||||
|
const std::set<std::string> &GetGlobVarRegexs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool ParseInnerBlock(std::ifstream &symbol_ifstream);
|
bool ParseInnerBlock(std::ifstream &symbol_ifstream);
|
||||||
@@ -54,11 +59,18 @@ class VersionScriptParser {
|
|||||||
|
|
||||||
int ApiStrToInt(const std::string &api);
|
int ApiStrToInt(const std::string &api);
|
||||||
|
|
||||||
|
void AddToVars(std::string &symbol);
|
||||||
|
|
||||||
|
void AddToFunctions(std::string &symbol);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string &version_script_;
|
const std::string &version_script_;
|
||||||
const std::string &arch_;
|
const std::string &arch_;
|
||||||
std::set<std::string> functions_;
|
std::set<std::string> functions_;
|
||||||
std::set<std::string> globvars_;
|
std::set<std::string> globvars_;
|
||||||
|
// Added to speed up version script parsing and linking.
|
||||||
|
std::set<std::string> function_regexs_;
|
||||||
|
std::set<std::string> globvar_regexs_;
|
||||||
int api_;
|
int api_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,22 @@ bool VersionScriptParser::SymbolExported(const std::string &line,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VersionScriptParser::AddToVars(std::string &symbol) {
|
||||||
|
if (symbol.find("*") != std::string::npos) {
|
||||||
|
globvar_regexs_.insert(symbol);
|
||||||
|
} else {
|
||||||
|
globvars_.insert(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionScriptParser::AddToFunctions(std::string &symbol) {
|
||||||
|
if (symbol.find("*") != std::string::npos) {
|
||||||
|
function_regexs_.insert(symbol);
|
||||||
|
} else {
|
||||||
|
functions_.insert(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool VersionScriptParser::ParseSymbolLine(const std::string &line) {
|
bool VersionScriptParser::ParseSymbolLine(const std::string &line) {
|
||||||
//The symbol lies before the ; and the tags are after ;
|
//The symbol lies before the ; and the tags are after ;
|
||||||
std::string::size_type pos = line.find(";");
|
std::string::size_type pos = line.find(";");
|
||||||
@@ -115,9 +131,9 @@ bool VersionScriptParser::ParseSymbolLine(const std::string &line) {
|
|||||||
std::string tags = line.substr(pos + 1);
|
std::string tags = line.substr(pos + 1);
|
||||||
if (SymbolExported(tags, arch_, api_)) {
|
if (SymbolExported(tags, arch_, api_)) {
|
||||||
if (StringContains(tags, "var")) {
|
if (StringContains(tags, "var")) {
|
||||||
globvars_.insert(symbol);
|
AddToVars(symbol);
|
||||||
} else {
|
} else {
|
||||||
functions_.insert(symbol);
|
AddToFunctions(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -161,6 +177,14 @@ const std::set<std::string> &VersionScriptParser::GetGlobVars() {
|
|||||||
return globvars_;
|
return globvars_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::set<std::string> &VersionScriptParser::GetFunctionRegexs() {
|
||||||
|
return function_regexs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::set<std::string> &VersionScriptParser::GetGlobVarRegexs() {
|
||||||
|
return globvar_regexs_;
|
||||||
|
}
|
||||||
|
|
||||||
bool VersionScriptParser::Parse() {
|
bool VersionScriptParser::Parse() {
|
||||||
std::ifstream symbol_ifstream(version_script_);
|
std::ifstream symbol_ifstream(version_script_);
|
||||||
if (!symbol_ifstream.is_open()) {
|
if (!symbol_ifstream.is_open()) {
|
||||||
|
|||||||
156
vndk/tools/header-checker/merge-abi-diff/src/merge_abi_diff.cpp
Normal file
156
vndk/tools/header-checker/merge-abi-diff/src/merge_abi_diff.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
// Copyright (C) 2016 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||||
|
#pragma clang diagnostic ignored "-Wnested-anon-types"
|
||||||
|
#include "proto/abi_dump.pb.h"
|
||||||
|
#include "proto/abi_diff.pb.h"
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
#include <header_abi_util.h>
|
||||||
|
|
||||||
|
#include <llvm/Support/CommandLine.h>
|
||||||
|
#include <llvm/Support/raw_ostream.h>
|
||||||
|
|
||||||
|
#include <google/protobuf/text_format.h>
|
||||||
|
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static llvm::cl::OptionCategory merge_abi_diff_category(
|
||||||
|
"merge-abi-diff options");
|
||||||
|
|
||||||
|
static llvm::cl::list<std::string> diff_report_list(
|
||||||
|
llvm::cl::Positional, llvm::cl::desc("<diff-reports>"), llvm::cl::Required,
|
||||||
|
llvm::cl::cat(merge_abi_diff_category), llvm::cl::OneOrMore);
|
||||||
|
|
||||||
|
static llvm::cl::opt<std::string> merged_diff_report(
|
||||||
|
"o", llvm::cl::desc("<merged-diff-report>"), llvm::cl::Required,
|
||||||
|
llvm::cl::cat(merge_abi_diff_category));
|
||||||
|
|
||||||
|
static llvm::cl::opt<bool> advice_only(
|
||||||
|
"advice-only", llvm::cl::desc("Advisory mode only"), llvm::cl::Optional,
|
||||||
|
llvm::cl::cat(merge_abi_diff_category));
|
||||||
|
|
||||||
|
static llvm::cl::opt<bool> do_not_break_on_extensions(
|
||||||
|
"allow-extensions",
|
||||||
|
llvm::cl::desc("Do not return a non zero status on extensions"),
|
||||||
|
llvm::cl::Optional, llvm::cl::cat(merge_abi_diff_category));
|
||||||
|
|
||||||
|
typedef abi_diff::CompatibilityStatus CompatibilityStatus;
|
||||||
|
|
||||||
|
static bool IsStatusDowngraded(const CompatibilityStatus &old_status,
|
||||||
|
const CompatibilityStatus &new_status) {
|
||||||
|
bool status_downgraded = false;
|
||||||
|
switch (old_status) {
|
||||||
|
case CompatibilityStatus::EXTENSION:
|
||||||
|
if (new_status == CompatibilityStatus::INCOMPATIBLE) {
|
||||||
|
status_downgraded = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CompatibilityStatus::COMPATIBLE:
|
||||||
|
if (new_status != CompatibilityStatus::COMPATIBLE) {
|
||||||
|
status_downgraded = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return status_downgraded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CompatibilityStatus MergeDiffReports(
|
||||||
|
const std::vector<std::string> &diff_reports,
|
||||||
|
const std::string &merged_diff_report) {
|
||||||
|
|
||||||
|
abi_diff::MergedTranslationUnitDiff merged_tu_diff;
|
||||||
|
std::ofstream text_output(merged_diff_report);
|
||||||
|
google::protobuf::io::OstreamOutputStream text_os(&text_output);
|
||||||
|
CompatibilityStatus status = CompatibilityStatus::COMPATIBLE;
|
||||||
|
|
||||||
|
for (auto &&i : diff_reports) {
|
||||||
|
abi_diff::TranslationUnitDiff diff_tu;
|
||||||
|
std::ifstream input(i);
|
||||||
|
google::protobuf::io::IstreamInputStream text_is(&input);
|
||||||
|
if (!google::protobuf::TextFormat::Parse(&text_is, &diff_tu)) {
|
||||||
|
llvm::errs() << "Failed to parse diff report\n";
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
abi_diff::ConciseDiffReportInformation *added_tu_diff =
|
||||||
|
merged_tu_diff.add_diff_reports();
|
||||||
|
if (!added_tu_diff) {
|
||||||
|
llvm::errs() << "Failed to add diff report to merged report\n";
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
CompatibilityStatus new_status = diff_tu.compatibility_status();
|
||||||
|
added_tu_diff->set_lib_name(diff_tu.lib_name());
|
||||||
|
added_tu_diff->set_arch(diff_tu.arch());
|
||||||
|
added_tu_diff->set_diff_report_path(i);
|
||||||
|
added_tu_diff->set_compatibility_status(new_status);
|
||||||
|
// Only, if the status is downgraded, change it.
|
||||||
|
if (IsStatusDowngraded(status, new_status)) {
|
||||||
|
status = new_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!google::protobuf::TextFormat::Print(merged_tu_diff, &text_os)) {
|
||||||
|
llvm::errs() << "Serialization to ostream failed\n";
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char **argv) {
|
||||||
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||||
|
llvm::cl::ParseCommandLineOptions(argc, argv, "merge-abi-diff");
|
||||||
|
CompatibilityStatus extension_or_incompatible =
|
||||||
|
MergeDiffReports(diff_report_list, merged_diff_report);
|
||||||
|
std::string status_str = "";
|
||||||
|
switch (extension_or_incompatible) {
|
||||||
|
case CompatibilityStatus::INCOMPATIBLE:
|
||||||
|
status_str = "broken";
|
||||||
|
break;
|
||||||
|
case CompatibilityStatus::EXTENSION:
|
||||||
|
status_str = "extended";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (extension_or_incompatible) {
|
||||||
|
llvm::errs() << "******************************************************\n"
|
||||||
|
<< "VNDK Abi "
|
||||||
|
<< status_str
|
||||||
|
<< ":"
|
||||||
|
<< " Please check compatiblity report at : "
|
||||||
|
<< merged_diff_report << "\n"
|
||||||
|
<< "*****************************************************\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_not_break_on_extensions &&
|
||||||
|
extension_or_incompatible == CompatibilityStatus::EXTENSION) {
|
||||||
|
extension_or_incompatible = CompatibilityStatus::COMPATIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!advice_only) {
|
||||||
|
return extension_or_incompatible;
|
||||||
|
}
|
||||||
|
return CompatibilityStatus::COMPATIBLE;
|
||||||
|
}
|
||||||
@@ -59,7 +59,7 @@ message ParamDeclDiff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message FunctionDeclDiff {
|
message FunctionDeclDiff {
|
||||||
required ReturnTypeDiff return_type_diffs = 1;
|
optional ReturnTypeDiff return_type_diffs = 1;
|
||||||
repeated ParamDeclDiff param_diffs = 2;
|
repeated ParamDeclDiff param_diffs = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,20 +67,43 @@ message GlobalVarDeclDiff {
|
|||||||
optional BasicNamedAndTypedDeclDiff type_diff = 1;
|
optional BasicNamedAndTypedDeclDiff type_diff = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TranslationUnitDiff {
|
enum CompatibilityStatus {
|
||||||
// Differing Elements.
|
COMPATIBLE = 0;
|
||||||
repeated RecordDeclDiff records_diff = 1;
|
EXTENSION = 1;
|
||||||
repeated EnumDeclDiff enums_diff = 2;
|
INCOMPATIBLE = 4;
|
||||||
repeated FunctionDeclDiff functions_diff = 3;
|
}
|
||||||
repeated GlobalVarDeclDiff global_vars_diff = 4;
|
|
||||||
// Removed Elements.
|
message TranslationUnitDiff {
|
||||||
repeated abi_dump.RecordDecl records_removed = 5;
|
// Library Name
|
||||||
repeated abi_dump.FunctionDecl functions_removed = 6;
|
optional string lib_name = 1;
|
||||||
repeated abi_dump.EnumDecl enums_removed = 7;
|
optional string arch = 2;
|
||||||
repeated abi_dump.GlobalVarDecl global_vars_removed = 8;
|
// Differing Elements.
|
||||||
// Added Elements.
|
repeated RecordDeclDiff records_diff = 3;
|
||||||
repeated abi_dump.RecordDecl records_added = 9;
|
repeated EnumDeclDiff enums_diff = 4;
|
||||||
repeated abi_dump.FunctionDecl functions_added = 10;
|
repeated FunctionDeclDiff functions_diff = 5;
|
||||||
repeated abi_dump.EnumDecl enums_added = 11;
|
repeated GlobalVarDeclDiff global_vars_diff = 6;
|
||||||
repeated abi_dump.GlobalVarDecl global_vars_added = 12;
|
// Removed Elements.
|
||||||
|
repeated abi_dump.RecordDecl records_removed = 7;
|
||||||
|
repeated abi_dump.FunctionDecl functions_removed = 8;
|
||||||
|
repeated abi_dump.EnumDecl enums_removed = 9;
|
||||||
|
repeated abi_dump.GlobalVarDecl global_vars_removed = 10;
|
||||||
|
// Added Elements.
|
||||||
|
repeated abi_dump.RecordDecl records_added = 11;
|
||||||
|
repeated abi_dump.FunctionDecl functions_added = 12;
|
||||||
|
repeated abi_dump.EnumDecl enums_added = 13;
|
||||||
|
repeated abi_dump.GlobalVarDecl global_vars_added = 14;
|
||||||
|
// Compatiblity Status
|
||||||
|
optional CompatibilityStatus compatibility_status = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not merged with TranslationUnitDiff to allow future extensions.
|
||||||
|
message ConciseDiffReportInformation {
|
||||||
|
optional string lib_name = 1;
|
||||||
|
optional string arch = 2;
|
||||||
|
optional string diff_report_path = 3;
|
||||||
|
optional CompatibilityStatus compatibility_status = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MergedTranslationUnitDiff {
|
||||||
|
repeated ConciseDiffReportInformation diff_reports = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user