Package: dpkg-dev
Version: 1.15.0
Severity: wishlist
Tags: patch

Hello,

when writing a tool which deals with C++ symbols, I found that feature like
this would be very useful. You will find the full description in the attached
patch header (also copy&pasted below). Just to give you an idea of the real
world usage for this:

MISSING - current use of deprecated symbols.
DEPRECATED - could be used for a few multiarch specific symbols which symbol
file preprocessor could turn into normal symbols under certain conditions.
(this is just an example, I know about that #include is different but limited
way to do it).
PRIVATE - C++ template instantiations and other exported private symbols
(i.e. those which cannot be found in the headers).

The patch is against current master branch. Patch description follows:
--
Up until now, all deprecated symbols were treated equally as MISSING.
DEPRECATED was a synomym of MISSING. This patch changes sematics of
DEPRECATED a bit and adds a new type - PRIVATE. Also types are
preserved between symbol file load() and dump(). Descriptions of the
deprecation types follow:

MISSING - the symbol is typically declared as MISSING if it can no longer
          be found in the object file itself. If that symbol reappears
          suddently, it gets undeprecated and its minimal version is
          bumped to the current version of the object. MISSING symbols
          are never removed from the symbols file automatically. MISSING
          used to be a default deprecation type in the earlier versions of
          dpkg, hence it is kept fully compatible.
DEPRECATED - it is similar to MISSING with the exception that if the
             symbol reappears, its minimal version is kept as it is
             instead of being bumped. DEPRECATED could be used to mark
             symbols as optional for whatever the reason. dpkg-gensymbols
             will still display reappearing DEPRECATED symbols in the diff
             as it does with MISSING.
PRIVATE - useful for marking private symbols which have been falsely
          exported to the dynamic symbol table by the compiler (e.g. C++).
          Private symbols are optional, they stay deprecated even if the
          object file actually have them and they get automatically removed
          from the symbol file when they disappear from the object file.

DEPRECATED and PRIVATE are for manual or for 3rd party tool use.
Dpkg::Shlibs::SymbolFile never changes symbol type to DEPRECATED or PRIVATE.
It only marks symbols as MISSING as needed.

The patch also adds 'export_private' option to dump() which allows to dump
private symbols as normal ones (defaults to OFF). dpkg-gensymbols enables
this option when exporting symbols files to DEBIAN/symbols but disables
it when diff'ing.
---

Also current master needs the fix below for man/po/de.po to build:

diff --git a/man/po/de.po b/man/po/de.po
index c8637d9..63aa7e0 100644
--- a/man/po/de.po
+++ b/man/po/de.po
@@ -9138,7 +9138,7 @@ msgstr ""
 #, no-wrap
 msgid "I<binary>B< contains an unresolvable reference to symbol >I<sym>B<: 
it's probably a plugin>"
 msgstr ""
-"I<Programm>B< enthält eine nicht-auflösbare Referenz auf Symbol I<Sym>B<: 
wahrscheinlich eine Erweiterung>."
+"I<Programm>B< enthält eine nicht-auflösbare Referenz auf Symbol >I<Sym>B<: 
wahrscheinlich eine Erweiterung>."
 
 # type: Plain text
 #: ../../man/dpkg-shlibdeps.1:251


-- System Information:
Debian Release: squeeze/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (101, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.29-1-amd64 (SMP w/1 CPU core)
Locale: LANG=lt_LT.UTF-8, LC_CTYPE=lt_LT.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages dpkg-dev depends on:
ii  binutils                      2.19.1-1   The GNU assembler, linker and bina
ii  bzip2                         1.0.5-1    high-quality block-sorting file co
ii  cpio                          2.9.90-3   GNU cpio -- a program to manage ar
ii  dpkg                          1.14.25    Debian package management system
ii  libtimedate-perl              1.1600-9   Time and date functions for Perl
ii  lzma                          4.43-14    Compression method of 7z format in
ii  make                          3.81-5     The GNU version of the "make" util
ii  patch                         2.5.9-5    Apply a diff file to an original
ii  perl [perl5]                  5.10.0-19  Larry Wall's Practical Extraction 
ii  perl-modules                  5.10.0-19  Core Perl modules

Versions of packages dpkg-dev recommends:
ii  build-essential               11.4       Informational list of build-essent
ii  gcc [c-compiler]              4:4.3.3-2  The GNU C compiler
ii  gcc-4.1 [c-compiler]          4.1.2-25   The GNU C compiler
ii  gcc-4.3 [c-compiler]          4.3.3-5    The GNU C compiler

Versions of packages dpkg-dev suggests:
pn  debian-keyring                <none>     (no description available)
ii  gnupg                         1.4.9-4    GNU privacy guard - a free PGP rep

-- no debconf information
>From 2593032aef16f5813584d9fe10e7b0636ed6ae93 Mon Sep 17 00:00:00 2001
From: Modestas Vainius <modes...@vainius.eu>
Date: Sat, 28 Mar 2009 13:59:56 +0200
Subject: [PATCH] Introduce different types of deprecation.

Up until now, all deprecated symbols were treated equally as MISSING.
DEPRECATED was a synomym of MISSING. This patch changes sematics of
DEPRECATED a bit and adds a new type - PRIVATE. Also types are
preserved between symbol file load() and dump(). Descriptions of the
deprecation types follow:

MISSING - the symbol is typically declared as MISSING if it can no longer
          be found in the object file itself. If that symbol reappears
          suddently, it gets undeprecated and its minimal version is
          bumped to the current version of the object. MISSING symbols
          are never removed from the symbols file automatically. MISSING
          used to be a default deprecation type in the earlier versions of
          dpkg, hence it is kept fully compatible.
DEPRECATED - it is similar to MISSING with the exception that if the
             symbol reappears, its minimal version is kept as it is
             instead of being bumped. DEPRECATED could be used to mark
             symbols as optional for whatever the reason. dpkg-gensymbols
             will still display reappearing DEPRECATED symbols in the diff
             as it does with MISSING.
PRIVATE - useful for marking private symbols which have been falsely
          exported to the dynamic symbol table by the compiler (e.g. C++).
          Private symbols are optional, they stay deprecated even if the
          object file actually have them and they get automatically removed
          from the symbol file when they disappear from the object file.

DEPRECATED and PRIVATE are for manual or for 3rd party tool use.
Dpkg::Shlibs::SymbolFile never changes symbol type to DEPRECATED or PRIVATE.
It only marks symbols as MISSING as needed.

The patch also adds 'export_private' option to dump() which allows to dump
private symbols as normal ones (defaults to OFF). dpkg-gensymbols enables
this option when exporting symbols files to DEBIAN/symbols but disables
it when diff'ing.

Signed-off-by: Modestas Vainius <modes...@vainius.eu>
---
 scripts/Dpkg/Shlibs/SymbolFile.pm |   50 +++++++++++++++++++++++-----------
 scripts/dpkg-gensymbols.pl        |    8 +++---
 scripts/t/200_Dpkg_Shlibs.t       |   54 +++++++++++++++++++++++++++++++-----
 3 files changed, 84 insertions(+), 28 deletions(-)

diff --git a/scripts/Dpkg/Shlibs/SymbolFile.pm 
b/scripts/Dpkg/Shlibs/SymbolFile.pm
index 4bd5bc8..0d5f895 100644
--- a/scripts/Dpkg/Shlibs/SymbolFile.pm
+++ b/scripts/Dpkg/Shlibs/SymbolFile.pm
@@ -129,7 +129,8 @@ sub load {
            my $sym = {
                minver => $2,
                dep_id => defined($3) ? $3 : 0,
-               deprecated => 0
+               type => '',
+               deprecated => 0,
            };
            if ($name =~ /^\*@(.*)$/) {
                error(_g("you can't use wildcards on unversioned symbols: %s"), 
$_) if $1 eq "Base";
@@ -142,13 +143,14 @@ sub load {
            my $dir = $file;
            $dir =~ s{[^/]+$}{}; # Strip filename
            $self->load("$dir$filename", $seen, $current_object_ref);
-       } elsif (/^#(?:DEPRECATED|MISSING): 
([^#]+)#\s*(\S+)\s(\S+)(?:\s(\d+))?/) {
+       } elsif (/^#(DEPRECATED|MISSING|PRIVATE): 
([^#]+)#\s*(\S+)\s(\S+)(?:\s(\d+))?/) {
            my $sym = {
-               minver => $3,
-               dep_id => defined($4) ? $4 : 0,
-               deprecated => $1
+               minver => $4,
+               dep_id => defined($5) ? $5 : 0,
+               type => $1,
+               deprecated => $2,
            };
-           $self->{objects}{$object}{syms}{$2} = $sym;
+           $self->{objects}{$object}{syms}{$3} = $sym;
        } elsif (/^#/) {
            # Skip possible comments
        } elsif (/^\|\s*(.*)$/) {
@@ -203,6 +205,7 @@ sub save {
 
 sub dump {
     my ($self, $fh, %opts) = @_;
+    $opts{export_private} = 0 unless exists $opts{export_private};
     $opts{with_deprecated} = 1 unless exists $opts{with_deprecated};
     foreach my $soname (sort keys %{$self->{objects}}) {
        my @deps = @{$self->{objects}{$soname}{deps}};
@@ -221,8 +224,11 @@ sub dump {
         }
        foreach my $sym (sort keys %{$self->{objects}{$soname}{syms}}) {
            my $info = $self->{objects}{$soname}{syms}{$sym};
-           next if $info->{deprecated} and not $opts{with_deprecated};
-           print $fh "#MISSING: $info->{deprecated}#" if $info->{deprecated};
+           if (!($opts{export_private} && $info->{type} eq 'PRIVATE')) {
+               next if $info->{deprecated} and not $opts{with_deprecated};
+               print $fh "#", ($info->{type}) ? $info->{type} : 'MISSING',
+                   ": $info->{deprecated}#" if ($info->{deprecated});
+           }
            print $fh " $sym $info->{minver}";
            print $fh " $info->{dep_id}" if $info->{dep_id};
            print $fh "\n";
@@ -256,11 +262,17 @@ sub merge_symbols {
        if (exists $obj->{syms}{$sym}) {
            # If the symbol is already listed in the file
            my $info = $obj->{syms}{$sym};
-           if ($info->{deprecated}) {
-               # Symbol reappeared somehow
+           # Don't touch the symbol if it is private
+           if ($info->{deprecated} && $info->{type} ne 'PRIVATE') {
+               my $dtype = $info->{type};
+               # Undeprecate it
                $info->{deprecated} = 0;
-               $info->{minver} = $minver;
-               next;
+               $info->{type} = '';
+               if ($dtype eq 'MISSING') {
+                   # Missing symbol reappeared somehow. Bump minver.
+                   $info->{minver} = $minver;
+                   next;
+               } # Version of DEPRECATED symbols is not bumped
            }
            # We assume that the right dependency information is already
            # there.
@@ -280,6 +292,7 @@ sub merge_symbols {
                $info = {
                    minver => $minver,
                    deprecated => 0,
+                   type => '',
                    dep_id => 0
                };
            }
@@ -292,12 +305,17 @@ sub merge_symbols {
     # the symbol was introduced)
     foreach my $sym (keys %{$self->{objects}{$soname}{syms}}) {
        if (! exists $dynsyms{$sym}) {
-           # Do nothing if already deprecated
-           next if $self->{objects}{$soname}{syms}{$sym}{deprecated};
-
            my $info = $self->{objects}{$soname}{syms}{$sym};
+           if ($info->{deprecated}) {
+               # Just remove no longer existing private symbols
+               if ($info->{type} eq 'PRIVATE') {
+                   delete $self->{objects}{$soname}{syms}{$sym};
+               }
+               next;
+           }
            if (vercmp($minver, $info->{minver}) > 0) {
-               $self->{objects}{$soname}{syms}{$sym}{deprecated} = $minver;
+               $info->{deprecated} = $minver;
+               $info->{type} = 'MISSING';
            }
        }
     }
diff --git a/scripts/dpkg-gensymbols.pl b/scripts/dpkg-gensymbols.pl
index bebe0f7..3beccab 100755
--- a/scripts/dpkg-gensymbols.pl
+++ b/scripts/dpkg-gensymbols.pl
@@ -189,7 +189,7 @@ $symfile->clear_except(keys %{$od->{objects}});
 # Write out symbols files
 if ($stdout) {
     $output = "standard output";
-    $symfile->save("-", package => $oppackage);
+    $symfile->save("-", package => $oppackage, export_private => 1);
 } else {
     unless (defined($output)) {
        unless($symfile->is_empty()) {
@@ -199,7 +199,7 @@ if ($stdout) {
     }
     if (defined($output)) {
        print "Storing symbols in $output.\n" if $debug;
-       $symfile->save($output, package => $oppackage);
+       $symfile->save($output, package => $oppackage, export_private => 1);
     } else {
        print "No symbol information to store.\n" if $debug;
     }
@@ -253,8 +253,8 @@ if ($compare) {
        # and after
        my $before = File::Temp->new(TEMPLATE=>'dpkg-gensymbolsXXXXXX');
        my $after = File::Temp->new(TEMPLATE=>'dpkg-gensymbolsXXXXXX');
-       $ref_symfile->dump($before, package => $oppackage);
-        $symfile->dump($after, package => $oppackage);
+       $ref_symfile->dump($before, package => $oppackage, export_private => 0);
+        $symfile->dump($after, package => $oppackage, export_private => 0);
        seek($before, 0, 0); seek($after, 0, 0);
        my ($md5_before, $md5_after) = (Digest::MD5->new(), Digest::MD5->new());
        $md5_before->addfile($before);
diff --git a/scripts/t/200_Dpkg_Shlibs.t b/scripts/t/200_Dpkg_Shlibs.t
index 8da5d6a..453b579 100644
--- a/scripts/t/200_Dpkg_Shlibs.t
+++ b/scripts/t/200_Dpkg_Shlibs.t
@@ -1,6 +1,6 @@
 # -*- mode: cperl;-*-
 
-use Test::More tests => 39;
+use Test::More tests => 43;
 use IO::String;
 
 use strict;
@@ -105,6 +105,23 @@ $sym_file_old->merge_symbols($obj_old, "2.3.6.ds1-13");
 
 ok( $sym_file->has_object('libc.so.6'), 'SONAME in sym file' );
 
+# Initialize testing for deprecation types
+my $deprecated_sym = 'p...@glibc_2.0';
+my $private_sym = 'g...@glibc_2.0';
+my $private_gone_sym = '__libc_cr...@glibc_private';
+
+sub set_deprecation_types {
+    my $syms = shift()->{objects}{'libc.so.6'}{syms};
+    $syms->{$deprecated_sym}{deprecated} = 'optional';
+    $syms->{$deprecated_sym}{type} = 'DEPRECATED';
+    $syms->{$private_sym}{deprecated} = 'internal';
+    $syms->{$private_sym}{type} = 'PRIVATE';
+    $syms->{$private_gone_sym}{deprecated} = 'disappearing PRIVATE';
+    $syms->{$private_gone_sym}{type} = 'PRIVATE';
+}
+set_deprecation_types($sym_file);
+set_deprecation_types($sym_file_old);
+
 $sym_file->merge_symbols($obj, "2.6-1");
 
 ok( $sym_file->get_new_symbols($sym_file_old), 'has new symbols' );
@@ -115,8 +132,21 @@ is( $sym_file_old->lookup_symbol('__bss_st...@base', 
['libc.so.6']),
 
 $sym = $sym_file->lookup_symbol('_er...@glibc_2.0', ['libc.so.6'], 1);
 is_deeply($sym, { 'minver' => '2.3.6.ds1-13', 'dep_id' => 0, 
-                 'deprecated' => '2.6-1', 'depends' => '', 
-                 'soname' => 'libc.so.6' }, 'deprecated symbol');
+                 'type' => 'MISSING', 'deprecated' => '2.6-1', 'depends' => 
'', 
+                 'soname' => 'libc.so.6' }, 'deprecated MISSING symbol');
+
+$sym = $sym_file->lookup_symbol($deprecated_sym, ['libc.so.6'], 1);
+is_deeply($sym, { 'minver' => '2.3.6.ds1-13', 'dep_id' => 0, 
+                 'type' => '', 'deprecated' => 0, 'depends' => '', 
+                 'soname' => 'libc.so.6' }, 'deprecated DEPRECATED symbol');
+
+$sym = $sym_file->lookup_symbol($private_sym, ['libc.so.6'], 1);
+is_deeply($sym, { 'minver' => '2.3.6.ds1-13', 'dep_id' => 0, 
+                 'type' => 'PRIVATE', 'deprecated' => 'internal', 'depends' => 
'', 
+                 'soname' => 'libc.so.6' }, 'deprecated PRIVATE symbol');
+
+is( $sym_file->lookup_symbol($private_gone_sym, ['libc.so.6'], 1),
+    undef, 'missing PRIVATE is gone after merge');
 
 use File::Temp;
 
@@ -129,26 +159,34 @@ $sym_file_dup->{file} = "$srcdir/symbol_file.tmp";
 
 is_deeply($sym_file_dup, $sym_file, 'save -> load' );
 
+# Test dump( export_private=>1 ). $private_sym should be normal now
+$sym_file->save($save_file->filename, export_private => 1);
+$sym_file_dup = Dpkg::Shlibs::SymbolFile->new($save_file->filename);
+$sym = $sym_file_dup->lookup_symbol($private_sym, ['libc.so.6'], 0);
+is_deeply($sym, { 'minver' => '2.3.6.ds1-13', 'dep_id' => 0, 
+                 'type' => '', 'deprecated' => 0, 'depends' => '', 
+                 'soname' => 'libc.so.6' }, 'dump(export_private=>1)');
+
 # Test include mechanism of SymbolFile
 $sym_file = Dpkg::Shlibs::SymbolFile->new("$srcdir/symbols.include-1");
 
 $sym = $sym_file->lookup_symbol('symbol_bef...@base', ['libfake.so.1']);
-is_deeply($sym, { 'minver' => '0.9', 'dep_id' => 0, 'deprecated' => 0,
+is_deeply($sym, { 'minver' => '0.9', 'dep_id' => 0, 'deprecated' => 0, type => 
'',
                  'depends' => 'libfake1 #MINVER#', 'soname' => 'libfake.so.1' 
}, 
            'symbol before include not lost');
 
 $sym = $sym_file->lookup_symbol('symbol_af...@base', ['libfake.so.1']);
-is_deeply($sym, {'minver' => '1.1', 'dep_id' => 0, 'deprecated' => 0, 
+is_deeply($sym, {'minver' => '1.1', 'dep_id' => 0, 'deprecated' => 0, type => 
'',
                  'depends' => 'libfake1 #MINVER#', 'soname' => 'libfake.so.1' 
}, 
            'symbol after include not lost');
 
 $sym = $sym_file->lookup_symbol('symbol1_fa...@base', ['libfake.so.1']);
-is_deeply($sym, {'minver' => '1.0', 'dep_id' => 0, 'deprecated' => 0, 
+is_deeply($sym, {'minver' => '1.0', 'dep_id' => 0, 'deprecated' => 0, type => 
'', 
                  'depends' => 'libfake1 #MINVER#', 'soname' => 'libfake.so.1' 
}, 
            'overrides order with #include');
 
 $sym = $sym_file->lookup_symbol('symbol3_fa...@base', ['libfake.so.1']);
-is_deeply($sym, { 'minver' => '0', 'dep_id' => 0, 'deprecated' => 0,
+is_deeply($sym, { 'minver' => '0', 'dep_id' => 0, 'deprecated' => 0, type => 
'',
                  'depends' => 'libfake1 #MINVER#', 'soname' => 'libfake.so.1' 
}, 
            'overrides order with #include');
 
@@ -158,7 +196,7 @@ is($sym_file->get_smallest_version('libfake.so.1'), "0",
 $sym_file = Dpkg::Shlibs::SymbolFile->new("$srcdir/symbols.include-2");
 
 $sym = $sym_file->lookup_symbol('symbol1_fa...@base', ['libfake.so.1']);
-is_deeply($sym, { 'minver' => '1.0', 'dep_id' => 1, 'deprecated' => 0,
+is_deeply($sym, { 'minver' => '1.0', 'dep_id' => 1, 'deprecated' => 0, type => 
'',
                  'depends' => 'libvirtualfake', 'soname' => 'libfake.so.1' }, 
            'overrides order with circular #include');
 
-- 
1.6.2.1

Reply via email to