@@ -104,12 +104,24 @@ Options
library that the tool has to consider. The tool will thus filter
out ABI changes on types that are not defined in public headers.
+ * ``--header-file1 | --hf1`` <header-file-path-1>
+
+ Specifies where to find one public header of the first shared
+ library that the tool has to consider. The tool will thus filter
+ out ABI changes on types that are not defined in public headers.
+
* ``--headers-dir2 | --hd2`` <headers-directory-path-1>
Specifies where to find the public headers of the second shared
library that the tool has to consider. The tool will thus filter
out ABI changes on types that are not defined in public headers.
+ * ``--header-file2 | --hf2`` <header-file-path-2>
+
+ Specifies where to find one public header of the second shared
+ library that the tool has to consider. The tool will thus filter
+ out ABI changes on types that are not defined in public headers.
+
* ``--no-linux-kernel-mode``
Without this option, if abidiff detects that the binaries it is
@@ -141,13 +153,13 @@ Options
* ``--drop-private-types``
- This option is to be used with the ``--headers-dir1`` and
- ``--headers-dir2`` options. With this option, types that are
- *NOT* defined in the headers are entirely dropped from the
- internal representation build by Libabigail to represent the ABI.
- They thus don't have to be filtered out from the final ABI change
- report because they are not even present in Libabigail's
- representation.
+ This option is to be used with the ``--headers-dir1``,
+ ``header-file1``, ``header-file2`` and ``--headers-dir2`` options.
+ With this option, types that are *NOT* defined in the headers are
+ entirely dropped from the internal representation build by
+ Libabigail to represent the ABI. They thus don't have to be
+ filtered out from the final ABI change report because they are not
+ even present in Libabigail's representation.
Without this option however, those private types are kept in the
internal representation and later filtered out from the report.
@@ -218,9 +230,10 @@ Options
This option might incur some serious performance degradation as
the number of types analyzed can be huge. However, if paired with
- the ``--headers-dir{1,2}`` options, the additional non-reachable
- types analyzed are restricted to those defined in public headers
- files, thus hopefully making the performance hit acceptable.
+ the ``--headers-dir{1,2}`` and/or ``header-file{1,2}`` options,
+ the additional non-reachable types analyzed are restricted to
+ those defined in public headers files, thus hopefully making the
+ performance hit acceptable.
Also, using this option alongside suppression specifications (by
also using the ``--suppressions`` option) might help keep the number of
@@ -132,6 +132,12 @@ Options
library that the tool has to consider. The tool will thus filter
out types that are not defined in public headers.
+ * ``--header-file | --hf`` <header-file-path>
+
+ Specifies where to find one of the public headers of the abi file
+ that the tool has to consider. The tool will thus filter out
+ types that are not defined in public headers.
+
* ``--no-linux-kernel-mode``
Without this option, if abipkgiff detects that the binaries it is
@@ -76,6 +76,12 @@ Options
library that the tool has to consider. The tool will thus filter
out types that are not defined in public headers.
+ * ``--header-file | --hf`` <header-file-path>
+
+ Specifies where to find one of the public headers of the abi file
+ that the tool has to consider. The tool will thus filter out
+ types that are not defined in public headers.
+
* ``--stdin | --``
Read the input content from standard input.
@@ -84,7 +84,8 @@ string trim_leading_string(const string& from, const string& to_trim);
void convert_char_stars_to_char_star_stars(const vector<char*>&,
vector<char**>&);
suppr::type_suppression_sptr
-gen_suppr_spec_from_headers(const string& hdrs_root_dir);
+gen_suppr_spec_from_headers(const string& hdrs_root_dir,
+ const vector<string>& hdr_files);
suppr::suppressions_type
gen_suppr_spec_from_kernel_abi_whitelists
@@ -1787,6 +1787,40 @@ make_path_absolute_to_be_freed(const char*p)
return result;
}
+/// This is a sub-routine of gen_suppr_spec_from_headers and
+/// handle_fts_entry.
+///
+/// @param file add to the to the vector returned by
+/// type_suppression::get_source_locations_to_keep()
+///
+/// @param suppr the file name is going to be added to the vector
+/// returned by the method type_suppression::get_source_locations_to_keep
+/// of this instance.
+/// If this smart pointer is nil then a new instance @ref
+/// type_suppression is created and this variable is made to point to
+/// it.
+static void
+handle_file_entry(const string& file,
+ type_suppression_sptr& suppr)
+{
+ if (!suppr)
+ {
+ suppr.reset(new type_suppression(get_private_types_suppr_spec_label(),
+ /*type_name_regexp=*/"",
+ /*type_name=*/""));
+
+ // Types that are defined in system headers are usually
+ // OK to be considered as public types.
+ suppr->set_source_location_to_keep_regex_str("^/usr/include/");
+ suppr->set_is_artificial(true);
+ }
+
+ // And types that are defined in header files that are under
+ // the header directory file we are looking are to be
+ // considered public types too.
+ suppr->get_source_locations_to_keep().insert(file);
+}
+
/// This is a sub-routine of gen_suppr_spec_from_headers.
///
/// @param entry if this file represents a regular (or symlink) file,
@@ -1815,23 +1849,7 @@ handle_fts_entry(const FTSENT *entry,
if (string_ends_with(fname, ".h")
|| string_ends_with(fname, ".hpp")
|| string_ends_with(fname, ".hxx"))
- {
- if (!suppr)
- {
- suppr.reset(new type_suppression(get_private_types_suppr_spec_label(),
- /*type_name_regexp=*/"",
- /*type_name=*/""));
-
- // Types that are defined in system headers are usually
- // OK to be considered as public types.
- suppr->set_source_location_to_keep_regex_str("^/usr/include/");
- suppr->set_is_artificial(true);
- }
- // And types that are defined in header files that are under
- // the header directory file we are looking are to be
- // considered public types too.
- suppr->get_source_locations_to_keep().insert(fname);
- }
+ handle_file_entry (fname, suppr);
}
}
@@ -1845,25 +1863,35 @@ handle_fts_entry(const FTSENT *entry,
/// @return the resulting type suppression generated, if any file was
/// found in the directory tree @p headers_root_dir.
type_suppression_sptr
-gen_suppr_spec_from_headers(const string& headers_root_dir)
+gen_suppr_spec_from_headers(const string& headers_root_dir,
+ const vector<string>& header_files)
{
type_suppression_sptr result;
- if (headers_root_dir.empty())
- // We were given no headers root dir so the resulting suppression
- // specification shall be empty.
+ if (headers_root_dir.empty() && header_files.empty())
+ // We were given no headers root dir and no header files
+ // so the resulting suppression specification shall be empty.
return result;
- char* paths[] = {const_cast<char*>(headers_root_dir.c_str()), 0};
+ if (!headers_root_dir.empty())
+ {
+ char* paths[] = {const_cast<char*>(headers_root_dir.c_str()), 0};
- FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL);
- if (!file_hierarchy)
- return result;
+ FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL);
+ if (!file_hierarchy)
+ return result;
+
+ FTSENT *entry;
+ while ((entry = fts_read(file_hierarchy)))
+ handle_fts_entry(entry, result);
+ fts_close(file_hierarchy);
+ }
+
+ for (vector<string>::const_iterator file = header_files.begin();
+ file != header_files.end();
+ ++file)
+ handle_file_entry(*file, result);
- FTSENT *entry;
- while ((entry = fts_read(file_hierarchy)))
- handle_fts_entry(entry, result);
- fts_close(file_hierarchy);
return result;
}
@@ -79,7 +79,9 @@ struct options
vector<string> keep_fn_regex_patterns;
vector<string> keep_var_regex_patterns;
string headers_dir1;
+ vector<string> header_files1;
string headers_dir2;
+ vector<string> header_files2;
bool drop_private_types;
bool linux_kernel_mode;
bool no_default_supprs;
@@ -183,7 +185,9 @@ display_usage(const string& prog_name, ostream& out)
<< " --debug-info-dir1|--d1 <path> the root for the debug info of file1\n"
<< " --debug-info-dir2|--d2 <path> the root for the debug info of file2\n"
<< " --headers-dir1|--hd1 <path> the path to headers of file1\n"
+ << " --header-file1|--hf1 <path> the path to one header of file1\n"
<< " --headers-dir2|--hd2 <path> the path to headers of file2\n"
+ << " --header-file2|--hf2 <path> the path to one header of file2\n"
<< " --drop-private-types drop private types from "
"internal representation\n"
<< " --no-linux-kernel-mode don't consider the input binaries as "
@@ -317,6 +321,19 @@ parse_command_line(int argc, char* argv[], options& opts)
opts.headers_dir1 = argv[j];
++i;
}
+ else if (!strcmp(argv[i], "--header-file1")
+ || !strcmp(argv[i], "--hf1"))
+ {
+ int j = i + 1;
+ if (j >= argc)
+ {
+ opts.missing_operand = true;
+ opts.wrong_option = argv[i];
+ return true;
+ }
+ opts.header_files1.push_back(argv[j]);
+ ++i;
+ }
else if (!strcmp(argv[i], "--headers-dir2")
|| !strcmp(argv[i], "--hd2"))
{
@@ -330,6 +347,19 @@ parse_command_line(int argc, char* argv[], options& opts)
opts.headers_dir2 = argv[j];
++i;
}
+ else if (!strcmp(argv[i], "--header-file2")
+ || !strcmp(argv[i], "--hf2"))
+ {
+ int j = i + 1;
+ if (j >= argc)
+ {
+ opts.missing_operand = true;
+ opts.wrong_option = argv[i];
+ return true;
+ }
+ opts.header_files2.push_back(argv[j]);
+ ++i;
+ }
else if (!strcmp(argv[i], "--kmi-whitelist")
|| !strcmp(argv[i], "-w"))
{
@@ -690,22 +720,22 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
load_default_user_suppressions(supprs);
}
- if (!opts.headers_dir1.empty())
+ if (!opts.headers_dir1.empty() || !opts.header_files1.empty())
{
// Generate suppression specification to avoid showing ABI
// changes on types that are not defined in public headers.
suppression_sptr suppr =
- gen_suppr_spec_from_headers(opts.headers_dir1);
+ gen_suppr_spec_from_headers(opts.headers_dir1, opts.header_files1);
if (suppr)
ctxt->add_suppression(suppr);
}
- if (!opts.headers_dir2.empty())
+ if (!opts.headers_dir2.empty() || !opts.header_files2.empty())
{
// Generate suppression specification to avoid showing ABI
// changes on types that are not defined in public headers.
suppression_sptr suppr =
- gen_suppr_spec_from_headers(opts.headers_dir2);
+ gen_suppr_spec_from_headers(opts.headers_dir2, opts.header_files2);
if (suppr)
ctxt->add_suppression(suppr);
}
@@ -740,7 +770,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
read_suppressions(*i, supprs);
if (read_context_get_path(read_ctxt) == opts.file1
- && !opts.headers_dir1.empty())
+ && (!opts.headers_dir1.empty() || !opts.header_files1.empty()))
{
// Generate suppression specification to avoid showing ABI
// changes on types that are not defined in public headers for
@@ -750,7 +780,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
// corpus loading, they are going to be dropped from the
// internal representation altogether.
suppression_sptr suppr =
- gen_suppr_spec_from_headers(opts.headers_dir1);
+ gen_suppr_spec_from_headers(opts.headers_dir1, opts.header_files1);
if (suppr)
{
if (opts.drop_private_types)
@@ -760,7 +790,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
}
if (read_context_get_path(read_ctxt) == opts.file2
- && !opts.headers_dir2.empty())
+ && (!opts.headers_dir2.empty() || !opts.header_files2.empty()))
{
// Generate suppression specification to avoid showing ABI
// changes on types that are not defined in public headers for
@@ -770,7 +800,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
// corpus loading, they are going to be dropped from the
// internal representation altogether.
suppression_sptr suppr =
- gen_suppr_spec_from_headers(opts.headers_dir2);
+ gen_suppr_spec_from_headers(opts.headers_dir2, opts.header_files2);
if (suppr)
{
if (opts.drop_private_types)
@@ -88,6 +88,7 @@ struct options
vector<char*> di_root_paths;
vector<char**> prepared_di_root_paths;
string headers_dir;
+ vector<string> header_files;
string vmlinux;
vector<string> suppression_paths;
vector<string> kabi_whitelist_paths;
@@ -149,6 +150,7 @@ display_usage(const string& prog_name, ostream& out)
<< " --version|-v display program version information and exit\n"
<< " --debug-info-dir|-d <dir-path> look for debug info under 'dir-path'\n"
<< " --headers-dir|--hd <path> the path to headers of the elf file\n"
+ << " --header-file|--hf <path> the path one header of the elf file\n"
<< " --out-file <file-path> write the output to 'file-path'\n"
<< " --noout do not emit anything after reading the binary\n"
<< " --suppressions|--suppr <path> specify a suppression file\n"
@@ -217,6 +219,15 @@ parse_command_line(int argc, char* argv[], options& opts)
opts.headers_dir = argv[j];
++i;
}
+ else if (!strcmp(argv[i], "--header-file")
+ || !strcmp(argv[i], "--hf"))
+ {
+ int j = i + 1;
+ if (j >= argc)
+ return false;
+ opts.header_files.push_back(argv[j]);
+ ++i;
+ }
else if (!strcmp(argv[i], "--out-file"))
{
if (argc <= i + 1
@@ -349,6 +360,24 @@ maybe_check_suppression_files(const options& opts)
return true;
}
+/// Check that the header files supplied are present.
+/// If not, emit an error on stderr.
+///
+/// @param opts the options instance to use.
+///
+/// @return true if all header files are present, false otherwise.
+static bool
+maybe_check_header_files(const options& opts)
+{
+ for (vector<string>::const_iterator file = opts.header_files.begin();
+ file != opts.header_files.end();
+ ++file)
+ if (!check_file(*file, cerr, "abidw"))
+ return false;
+
+ return true;
+}
+
/// Set suppression specifications to the @p read_context used to load
/// the ABI corpus from the ELF/DWARF file.
///
@@ -371,7 +400,8 @@ set_suppressions(read_context& read_ctxt, options& opts)
read_suppressions(*i, supprs);
suppression_sptr suppr =
- abigail::tools_utils::gen_suppr_spec_from_headers(opts.headers_dir);
+ abigail::tools_utils::gen_suppr_spec_from_headers(opts.headers_dir,
+ opts.header_files);
if (suppr)
supprs.push_back(suppr);
@@ -721,6 +751,9 @@ main(int argc, char* argv[])
if (!maybe_check_suppression_files(opts))
return 1;
+ if (!maybe_check_header_files(opts))
+ return 1;
+
abigail::tools_utils::file_type type =
abigail::tools_utils::guess_file_type(opts.in_file_path);
if (type != abigail::tools_utils::FILE_TYPE_ELF
@@ -86,6 +86,7 @@ struct options
abg_compat::shared_ptr<char> di_root_path;
vector<string> suppression_paths;
string headers_dir;
+ vector<string> header_files;
options()
: display_version(false),
@@ -107,6 +108,8 @@ display_usage(const string& prog_name, ostream& out)
<< " --debug-info-dir <path> the path under which to look for "
<< " --headers-dir|--hd <patch> the path to headers of the elf file\n"
"debug info for the elf <abi-file>\n"
+ << " --header-file|--hf <path> the path to one header of the elf file\n"
+ "debug info for the elf <abi-file>\n"
<< " --suppressions|--suppr <path> specify a suppression file\n"
<< " --diff for xml inputs, perform a text diff between "
"the input and the memory model saved back to disk\n"
@@ -161,6 +164,15 @@ parse_command_line(int argc, char* argv[], options& opts)
opts.headers_dir = argv[j];
++i;
}
+ else if (!strcmp(argv[i], "--header-file")
+ || !strcmp(argv[i], "--hf"))
+ {
+ int j = i + 1;
+ if (j >= argc)
+ return false;
+ opts.header_files.push_back(argv[j]);
+ ++i;
+ }
else if (!strcmp(argv[i], "--suppressions")
|| !strcmp(argv[i], "--suppr"))
{
@@ -240,7 +252,8 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
read_suppressions(*i, supprs);
suppression_sptr suppr =
- abigail::tools_utils::gen_suppr_spec_from_headers(opts.headers_dir);
+ abigail::tools_utils::gen_suppr_spec_from_headers(opts.headers_dir,
+ opts.header_files);
if (suppr)
supprs.push_back(suppr);
@@ -1529,8 +1529,10 @@ maybe_create_private_types_suppressions(package& pkg, const options &opts)
if (!is_dir(headers_path))
return false;
+ // We don't list individual files, just look under the headers_path.
+ vector<string> no_header_files;
suppression_sptr suppr =
- gen_suppr_spec_from_headers(headers_path);
+ gen_suppr_spec_from_headers(headers_path, no_header_files);
if (suppr)
{