diff options
Diffstat (limited to 'abi-compliance-checker.pl')
-rw-r--r-- | abi-compliance-checker.pl | 204 |
1 files changed, 146 insertions, 58 deletions
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl index 9c17b97..e71d93a 100644 --- a/abi-compliance-checker.pl +++ b/abi-compliance-checker.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl ########################################################################### -# ABI Compliance Checker (ABICC) 1.99.22 +# ABI Compliance Checker (ABICC) 1.99.23 # A tool for checking backward compatibility of a C/C++ library API # # Copyright (C) 2009-2011 Institute for System Programming, RAS @@ -31,11 +31,11 @@ # - MinGW (3.0-4.7, 4.8.3, 4.9 or newer) # - MS Visual C++ (dumpbin, undname, cl) # - Active Perl 5 (5.8 or newer) -# - Sigcheck v1.71 or newer -# - Info-ZIP 3.0 (zip, unzip) -# - Ctags (5.8 or newer) +# - Sigcheck v2.52 or newer +# - GnuWin Zip and UnZip +# - Exuberant Ctags (5.8 or newer) # - Add tool locations to the PATH environment variable -# - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\) +# - Run vcvars64.bat (C:\Microsoft Visual Studio 9.0\VC\bin\) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser @@ -60,7 +60,7 @@ use Storable qw(dclone); use Data::Dumper; use Config; -my $TOOL_VERSION = "1.99.22"; +my $TOOL_VERSION = "1.99.23"; my $ABI_DUMP_VERSION = "3.2"; my $XML_REPORT_VERSION = "1.2"; my $XML_ABI_DUMP_VERSION = "1.2"; @@ -91,7 +91,8 @@ $SourceReportPath, $UseXML, $SortDump, $DumpFormat, $ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath, $CheckInfo, $Quick, $AffectLimit, $AllAffected, $CppIncompat, $SkipInternalSymbols, $SkipInternalTypes, $TargetArch, $GccOptions, -$TypesListPath, $SkipTypesListPath, $CheckPrivateABI, $CountSymbols, $OldStyle); +$TypesListPath, $SkipTypesListPath, $CheckPrivateABI, $CountSymbols, $OldStyle, +$DisableQuickEmptyReport); my $CmdName = get_filename($0); my %OS_LibExt = ( @@ -148,7 +149,7 @@ my $HomePage = "http://lvc.github.io/abi-compliance-checker/"; my $ShortUsage = "ABI Compliance Checker (ABICC) $TOOL_VERSION A tool for checking backward compatibility of a C/C++ library API -Copyright (C) 2015 Andrey Ponomarenko's ABI Laboratory +Copyright (C) 2016 Andrey Ponomarenko's ABI Laboratory License: GNU LGPL or GNU GPL Usage: $CmdName [options] @@ -187,7 +188,7 @@ GetOptions("h|help!" => \$Help, "dump|dump-abi|dump_abi=s" => \$DumpAPI, # extra options "app|application=s" => \$AppPath, - "static-libs!" => \$UseStaticLibs, + "static|static-libs!" => \$UseStaticLibs, "gcc-path|cross-gcc=s" => \$CrossGcc, "gcc-prefix|cross-prefix=s" => \$CrossPrefix, "gcc-options=s" => \$GccOptions, @@ -251,6 +252,7 @@ GetOptions("h|help!" => \$Help, "tolerant!" => \$Tolerant, "check!" => \$CheckInfo, "quick!" => \$Quick, + "disable-quick-empty-report!" => \$DisableQuickEmptyReport, "all-affected!" => \$AllAffected, "skip-internal-symbols|skip-internal=s" => \$SkipInternalSymbols, "skip-internal-types=s" => \$SkipInternalTypes, @@ -401,7 +403,7 @@ EXTRA OPTIONS: This option allows to specify the application that should be checked for portability to the new library version. - -static-libs + -static Check static libraries instead of the shared ones. The <libs> section of the XML-descriptor should point to static libraries location. @@ -754,6 +756,9 @@ OTHER OPTIONS: -quick Quick analysis. Disable check of some template instances. + + -disable-quick-empty-report + Do not generate quick empty report if input ABI dumps are equal. -skip-internal-symbols PATTERN Do not check symbols matched by the pattern. @@ -6742,7 +6747,7 @@ sub detect_recursive_includes($$) { # for #include "..." my $Candidate = join_P($AbsDir, $Include); if(-f $Candidate) { - $HPath = realpath($Candidate); + $HPath = realpath_F($Candidate); } } elsif($IncType>0 @@ -7866,6 +7871,8 @@ sub platformSpecs($) { # add options to MinGW compiler # to simulate the MSVC compiler my %MinGW_Opts = map {$_=>1} ( + "-D__unaligned=\" \"", + "-D__nullptr=\"nullptr\"", "-D_WIN32", "-D_STDCALL_SUPPORTED", "-D__int64=\"long long\"", @@ -7904,11 +7911,14 @@ sub platformSpecs($) "-DDECLSPEC_DEPRECATED=\" \"", "-D__builtin_alignof(x)=__alignof__(x)", "-DSORTPP_PASS"); - if($Arch eq "x86") { + if($Arch eq "x86") + { $MinGW_Opts{"-D_M_IX86=300"}=1; } - elsif($Arch eq "x86_64") { + elsif($Arch eq "x86_64") + { $MinGW_Opts{"-D_M_AMD64=300"}=1; + $MinGW_Opts{"-D_M_X64=300"}=1; } elsif($Arch eq "ia64") { $MinGW_Opts{"-D_M_IA64=300"}=1; @@ -10445,7 +10455,7 @@ sub isPublic($$) # by name in C language # TODO: add other methods to detect private members my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"}; - if($MName=~/priv|abidata|parent_object/i) + if($MName=~/priv|abidata|parent_object|impl/i) { # C-styled private data return 0; } @@ -15463,7 +15473,7 @@ sub get_abs_path($) if(not is_abs($Path)) { $Path = abs_path($Path); } - return $Path; + return path_format($Path, $OSgroup); } sub get_OSgroup() @@ -17405,9 +17415,11 @@ sub getAffectedSymbols($$$) foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%SymSel)) { + my $Kind = $SymSel{$Symbol}{"Kind"}; my $Loc = $SymSel{$Symbol}{"Loc"}; + my $PName = getParamName($Loc); - my $Desc = getAffectDesc($Level, $Symbol, $SymSel{$Symbol}{"Kind"}, $Loc); + my $Desc = getAffectDesc($Level, $Symbol, $Kind, $Loc); my $Target = ""; if($PName) @@ -18715,7 +18727,6 @@ sub translateSymbols(@) } elsif(index($Symbol, "?")==0) { - next if($tr_name{$Symbol}); push(@MnglNames2, $Symbol); } else @@ -19011,7 +19022,7 @@ sub readSymbols_Lib($$$$$$) my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_; return () if(not $LibVersion or not $Lib_Path); - my $Real_Path = realpath($Lib_Path); + my $Real_Path = realpath_F($Lib_Path); if(not $Real_Path) { # broken link @@ -19156,15 +19167,32 @@ sub readSymbols_Lib($$$$$$) open(LIB, $DumpBinCmd." |"); } while(<LIB>) - { # 1197 4AC 0000A620 SetThreadStackGuarantee - # 1198 4AD SetThreadToken (forwarded to ...) - # 3368 _o2i_ECPublicKey - # 1 0 00005B30 ??0?N = ... (with pdb) - if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*(?:=.+)?\Z/i - or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/ - or /\A\s*\d+\s+_([\w\?\@]+)\s*(?:=.+)?\Z/) - { # dynamic, static and forwarded symbols - my $realname = $1; + { + my $realname = undef; + if($LIB_TYPE eq "dynamic") + { + # 1197 4AC 0000A620 SetThreadStackGuarantee + # 1198 4AD SetThreadToken (forwarded to ...) + # 3368 _o2i_ECPublicKey + # 1 0 00005B30 ??0?N = ... (with pdb) + if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*(?:=.+)?\Z/i + or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/ + or /\A\s*\d+\s+_([\w\?\@]+)\s*(?:=.+)?\Z/) + { # dynamic, static and forwarded symbols + $realname = $1; + } + } + else + { # static + if(/\A\s{10,}\d*\s+([\w\?\@]+)\s*\Z/i) + { + # 16 IID_ISecurityInformation + $realname = $1; + } + } + + if($realname) + { if($IsNeededLib) { if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) @@ -19876,7 +19904,7 @@ sub getSOPaths_Dest($$) if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i) { registerObject($Path, $LibVersion); - $Libs{realpath($Path)}=1; + $Libs{realpath_F($Path)} = 1; } } } @@ -19887,7 +19915,7 @@ sub getSOPaths_Dest($$) next if(ignore_path($Path)); next if(skipLib($Path, $LibVersion)); registerObject($Path, $LibVersion); - $Libs{realpath($Path)}=1; + $Libs{realpath_F($Path)} = 1; } if($OSgroup eq "macos") { # shared libraries on MacOS X may have no extension @@ -19899,7 +19927,7 @@ sub getSOPaths_Dest($$) and cmd_file($Path)=~/(shared|dynamic)\s+library/i) { registerObject($Path, $LibVersion); - $Libs{realpath($Path)}=1; + $Libs{realpath_F($Path)} = 1; } } } @@ -19911,6 +19939,12 @@ sub getSOPaths_Dest($$) } } +sub realpath_F($) +{ + my $Path = $_[0]; + return path_format(realpath($Path), $OSgroup); +} + sub isCyclical($$) { my ($Stack, $Value) = @_; @@ -19980,10 +20014,16 @@ sub getArch_GCC($) system($Cmd); chdir($ORIG_DIR); - $Arch = getArch_Object("$TMP_DIR/test"); + my $EX = join_P($TMP_DIR, "test"); + + if($OSgroup eq "windows") { + $EX = join_P($TMP_DIR, "test.exe"); + } + + $Arch = getArch_Object($EX); unlink("$TMP_DIR/test.c"); - unlink("$TMP_DIR/test"); + unlink($EX); } if(not $Arch) { @@ -20304,7 +20344,7 @@ sub read_ABI_Dump($$) $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"}; } - if(not $SkipTypes{$LibVersion}) + if(not keys(%{$SkipTypes{$LibVersion}})) { # if not defined by -skip-types option if(defined $ABI->{"SkipTypes"}) { @@ -20322,14 +20362,16 @@ sub read_ABI_Dump($$) } } - if(not $SkipSymbols{$LibVersion}) + if(not keys(%{$SkipSymbols{$LibVersion}})) { # if not defined by -skip-symbols option - $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"}; - if(not $SkipSymbols{$LibVersion}) + if(defined $ABI->{"SkipSymbols"}) { + $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"}; + } + if(defined $ABI->{"SkipInterfaces"}) { # support for old dumps $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"}; } - if(not $SkipSymbols{$LibVersion}) + if(defined $ABI->{"InternalInterfaces"}) { # support for old dumps $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"}; } @@ -20891,8 +20933,7 @@ sub detect_inc_default_paths() if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/) { - my $Path = realpath($1); - $Path = path_format($Path, $OSgroup); + my $Path = realpath_F($1); if(index($Path, "c++")!=-1 or index($Path, "/g++/")!=-1) { @@ -21547,6 +21588,9 @@ sub is_target_lib($) if(not $LName) { return 0; } + if($OSgroup eq "windows") { + $LName = lc($LName); + } if($TargetLibraryName and $LName!~/\Q$TargetLibraryName\E/) { return 0; @@ -21840,9 +21884,9 @@ sub printReport() sub check_win32_env() { - if(not $ENV{"DevEnvDir"} - or not $ENV{"LIB"}) { - exitStatus("Error", "can't start without VS environment (vsvars32.bat)"); + if(not $ENV{"VCINSTALLDIR"} + or not $ENV{"INCLUDE"}) { + exitStatus("Error", "can't start without VC environment (vcvars64.bat)"); } } @@ -22082,13 +22126,14 @@ sub create_ABI_Dump() sub quickEmptyReports() { # Quick "empty" reports - # 4 times faster than merging equal dumps + # ~4 times faster than merging equal dumps # NOTE: the dump contains the "LibraryVersion" attribute # if you change the version, then your dump will be different # OVERCOME: use -v1 and v2 options for comparing dumps # and don't change version in the XML descriptor (and dumps) # OVERCOME 2: separate meta info from the dumps in ACC 2.0 - if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"}) + if($Descriptor{1}{"Path"} eq $Descriptor{2}{"Path"} + or -s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"}) { my $FilePath1 = $Descriptor{1}{"Path"}; my $FilePath2 = $Descriptor{2}{"Path"}; @@ -22116,15 +22161,29 @@ sub quickEmptyReports() my $Content1 = <DUMP1>; close(DUMP1); - open(DUMP2, $FilePath2); - my $Content2 = <DUMP2>; - close(DUMP2); + my $Eq = 0; + + if($FilePath1 eq $FilePath2) { + $Eq = 1; + } - if($Content1 eq $Content2) + if(not $Eq) { + open(DUMP2, $FilePath2); + my $Content2 = <DUMP2>; + close(DUMP2); + + if($Content1 eq $Content2) { + $Eq = 1; + } + # clean memory undef $Content2; - + } + + if($Eq) + { + printMsg("INFO", "Input ABI dumps are equal, so generating quick empty report"); # read a number of headers, libs, symbols and types my $ABIdump = eval($Content1); @@ -22143,6 +22202,11 @@ sub quickEmptyReports() $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"}; } read_Source_DumpInfo($ABIdump, 1); + + foreach (keys(%{$Registered_Headers{1}})) { + $TargetHeaders{1}{$_} = 1; + } + read_Libs_DumpInfo($ABIdump, 1); read_Machine_DumpInfo($ABIdump, 1); read_Machine_DumpInfo($ABIdump, 2); @@ -22169,6 +22233,16 @@ sub quickEmptyReports() $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"}; $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"}; + + if(defined $ABIdump->{"ABI_DUMPER_VERSION"}) + { + $UsedDump{1}{"DWARF"} = 1; + $UsedDump{2}{"DWARF"} = 1; + + $UsedDump{1}{"M"} = $ABIdump->{"LibraryName"}; + $UsedDump{2}{"M"} = $ABIdump->{"LibraryName"}; + } + exitReport(); } } @@ -22187,7 +22261,7 @@ sub initLogging($) if($LogMode ne "n") { mkpath($LOG_DIR); } - $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE; + $LOG_PATH{$LibVersion} = join_P(get_abs_path($LOG_DIR), $LOG_FILE); if($Debug) { # debug directory $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}; @@ -22263,10 +22337,14 @@ sub compareInit() } detect_default_paths("bin"); # to extract dumps - if(isDump($Descriptor{1}{"Path"}) - and isDump($Descriptor{2}{"Path"})) - { # optimization: equal ABI dumps - quickEmptyReports(); + + if(not defined $DisableQuickEmptyReport) + { + if(isDump($Descriptor{1}{"Path"}) + and isDump($Descriptor{2}{"Path"})) + { # optimization: equal ABI dumps + quickEmptyReports(); + } } printMsg("INFO", "preparation, please wait ..."); @@ -22682,6 +22760,7 @@ sub getSysOpts() "CrossGcc"=>$CrossGcc, "UseStaticLibs"=>$UseStaticLibs, "NoStdInc"=>$NoStdInc, + "CppCompat"=>$CppCompat, "BinaryOnly" => $BinaryOnly, "SourceOnly" => $SourceOnly @@ -22821,7 +22900,7 @@ sub scenario() } if($ShowVersion) { - printMsg("INFO", "ABI Compliance Checker (ABICC) $TOOL_VERSION\nCopyright (C) 2015 Andrey Ponomarenko's ABI Laboratory\nLicense: LGPL or GPL <http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko."); + printMsg("INFO", "ABI Compliance Checker (ABICC) $TOOL_VERSION\nCopyright (C) 2016 Andrey Ponomarenko's ABI Laboratory\nLicense: LGPL or GPL <http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko."); exit(0); } if($DumpVersion) @@ -22856,8 +22935,14 @@ sub scenario() if(not -f $TargetLibsPath) { exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'"); } - foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) { - $TargetLibs{$Lib} = 1; + foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) + { + if($OSgroup eq "windows") { + $TargetLibs{lc($Lib)} = 1; + } + else { + $TargetLibs{$Lib} = 1; + } } } if($TargetHeadersPath) @@ -22887,7 +22972,10 @@ sub scenario() } if($DumpSystem) { # --dump-system - + if(-d $MODULES_DIR."/Targets/" + and -d $MODULES_DIR."/Targets/".$OStarget) { + $TargetSysInfo = $MODULES_DIR."/Targets/".$OStarget; + } if(not $TargetSysInfo) { exitStatus("Error", "-sysinfo option should be specified to dump system ABI"); } |