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:
parent
a102a2f032
commit
fc55e7f343
|
@ -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
|
||||
==============
|
||||
|
||||
|
|
|
@ -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
|
||||
==============
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__
|
||||
|
|
Loading…
Reference in New Issue