mirror of
git://sourceware.org/git/libabigail.git
synced 2024-12-30 05:42:05 +00:00
a102a2f032
This patch implements the weak mode of abicompat. In this mode, just the application and the new version of the library are provided. The types of functions and variables of the library that are consumed by the application are compared to the types of the functions and variables expected by the application. The goal is to check if the types of the declarations consumed by the application and provided by the library are compatible with what the application expects. The abicompat first gets the set of symbols undefined in the application and exported by the library. It then builds the set of declarations exported by the library that have those symbols. We call these the set of declarations of the library that are consumed by the application. Note that the debug information for the application does not contain the declarations of the functions/variables whose symbols are undefined. So we can not just read them to compare them to declarations exported by the library. But the *types* of the variables and the *sub-types* of the functions whose symbols are undefined in the application are present in the debug information of the application. So in the weak mode, abicompat compare the *types* of the declarations consumed by the application as expected by the application (described by the debug information of the application) with the types of the declarations exported by the library. To do this a number of changes were necessary. The patch builds a representation of all the types found in the application's debug info. Before that, only the types that are reachable from exported declarations were represented. The abidw tool got a new --load-all-types to test this new ability of loading all types. The patch also adds support for looking a type, not by name, but by its internal representation. In the comparison engine, function_type_diff is introduced to represent changes between two function types. For this, a new class type_or_decl_base has been introduced in the IR. It's now the base class for both decl_base and type_base. And abigail::comparison::diff now takes two pointers of type_or_decl, not decl_base anymore. So function_type_diff can take two function_type now; not that a function_type has no declaration so it doesn't inherit decl_base. A bunch of changes got made just to adjust to this modification. A number of fixes were made too, to make this work, like adding missing comparison operators, removing asserts that too strong, etc.. The patch also adjust the test suite as well as the documentation. * include/abg-fwd.h (class type_or_decl_base): Forward declare this. (is_decl, is_type, is_function_type, get_name, get_type_name) (get_function_type_name, get_pretty_representation) (lookup_function_type_in_corpus, lookup_type_in_translation_unit) (lookup_function_type_in_translation_unit) (synthesize_function_type_from_translation_unit) (hash_type_or_decl): New function declarations. * src/abg-corpus.cc (lookup_type_in_corpus) (lookup_function_type_in_corpus): Define new functions. * include/abg-ir.h (translation_unit::lookup_function_type_in_translation_unit): Declare new friend function. (class type_or_decl_base): Declare this. (operator==(const type_or_decl_base&, const type_or_decl_base&)): Declare new operator. (operator==(const type_or_decl_base_sptr&, const type_or_decl_base_sptr&)): Likewise. (class {decl_base, type_base}): Make these class inherit type_or_decl_base. (decl_base::get_member_scopes): New const overload. (bool operator==(const function_decl::parameter_sptr&, const function_decl::parameter_sptr&)): New operator. (function_type::get_parameters): Remove the non-const overload. (function_type::get_pretty_representation): Declare new member function. (method_type::get_pretty_representation): Likewise. * src/abg-ir.cc (bool operator==(const type_or_decl_base&, const type_or_decl_base&)): Define new equality operator. (bool operator==(const type_or_decl_base_sptr&, const type_or_decl_base_sptr&)): Likewise. (strip_typedef): Do not expect canonicalized types anymore. Now the system accepts (and expects) canonicalized types in certain cases. For instance, non-complete types and aggregated types that contain non-complete sub-types. (get_name, get_function_type_name, get_type_name) (get_pretty_representation, is_decl, is_type, is_function_type) (lookup_function_type_in_translation_unit) (synthesize_function_type_from_translation_unit) (lookup_type_in_scope, lookup_type_in_translation_unit): Define new functions or new overloads. (bool operator==(const function_decl::parameter_sptr&, const function_decl::parameter_sptr& r)): Define new operator. (function_type::get_parameters): Remove non-const overload. (function_type::get_pretty_representation): Define new function. (function_type::traverse): Adjust. (method_type::get_pretty_representation): Likewise. (function_decl::get_pretty_representation): Avoid emitting the type of cdtors. (hash_type_or_decl): Define new function. * include/abg-dwarf-reader.h (create_read_context) (read_corpus_from_elf): Take a new 'read_all_types' flag. * src/abg-dwarf-reader.cc (read_context::load_all_types_): New flag. (read_context::read_context): Initialize it. (read_context::canonical_types_scheduled): If some types still have non-canonicalized sub-types, then do not canonicalize them. (read_context::load_all_types): New member functions. (build_function_decl): Do not represent void return type like empty type anymore, rather, represent it like a void type node. (build_ir_node_from_die): When asked, load all types including those that are not reachable from an exported declaration. (create_read_context, read_corpus_from_elf): Take a new 'load_all_types' flag and honour it. * src/abg-reader.cc (read_context::type_is_from_translation_unit): Support looking up function types in the current translation unit, now that we now how to lookup function types. * include/abg-comparison.h (diff_context::{has_diff_for, add_diff, set_canonical_diff_for, set_or_get_canonical_diff_for, get_canonical_diff_for}): Make these take instances of type_or_decl_base_sptr, instead of decl_base_sptr. (diff::diff): Likewise. (diff::{first_subject, second_subject}): Make these return type_or_decl_base_sptr instead of decl_base_sptr. (type_diff_base::type_diff_base): Make these take instances of type_or_decl_base_sptr instead of decl_base_sptr. (distinct_diff::distinct_diff): Likewise. (distinct_diff::{first, second}): Make these return type_or_decl_base_sptr instead of decl_base_sptr. (distinct_diff::entities_are_of_distinct_kinds): Make these take instances of type_or_decl_base_sptr instead of decl_base_sptr. (class function_type_diff): Create this new type. It's a factorization of the function_decl_diff type. * src/abg-comparison.cc (): * src/abg-comp-filter.cc ({harmless, harmful}_filter::visit): Adjust as diff::{first,second}_subject() now returns a type_or_decl_base_sptr, no more a decl_base_sptr. (decls_type, decls_diff_map_type): Remove these typedefs and replace it with ... (types_or_decls_type, types_or_decls_diff_map_type): ... these. (struct {decls_hash, decls_equals): Remove these type sand replace them with ... (struct {types_or_decls_hash, types_or_decls_equals}): ... these. ({type_suppression, variable_suppression}::suppresses_diff): Adjust. (diff_context::priv::decls_diff_map): Replace this with ... (diff_context::priv::types_or_decls_diff_map): ... this. (diff_context::{has_diff_for, add_diff, get_canonical_diff_for, set_canonical_diff_for, set_or_get_canonical_diff_for}): Take type_or_decl_base_sptr instead of decl_base_sptr. (diff::priv::{first, second}_subject): Make the type of these be type_or_decl_base_sptr, no more decl_base_sptr. (diff::priv::priv): Adjust for the subjects of the diff being of type type_or_decl_sptr now, no more decl_base_sptr. (diff_less_than_functor::operator()(const diff_sptr, const diff_sptr) const): Adjust. (diff::diff): djust for the subjects of the diff being of type type_or_decl_sptr now, no more decl_base_sptr. (diff::{first,second}_subject): Make the type of these be type_or_decl_base_sptr, no more decl_base_sptr. (report_size_and_alignment_changes): Likewise. (type_diff_base::type_diff_base): Make the type of this be type_or_decl_base_sptr instead of type_base_sptr. (distinct_diff::distinct_diff): Make this take instances of type_or_decl_base_sptr instead of decl_base_sptr. (distinct_diff::{first, second, entities_are_of_distinct_kinds}): Likewise. (distinct_diff::has_changes): Simplify logic. (distinct_diff::report): Adjust. (compute_diff_for_types): Add an additional case to support the new function_type. (report_size_and_alignment_changes): Make this take instances of type_or_decl_base_sptr instead of decl_base_sptr. (class_diff::priv::member_type_has_changed): Return an instance of type_or_decl_base_sptr rather than a decl_base_sptr. (class_diff::report): Adjust. (diff_comp::operator()(const diff&, diff&) const): Adjust. (enum function_decl_diff::priv::Flags): Remove. (function_decl_diff::priv::{first_fn_flags_, second_fn_flags_, fn_flags_changes_}): Remove. (function_decl_diff::priv::{fn_is_declared_inline_to_flag, fn_binding_to_flag}): Remove. (function_decl_diff::{deleted_parameter_at, inserted_parameter_at}): Remove. (function_decl_diff::ensure_lookup_tables_populated): Empty this. (function_decl_diff::chain_into_hierarchy): Adjust. (function_decl_diff::function_decl_diff): This now only takes the subjects. It's body is now empty. (function_decl_diff::{return_type_diff, subtype_changed_parms, removed_parms, added_parms, type_diff}): Remove these member functions. (function_decl_diff::type_diff): Define new member function. (function_decl_diff::report): Simplify logic by using the reporting of the child type diff node. (compute_diff): Likewise, in the overload for function_decl_sptr simplify logic by using the child type diff object. (function_type_diff::priv): Define new type. (function_type_diff::{function_type_diff, ensure_lookup_tables_populated, deleted_parameter_at, inserted_parameter_at, finish_diff_type, first_function_type, second_function_type, return_type_diff, subtype_changed_parms, removed_parms, added_parms, get_pretty_representation, has_changes, has_local_changes, report, chain_into_hierarchy}): Define new functions. (compute_diff): Define new overload for function_type_sptr. * tools/abicompat.cc (options::weak_mode): New data member. (options::options): Initialize it. (enum abicompat_status): New enum (abicompat_status operator|(abicompat_status, abicompat_status)) (abicompat_status& operator|=(abicompat_status &, abicompat_status)) (abicompat_status operator&(abicompat_status, abicompat_status)): New operators to manipulate the abicompat_status enum. (display_usage): Add help string for the new --weak-mode option. (parse_command_line): Add the new --weak-mode command line argument. If the tool is called with just the application and one library then assume that we are in the weak mode. (perform_compat_check_in_normal_mode): Define new function, factorized from what was in the main function. (perform_compat_check_in_weak_mode): Define new function. (struct {fn,var}_change): Define new types. (main): Use perform_compat_check_in_weak_mode() and perform_compat_check_in_normal_mode(). * tools/abidiff.cc (main): Adjust. * tools/abidw.cc: (options::load_all_types): Add new data member. (options::options): Initialize it. (display_usage): New help string for --load-all-types. (parse_command_line): Support the new --load-all-types option. (main): Adjust and honour the --load-all-types option. * tools/abilint.cc (main): Adjust. * doc/manuals/abicompat.rst: Update documentation for the new weak mode. Also provide stuff that was missing from the examples provided. * doc/manuals/abidw.rst: Update documentation for the new --load-all-types option. * tests/print-diff-tree.cc (main): Adjust. * tests/test-diff-dwarf.cc (main): Likewise. * tests/test-read-dwarf.cc (main): Likewise. * tests/data/test-abicompat/test0-fn-changed-app: Recompile this. * tests/data/test-abicompat/libtest5-fn-changed-libapp-v{0,1}.so: New new test input binaries * tests/data/test-abicompat/test5-fn-changed-app: Likewise. * tests/data/test-abicompat/test6-var-changed-app: Likewise. * tests/data/test-abicompat/libtest6-var-changed-libapp-v{0,1}.so: Likewise. * tests/data/test-abicompat/test5-fn-changed-report-0.txt: Reference output for one test above. * tests/data/test-abicompat/test6-var-changed-report-0.txt: Likewise. * tests/data/test-abicompat/test5-fn-changed-app.cc: Source file for a binary above. * tests/data/test-abicompat/test5-fn-changed-libapp-v{0,1}.{h,cc}: Likewise. * tests/data/test-abicompat/test6-var-changed-libapp-v{0,1}.{cc,h}: Likewise. * tests/data/test-abicompat/test6-var-changed-app.cc: Likewise. * tests/data/Makefile.am: Add the test related files above to the source distribution. * tests/test-abicompat.cc (in_out_spec): Add the new test input above to the list of inputs to feed to this test harness. (main): Support taking just the app and one library. * tests/data/test-read-dwarf/test{0, 1, 2.so, 3.so, 5.o, 8-qualified-this-pointer.so,}.abi: Adjust for void type being really emitted now, as opposed to just being an empty type. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
298 lines
8.9 KiB
C++
298 lines
8.9 KiB
C++
// -*- Mode: C++ -*-
|
|
//
|
|
// Copyright (C) 2013-2015 Red Hat, Inc.
|
|
//
|
|
// This file is part of the GNU Application Binary Interface Generic
|
|
// Analysis and Instrumentation Library (libabigail). This library is
|
|
// free software; you can redistribute it and/or modify it under the
|
|
// terms of the GNU Lesser General Public License as published by the
|
|
// Free Software Foundation; either version 3, or (at your option) any
|
|
// later version.
|
|
|
|
// This library is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// General Lesser Public License for more details.
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this program; see the file COPYING-LGPLV3. If
|
|
// not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// Author: Dodji Seketeli
|
|
|
|
/// @file
|
|
///
|
|
/// This program runs a diff between input dwarf files and compares
|
|
/// the resulting report with a reference report. If the resulting
|
|
/// report is different from the reference report, the test has
|
|
/// failed. Note that the comparison is done using the libabigail
|
|
/// library directly.
|
|
///
|
|
/// The set of input files and reference reports to consider should be
|
|
/// present in the source distribution.
|
|
|
|
#include <string>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <cstdlib>
|
|
#include "abg-tools-utils.h"
|
|
#include "test-utils.h"
|
|
#include "abg-dwarf-reader.h"
|
|
#include "abg-comparison.h"
|
|
|
|
using std::string;
|
|
using std::ofstream;
|
|
using std::cerr;
|
|
|
|
/// This is an aggregate that specifies where a test shall get its
|
|
/// input from and where it shall write its ouput to.
|
|
struct InOutSpec
|
|
{
|
|
const char* in_elfv0_path;
|
|
const char* in_elfv1_path;
|
|
const char* in_report_path;
|
|
const char* out_report_path;
|
|
};// end struct InOutSpec
|
|
|
|
InOutSpec in_out_specs[] =
|
|
{
|
|
{
|
|
"data/test-diff-dwarf/test0-v0.o",
|
|
"data/test-diff-dwarf/test0-v1.o",
|
|
"data/test-diff-dwarf/test0-report.txt",
|
|
"output/test-diff-dwarf/test0-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test1-v0.o",
|
|
"data/test-diff-dwarf/test1-v1.o",
|
|
"data/test-diff-dwarf/test1-report.txt",
|
|
"output/test-diff-dwarf/test1-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test2-v0.o",
|
|
"data/test-diff-dwarf/test2-v1.o",
|
|
"data/test-diff-dwarf/test2-report.txt",
|
|
"output/test-diff-dwarf/test2-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test3-v0.o",
|
|
"data/test-diff-dwarf/test3-v1.o",
|
|
"data/test-diff-dwarf/test3-report.txt",
|
|
"output/test-diff-dwarf/test3-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test3-v0.o",
|
|
"data/test-diff-dwarf/test3-v1.o",
|
|
"data/test-diff-dwarf/test3-report.txt",
|
|
"output/test-diff-dwarf/test3-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test4-v0.o",
|
|
"data/test-diff-dwarf/test4-v1.o",
|
|
"data/test-diff-dwarf/test4-report.txt",
|
|
"output/test-diff-dwarf/test4-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test5-v0.o",
|
|
"data/test-diff-dwarf/test5-v1.o",
|
|
"data/test-diff-dwarf/test5-report.txt",
|
|
"output/test-diff-dwarf/test5-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test6-v0.o",
|
|
"data/test-diff-dwarf/test6-v1.o",
|
|
"data/test-diff-dwarf/test6-report.txt",
|
|
"output/test-diff-dwarf/test6-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test7-v0.o",
|
|
"data/test-diff-dwarf/test7-v1.o",
|
|
"data/test-diff-dwarf/test7-report.txt",
|
|
"output/test-diff-dwarf/test7-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test8-v0.o",
|
|
"data/test-diff-dwarf/test8-v1.o",
|
|
"data/test-diff-dwarf/test8-report.txt",
|
|
"output/test-diff-dwarf/test8-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest9-v0.so",
|
|
"data/test-diff-dwarf/libtest9-v1.so",
|
|
"data/test-diff-dwarf/test9-report.txt",
|
|
"output/test-diff-dwarf/test9-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test10-v0.o",
|
|
"data/test-diff-dwarf/test10-v1.o",
|
|
"data/test-diff-dwarf/test10-report.txt",
|
|
"output/test-diff-dwarf/test10-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test11-v0.o",
|
|
"data/test-diff-dwarf/test11-v1.o",
|
|
"data/test-diff-dwarf/test11-report.txt",
|
|
"output/test-diff-dwarf/test11-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest12-v0.so",
|
|
"data/test-diff-dwarf/libtest12-v1.so",
|
|
"data/test-diff-dwarf/test12-report.txt",
|
|
"output/test-diff-dwarf/test12-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test13-v0.o",
|
|
"data/test-diff-dwarf/test13-v1.o",
|
|
"data/test-diff-dwarf/test13-report.txt",
|
|
"output/test-diff-dwarf/test13-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test14-inline-v0.o",
|
|
"data/test-diff-dwarf/test14-inline-v1.o",
|
|
"data/test-diff-dwarf/test14-inline-report.txt",
|
|
"output/test-diff-dwarf/test14-inline-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test15-enum-v0.o",
|
|
"data/test-diff-dwarf/test15-enum-v1.o",
|
|
"data/test-diff-dwarf/test15-enum-report.txt",
|
|
"output/test-diff-dwarf/test15-enum-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test16-syms-only-v0.o",
|
|
"data/test-diff-dwarf/test16-syms-only-v1.o",
|
|
"data/test-diff-dwarf/test16-syms-only-report.txt",
|
|
"output/test-diff-dwarf/test16-syms-only-report.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/test17-non-refed-syms-v0.o",
|
|
"data/test-diff-dwarf/test17-non-refed-syms-v1.o",
|
|
"data/test-diff-dwarf/test17-non-refed-syms-report-0.txt",
|
|
"output/test-diff-dwarf/test17-non-refed-syms-report-0.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest18-alias-sym-v0.so",
|
|
"data/test-diff-dwarf/libtest18-alias-sym-v1.so",
|
|
"data/test-diff-dwarf/test18-alias-sym-report-0.txt",
|
|
"output/test-diff-dwarf/test18-alias-sym-report-0.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest19-soname-v0.so",
|
|
"data/test-diff-dwarf/libtest19-soname-v1.so",
|
|
"data/test-diff-dwarf/test19-soname-report-0.txt",
|
|
"output/test-diff-dwarf/test19-soname-report-0.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest20-add-fn-parm-v0.so",
|
|
"data/test-diff-dwarf/libtest20-add-fn-parm-v1.so",
|
|
"data/test-diff-dwarf/test20-add-fn-parm-report-0.txt",
|
|
"output/test-diff-dwarf/test20-add-fn-parm-report-0.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest21-redundant-fn-v0.so",
|
|
"data/test-diff-dwarf/libtest21-redundant-fn-v1.so",
|
|
"data/test-diff-dwarf/test21-redundant-fn-report-0.txt",
|
|
"output/test-diff-dwarf/test21-redundant-fn-report-0.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest22-changed-parm-c-v0.so",
|
|
"data/test-diff-dwarf/libtest22-changed-parm-c-v1.so",
|
|
"data/test-diff-dwarf/test22-changed-parm-c-report-0.txt",
|
|
"output/test-diff-dwarf/test22-changed-parm-c-report-0.txt"
|
|
},
|
|
{
|
|
"data/test-diff-dwarf/libtest-23-diff-arch-v0-32.so",
|
|
"data/test-diff-dwarf/libtest-23-diff-arch-v0-64.so",
|
|
"data/test-diff-dwarf/test-23-diff-arch-report-0.txt",
|
|
"output/test-diff-dwarf/test-23-diff-arch-report-0.txt"
|
|
},
|
|
// This should be the last entry
|
|
{NULL, NULL, NULL, NULL}
|
|
};
|
|
|
|
int
|
|
main()
|
|
{
|
|
using abigail::tests::get_src_dir;
|
|
using abigail::tests::get_build_dir;
|
|
using abigail::tools_utils::ensure_parent_dir_created;
|
|
using abigail::dwarf_reader::read_corpus_from_elf;
|
|
using abigail::comparison::compute_diff;
|
|
using abigail::comparison::corpus_diff_sptr;
|
|
|
|
bool is_ok = true;
|
|
string in_elfv0_path, in_elfv1_path,
|
|
ref_diff_report_path, out_diff_report_path;
|
|
abigail::corpus_sptr corp0, corp1;
|
|
|
|
for (InOutSpec* s = in_out_specs; s->in_elfv0_path; ++s)
|
|
{
|
|
in_elfv0_path = get_src_dir() + "/tests/" + s->in_elfv0_path;
|
|
in_elfv1_path = get_src_dir() + "/tests/" + s->in_elfv1_path;
|
|
out_diff_report_path = get_build_dir() + "/tests/" + s->out_report_path;
|
|
|
|
if (!ensure_parent_dir_created(out_diff_report_path))
|
|
{
|
|
cerr << "could not create parent directory for "
|
|
<< out_diff_report_path;
|
|
is_ok = false;
|
|
continue;
|
|
}
|
|
|
|
read_corpus_from_elf(in_elfv0_path,
|
|
/*debug_info_root_path=*/0,
|
|
/*load_all_types=*/false,
|
|
corp0);
|
|
read_corpus_from_elf(in_elfv1_path,
|
|
/*debug_info_root_path=*/0,
|
|
/*load_all_types=*/false,
|
|
corp1);
|
|
|
|
if (!corp0)
|
|
{
|
|
cerr << "failed to read " << in_elfv0_path << "\n";
|
|
is_ok = false;
|
|
continue;
|
|
}
|
|
if (!corp1)
|
|
{
|
|
cerr << "failed to read " << in_elfv1_path << "\n";
|
|
is_ok = false;
|
|
continue;
|
|
}
|
|
|
|
corp0->set_path(s->in_elfv0_path);
|
|
corp1->set_path(s->in_elfv1_path);
|
|
|
|
corpus_diff_sptr d = compute_diff(corp0, corp1);
|
|
if (!d)
|
|
{
|
|
cerr << "failed to compute diff\n";
|
|
is_ok = false;
|
|
continue;
|
|
}
|
|
|
|
ref_diff_report_path = get_src_dir() + "/tests/" + s->in_report_path;
|
|
out_diff_report_path = get_build_dir() + "/tests/" + s->out_report_path;
|
|
|
|
ofstream of(out_diff_report_path.c_str(), std::ios_base::trunc);
|
|
if (!of.is_open())
|
|
{
|
|
cerr << "failed to read " << out_diff_report_path << "\n";
|
|
is_ok = false;
|
|
continue;
|
|
}
|
|
|
|
if (d->has_changes())
|
|
d->report(of);
|
|
of.close();
|
|
|
|
string cmd =
|
|
"diff -u " + ref_diff_report_path + " " + out_diff_report_path;
|
|
if (system(cmd.c_str()))
|
|
is_ok = false;
|
|
}
|
|
|
|
return !is_ok;
|
|
}
|