public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
From: Giuliano Procida <gprocida@google.com>
To: libabigail@sourceware.org
Cc: dodji@seketeli.org, kernel-team@android.com, gprocida@google.com,
	 maennich@google.com, woodard@redhat.com
Subject: [RFC PATCH 8/9] Add pass to stabilise types and declarations
Date: Thu, 25 Mar 2021 21:51:45 +0000	[thread overview]
Message-ID: <20210325215146.3597963-9-gprocida@google.com> (raw)
In-Reply-To: <20210325215146.3597963-1-gprocida@google.com>

This commit adds a pass which consolidates all types and declarations
within an abi-corpus into a replacement abi-instr. These elements are
then ordered by id and name respectively, with types before
declarations.

	* scripts/abitidy.pl (stabilise_types_and_declarations): New
	function to order types and declarations as deterministically
	as possible within an abi-corpus.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 scripts/abitidy.pl | 84 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)

diff --git a/scripts/abitidy.pl b/scripts/abitidy.pl
index 35b3c054..67fe3a69 100755
--- a/scripts/abitidy.pl
+++ b/scripts/abitidy.pl
@@ -496,6 +496,82 @@ sub report_duplicate_types($dom) {
   }
 }
 
+# Stabilise types and declarations.
+sub stabilise_types_and_declarations($dom) {
+  my $corpus_path = new XML::LibXML::XPathExpression('//abi-corpus');
+  my $instr_path = new XML::LibXML::XPathExpression('abi-instr');
+  my $type_or_decl_path = new XML::LibXML::XPathExpression('*[@id]|*[@name]');
+
+  my @corpora = $dom->findnodes($corpus_path);
+  for my $coprus (@corpora) {
+    # Let's squish it. We expect its abi-instr elements to have
+    # consistent attributes, ignoring path.
+    my %attrs;
+    my @children = $coprus->findnodes($instr_path);
+    for my $child (@children) {
+      for my $attr (keys %$child) {
+        my $value = $child->{$attr};
+        $attrs{$attr}{$value} = undef;
+      }
+    }
+    next unless scalar keys %attrs;
+
+    # Create a replacement abi-instr node.
+    my $replacement = new XML::LibXML::Element('abi-instr');
+    # Original attribute ordering is lost, may as well be deterministic here.
+    for my $attr (sort keys %attrs) {
+      # Check attribute consistency.
+      for my $values ($attrs{$attr}) {
+        if (scalar keys %{$values} > 1) {
+          die "unexpected non-constant abi-instr attribute $attr\n"
+            unless $attr eq 'path' || $attr eq 'comp-dir-path' || $attr eq 'language';
+          $values = { 'various' => undef };
+        }
+        for my $value (keys %$values) {
+          $replacement->setAttribute($attr, $value);
+        }
+      }
+    }
+
+    # Gather sorted types and decls.
+    my @types_and_decls = sort {
+      my $a_id = $a->{id};
+      my $a_name = $a->{name};
+      die unless defined $a_id || defined $a_name;
+      my $b_id = $b->{id};
+      my $b_name = $b->{name};
+      die unless defined $b_id || defined $b_name;
+      # types before declarations
+      # order types by id
+      # order declarations by name
+      defined $a_id != defined $b_id ? !defined $a_id <=> !defined $b_id
+        : defined $a_id ? $a_id cmp $b_id
+        : $a_name cmp $b_name
+    } map { $_->findnodes($type_or_decl_path) } @children;
+
+    # Add them to replacement abi-instr
+    map {
+      my $prev = $_->previousSibling();
+      if ($prev && $prev->nodeType == XML_COMMENT_NODE) {
+        $prev->unbindNode();
+        $replacement->appendChild($prev);
+      }
+      $_->unbindNode();
+      $replacement->appendChild($_)
+    } @types_and_decls;
+    # Remove the old abi-instr nodes.
+    for my $child (@children) {
+      if ($child->hasChildNodes()) {
+        warn "failed to evacuate abi-instr: ", $child->toString(), "\n";
+        next;
+      }
+      remove_node($child);
+    }
+    # Add the replacement abi-instr node to the abi-corpus.
+    $coprus->appendChild($replacement);
+  }
+}
+
 # Parse arguments.
 my $input_opt;
 my $output_opt;
@@ -505,17 +581,19 @@ my $drop_opt;
 my $prune_opt;
 my $normalise_opt;
 my $eliminate_opt;
+my $stabilise_opt;
 my $report_opt;
 GetOptions('i|input=s' => \$input_opt,
            'o|output=s' => \$output_opt,
            's|symbols=s' => \$symbols_opt,
            'a|all' => sub {
-             $drop_opt = $prune_opt = $normalise_opt = $eliminate_opt = $report_opt = 1
+             $drop_opt = $prune_opt = $normalise_opt = $eliminate_opt = $stabilise_opt = $report_opt = 1
            },
            'd|drop-empty!' => \$drop_opt,
            'p|prune-unreachable!' => \$prune_opt,
            'n|normalise-anonymous!' => \$normalise_opt,
            'e|eliminate-duplicates!' => \$eliminate_opt,
+           't|stabilise-order!' => \$stabilise_opt,
            'r|report-duplicates!' => \$report_opt,
   ) and !@ARGV or die("usage: $0",
                       map { (' ', $_) } (
@@ -527,6 +605,7 @@ GetOptions('i|input=s' => \$input_opt,
                         '[-p|--[no-]prune-unreachable]',
                         '[-n|--[no-]normalise-anonymous]',
                         '[-e|--[no-]eliminate-duplicates]',
+                        '[-t|--[no-]stabilise-order]',
                         '[-r|--[no-]report-duplicates]',
                       ), "\n");
 
@@ -555,6 +634,9 @@ report_duplicate_types($dom) if $report_opt;
 # Prune unreachable elements.
 prune_unreachable($dom) if $prune_opt;
 
+# Stabilise types and declarations.
+stabilise_types_and_declarations($dom) if $stabilise_opt;
+
 # Drop empty elements.
 drop_empty($dom) if $drop_opt;
 
-- 
2.31.0.291.g576ba9dcdaf-goog


  parent reply	other threads:[~2021-03-25 21:52 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-11 11:53 [RFC PATCH] Add an experimental ABI pruning utility Giuliano Procida
2021-03-11 20:39 ` Ben Woodard
2021-03-12 16:51   ` Giuliano Procida
2021-03-12 18:41     ` Ben Woodard
2021-03-15 11:08       ` Giuliano Procida
2021-03-12 16:59 ` [RFC PATCH v2] " Giuliano Procida
2021-03-16 16:55   ` [RFC PATCH v3] " Giuliano Procida
2021-03-25 21:51     ` [RFC PATCH 0/9] Utility to manipulate ABI XML Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 1/9] Add ABI tidying utility Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 2/9] Add pass to drop empty XML elements Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 3/9] Add pass to prune unreachable parts of the ABI Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 4/9] Add pass to filter symbols Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 5/9] Add pass to normalise anonymous type names Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 6/9] Add pass to report duplicate type ids Giuliano Procida
2021-03-25 21:51       ` [RFC PATCH 7/9] Add pass to eliminate duplicate member-type fragments Giuliano Procida
2021-03-25 21:51       ` Giuliano Procida [this message]
2021-03-25 21:51       ` [RFC PATCH 9/9] Add pass to resolve stray forward type declarations Giuliano Procida

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210325215146.3597963-9-gprocida@google.com \
    --to=gprocida@google.com \
    --cc=dodji@seketeli.org \
    --cc=kernel-team@android.com \
    --cc=libabigail@sourceware.org \
    --cc=maennich@google.com \
    --cc=woodard@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).