ABI Compliance Checker 1.98.4
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
index a7f1801..15885c8 100755
--- a/abi-compliance-checker.pl
+++ b/abi-compliance-checker.pl
@@ -1,6 +1,6 @@
#!/usr/bin/perl
###########################################################################
-# ABI Compliance Checker (ACC) 1.98.3
+# ABI Compliance Checker (ACC) 1.98.4
# A tool for checking backward compatibility of a C/C++ library API
#
# Copyright (C) 2009-2010 The Linux Foundation
@@ -57,9 +57,10 @@
use Cwd qw(abs_path cwd);
use Data::Dumper;
use Config;
+use Fcntl;
-my $TOOL_VERSION = "1.98.3";
-my $ABI_DUMP_VERSION = "2.19";
+my $TOOL_VERSION = "1.98.4";
+my $ABI_DUMP_VERSION = "2.19.1";
my $OLDEST_SUPPORTED_VERSION = "1.18";
my $XML_REPORT_VERSION = "1.0";
my $XML_ABI_DUMP_VERSION = "1.2";
@@ -90,15 +91,17 @@
my $CmdName = get_filename($0);
my %OS_LibExt = (
"dynamic" => {
- "default"=>"so",
+ "linux"=>"so",
"macos"=>"dylib",
"windows"=>"dll",
- "symbian"=>"dso"
+ "symbian"=>"dso",
+ "default"=>"so"
},
"static" => {
- "default"=>"a",
+ "linux"=>"a",
"windows"=>"lib",
- "symbian"=>"lib"
+ "symbian"=>"lib",
+ "default"=>"a"
}
);
@@ -1187,6 +1190,7 @@
"stdio.h",
"stdlib.h",
"string.h",
+ "strings.h",
"tar.h",
"termios.h",
"time.h",
@@ -1208,6 +1212,32 @@
"sys",
"linux" );
+my %WinHeaders = map {$_=>1} (
+ "dos.h",
+ "process.h",
+ "winsock.h",
+ "config-win.h",
+ "mem.h",
+ "windows.h",
+ "winsock2.h",
+ "crtdbg.h",
+ "ws2tcpip.h"
+);
+
+my %ObsoleteHeaders = map {$_=>1} (
+ "iostream.h",
+ "fstream.h"
+);
+
+my %ConfHeaders = map {$_=>1} (
+ "atomic",
+ "conf.h",
+ "config.h",
+ "configure.h",
+ "build.h",
+ "setup.h"
+);
+
my %LocalIncludes = map {$_=>1} (
"/usr/local/include",
"/usr/local" );
@@ -1258,6 +1288,9 @@
2 => "C" );
my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
+my $MAX_CPPFILT_FILE_SIZE = 50000;
+my $CPPFILT_SUPPORT_FILE;
+
my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
my $STDCXX_TESTING = 0;
@@ -1330,6 +1363,7 @@
my %MissedTypedef;
my %MissedBase;
my %MissedBase_R;
+my %TypeTypedef;
# Symbols
my %SymbolInfo;
@@ -1361,6 +1395,7 @@
"1"=>{},
"2"=>{} );
my %MangledNames;
+my %Func_ShortName;
my %AddIntParams;
my %Interface_Impl;
my %GlobalDataObject;
@@ -1391,6 +1426,8 @@
my %Include_Order;
my %TUnit_NameSpaces;
my %TUnit_Classes;
+my %TUnit_Funcs;
+my %TUnit_Vars;
my %C99Mode = (
"1"=>0,
@@ -1406,13 +1443,14 @@
"2"=>0 );
# Shared Objects
-my %DyLib_DefaultPath;
-my %InputObject_Paths;
-my %RegisteredObjDirs;
+my %RegisteredObjects;
+my %RegisteredSONAMEs;
+my %RegisteredObject_Dirs;
# System Objects
my %SystemObjects;
my %DefaultLibPaths;
+my %DyLib_DefaultPath;
# System Headers
my %SystemHeaders;
@@ -2223,13 +2261,13 @@
{
$TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g;
$TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g;
- $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName);
+ $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T");
}
}
}
}
}
- $TypeName = formatName($TypeName);
+ $TypeName = formatName($TypeName, "T");
$TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName;
$TName_Tid{$Version}{$TypeName} = $TypeId;
}
@@ -2619,7 +2657,7 @@
$TypeAttr{"Name"} = $BTAttr{"Name"}."[]";
}
}
- $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
+ $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
if($BTAttr{"Header"}) {
$TypeAttr{"Header"} = $BTAttr{"Header"};
}
@@ -2760,7 +2798,7 @@
if(my $Algn = getAlgn($TypeId)) {
$TypeAttr{"Algn"} = $Algn/$BYTE_SIZE;
}
- $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
+ $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
if(not $TypeAttr{"Header"} and $BTAttr{"Header"}) {
$TypeAttr{"Header"} = $BTAttr{"Header"};
}
@@ -2869,7 +2907,7 @@
$Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g;
}
}
- return formatName($Covered);
+ return formatName($Covered, "T");
}
sub getNodeIntCst($)
@@ -3026,7 +3064,7 @@
}
$MemPtrName .= " (".join(", ", @ParamTypeName).")";
}
- $TypeAttr{"Name"} = formatName($MemPtrName);
+ $TypeAttr{"Name"} = formatName($MemPtrName, "T");
return %TypeAttr;
}
@@ -3185,8 +3223,8 @@
}
my $Info = $LibInfo{$Version}{"info"}{$TypeId};
my ($Qual, $To) = getQual($TypeId);
- if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) /
- and (getTypeId($1) ne $TypeId))
+ if(($Qual or $To) and $TypeDeclId
+ and (getTypeId($TypeDeclId) ne $TypeId))
{ # qualified types (special)
return getQualType($Qual);
}
@@ -3198,6 +3236,12 @@
{ # qualified types
return getQualType($Qual);
}
+
+ if($Info=~/unql[ ]*:[ ]*\@(\d+)/)
+ { # typedef struct { ... } name
+ $TypeTypedef{$Version}{$TypeId} = $1;
+ }
+
my $TypeType = getTypeTypeByTypeId($TypeId);
if($TypeType eq "Struct")
{
@@ -3348,13 +3392,13 @@
$SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName;
}
if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
- and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
+ and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
{ # validate mangled name
delete($SymbolInfo{$Version}{$InfoId});
return;
}
if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
- and $ShortName=~/\A_Z/)
+ and index($ShortName, "_Z")==0)
{ # _ZTS, etc.
$SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
}
@@ -3414,7 +3458,7 @@
{
if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
{ # for some symbols (_ZTI) the short name is the mangled name
- if($ShortName=~/\A_Z/) {
+ if(index($ShortName, "_Z")==0) {
$SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
}
}
@@ -3451,7 +3495,7 @@
}
}
setFuncAccess($InfoId);
- if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
+ if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) {
delete($SymbolInfo{$Version}{$InfoId}{"Return"});
}
if($ShortName=~/\A(_Z|\?)/) {
@@ -3511,7 +3555,7 @@
if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
$TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
}
- $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
+ $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T");
if(isAnon($TypeAttr{"Name"}))
{ # anon-struct-header.h-line
$TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
@@ -3528,7 +3572,7 @@
{ # template declarations with abstract params
return ("", "");
}
- $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
+ $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T");
}
return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
}
@@ -3583,6 +3627,10 @@
$Size = $Size/$BYTE_SIZE;
$TypeAttr{"Size"} = "$Size";
}
+ else
+ { # declaration only
+ $TypeAttr{"Forward"} = 1;
+ }
if($TypeAttr{"Type"} eq "Struct"
and detect_lang($TypeId))
{
@@ -3781,7 +3829,7 @@
$PureSignature = $ReturnName." ".$PureSignature;
}
}
- return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
+ return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S"));
}
sub mangle_symbol($$$)
@@ -4291,7 +4339,7 @@
if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
}
- my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
+ my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), "");
while($TypeName_New ne $TypeName_Pre)
{
$TypeName_Pre = $TypeName_New;
@@ -4315,14 +4363,14 @@
my $Type_Suffix = $1;
$TypeName_New = $BaseType_Name;
if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
- $TypeName_New = formatName($TypeName_New);
+ $TypeName_New = formatName($TypeName_New, "T");
}
}
}
else
{
if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) {
- $TypeName_New = formatName($TypeName_New);
+ $TypeName_New = formatName($TypeName_New, "T");
}
}
}
@@ -4570,7 +4618,7 @@
$SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
}
$SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
- $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
+ $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S");
}
else
{ # support for GCC 3.4
@@ -4590,7 +4638,7 @@
}
if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
- and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
+ and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0)
{
delete($SymbolInfo{$Version}{$InfoId});
return;
@@ -4704,7 +4752,8 @@
or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
or $SymbolInfo{$Version}{$InfoId}{"Class"})
{
- if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
+ if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/)
+ {
delete($SymbolInfo{$Version}{$InfoId});
return;
}
@@ -4739,7 +4788,8 @@
{
if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
{
- if($Unmangled=~/\.\_\d/) {
+ if($Unmangled=~/\.\_\d/)
+ {
delete($SymbolInfo{$Version}{$InfoId});
return;
}
@@ -5499,7 +5549,7 @@
next if(ignore_path($Path));
next if(skipHeader($Path, $LibVersion));
# Neighbors
- foreach my $Part (get_path_prefixes($Path)) {
+ foreach my $Part (get_prefixes($Path)) {
$Include_Neighbors{$LibVersion}{$Part} = $Path;
}
}
@@ -5527,7 +5577,7 @@
|update\ to\ include
|replaced\ with
|replaced\ by|renamed\ to
- |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
+ |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
{
$Redirect = $2;
last;
@@ -5542,7 +5592,7 @@
|you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
|is\ not\ supported\ API\ for\ general\ use
|do\ not\ use
- |should\ not\ be\ used
+ |should\ not\ be\ (used|using)
|cannot\ be\ included\ directly/ix and not /\ from\ /i) {
$Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
}
@@ -5595,14 +5645,14 @@
return 0;
}
-sub sort_by_word($$)
+sub sortByWord($$)
{
my ($ArrRef, $W) = @_;
return if(length($W)<2);
@{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
}
-sub natural_sorting($$)
+sub sortHeaders($$)
{
my ($H1, $H2) = @_;
$H1=~s/\.[a-z]+\Z//ig;
@@ -5611,7 +5661,8 @@
my ($HDir2, $Hname2) = separate_path($H2);
my $Dirname1 = get_filename($HDir1);
my $Dirname2 = get_filename($HDir2);
- if($H1 eq $H2) {
+ if($_[0] eq $_[1]
+ or $H1 eq $H2) {
return 0;
}
elsif($H1=~/\A\Q$H2\E/) {
@@ -5622,45 +5673,46 @@
}
elsif($HDir1=~/\Q$Hname1\E/i
and $HDir2!~/\Q$Hname2\E/i)
- {# include/glib-2.0/glib.h
+ { # include/glib-2.0/glib.h
return -1;
}
elsif($HDir2=~/\Q$Hname2\E/i
and $HDir1!~/\Q$Hname1\E/i)
- {# include/glib-2.0/glib.h
+ { # include/glib-2.0/glib.h
return 1;
}
elsif($Hname1=~/\Q$Dirname1\E/i
and $Hname2!~/\Q$Dirname2\E/i)
- {# include/hildon-thumbnail/hildon-thumbnail-factory.h
+ { # include/hildon-thumbnail/hildon-thumbnail-factory.h
return -1;
}
elsif($Hname2=~/\Q$Dirname2\E/i
and $Hname1!~/\Q$Dirname1\E/i)
- {# include/hildon-thumbnail/hildon-thumbnail-factory.h
+ { # include/hildon-thumbnail/hildon-thumbnail-factory.h
return 1;
}
- elsif($Hname1=~/(config|lib)/i
- and $Hname2!~/(config|lib)/i)
- {# include/alsa/asoundlib.h
+ elsif($Hname1=~/(config|lib|util)/i
+ and $Hname2!~/(config|lib|util)/i)
+ { # include/alsa/asoundlib.h
return -1;
}
- elsif($Hname2=~/(config|lib)/i
- and $Hname1!~/(config|lib)/i)
- {# include/alsa/asoundlib.h
+ elsif($Hname2=~/(config|lib|util)/i
+ and $Hname1!~/(config|lib|util)/i)
+ { # include/alsa/asoundlib.h
return 1;
}
elsif(checkRelevance($H1)
and not checkRelevance($H2))
- {# libebook/e-book.h
+ { # libebook/e-book.h
return -1;
}
elsif(checkRelevance($H2)
and not checkRelevance($H1))
- {# libebook/e-book.h
+ { # libebook/e-book.h
return 1;
}
- else {
+ else
+ {
return (lc($H1) cmp lc($H2));
}
}
@@ -5757,8 +5809,8 @@
push(@Registered, $HPath);
}
}
- @Registered = sort {natural_sorting($a, $b)} @Registered;
- sort_by_word(\@Registered, $TargetLibraryShortName);
+ @Registered = sort {sortHeaders($a, $b)} @Registered;
+ sortByWord(\@Registered, $TargetLibraryShortName);
foreach my $Path (@Registered) {
$Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
}
@@ -5778,6 +5830,10 @@
$Header = path_format($Header, $OSgroup);
if(my $Header_Path = is_header($Header, 1, $LibVersion))
{
+ if(defined $Include_Preamble{$LibVersion}{$Header_Path})
+ { # duplicate
+ next;
+ }
next if(skipHeader($Header_Path, $LibVersion));
$Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
}
@@ -5906,6 +5962,10 @@
$Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
}
}
+ else
+ { # can't find
+ $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
+ }
}
if(my $Inc = parse_includes($Content, $Path))
{
@@ -6005,6 +6065,15 @@
if($HPath eq $AbsPath) {
next;
}
+
+ if($Debug)
+ { # boundary headers
+ #if($HPath=~/vtk/ and $AbsPath!~/vtk/)
+ #{
+ # print STDERR "$AbsPath -> $HPath\n";
+ #}
+ }
+
$RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType;
if($IncType>0)
{ # only include <...>, skip include "..." prefixes
@@ -6202,12 +6271,20 @@
return 0;
}
}
- if($OStarget ne "bsd") {
+ if($OStarget ne "bsd")
+ {
if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
{ # openssh: skip /usr/lib/bcc/include/bsd/signal.h
return 0;
}
}
+ if($OStarget ne "windows")
+ {
+ if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/)
+ { # skip /usr/include/wine/msvcrt
+ return 0;
+ }
+ }
if(not get_dirname($Header)
and $Candidate=~/[\/\\]wx[\/\\]/)
{ # do NOT search in system /wx/ directory
@@ -6279,28 +6356,35 @@
{ # incorrect absolute path
return "";
}
- if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i)
+ if(defined $ConfHeaders{lc($Header)})
{ # too abstract configuration headers
return "";
}
+ my $HName = get_filename($Header);
if($OSgroup ne "windows")
{
- if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i)
+ if(defined $WinHeaders{lc($HName)}
+ or $HName=~/windows|win32|win64/i)
{ # windows headers
return "";
}
- elsif($Header=~/\A(mem)\.h\Z/)
- { # pngconf.h include mem.h for __MSDOS__
+ }
+ if($OSgroup ne "macos")
+ {
+ if($HName eq "fp.h")
+ { # pngconf.h includes fp.h for MACOS
return "";
}
}
if($OSgroup ne "solaris")
{
- if($Header=~/\A(thread)\.h\Z/)
- { # thread.h in Solaris
+ if($Header eq "thread.h") {
return "";
}
}
+ if($ObsoleteHeaders{$HName}) {
+ return "";
+ }
foreach my $Path (keys(%{$SystemPaths{"include"}}))
{ # search in default paths
@@ -6419,7 +6503,7 @@
if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
{
if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
- return ($1, $2);
+ return (path_format($1, $OSgroup), $2);
}
}
return ();
@@ -6553,20 +6637,39 @@
if(not $CppFiltCmd) {
exitStatus("Not_Found", "can't find c++filt in PATH");
}
- my $Info = `$CppFiltCmd -h 2>&1`;
- if($Info=~/\@<file>/)
- {# new version of c++filt can take a file
- my $NoStrip = "";
- if($OSgroup eq "macos"
- or $OSgroup eq "windows") {
- $NoStrip = "-n";
+ if(not defined $CPPFILT_SUPPORT_FILE)
+ {
+ my $Info = `$CppFiltCmd -h 2>&1`;
+ $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
+ }
+ if($CPPFILT_SUPPORT_FILE)
+ { # new versions of c++filt can take a file
+ if($#_>$MAX_CPPFILT_FILE_SIZE)
+ { # c++filt <= 2.22 may crash on large files (larger than 8mb)
+ # this is fixed in the oncoming version of Binutils
+ my @Half = splice(@_, 0, ($#_+1)/2);
+ return (unmangleArray(@Half), unmangleArray(@_))
}
- writeFile("$TMP_DIR/unmangle", join("\n", @_));
- return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
+ else
+ {
+ my $NoStrip = "";
+ if($OSgroup eq "macos"
+ or $OSgroup eq "windows") {
+ $NoStrip = "-n";
+ }
+ writeFile("$TMP_DIR/unmangle", join("\n", @_));
+ my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
+ if($?==139)
+ { # segmentation fault
+ printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant");
+ }
+ return split(/\n/, $Res);
+ }
}
else
{ # old-style unmangling
- if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
+ if($#_>$MAX_COMMAND_LINE_ARGUMENTS)
+ {
my @Half = splice(@_, 0, ($#_+1)/2);
return (unmangleArray(@Half), unmangleArray(@_))
}
@@ -6578,7 +6681,12 @@
$NoStrip = "-n";
}
my $Strings = join(" ", @_);
- return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
+ my $Res = `$CppFiltCmd $NoStrip $Strings`;
+ if($?==139)
+ { # segmentation fault
+ printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant");
+ }
+ return split(/\n/, $Res);
}
}
}
@@ -6825,17 +6933,22 @@
return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/);
}
-sub formatName($)
+sub formatName($$)
{ # type name correction
- if(defined $Cache{"formatName"}{$_[0]}) {
- return $Cache{"formatName"}{$_[0]};
+ if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) {
+ return $Cache{"formatName"}{$_[1]}{$_[0]};
}
my $N = $_[0];
- $N=~s/\A[ ]+|[ ]+\Z//g;
- $N=~s/[ ]{2,}/ /g;
- $N=~s/[ ]*(\W)[ ]*/$1/g;
+ if($_[1] ne "S")
+ {
+ $N=~s/\A[ ]+//g;
+ $N=~s/[ ]+\Z//g;
+ $N=~s/[ ]{2,}/ /g;
+ }
+
+ $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string<char> const
$N=~s/\bvolatile const\b/const volatile/g;
@@ -6846,9 +6959,14 @@
while($N=~s/>>/> >/g) {};
- $N=~s/\b(operator[ ]*)> >/$1>>/;
+ if($_[1] eq "S")
+ {
+ if(index($N, "operator")!=-1) {
+ $N=~s/\b(operator[ ]*)> >/$1>>/;
+ }
+ }
- return ($Cache{"formatName"}{$_[0]}=$N);
+ return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N);
}
sub get_HeaderDeps($$)
@@ -7200,31 +7318,32 @@
# Types
"stdio.h" => ["FILE", "va_list"],
"stddef.h" => ["NULL", "ptrdiff_t"],
- "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
+ "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t",
+ "int8_t", "int16_t", "int32_t", "int64_t"],
"time.h" => ["time_t"],
"sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
- "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
- "unistd.h" => ["gid_t", "uid_t"],
+ "u_int", "off_t", "u_quad_t", "u_long", "mode_t"],
+ "unistd.h" => ["gid_t", "uid_t", "socklen_t"],
"stdbool.h" => ["_Bool"],
"rpc/xdr.h" => ["bool_t"],
"in_systm.h" => ["n_long", "n_short"],
# Fields
"arpa/inet.h" => ["fw_src", "ip_src"],
# Functions
- "stdlib.h" => ["free", "malloc"],
+ "stdlib.h" => ["free", "malloc", "size_t"],
"string.h" => ["memmove", "strcmp"]
);
my %AutoPreamble = ();
foreach (keys(%HeaderElems))
{
foreach my $Elem (@{$HeaderElems{$_}}) {
- $AutoPreamble{$Elem}=$_;
+ $AutoPreamble{$Elem} = $_;
}
}
my %Types = ();
while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
{ # error: 'FILE' has not been declared
- $Types{$2}=1;
+ $Types{$2} = 1;
}
if(keys(%Types))
{
@@ -7233,16 +7352,22 @@
{
if(my $Header = $AutoPreamble{$Type})
{
- if(my $Path = identifyHeader($Header, $LibVersion)) {
- $AddHeaders{path_format($Path, $OSgroup)}=$Type;
+ if(my $Path = identifyHeader($Header, $LibVersion))
+ {
+ if(skipHeader($Path, $LibVersion)) {
+ next;
+ }
+ $Path = path_format($Path, $OSgroup);
+ $AddHeaders{$Path}{"Type"} = $Type;
+ $AddHeaders{$Path}{"Header"} = $Header;
}
}
}
if(keys(%AddHeaders)) {
- return %AddHeaders;
+ return \%AddHeaders;
}
}
- return ();
+ return undef;
}
sub checkCTags($)
@@ -7256,26 +7381,46 @@
return;
}
my $Out = $TMP_DIR."/ctags.txt";
+ system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\"");
if($Debug) {
- $Out = $DEBUG_PATH{$Version}."/ctags.txt";
+ copy($Out, $DEBUG_PATH{$Version}."/ctags.txt");
}
- system("$CTags -f \"$Out\" \"$Path\"");
open(CTAGS, "<", $Out);
while(my $Line = <CTAGS>)
{
chomp($Line);
my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line);
+ if(defined $Intrinsic_Keywords{$Name})
+ { # noise
+ next;
+ }
if($Type eq "n")
{
- if($Scpe=~/\Aclass:/) {
+ if(index($Scpe, "class:")==0) {
next;
}
- if($Scpe)
- {
- $Scpe=~s/\Anamespace://;
- $Name = $Scpe."::".$Name;
+ if(index($Scpe, "struct:")==0) {
+ next;
}
- $TUnit_NameSpaces{$Version}{$Name}=1;
+ if(index($Scpe, "namespace:")==0)
+ {
+ if($Scpe=~s/\Anamespace://) {
+ $Name = $Scpe."::".$Name;
+ }
+ }
+ $TUnit_NameSpaces{$Version}{$Name} = 1;
+ }
+ elsif($Type eq "p")
+ {
+ if(not $Scpe or index($Scpe, "namespace:")==0) {
+ $TUnit_Funcs{$Version}{$Name} = 1;
+ }
+ }
+ elsif($Type eq "x")
+ {
+ if(not $Scpe or index($Scpe, "namespace:")==0) {
+ $TUnit_Vars{$Version}{$Name} = 1;
+ }
}
}
close(CTAGS);
@@ -7309,6 +7454,12 @@
}
close(TMP_HEADER);
my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
+
+ if(not keys(%{$TargetHeaders{$Version}}))
+ { # Target headers
+ addTargetHeaders($Version);
+ }
+
if($Debug)
{ # debug mode
writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
@@ -7317,11 +7468,6 @@
writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
}
- if(not keys(%{$TargetHeaders{$Version}}))
- { # Target headers
- addTargetHeaders($Version);
- }
-
# clean memory
%RecursiveIncludes = ();
%Header_Include_Prefix = ();
@@ -7428,14 +7574,30 @@
# void setTabEnabled(int index, bool);
$C99Mode{$Version} = 1;
}
- if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
+ if($MContent=~s/(\w)(\s*[^\w\(\,\s]\s*|\s+)(this|throw)(\s*[\,\)])/$1$2c99_$3$4/g)
{ # MATCH:
# int foo(int* this);
# int bar(int this);
+ # int baz(int throw);
# DO NOT MATCH:
- # baz(X, this);
+ # foo(X, this);
$C99Mode{$Version} = 1;
}
+
+ # remove typedef enum NAME NAME;
+ my @FwdTypedefs = $MContent=~/typedef\s+enum\s+(\w+)\s+(\w+);/g;
+ my $N = 0;
+ while($N<=$#FwdTypedefs-1)
+ {
+ my $S = $FwdTypedefs[$N];
+ if($S eq $FwdTypedefs[$N+1])
+ {
+ $MContent=~s/typedef\s+enum\s+\Q$S\E\s+\Q$S\E;//g;
+ $C99Mode{$Version}=1;
+ }
+ $N+=2;
+ }
+
if($C99Mode{$Version}==1)
{ # try to change C++ "keyword" to "c99_keyword"
printMsg("INFO", "Using C99 compatibility mode");
@@ -7519,6 +7681,14 @@
{ # will be added by name space
next;
}
+ if(defined $TUnit_Funcs{$Version}{$CName})
+ { # the same name for a function and type
+ next;
+ }
+ if(defined $TUnit_Vars{$Version}{$CName})
+ { # the same name for a variable and type
+ next;
+ }
$AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
}
if($AddClass) {
@@ -7551,10 +7721,10 @@
return getDump();
}
elsif($AutoPreambleMode{$Version}!=-1
- and my %AddHeaders = detectPreamble($Errors, $Version))
+ and my $AddHeaders = detectPreamble($Errors, $Version))
{ # add auto preamble headers and try again
$AutoPreambleMode{$Version}=-1;
- my @Headers = sort {$b cmp $a} keys(%AddHeaders); # sys/types.h should be the first
+ my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first
foreach my $Num (0 .. $#Headers)
{
my $Path = $Headers[$Num];
@@ -7563,8 +7733,7 @@
next;
}
$Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
- my $Type = $AddHeaders{$Path};
- printMsg("INFO", "Add \'".get_filename($Path)."\' preamble header for \'$Type\'");
+ printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
}
resetLogging($Version);
$TMP_DIR = tempdir(CLEANUP=>1);
@@ -7762,7 +7931,11 @@
$Cmd .= " -name \"$Name\"";
}
}
- return split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
+ my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
+ if($?) {
+ printMsg("ERROR", "problem with \'find\' utility ($?): $!");
+ }
+ return split(/\n/, $Res);
}
}
@@ -7908,6 +8081,15 @@
}
}
+sub readBytes($)
+{
+ sysopen(FILE, $_[0], O_RDONLY);
+ sysread(FILE, my $Header, 4);
+ close(FILE);
+ my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header);
+ return join("", @Bytes);
+}
+
sub is_header_file($)
{
if($_[0]=~/\.($HEADER_EXT)\Z/i) {
@@ -7982,6 +8164,11 @@
{
my $RegDir = get_dirname($RegHeader);
$TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
+
+ if(not $INC_PATH_AUTODETECT{$LibVersion}) {
+ detect_recursive_includes($RegHeader, $LibVersion);
+ }
+
foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
{
my $Dir = get_dirname($RecInc);
@@ -8261,6 +8448,7 @@
foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
{ # detect allocable classes with public exported constructors
# or classes with auto-generated or inline-only constructors
+ # and other temp info
if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
{
my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"};
@@ -8332,10 +8520,13 @@
}
}
}
+
+ # mapping {short name => symbols}
+ $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1;
}
foreach my $MnglName (keys(%VTableClass))
{ # reconstruct header name for v-tables
- if($MnglName=~/\A_ZTV/)
+ if(index($MnglName, "_ZTV")==0)
{
if(my $ClassName = $VTableClass{$MnglName})
{
@@ -8576,6 +8767,18 @@
sub selectType($$)
{
my ($Tid, $LibVersion) = @_;
+
+ if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid})
+ {
+ if(defined $TypeInfo{$LibVersion}{$Dupl})
+ {
+ if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"})
+ { # duplicate
+ return 0;
+ }
+ }
+ }
+
if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"})
{
if(not isBuiltIn($THeader))
@@ -9008,7 +9211,7 @@
if($MName=~/reserved|padding|f_spare/i) {
return 1;
}
- if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
+ if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
return 1;
}
if($MName=~/(pad\d+)/i) {
@@ -9232,14 +9435,21 @@
next;
}
$ProblemType = "Pure_Virtual_Replacement";
- @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
+
+ # affected all methods (both virtual and non-virtual ones)
+ @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
+ push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}}));
}
+ $VTableChanged_M{$ClassName}=1;
foreach my $AffectedInt (@Affected)
{
if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
{ # affected exported methods only
next;
}
+ if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) {
+ next;
+ }
%{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
"Type_Name"=>$Class_Type{"Name"},
"Type_Type"=>"Class",
@@ -9253,7 +9463,7 @@
if(not checkDump(1, "2.0")
or not checkDump(2, "2.0"))
{ # support for old ABI dumps
- # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
+ # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format)
return;
}
foreach my $ClassName (sort keys(%{$ClassNames{1}}))
@@ -9347,6 +9557,9 @@
}
foreach my $Interface (@Affected)
{
+ if(not symbolFilter($Interface, 1, "Affected", $Level)) {
+ next;
+ }
%{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
"Type_Name"=>$ClassName,
"Type_Type"=>"Class",
@@ -9401,6 +9614,9 @@
}
foreach my $Interface (@Affected)
{
+ if(not symbolFilter($Interface, 1, "Affected", $Level)) {
+ next;
+ }
%{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
"Type_Name"=>$ClassName,
"Type_Type"=>"Class",
@@ -9428,6 +9644,9 @@
{ # changed position of the base class
foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
{
+ if(not symbolFilter($Interface, 1, "Affected", $Level)) {
+ next;
+ }
%{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
"Type_Name"=>$ClassName,
"Type_Type"=>"Class",
@@ -9441,6 +9660,9 @@
{ # became non-virtual base
foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
{
+ if(not symbolFilter($Interface, 1, "Affected", $Level)) {
+ next;
+ }
%{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
"Type_Name"=>$ClassName,
"Type_Type"=>"Class",
@@ -9452,6 +9674,9 @@
{ # became virtual base
foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
{
+ if(not symbolFilter($Interface, 1, "Affected", $Level)) {
+ next;
+ }
%{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
"Type_Name"=>$ClassName,
"Type_Type"=>"Class",
@@ -9493,6 +9718,9 @@
next if(not $ProblemType);
foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
{ # base class size changes affecting current class
+ if(not symbolFilter($Interface, 1, "Affected", $Level)) {
+ next;
+ }
%{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
"Type_Name"=>$BaseType{"Name"},
"Type_Type"=>"Class",
@@ -9695,7 +9923,7 @@
{
my $VSize_Old = getVTable_Size($CName, 1);
my $VSize_New = getVTable_Size($CName, 2);
- next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
+ next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method
if(isCopyingClass($Class_Id, 1))
{ # class has no constructors and v-table will be copied by applications, this may affect all methods
my $ProblemType = "Added_Virtual_Method";
@@ -9737,7 +9965,7 @@
{
if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
{
- if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
+ if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
next;
}
}
@@ -9761,7 +9989,7 @@
if($RemovedVFunc eq $Interface
and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
{ # This case is for removed virtual methods
- # implemented in both versions of a library
+ # implemented in both versions of a library
next;
}
if(not keys(%{$VirtualTable_Model{2}{$CName}}))
@@ -9800,7 +10028,7 @@
{
if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"})
{
- if(symbolFilter($ASymbol, 1, "Affected", $Level)) {
+ if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
next;
}
}
@@ -10079,8 +10307,8 @@
# std::__va_list and __va_list
$Base_1{"Name"}=~s/\A(\w+::)+//;
$Base_2{"Name"}=~s/\A(\w+::)+//;
- $Base_1{"Name"} = formatName($Base_1{"Name"});
- $Base_2{"Name"} = formatName($Base_2{"Name"});
+ $Base_1{"Name"} = formatName($Base_1{"Name"}, "T");
+ $Base_2{"Name"} = formatName($Base_2{"Name"}, "T");
}
}
if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
@@ -10342,6 +10570,15 @@
"Old_Value"=>$Member_Name,
"New_Value"=>$RenamedTo );
}
+ elsif(isReserved($Member_Name))
+ {
+ %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=(
+ "Target"=>$Member_Name,
+ "Type_Name"=>$Type1_Pure{"Name"},
+ "Type_Type"=>$Type1_Pure{"Type"},
+ "Old_Value"=>$Member_Name,
+ "New_Value"=>$RenamedTo );
+ }
}
elsif($Type1_Pure{"Type"} eq "Enum")
{
@@ -11229,7 +11466,7 @@
{ # checking removed symbols
next if($CompleteSignature{1}{$Symbol}{"Private"});
next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
- if($Symbol=~/\A_ZTV/)
+ if(index($Symbol, "_ZTV")==0)
{ # skip v-tables for templates, that should not be imported by applications
next if($tr_name{$Symbol}=~/</);
if(my $CName = $VTableClass{$Symbol})
@@ -11372,6 +11609,21 @@
next;
}
}
+ if(not $CompleteSignature{1}{$Symbol}{"Class"})
+ {
+ if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"})
+ {
+ if(defined $Constants{2}{$Short})
+ {
+ my $Val = $Constants{2}{$Short}{"Value"};
+ if(defined $Func_ShortName{2}{$Val})
+ { # old name defined to new
+ next;
+ }
+ }
+ }
+
+ }
$RemovedInt{$Level}{$Symbol} = 1;
if($Level eq "Source")
{ # search for a source-compatible equivalent
@@ -11387,6 +11639,8 @@
foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
{ # checking added symbols
next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
+ next if($CompleteSignature{2}{$Symbol}{"Private"});
+ next if(not symbolFilter($Symbol, 2, "Affected", $Level));
if($Level eq "Binary")
{
if($CompleteSignature{2}{$Symbol}{"InLine"})
@@ -11403,13 +11657,13 @@
next;
}
}
- next if($CompleteSignature{2}{$Symbol}{"Private"});
- next if(not symbolFilter($Symbol, 2, "Affected", $Level));
%{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
}
foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
{ # checking removed symbols
next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
+ next if($CompleteSignature{1}{$Symbol}{"Private"});
+ next if(not symbolFilter($Symbol, 1, "Affected", $Level));
if($Level eq "Binary")
{
if($CompleteSignature{1}{$Symbol}{"InLine"})
@@ -11439,8 +11693,6 @@
}
}
}
- next if($CompleteSignature{1}{$Symbol}{"Private"});
- next if(not symbolFilter($Symbol, 1, "Affected", $Level));
%{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
}
}
@@ -11858,6 +12110,27 @@
{ # without a header
next;
}
+
+ if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
+ and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
+ { # became pure
+ next;
+ }
+ if($CompleteSignature{1}{$Symbol}{"PureVirt"}
+ and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
+ { # became non-pure
+ next;
+ }
+
+ if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
+ { # exported, target, inline virtual and pure virtual
+ next;
+ }
+ if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
+ { # exported, target, inline virtual and pure virtual
+ next;
+ }
+
if(checkDump(1, "2.13") and checkDump(2, "2.13"))
{
if($CompleteSignature{1}{$Symbol}{"Data"}
@@ -11883,26 +12156,6 @@
}
}
- if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
- and $CompleteSignature{2}{$PSymbol}{"PureVirt"})
- { # became pure
- next;
- }
- if($CompleteSignature{1}{$Symbol}{"PureVirt"}
- and not $CompleteSignature{2}{$PSymbol}{"PureVirt"})
- { # became non-pure
- next;
- }
-
- if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level))
- { # exported, target, inline virtual and pure virtual
- next;
- }
- if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level))
- { # exported, target, inline virtual and pure virtual
- next;
- }
-
if($CompleteSignature{2}{$PSymbol}{"Private"})
{
%{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=(
@@ -11934,20 +12187,22 @@
}
if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol}
and not $CompleteSignature{2}{$PSymbol}{"Data"})
- {# missed information about parameters in older version
+ { # missed information about parameters in older version
next;
}
}
my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
# checking attributes
if($CompleteSignature{2}{$PSymbol}{"Static"}
- and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
+ and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
+ {
%{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
"Target"=>get_Signature($Symbol, 1)
);
}
elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
- and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
+ and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/)
+ {
%{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
"Target"=>get_Signature($Symbol, 1)
);
@@ -11973,9 +12228,12 @@
if(isUsedClass($Class_Id, 1, $Level))
{
my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
- foreach my $AffectedInterface (@Affected)
+ foreach my $ASymbol (@Affected)
{
- %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
+ if(not symbolFilter($ASymbol, 1, "Affected", $Level)) {
+ next;
+ }
+ %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=(
"Type_Name"=>$Class_Type{"Name"},
"Type_Type"=>"Class",
"Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
@@ -12163,6 +12421,7 @@
my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
my $NewProblemType = $SubProblemType;
+ my $AddProblemType = undef;
if($SubProblemType eq "Return_Type_And_Size"
and $CompleteSignature{1}{$Symbol}{"Data"}) {
@@ -12175,10 +12434,12 @@
if(removedQual($Old_Value, $New_Value, "const"))
{ # const -> non-const global data
$NewProblemType = "Global_Data_Became_Non_Const";
+ $AddProblemType = "Global_Data_Type";
}
elsif(addedQual($Old_Value, $New_Value, "const"))
{ # non-const -> const global data
$NewProblemType = "Global_Data_Became_Const";
+ $AddProblemType = "Global_Data_Type";
}
else {
$NewProblemType = "Global_Data_Type";
@@ -12186,8 +12447,10 @@
}
else
{
- if(addedQual($Old_Value, $New_Value, "const")) {
+ if(addedQual($Old_Value, $New_Value, "const"))
+ {
$NewProblemType = "Return_Type_Became_Const";
+ $AddProblemType = "Return_Type";
}
}
}
@@ -12277,6 +12540,9 @@
}
}
@{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
+ if(defined $AddProblemType) {
+ @{$CompatProblems{$Level}{$Symbol}{$AddProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
+ }
}
if($ReturnType1_Id and $ReturnType2_Id)
{
@@ -12355,7 +12621,7 @@
$Qual = "const|volatile|restrict";
}
while($Value=~s/\b$Qual\b//) {
- $Value = formatName($Value);
+ $Value = formatName($Value, "T");
}
return $Value;
}
@@ -12762,7 +13028,7 @@
sub getTypeIdByName($$)
{
my ($TypeName, $Version) = @_;
- return $TName_Tid{$Version}{formatName($TypeName)};
+ return $TName_Tid{$Version}{formatName($TypeName, "T")};
}
sub checkFormatChange($$$)
@@ -12774,6 +13040,10 @@
{ # equal types
return 0;
}
+ if($Type1_Pure{"Name"} eq "void")
+ { # from void* to something
+ return 0;
+ }
if($Type1_Pure{"Name"}=~/\*/
or $Type2_Pure{"Name"}=~/\*/)
{ # compared in detectTypeChange()
@@ -12884,10 +13154,22 @@
and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
{ # base type change
- if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
- and $Type1{"Name"} eq $Type2{"Name"})
- { # will be reported in mergeTypes() as typedef problem
- return ();
+ if($Type1{"Name"} eq $Type2{"Name"})
+ {
+ if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef")
+ { # will be reported in mergeTypes() as typedef problem
+ return ();
+ }
+ my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef");
+ my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef");
+ if(%Typedef_1 and %Typedef_2)
+ {
+ if($Typedef_1{"Name"} eq $Typedef_2{"Name"}
+ and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef")
+ { # const Typedef
+ return ();
+ }
+ }
}
if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
{
@@ -14378,7 +14660,8 @@
if($NameSpace) {
$Signature=~s/\b\Q$NameSpace\E::\b//g;
}
- if($Interface=~/\A(_Z|\?)/) {
+ if($Interface=~/\A(_Z|\?)/)
+ {
if($Signature) {
$ADDED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Interface</b>]</span><br/><br/>".$ContentDivEnd."\n");
}
@@ -14386,7 +14669,8 @@
$ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
}
}
- else {
+ else
+ {
if($Signature) {
$ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
}
@@ -15550,7 +15834,7 @@
</div>";
$Report .= "<div id='BinaryTab' class='tab'>\n$BSummary\n".get_Report_Added("Binary").get_Report_Removed("Binary").get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary").get_SourceInfo()."<br/><br/><br/></div>";
$Report .= "<div id='SourceTab' class='tab'>\n$SSummary\n".get_Report_Added("Source").get_Report_Removed("Source").get_Report_Problems("High", "Source").get_Report_Problems("Medium", "Source").get_Report_Problems("Low", "Source").get_Report_Problems("Safe", "Source").get_SourceInfo()."<br/><br/><br/></div>";
- $Report .= getReportFooter($TargetLibraryFName);
+ $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
$Report .= "\n<div style='height:999px;'></div>\n</body></html>";
return $Report;
}
@@ -15573,7 +15857,7 @@
$Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
$Report .= get_SourceInfo();
$Report .= "</div>\n<br/><br/><br/><hr/>\n";
- $Report .= getReportFooter($TargetLibraryFName);
+ $Report .= getReportFooter($TargetLibraryFName, not $JoinReport);
$Report .= "\n<div style='height:999px;'></div>\n</body></html>";
return $Report;
}
@@ -15615,10 +15899,10 @@
}
}
-sub getReportFooter($)
+sub getReportFooter($$)
{
- my $LibName = $_[0];
- my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
+ my ($LibName, $Wide) = @_;
+ my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px";
my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
$Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
$Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
@@ -15734,7 +16018,7 @@
{ # user-defined header
next;
}
- if($Line=~/\A\#\s*define\s+([_A-Z0-9]+)\s+(.+)\s*\Z/)
+ if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/)
{
my ($Name, $Value) = ($1, $2);
if(not $Constants{$Version}{$Name}{"Access"})
@@ -15796,51 +16080,53 @@
return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
}
-my %IgnoreConstant=(
- "VERSION"=>1,
- "VERSIONCODE"=>1,
- "VERNUM"=>1,
- "VERS_INFO"=>1,
- "PATCHLEVEL"=>1,
- "INSTALLPREFIX"=>1,
- "VBUILD"=>1,
- "VPATCH"=>1,
- "VMINOR"=>1,
- "BUILD_STRING"=>1,
- "BUILD_TIME"=>1,
- "PACKAGE_STRING"=>1,
- "PRODUCTION"=>1,
- "CONFIGURE_COMMAND"=>1,
- "INSTALLDIR"=>1,
- "BINDIR"=>1,
- "CONFIG_FILE_PATH"=>1,
- "DATADIR"=>1,
- "EXTENSION_DIR"=>1,
- "INCLUDE_PATH"=>1,
- "LIBDIR"=>1,
- "LOCALSTATEDIR"=>1,
- "SBINDIR"=>1,
- "SYSCONFDIR"=>1,
- "RELEASE"=>1,
- "SOURCE_ID"=>1,
- "SUBMINOR"=>1,
- "MINOR"=>1,
- "MINNOR"=>1,
- "MINORVERSION"=>1,
- "MAJOR"=>1,
- "MAJORVERSION"=>1,
- "MICRO"=>1,
- "MICROVERSION"=>1,
- "BINARY_AGE"=>1,
- "INTERFACE_AGE"=>1,
- "CORE_ABI"=>1,
- "PATCH"=>1,
- "COPYRIGHT"=>1,
- "TIMESTAMP"=>1,
- "REVISION"=>1,
- "PACKAGE_TAG"=>1,
- "PACKAGEDATE"=>1,
- "NUMVERSION"=>1
+my %IgnoreConstant = map {$_=>1} (
+ "VERSION",
+ "VERSIONCODE",
+ "VERNUM",
+ "VERS_INFO",
+ "PATCHLEVEL",
+ "INSTALLPREFIX",
+ "VBUILD",
+ "VPATCH",
+ "VMINOR",
+ "BUILD_STRING",
+ "BUILD_TIME",
+ "PACKAGE_STRING",
+ "PRODUCTION",
+ "CONFIGURE_COMMAND",
+ "INSTALLDIR",
+ "BINDIR",
+ "CONFIG_FILE_PATH",
+ "DATADIR",
+ "EXTENSION_DIR",
+ "INCLUDE_PATH",
+ "LIBDIR",
+ "LOCALSTATEDIR",
+ "SBINDIR",
+ "SYSCONFDIR",
+ "RELEASE",
+ "SOURCE_ID",
+ "SUBMINOR",
+ "MINOR",
+ "MINNOR",
+ "MINORVERSION",
+ "MAJOR",
+ "MAJORVERSION",
+ "MICRO",
+ "MICROVERSION",
+ "BINARY_AGE",
+ "INTERFACE_AGE",
+ "CORE_ABI",
+ "PATCH",
+ "COPYRIGHT",
+ "TIMESTAMP",
+ "REVISION",
+ "PACKAGE_TAG",
+ "PACKAGEDATE",
+ "NUMVERSION",
+ "Release",
+ "Version"
);
sub mergeConstants($)
@@ -15875,9 +16161,19 @@
{ # different values
if($Level eq "Binary")
{
- if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
- { # ignore library version
- next;
+ foreach (keys(%IgnoreConstant))
+ {
+ if($Constant=~/(\A|_)$_(_|\Z)/)
+ { # ignore library version
+ next;
+ }
+ if(/\A[A-Z].*[a-z]\Z/)
+ {
+ if($Constant=~/(\A|[a-z])$_([A-Z]|\Z)/)
+ { # ignore library version
+ next;
+ }
+ }
}
if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
{ # ignore library version
@@ -15894,7 +16190,7 @@
# (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
next;
}
- if($Old_Value=~/\(/i and $Old_Value!~/[\"\']/i)
+ if($Old_Value=~/\(/i and $Old_Value!~/\A[\"\']/i)
{ # ignore source defines:
# foo(p)
next;
@@ -15955,9 +16251,8 @@
exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
}
}
- my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
- readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
+ readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
}
if(not $CheckHeadersOnly)
{
@@ -16011,22 +16306,22 @@
{
my $LibVersion = pop(@_);
my (@MnglNames1, @MnglNames2, @UnmangledNames) = ();
- foreach my $Interface (sort @_)
+ foreach my $Symbol (sort @_)
{
- if($Interface=~/\A_Z/)
+ if(index($Symbol, "_Z")==0)
{
- next if($tr_name{$Interface});
- $Interface=~s/[\@\$]+(.*)\Z//;
- push(@MnglNames1, $Interface);
+ next if($tr_name{$Symbol});
+ $Symbol=~s/[\@\$]+(.*)\Z//;
+ push(@MnglNames1, $Symbol);
}
- elsif($Interface=~/\A\?/) {
- push(@MnglNames2, $Interface);
+ elsif(index($Symbol, "?")==0) {
+ push(@MnglNames2, $Symbol);
}
else
{ # not mangled
- $tr_name{$Interface} = $Interface;
- $mangled_name_gcc{$Interface} = $Interface;
- $mangled_name{$LibVersion}{$Interface} = $Interface;
+ $tr_name{$Symbol} = $Symbol;
+ $mangled_name_gcc{$Symbol} = $Symbol;
+ $mangled_name{$LibVersion}{$Symbol} = $Symbol;
}
}
if($#MnglNames1 > -1)
@@ -16036,11 +16331,11 @@
{
if(my $Unmangled = pop(@UnmangledNames))
{
- $tr_name{$MnglName} = formatName(canonifyName($Unmangled));
+ $tr_name{$MnglName} = formatName(canonifyName($Unmangled), "S");
if(not $mangled_name_gcc{$tr_name{$MnglName}}) {
$mangled_name_gcc{$tr_name{$MnglName}} = $MnglName;
}
- if($MnglName=~/\A_ZTV/
+ if(index($MnglName, "_ZTV")==0
and $tr_name{$MnglName}=~/vtable for (.+)/)
{ # bind class name and v-table symbol
my $ClassName = $1;
@@ -16057,7 +16352,7 @@
{
if(my $Unmangled = pop(@UnmangledNames))
{
- $tr_name{$MnglName} = formatName($Unmangled);
+ $tr_name{$MnglName} = formatName($Unmangled, "S");
$mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
}
}
@@ -16091,7 +16386,7 @@
if(my $VSym = $SymVer{$RunWith}{$Symbol})
{ # indirect symbol version, i.e.
# foo_old and its symlink foo@v (or foo@@v)
- # foo_old may be in .symtab table
+ # foo_old may be in symtab table
if($Where->{$RunWith}{$VSym}) {
return 1;
}
@@ -16122,7 +16417,7 @@
sub readSymbols_App($)
{
my $Path = $_[0];
- return () if(not $Path or not -f $Path);
+ return () if(not $Path);
my @Imported = ();
if($OSgroup eq "macos")
{
@@ -16131,7 +16426,8 @@
exitStatus("Not_Found", "can't find \"otool\"");
}
open(APP, "$OtoolCmd -IV \"$Path\" 2>\"$TMP_DIR/null\" |");
- while(<APP>) {
+ while(<APP>)
+ {
if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
push(@Imported, $1);
}
@@ -16145,7 +16441,8 @@
exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
}
open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |");
- while(<APP>) {
+ while(<APP>)
+ {
if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
push(@Imported, $1);
}
@@ -16159,24 +16456,26 @@
exitStatus("Not_Found", "can't find \"readelf\"");
}
open(APP, "$ReadelfCmd -WhlSsdA \"$Path\" 2>\"$TMP_DIR/null\" |");
- my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
+ my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
while(<APP>)
{
- if( /'.dynsym'/ ) {
- $symtab=0;
+ if(defined $symtab)
+ { # do nothing with symtab
+ if(index($_, "'.dynsym'")!=-1)
+ { # dynamic table
+ $symtab = undef;
+ }
}
- elsif($symtab == 1) {
- # do nothing with symtab (but there are some plans for the future)
- next;
+ elsif(index($_, "'.symtab'")!=-1)
+ { # symbol table
+ $symtab = 1;
}
- elsif( /'.symtab'/ ) {
- $symtab=1;
- }
- elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
+ elsif(my @Info = readline_ELF($_))
{
- if( $Ndx eq "UND" ) {
- #only imported symbols
- push(@Imported, $fullname);
+ my ($Ndx, $Symbol) = ($Info[5], $Info[6]);
+ if($Ndx eq "UND")
+ { # only imported symbols
+ push(@Imported, $Symbol);
}
}
}
@@ -16185,78 +16484,99 @@
return @Imported;
}
+my %ELF_BIND = map {$_=>1} (
+ "WEAK",
+ "GLOBAL"
+);
+
+my %ELF_TYPE = map {$_=>1} (
+ "FUNC",
+ "IFUNC",
+ "OBJECT",
+ "COMMON"
+);
+
+my %ELF_VIS = map {$_=>1} (
+ "DEFAULT",
+ "PROTECTED"
+);
+
sub readline_ELF($)
-{
- if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
- { # the line of 'readelf' output corresponding to the interface
- # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
- my ($value, $size, $type, $bind,
- $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
- if($bind!~/\A(WEAK|GLOBAL)\Z/) {
- return ();
- }
- if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
- return ();
- }
- if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
- return ();
- }
- if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
- return ();
- }
- if($OStarget eq "symbian")
- {
- if($fullname=~/_\._\.absent_export_\d+/)
- { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
- return ();
- }
- my @Elems = separate_symbol($fullname);
- $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
- }
- if(index($size, "0x")!=-1)
- { # 0x3d158
- $size = hex($size);
- }
- return ($fullname, $value, $Ndx, $type, $size, $bind);
+{ # read the line of 'readelf' output corresponding to the symbol
+ my @Info = split(/\s+/, $_[0]);
+ # Num: Value Size Type Bind Vis Ndx Name
+ # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4
+ shift(@Info); # spaces
+ shift(@Info); # num
+ if($#Info!=6)
+ { # other lines
+ return ();
}
- return ();
+ return () if(not defined $ELF_TYPE{$Info[2]});
+ return () if(not defined $ELF_BIND{$Info[3]});
+ return () if(not defined $ELF_VIS{$Info[4]});
+ if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/)
+ { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3
+ return ();
+ }
+ if($OStarget eq "symbian")
+ { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
+ if(index($Info[6], "_._.absent_export_")!=-1)
+ { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
+ return ();
+ }
+ $Info[6]=~s/\@.+//g; # remove version
+ }
+ if(index($Info[2], "0x") == 0)
+ { # size == 0x3d158
+ $Info[2] = hex($Info[2]);
+ }
+ return @Info;
}
sub read_symlink($)
{
my $Path = $_[0];
- return "" if(not $Path);
- return "" if(not -f $Path and not -l $Path);
- if(defined $Cache{"read_symlink"}{$Path}) {
- return $Cache{"read_symlink"}{$Path};
- }
if(my $Res = readlink($Path)) {
- return ($Cache{"read_symlink"}{$Path} = $Res);
+ return $Res;
}
elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
- return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n \"$Path\"`);
+ return `$ReadlinkCmd -n \"$Path\"`;
}
elsif(my $FileCmd = get_CmdPath("file"))
{
my $Info = `$FileCmd \"$Path\"`;
if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
- return ($Cache{"read_symlink"}{$Path} = $1);
+ return $1;
}
}
- return ($Cache{"read_symlink"}{$Path} = "");
+
+ # can't read
+ return "";
}
sub resolve_symlink($)
{
my $Path = $_[0];
return "" if(not $Path);
- return "" if(not -f $Path and not -l $Path);
+
if(defined $Cache{"resolve_symlink"}{$Path}) {
return $Cache{"resolve_symlink"}{$Path};
}
+ if(not -f $Path and not -l $Path)
+ { # broken
+ return ($Cache{"resolve_symlink"}{$Path} = "");
+ }
+ return ($Cache{"resolve_symlink"}{$Path} = resolve_symlink_I($Path));
+}
+
+sub resolve_symlink_I($)
+{
+ my $Path = $_[0];
return $Path if(isCyclical(\@RecurSymlink, $Path));
+ my $Res = $Path;
push(@RecurSymlink, $Path);
- if(-l $Path and my $Redirect=read_symlink($Path))
+ if(-l $Path and my $Redirect = read_symlink($Path))
{
if(is_abs($Redirect))
{ # absolute path
@@ -16268,95 +16588,124 @@
# the files inside sysroot
$Redirect = $SystemRoot.$Redirect;
}
- my $Res = resolve_symlink($Redirect);
- pop(@RecurSymlink);
- return ($Cache{"resolve_symlink"}{$Path} = $Res);
+ $Res = resolve_symlink($Redirect);
}
elsif($Redirect=~/\.\.[\/\\]/)
{ # relative path
$Redirect = joinPath(get_dirname($Path), $Redirect);
while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
- my $Res = resolve_symlink($Redirect);
- pop(@RecurSymlink);
- return ($Cache{"resolve_symlink"}{$Path} = $Res);
+ $Res = resolve_symlink($Redirect);
}
elsif(-f get_dirname($Path)."/".$Redirect)
{ # file name in the same directory
- my $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
- pop(@RecurSymlink);
- return ($Cache{"resolve_symlink"}{$Path} = $Res);
+ $Res = resolve_symlink(joinPath(get_dirname($Path), $Redirect));
}
else
{ # broken link
- pop(@RecurSymlink);
- return ($Cache{"resolve_symlink"}{$Path} = "");
+ $Res = "";
}
}
pop(@RecurSymlink);
- return ($Cache{"resolve_symlink"}{$Path} = $Path);
+ return $Res;
}
-sub find_lib_path($$)
+sub get_LibPath($$)
{
- my ($LibVersion, $DyLib) = @_;
- return "" if(not $DyLib or not $LibVersion);
- return $DyLib if(is_abs($DyLib));
- if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
- return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
+ my ($LibVersion, $Name) = @_;
+ return "" if(not $LibVersion or not $Name);
+ if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) {
+ return $Cache{"get_LibPath"}{$LibVersion}{$Name};
}
- if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
- return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
- }
- elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
- return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
- }
- else
+ return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name));
+}
+
+sub get_LibPath_I($$)
+{
+ my ($LibVersion, $Name) = @_;
+ if(is_abs($Name))
{
- foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
- { # search in default linker paths and then in all system paths
- if(-f $Dir."/".$DyLib) {
- return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
+ if(-f $Name)
+ { # absolute path
+ return $Name;
+ }
+ else
+ { # broken
+ return "";
+ }
+ }
+ if(my @Paths = sort keys(%{$RegisteredObjects{$LibVersion}{$Name}}))
+ { # registered paths
+ return $Paths[0];
+ }
+ if(my @Paths = sort keys(%{$RegisteredSONAMEs{$LibVersion}{$Name}}))
+ { # registered paths
+ return $Paths[0];
+ }
+ if(my $DefaultPath = $DyLib_DefaultPath{$Name})
+ { # ldconfig default paths
+ return $DefaultPath;
+ }
+ foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
+ { # search in default linker directories
+ # and then in all system paths
+ if(-f $Dir."/".$Name) {
+ return joinPath($Dir,$Name);
+ }
+ }
+ detectSystemObjects() if(not keys(%SystemObjects));
+ if(my @AllObjects = keys(%{$SystemObjects{$Name}})) {
+ return $AllObjects[0];
+ }
+ if(my $ShortName = parse_libname($Name, "name+ext", $OStarget))
+ {
+ if($ShortName ne $Name)
+ { # FIXME: check this case
+ if(my $Path = get_LibPath($LibVersion, $ShortName)) {
+ return $Path;
}
}
- detectSystemObjects() if(not keys(%SystemObjects));
- if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
- return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
- }
- my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
- if($ShortName ne $DyLib
- and my $Path = find_lib_path($ShortName))
- { # FIXME: check this case
- return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
- }
- return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
}
+ # can't find
+ return "";
}
-sub readSymbols_Lib($$$$$)
+sub readSymbols_Lib($$$$$$)
{
- my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
- return if(not $Lib_Path or not -f $Lib_Path);
- my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
- return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
- return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
+ my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_;
+ return () if(not $LibVersion or not $Lib_Path);
+ my $Lib_Name = get_filename(resolve_symlink($Lib_Path));
+ if($IsNeededLib)
+ {
+ if($CheckedDyLib{$LibVersion}{$Lib_Name}) {
+ return ();
+ }
+ }
+ return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
$CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
- my $Lib_SName = parse_libname($Lib_Name, "name+ext", $OStarget);
- if($CheckImpl and not $IsNeededLib) {
- getImplementations($LibVersion, $Lib_Path);
+ if($CheckImpl)
+ {
+ if(not $IsNeededLib) {
+ getImplementations($LibVersion, $Lib_Path);
+ }
}
push(@RecurLib, $Lib_Name);
my (%Value_Interface, %Interface_Value, %NeededLib) = ();
- if(not $IsNeededLib)
+ my $Lib_ShortName = parse_libname($Lib_Name, "short", $OStarget);
+ if($IsNeededLib)
+ { # change short name to use later for needed libraries
+ $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget);
+ }
+ else
{ # libstdc++ and libc are always used by other libs
# if you test one of these libs then you not need
# to find them in the system for reusing
- if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
+ if($Lib_ShortName eq "libstdc++")
{ # libstdc++.so.6
$STDCXX_TESTING = 1;
}
- if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
+ elsif($Lib_ShortName eq "libc")
{ # libc-2.11.3.so
$GLIBC_TESTING = 1;
}
@@ -16391,7 +16740,7 @@
my $realname = $1;
if($IsNeededLib)
{
- if(not $GroupNames->{$Lib_SName})
+ if(not defined $RegisteredObjects{$Lib_ShortName})
{
$DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
$DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
@@ -16401,9 +16750,11 @@
{
$Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
$Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
- if($COMMON_LANGUAGE{$LibVersion} ne "C++"
- and $realname=~/\A(_Z|\?)/) {
- setLanguage($LibVersion, "C++");
+ if($COMMON_LANGUAGE{$LibVersion} ne "C++")
+ {
+ if(index($realname, "_Z")==0 or index($realname, "?")==0) {
+ setLanguage($LibVersion, "C++");
+ }
}
if($CheckObjectsOnly
and $LibVersion==1) {
@@ -16413,17 +16764,20 @@
}
}
close(LIB);
- if($LIB_TYPE eq "dynamic")
- { # dependencies
- open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
- while(<LIB>)
- {
- if(/\s*([\/\\].+\.$LIB_EXT)\s*/
- and $1 ne $Lib_Path) {
- $NeededLib{$1} = 1;
+ if($Deps)
+ {
+ if($LIB_TYPE eq "dynamic")
+ { # dependencies
+ open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
+ while(<LIB>)
+ {
+ if(/\s*([\/\\].+\.$LIB_EXT)\s*/
+ and $1 ne $Lib_Path) {
+ $NeededLib{$1} = 1;
+ }
}
+ close(LIB);
}
- close(LIB);
}
}
elsif($OStarget eq "windows")
@@ -16454,7 +16808,7 @@
my $realname = $1;
if($IsNeededLib)
{
- if(not $GroupNames->{$Lib_SName})
+ if(not defined $RegisteredObjects{$Lib_ShortName})
{
$DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
$DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
@@ -16464,9 +16818,11 @@
{
$Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
$Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
- if($COMMON_LANGUAGE{$LibVersion} ne "C++"
- and $realname=~/\A(_Z|\?)/) {
- setLanguage($LibVersion, "C++");
+ if($COMMON_LANGUAGE{$LibVersion} ne "C++")
+ {
+ if(index($realname, "_Z")==0 or index($realname, "?")==0) {
+ setLanguage($LibVersion, "C++");
+ }
}
if($CheckObjectsOnly
and $LibVersion==1) {
@@ -16476,17 +16832,20 @@
}
}
close(LIB);
- if($LIB_TYPE eq "dynamic")
- { # dependencies
- open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
- while(<LIB>)
- {
- if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
- and $1 ne $Lib_Path) {
- $NeededLib{path_format($1, $OSgroup)} = 1;
+ if($Deps)
+ {
+ if($LIB_TYPE eq "dynamic")
+ { # dependencies
+ open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |");
+ while(<LIB>)
+ {
+ if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
+ and $1 ne $Lib_Path) {
+ $NeededLib{path_format($1, $OSgroup)} = 1;
+ }
}
+ close(LIB);
}
- close(LIB);
}
}
else
@@ -16507,137 +16866,156 @@
{ # write to pipe
open(LIB, $ReadelfCmd." |");
}
- my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
+ my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output
while(<LIB>)
{
if($LIB_TYPE eq "dynamic")
{ # dynamic library specifics
- if($symtab==1)
+ if(defined $symtab)
{
- if(/'\.dynsym'/)
+ if(index($_, "'.dynsym'")!=-1)
{ # dynamic table
- $symtab=0;
- next;
+ $symtab = undef;
}
- else
- { # do nothing with symtab
- next;
- }
+ # do nothing with symtab
+ next;
}
- elsif(/'\.symtab'/)
+ elsif(index($_, "'.symtab'")!=-1)
{ # symbol table
- $symtab=1;
+ $symtab = 1;
next;
}
}
- if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
+ if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_))
{ # read ELF entry
- if( $Ndx eq "UND" )
+ if($Ndx eq "UND")
{ # ignore interfaces that are imported from somewhere else
next;
}
- if($bind eq "WEAK"
+ if($Bind eq "WEAK"
and $Weak eq "-Weak")
{ # skip WEAK symbols
next;
}
- my ($realname, $version_spec, $version) = separate_symbol($fullname);
- if($type eq "OBJECT")
+ my $Short = $Symbol;
+ $Short=~s/\@.+//g;
+ if($Type eq "OBJECT")
{ # global data
- $GlobalDataObject{$LibVersion}{$fullname} = 1;
- $GlobalDataObject{$LibVersion}{$realname} = 1;
+ $GlobalDataObject{$LibVersion}{$Symbol} = 1;
+ $GlobalDataObject{$LibVersion}{$Short} = 1;
}
if($IsNeededLib)
{
- if(not $GroupNames->{$Lib_SName})
+ if(not defined $RegisteredObjects{$Lib_ShortName})
{
- $DepSymbol_Library{$LibVersion}{$fullname} = $Lib_Name;
- $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
+ $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
+ $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
}
}
else
{
- $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
- $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
- if($LIB_EXT eq "so")
- { # value
- $Interface_Value{$LibVersion}{$fullname} = $idx;
- $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
+ $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
+ $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1;
+ if($Vers)
+ {
+ if($LIB_EXT eq "so")
+ { # value
+ $Interface_Value{$LibVersion}{$Symbol} = $Value;
+ $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1;
+ }
}
- if($COMMON_LANGUAGE{$LibVersion} ne "C++"
- and $realname=~/\A(_Z|\?)/) {
- setLanguage($LibVersion, "C++");
+ if($COMMON_LANGUAGE{$LibVersion} ne "C++")
+ {
+ if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
+ setLanguage($LibVersion, "C++");
+ }
}
if($CheckObjectsOnly
and $LibVersion==1) {
- $CheckedSymbols{"Binary"}{$fullname} = 1;
+ $CheckedSymbols{"Binary"}{$Symbol} = 1;
}
}
}
elsif($LIB_TYPE eq "dynamic")
{ # dynamic library specifics
- if(/NEEDED.+\[([^\[\]]+)\]/)
- { # dependencies:
- # 0x00000001 (NEEDED) Shared library: [libc.so.6]
- $NeededLib{$1} = 1;
+ if($Deps)
+ {
+ if(/NEEDED.+\[([^\[\]]+)\]/)
+ { # dependencies:
+ # 0x00000001 (NEEDED) Shared library: [libc.so.6]
+ $NeededLib{$1} = 1;
+ }
}
}
}
close(LIB);
}
- if(not $IsNeededLib and $LIB_EXT eq "so")
- { # get symbol versions
- foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
- {
- next if(index($Symbol,"\@")==-1);
- if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
+ if($Vers)
+ {
+ if(not $IsNeededLib and $LIB_EXT eq "so")
+ { # get symbol versions
+ foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
{
- my $Interface_SymName = "";
- foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
+ next if(index($Symbol,"\@")==-1);
+ if(my $Value = $Interface_Value{$LibVersion}{$Symbol})
{
- if($Symbol_SameValue ne $Symbol
- and index($Symbol_SameValue,"\@")==-1)
+ my $Interface_SymName = "";
+ foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}}))
{
- $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
- $Interface_SymName = $Symbol_SameValue;
- last;
+ if($Symbol_SameValue ne $Symbol
+ and index($Symbol_SameValue,"\@")==-1)
+ {
+ $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
+ $Interface_SymName = $Symbol_SameValue;
+ last;
+ }
}
- }
- if(not $Interface_SymName)
- {
- if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
- and not $SymVer{$LibVersion}{$1}) {
- $SymVer{$LibVersion}{$1} = $Symbol;
+ if(not $Interface_SymName)
+ {
+ if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
+ and not $SymVer{$LibVersion}{$1}) {
+ $SymVer{$LibVersion}{$1} = $Symbol;
+ }
}
}
}
}
}
- foreach my $DyLib (sort keys(%NeededLib))
+ if($Deps)
{
- my $DepPath = find_lib_path($LibVersion, $DyLib);
- if($DepPath and -f $DepPath) {
- readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
+ foreach my $DyLib (sort keys(%NeededLib))
+ {
+ if(my $DepPath = get_LibPath($LibVersion, $DyLib)) {
+ readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers);
+ }
}
}
pop(@RecurLib);
return $Library_Symbol{$LibVersion};
}
-sub get_path_prefixes($)
+sub get_prefixes($)
{
- my $Path = $_[0];
- my ($Dir, $Name) = separate_path($Path);
my %Prefixes = ();
- foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
- {
- $Prefixes{$Name} = 1;
- $Name = joinPath($Prefix, $Name);
- last if(keys(%Prefixes)>5 or $Prefix eq "include");
- }
+ get_prefixes_I([$_[0]], \%Prefixes);
return keys(%Prefixes);
}
+sub get_prefixes_I($$)
+{
+ foreach my $P (@{$_[0]})
+ {
+ my @Parts = reverse(split(/[\/\\]+/, $P));
+ my $Name = $Parts[0];
+ foreach (1 .. $#Parts)
+ {
+ $_[1]->{$Name}{$P} = 1;
+ last if($_>4 or $Parts[$_] eq "include");
+ $Name = $Parts[$_].$SLASH.$Name;
+ }
+ }
+}
+
sub detectSystemHeaders()
{
my @SysHeaders = ();
@@ -16655,26 +17033,19 @@
}
}
foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
- {
+ { # search for config headers in the /usr/lib
next if(not -d $DevelPath);
- # search for config headers in the /usr/lib
- @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
- foreach my $Dir (cmd_find($DevelPath,"d","include",""))
- { # search for all include directories
- # this is for headers that are installed to /usr/lib
- # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
- if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
- next;
+ foreach (cmd_find($DevelPath,"f","",""))
+ {
+ if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
+ {
+ if(/\.h\Z|\/include\//) {
+ push(@SysHeaders, $_);
+ }
}
- @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
}
}
- foreach my $Path (@SysHeaders)
- {
- foreach my $Part (get_path_prefixes($Path)) {
- $SystemHeaders{$Part}{$Path}=1;
- }
- }
+ get_prefixes_I(\@SysHeaders, \%SystemHeaders);
}
sub detectSystemObjects()
@@ -16760,8 +17131,11 @@
}
foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
{
- if($Path=~/\Q$D\E([\/\\]|\Z)/) {
- return $SkipHeaders{$LibVersion}{"Path"}{$D};
+ if(index($Path, $D)!=-1)
+ {
+ if($Path=~/\Q$D\E([\/\\]|\Z)/) {
+ return $SkipHeaders{$LibVersion}{"Path"}{$D};
+ }
}
}
foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
@@ -16779,14 +17153,14 @@
return 0;
}
-sub register_objects($$)
+sub registerObject_Dir($$)
{
my ($Dir, $LibVersion) = @_;
if($SystemPaths{"lib"}{$Dir})
{ # system directory
return;
}
- if($RegisteredObjDirs{$LibVersion}{$Dir})
+ if($RegisteredObject_Dirs{$LibVersion}{$Dir})
{ # already registered
return;
}
@@ -16794,9 +17168,48 @@
{
next if(ignore_path($Path));
next if(skip_lib($Path, $LibVersion));
- $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+ registerObject($Path, $LibVersion);
}
- $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
+ $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1;
+}
+
+sub registerObject($$)
+{
+ my ($Path, $LibVersion) = @_;
+ my $Name = get_filename($Path);
+ $RegisteredObjects{$LibVersion}{$Name}{$Path} = 1;
+ if(my $SONAME = getSONAME($Path)) {
+ $RegisteredSONAMEs{$LibVersion}{$SONAME}{$Path} = 1;
+ }
+ if(my $SName = parse_libname($Name, "name", $OStarget)) {
+ $RegisteredObjects{$LibVersion}{$SName}{$Path} = 1;
+ }
+}
+
+sub getSONAME($)
+{
+ my $Path = $_[0];
+ return if(not $Path);
+ if(defined $Cache{"getSONAME"}{$Path}) {
+ return $Cache{"getSONAME"}{$Path};
+ }
+ my $ObjdumpCmd = get_CmdPath("objdump");
+ if(not $ObjdumpCmd) {
+ exitStatus("Not_Found", "can't find \"objdump\"");
+ }
+ my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null";
+ if($OSgroup eq "windows") {
+ $SonameCmd .= " | find \"SONAME\"";
+ }
+ else {
+ $SonameCmd .= " | grep SONAME";
+ }
+ if(my $SonameInfo = `$SonameCmd`) {
+ if($SonameInfo=~/SONAME\s+([^\s]+)/) {
+ return ($Cache{"getSONAME"}{$Path} = $1);
+ }
+ }
+ return ($Cache{"getSONAME"}{$Path}="");
}
sub getSOPaths_Dest($$)
@@ -16810,8 +17223,8 @@
if(not parse_libname($Dest, "name", $OStarget)) {
exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
}
- $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
- register_objects(get_dirname($Dest), $LibVersion);
+ registerObject($Dest, $LibVersion);
+ registerObject_Dir(get_dirname($Dest), $LibVersion);
return ($Dest);
}
elsif(-d $Dest)
@@ -16825,7 +17238,7 @@
{ # all files and symlinks that match the name of a library
if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
{
- $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+ registerObject($Path, $LibVersion);
$Libs{resolve_symlink($Path)}=1;
}
}
@@ -16836,7 +17249,7 @@
{
next if(ignore_path($Path));
next if(skip_lib($Path, $LibVersion));
- $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+ registerObject($Path, $LibVersion);
$Libs{resolve_symlink($Path)}=1;
}
if($OSgroup eq "macos")
@@ -16848,7 +17261,7 @@
if(get_filename($Path)!~/\./
and cmd_file($Path)=~/(shared|dynamic)\s+library/i)
{
- $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+ registerObject($Path, $LibVersion);
$Libs{resolve_symlink($Path)}=1;
}
}
@@ -16935,16 +17348,16 @@
my ($LibVersion, $Path) = @_;
return if(not $LibVersion or not -e $Path);
my $FilePath = "";
- if($Path=~/\.abi\Z/)
+ if(isDump_U($Path))
{ # input *.abi
$FilePath = $Path;
}
else
{ # input *.abi.tar.gz
$FilePath = unpackDump($Path);
- }
- if($FilePath!~/\.abi\Z/) {
- exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
+ if(not isDump_U($FilePath)) {
+ exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
+ }
}
my $ABI = {};
@@ -17105,11 +17518,6 @@
exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
}
}
- $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
- if(not $Library_Symbol{$LibVersion})
- { # support for old dumps
- $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
- }
if(checkDump($LibVersion, "2.15")) {
$DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"};
}
@@ -17186,9 +17594,11 @@
{ # data marked as -size in the dump
$GlobalDataObject{$LibVersion}{$Symbol}=1;
}
- if($COMMON_LANGUAGE{$LibVersion} ne "C++"
- and $Symbol=~/\A(_Z|\?)/) {
- setLanguage($LibVersion, "C++");
+ if($COMMON_LANGUAGE{$LibVersion} ne "C++")
+ {
+ if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
+ setLanguage($LibVersion, "C++");
+ }
}
}
}
@@ -17230,6 +17640,10 @@
}
delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"});
}
+ if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"})
+ { # support for old ABI dumps
+ $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup);
+ }
if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) {
$TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId;
}
@@ -17307,6 +17721,10 @@
{ # ABI dumps have no mangled names for C-functions
$SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
}
+ if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"})
+ { # support for old ABI dumps
+ $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup);
+ }
}
$Descriptor{$LibVersion}{"Dump"} = 1;
@@ -17359,6 +17777,11 @@
sub read_Libs_DumpInfo($$)
{
my ($ABI, $LibVersion) = @_;
+ $Library_Symbol{$LibVersion} = $ABI->{"Symbols"};
+ if(not $Library_Symbol{$LibVersion})
+ { # support for old dumps
+ $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"};
+ }
if(keys(%{$Library_Symbol{$LibVersion}})
and not $DumpAPI) {
$Descriptor{$LibVersion}{"Libs"} = "OK";
@@ -17415,7 +17838,7 @@
}
else
{ # files
- if($Path=~/\.xml\Z/i)
+ if($Path=~/\.(xml|desc)\Z/i)
{ # standard XML-descriptor
return readFile($Path);
}
@@ -17858,7 +18281,7 @@
sub get_depth($)
{
if(defined $Cache{"get_depth"}{$_[0]}) {
- return $Cache{"get_depth"}{$_[0]}
+ return $Cache{"get_depth"}{$_[0]};
}
return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
}
@@ -17895,10 +18318,16 @@
sub parse_libname($$$)
{
- my ($Name, $Type, $Target) = @_;
- if(not $Name) {
- return "";
+ return "" if(not $_[0]);
+ if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) {
+ return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]};
}
+ return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_));
+}
+
+sub parse_libname_I($$$)
+{
+ my ($Name, $Type, $Target) = @_;
if($Target eq "symbian") {
return parse_libname_symbian($Name, $Type);
}
@@ -18022,58 +18451,6 @@
return $Name;
}
-sub getPrefix($)
-{
- my $Str = $_[0];
- if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
- { # GetError
- return "";
- }
- if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
- { # XmuValidArea: Xmu
- return $1;
- }
- elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
- { # snfReadFont: snf
- return $1;
- }
- elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
- { # XRRTimes: XRR
- return $1;
- }
- elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
- { # alarm_event_add: alarm_
- return $1;
- }
- elsif($Str=~/\A(([a-z])\2{1,})/i)
- { # ffopen
- return $1;
- }
- else {
- return "";
- }
-}
-
-sub problem_title($)
-{
- if($_[0]==1) {
- return "1 problem";
- }
- else {
- return $_[0]." problems";
- }
-}
-
-sub warning_title($)
-{
- if($_[0]==1) {
- return "1 warning";
- }
- else {
- return $_[0]." warnings";
- }
-}
-
sub createSymbolsList($$$$$)
{
my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
@@ -18133,7 +18510,7 @@
{
if($Signature) {
$SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[symbol: <b>$Symbol</b>]</span><br/><br/>".$ContentDivEnd."\n");
- }# report_added
+ }
else {
$SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
}
@@ -18168,7 +18545,7 @@
my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
$SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
<body><div>\n$SYMBOLS_LIST</div>
- <br/><br/><hr/>\n".getReportFooter($LName)."
+ <br/><br/><hr/>\n".getReportFooter($LName, 1)."
<div style='height:999px;'></div></body></html>";
writeFile($SaveTo, $SYMBOLS_LIST);
}
@@ -18183,6 +18560,13 @@
return readFile($Path);
}
+sub add_target_libs($)
+{
+ foreach (@{$_[0]}) {
+ $TargetLibs{$_} = 1;
+ }
+}
+
sub is_target_lib($)
{
my $LName = $_[0];
@@ -18222,8 +18606,8 @@
my $UsedAltDescr = 0;
foreach my $Part (split(/\s*,\s*/, $Path))
{ # try to get version string from file path
- next if($Part=~/\.xml\Z/i);
- next if(isDump($Part));
+ next if(isDump($Part)); # ABI dump
+ next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor
my $VerNum = "";
if(parse_libname($Part, "name", $OStarget))
{
@@ -18783,7 +19167,7 @@
undef $Content1;
if(not $ABIdump) {
- exitStatus("Error", "internal error");
+ exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
}
if(not $ABIdump->{"TypeInfo"})
{ # support for old dumps
@@ -18862,8 +19246,15 @@
sub isDump($)
{
- if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
- { # returns a name of package
+ if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.tar\.gz|\.zip|\.xml|)\Z/) {
+ return $1;
+ }
+ return 0;
+}
+
+sub isDump_U($)
+{
+ if(get_filename($_[0])=~/\A(.+)\.(abi|abidump)(\.xml|)\Z/) {
return $1;
}
return 0;
@@ -19320,7 +19711,7 @@
}
}
-sub writeOpts()
+sub getSysOpts()
{
my %Opts = (
"OStarget"=>$OStarget,
@@ -19337,7 +19728,10 @@
"TargetLibraryName"=>$TargetLibraryName,
"CrossGcc"=>$CrossGcc,
"UseStaticLibs"=>$UseStaticLibs,
- "NoStdInc"=>$NoStdInc
+ "NoStdInc"=>$NoStdInc,
+
+ "BinaryOnly" => $BinaryOnly,
+ "SourceOnly" => $SourceOnly
);
return \%Opts;
}
@@ -19521,13 +19915,14 @@
if($DumpSystem)
{ # --dump-system
loadModule("SysCheck");
- if($DumpSystem=~/\.xml\Z/)
+ if($DumpSystem=~/\.(xml|desc)\Z/)
{ # system XML descriptor
if(not -f $DumpSystem) {
exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
}
my $Ret = readSystemDescriptor(readFile($DumpSystem));
- foreach (@{$Ret->{"Tools"}}) {
+ foreach (@{$Ret->{"Tools"}})
+ {
$SystemPaths{"bin"}{$_} = 1;
$TargetTools{$_}=1;
}
@@ -19571,14 +19966,14 @@
# and undname.exe
check_win32_env();
}
- dumpSystem(writeOpts());
+ dumpSystem(getSysOpts());
exit(0);
}
if($CmpSystems)
{ # --cmp-systems
detect_default_paths("bin"); # to extract dumps
loadModule("SysCheck");
- cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
+ cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
exit(0);
}
if($GenerateTemplate) {