#!/bin/sh -ef
export LC_ALL=C

cd "${workdir:?}"
rpmelfsym "$@" >sym
awk -F'\t' '$3~/[A-TV-Z]/#^U' sym >def
awk -F'\t' '$3~/[Uvw]/' sym >refw
awk -F'\t' '$3~/[U]/' refw >ref

rpmsoname "$@" >sonames
sort -t$'\t' -k2 -o sonames sonames
sort -t$'\t' -k2 -o def def
# sodef ::= pkg libpath soname T sym
join -t$'\t' -j 2 -o '1.1 2.1 1.2 1.3 2.3 2.4' sonames def |
	awk -F'\t' '$1==$2' |cut -f2- >sodef
sort -t$'\t' -k5 -o sodef sodef
	
rpmelfneed "$@" >elfneed
sort -t$'\t' -k2 -o elfneed elfneed
sort -t$'\t' -k2 -o refw refw
# soref [pipe] ::= pkg bin soname sym
# joined ::= pkg bin libpkg libpath soname T sym
join -t$'\t' -j 2 -o '1.1 2.1 1.2 2.3 1.4' refw elfneed |
	awk -F'\t' '$1==$2' |cut -f2- |sort -t$'\t' -T. -k4 |
		join -t$'\t' -14 -25 -o '1.1 1.2 1.3 2.1 2.2 2.3 2.4 2.5' - sodef |
			awk -F'\t' '$3==$6' |cut -f-2,4- >joined
# sort must have failed
[ -s joined ]

sort -o ref -u ref
awk -F'\t' 'BEGIN{OFS=FS}{print$1,$2,"U",$NF}' joined |sort -u |
	comm -23 ref - >unjoined

# what if some symbols map to a few sonames?
awk -F'\t' 'BEGIN{OFS=FS}{print$3,$4,$5,$6,$1,$2,$7}' joined |
	sort -t$'\t' -k3,7 -k2,2 -k1,1r |sort -t$'\t' -u -k3,7 |sort -t$'\t' -k5,7 |uniq -D -f4 |
		awk -F'\t' 'BEGIN{OFS=FS}{print$5,$6,$1,$2,$3,$4,$7}' >multijoined

# elfneed = realneed + unneed
cut -f-2,5 joined >realneed
sort -o elfneed -u elfneed
sort -o realneed -u realneed
comm -23 elfneed realneed >unneed.all

sort -t$'\t' -k3 -o sonames sonames
sort -t$'\t' -k3 -o unneed.all unneed.all
join -t$'\t' -j 3 -o '1.1 1.2 1.3' unneed.all sonames |sort -u >unneed


cd - >/dev/null

: <<'__EOF__'

=head1	NAME

linkage_problems - observe possible linkage problems in RPM repo

=head1	SYNOPSIS

workdir=$PWD linkage_problems -p $sisyphus/files/i586/RPMS

=head1	DESCRIPTION

Warning: you must provide 4G capable I<workdir>.

Possible linkage problems are:

=over

=item	unjoined

I.e. undefined symbol is not resolved into any shared library the binary is linked against.
Note: this is similar to B<bad_elf_symbols> but is a lot more rigorous.
Example:

    libcdf    /usr/lib/libcdf_idl.so.0.0.0    U    IDL_MakeTempArray
    libcdf    /usr/lib/libcdf_idl.so.0.0.0    U    IDL_StoreScalar
    libcdf    /usr/lib/libcdf_idl.so.0.0.0    U    IDL_StrDelete
    libcdf    /usr/lib/libcdf_idl.so.0.0.0    U    IDL_StrStore
    libcdf    /usr/lib/libcdf_idl.so.0.0.0    U    IDL_VarCopy

Basically it is impossible to link with this shared library and/or use it:

    $ ldd -r /usr/lib/libcdf_idl.so.0.0.0
            linux-gate.so.1 =>  (0xffffe000)
            libc.so.6 => /lib/i686/libc.so.6 (0xb7e77000)
            /lib/ld-linux.so.2 (0x80000000)
    undefined symbol: IDL_StoreScalar       (/usr/lib/libcdf_idl.so.0.0.0)
    undefined symbol: IDL_VarCopy   (/usr/lib/libcdf_idl.so.0.0.0)
    undefined symbol: IDL_StrStore  (/usr/lib/libcdf_idl.so.0.0.0)
    undefined symbol: IDL_StrDelete (/usr/lib/libcdf_idl.so.0.0.0)
    undefined symbol: IDL_MakeTempArray     (/usr/lib/libcdf_idl.so.0.0.0)
    $

Here is more subtle problem:

    chess    /usr/bin/gnuchess    U    add_history
    chess    /usr/bin/gnuchess    U    using_history

gnuchess is linked with libreadline.so.4.3, while libreadline.so.4.3 is linked
with libhistory.so.4.3; the latter provides add_history() and using_history(),
so the linker does not complain.  However symbol versionig is possibly broken.

=item	multijoined

I.e. undefined symbol is resolved into a few shared libraries the binary is linked against.
Example:

    AutoScan    /usr/bin/AutoScan    libxml     /usr/lib/libxml.so.1.8.17     libxml.so.1     T    xmlAddChild
    AutoScan    /usr/bin/AutoScan    libxml2    /usr/lib/libxml2.so.2.6.22    libxml2.so.2    T    xmlAddChild

Here AutoScan is linked with both libxml and libxml2, while using xmlAddChild() function,
which is provided by both (incompatible) libraries.

=item	unneed

I.e. no undefined symbols is resolved into this shared library the binary is linked against.
To put it another way, the library is linked in but possibly unused.
Example:

    7colors /usr/bin/sevencolors    libICE.so.6
    7colors /usr/bin/sevencolors    libSM.so.6
    7colors /usr/bin/sevencolors    libX11.so.6
    7colors /usr/bin/sevencolors    libXext.so.6
    7colors /usr/bin/sevencolors    libXi.so.6
    7colors /usr/bin/sevencolors    libart_lgpl.so.2
    7colors /usr/bin/sevencolors    libaudiofile.so.0
    7colors /usr/bin/sevencolors    libdb.so.2
    7colors /usr/bin/sevencolors    libdl.so.2
    7colors /usr/bin/sevencolors    libesd.so.0
    7colors /usr/bin/sevencolors    libgmodule-1.2.so.0
    7colors /usr/bin/sevencolors    libm.so.6

To make it clear, the following libraries are actually used by 7colors (directly):

    libc.so.6
    libgdk-1.2.so.0
    libgdk_imlib.so.1
    libglib-1.2.so.0
    libgnome.so.32
    libgnomesupport.so.0
    libgnomeui.so.32
    libgtk-1.2.so.0

Now some stats (i.e. "most unneded libraries").

    $ cut -f3 unneed |sort |uniq -c |sort -n |tail
       1037 libc.so.6
       1207 libX11.so.6
       1240 libSM.so.6
       1244 libICE.so.6
       1247 libgcc_s.so.1
       1511 libXext.so.6
       2066 libz.so.1
       3164 libpthread.so.0
       3177 libdl.so.2
       5348 libm.so.6
    $

You see libm.so.6 is plugged by g++ by default.

=back

=head1	AUTHOR

Written by Alexey Tourbin <at@altlinux.org>.

=head1	COPYING

Copyright (c) 2006 Alexey Tourbin, ALT Linux Team.

This is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.

=cut

__EOF__
