aboutsummaryrefslogtreecommitdiff
path: root/modules/Internals
diff options
context:
space:
mode:
authorAndrey Ponomarenko <aponomarenko@rosalab.ru>2012-10-19 10:50:48 +0400
committerAndrey Ponomarenko <aponomarenko@rosalab.ru>2012-10-19 10:50:48 +0400
commit9927e33079b748463e883b96c4759f43f4d5de67 (patch)
tree5ac8a326451912e041394cf8555f74a590795815 /modules/Internals
parentf48ec93de57523ec5eef23a60d3b50c71c106983 (diff)
downloadabi-compliance-checker-9927e33079b748463e883b96c4759f43f4d5de67.tar.gz
ABI Compliance Checker 1.98.4
Diffstat (limited to 'modules/Internals')
-rw-r--r--modules/Internals/RegTests.pm108
-rw-r--r--modules/Internals/Styles/CmpSystems.css56
-rw-r--r--modules/Internals/Styles/Report.css2
-rw-r--r--modules/Internals/Styles/SymbolsList.css3
-rw-r--r--modules/Internals/SysCheck.pm1754
-rw-r--r--modules/Internals/XmlDump.pm6
6 files changed, 1452 insertions, 477 deletions
diff --git a/modules/Internals/RegTests.pm b/modules/Internals/RegTests.pm
index 628b4c0..7de39d7 100644
--- a/modules/Internals/RegTests.pm
+++ b/modules/Internals/RegTests.pm
@@ -51,6 +51,79 @@ sub testCpp()
$SOURCE1 .= "namespace TestNS {\n";
$SOURCE2 .= "namespace TestNS {\n";
+ # Pure_Virtual_Replacement
+ $HEADER1 .= "
+ class $DECL_SPEC PureVirtualReplacement {
+ public:
+ virtual int methodOld(int param) = 0;
+ int otherMethod();
+ };
+
+ class $DECL_SPEC PureVirtualReplacement_Derived: public PureVirtualReplacement {
+ public:
+ int methodOld(int param);
+ };";
+ $SOURCE1 .= "
+ int PureVirtualReplacement::otherMethod() { return 0; }
+ int PureVirtualReplacement_Derived::methodOld(int param) { return 0; }";
+
+ $HEADER2 .= "
+ class $DECL_SPEC PureVirtualReplacement {
+ public:
+ virtual int methodNew(int param) = 0;
+ int otherMethod();
+ };
+
+ class $DECL_SPEC PureVirtualReplacement_Derived: public PureVirtualReplacement {
+ public:
+ int methodNew(int param);
+ };";
+ $SOURCE2 .= "
+ int PureVirtualReplacement::otherMethod() { return 0; }
+ int PureVirtualReplacement_Derived::methodNew(int param) { return 0; }";
+
+ # Virtual_Replacement
+ $HEADER1 .= "
+ class $DECL_SPEC VirtualReplacement {
+ public:
+ virtual int methodOld(int param);
+ };";
+ $SOURCE1 .= "
+ int VirtualReplacement::methodOld(int param) { return 0; }";
+
+ $HEADER2 .= "
+ class $DECL_SPEC VirtualReplacement {
+ public:
+ virtual int methodNew(int param);
+ };";
+ $SOURCE2 .= "
+ int VirtualReplacement::methodNew(int param) { return 0; }";
+
+ # Removed_Symbol (renamed, source-compatible)
+ $HEADER1 .= "
+ int $DECL_SPEC renamedFunc(int param);";
+ $SOURCE1 .= "
+ int renamedFunc(int param) { return 0; }";
+
+ $HEADER2 .= "
+ int $DECL_SPEC renamedFunc_NewName(int param);
+ #define renamedFunc renamedFunc_NewName";
+ $SOURCE2 .= "
+ int renamedFunc_NewName(int param) { return 0; }";
+
+ # Removed_Symbol
+ $HEADER1 .= "
+ int $DECL_SPEC functionBecameInline(int param);";
+ $SOURCE1 .= "
+ int functionBecameInline(int param) { return 0; }";
+
+ $HEADER2 .= "
+ inline int functionBecameInline(int param) { return 0; }";
+
+ # Removed_Symbol (safe)
+ $HEADER1 .= "
+ inline int removedInlineFunction(int param) { return 0; }";
+
# Field_Became_Const
# Typedef
$HEADER1 .= "
@@ -2663,6 +2736,29 @@ sub testC()
my $DECL_SPEC = ($OSgroup eq "windows")?"__declspec( dllexport )":"";
my $EXTERN = ($OSgroup eq "windows")?"extern ":""; # add "extern" for CL compiler
+ # Used_Reserved
+ $HEADER1 .= "
+ typedef struct {
+ int f;
+ void* reserved0;
+ void* reserved1;
+ } UsedReserved;
+
+ $DECL_SPEC int usedReserved(UsedReserved p);";
+ $SOURCE1 .= "
+ int usedReserved(UsedReserved p) { return 0; }";
+
+ $HEADER2 .= "
+ typedef struct {
+ int f;
+ void* f0;
+ void* f1;
+ } UsedReserved;
+
+ $DECL_SPEC int usedReserved(UsedReserved p);";
+ $SOURCE2 .= "
+ int usedReserved(UsedReserved p) { return 0; }";
+
# Parameter_Type_And_Register
$HEADER1 .= "
typedef struct {
@@ -4295,12 +4391,12 @@ sub runTests($$$$$$$$)
changedDefaultVersion;
};
");
- $BuildCmd = $GCC_PATH." -Wl,--version-script version -shared -fkeep-inline-functions libsample.$Ext -o libsample.$LIB_EXT";
+ $BuildCmd = $GCC_PATH." -Wl,--version-script version -shared libsample.$Ext -o libsample.$LIB_EXT";
$BuildCmd_Test = $GCC_PATH." -Wl,--version-script version test.$Ext -Wl,libsample.$LIB_EXT -o test";
}
else
{
- $BuildCmd = $GCC_PATH." -shared -fkeep-inline-functions -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT";
+ $BuildCmd = $GCC_PATH." -shared -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT";
$BuildCmd_Test = $GCC_PATH." -x c++ test.$Ext -lstdc++ -Wl,libsample.$LIB_EXT -o test";
}
if(getArch(1)=~/\A(arm|x86_64)\Z/i)
@@ -4313,12 +4409,12 @@ sub runTests($$$$$$$$)
{ # using GCC -dynamiclib
if($Lang eq "C")
{
- $BuildCmd = $GCC_PATH." -dynamiclib -fkeep-inline-functions libsample.$Ext -o libsample.$LIB_EXT";
+ $BuildCmd = $GCC_PATH." -dynamiclib libsample.$Ext -o libsample.$LIB_EXT";
$BuildCmd_Test = $GCC_PATH." test.$Ext libsample.$LIB_EXT -o test";
}
else
{ # C++
- $BuildCmd = $GCC_PATH." -dynamiclib -fkeep-inline-functions -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT";
+ $BuildCmd = $GCC_PATH." -dynamiclib -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT";
$BuildCmd_Test = $GCC_PATH." -x c++ test.$Ext libsample.$LIB_EXT -o test";
}
}
@@ -4327,12 +4423,12 @@ sub runTests($$$$$$$$)
# symbian target
if($Lang eq "C")
{
- $BuildCmd = $GCC_PATH." -shared -fkeep-inline-functions libsample.$Ext -o libsample.$LIB_EXT";
+ $BuildCmd = $GCC_PATH." -shared libsample.$Ext -o libsample.$LIB_EXT";
$BuildCmd_Test = $GCC_PATH." test.$Ext -Wl,libsample.$LIB_EXT -o test";
}
else
{ # C++
- $BuildCmd = $GCC_PATH." -shared -fkeep-inline-functions -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT";
+ $BuildCmd = $GCC_PATH." -shared -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT";
$BuildCmd_Test = $GCC_PATH." -x c++ test.$Ext -Wl,libsample.$LIB_EXT -o test";
}
}
diff --git a/modules/Internals/Styles/CmpSystems.css b/modules/Internals/Styles/CmpSystems.css
index 53cba19..e4b4e5a 100644
--- a/modules/Internals/Styles/CmpSystems.css
+++ b/modules/Internals/Styles/CmpSystems.css
@@ -1,9 +1,8 @@
body {
font-family:Arial, sans-serif;
font-size:14px;
- background:#ffffff;
+ background:#FFFFFF;
color:Black;
- padding-left:15px;
}
hr {
color:Black;
@@ -12,31 +11,55 @@ hr {
border:0;
}
h1 {
- margin-bottom:3px;
- padding-bottom:3px;
font-size:26px;
white-space:nowrap;
}
-table.wikitable {
+h2 {
+ margin-bottom:0px;
+ padding-bottom:0px;
+ font-size:20px;
+ white-space:nowrap;
+}
+table.summary, table.wikitable {
border-collapse:collapse;
- margin:1em 1em 1em 0;
- background:#f9f9f9;
- border:1px #aaaaaa solid;
+ border:1px outset black;
+}
+table.summary td, table.summary th {
+ border:1px inset gray;
+ padding: 3px 5px 3px 5px;
+ white-space:nowrap;
+}
+table.summary th {
+ background-color:#EEEEEE;
+ font-weight:100;
+ text-align:left;
+ padding: 3px;
+ font-size:15px;
}
-table.wikitable td, th {
- border:1px #aaaaaa solid;
+table.summary td {
+ text-align:right;
+ padding-left:10px;
+ padding: 3px 5px 3px 10px;
+ font-size:16px;
+}
+table.wikitable td, table.wikitable th {
+ border:1px inset gray;
text-align:center;
- padding:0.2em;
- padding-left:5px;
- padding-right:5px;
+ padding: 3px;
white-space:nowrap;
}
table.wikitable th {
- background:#f2f2f2;
+ background-color:#EEEEEE;
+ font-size:15px;
+}
+table.wikitable td {
+ font-size:16px;
}
table.wikitable td.left {
text-align:left;
- background-color:#f2f2f2;
+ font-size:16px;
+ padding-left:5px;
+ background-color:#F9F9F9;
}
td.passed {
background-color:#CCFFCC;
@@ -54,8 +77,7 @@ a.default {
color:#336699;
}
th.severity {
- width:85px;
- color:Black;
+ width:55px;
}
sup {
font-size:10px;
diff --git a/modules/Internals/Styles/Report.css b/modules/Internals/Styles/Report.css
index 138a2a9..7b9853e 100644
--- a/modules/Internals/Styles/Report.css
+++ b/modules/Internals/Styles/Report.css
@@ -201,8 +201,10 @@ span.mangled {
padding-left:15px;
font-size:14px;
cursor:text;
+ color:#444444;
}
span.sym_ver {
+ color:#333333;
white-space:nowrap;
}
span.color_p {
diff --git a/modules/Internals/Styles/SymbolsList.css b/modules/Internals/Styles/SymbolsList.css
index 577936f..1e7757a 100644
--- a/modules/Internals/Styles/SymbolsList.css
+++ b/modules/Internals/Styles/SymbolsList.css
@@ -16,6 +16,7 @@ span.iname {
font-weight:bold;
font-size:16px;
color:#003E69;
+ margin-left:5px;
}
span.section {
font-weight:bold;
@@ -23,6 +24,7 @@ span.section {
font-size:16px;
color:#003E69;
white-space:nowrap;
+ margin-left:5px;
}
span:hover.section {
color:#336699;
@@ -62,7 +64,6 @@ span.mangled {
}
span.sym_ver {
color:#333333;
- font-size:14px;
white-space:nowrap;
}
span.color_p {
diff --git a/modules/Internals/SysCheck.pm b/modules/Internals/SysCheck.pm
index 5c6f873..fa45a06 100644
--- a/modules/Internals/SysCheck.pm
+++ b/modules/Internals/SysCheck.pm
@@ -26,7 +26,9 @@ use File::Temp qw(tempdir);
use Cwd qw(abs_path cwd);
my ($Debug, $Quiet, $LogMode, $CheckHeadersOnly, $SystemRoot, $MODULES_DIR, $GCC_PATH,
-$CrossPrefix, $TargetSysInfo, $TargetLibraryName, $CrossGcc, $UseStaticLibs, $NoStdInc, $OStarget);
+$CrossPrefix, $TargetSysInfo, $TargetLibraryName, $CrossGcc, $UseStaticLibs, $NoStdInc,
+$OStarget, $BinaryOnly, $SourceOnly);
+
my $OSgroup = get_OSgroup();
my $TMP_DIR = tempdir(CLEANUP=>1);
my $ORIG_DIR = cwd();
@@ -34,12 +36,13 @@ my $LIB_EXT = getLIB_EXT($OSgroup);
my %SysDescriptor;
my %Cache;
+my %NonPrefix;
sub cmpSystems($$$)
{ # -cmp-systems option handler
# should be used with -d1 and -d2 options
my ($SPath1, $SPath2, $Opts) = @_;
- readOpts($Opts);
+ initModule($Opts);
if(not $SPath1) {
exitStatus("Error", "the option -d1 should be specified");
}
@@ -86,7 +89,8 @@ sub cmpSystems($$$)
my $SYS_REPORT_PATH = "sys_compat_reports/".$SystemName1."_to_".$SystemName2."/$ArchName";
rmtree($SYS_REPORT_PATH);
my (%LibSoname1, %LibSoname2) = ();
- foreach (split(/\n/, readFile($SPath1."/sonames.txt"))) {
+ foreach (split(/\n/, readFile($SPath1."/sonames.txt")))
+ {
if(my ($LFName, $Soname) = split(/;/, $_))
{
if($OStarget eq "symbian") {
@@ -95,7 +99,8 @@ sub cmpSystems($$$)
$LibSoname1{$LFName} = $Soname;
}
}
- foreach (split(/\n/, readFile($SPath2."/sonames.txt"))) {
+ foreach (split(/\n/, readFile($SPath2."/sonames.txt")))
+ {
if(my ($LFName, $Soname) = split(/;/, $_))
{
if($OStarget eq "symbian") {
@@ -105,12 +110,14 @@ sub cmpSystems($$$)
}
}
my (%LibV1, %LibV2) = ();
- foreach (split(/\n/, readFile($SPath1."/versions.txt"))) {
+ foreach (split(/\n/, readFile($SPath1."/versions.txt")))
+ {
if(my ($LFName, $V) = split(/;/, $_)) {
$LibV1{$LFName} = $V;
}
}
- foreach (split(/\n/, readFile($SPath2."/versions.txt"))) {
+ foreach (split(/\n/, readFile($SPath2."/versions.txt")))
+ {
if(my ($LFName, $V) = split(/;/, $_)) {
$LibV2{$LFName} = $V;
}
@@ -126,6 +133,7 @@ sub cmpSystems($$$)
@Dumps2 = cmd_find($SPath2."/abi_dumps","f","*.zip",1);
}
my (%LibVers1, %LibVers2) = ();
+ my (%ShortNames1, %ShortNames2) = ();
foreach my $DPath (@Dumps1)
{
if(my $Name = isDump($DPath))
@@ -138,6 +146,7 @@ sub cmpSystems($$$)
$Soname = $Name;
}
$LibVers1{$Soname}{$V} = $DPath;
+ $ShortNames1{parse_libname($Soname, "short", $OStarget)}{$Soname} = 1;
}
}
foreach my $DPath (@Dumps2)
@@ -152,10 +161,12 @@ sub cmpSystems($$$)
$Soname = $Name;
}
$LibVers2{$Soname}{$V} = $DPath;
+ $ShortNames2{parse_libname($Soname, "short", $OStarget)}{$Soname} = 1;
}
}
my (%Added, %Removed) = ();
- my (%ChangedSoname, %TestResults, %SONAME_Changed);
+ my (%ChangedSoname, %TestResults) = ();
+ my (%AddedShort, %RemovedShort) = ();
if(not $GroupByHeaders)
{
my %ChangedSoname_Safe = ();
@@ -187,7 +198,6 @@ sub cmpSystems($$$)
$LibVers1{$LName} = $LibVers1{$Soname};
}
}
- my (%AddedShort, %RemovedShort) = ();
if(not $GroupByHeaders) {
printMsg("INFO", "Checking added/removed libs");
}
@@ -209,11 +219,18 @@ sub cmpSystems($$$)
{ # removed library
if(not $LibSoname2{$LName})
{
- $RemovedShort{parse_libname($LName, "name+ext", $OStarget)}{$LName}=1;
- $Removed{$LName}{"version"}=$Versions1[0];
+ my $LSName = parse_libname($LName, "short", $OStarget);
+ $RemovedShort{$LSName}{$LName} = 1;
+ my $V = $Versions1[0];
+ $Removed{$LName}{"version"} = $V;
+
my $ListPath = "info/$LName/symbols.html";
- createSymbolsList($LibVers1{$LName}{$Versions1[0]},
- $SYS_REPORT_PATH."/".$ListPath, $LName, $Versions1[0]."-".$SystemName1, $ArchName);
+ my $FV = $SystemName1;
+ if($V) {
+ $FV = $V."-".$FV;
+ }
+ createSymbolsList($LibVers1{$LName}{$V},
+ $SYS_REPORT_PATH."/".$ListPath, $LName, $FV, $ArchName);
$Removed{$LName}{"list"} = $ListPath;
}
}
@@ -240,11 +257,18 @@ sub cmpSystems($$$)
{ # added library
if(not $LibSoname1{$LName})
{
- $AddedShort{parse_libname($LName, "name+ext", $OStarget)}{$LName}=1;
- $Added{$LName}{"version"}=$Versions2[0];
+ my $LSName = parse_libname($LName, "short", $OStarget);
+ $AddedShort{$LSName}{$LName} = 1;
+ my $V = $Versions2[0];
+ $Added{$LName}{"version"} = $V;
+
my $ListPath = "info/$LName/symbols.html";
- createSymbolsList($LibVers2{$LName}{$Versions2[0]},
- $SYS_REPORT_PATH."/".$ListPath, $LName, $Versions2[0]."-".$SystemName2, $ArchName);
+ my $FV = $SystemName2;
+ if($V) {
+ $FV = $V."-".$FV;
+ }
+ createSymbolsList($LibVers2{$LName}{$V},
+ $SYS_REPORT_PATH."/".$ListPath, $LName, $FV, $ArchName);
$Added{$LName}{"list"} = $ListPath;
}
}
@@ -252,13 +276,26 @@ sub cmpSystems($$$)
foreach my $LSName (keys(%AddedShort))
{ # changed SONAME
my @AddedSonames = keys(%{$AddedShort{$LSName}});
- next if(length(@AddedSonames)!=1);
- my @RemovedSonames = keys(%{$RemovedShort{$LSName}});
- next if(length(@RemovedSonames)!=1);
- $ChangedSoname{$AddedSonames[0]}=$RemovedSonames[0];
- $ChangedSoname{$RemovedSonames[0]}=$AddedSonames[0];
+ next if($#AddedSonames!=0);
+
+ if(defined $RemovedShort{$LSName})
+ { # removed old soname
+ my @RemovedSonames = keys(%{$RemovedShort{$LSName}});
+ $ChangedSoname{$AddedSonames[0]} = $RemovedSonames[0];
+ $ChangedSoname{$RemovedSonames[0]} = $AddedSonames[0];
+ }
+ elsif(defined $ShortNames1{$LSName})
+ { # saved old soname
+ my @Sonames = keys(%{$ShortNames1{$LSName}});
+ $ChangedSoname{$AddedSonames[0]} = $Sonames[0];
+ $ChangedSoname{$Sonames[0]} = $AddedSonames[0];
+ }
}
}
+
+ my %SONAME_Changed = ();
+ my %SONAME_Added = ();
+
foreach my $LName (sort {lc($a) cmp lc($b)} keys(%LibVers1))
{
if(not is_target_lib($LName)) {
@@ -277,12 +314,8 @@ sub cmpSystems($$$)
next;
}
my ($LV2, $LName2, $DPath2) = ();
- if(@Versions2)
- {
- $LV2 = $Versions2[0];
- $DPath2 = $LibVers2{$LName}{$LV2};
- }
- elsif($LName2 = $ChangedSoname{$LName})
+ my $LName_Short = parse_libname($LName, "name+ext", $OStarget);
+ if($LName2 = $ChangedSoname{$LName})
{ # changed SONAME
@Versions2 = keys(%{$LibVers2{$LName2}});
if(not @Versions2 or $#Versions2>=1) {
@@ -290,18 +323,47 @@ sub cmpSystems($$$)
}
$LV2 = $Versions2[0];
$DPath2 = $LibVers2{$LName2}{$LV2};
- $LName = parse_libname($LName, "name+ext", $OStarget);
- $SONAME_Changed{$LName} = 1;
+
+ if(defined $LibVers2{$LName})
+ { # show old soname in the table
+ $TestResults{$LName}{"v1"} = $LV1;
+ $TestResults{$LName}{"v2"} = $LV1;
+ }
+
+ if(defined $LibVers2{$LName})
+ { # do not count results
+ $SONAME_Added{$LName_Short} = 1;
+ }
+ $SONAME_Changed{$LName_Short} = 1;
+ $LName = $LName_Short;
+ }
+ elsif(@Versions2)
+ {
+ $LV2 = $Versions2[0];
+ $DPath2 = $LibVers2{$LName}{$LV2};
}
else
{ # removed
next;
}
- my ($FV1, $FV2) = ($LV1."-".$SystemName1, $LV2."-".$SystemName2);
- my $ACC_compare = "perl $0 -binary -l $LName -d1 \"$DPath1\" -d2 \"$DPath2\"";
- my $LReportPath = "compat_reports/$LName/abi_compat_report.html";
- my $LReportPath_Full = $SYS_REPORT_PATH."/".$LReportPath;
- $ACC_compare .= " -report-path \"$LReportPath_Full\"";
+ my $ACC_compare = "perl $0 -l $LName -d1 \"$DPath1\" -d2 \"$DPath2\"";
+
+ my $BinReportPath = "compat_reports/$LName/abi_compat_report.html";
+ my $SrcReportPath = "compat_reports/$LName/src_compat_report.html";
+ my $BinReportPath_Full = $SYS_REPORT_PATH."/".$BinReportPath;
+ my $SrcReportPath_Full = $SYS_REPORT_PATH."/".$SrcReportPath;
+
+ if($BinaryOnly)
+ {
+ $ACC_compare .= " -binary";
+ $ACC_compare .= " -bin-report-path \"$BinReportPath_Full\"";
+ }
+ if($SourceOnly)
+ {
+ $ACC_compare .= " -source";
+ $ACC_compare .= " -src-report-path \"$SrcReportPath_Full\"";
+ }
+
if($CheckHeadersOnly) {
$ACC_compare .= " -headers-only";
}
@@ -334,12 +396,83 @@ sub cmpSystems($$$)
else
{
printMsg("INFO", "Ok");
- $TestResults{$LName} = readAttributes($LReportPath_Full, 0);
+ if($BinaryOnly)
+ {
+ $TestResults{$LName}{"Binary"} = readAttributes($BinReportPath_Full, 0);
+ $TestResults{$LName}{"Binary"}{"path"} = $BinReportPath;
+ }
+ if($SourceOnly)
+ {
+ $TestResults{$LName}{"Source"} = readAttributes($SrcReportPath_Full, 0);
+ $TestResults{$LName}{"Source"}{"path"} = $SrcReportPath;
+ }
$TestResults{$LName}{"v1"} = $LV1;
$TestResults{$LName}{"v2"} = $LV2;
- $TestResults{$LName}{"path"} = $LReportPath;
}
}
+
+ my %META_DATA = ();
+ my %STAT = ();
+ foreach my $Comp ("Binary", "Source")
+ {
+ $STAT{$Comp}{"total"} = keys(%TestResults) - keys(%SONAME_Changed);
+ $STAT{$Comp}{"added"} = keys(%Added);
+ $STAT{$Comp}{"removed"} = keys(%Removed);
+
+ foreach ("added", "removed")
+ {
+ my $Kind = $_."_interfaces";
+ foreach my $LName (keys(%TestResults))
+ {
+ next if($SONAME_Changed{$LName});
+ $STAT{$Comp}{$Kind} += $TestResults{$LName}{$Comp}{$_};
+ }
+ push(@{$META_DATA{$Comp}}, $Kind.":".$STAT{$Comp}{$Kind});
+ }
+ foreach my $T ("type", "interface")
+ {
+ foreach my $S ("high", "medium", "low")
+ {
+ my $Kind = $T."_problems_".$S;
+ foreach my $LName (keys(%TestResults))
+ {
+ next if($SONAME_Changed{$LName});
+ $STAT{$Comp}{$Kind} += $TestResults{$LName}{$Comp}{$Kind};
+ }
+ push(@{$META_DATA{$Comp}}, $Kind.":".$STAT{$Comp}{$Kind});
+ }
+ }
+ foreach my $LName (keys(%TestResults))
+ {
+ next if($SONAME_Changed{$LName});
+ foreach ("affected", "changed_constants") {
+ $STAT{$Comp}{$_} += $TestResults{$LName}{$Comp}{$_};
+ }
+ if(not defined $STAT{$Comp}{"verdict"}
+ and $TestResults{$LName}{$Comp}{"verdict"} eq "incompatible") {
+ $STAT{$Comp}{"verdict"} = "incompatible";
+ }
+ }
+ if(not defined $STAT{$Comp}{"verdict"}) {
+ $STAT{$Comp}{"verdict"} = "compatible";
+ }
+ if($STAT{$Comp}{"total"}) {
+ $STAT{$Comp}{"affected"} /= $STAT{$Comp}{"total"};
+ }
+ else {
+ $STAT{$Comp}{"affected"} = 0;
+ }
+ $STAT{$Comp}{"affected"} = show_number($STAT{$Comp}{"affected"});
+ if($STAT{$Comp}{"verdict"}>1) {
+ $STAT{$Comp}{"verdict"} = 1;
+ }
+ push(@{$META_DATA{$Comp}}, "changed_constants:".$STAT{$Comp}{"changed_constants"});
+ push(@{$META_DATA{$Comp}}, "tool_version:".get_dumpversion("perl $0"));
+ foreach ("removed", "added", "total", "affected", "verdict") {
+ @{$META_DATA{$Comp}} = ($_.":".$STAT{$Comp}{$_}, @{$META_DATA{$Comp}});
+ }
+ }
+
my $SONAME_Title = "SONAME";
if($OStarget eq "windows") {
$SONAME_Title = "DLL";
@@ -351,62 +484,267 @@ sub cmpSystems($$$)
{ # show the list of headers
$SONAME_Title = "Header File";
}
- my $SYS_REPORT = "<h1>Binary compatibility between <span style='color:Blue;'>$SystemName1</span> and <span style='color:Blue;'>$SystemName2</span> on <span style='color:Blue;'>".showArch($ArchName)."</span></h1>\n";
+
+ my $SYS_REPORT = "<h1>";
+
+ if($BinaryOnly and $SourceOnly) {
+ $SYS_REPORT .= "API compatibility";
+ }
+ elsif($BinaryOnly) {
+ $SYS_REPORT .= "Binary compatibility";
+ }
+ elsif($SourceOnly) {
+ $SYS_REPORT .= "Source compatibility";
+ }
+
+ $SYS_REPORT .= " report between <span style='color:Blue;'>$SystemName1</span> and <span style='color:Blue;'>$SystemName2</span>";
+ $SYS_REPORT .= " on <span style='color:Blue;'>".showArch($ArchName)."</span>\n";
+
+ $SYS_REPORT .= "</h1>";
# legend
- $SYS_REPORT .= "<table cellpadding='2'><tr>\n";
- $SYS_REPORT .= "<td class='new' width='85px' style='text-align:center'>Added</td>\n";
- $SYS_REPORT .= "<td class='passed' width='85px' style='text-align:center'>Compatible</td>\n";
- $SYS_REPORT .= "</tr><tr>\n";
- $SYS_REPORT .= "<td class='warning' style='text-align:center'>Warning</td>\n";
- $SYS_REPORT .= "<td class='failed' style='text-align:center'>Incompatible</td>\n";
- $SYS_REPORT .= "</tr></table>\n";
-
- $SYS_REPORT .= "<table class='wikitable'>
- <tr><th rowspan='2'>$SONAME_Title<sup>".(keys(%TestResults) + keys(%Added) + keys(%Removed) - keys(%SONAME_Changed))."</sup></th>";
+ my $LEGEND = "<table cellspacing='2' cellpadding='3'><tr>\n";
+ $LEGEND .= "<td class='new' width='70px' style='text-align:left'>Added</td>\n";
+ $LEGEND .= "<td class='passed' width='70px' style='text-align:left'>Compatible</td>\n";
+ $LEGEND .= "</tr><tr>\n";
+ $LEGEND .= "<td class='warning' style='text-align:left'>Warning</td>\n";
+ $LEGEND .= "<td class='failed' style='text-align:left'>Incompatible</td>\n";
+ $LEGEND .= "</tr></table>\n";
+
+ $SYS_REPORT .= $LEGEND;
+
+ # test info
+ my $TEST_INFO = "<h2>Test Info</h2><hr/>\n";
+ $TEST_INFO .= "<table class='summary'>\n";
+ $TEST_INFO .= "<tr><th>System #1</th><td>$SystemName1</td></tr>\n";
+ $TEST_INFO .= "<tr><th>System #2</th><td>$SystemName2</td></tr>\n";
+ $TEST_INFO .= "<tr><th>CPU Type</th><td>".showArch($ArchName)."</td></tr>\n";
+ $TEST_INFO .= "</table>\n";
+
+ # $SYS_REPORT .= $TEST_INFO;
+
+ my $Total = (keys(%TestResults) + keys(%Added) + keys(%Removed) - keys(%SONAME_Changed));
+
+ # test results
+ my $TEST_RES = "<h2>Test Results</h2><hr/>\n";
+ $TEST_RES .= "<table class='summary'>\n";
+ $TEST_RES .= "<tr><th>Total Libraries</th><td><a href='#Report'>$Total</a></td></tr>\n";
+ if($BinaryOnly and $SourceOnly)
+ {
+ if(my $Affected = $STAT{"Binary"}{"affected"}) {
+ $TEST_RES .= "<tr><th>Binary Compatibility</th><td class='failed'>".cut_off_number(100 - $Affected, 3, 1)."%</td></tr>\n";
+ }
+ else {
+ $TEST_RES .= "<tr><th>Binary Compatibility</th><td class='passed'>100%</td></tr>\n";
+ }
+ if(my $Affected = $STAT{"Source"}{"affected"}) {
+ $TEST_RES .= "<tr><th>Source Compatibility</th><td class='failed'>".cut_off_number(100 - $Affected, 3, 1)."%</td></tr>\n";
+ }
+ else {
+ $TEST_RES .= "<tr><th>Source Compatibility</th><td class='passed'>100%</td></tr>\n";
+ }
+ }
+ elsif($BinaryOnly)
+ {
+ if(my $Affected = $STAT{"Binary"}{"affected"}) {
+ $TEST_RES .= "<tr><th>Compatibility</th><td class='failed'>".cut_off_number(100 - $Affected, 3, 1)."%</td></tr>\n";
+ }
+ else {
+ $TEST_RES .= "<tr><th>Compatibility</th><td class='passed'>100%</td></tr>\n";
+ }
+ }
+ elsif($SourceOnly)
+ {
+ if(my $Affected = $STAT{"Source"}{"affected"}) {
+ $TEST_RES .= "<tr><th>Compatibility</th><td class='failed'>".cut_off_number(100 - $Affected, 3, 1)."%</td></tr>\n";
+ }
+ else {
+ $TEST_RES .= "<tr><th>Compatibility</th><td class='passed'>100%</td></tr>\n";
+ }
+ }
+ $TEST_RES .= "</table>\n";
+
+ $SYS_REPORT .= $TEST_RES;
+
+ # problem summary
+ foreach my $Comp ("Binary", "Source")
+ {
+ my $PSUMMARY = "<h2>Problem Summary";
+ if(not $BinaryOnly or not $SourceOnly)
+ {
+ next if($BinaryOnly and $Comp eq "Source");
+ next if($SourceOnly and $Comp eq "Binary");
+ }
+ else {
+ $PSUMMARY .= " ($Comp Compatibility)\n";
+ }
+ $PSUMMARY .= "</h2><hr/>\n";
+
+ $PSUMMARY .= "<table class='summary'>\n";
+ $PSUMMARY .= "<tr><th></th><th style='text-align:center;font-weight:bold;'>Severity</th><th style='text-align:center;font-weight:bold;'>Count</th></tr>\n";
+ if(my $Added = $STAT{$Comp}{"added_interfaces"}) {
+ $PSUMMARY .= "<tr><th>Added Symbols</th><td>-</td><td class='new'>$Added</td></tr>\n";
+ }
+ else {
+ $PSUMMARY .= "<tr><th>Added Symbols</th><td>-</td><td>0</td></tr>\n";
+ }
+ if(my $Removed = $STAT{$Comp}{"removed_interfaces"}) {
+ $PSUMMARY .= "<tr><th>Removed Symbols</th><td>High</td><td class='failed'>$Removed</td></tr>\n";
+ }
+ else {
+ $PSUMMARY .= "<tr><th>Removed Symbols</th><td>High</td><td>0</td></tr>\n";
+ }
+ $PSUMMARY .= "<tr>";
+
+ if($BinaryOnly and $SourceOnly) {
+ $PSUMMARY .= "<th rowspan='3'>$Comp Compatibility<br/>Problems</th>";
+ }
+ else {
+ $PSUMMARY .= "<th rowspan='3'>Compatibility<br/>Problems</th>";
+ }
+ if(my $High = $STAT{$Comp}{"interface_problems_high"}+$STAT{$Comp}{"type_problems_high"}) {
+ $PSUMMARY .= "<td>High</td><td class='failed'>$High</td>\n";
+ }
+ else {
+ $PSUMMARY .= "<td>High</td><td>0</td>\n";
+ }
+ $PSUMMARY .= "</tr>";
+ $PSUMMARY .= "<tr>";
+ if(my $Medium = $STAT{$Comp}{"interface_problems_medium"}+$STAT{$Comp}{"type_problems_medium"}) {
+ $PSUMMARY .= "<td>Medium</td><td class='failed'>$Medium</td>\n";
+ }
+ else {
+ $PSUMMARY .= "<td>Medium</td><td>0</td>\n";
+ }
+ $PSUMMARY .= "</tr>";
+ $PSUMMARY .= "<tr>";
+ if(my $Low = $STAT{$Comp}{"interface_problems_low"}+$STAT{$Comp}{"type_problems_low"}+$STAT{$Comp}{"changed_constants"}) {
+ $PSUMMARY .= "<td>Low</td><td class='warning'>$Low</td>\n";
+ }
+ else {
+ $PSUMMARY .= "<td>Low</td><td>0</td>\n";
+ }
+ $PSUMMARY .= "</tr>";
+ $PSUMMARY .= "</table>\n";
+
+ $SYS_REPORT .= $PSUMMARY;
+ }
+
+ # added/removed libraries
+ my $LIB_PROBLEMS = "<h2>Added/Removed Libraries</h2><hr/>\n";
+ $LIB_PROBLEMS .= "<table class='summary'>\n";
+ $LIB_PROBLEMS .= "<tr><th></th><th style='text-align:center;font-weight:bold;'>Severity</th><th style='text-align:center;font-weight:bold;'>Count</th></tr>\n";
+ if(my $Added = keys(%Added)) {
+ $LIB_PROBLEMS .= "<tr><th>Added</th><td>-</td><td class='new'>$Added</td></tr>\n";
+ }
+ else {
+ $LIB_PROBLEMS .= "<tr><th>Added</th><td>-</td><td>0</td></tr>\n";
+ }
+ if(my $Removed = keys(%Removed)) {
+ $LIB_PROBLEMS .= "<tr><th>Removed</th><td>High</td><td class='failed'>$Removed</td></tr>\n";
+ }
+ else {
+ $LIB_PROBLEMS .= "<tr><th>Removed</th><td>High</td><td>0</td></tr>\n";
+ }
+ $LIB_PROBLEMS .= "</table>\n";
+ $SYS_REPORT .= $LIB_PROBLEMS;
+
+ # report table
+ $SYS_REPORT .= "<a name='Report'></a>\n";
+ $SYS_REPORT .= "<h2>Report</h2><hr/>\n";
+
+ # $SYS_REPORT .= "<br/>";
+
+ $SYS_REPORT .= "<table class='wikitable'>";
+
+ $SYS_REPORT .= "<tr>";
+ $SYS_REPORT .= "<th rowspan='2'>$SONAME_Title<sup>$Total</sup></th>";
if(not $GroupByHeaders) {
- $SYS_REPORT .= "<th colspan='2'>VERSION</th>";
+ $SYS_REPORT .= "<th colspan='2'>Version</th>";
}
- $SYS_REPORT .= "<th rowspan='2'>Compatibility</th>
- <th rowspan='2'>Added<br/>Symbols</th>
- <th rowspan='2'>Removed<br/>Symbols</th>
- <th colspan='3' style='white-space:nowrap;'>API Changes / Compatibility Problems</th></tr>";
+ if($BinaryOnly and $SourceOnly) {
+ $SYS_REPORT .= "<th colspan='2'>Compatible</th>";
+ }
+ else {
+ $SYS_REPORT .= "<th rowspan='2'>Compatible</th>";
+ }
+ $SYS_REPORT .= "<th rowspan='2'>Added<br/>Symbols</th><th rowspan='2'>Removed<br/>Symbols</th>";
+ if($BinaryOnly and $SourceOnly)
+ {
+ $SYS_REPORT .= "<th colspan='3' style='white-space:nowrap;'>API Changes / Binary Compatibility</th>";
+ $SYS_REPORT .= "<th colspan='3' style='white-space:nowrap;'>API Changes / Source Compatibility</th>";
+ }
+ else {
+ $SYS_REPORT .= "<th colspan='3' style='white-space:nowrap;'>API Changes / Compatibility</th>";
+ }
+ $SYS_REPORT .= "</tr>";
+
+ $SYS_REPORT .= "<tr>";
if(not $GroupByHeaders) {
- $SYS_REPORT .= "<tr><th>$SystemName1</th><th>$SystemName2</th>";
+ $SYS_REPORT .= "<th>$SystemName1</th><th>$SystemName2</th>";
+ }
+ if($BinaryOnly and $SourceOnly) {
+ $SYS_REPORT .= "<th>Binary</th><th>Source</th>";
}
- $SYS_REPORT .= "<th class='severity'>High</th><th class='severity'>Medium</th><th class='severity'>Low</th></tr>\n";
+ $SYS_REPORT .= "<th class='severity'>High</th><th class='severity'>Medium</th><th class='severity'>Low</th>\n" if($BinaryOnly);
+ $SYS_REPORT .= "<th class='severity'>High</th><th class='severity'>Medium</th><th class='severity'>Low</th>\n" if($SourceOnly);
+ $SYS_REPORT .= "</tr>";
my %RegisteredPairs = ();
+
+ my $Columns = 2;
+ if($BinaryOnly) {
+ $Columns += 3;
+ }
+ if($SourceOnly) {
+ $Columns += 3;
+ }
+
foreach my $LName (sort {lc($a) cmp lc($b)} (keys(%TestResults), keys(%Added), keys(%Removed)))
{
next if($SONAME_Changed{$LName});
- my $CompatReport = $TestResults{$LName}{"path"};
+ my $LName_Short = parse_libname($LName, "name+ext", $OStarget);
my $Anchor = $LName;
- $Anchor=~s/\+/p/g;# anchors to libFLAC++ is libFLACpp
- $Anchor=~s/\~//g;# libqttracker.so.1~6
+ $Anchor=~s/\+/p/g; # anchor for libFLAC++ is libFLACpp
+ $Anchor=~s/\~/-/g; # libqttracker.so.1~6
$SYS_REPORT .= "<tr>\n<td class='left'>$LName<a name=\'$Anchor\'></a></td>\n";
if(defined $Removed{$LName}) {
- $SYS_REPORT .= "<td class='failed'>".$Removed{$LName}{"version"}."</td>\n";
+ $SYS_REPORT .= "<td class='failed'>".printVer($Removed{$LName}{"version"})."</td>\n";
}
elsif(defined $Added{$LName}) {
$SYS_REPORT .= "<td class='new'><a href='".$Added{$LName}{"list"}."'>added</a></td>\n";
}
- elsif(not $GroupByHeaders) {
- $SYS_REPORT .= "<td>".$TestResults{$LName}{"v1"}."</td>\n";
+ elsif(not $GroupByHeaders)
+ {
+ $SYS_REPORT .= "<td>".printVer($TestResults{$LName}{"v1"})."</td>\n";
+ }
+ my $SONAME_report = "<td colspan=\'$Columns\' rowspan='2'>";
+ if($BinaryOnly and $SourceOnly) {
+ $SONAME_report .= "SONAME has been changed (see <a href='".$TestResults{$LName_Short}{"Binary"}{"path"}."'>binary</a> and <a href='".$TestResults{$LName_Short}{"Source"}{"path"}."'>source</a> compatibility reports)\n";
+ }
+ elsif($BinaryOnly) {
+ $SONAME_report .= "SONAME has been <a href='".$TestResults{$LName_Short}{"Binary"}{"path"}."'>changed</a>\n";
}
+ elsif($SourceOnly) {
+ $SONAME_report .= "SONAME has been <a href='".$TestResults{$LName_Short}{"Source"}{"path"}."'>changed</a>\n";
+ }
+ $SONAME_report .= "</td>";
+
if(defined $Added{$LName})
{ # added library
- $SYS_REPORT .= "<td class='new'>".$Added{$LName}{"version"}."</td>\n";
- $SYS_REPORT .= "<td class='passed'>100%</td>\n";
+ $SYS_REPORT .= "<td class='new'>".printVer($Added{$LName}{"version"})."</td>\n";
+ $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($BinaryOnly);
+ $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($SourceOnly);
if($RegisteredPairs{$LName}) {
# do nothing
}
elsif(my $To = $ChangedSoname{$LName})
{
$RegisteredPairs{$To}=1;
- $SYS_REPORT .= "<td colspan='5' rowspan='2'>SONAME has <a href='".$TestResults{parse_libname($LName, "name+ext", $OStarget)}{"path"}."'>changed</a></td>\n";
+ $SYS_REPORT .= $SONAME_report;
}
- else {
- foreach (1 .. 5) {
+ else
+ {
+ foreach (1 .. $Columns) {
$SYS_REPORT .= "<td>n/a</td>\n"; # colspan='5'
}
}
@@ -416,164 +754,325 @@ sub cmpSystems($$$)
elsif(defined $Removed{$LName})
{ # removed library
$SYS_REPORT .= "<td class='failed'><a href='".$Removed{$LName}{"list"}."'>removed</a></td>\n";
- $SYS_REPORT .= "<td class='failed'>0%</td>\n";
+ $SYS_REPORT .= "<td class='failed'>0%</td>\n" if($BinaryOnly);
+ $SYS_REPORT .= "<td class='failed'>0%</td>\n" if($SourceOnly);
if($RegisteredPairs{$LName}) {
# do nothing
}
elsif(my $To = $ChangedSoname{$LName})
{
$RegisteredPairs{$To}=1;
- $SYS_REPORT .= "<td colspan='5' rowspan='2'>SONAME has <a href='".$TestResults{parse_libname($LName, "name+ext", $OStarget)}{"path"}."'>changed</a></td>\n";
+ $SYS_REPORT .= $SONAME_report;
}
- else {
- foreach (1 .. 5) {
+ else
+ {
+ foreach (1 .. $Columns) {
$SYS_REPORT .= "<td>n/a</td>\n"; # colspan='5'
}
}
$SYS_REPORT .= "</tr>\n";
next;
}
- elsif(not $GroupByHeaders) {
- $SYS_REPORT .= "<td>".$TestResults{$LName}{"v2"}."</td>\n";
- }
- if($TestResults{$LName}{"verdict"} eq "compatible") {
- $SYS_REPORT .= "<td class='passed'><a href=\'$CompatReport\'>100%</a></td>\n";
+ elsif(defined $ChangedSoname{$LName})
+ { # added library
+ $SYS_REPORT .= "<td>".printVer($TestResults{$LName}{"v2"})."</td>\n";
+ $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($BinaryOnly);
+ $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($SourceOnly);
+ if($RegisteredPairs{$LName}) {
+ # do nothing
+ }
+ elsif(my $To = $ChangedSoname{$LName})
+ {
+ $RegisteredPairs{$To}=1;
+ $SYS_REPORT .= $SONAME_report;
+ }
+ else
+ {
+ foreach (1 .. $Columns) {
+ $SYS_REPORT .= "<td>n/a</td>\n"; # colspan='5'
+ }
+ }
+ $SYS_REPORT .= "</tr>\n";
+ next;
}
- else
+ elsif(not $GroupByHeaders)
{
- my $Compatible = 100 - $TestResults{$LName}{"affected"};
- $SYS_REPORT .= "<td class='failed'><a href=\'$CompatReport\'>$Compatible%</a></td>\n";
- }
- my $AddedSym="";
- if(my $Count = $TestResults{$LName}{"added"}) {
- $AddedSym="<a href='$CompatReport\#Added'>$Count new</a>";
- }
- if($AddedSym) {
- $SYS_REPORT.="<td class='new'>$AddedSym</td>";
- }
- else {
- $SYS_REPORT.="<td class='passed'>0</td>";
- }
- my $RemovedSym="";
- if(my $Count = $TestResults{$LName}{"removed"}) {
- $RemovedSym="<a href='$CompatReport\#Removed'>$Count removed</a>";
+ $SYS_REPORT .= "<td>".printVer($TestResults{$LName}{"v2"})."</td>\n";
}
- if($RemovedSym) {
- $SYS_REPORT.="<td class='failed'>$RemovedSym</td>";
- }
- else {
- $SYS_REPORT.="<td class='passed'>0</td>";
- }
- my $High="";
- if(my $Count = $TestResults{$LName}{"type_problems_high"}+$TestResults{$LName}{"interface_problems_high"}) {
- $High="<a href='$CompatReport\#High_Risk_Problems'>".problem_title($Count)."</a>";
- }
- if($High) {
- $SYS_REPORT.="<td class='failed'>$High</td>";
- }
- else {
- $SYS_REPORT.="<td class='passed'>0</td>";
- }
- my $Medium="";
- if(my $Count = $TestResults{$LName}{"type_problems_medium"}+$TestResults{$LName}{"interface_problems_medium"}) {
- $Medium="<a href='$CompatReport\#Medium_Risk_Problems'>".problem_title($Count)."</a>";
- }
- if($Medium) {
- $SYS_REPORT.="<td class='failed'>$Medium</td>";
- }
- else {
- $SYS_REPORT.="<td class='passed'>0</td>";
- }
- my $Low="";
- if(my $Count = $TestResults{$LName}{"type_problems_low"}+$TestResults{$LName}{"interface_problems_low"}+$TestResults{$LName}{"changed_constants"}) {
- $Low="<a href='$CompatReport\#Low_Risk_Problems'>".warning_title($Count)."</a>";
- }
- if($Low) {
- $SYS_REPORT.="<td class='warning'>$Low</td>";
+
+ my $BinCompatReport = $TestResults{$LName}{"Binary"}{"path"};
+ my $SrcCompatReport = $TestResults{$LName}{"Source"}{"path"};
+
+ if($BinaryOnly)
+ {
+ if($TestResults{$LName}{"Binary"}{"verdict"} eq "compatible") {
+ $SYS_REPORT .= "<td class='passed'><a href=\'$BinCompatReport\'>100%</a></td>\n";
+ }
+ else
+ {
+ my $Compatible = 100 - $TestResults{$LName}{"Binary"}{"affected"};
+ $SYS_REPORT .= "<td class='failed'><a href=\'$BinCompatReport\'>$Compatible%</a></td>\n";
+ }
}
- else {
- $SYS_REPORT.="<td class='passed'>0</td>";
+ if($SourceOnly)
+ {
+ if($TestResults{$LName}{"Source"}{"verdict"} eq "compatible") {
+ $SYS_REPORT .= "<td class='passed'><a href=\'$SrcCompatReport\'>100%</a></td>\n";
+ }
+ else
+ {
+ my $Compatible = 100 - $TestResults{$LName}{"Source"}{"affected"};
+ $SYS_REPORT .= "<td class='failed'><a href=\'$SrcCompatReport\'>$Compatible%</a></td>\n";
+ }
}
- $SYS_REPORT .= "</tr>\n";
- }
- my @META_DATA = ();
- my %Stat = (
- "total"=>int(keys(%TestResults)),
- "added"=>int(keys(%Added)),
- "removed"=>int(keys(%Removed))
- );
- foreach ("added", "removed")
- {
- my $Kind = $_."_interfaces";
- foreach my $LName (keys(%TestResults)) {
- $Stat{$Kind} += $TestResults{$LName}{$_};
+ if($BinaryOnly)
+ { # show added/removed symbols at binary level
+ # for joined and -binary-only reports
+ my $AddedSym="";
+ if(my $Count = $TestResults{$LName}{"Binary"}{"added"}) {
+ $AddedSym="<a href='$BinCompatReport\#Added'>$Count new</a>";
+ }
+ if($AddedSym) {
+ $SYS_REPORT.="<td class='new'>$AddedSym</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
+ my $RemovedSym="";
+ if(my $Count = $TestResults{$LName}{"Binary"}{"removed"}) {
+ $RemovedSym="<a href='$BinCompatReport\#Removed'>$Count removed</a>";
+ }
+ if($RemovedSym) {
+ $SYS_REPORT.="<td class='failed'>$RemovedSym</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
}
- push(@META_DATA, $Kind.":".$Stat{$Kind});
- }
- foreach my $T ("type", "interface")
- {
- foreach my $S ("high", "medium", "low")
+ elsif($SourceOnly)
{
- my $Kind = $T."_problems_".$S;
- foreach my $LName (keys(%TestResults)) {
- $Stat{$Kind} += $TestResults{$LName}{$Kind};
+ my $AddedSym="";
+ if(my $Count = $TestResults{$LName}{"Source"}{"added"}) {
+ $AddedSym="<a href='$SrcCompatReport\#Added'>$Count new</a>";
+ }
+ if($AddedSym) {
+ $SYS_REPORT.="<td class='new'>$AddedSym</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
+ my $RemovedSym="";
+ if(my $Count = $TestResults{$LName}{"Source"}{"removed"}) {
+ $RemovedSym="<a href='$SrcCompatReport\#Removed'>$Count removed</a>";
+ }
+ if($RemovedSym) {
+ $SYS_REPORT.="<td class='failed'>$RemovedSym</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
}
- push(@META_DATA, $Kind.":".$Stat{$Kind});
}
- }
- foreach my $LName (keys(%TestResults))
- {
- foreach ("affected", "changed_constants") {
- $Stat{$_} += $TestResults{$LName}{$_};
+
+ if($BinaryOnly)
+ {
+ my $High="";
+ if(my $Count = $TestResults{$LName}{"Binary"}{"type_problems_high"}+$TestResults{$LName}{"Binary"}{"interface_problems_high"}) {
+ $High="<a href='$BinCompatReport\#High_Risk_Problems'>".problem_title($Count)."</a>";
+ }
+ if($High) {
+ $SYS_REPORT.="<td class='failed'>$High</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
+ my $Medium="";
+ if(my $Count = $TestResults{$LName}{"Binary"}{"type_problems_medium"}+$TestResults{$LName}{"Binary"}{"interface_problems_medium"}) {
+ $Medium="<a href='$BinCompatReport\#Medium_Risk_Problems'>".problem_title($Count)."</a>";
+ }
+ if($Medium) {
+ $SYS_REPORT.="<td class='failed'>$Medium</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
+ my $Low="";
+ if(my $Count = $TestResults{$LName}{"Binary"}{"type_problems_low"}+$TestResults{$LName}{"Binary"}{"interface_problems_low"}+$TestResults{$LName}{"Binary"}{"changed_constants"}) {
+ $Low="<a href='$BinCompatReport\#Low_Risk_Problems'>".warning_title($Count)."</a>";
+ }
+ if($Low) {
+ $SYS_REPORT.="<td class='warning'>$Low</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
}
- if(not defined $Stat{"verdict"}
- and $TestResults{$LName}{"verdict"} eq "incompatible") {
- $Stat{"verdict"} = "incompatible";
+
+ if($SourceOnly)
+ {
+ my $High="";
+ if(my $Count = $TestResults{$LName}{"Source"}{"type_problems_high"}+$TestResults{$LName}{"Source"}{"interface_problems_high"}) {
+ $High="<a href='$SrcCompatReport\#High_Risk_Problems'>".problem_title($Count)."</a>";
+ }
+ if($High) {
+ $SYS_REPORT.="<td class='failed'>$High</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
+ my $Medium="";
+ if(my $Count = $TestResults{$LName}{"Source"}{"type_problems_medium"}+$TestResults{$LName}{"Source"}{"interface_problems_medium"}) {
+ $Medium="<a href='$SrcCompatReport\#Medium_Risk_Problems'>".problem_title($Count)."</a>";
+ }
+ if($Medium) {
+ $SYS_REPORT.="<td class='failed'>$Medium</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
+ my $Low="";
+ if(my $Count = $TestResults{$LName}{"Source"}{"type_problems_low"}+$TestResults{$LName}{"Source"}{"interface_problems_low"}+$TestResults{$LName}{"Source"}{"changed_constants"}) {
+ $Low="<a href='$SrcCompatReport\#Low_Risk_Problems'>".warning_title($Count)."</a>";
+ }
+ if($Low) {
+ $SYS_REPORT.="<td class='warning'>$Low</td>";
+ }
+ else {
+ $SYS_REPORT.="<td class='passed'>0</td>";
+ }
}
+
+ $SYS_REPORT .= "</tr>\n";
}
- if(not defined $Stat{"verdict"}) {
- $Stat{"verdict"} = "compatible";
+
+ # bottom header
+ $SYS_REPORT .= "<tr>";
+ $SYS_REPORT .= "<th rowspan='2'>$SONAME_Title</th>";
+ if(not $GroupByHeaders) {
+ $SYS_REPORT .= "<th>$SystemName1</th><th>$SystemName2</th>";
}
- if($Stat{"total"}) {
- $Stat{"affected"} /= $Stat{"total"};
+ if($BinaryOnly and $SourceOnly) {
+ $SYS_REPORT .= "<th>Binary</th><th>Source</th>";
}
else {
- $Stat{"affected"} = 0;
- }
- $Stat{"affected"} = show_number($Stat{"affected"});
- if($Stat{"verdict"}>1) {
- $Stat{"verdict"} = 1;
- }
- push(@META_DATA, "changed_constants:".$Stat{"changed_constants"});
- push(@META_DATA, "tool_version:".get_dumpversion("perl $0"));
- foreach ("removed", "added", "total", "affected", "verdict") {
- @META_DATA = ($_.":".$Stat{$_}, @META_DATA);
+ $SYS_REPORT .= "<th rowspan='2'>Compatible</th>";
}
+ $SYS_REPORT .= "<th rowspan='2'>Added<br/>Symbols</th><th rowspan='2'>Removed<br/>Symbols</th>";
+ $SYS_REPORT .= "<th class='severity'>High</th><th class='severity'>Medium</th><th class='severity'>Low</th>" if($BinaryOnly);
+ $SYS_REPORT .= "<th class='severity'>High</th><th class='severity'>Medium</th><th class='severity'>Low</th>" if($SourceOnly);
+ $SYS_REPORT .= "</tr>";
- # bottom header
- $SYS_REPORT .= "<tr><th rowspan='2'>$SONAME_Title</th>";
+ $SYS_REPORT .= "<tr>";
if(not $GroupByHeaders) {
- $SYS_REPORT .= "<th>$SystemName1</th><th>$SystemName2</th>";
+ $SYS_REPORT .= "<th colspan='2'>Version</th>";
}
- $SYS_REPORT .= "<th rowspan='2'>Compatibility</th>
- <th rowspan='2'>Added<br/>Symbols</th>
- <th rowspan='2'>Removed<br/>Symbols</th>
- <th class='severity'>High</th><th class='severity'>Medium</th><th class='severity'>Low</th></tr>";
- if(not $GroupByHeaders) {
- $SYS_REPORT .= "<tr><th colspan='2'>VERSION</th>";
+
+ if($BinaryOnly and $SourceOnly) {
+ $SYS_REPORT .= "<th colspan='2'>Compatible</th>";
+ }
+ if($BinaryOnly and $SourceOnly)
+ {
+ $SYS_REPORT .= "<th colspan='3' style='white-space:nowrap;'>API Changes / Binary Compatibility</th>";
+ $SYS_REPORT .= "<th colspan='3' style='white-space:nowrap;'>API Changes / Source Compatibility</th>";
}
- $SYS_REPORT .= "<th colspan='3' style='white-space:nowrap;'>API Changes / Compatibility Problems</th></tr>\n";
+ else {
+ $SYS_REPORT .= "<th colspan='3' style='white-space:nowrap;'>API Changes / Compatibility</th>";
+ }
+ $SYS_REPORT .= "</tr>";
$SYS_REPORT .= "</table>";
- my $Title = "$SystemName1 to $SystemName2 binary compatibility report";
+
+ my $Title = "$SystemName1 to $SystemName2 compatibility report";
my $Keywords = "compatibility, $SystemName1, $SystemName2, API, changes";
- my $Description = "Binary compatibility between $SystemName1 and $SystemName2 on ".showArch($ArchName);
+ my $Description = "API compatibility report between $SystemName1 and $SystemName2 on ".showArch($ArchName);
my $Styles = readModule("Styles", "CmpSystems.css");
- writeFile($SYS_REPORT_PATH."/abi_compat_report.html", "<!-\- ".join(";", @META_DATA)." -\->\n".composeHTML_Head($Title, $Keywords, $Description, $Styles, "")."\n<body>
- <div>$SYS_REPORT</div>
- <br/><br/><br/><hr/>
- ".getReportFooter($SystemName2)."
- <div style='height:999px;'></div>\n</body></html>");
- printMsg("INFO", "see detailed report:\n $SYS_REPORT_PATH/abi_compat_report.html");
+
+ $SYS_REPORT = composeHTML_Head($Title, $Keywords, $Description, $Styles, "")."\n<body>\n<div>".$SYS_REPORT."</div>\n";
+ $SYS_REPORT .= "<br/><br/><br/><hr/>\n".getReportFooter($SystemName2, 1)."<div style='height:999px;'></div>\n</body></html>";
+
+ if($SourceOnly) {
+ $SYS_REPORT = "<!-\- kind:source;".join(";", @{$META_DATA{"Source"}})." -\->\n".$SYS_REPORT;
+ }
+ if($BinaryOnly) {
+ $SYS_REPORT = "<!-\- kind:binary;".join(";", @{$META_DATA{"Binary"}})." -\->\n".$SYS_REPORT;
+ }
+ my $REPORT_PATH = $SYS_REPORT_PATH."/";
+ if($BinaryOnly and $SourceOnly) {
+ $REPORT_PATH .= "compat_report.html";
+ }
+ elsif($BinaryOnly) {
+ $REPORT_PATH .= "abi_compat_report.html";
+ }
+ elsif($SourceOnly) {
+ $REPORT_PATH .= "src_compat_report.html";
+ }
+ writeFile($REPORT_PATH, $SYS_REPORT);
+ printMsg("INFO", "see detailed report:\n $REPORT_PATH");
+}
+
+sub printVer($)
+{
+ if($_[0] eq "") {
+ return 0;
+ }
+ return $_[0];
+}
+
+sub getPrefix($)
+{
+ my $Prefix = getPrefix_I($_[0]);
+ if(not $Prefix or defined $NonPrefix{lc($Prefix)}) {
+ return "NONE";
+ }
+ return $Prefix;
+}
+
+sub getPrefix_I($)
+{
+ my $Str = $_[0];
+ 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-z]{1,2}\d+)[a-z\d]*_[a-z]+/i)
+ { # H5HF_delete: H5
+ 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;
+ }
+ return "";
+}
+
+sub problem_title($)
+{
+ if($_[0]==1) {
+ return "1 change";
+ }
+ else {
+ return $_[0]." changes";
+ }
+}
+
+sub warning_title($)
+{
+ if($_[0]==1) {
+ return "1 warning";
+ }
+ else {
+ return $_[0]." warnings";
+ }
}
sub readSystemDescriptor($)
@@ -602,6 +1101,10 @@ sub readSystemDescriptor($)
$Path = get_abs_path($Path);
$SysDescriptor{"SearchLibs"}{clean_path($Path)} = 1;
}
+ foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_libs")))
+ { # skip libs
+ $SysDescriptor{"SkipLibs"}{$Path} = 1;
+ }
foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "headers")))
{
if(not -e $Path) {
@@ -650,9 +1153,10 @@ sub readSystemDescriptor($)
return {"Tools"=>\@Tools,"CrossPrefix"=>$CrossPrefix};
}
-sub readOpts($)
+sub initModule($)
{
my $S = $_[0];
+
$OStarget = $S->{"OStarget"};
$Debug = $S->{"Debug"};
$Quiet = $S->{"Quiet"};
@@ -668,24 +1172,34 @@ sub readOpts($)
$CrossGcc = $S->{"CrossGcc"};
$UseStaticLibs = $S->{"UseStaticLibs"};
$NoStdInc = $S->{"NoStdInc"};
+
+ $BinaryOnly = $S->{"BinaryOnly"};
+ $SourceOnly = $S->{"SourceOnly"};
+
+ if(not $BinaryOnly and not $SourceOnly)
+ { # default
+ $BinaryOnly = 1;
+ }
}
sub check_list($$)
{
my ($Item, $Skip) = @_;
return 0 if(not $Skip);
- my @Patterns = @{$Skip};
- foreach my $Pattern (@Patterns)
+ foreach (@{$Skip})
{
- if($Pattern=~s/\*/.*/g)
+ my $Pattern = $_;
+ if(index($Pattern, "*")!=-1)
{ # wildcards
+ $Pattern=~s/\*/.*/g; # to perl format
if($Item=~/$Pattern/) {
return 1;
}
}
- elsif($Pattern=~/[\/\\]/)
+ elsif(index($Pattern, "/")!=-1
+ or index($Pattern, "\\")!=-1)
{ # directory
- if($Item=~/\Q$Pattern\E/) {
+ if(index($Item, $Pattern)!=-1) {
return 1;
}
}
@@ -723,12 +1237,12 @@ sub read_sys_descriptor($)
"skip_include_paths" => "mf",
"skip_libs" => "mf",
"include_preamble" => "mf",
- "non_self_compiled" => "mf",
"add_include_paths" => "mf",
"gcc_options" => "m",
"skip_symbols" => "m",
"skip_types" => "m",
"ignore_symbols" => "h",
+ "non_prefix" => "h",
"defines" => "s"
);
my %DInfo = ();
@@ -762,6 +1276,12 @@ sub read_sys_descriptor($)
}
}
}
+
+ if(defined $DInfo{"non_self_compiled"})
+ { # support for old ABI dumps
+ $DInfo{"skip_including"} = $DInfo{"non_self_compiled"};
+ }
+
return \%DInfo;
}
@@ -808,9 +1328,6 @@ sub read_sys_info($)
{ # GL/gl.h: No such file
$SysInfo{"libSDL"}{"skip_headers"}=["SDL_opengl.h"];
}
- if($OStarget eq "linux") {
- $SysInfo{"libboost_"}{"headers"} = ["/boost/", "/asio/"];
- }
# Common Info
if(not -f $SYS_INFO_PATH."/common.xml") {
exitStatus("Module_Error", "can't access \'$SYS_INFO_PATH/common.xml\'");
@@ -830,13 +1347,6 @@ sub read_sys_info($)
}
push(@{$SysCInfo->{"gcc_options"}}, @CompilerOpts);
}
- foreach my $Name (keys(%SysInfo))
- { # strict headers that should be
- # matched for only one library
- if($SysInfo{$Name}{"headers"}) {
- $SysCInfo->{"sheaders"}{$Name} = $SysInfo{$Name}{"headers"};
- }
- }
return (\%SysInfo, $SysCInfo);
}
@@ -858,42 +1368,17 @@ sub get_binversion($)
return "";
}
-sub get_soname($)
-{
- my $Path = $_[0];
- return if(not $Path or not -e $Path);
- if(defined $Cache{"get_soname"}{$Path}) {
- return $Cache{"get_soname"}{$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{"get_soname"}{$Path} = $1);
- }
- }
- return ($Cache{"get_soname"}{$Path}="");
-}
-
sub dumpSystem($)
{ # -dump-system option handler
# should be used with -sysroot and -cross-gcc options
my $Opts = $_[0];
- readOpts($Opts);
+ initModule($Opts);
my $SYS_DUMP_PATH = "sys_dumps/".$SysDescriptor{"Name"}."/".getArch(1);
if(not $TargetLibraryName) {
rmtree($SYS_DUMP_PATH);
}
my (@SystemLibs, @SysHeaders) = ();
+
foreach my $Path (keys(%{$SysDescriptor{"Libs"}}))
{
if(not -e $Path) {
@@ -943,17 +1428,32 @@ sub dumpSystem($)
}
writeFile($SYS_DUMP_PATH."/target.txt", $OStarget);
my (%SysLib_Symbols, %SymbolGroup, %Symbol_SysHeaders,
- %SysHeader_Symbols, %SysLib_SysHeaders, %MatchByName) = ();
- my (%Skipped, %Failed, %Success) = ();
- my (%SysHeaderDir_SysLibs, %SysHeaderDir_SysHeaders) = ();
- my (%LibPrefixes, %SymbolCounter, %TotalLibs) = ();
+ %SysHeader_Symbols, %SysLib_SysHeaders) = ();
+ my (%Skipped, %Failed) = ();
+ my (%SysHeaderDir_Used, %SysHeaderDir_SysHeaders) = ();
+ my (%SymbolCounter, %TotalLibs) = ();
+ my (%PrefixToLib, %LibPrefix, %PrefixSymbols) = ();
+
my %Glibc = map {$_=>1} (
"libc",
"libpthread"
);
my ($SysInfo, $SysCInfo) = read_sys_info($OStarget);
- if(not $GroupByHeaders) {
- printMsg("INFO", "Indexing sonames ...");
+
+ foreach (keys(%{$SysCInfo->{"non_prefix"}}))
+ {
+ $NonPrefix{$_} = 1;
+ $NonPrefix{$_."_"} = 1;
+ $NonPrefix{"_".$_} = 1;
+ $NonPrefix{"_".$_."_"} = 1;
+ }
+
+ if(not $GroupByHeaders)
+ {
+ if($Debug) {
+ printMsg("INFO", localtime(time));
+ }
+ printMsg("INFO", "Indexing sonames ...\n");
}
my (%LibSoname, %SysLibVersion) = ();
my %DevelPaths = map {$_=>1} @SystemLibs;
@@ -966,7 +1466,6 @@ sub dumpSystem($)
foreach my $LPath (keys(%DevelPaths))
{ # register SONAMEs
my $LName = get_filename($LPath);
- my $LRelPath = cut_path_prefix($LPath, $SystemRoot);
if(not is_target_lib($LName)) {
next;
}
@@ -974,7 +1473,7 @@ sub dumpSystem($)
and $LName!~/\Alib/) {
next;
}
- if(my $Soname = get_soname($LPath))
+ if(my $Soname = getSONAME($LPath))
{
if($OStarget eq "symbian")
{
@@ -1022,6 +1521,10 @@ sub dumpSystem($)
{ # source version
$SysLibVersion{$LName} = $PV;
}
+ elsif(my $SV = parse_libname(getSONAME($LPath), "version", $OStarget))
+ { # soname version
+ $SysLibVersion{$LName} = $SV;
+ }
elsif($LName=~/(\d[\d\.\-\_]*)\.$LIB_EXT\Z/)
{ # libfreebl3.so
if($1 ne 32 and $1 ne 64) {
@@ -1036,6 +1539,29 @@ sub dumpSystem($)
if(not $GroupByHeaders) {
writeFile($SYS_DUMP_PATH."/versions.txt", $VERSIONS);
}
+
+ # create target list
+ my @SkipLibs = keys(%{$SysDescriptor{"SkipLibs"}});
+ if(my $CSkip = $SysCInfo->{"skip_libs"}) {
+ push(@SkipLibs, @{$CSkip});
+ }
+ if(@SkipLibs and not $TargetLibraryName)
+ {
+ my %SkipLibs = map {$_ => 1} @SkipLibs;
+ my @Target = ();
+ foreach my $LPath (@SystemLibs)
+ {
+ my $LName = get_filename($LPath);
+ my $LName_Short = parse_libname($LName, "name+ext", $OStarget);
+ if(not defined $SkipLibs{$LName_Short}
+ and not defined $SkipLibs{$LName}
+ and not check_list($LPath, \@SkipLibs)) {
+ push(@Target, $LName);
+ }
+ }
+ add_target_libs(\@Target);
+ }
+
my %SysLibs = ();
foreach my $LPath (sort @SystemLibs)
{
@@ -1064,12 +1590,6 @@ sub dumpSystem($)
}
}
}
- if(my $Skip = $SysCInfo->{"skip_libs"})
- { # do NOT check some libs
- if(check_list($LRelPath, $Skip)) {
- next;
- }
- }
if(-l $LPath)
{ # symlinks
if(my $Path = resolve_symlink($LPath)) {
@@ -1080,7 +1600,7 @@ sub dumpSystem($)
{
if($Glibc{$LSName}
and cmd_file($LPath)=~/ASCII/)
- {# GNU ld scripts (libc.so, libpthread.so)
+ { # GNU ld scripts (libc.so, libpthread.so)
my @Candidates = cmd_find($SystemRoot."/lib","",$LSName.".".$LIB_EXT."*","1");
if(@Candidates)
{
@@ -1097,25 +1617,45 @@ sub dumpSystem($)
}
}
}
- @SystemLibs = ();# clear memory
+ @SystemLibs = (); # clear memory
if(not $CheckHeadersOnly)
{
+ if($Debug) {
+ printMsg("INFO", localtime(time));
+ }
if($SysDescriptor{"Image"}) {
- printMsg("INFO", "Reading symbols from image ...");
+ printMsg("INFO", "Reading symbols from image ...\n");
}
else {
- printMsg("INFO", "Reading symbols from libraries ...");
+ printMsg("INFO", "Reading symbols from libraries ...\n");
}
}
- foreach my $LPath (sort keys(%SysLibs))
+ my %Syms = ();
+ my @AllSyms = {};
+ my %ShortestNames = ();
+
+ foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs))
{
my $LRelPath = cut_path_prefix($LPath, $SystemRoot);
my $LName = get_filename($LPath);
- my $Library_Symbol = readSymbols_Lib(1, $LPath, 0, (), "-Weak");
- my @AllSymbols = keys(%{$Library_Symbol->{$LName}});
- my $tr_name = translateSymbols(@AllSymbols, 1);
- foreach my $Symbol (@AllSymbols)
+
+ $ShortestNames{$LPath} = parse_libname($LName, "shortest", $OStarget);
+
+ my $Res = readSymbols_Lib(1, $LPath, 0, "-Weak", 0, 0);
+ $Syms{$LPath} = $Res->{$LName};
+ push(@AllSyms, keys(%{$Syms{$LPath}}));
+ }
+
+ my $Translate = translateSymbols(@AllSyms, 1);
+
+ my %DupSymbols = ();
+
+ foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs))
+ {
+ my $LRelPath = cut_path_prefix($LPath, $SystemRoot);
+ my $LName = get_filename($LPath);
+ foreach my $Symbol (keys(%{$Syms{$LPath}}))
{
$Symbol=~s/[\@\$]+(.*)\Z//g;
if($Symbol=~/\A(_Z|\?)/)
@@ -1128,7 +1668,7 @@ sub dumpSystem($)
# and destructors
next;
}
- my $Unmangled = $tr_name->{$Symbol};
+ my $Unmangled = $Translate->{$Symbol};
$Unmangled=~s/<.+>//g;
if($Unmangled=~/\A([\w:]+)/)
{ # cut out the parameters
@@ -1149,11 +1689,24 @@ sub dumpSystem($)
{ # do NOT match this symbol
next;
}
- $SysLib_Symbols{$LPath}{$Sym}=1;
- if(my $Prefix = getPrefix($Sym)) {
- $LibPrefixes{$Prefix}{$LName}+=1;
+ $SysLib_Symbols{$LPath}{$Sym} = 1;
+ if(my $Prefix = getPrefix($Sym))
+ {
+ $PrefixToLib{$Prefix}{$LName} += 1;
+ $LibPrefix{$LPath}{$Prefix} += 1;
+ $PrefixSymbols{$LPath}{$Prefix}{$Sym} = 1;
+ }
+ $SymbolCounter{$Sym}{$LPath} = 1;
+
+ if(my @Libs = keys(%{$SymbolCounter{$Sym}}))
+ {
+ if($#Libs>=1)
+ {
+ foreach (@Libs) {
+ $DupSymbols{$_}{$Sym} = 1;
+ }
+ }
}
- $SymbolCounter{$Sym}{$LName}=1;
}
}
}
@@ -1163,53 +1716,193 @@ sub dumpSystem($)
{ # do NOT match this symbol
next;
}
- $SysLib_Symbols{$LPath}{$Symbol}=1;
- if(my $Prefix = getPrefix($Symbol)) {
- $LibPrefixes{$Prefix}{$LName}+=1;
+ $SysLib_Symbols{$LPath}{$Symbol} = 1;
+ if(my $Prefix = getPrefix($Symbol))
+ {
+ $PrefixToLib{$Prefix}{$LName} += 1;
+ $LibPrefix{$LPath}{$Prefix} += 1;
+ $PrefixSymbols{$LPath}{$Prefix}{$Symbol} = 1;
+ }
+ $SymbolCounter{$Symbol}{$LPath} = 1;
+
+ if(my @Libs = keys(%{$SymbolCounter{$Symbol}}))
+ {
+ if($#Libs>=1)
+ {
+ foreach (@Libs) {
+ $DupSymbols{$_}{$Symbol} = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ %Syms = ();
+ %{$Translate} = ();
+
+ # remove minor symbols
+ foreach my $LPath (keys(%SysLib_Symbols))
+ {
+ my $SName = $ShortestNames{$LPath};
+ my $Count = keys(%{$SysLib_Symbols{$LPath}});
+ my %Prefixes = %{$LibPrefix{$LPath}};
+ my @Prefixes = sort {$Prefixes{$b}<=>$Prefixes{$a}} keys(%Prefixes);
+ # print "$LPath ".Dumper(\%Prefixes);
+ if($#Prefixes>=1)
+ {
+ my $MaxPrefix = $Prefixes[0];
+ if($MaxPrefix eq "NONE") {
+ $MaxPrefix = $Prefixes[1];
+ }
+ my $Max = $Prefixes{$MaxPrefix};
+ my $None = $Prefixes{"NONE"};
+
+ next if($None*100/$Count>=50);
+ next if($None>=$Max);
+
+ foreach my $Prefix (@Prefixes)
+ {
+ next if($Prefix eq $MaxPrefix);
+ my $Num = $Prefixes{$Prefix};
+ my $Rm = 0;
+
+ if($Prefix eq "NONE") {
+ $Rm = 1;
+ }
+ else
+ {
+ if($Num*100/$Max<5) {
+ $Rm = 1;
+ }
+ }
+
+ if($Rm)
+ {
+ next if($Prefix=~/\Q$MaxPrefix\E/i);
+ next if($MaxPrefix=~/\Q$Prefix\E/i);
+ next if($Prefix=~/\Q$SName\E/i);
+
+ # print "Removing $Prefix $Num\n";
+ foreach my $Symbol (keys(%{$PrefixSymbols{$LPath}{$Prefix}})) {
+ delete($SysLib_Symbols{$LPath}{$Symbol});
+ }
}
- $SymbolCounter{$Symbol}{$LName}=1;
}
}
}
+
+ %PrefixSymbols = (); # free memory
+
if(not $CheckHeadersOnly) {
- writeFile($SYS_DUMP_PATH."/symbols.txt", Dumper(\%SysLib_Symbols));
+ writeFile($SYS_DUMP_PATH."/debug/symbols.txt", Dumper(\%SysLib_Symbols));
}
+
my (%DupLibs, %VersionedLibs) = ();
- foreach my $LPath1 (sort keys(%SysLib_Symbols))
+ foreach my $LPath (sort keys(%DupSymbols))
{ # match duplicated libs
# libmenu contains all symbols from libmenuw
- my $SName = parse_libname(get_filename($LPath1), "shortest", $OStarget);
- foreach my $LPath2 (sort keys(%SysLib_Symbols))
+ my @Syms = keys(%{$SysLib_Symbols{$LPath}});
+ next if($#Syms==-1);
+ if($#Syms+1==keys(%{$DupSymbols{$LPath}})) {
+ $DupLibs{$LPath} = 1;
+ }
+ }
+ foreach my $Prefix (keys(%PrefixToLib))
+ {
+ my @Libs = keys(%{$PrefixToLib{$Prefix}});
+ @Libs = sort {$PrefixToLib{$Prefix}{$b}<=>$PrefixToLib{$Prefix}{$a}} @Libs;
+ $PrefixToLib{$Prefix} = $Libs[0];
+ }
+
+ my %PackageFile = (); # to improve results
+ my %FilePackage = ();
+ my %LibraryFile = ();
+
+ if(0)
+ {
+ if($Debug) {
+ printMsg("INFO", localtime(time));
+ }
+ printMsg("INFO", "Reading info from packages ...\n");
+ if(my $Urpmf = get_CmdPath("urpmf"))
+ { # Mandriva, ROSA
+ my $Out = $TMP_DIR."/urpmf.out";
+ system("urpmf : >\"$Out\"");
+ open(FILE, $Out);
+ while(<FILE>)
+ {
+ chomp($_);
+ if(my $M = index($_, ":"))
+ {
+ my $Pkg = substr($_, 0, $M);
+ my $File = substr($_, $M+1);
+ $PackageFile{$Pkg}{$File} = 1;
+ $FilePackage{$File} = $Pkg;
+ }
+ }
+ close(FILE);
+ }
+ }
+
+ if(keys(%FilePackage))
+ {
+ foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs))
{
- next if($LPath1 eq $LPath2);
- if($SName eq parse_libname(get_filename($LPath2), "shortest", $OStarget))
- { # libpython-X.Y
- $VersionedLibs{$LPath1}{$LPath2}=1;
- next;
+ my $LName = get_filename($LPath);
+ my $LDir = get_dirname($LPath);
+ my $LName_Short = parse_libname($LName, "name+ext", $OStarget);
+
+ my $Pkg = $FilePackage{$LDir."/".$LName_Short};
+ if(not $Pkg)
+ {
+ my $RPkg = $FilePackage{$LPath};
+ if(defined $PackageFile{$RPkg."-devel"}) {
+ $Pkg = $RPkg."-devel";
+ }
+ if($RPkg=~s/[\d\.]+\Z//g)
+ {
+ if(defined $PackageFile{$RPkg."-devel"}) {
+ $Pkg = $RPkg."-devel";
+ }
+ }
}
- my $Duplicate=1;
- foreach (keys(%{$SysLib_Symbols{$LPath1}}))
+ if($Pkg)
{
- if(not defined $SysLib_Symbols{$LPath2}{$_}) {
- $Duplicate=0;
- last;
+ foreach (keys(%{$PackageFile{$Pkg}}))
+ {
+ if(index($_, "/usr/include/")==0) {
+ $LibraryFile{$LPath}{$_} = 1;
+ }
}
}
- if($Duplicate) {
- $DupLibs{$LPath1}{$LPath2}=1;
+
+ $LName_Short=~s/\.so\Z/.a/;
+ if($Pkg = $FilePackage{$LDir."/".$LName_Short})
+ { # headers for static library
+ foreach (keys(%{$PackageFile{$Pkg}}))
+ {
+ if(index($_, "/usr/include/")==0) {
+ $LibraryFile{$LPath}{$_} = 1;
+ }
+ }
}
}
}
- foreach my $Prefix (keys(%LibPrefixes))
- {
- my @Libs = keys(%{$LibPrefixes{$Prefix}});
- @Libs = sort {$LibPrefixes{$Prefix}{$b}<=>$LibPrefixes{$Prefix}{$a}} @Libs;
- $LibPrefixes{$Prefix}=$Libs[0];
+
+ my %HeaderFile_Path = ();
+
+ if($Debug) {
+ printMsg("INFO", localtime(time));
}
- printMsg("INFO", "Reading symbols from headers ...");
+ printMsg("INFO", "Reading symbols from headers ...\n");
foreach my $HPath (@SysHeaders)
{
$HPath = path_format($HPath, $OSgroup);
+ if(readBytes($HPath) eq "7f454c46")
+ { # skip ELF files
+ next;
+ }
my $HRelPath = cut_path_prefix($HPath, $SystemRoot);
my ($HDir, $HName) = separate_path($HRelPath);
if(is_not_header($HName))
@@ -1220,20 +1913,20 @@ sub dumpSystem($)
{ # reserved copy
next;
}
- if($HRelPath=~/[\/\\]_gen/)
+ if(index($HRelPath, "/_gen")!=-1)
{ # telepathy-1.0/telepathy-glib/_gen
# telepathy-1.0/libtelepathy/_gen-tp-constants-deprecated.h
next;
}
- if($HRelPath=~/include[\/\\]linux[\/\\]/)
+ if(index($HRelPath, "include/linux/")!=-1)
{ # kernel-space headers
next;
}
- if($HRelPath=~/include[\/\\]asm[\/\\]/)
+ if(index($HRelPath, "include/asm/")!=-1)
{ # asm headers
next;
}
- if($HRelPath=~/[\/\\]microb-engine[\/\\]/)
+ if(index($HRelPath, "/microb-engine/")!=-1)
{ # MicroB engine (Maemo 4)
next;
}
@@ -1241,35 +1934,33 @@ sub dumpSystem($)
{ # private directories (include/tcl-private, ...)
next;
}
+ if(index($HRelPath, "/lib/")!=-1)
+ {
+ if(not is_header_file($HName))
+ { # without or with a wrong extension
+ # under the /lib directory
+ next;
+ }
+ }
my $Content = readFile($HPath);
$Content=~s/\/\*(.|\n)+?\*\///g;
- $Content=~s/\/\/.*?\n//g;# remove comments
- $Content=~s/#\s*define[^\n\\]*(\\\n[^\n\\]*)+\n*//g;# remove defines
- $Content=~s/#[^\n]*?\n//g;# remove directives
- $Content=~s/(\A|\n)class\s+\w+;\n//g;# remove forward declarations
+ $Content=~s/\/\/.*?\n//g; # remove comments
+ $Content=~s/#\s*define[^\n\\]*(\\\n[^\n\\]*)+\n*//g; # remove defines
+ $Content=~s/#[^\n]*?\n//g; # remove directives
+ $Content=~s/(\A|\n)class\s+\w+;\n//g; # remove forward declarations
# FIXME: try to add preprocessing stage
foreach my $Symbol (split(/\W+/, $Content))
{
+ next if(not $Symbol);
$Symbol_SysHeaders{$Symbol}{$HRelPath} = 1;
$SysHeader_Symbols{$HRelPath}{$Symbol} = 1;
}
$SysHeaderDir_SysHeaders{$HDir}{$HName} = 1;
- my $HShort = $HName;
- $HShort=~s/\.\w+\Z//g;
- if($HShort=~/\Alib/) {
- $MatchByName{$HShort} = $HRelPath;
- }
- elsif(get_filename(get_dirname($HRelPath))=~/\Alib(.+)\Z/)
- { # libical/ical.h
- if($HShort=~/\Q$1\E/) {
- $MatchByName{"lib".$HShort} = $HRelPath;
- }
- }
- elsif($OStarget eq "windows"
- and $HShort=~/api\Z/) {
- $MatchByName{$HShort} = $HRelPath;
- }
+ $HeaderFile_Path{get_filename($HRelPath)}{$HRelPath} = 1;
}
+
+ # writeFile($SYS_DUMP_PATH."/debug/headers.txt", Dumper(\%SysHeader_Symbols));
+
my %SkipDHeaders = (
# header files, that should be in the <skip_headers> section
# but should be matched in the algorithm
@@ -1279,34 +1970,55 @@ sub dumpSystem($)
"properties.h", "Channel", "channel.h", "message.h"],
);
filter_format(\%SkipDHeaders);
- if(not $GroupByHeaders) {
- printMsg("INFO", "Matching symbols ...");
+ if(not $GroupByHeaders)
+ {
+ if($Debug) {
+ printMsg("INFO", localtime(time));
+ }
+ printMsg("INFO", "Matching symbols ...\n");
+ }
+
+ foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs))
+ { # matching
+ my $LName = get_filename($LPath);
}
- foreach my $LPath (sort keys(%SysLibs))
+
+ foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs))
{ # matching
my $LName = get_filename($LPath);
- my $LNameSE = parse_libname($LName, "name+ext", $OStarget);
+ my $LName_Short = parse_libname($LName, "name", $OStarget);
my $LRelPath = cut_path_prefix($LPath, $SystemRoot);
my $LSName = parse_libname($LName, "short", $OStarget);
- my $SName = parse_libname($LName, "shortest", $OStarget);
+ my $SName = $ShortestNames{$LPath};
+
+ my @TryNames = (); # libX-N.so.M
+
+ if(my $Ver = $SysLibVersion{$LName})
+ { # libX-N-M
+ if($LSName."-".$Ver ne $LName_Short)
+ {
+ push(@TryNames, $LName_Short."-".$Ver);
+ #while($Ver=~s/\.\d+\Z//) { # partial versions
+ # push(@TryNames, $LName_Short."-".$Ver);
+ #}
+ }
+ }
+ push(@TryNames, $LName_Short); # libX-N
+ if($LSName ne $LName_Short)
+ { # libX
+ push(@TryNames, $LSName);
+ }
+
if($LRelPath=~/\/debug\//)
{ # debug libs
- $Skipped{$LRelPath}=1;
+ $Skipped{$LRelPath} = 1;
next;
}
- $TotalLibs{$LRelPath}=1;
+ $TotalLibs{$LRelPath} = 1;
$SysLib_SysHeaders{$LRelPath} = ();
- if(keys(%{$SysLib_Symbols{$LPath}}))
- { # try to match by name of the header
- if(my $Path = $MatchByName{$LSName}) {
- $SysLib_SysHeaders{$LRelPath}{$Path}="exact match ($LSName)";
- }
- if(length($SName)>=3
- and my $Path = $MatchByName{"lib".$SName}) {
- $SysLib_SysHeaders{$LRelPath}{$Path}="exact match (lib$SName)";
- }
- }
+
my (%SymbolDirs, %SymbolFiles) = ();
+
foreach my $Symbol (sort {length($b) cmp length($a)}
sort keys(%{$SysLib_Symbols{$LPath}}))
{
@@ -1318,8 +2030,8 @@ sub dumpSystem($)
and keys(%{$SymbolCounter{$Symbol}})>=2
and my $Prefix = getPrefix($Symbol))
{ # duplicated symbols
- if($LibPrefixes{$Prefix}
- and $LibPrefixes{$Prefix} ne $LName
+ if($PrefixToLib{$Prefix}
+ and $PrefixToLib{$Prefix} ne $LName
and not $Glibc{$LSName}) {
next;
}
@@ -1353,8 +2065,8 @@ sub dumpSystem($)
next;
}
my @SymHeaders = keys(%{$Symbol_SysHeaders{$Symbol}});
- @SymHeaders = sort {lc($a) cmp lc($b)} @SymHeaders;# sort by name
- @SymHeaders = sort {length(get_dirname($a))<=>length(get_dirname($b))} @SymHeaders;# sort by length
+ @SymHeaders = sort {lc($a) cmp lc($b)} @SymHeaders; # sort by name
+ @SymHeaders = sort {length(get_dirname($a))<=>length(get_dirname($b))} @SymHeaders; # sort by length
if(length($SName)>=3)
{ # sort candidate headers by name
@SymHeaders = sort {$b=~/\Q$SName\E/i<=>$a=~/\Q$SName\E/i} @SymHeaders;
@@ -1369,85 +2081,136 @@ sub dumpSystem($)
@SymHeaders = sort {$SymbolFiles{get_filename($b)}<=>$SymbolFiles{get_filename($a)}} @SymHeaders;
foreach my $HRelPath (@SymHeaders)
{
- if(my $Group = $SymbolGroup{$LRelPath}{$Symbol}) {
+ my $HDir = get_dirname($HRelPath);
+ my $HName = get_filename($HRelPath);
+
+ if(my $Group = $SymbolGroup{$LRelPath}{$Symbol})
+ {
if(not $SysHeader_Symbols{$HRelPath}{$Group}) {
next;
}
}
- if(my $Search = $SysInfo->{$LSName}{"headers"})
- { # search for specified headers
- if(not check_list($HRelPath, $Search)) {
- next;
+ my $Filter = 0;
+ foreach (@TryNames)
+ {
+ if(my $Filt = $SysInfo->{$_}{"headers"})
+ { # search for specified headers
+ if(not check_list($HRelPath, $Filt))
+ {
+ $Filter = 1;
+ last;
+ }
}
- }
- if(my $Skip = $SysInfo->{$LSName}{"skip_headers"})
- { # do NOT search for some headers
- if(check_list($HRelPath, $Skip)) {
- next;
+ if(my $Filt = $SysInfo->{$_}{"skip_headers"})
+ { # do NOT search for some headers
+ if(check_list($HRelPath, $Filt))
+ {
+ $Filter = 1;
+ last;
+ }
}
- }
- if(my $Skip = $SysInfo->{$LSName}{"skip_including"})
- { # do NOT search for some headers
- if(check_list($HRelPath, $Skip)) {
- next;
+ if(my $Filt = $SysInfo->{$_}{"skip_including"})
+ { # do NOT search for some headers
+ if(check_list($HRelPath, $Filt))
+ {
+ $SymbolDirs{$HDir}+=1;
+ $SymbolFiles{$HName}+=1;
+ $Filter = 1;
+ last;
+ }
}
}
- if(my $Skip = $SysCInfo->{"skip_headers"})
+ if($Filter) {
+ next;
+ }
+ if(my $Filt = $SysCInfo->{"skip_headers"})
{ # do NOT search for some headers
- if(check_list($HRelPath, $Skip)) {
+ if(check_list($HRelPath, $Filt)) {
next;
}
}
- if(my $Skip = $SysCInfo->{"skip_including"})
+ if(my $Filt = $SysCInfo->{"skip_including"})
{ # do NOT search for some headers
- if(check_list($HRelPath, $Skip)) {
+ if(check_list($HRelPath, $Filt)) {
next;
}
}
- if(my $Skip = $SysInfo->{$LSName}{"non_self_compiled"})
- { # do NOT search for some headers
- if(check_list($HRelPath, $Skip)) {
- $SymbolDirs{get_dirname($HRelPath)}+=1;
- $SymbolFiles{get_filename($HRelPath)}+=1;
- next;
+
+ if(defined $LibraryFile{$LRelPath})
+ { # skip wrongly matched headers
+ if(not defined $LibraryFile{$LRelPath}{$HRelPath})
+ { print "WRONG: $LRelPath $HRelPath\n";
+ # next;
}
}
- my $Continue = 1;
- foreach my $Name (keys(%{$SysCInfo->{"sheaders"}}))
+
+ $SysLib_SysHeaders{$LRelPath}{$HRelPath} = $Symbol;
+
+ $SysHeaderDir_Used{$HDir}{$LName_Short} = 1;
+ $SysHeaderDir_Used{get_dirname($HDir)}{$LName_Short} = 1;
+
+ $SymbolDirs{$HDir} += 1;
+ $SymbolFiles{$HName} +=1 ;
+
+ # select one header for one symbol
+ last;
+ }
+ }
+
+ if(keys(%{$SysLib_Symbols{$LPath}})
+ and not $SysInfo->{$_}{"headers"})
+ { # try to match by name of the header
+ if(length($SName)>=3)
+ {
+ my @Paths = ();
+ foreach my $Path (keys(%{$HeaderFile_Path{$SName.".h"}}), keys(%{$HeaderFile_Path{$LSName.".h"}}))
{
- if($LSName!~/\Q$Name\E/
- and check_list($HRelPath, $SysCInfo->{"sheaders"}{$Name}))
- { # restriction to search for C++ or Boost headers
- # in the boost/ and c++/ directories only
- $Continue=0;
- last;
+ my $Dir = get_dirname($Path);
+ if(defined $SymbolDirs{$Dir} or $Dir eq "/usr/include") {
+ push(@Paths, $Path);
}
}
- if(not $Continue) {
- next;
+ if($#Paths==0)
+ {
+ my $Path = $Paths[0];
+ if(not defined $SysLib_SysHeaders{$LRelPath}{$Path}) {
+ $SysLib_SysHeaders{$LRelPath}{$Path} = "by name ($LSName)";
+ }
}
- $SysLib_SysHeaders{$LRelPath}{$HRelPath}=$Symbol;
- $SysHeaderDir_SysLibs{get_dirname($HRelPath)}{$LNameSE}=1;
- $SysHeaderDir_SysLibs{get_dirname(get_dirname($HRelPath))}{$LNameSE}=1;
- $SymbolDirs{get_dirname($HRelPath)}+=1;
- $SymbolFiles{get_filename($HRelPath)}+=1;
- last;# select one header for one symbol
}
}
- if(keys(%{$SysLib_SysHeaders{$LRelPath}})) {
- $Success{$LRelPath}=1;
+
+ if(not keys(%{$SysLib_SysHeaders{$LRelPath}}))
+ {
+ foreach (@TryNames)
+ {
+ if(my $List = $SysInfo->{$_}{"headers"})
+ {
+ foreach my $HName (@{$List})
+ {
+ next if($HName=~/[\*\/\\]/);
+ if(my $HPath = selectSystemHeader($HName, 1))
+ {
+ my $HRelPath = cut_path_prefix($HPath, $SystemRoot);
+ $SysLib_SysHeaders{$LRelPath}{$HRelPath} = "by descriptor";
+ }
+ }
+ }
+ }
}
- else {
- $Failed{$LRelPath}=1;
+
+ if(not keys(%{$SysLib_SysHeaders{$LRelPath}})) {
+ $Failed{$LRelPath} = 1;
}
}
+
if(not $GroupByHeaders)
{ # matching results
- writeFile($SYS_DUMP_PATH."/match.txt", Dumper(\%SysLib_SysHeaders));
- writeFile($SYS_DUMP_PATH."/skipped.txt", join("\n", sort keys(%Skipped)));
- writeFile($SYS_DUMP_PATH."/failed.txt", join("\n", sort keys(%Failed)));
+ writeFile($SYS_DUMP_PATH."/debug/match.txt", Dumper(\%SysLib_SysHeaders));
+ writeFile($SYS_DUMP_PATH."/debug/skipped.txt", join("\n", sort keys(%Skipped)));
+ writeFile($SYS_DUMP_PATH."/debug/failed.txt", join("\n", sort keys(%Failed)));
}
- (%SysLib_Symbols, %SymbolGroup, %Symbol_SysHeaders, %SysHeader_Symbols) = ();# free memory
+ (%SysLib_Symbols, %SymbolGroup, %Symbol_SysHeaders, %SysHeader_Symbols) = (); # free memory
if($GroupByHeaders)
{
if($SysDescriptor{"Image"} and not $CheckHeadersOnly) {
@@ -1478,8 +2241,12 @@ sub dumpSystem($)
}
}
@SysHeaders = (); # clear memory
- (%Skipped, %Failed, %Success) = ();
+
+ if($Debug) {
+ printMsg("INFO", localtime(time));
+ }
printMsg("INFO", "Generating XML descriptors ...");
+ my %Generated = ();
foreach my $LRelPath (keys(%SysLib_SysHeaders))
{
my $LName = get_filename($LRelPath);
@@ -1488,16 +2255,30 @@ sub dumpSystem($)
if(my @LibHeaders = keys(%{$SysLib_SysHeaders{$LRelPath}}))
{
my $LSName = parse_libname($LName, "short", $OStarget);
- my $SName = parse_libname($LName, "shortest", $OStarget);
+ my $LName_Short = parse_libname($LName, "name", $OStarget);
+ my $LName_Shortest = parse_libname($LName, "shortest", $OStarget);
if($GroupByHeaders)
{ # header short name
$LSName = $LName;
$LSName=~s/\.(.+?)\Z//;
}
- my (%DirsHeaders, %Includes) = ();
- foreach my $HRelPath (@LibHeaders) {
- $DirsHeaders{get_dirname($HRelPath)}{$HRelPath}=1;
+
+ my (%DirsHeaders, %Includes, %MainDirs) = ();
+ foreach my $HRelPath (@LibHeaders)
+ {
+ my $Dir = get_dirname($HRelPath);
+ $DirsHeaders{$Dir}{$HRelPath} = 1;
+
+ if($Dir=~/\/\Q$LName_Shortest\E(\/|\Z)/i
+ or $Dir=~/\/\Q$LName_Short\E(\/|\Z)/i)
+ {
+ if(get_filename($Dir) ne "include")
+ { # except /usr/include
+ $MainDirs{$Dir} += 1;
+ }
+ }
}
+
if($#LibHeaders==0)
{ # one header at all
$Includes{$LibHeaders[0]} = 1;
@@ -1506,12 +2287,19 @@ sub dumpSystem($)
{
foreach my $Dir (keys(%DirsHeaders))
{
+ if(keys(%MainDirs) and not defined $MainDirs{$Dir})
+ { # search in /X/ dir for libX headers
+ if(get_filename($Dir) ne "include")
+ { # except /usr/include
+ next;
+ }
+ }
my $DirPart = 0;
my $TotalHeaders = keys(%{$SysHeaderDir_SysHeaders{$Dir}});
if($TotalHeaders) {
$DirPart = (keys(%{$DirsHeaders{$Dir}})*100)/$TotalHeaders;
}
- my $Neighbourhoods = keys(%{$SysHeaderDir_SysLibs{$Dir}});
+ my $Neighbourhoods = keys(%{$SysHeaderDir_Used{$Dir}});
if($Neighbourhoods==1)
{ # one lib in this directory
if(get_filename($Dir) ne "include"
@@ -1521,19 +2309,32 @@ sub dumpSystem($)
}
else
{ # list of headers
- @Includes{keys(%{$DirsHeaders{$Dir}})}=values(%{$DirsHeaders{$Dir}});
+ foreach (keys(%{$DirsHeaders{$Dir}})) {
+ $Includes{$_} = 1;
+ }
}
}
elsif((keys(%{$DirsHeaders{$Dir}})*100)/($#LibHeaders+1)>5)
{ # remove 5% divergence
if(get_filename($Dir) ne "include"
and $DirPart>=50)
- { # complete directory
+ { # complete directory if more than 50%
$Includes{$Dir} = 1;
}
else
{ # list of headers
- @Includes{keys(%{$DirsHeaders{$Dir}})}=values(%{$DirsHeaders{$Dir}});
+ foreach (keys(%{$DirsHeaders{$Dir}})) {
+ $Includes{$_} = 1;
+ }
+ }
+ }
+ else
+ { # noise
+ foreach (keys(%{$DirsHeaders{$Dir}}))
+ { # NOTE: /usr/include/libX.h
+ if(/\Q$LName_Shortest\E/i) {
+ $Includes{$_} = 1;
+ }
}
}
}
@@ -1551,9 +2352,19 @@ sub dumpSystem($)
$LVersion = $SysDescriptor{"Name"};
}
my @Content = ("<version>\n $LVersion\n</version>");
- my @IncHeaders = sort {natural_sorting($a, $b)} keys(%Includes);
- sort_by_word(\@IncHeaders, parse_libname($LName, "shortest", $OStarget));
- if(is_abs($IncHeaders[0])) {
+
+ my @IncHeaders = keys(%Includes);
+
+ # sort files up
+ @IncHeaders = sort {$b=~/\.h\Z/<=>$a=~/\.h\Z/} @IncHeaders;
+
+ # sort by name
+ @IncHeaders = sort {sortHeaders($a, $b)} @IncHeaders;
+
+ # sort by library name
+ sortByWord(\@IncHeaders, parse_libname($LName, "shortest", $OStarget));
+
+ if(is_abs($IncHeaders[0]) or -f $IncHeaders[0]) {
push(@Content, "<headers>\n ".join("\n ", @IncHeaders)."\n</headers>");
}
else {
@@ -1574,6 +2385,8 @@ sub dumpSystem($)
push(@Content, "<libs>\n {RELPATH}/$LRelPath\n</libs>");
}
}
+
+ # system
if(my @SearchHeaders = keys(%{$SysDescriptor{"SearchHeaders"}})) {
push(@Content, "<search_headers>\n ".join("\n ", @SearchHeaders)."\n</search_headers>");
}
@@ -1583,98 +2396,133 @@ sub dumpSystem($)
if(my @Tools = keys(%{$SysDescriptor{"Tools"}})) {
push(@Content, "<tools>\n ".join("\n ", @Tools)."\n</tools>");
}
- my @Skip = ();
- if($SysInfo->{$LSName}{"skip_headers"}) {
- @Skip = (@Skip, @{$SysInfo->{$LSName}{"skip_headers"}});
- }
- if($SysCInfo->{"skip_headers"}) {
- @Skip = (@Skip, @{$SysCInfo->{"skip_headers"}});
- }
- if(@Skip) {
- push(@Content, "<skip_headers>\n ".join("\n ", @Skip)."\n</skip_headers>");
- }
- my @SkipInc = ();
- if($SysInfo->{$LSName}{"skip_including"}) {
- @SkipInc = (@SkipInc, @{$SysInfo->{$LSName}{"skip_including"}});
+ if(my $Prefix = $SysDescriptor{"CrossPrefix"}) {
+ push(@Content, "<cross_prefix>\n $Prefix\n</cross_prefix>");
}
- if($SysCInfo->{"skip_including"}) {
- @SkipInc = (@SkipInc, @{$SysCInfo->{"skip_including"}});
+
+ # library
+ my (@Skip, @SkipInc, @AddIncPath, @SkipIncPath,
+ @SkipTypes, @SkipSymb, @Preamble, @Defines, @CompilerOpts) = ();
+
+ my @TryNames = ();
+ if(my $Ver = $SysLibVersion{$LName})
+ {
+ if($LSName."-".$Ver ne $LName_Short) {
+ push(@TryNames, $LName_Short."-".$Ver);
+ }
}
- if($SysInfo->{$LSName}{"non_self_compiled"}) {
- @SkipInc = (@SkipInc, @{$SysInfo->{$LSName}{"non_self_compiled"}});
+ push(@TryNames, $LName_Short);
+ if($LSName ne $LName_Short) {
+ push(@TryNames, $LSName);
}
- if($SkipDHeaders{$LSName}) {
- @SkipInc = (@SkipInc, @{$SkipDHeaders{$LSName}});
- }
- if(@SkipInc) {
- push(@Content, "<skip_including>\n ".join("\n ", @SkipInc)."\n</skip_including>");
- }
- if($SysInfo->{$LSName}{"add_include_paths"}) {
- push(@Content, "<add_include_paths>\n ".join("\n ", @{$SysInfo->{$LSName}{"add_include_paths"}})."\n</add_include_paths>");
+
+ foreach (@TryNames)
+ {
+ if(my $List = $SysInfo->{$_}{"include_preamble"}) {
+ push(@Preamble, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"skip_headers"}) {
+ @Skip = (@Skip, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"skip_including"}) {
+ @SkipInc = (@SkipInc, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"add_include_paths"}) {
+ @AddIncPath = (@AddIncPath, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"skip_include_paths"}) {
+ @SkipIncPath = (@SkipIncPath, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"skip_symbols"}) {
+ push(@SkipSymb, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"skip_types"}) {
+ @SkipTypes = (@SkipTypes, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"gcc_options"}) {
+ push(@CompilerOpts, @{$List});
+ }
+ if(my $List = $SysInfo->{$_}{"defines"}) {
+ push(@Defines, $List);
+ }
}
- if($SysInfo->{$LSName}{"skip_include_paths"}) {
- push(@Content, "<skip_include_paths>\n ".join("\n ", @{$SysInfo->{$LSName}{"skip_include_paths"}})."\n</skip_include_paths>");
+
+ # common
+ if(my $List = $SysCInfo->{"include_preamble"}) {
+ push(@Preamble, @{$List});
}
- if($SysInfo->{$LSName}{"skip_types"}) {
- push(@Content, "<skip_types>\n ".join("\n ", @{$SysInfo->{$LSName}{"skip_types"}})."\n</skip_types>");
+ if(my $List = $SysCInfo->{"skip_headers"}) {
+ @Skip = (@Skip, @{$List});
}
- my @SkipSymb = ();
- if($SysInfo->{$LSName}{"skip_symbols"}) {
- push(@SkipSymb, @{$SysInfo->{$LSName}{"skip_symbols"}});
+ if(my $List = $SysCInfo->{"skip_including"}) {
+ @SkipInc = (@SkipInc, @{$List});
}
- if($SysCInfo->{"skip_symbols"}) {
- push(@SkipSymb, @{$SysCInfo->{"skip_symbols"}});
+ if(my $List = $SysCInfo->{"skip_symbols"}) {
+ push(@SkipSymb, @{$List});
}
- if(@SkipSymb) {
- push(@Content, "<skip_symbols>\n ".join("\n ", @SkipSymb)."\n</skip_symbols>");
+ if(my $List = $SysCInfo->{"gcc_options"}) {
+ push(@CompilerOpts, @{$List});
}
- my @Preamble = ();
- if($SysCInfo->{"include_preamble"}) {
- push(@Preamble, @{$SysCInfo->{"include_preamble"}});
+ if($SysCInfo->{"defines"}) {
+ push(@Defines, $SysCInfo->{"defines"});
}
+
+ # common other
if($LSName=~/\AlibX\w+\Z/)
{ # add Xlib.h for libXt, libXaw, libXext and others
push(@Preamble, "Xlib.h", "X11/Intrinsic.h");
}
- if($SysInfo->{$LSName}{"include_preamble"}) {
- push(@Preamble, @{$SysInfo->{$LSName}{"include_preamble"}});
+ if($SkipDHeaders{$LSName}) {
+ @SkipInc = (@SkipInc, @{$SkipDHeaders{$LSName}});
+ }
+ if($SysDescriptor{"Defines"}) {
+ push(@Defines, $SysDescriptor{"Defines"});
}
+
+ # add sections
if(@Preamble) {
push(@Content, "<include_preamble>\n ".join("\n ", @Preamble)."\n</include_preamble>");
}
- my @Defines = ();
- if($SysCInfo->{"defines"}) {
- push(@Defines, $SysCInfo->{"defines"});
+ if(@Skip) {
+ push(@Content, "<skip_headers>\n ".join("\n ", @Skip)."\n</skip_headers>");
}
- if($SysInfo->{$LSName}{"defines"}) {
- push(@Defines, $SysInfo->{$LSName}{"defines"});
+ if(@SkipInc) {
+ push(@Content, "<skip_including>\n ".join("\n ", @SkipInc)."\n</skip_including>");
}
- if($SysDescriptor{"Defines"}) {
- push(@Defines, $SysDescriptor{"Defines"});
+ if(@AddIncPath) {
+ push(@Content, "<add_include_paths>\n ".join("\n ", @AddIncPath)."\n</add_include_paths>");
}
- if(@Defines) {
- push(@Content, "<defines>\n ".join("\n ", @Defines)."\n</defines>");
+ if(@SkipIncPath) {
+ push(@Content, "<skip_include_paths>\n ".join("\n ", @SkipIncPath)."\n</skip_include_paths>");
}
- my @CompilerOpts = ();
- if($SysCInfo->{"gcc_options"}) {
- push(@CompilerOpts, @{$SysCInfo->{"gcc_options"}});
+ if(@SkipSymb) {
+ push(@Content, "<skip_symbols>\n ".join("\n ", @SkipSymb)."\n</skip_symbols>");
}
- if($SysInfo->{$LSName}{"gcc_options"}) {
- push(@CompilerOpts, @{$SysInfo->{$LSName}{"gcc_options"}});
+ if(@SkipTypes) {
+ push(@Content, "<skip_types>\n ".join("\n ", @SkipTypes)."\n</skip_types>");
}
if(@CompilerOpts) {
push(@Content, "<gcc_options>\n ".join("\n ", @CompilerOpts)."\n</gcc_options>");
}
- if($SysDescriptor{"CrossPrefix"}) {
- push(@Content, "<cross_prefix>\n ".$SysDescriptor{"CrossPrefix"}."\n</cross_prefix>");
+ if(@Defines) {
+ push(@Content, "<defines>\n ".join("\n ", @Defines)."\n</defines>");
}
+
writeFile($DPath, join("\n\n", @Content));
- $Success{$LRelPath}=1;
+ $Generated{$LRelPath}=1;
}
}
+ printMsg("INFO", "Created descriptors: ".keys(%Generated)." ($SYS_DUMP_PATH/descriptors/)\n");
+
+ if($Debug) {
+ printMsg("INFO", localtime(time));
+ }
printMsg("INFO", "Dumping ABIs:");
- my %DumpSuccess = ();
+ my %Dumped = ();
my @Descriptors = cmd_find($SYS_DUMP_PATH."/descriptors","f","*.xml","1");
+ if(-d $SYS_DUMP_PATH."/descriptors" and $#Descriptors==-1) {
+ printMsg("ERROR", "internal problem with \'find\' utility");
+ }
foreach my $DPath (sort {lc($a) cmp lc($b)} @Descriptors)
{
my $DName = get_filename($DPath);
@@ -1690,7 +2538,7 @@ sub dumpSystem($)
next;
}
$DPath = cut_path_prefix($DPath, $ORIG_DIR);
- my $ACC_dump = "perl $0 -binary";
+ my $ACC_dump = "perl $0";
if($GroupByHeaders)
{ # header name is going here
$ACC_dump .= " -l $LName";
@@ -1761,18 +2609,18 @@ sub dumpSystem($)
}
else
{
- $DumpSuccess{$LName}=1;
+ $Dumped{$LName}=1;
printMsg("INFO", "Ok");
}
}
+ printMsg("INFO", "\n");
if(not $GroupByHeaders)
{ # general mode
printMsg("INFO", "Total libraries: ".keys(%TotalLibs));
printMsg("INFO", "Skipped libraries: ".keys(%Skipped)." ($SYS_DUMP_PATH/skipped.txt)");
printMsg("INFO", "Failed to find headers: ".keys(%Failed)." ($SYS_DUMP_PATH/failed.txt)");
}
- printMsg("INFO", "Created descriptors: ".keys(%Success)." ($SYS_DUMP_PATH/descriptors/)");
- printMsg("INFO", "Dumped ABIs: ".keys(%DumpSuccess)." ($SYS_DUMP_PATH/abi_dumps/)");
+ printMsg("INFO", "Dumped ABIs: ".keys(%Dumped)." ($SYS_DUMP_PATH/abi_dumps/)");
printMsg("INFO", "The ".$SysDescriptor{"Name"}." system ABI has been dumped to:\n $SYS_DUMP_PATH");
}
diff --git a/modules/Internals/XmlDump.pm b/modules/Internals/XmlDump.pm
index 76b8247..5b4fd4d 100644
--- a/modules/Internals/XmlDump.pm
+++ b/modules/Internals/XmlDump.pm
@@ -188,6 +188,9 @@ sub createXmlDump($)
if($TInfo{"Spec"}) {
$ABI_DUMP .= addTag("note", "specialization");
}
+ if($TInfo{"Forward"}) {
+ $ABI_DUMP .= addTag("note", "forward");
+ }
$ABI_DUMP .= closeTag("data_type");
}
$ABI_DUMP .= closeTag("type_info");
@@ -545,6 +548,9 @@ sub readXmlDump($)
elsif($Note eq "specialization") {
$TInfo{"Spec"} = 1;
}
+ elsif($Note eq "forward") {
+ $TInfo{"Forward"} = 1;
+ }
}
foreach my $Attr ("Name", "Type", "Size",
"Header", "Line", "NameSpace", "Class", "Return", "Algn")