Make abidiff and abicompat return meaningful exit codes

As per https://sourceware.org/bugzilla/show_bug.cgi?id=18146, abidiff
the exit code of abidiff and abicompat is now a bit field that can be
inspected to know if the ABI change reported is incompatible for sure,
or if it needs user review of the output to decide.

This patch also updates the documentation.

	* doc/manuals/abicompat.rst: Update documentation for abicompat
	exit codes.
	* doc/manuals/abidiff.rst: Likewise for abidiff exit codes.
	* include/abg-tools-utils.h (enum abidiff_status): Declare new
	enum.
	(operator{|,&,|=}): Declare new operators for the new enum
	abidiff_status.
	(abidiff_status_has_error, abidiff_status_has_abi_change)
	(abidiff_status_has_incompatible_abi_change): Declare new
	functions.
	* src/abg-tools-utils.cc (operator{|,&,|=}): Define these new
	operators.
	(abidiff_status_has_error, abidiff_status_has_abi_change)
	(abidiff_status_has_incompatible_abi_change): Define new
	functions.
	* tests/test-diff-filter.cc (main): Adjust for the new exit code
	of abidiff.
	* tests/test-diff-suppr.cc (main): Likewise.
	* tests/test-abicompat.cc (main): Likewise.
	* tools/abicompat.cc (enum abicompat_status): Remove.
	(operator{|,&,|=}): Remove these operators for enum
	abicompat_status.
	(perform_compat_check_in_normal_mode)
	(perform_compat_check_in_weak_mode): Return abidiff_status instead
	of abicompat_status.  Adjust therefore.
	(main): Adjust to return abidiff_status now, instead of a just
	zero for all non-error cases.
	* tools/abidiff.cc (main): Likewise.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2015-04-10 15:42:35 +02:00
parent a102a2f032
commit fc55e7f343
9 changed files with 287 additions and 80 deletions

View File

@ -10,6 +10,8 @@ library. If the new version of the library introduces an ABI
incompatibility, then abicompat hints the user at what exactly that
incompatibility is.
.. _abicompat_invocation_label:
Invocation
==========
@ -17,6 +19,8 @@ Invocation
abicompat [options] [<application> <shared-library-first-version> <shared-library-second-version>]
.. _abicompat_options_label:
Options
=======
@ -90,6 +94,43 @@ Options
application but that are removed from the library. That is why it
is called ``weak`` mode.
.. _abicompat_return_value_label:
Return values
=============
The exit code of the ``abicompat`` command is either 0 if the ABI of
the binaries being compared are equal, or non-zero if they differ or
if the tool encountered an error.
In the later case, the exit code is a 8-bits-wide bit field in which
each bit has a specific meaning.
The first bit, of value 1, named ``ABIDIFF_ERROR`` means there was an
error.
The second bit, of value 2, named ``ABIDIFF_USAGE_ERROR`` means there
was an error in the way the user invoked the tool. It might be set,
for instance, if the user invoked the tool with an unknown command
line switch, with a wrong number or argument, etc. If this bit is
set, then the ``ABIDIFF_ERROR`` bit must be set as well.
The third bit, of value 4, named ``ABIDIFF_ABI_CHANGE`` means the ABI
of the binaries being compared are different.
The fourth bit, of value 8, named ``ABIDIFF_ABI_INCOMPATIBLE_CHANGE``
means the ABI of the binaries compared are different in an
incompatible way. If this bit is set, then the ``ABIDIFF_ABI_CHANGE``
bit must be set as well. If the ``ABIDIFF_ABI_CHANGE`` is set and the
``ABIDIFF_INCOMPATIBLE_CHANGE`` is *NOT* set, then it means that the
ABIs being compared might or might not be compatible. In that case, a
human being needs to review the ABI changes to decide if they are
compatible or not.
The remaining bits are not used for the moment.
.. _abicompat_usage_example_label:
Usage examples
==============

View File

@ -14,6 +14,8 @@ be accompanied with their debug information in `DWARF`_ format.
Otherwise, only `ELF`_ symbols that were added or removed are
reported.
.. _abidiff_invocation_label:
Invocation
==========
@ -21,6 +23,8 @@ Invocation
abidiff [options] <first-shared-library> <second-shared-library>
.. _abidiff_options_label:
Options
=======
@ -202,6 +206,43 @@ Options
changes. Added or removed functions and variables do not have any
diff nodes tree associated to them.
.. _abidiff_return_value_label:
Return values
=============
The exit code of the ``abidiff`` command is either 0 if the ABI of the
binaries being compared are equal, or non-zero if they differ or if
the tool encountered an error.
In the later case, the exit code is a 8-bits-wide bit field in which
each bit has a specific meaning.
The first bit, of value 1, named ``ABIDIFF_ERROR`` means there was an
error.
The second bit, of value 2, named ``ABIDIFF_USAGE_ERROR`` means there
was an error in the way the user invoked the tool. It might be set,
for instance, if the user invoked the tool with an unknown command
line switch, with a wrong number or argument, etc. If this bit is
set, then the ``ABIDIFF_ERROR`` bit must be set as well.
The third bit, of value 4, named ``ABIDIFF_ABI_CHANGE`` means the ABI
of the binaries being compared are different.
The fourth bit, of value 8, named ``ABIDIFF_ABI_INCOMPATIBLE_CHANGE``
means the ABI of the binaries compared are different in an
incompatible way. If this bit is set, then the ``ABIDIFF_ABI_CHANGE``
bit must be set as well. If the ``ABIDIFF_ABI_CHANGE`` is set and the
``ABIDIFF_INCOMPATIBLE_CHANGE`` is *NOT* set, then it means that the
ABIs being compared might or might not be compatible. In that case, a
human being needs to review the ABI changes to decide if they are
compatible or not.
The remaining bits are not used for the moment.
.. _abidiff_usage_example_label:
Usage examples
==============

View File

@ -65,6 +65,57 @@ enum file_type
FILE_TYPE_ZIP_CORPUS,
};
/// Exit status for abidiff and abicompat tools.
///
/// It's actually a bit mask. The valu of each enumerator is a power
/// of two.
enum abidiff_status
{
/// This is for when the compared ABIs are equal.
///
/// Its numerical value is 0.
ABIDIFF_OK = 0,
/// This bit is set if there an application error.
///
/// Its numerical value is 1.
ABIDIFF_ERROR = 1,
/// This bit is set if the tool is invoked in an non appropriate
/// manner.
///
/// Its numerical value is 2.
ABIDIFF_USAGE_ERROR = 1 << 1,
/// This bit is set if the ABIs being compared are different.
///
/// Its numerical value is 4.
ABIDIFF_ABI_CHANGE = 1 << 2,
/// This bit is set if the ABIs being compared are different *and*
/// are incompatible.
///
/// Its numerical value is 8.
ABIDIFF_ABI_INCOMPATIBLE_CHANGE = 1 << 3
};
abidiff_status
operator|(abidiff_status, abidiff_status);
abidiff_status
operator&(abidiff_status, abidiff_status);
abidiff_status&
operator|=(abidiff_status&l, abidiff_status r);
bool
abidiff_status_has_error(abidiff_status s);
bool
abidiff_status_has_abi_change(abidiff_status s);
bool
abidiff_status_has_incompatible_abi_change(abidiff_status s);
file_type guess_file_type(istream& in);
file_type guess_file_type(const string& file_path);

View File

@ -41,6 +41,86 @@ namespace abigail
namespace tools_utils
{
/// The bitwise 'OR' operator for abidiff_status bit masks.
///
/// @param l the left hand side operand of the OR operator.
///
/// @param r the right hand side operand of the OR operator.
///
/// @return the result of the OR expression.
abidiff_status
operator|(abidiff_status l, abidiff_status r)
{return static_cast<abidiff_status>(static_cast<unsigned>(l)
| static_cast<unsigned>(r));}
/// The bitwise 'AND' operator for abidiff_status bit masks.
///
/// @param l the left hand side operand of the AND operator.
///
/// @param r the right hand side operand of the AND operator.
///
/// @return the result of the AND expression.
abidiff_status
operator&(abidiff_status l, abidiff_status r)
{return static_cast<abidiff_status>(static_cast<unsigned>(l)
& static_cast<unsigned>(r));}
/// The |= operator.
///
/// @param l the left hand side operand of the operator.
///
/// @param r the right hand side operand of the operator.
///
/// @param the resulting bit mask.
abidiff_status&
operator|=(abidiff_status&l, abidiff_status r)
{
l = static_cast<abidiff_status>(static_cast<unsigned>(l)
| static_cast<unsigned>(r));
return l;
}
/// Test if an instance of @param abidiff_status bits mask represents
/// an error.
///
/// This functions tests if the @ref ABIDIFF_ERROR bit is set in the
/// given bits mask.
///
/// @param s the bit mask to consider.
///
/// @return true iff @p s has its ABIDIFF_ERROR bit set.
bool
abidiff_status_has_error(abidiff_status s)
{return s & ABIDIFF_ERROR;}
/// Test if an instance of @param abidiff_status bits mask represents
/// an abi change.
///
/// This functions tests if the @ref ABIDIFF_ABI_CHANGE bit is set in the
/// given bits mask.
///
/// @param s the bit mask to consider.
///
/// @return true iff @p s has its @ref ABIDIFF_ABI_CHANGE bit set.
bool
abidiff_status_has_abi_change(abidiff_status s)
{return s & ABIDIFF_ABI_CHANGE;}
/// Test if an instance of @param abidiff_status bits mask represents
/// an incompatible abi change.
///
/// This functions tests if the @ref ABIDIFF_INCOMPATIBLE_ABI_CHANGE
/// bit is set in the given bits mask. Note that the this bit is set
/// then the bit @ref ABIDIFF_ABI_CHANGE must be set as well.
///
/// @param s the bit mask to consider.
///
/// @return true iff @p s has its @ref ABIDIFF_INCOMPATIBLE ABI_CHANGE
/// set.
bool
abidiff_status_has_incompatible_abi_change(abidiff_status s)
{return s & ABIDIFF_ABI_INCOMPATIBLE_CHANGE;}
#define DECLARE_STAT(st) \
struct stat st; \
memset(&st, 0, sizeof(st))

View File

@ -138,6 +138,7 @@ main()
using abigail::tests::get_src_dir;
using abigail::tests::get_build_dir;
using abigail::tools_utils::ensure_parent_dir_created;
using abigail::tools_utils::abidiff_status;
bool is_ok = true;
string in_app_path, in_lib1_path, in_lib2_path, suppression_path,
@ -179,7 +180,8 @@ main()
cmd += " > " + out_report_path;
bool abicompat_ok = true;
if (system(cmd.c_str()))
abidiff_status status = static_cast<abidiff_status>(system(cmd.c_str()));
if (abigail::tools_utils::abidiff_status_has_error(status))
abicompat_ok = false;
if (abicompat_ok)

View File

@ -372,6 +372,7 @@ main()
using abigail::tests::get_src_dir;
using abigail::tests::get_build_dir;
using abigail::tools_utils::ensure_parent_dir_created;
using abigail::tools_utils::abidiff_status;
bool is_ok = true;
string in_elfv0_path, in_elfv1_path,
@ -401,7 +402,9 @@ main()
cmd += " > " + out_diff_report_path;
bool abidiff_ok = true;
if (system(cmd.c_str()))
abidiff_status status =
static_cast<abidiff_status>(system(cmd.c_str()) & 255);
if (abigail::tools_utils::abidiff_status_has_error(status))
abidiff_ok = false;
if (abidiff_ok)

View File

@ -369,6 +369,7 @@ main()
using abigail::tests::get_src_dir;
using abigail::tests::get_build_dir;
using abigail::tools_utils::ensure_parent_dir_created;
using abigail::tools_utils::abidiff_status;
bool is_ok = true;
string in_elfv0_path, in_elfv1_path,
@ -406,7 +407,9 @@ main()
cmd += " > " + out_diff_report_path;
bool bidiff_ok = true;
if (system(cmd.c_str()))
abigail::tools_utils::abidiff_status status =
static_cast<abidiff_status>(system(cmd.c_str()) & 255);
if (abigail::tools_utils::abidiff_status_has_error(status))
bidiff_ok = false;
if (bidiff_ok)

View File

@ -87,34 +87,6 @@ struct options
{}
}; // end struct options
/// The status of the abicompat operations. It's a bit field.
enum abicompat_status
{
NO_STATUS = 0,
ERROR_STATUS = 1,
OK_STATUS = 1 << 1,
NO_CHANGE_STATUS = 1 << 2,
IS_ABI_INCOMPATIBLE_STATUS = 1 << 3,
MAY_BE_ABI_INCOMPATIBLE_STATUS = 1 << 4
};
abicompat_status
operator|(abicompat_status l, abicompat_status r)
{return static_cast<abicompat_status>(static_cast<int>(l)
| static_cast<int>(r));}
abicompat_status&
operator|=(abicompat_status &l, abicompat_status r)
{
l = static_cast<abicompat_status>( static_cast<int>(l) | static_cast<int>(r));
return l;
}
abicompat_status
operator&(abicompat_status l, abicompat_status r)
{return static_cast<abicompat_status>(static_cast<int>(l)
& static_cast<int>(r));}
static void
display_usage(const string& prog_name, ostream& out)
{
@ -240,6 +212,7 @@ parse_command_line(int argc, char* argv[], options& opts)
using abigail::tools_utils::check_file;
using abigail::tools_utils::base_name;
using abigail::tools_utils::abidiff_status;
using abigail::corpus;
using abigail::corpus_sptr;
using abigail::ir::elf_symbols;
@ -279,7 +252,7 @@ using abigail::comparison::read_suppressions;
/// thing.
///
/// @return a status bitfield.
static abicompat_status
static abidiff_status
perform_compat_check_in_normal_mode(options& opts,
corpus_sptr app_corpus,
corpus_sptr lib1_corpus,
@ -289,7 +262,7 @@ perform_compat_check_in_normal_mode(options& opts,
assert(lib2_corpus);
assert(app_corpus);
abicompat_status status = NO_STATUS;
abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
// compare lib1 and lib2 only by looking at the functions and
// variables which symbols are those undefined in the app.
@ -372,6 +345,8 @@ perform_compat_check_in_normal_mode(options& opts,
base_name(opts.lib2_path, lib2_path);
}
status |= abigail::tools_utils::ABIDIFF_ABI_CHANGE;
bool abi_broke_for_sure = changes->soname_changed()
|| s.num_vars_removed()
|| s.num_func_removed()
@ -382,22 +357,16 @@ perform_compat_check_in_normal_mode(options& opts,
if (abi_broke_for_sure)
{
cout << " is not ";
status |= IS_ABI_INCOMPATIBLE_STATUS;
status |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
}
else
{
cout << " might not be ";
status |= MAY_BE_ABI_INCOMPATIBLE_STATUS;
}
cout << "ABI compatible with '" << lib2_path
<< "' due to differences with '" << lib1_path
<< "' below:\n";
changes->report(cout);
status |= OK_STATUS;
}
else
status |= NO_CHANGE_STATUS | OK_STATUS;
return status;
}
@ -455,7 +424,7 @@ struct var_change
/// layout differences found.
///
/// @return a status bitfield.
static abicompat_status
static abidiff_status
perform_compat_check_in_weak_mode(options& opts,
corpus_sptr app_corpus,
corpus_sptr lib_corpus)
@ -463,7 +432,7 @@ perform_compat_check_in_weak_mode(options& opts,
assert(lib_corpus);
assert(app_corpus);
abicompat_status status = NO_STATUS;
abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
for (elf_symbols::const_iterator i =
app_corpus->get_sorted_undefined_fun_symbols().begin();
@ -555,7 +524,7 @@ perform_compat_check_in_weak_mode(options& opts,
}
if (!fn_changes.empty())
status |= MAY_BE_ABI_INCOMPATIBLE_STATUS;
status |= abigail::tools_utils::ABIDIFF_ABI_CHANGE;
type_base_sptr lib_var_type, app_var_type;
diff_sptr type_diff;
@ -591,9 +560,6 @@ perform_compat_check_in_weak_mode(options& opts,
}
}
}
status |= OK_STATUS;
return status;
}
@ -608,30 +574,33 @@ main(int argc, char* argv[])
{
cerr << "unrecognized option: " << opts.unknow_option << "\n"
<< "try the --help option for more information\n";
return false;
return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
| abigail::tools_utils::ABIDIFF_ERROR);
}
cerr << "wrong invocation\n"
<< "try the --help option for more information\n";
return false;
return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
| abigail::tools_utils::ABIDIFF_ERROR);
}
if (opts.display_help)
{
display_usage(argv[0], cout);
return true;
return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
| abigail::tools_utils::ABIDIFF_ERROR);
}
assert(!opts.app_path.empty());
if (!abigail::tools_utils::check_file(opts.app_path, cerr))
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
abigail::tools_utils::file_type type =
abigail::tools_utils::guess_file_type(opts.app_path);
if (type != abigail::tools_utils::FILE_TYPE_ELF)
{
cerr << opts.app_path << " is not an ELF file\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
// Read the application ELF file.
@ -646,12 +615,12 @@ main(int argc, char* argv[])
if (status & abigail::dwarf_reader::STATUS_NO_SYMBOLS_FOUND)
{
cerr << "could not read symbols from " << opts.app_path << "\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
if (!(status & abigail::dwarf_reader::STATUS_OK))
{
cerr << "could not read file " << opts.app_path << "\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
if (opts.list_undefined_symbols_only)
@ -669,18 +638,18 @@ main(int argc, char* argv[])
else
cout << id << "\n";
}
return 0;
return abigail::tools_utils::ABIDIFF_OK;
}
// Read the first version of the library.
assert(!opts.lib1_path.empty());
if (!abigail::tools_utils::check_file(opts.lib1_path, cerr))
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
type = abigail::tools_utils::guess_file_type(opts.lib1_path);
if (type != abigail::tools_utils::FILE_TYPE_ELF)
{
cerr << opts.lib1_path << " is not an ELF file\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
corpus_sptr lib1_corpus;
@ -694,12 +663,12 @@ main(int argc, char* argv[])
if (status & abigail::dwarf_reader::STATUS_NO_SYMBOLS_FOUND)
{
cerr << "could not read symbols from " << opts.lib1_path << "\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
if (!(status & abigail::dwarf_reader::STATUS_OK))
{
cerr << "could not read file " << opts.lib1_path << "\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
// Read the second version of the library.
@ -717,16 +686,16 @@ main(int argc, char* argv[])
if (status & abigail::dwarf_reader::STATUS_NO_SYMBOLS_FOUND)
{
cerr << "could not read symbols from " << opts.lib2_path << "\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
if (!(status & abigail::dwarf_reader::STATUS_OK))
{
cerr << "could not read file " << opts.lib2_path << "\n";
return 1;
return abigail::tools_utils::ABIDIFF_ERROR;
}
}
abicompat_status s = NO_STATUS;
abidiff_status s = abigail::tools_utils::ABIDIFF_OK;
if (opts.weak_mode)
s = perform_compat_check_in_weak_mode(opts,
@ -738,7 +707,5 @@ main(int argc, char* argv[])
lib1_corpus,
lib2_corpus);
if (s & OK_STATUS)
return 0;
return 1;
return s;
}

View File

@ -41,6 +41,7 @@ using abigail::translation_unit;
using abigail::translation_unit_sptr;
using abigail::corpus_sptr;
using abigail::comparison::translation_unit_diff_sptr;
using abigail::comparison::corpus_diff;
using abigail::comparison::corpus_diff_sptr;
using abigail::comparison::compute_diff;
using abigail::comparison::suppression_sptr;
@ -49,6 +50,7 @@ using abigail::comparison::read_suppressions;
using namespace abigail::dwarf_reader;
using abigail::tools_utils::check_file;
using abigail::tools_utils::guess_file_type;
using abigail::tools_utils::abidiff_status;
struct options
{
@ -464,29 +466,33 @@ main(int argc, char* argv[])
{
cerr << "unrecognized option\n"
"try the --help option for more information\n";
return false;
return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
| abigail::tools_utils::ABIDIFF_ERROR);
}
if (opts.missing_operand)
{
cerr << "missing operand\n"
"try the --help option for more information\n";
return false;
return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
| abigail::tools_utils::ABIDIFF_ERROR);
}
if (opts.display_usage)
{
display_usage(argv[0], cout);
return true;
return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
| abigail::tools_utils::ABIDIFF_ERROR);
}
abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
if (!opts.file1.empty() && !opts.file2.empty())
{
if (!check_file(opts.file1, cerr))
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
if (!check_file(opts.file2, cerr))
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
abigail::tools_utils::file_type t1_type, t2_type;
@ -494,14 +500,14 @@ main(int argc, char* argv[])
if (t1_type == abigail::tools_utils::FILE_TYPE_UNKNOWN)
{
cerr << "Unknown content type for file " << opts.file1 << "\n";
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
}
t2_type = guess_file_type(opts.file2);
if (t2_type == abigail::tools_utils::FILE_TYPE_UNKNOWN)
{
cerr << "Unknown content type for file " << opts.file2 << "\n";
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
}
translation_unit_sptr t1, t2;
@ -515,7 +521,7 @@ main(int argc, char* argv[])
{
case abigail::tools_utils::FILE_TYPE_UNKNOWN:
cerr << "Unknown content type for file " << opts.file1 << "\n";
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
break;
case abigail::tools_utils::FILE_TYPE_NATIVE_BI:
t1 = abigail::xml_reader::read_translation_unit_from_file(opts.file1);
@ -544,7 +550,7 @@ main(int argc, char* argv[])
{
case abigail::tools_utils::FILE_TYPE_UNKNOWN:
cerr << "Unknown content type for file " << opts.file2 << "\n";
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
break;
case abigail::tools_utils::FILE_TYPE_NATIVE_BI:
t2 = abigail::xml_reader::read_translation_unit_from_file(opts.file2);
@ -592,7 +598,7 @@ main(int argc, char* argv[])
cerr << "could not find the ELF symbols in the file '"
<< opts.file1
<< "'\n";
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
}
}
@ -619,7 +625,7 @@ main(int argc, char* argv[])
cerr << "could not find the ELF symbols in the file '"
<< opts.file2
<< "'\n";
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
}
}
@ -627,7 +633,7 @@ main(int argc, char* argv[])
|| !!t1 != !!t2)
{
cerr << "the two input should be of the same kind\n";
return true;
return abigail::tools_utils::ABIDIFF_ERROR;
}
if (t1)
@ -641,7 +647,7 @@ main(int argc, char* argv[])
if (opts.show_symtabs)
{
display_symtabs(c1, c2, cout);
return false;
return abigail::tools_utils::ABIDIFF_OK;
}
set_corpus_keep_drop_regex_patterns(opts, c1);
@ -650,14 +656,27 @@ main(int argc, char* argv[])
diff_context_sptr ctxt(new diff_context);
set_diff_context_from_opts(ctxt, opts);
corpus_diff_sptr diff = compute_diff(c1, c2, ctxt);
const corpus_diff::diff_stats& stats =
diff->apply_filters_and_suppressions_before_reporting();
if (diff->soname_changed()
|| stats.num_func_removed() != 0
|| stats.num_vars_removed() != 0
|| stats.num_func_syms_removed() != 0
|| stats.num_var_syms_removed() != 0)
status = (abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE
| abigail::tools_utils::ABIDIFF_ABI_CHANGE);
else if (stats.net_num_func_changed() != 0
|| stats.net_num_vars_changed() != 0)
status = abigail::tools_utils::ABIDIFF_ABI_CHANGE;
if (diff->has_changes() > 0)
diff->report(cout);
}
return false;
else
status = abigail::tools_utils::ABIDIFF_ERROR;
}
return true;
return status;
}
#ifdef __ABIGAIL_IN_THE_DEBUGGER__