ABI Compliance Checker 1.98.5
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
index 8822c18..5186881 100755
--- a/abi-compliance-checker.pl
+++ b/abi-compliance-checker.pl
@@ -23,7 +23,7 @@
 #    - Ctags (5.8 or newer)
 #
 #  Mac OS X
-#    - Xcode (g++, c++filt, nm)
+#    - Xcode (g++, c++filt, otool, nm)
 #    - Ctags (5.8 or newer)
 #
 #  MS Windows
@@ -87,7 +87,7 @@
 $SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat,
 $UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
 $SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
-$ExtraInfo);
+$ExtraInfo, $ExtraDump, $Force);
 
 my $CmdName = get_filename($0);
 my %OS_LibExt = (
@@ -170,23 +170,27 @@
 
 More info: $CmdName --help\n";
 
-if($#ARGV==-1) {
+if($#ARGV==-1)
+{
     printMsg("INFO", $ShortUsage);
     exit(0);
 }
 
 foreach (2 .. $#ARGV)
 { # correct comma separated options
-    if($ARGV[$_-1] eq ",") {
+    if($ARGV[$_-1] eq ",")
+    {
         $ARGV[$_-2].=",".$ARGV[$_];
         splice(@ARGV, $_-1, 2);
     }
-    elsif($ARGV[$_-1]=~/,\Z/) {
+    elsif($ARGV[$_-1]=~/,\Z/)
+    {
         $ARGV[$_-1].=$ARGV[$_];
         splice(@ARGV, $_, 1);
     }
     elsif($ARGV[$_]=~/\A,/
-    and $ARGV[$_] ne ",") {
+    and $ARGV[$_] ne ",")
+    {
         $ARGV[$_-1].=$ARGV[$_];
         splice(@ARGV, $_, 1);
     }
@@ -257,7 +261,9 @@
   "component=s" => \$TargetComponent_Opt,
   "b|browse=s" => \$Browse,
   "open!" => \$OpenReport,
-  "extra-info=s" => \$ExtraInfo
+  "extra-info=s" => \$ExtraInfo,
+  "extra-dump!" => \$ExtraDump,
+  "force!" => \$Force
 ) or ERR_MESSAGE();
 
 sub ERR_MESSAGE()
@@ -378,7 +384,7 @@
          6. Comma separated list of headers and/or libraries
 
       If you are using an 2-6 descriptor types then you should
-      specify version numbers with -v1 <num> and -v2 <num> options too.
+      specify version numbers with -v1 and -v2 options too.
 
       For more information, please see:
         http://ispras.linuxbase.org/index.php/Library_Descriptor
@@ -387,9 +393,11 @@
       Descriptor of 2nd (new) library version.
 
   -dump|-dump-abi PATH
-      Dump library ABI to gzipped TXT format file. You can transfer it
-      anywhere and pass instead of the descriptor. Also it can be used
-      for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
+      Create library ABI dump for the input XML descriptor. You can
+      transfer it anywhere and pass instead of the descriptor. Also
+      it can be used for debugging the tool.
+      
+      Supported ABI dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
 
   -old-dumps
       Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
@@ -483,7 +491,7 @@
       increase the performance of the tool and decrease the system memory usage.
 
   -nostdinc
-      Do not search the GCC standard system directories for header files.
+      Do not search in GCC standard system directories for header files.
 
   -dump-system NAME -sysroot DIR
       Find all the shared libraries and header files in DIR directory,
@@ -727,6 +735,13 @@
       
   -extra-info DIR
       Dump extra info to DIR.
+      
+  -extra-dump
+      Create extended ABI dump containing all symbols
+      from the translation unit.
+      
+  -force
+      Try to use this option if the tool doesn't work.
 
 REPORT:
     Compatibility report will be generated to:
@@ -1251,34 +1266,36 @@
 my %OS_AddPath=(
 # These paths are needed if the tool cannot detect them automatically
     "macos"=>{
-        "include"=>{
-            "/Library"=>1,
-            "/Developer/usr/include"=>1
-        },
-        "lib"=>{
-            "/Library"=>1,
-            "/Developer/usr/lib"=>1
-        },
-        "bin"=>{
-            "/Developer/usr/bin"=>1
-        }
+        "include"=>[
+            "/Library",
+            "/Developer/usr/include"
+        ],
+        "lib"=>[
+            "/Library",
+            "/Developer/usr/lib"
+        ],
+        "bin"=>[
+            "/Developer/usr/bin"
+        ]
     },
     "beos"=>{
     # Haiku has GCC 2.95.3 by default
     # try to find GCC>=3.0 in /boot/develop/abi
-        "include"=>{
-            "/boot/common"=>1,
-            "/boot/develop"=>1},
-        "lib"=>{
-            "/boot/common/lib"=>1,
-            "/boot/system/lib"=>1,
-            "/boot/apps"=>1},
-        "bin"=>{
-            "/boot/common/bin"=>1,
-            "/boot/system/bin"=>1,
-            "/boot/develop/abi"=>1
+        "include"=>[
+            "/boot/common",
+            "/boot/develop"
+        ],
+        "lib"=>[
+            "/boot/common/lib",
+            "/boot/system/lib",
+            "/boot/apps"
+        ],
+        "bin"=>[
+            "/boot/common/bin",
+            "/boot/system/bin",
+            "/boot/develop/abi"
+        ]
     }
-}
 );
 
 my %Slash_Type=(
@@ -1306,6 +1323,8 @@
 my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
 my $TargetComponent;
 
+my $CheckUndefined = 0;
+
 # Set Target Component Name
 if($TargetComponent_Opt) {
     $TargetComponent = lc($TargetComponent_Opt);
@@ -1408,17 +1427,26 @@
 my %GlobalDataObject;
 my %WeakSymbols;
 
+# Extra Info
+my %UndefinedSymbols;
+
 # Headers
-my %Include_Preamble;
+my %Include_Preamble = (
+    "1"=>[],
+    "2"=>[] );
 my %Registered_Headers;
 my %HeaderName_Paths;
 my %Header_Dependency;
 my %Include_Neighbors;
-my %Include_Paths;
+my %Include_Paths = (
+    "1"=>[],
+    "2"=>[] );
 my %INC_PATH_AUTODETECT = (
   "1"=>1,
   "2"=>1 );
-my %Add_Include_Paths;
+my %Add_Include_Paths = (
+    "1"=>[],
+    "2"=>[] );
 my %Skip_Include_Paths;
 my %RegisteredDirs;
 my %Header_ErrorRedirect;
@@ -1458,17 +1486,17 @@
 
 # System Objects
 my %SystemObjects;
-my %DefaultLibPaths;
+my @DefaultLibPaths;
 my %DyLib_DefaultPath;
 
 # System Headers
 my %SystemHeaders;
-my %DefaultCppPaths;
-my %DefaultGccPaths;
-my %DefaultIncPaths;
+my @DefaultCppPaths;
+my @DefaultGccPaths;
+my @DefaultIncPaths;
 my %DefaultCppHeader;
 my %DefaultGccHeader;
-my %UserIncPath;
+my @UsersIncPath;
 
 # Merging
 my %CompleteSignature;
@@ -1514,8 +1542,12 @@
 my @RecurConstant;
 
 # System
-my %SystemPaths;
-my %DefaultBinPaths;
+my %SystemPaths = (
+    "include"=>[],
+    "lib"=>[],
+    "bin"=>[]
+);
+my @DefaultBinPaths;
 my $GCC_PATH;
 
 # Symbols versioning
@@ -1591,6 +1623,16 @@
     $LoadedModules{$Name} = 1;
 }
 
+sub readModule($$)
+{
+    my ($Module, $Name) = @_;
+    my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
+    if(not -f $Path) {
+        exitStatus("Module_Error", "can't access \'$Path\'");
+    }
+    return readFile($Path);
+}
+
 sub showPos($)
 {
     my $Number = $_[0];
@@ -1724,7 +1766,7 @@
     if(my $DefaultPath = get_CmdPath_Default($Name)) {
         return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
     }
-    foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
+    foreach my $Path (@{$SystemPaths{"bin"}})
     {
         my $CmdPath = joinPath($Path,$Name);
         if(-f $CmdPath)
@@ -1759,7 +1801,7 @@
     elsif($Name=~/gcc/) {
         return check_gcc($Name, "3");
     }
-    if(check_command($Name)) {
+    if(checkCmd($Name)) {
         return $Name;
     }
     if($OSgroup eq "windows")
@@ -1768,31 +1810,15 @@
             return $Name;
         }
     }
-    if($Name!~/which/)
-    {
-        if(my $WhichCmd = get_CmdPath("which"))
-        {
-            if(`$WhichCmd $Name 2>\"$TMP_DIR/null\"`) {
-                return $Name;
-            }
-        }
-    }
-    foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
+    foreach my $Path (@DefaultBinPaths)
     {
         if(-f $Path."/".$Name) {
-            return joinPath($Path,$Name);
+            return joinPath($Path, $Name);
         }
     }
     return "";
 }
 
-sub clean_path($)
-{
-    my $Path = $_[0];
-    $Path=~s/[\/\\]+\Z//g;
-    return $Path;
-}
-
 sub classifyPath($)
 {
     my $Path = $_[0];
@@ -1825,6 +1851,7 @@
     }
     $Content=~s/\/\*(.|\n)+?\*\///g;
     $Content=~s/<\!--(.|\n)+?-->//g;
+    
     $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
     if($TargetVersion{$LibVersion}) {
         $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
@@ -1892,57 +1919,54 @@
     }
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
     {
-        $Path = clean_path($Path);
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
         $Path = path_format($Path, $OSgroup);
-        $SystemPaths{"include"}{$Path}=1;
+        push_U($SystemPaths{"include"}, $Path);
     }
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
     {
-        $Path = clean_path($Path);
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
         $Path = path_format($Path, $OSgroup);
-        $SystemPaths{"lib"}{$Path}=1;
+        push_U($SystemPaths{"lib"}, $Path);
     }
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
     {
-        $Path=clean_path($Path);
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
         $Path = path_format($Path, $OSgroup);
-        $SystemPaths{"bin"}{$Path}=1;
+        push_U($SystemPaths{"bin"}, $Path);
         $TargetTools{$Path}=1;
     }
     if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
         $CrossPrefix = $Prefix;
     }
+    $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //=
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
     {
-        $Path=clean_path($Path);
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
         $Path = path_format($Path, $OSgroup);
-        $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
+        push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path);
     }
+    $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"});
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
     {
-        $Path=clean_path($Path);
         if(not -d $Path) {
             exitStatus("Access_Error", "can't access directory \'$Path\'");
         }
         $Path = path_format($Path, $OSgroup);
-        $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
+        push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path);
     }
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
     {
         # skip some auto-generated include paths
-        $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
+        $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1;
     }
     foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
     {
@@ -2167,13 +2191,16 @@
     delete($Cache{"getTypeAttr"});
     delete($Cache{"getTypeDeclId"});
     
-    # remove unused types
-    if($BinaryOnly and not $ExtendedCheck)
-    { # --binary
-        removeUnused($Version, "All");
-    }
-    else {
-        removeUnused($Version, "Derived");
+    if(not $ExtraInfo)
+    {
+        # remove unused types
+        if($BinaryOnly and not $ExtendedCheck)
+        { # --binary
+            removeUnused($Version, "All");
+        }
+        else {
+            removeUnused($Version, "Derived");
+        }
     }
     
     if($Debug) {
@@ -4520,7 +4547,17 @@
     if($SymbolInfo{$Version}{$InfoId}{"Class"}
     or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
     { # identify language
-        setLanguage($Version, "C++");
+        if($COMMON_LANGUAGE{$Version} ne "C++")
+        {
+            if(my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"})
+            {
+                if(index($ShortName, "__")!=0)
+                { # skip C++ symbols from pthread.h:
+                  # __pthread_cleanup_class, __restore, __defer, __setdoit, etc.
+                    setLanguage($Version, "C++");
+                }
+            }
+        }
     }
 }
 
@@ -4783,10 +4820,13 @@
     }
     if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"})
     {
-        if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
-        { # non-target symbols
-            delete($SymbolInfo{$Version}{$InfoId});
-            return;
+        if(not $ExtraDump)
+        {
+            if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version))
+            { # non-target symbols
+                delete($SymbolInfo{$Version}{$InfoId});
+                return;
+            }
         }
     }
     if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
@@ -5598,12 +5638,12 @@
     $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
     if($Mode eq "DepsOnly")
     {
-        foreach my $Path (cmd_find($Dir,"d","","")) {
+        foreach my $Path (cmd_find($Dir,"d")) {
             $Header_Dependency{$LibVersion}{$Path} = 1;
         }
         return;
     }
-    foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
+    foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f"))
     {
         if($WithDeps)
         { 
@@ -5788,11 +5828,18 @@
 sub searchForHeaders($)
 {
     my $LibVersion = $_[0];
+    
     # gcc standard include paths
-    find_gcc_cxx_headers($LibVersion);
+    registerGccHeaders();
+    
+    if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
+    { # c++ standard include paths
+        registerCppHeaders();
+    }
+    
     # processing header paths
-    foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
-    keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
+    foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}},
+    @{$Descriptor{$LibVersion}{"AddIncludePaths"}})
     {
         my $IPath = $Path;
         if($SystemRoot)
@@ -5811,17 +5858,18 @@
         {
             $Path = get_abs_path($Path);
             register_directory($Path, 0, $LibVersion);
-            if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
-                $Add_Include_Paths{$LibVersion}{$Path} = 1;
+            if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) {
+                push(@{$Add_Include_Paths{$LibVersion}}, $Path);
             }
             else {
-                $Include_Paths{$LibVersion}{$Path} = 1;
+                push(@{$Include_Paths{$LibVersion}}, $Path);
             }
         }
     }
-    if(keys(%{$Include_Paths{$LibVersion}})) {
+    if(@{$Include_Paths{$LibVersion}}) {
         $INC_PATH_AUTODETECT{$LibVersion} = 0;
     }
+    
     # registering directories
     foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
     {
@@ -5834,13 +5882,13 @@
         elsif(-f $Path)
         {
             my $Dir = get_dirname($Path);
-            if(not $SystemPaths{"include"}{$Dir}
+            if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}})
             and not $LocalIncludes{$Dir})
             {
                 register_directory($Dir, 1, $LibVersion);
                 if(my $OutDir = get_dirname($Dir))
                 { # registering the outer directory
-                    if(not $SystemPaths{"include"}{$OutDir}
+                    if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}})
                     and not $LocalIncludes{$OutDir}) {
                         register_directory($OutDir, 0, $LibVersion);
                     }
@@ -5869,7 +5917,7 @@
         elsif(-d $Dest)
         {
             my @Registered = ();
-            foreach my $Path (cmd_find($Dest,"f","",""))
+            foreach my $Path (cmd_find($Dest,"f"))
             {
                 next if(ignore_path($Path));
                 next if(not is_header($Path, 0, $LibVersion));
@@ -5889,7 +5937,6 @@
     }
     if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
     { # preparing preamble headers
-        my $PPos=0;
         foreach my $Header (split(/\s*\n\s*/, $HList))
         {
             if(is_abs($Header) and not -f $Header) {
@@ -5898,12 +5945,8 @@
             $Header = path_format($Header, $OSgroup);
             if(my $Header_Path = is_header($Header, 1, $LibVersion))
             {
-                if(defined $Include_Preamble{$LibVersion}{$Header_Path})
-                { # duplicate
-                    next;
-                }
                 next if(skipHeader($Header_Path, $LibVersion));
-                $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
+                push_U($Include_Preamble{$LibVersion}, $Header_Path);
             }
             else {
                 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
@@ -6094,9 +6137,14 @@
         return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
     }
     return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
-    return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
+    
+    if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING)
+    { # skip /usr/include/c++/*/ headers
+        return () if(not $ExtraInfo);
+    }
+    
     push(@RecurInclude, $AbsPath);
-    if($DefaultGccPaths{$AbsDir}
+    if(grep { $AbsDir eq $_ } @DefaultGccPaths
     or fromLibc($AbsPath))
     { # check "real" (non-"model") include paths
         my @Paths = detect_real_includes($AbsPath, $LibVersion);
@@ -6206,8 +6254,10 @@
     if(defined $Cache{"find_in_defaults"}{$Header}) {
         return $Cache{"find_in_defaults"}{$Header};
     }
-    foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
-    (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
+    foreach my $Dir (@DefaultIncPaths,
+                     @DefaultGccPaths,
+                     @DefaultCppPaths,
+                     @UsersIncPath)
     {
         next if(not $Dir);
         if(-f $Dir."/".$Header) {
@@ -6449,6 +6499,9 @@
         if($Header eq "thread.h") {
             return "";
         }
+        if($Header eq "sys/atomic.h") {
+            return "";
+        }
     }
     if($OSgroup ne "hpux")
     {
@@ -6460,7 +6513,7 @@
         return "";
     }
     
-    foreach my $Path (keys(%{$SystemPaths{"include"}}))
+    foreach my $Path (@{$SystemPaths{"include"}})
     { # search in default paths
         if(-f $Path."/".$Header) {
             return joinPath($Path,$Header);
@@ -6508,7 +6561,7 @@
 {
     my $Dir = $_[0];
     $Dir=~s/[\/\\]+\Z//;
-    return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
+    return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths);
 }
 
 sub identifyHeader($$)
@@ -6542,7 +6595,7 @@
     { # search in the target library paths
         return $Path;
     }
-    elsif($DefaultGccHeader{$Header})
+    elsif(defined $DefaultGccHeader{$Header})
     { # search in the internal GCC include paths
         return $DefaultGccHeader{$Header};
     }
@@ -6550,7 +6603,7 @@
     { # search in the default GCC include paths
         return joinPath($DefaultDir,$Header);
     }
-    elsif($DefaultCppHeader{$Header})
+    elsif(defined $DefaultCppHeader{$Header})
     { # search in the default G++ include paths
         return $DefaultCppHeader{$Header};
     }
@@ -6609,7 +6662,8 @@
         {
             my $Str = $1;
             if($CppMode{$Version}
-            and $Str=~/\Ac99_(.+)\Z/) {
+            and $Str=~/\Ac99_(.+)\Z/)
+            {
                 if($CppKeywords_A{$1}) {
                     $Str=$1;
                 }
@@ -6624,9 +6678,9 @@
 {
     if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
     {
-        if($Info=~/ operator /)
+        if(index($Info, " operator ")!=-1)
         {
-            if($Info=~/ conversion /)
+            if(index($Info, " conversion ")!=-1)
             {
                 if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"})
                 {
@@ -6685,15 +6739,6 @@
     return $_[0];
 }
 
-sub unmangleSymbol($)
-{
-    my $Symbol = $_[0];
-    if(my @Unmngl = unmangleArray($Symbol)) {
-        return $Unmngl[0];
-    }
-    return "";
-}
-
 sub unmangleArray(@)
 {
     if($_[0]=~/\A\?/)
@@ -6716,6 +6761,7 @@
             my $Info = `$CppFiltCmd -h 2>&1`;
             $CPPFILT_SUPPORT_FILE = $Info=~/\@<file>/;
         }
+        my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":"";
         if($CPPFILT_SUPPORT_FILE)
         { # new versions of c++filt can take a file
             if($#_>$MAX_CPPFILT_FILE_SIZE)
@@ -6726,11 +6772,6 @@
             }
             else
             {
-                my $NoStrip = "";
-                if($OSgroup eq "macos"
-                or $OSgroup eq "windows") {
-                    $NoStrip = "-n";
-                }
                 writeFile("$TMP_DIR/unmangle", join("\n", @_));
                 my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`;
                 if($?==139)
@@ -6749,11 +6790,6 @@
             }
             else
             {
-                my $NoStrip = "";
-                if($OSgroup eq "macos"
-                or $OSgroup eq "windows") {
-                    $NoStrip = "-n";
-                }
                 my $Strings = join(" ", @_);
                 my $Res = `$CppFiltCmd $NoStrip $Strings`;
                 if($?==139)
@@ -7102,7 +7138,7 @@
             { # do NOT include /usr/include/{sys,bits}
                 next;
             }
-            $IncDir{$Dep}=1;
+            $IncDir{$Dep} = 1;
         }
     }
     $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
@@ -7170,6 +7206,7 @@
 sub path_format($$)
 { # forward slash to pass into MinGW GCC
     my ($Path, $Fmt) = @_;
+    $Path=~s/[\/\\]+\Z//;
     if($Fmt eq "windows")
     {
         $Path=~s/\//\\/g;
@@ -7192,7 +7229,7 @@
         }
         elsif($OSgroup eq "macos"
         and $Path=~/\.framework\Z/)
-        {# to Apple's GCC
+        { # to Apple's GCC
             return "-F".esc(get_dirname($Path));
         }
         else {
@@ -7335,6 +7372,7 @@
     "fd_set",
     "siginfo",
     "mallinfo",
+    "timex",
  # Mac
     "_timex",
     "_class_t",
@@ -7458,8 +7496,21 @@
     if(not $Path) {
         return;
     }
-    my $CTags = get_CmdPath("ctags");
+    my $CTags = undef;
+    
+    if($OSgroup eq "bsd")
+    { # use ectags on BSD
+        $CTags = get_CmdPath("ectags");
+        if(not $CTags) {
+            printMsg("WARNING", "can't find \'ectags\' program");
+        }
+    }
     if(not $CTags) {
+        $CTags = get_CmdPath("ctags");
+    }
+    if(not $CTags)
+    {
+        printMsg("WARNING", "can't find \'ctags\' program");
         return;
     }
     
@@ -7533,24 +7584,26 @@
         print TMP_HEADER "\n  // add defines\n  ".$AddDefines."\n";
     }
     print TMP_HEADER "\n  // add includes\n";
-    my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
-    @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
-    foreach my $Header_Path (@PreambleHeaders) {
-        print TMP_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
+    foreach my $HPath (@{$Include_Preamble{$Version}}) {
+        print TMP_HEADER "  #include \"".path_format($HPath, "unix")."\"\n";
     }
     my @Headers = keys(%{$Registered_Headers{$Version}});
     @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
-    foreach my $Header_Path (@Headers)
+    foreach my $HPath (@Headers)
     {
-        next if($Include_Preamble{$Version}{$Header_Path});
-        print TMP_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
+        if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) {
+            print TMP_HEADER "  #include \"".path_format($HPath, "unix")."\"\n";
+        }
     }
     close(TMP_HEADER);
-    my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
+    my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC");
     
     if($ExtraInfo)
     { # extra information for other tools
-        writeFile($ExtraInfo."/include-string", $IncludeString);
+        if($IncludeString) {
+            writeFile($ExtraInfo."/include-string", $IncludeString);
+        }
+        writeFile($ExtraInfo."/includes", Dumper($RecursiveIncludes{$Version}));
     }
     
     if(not keys(%{$TargetHeaders{$Version}}))
@@ -7563,7 +7616,7 @@
         writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper($Header_Includes{$Version}));
         writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper($RecursiveIncludes{$Version}));
         writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}{$Version}));
-        writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
+        writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\@DefaultIncPaths));
     }
     
     # clean memory
@@ -7618,6 +7671,7 @@
     if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
     and $CppMode{$Version}!=-1 and not $CppCompat)
     { # rename C++ keywords in C code
+      # disable this code by -cpp-compatible option
         if(not $MContent)
         { # preprocessing
             $MContent = `$PreprocessCmd 2>\"$TMP_DIR/null\"`;
@@ -7788,16 +7842,18 @@
         }
         # some GCC versions don't include class methods to the TU dump by default
         my ($AddClass, $ClassNum) = ("", 0);
+        my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions
         foreach my $CName (sort keys(%{$TUnit_Classes{$Version}}))
         {
             next if($C_Structure{$CName});
             next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
             next if($SkipTypes{$Version}{$CName});
-            if($OSgroup eq "linux")
-            {
-                next if(($CName=~tr![:]!!)>2);
-                if($CName=~/\A(.+)::[^:]+\Z/)
-                { # will be added by name space
+            if(not $Force and $GCC_44
+            and $OSgroup eq "linux")
+            { # optimization for linux with GCC >= 4.4
+              # disable this code by -force option
+                if(index($CName, "::")!=-1)
+                { # should be added by name space
                     next;
                 }
             }
@@ -7834,13 +7890,14 @@
     writeLog($Version, "The GCC parameters:\n  $SyntaxTreeCmd\n\n");
     chdir($TMP_DIR);
     system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1");
+    my $Errors = "";
     if($?)
     { # failed to compile, but the TU dump still can be created
-        if(my $Errors = readFile($TMP_DIR."/tu_errors"))
+        if($Errors = readFile($TMP_DIR."/tu_errors"))
         { # try to recompile
           # FIXME: handle other errors and try to recompile
             if($CppMode{$Version}==1
-            and $Errors=~/c99_/)
+            and index($Errors, "c99_")!=-1)
             { # disable c99 mode and try again
                 $CppMode{$Version}=-1;
                 printMsg("INFO", "Disabling C++ compatibility mode");
@@ -7856,12 +7913,11 @@
                 foreach my $Num (0 .. $#Headers)
                 {
                     my $Path = $Headers[$Num];
-                    if(defined $Include_Preamble{$Version}{$Path})
-                    { # already added
-                        next;
+                    if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}}))
+                    {
+                        push_U($Include_Preamble{$Version}, $Path);
+                        printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
                     }
-                    $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
-                    printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'");
                 }
                 resetLogging($Version);
                 $TMP_DIR = tempdir(CLEANUP=>1);
@@ -7871,12 +7927,19 @@
             and ($Errors=~/\Q-std=c++0x\E/
             or $Errors=~/is not a class or namespace/))
             { # c++0x: enum class
-                $Cpp0xMode{$Version}=-1;
-                printMsg("INFO", "Enabling c++0x mode");
-                resetLogging($Version);
-                $TMP_DIR = tempdir(CLEANUP=>1);
-                $CompilerOptions{$Version} .= " -std=c++0x";
-                return getDump();
+                if(check_gcc($GCC_PATH, "4.6"))
+                {
+                    $Cpp0xMode{$Version}=-1;
+                    printMsg("INFO", "Enabling c++0x mode");
+                    resetLogging($Version);
+                    $TMP_DIR = tempdir(CLEANUP=>1);
+                    $CompilerOptions{$Version} .= " -std=c++0x";
+                    return getDump();
+                }
+                else {
+                    printMsg("WARNING", "Probably c++0x construction detected");
+                }
+                
             }
             elsif($MinGWMode{$Version}==1)
             { # disable MinGW mode and try again
@@ -7893,12 +7956,23 @@
         printMsg("ERROR", "some errors occurred when compiling headers");
         printErrorLog($Version);
         $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
-        writeLog($Version, "\n");# new line
+        writeLog($Version, "\n"); # new line
     }
     chdir($ORIG_DIR);
     unlink($TmpHeaderPath);
     unlink($MHeaderPath);
-    return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
+    
+    if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) {
+        return $TUs[0];
+    }
+    else
+    {
+        my $Msg = "can't compile header(s)";
+        if($Errors=~/error trying to exec \W+cc1plus\W+/) {
+            $Msg .= "\nDid you install G++?";
+        }
+        exitStatus("Cannot_Compile", $Msg);
+    }
 }
 
 sub cmd_file($)
@@ -7925,7 +7999,7 @@
 sub getIncPaths(@)
 {
     my @HeaderPaths = @_;
-    my @IncPaths = ();
+    my @IncPaths = @{$Add_Include_Paths{$Version}};
     if($INC_PATH_AUTODETECT{$Version})
     { # auto-detecting dependencies
         my %Includes = ();
@@ -7942,28 +8016,39 @@
                         next;
                     }
                 }
-                $Includes{$Dir}=1;
+                $Includes{$Dir} = 1;
             }
         }
-        foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
-        { # added by user
-            next if($Includes{$Dir});
-            push(@IncPaths, $Dir);
-        }
         foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
-            push(@IncPaths, $Dir);
+            push_U(\@IncPaths, $Dir);
         }
     }
     else
     { # user-defined paths
-        foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
-        sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
-            push(@IncPaths, $Dir);
-        }
+        @IncPaths = @{$Include_Paths{$Version}};
     }
     return \@IncPaths;
 }
 
+sub push_U($@)
+{ # push unique
+    if(my $Array = shift @_)
+    {
+        if(@_)
+        {
+            my %Exist = map {$_=>1} @{$Array};
+            foreach my $Elem (@_)
+            {
+                if(not defined $Exist{$Elem})
+                {
+                    push(@{$Array}, $Elem);
+                    $Exist{$Elem} = 1;
+                }
+            }
+        }
+    }
+}
+
 sub callPreprocessor($$$)
 {
     my ($Path, $Inc, $LibVersion) = @_;
@@ -7978,11 +8063,11 @@
     return $Out;
 }
 
-sub cmd_find($$$$)
+sub cmd_find(@)
 { # native "find" is much faster than File::Find (~6x)
   # also the File::Find doesn't support --maxdepth N option
   # so using the cross-platform wrapper for the native one
-    my ($Path, $Type, $Name, $MaxDepth) = @_;
+    my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_;
     return () if(not $Path or not -e $Path);
     if($OSgroup eq "windows")
     {
@@ -8000,19 +8085,13 @@
         if($Type eq "d") {
             $Cmd .= " /AD";
         }
-        my @Files = ();
+        my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
         if($Name)
         { # FIXME: how to search file names in MS shell?
-            $Name=~s/\*/.*/g if($Name!~/\]/);
-            foreach my $File (split(/\n/, `$Cmd`))
-            {
-                if($File=~/$Name\Z/i) {
-                    push(@Files, $File);
-                }
+            if(not $UseRegex) {
+                $Name=~s/\*/.*/g;
             }
-        }
-        else {
-            @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`);
+            @Files = grep { /\A$Name\Z/i } @Files;
         }
         my @AbsPaths = ();
         foreach my $File (@Files)
@@ -8050,19 +8129,19 @@
         if($Type) {
             $Cmd .= " -type $Type";
         }
-        if($Name)
-        { # file name
-            if($Name=~/\]/) {
-                $Cmd .= " -regex \"$Name\"";
-            }
-            else {
-                $Cmd .= " -name \"$Name\"";
-            }
+        if($Name and not $UseRegex)
+        { # wildcards
+            $Cmd .= " -name \"$Name\"";
         }
         my $Res = `$Cmd 2>\"$TMP_DIR/null\"`;
         if($?) {
             printMsg("ERROR", "problem with \'find\' utility ($?): $!");
         }
+        my @Files = split(/\n/, $Res);
+        if($Name and $UseRegex)
+        { # regex
+            @Files = grep { /\A$Name\Z/ } @Files;
+        }
         return split(/\n/, $Res);
     }
 }
@@ -8275,7 +8354,7 @@
         }
         else
         {
-            if($Header=~/\/include\//
+            if(index($Header, "/include/")!=-1
             or cmd_file($Header)=~/C[\+]*\s+program/i)
             { # !~/HTML|XML|shared|dynamic/i
                 return $Header;
@@ -8314,9 +8393,6 @@
     $Version = $_[0];
     printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
     my $DumpPath = getDump();
-    if(not $DumpPath) {
-        exitStatus("Cannot_Compile", "can't compile header(s)");
-    }
     if($Debug)
     { # debug mode
         mkpath($DEBUG_PATH{$Version});
@@ -11879,7 +11955,7 @@
 {
     my ($Symbol, $Full) = @_;
     my ($SN, $SO, $SV) = separate_symbol($Symbol);
-    $Symbol=$SN;# remove version
+    $Symbol=$SN; # remove version
     my $Signature = $tr_name{$Symbol};
     my $Suffix = substr($Signature, find_center($Signature, "("));
     if(not $Full) {
@@ -13223,6 +13299,10 @@
         {
             my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
             my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
+            if(not @Membs2)
+            { # private
+                return 0;
+            }
             if($#Membs1!=$#Membs2)
             { # different number of elements
                 return 1;
@@ -13244,6 +13324,10 @@
                 { # compare elements by type name
                     my $MT1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
                     my $MT2 = $TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}{"Name"};
+                    
+                    $MT1 = uncover_typedefs($MT1, 1);
+                    $MT2 = uncover_typedefs($MT2, 2);
+                    
                     if($MT1 ne $MT2)
                     { # different types
                         if(not isAnon($MT1) and not isAnon($MT2)) {
@@ -16397,9 +16481,54 @@
             exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
         }
     }
-    foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
+    
+    foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths)
+    {
         readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1);
+        
+        
     }
+    
+    if($CheckUndefined)
+    {
+        my %UndefinedLibs = ();
+        
+        foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths)
+        {
+            my $LibName = get_filename($LibPath);
+            foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibPath}}))
+            {
+                if(not $Symbol_Library{$LibVersion}{$Symbol} and not $DepSymbol_Library{$LibVersion}{$Symbol})
+                {
+                    foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) {
+                        $UndefinedLibs{$Path} = 1;
+                    }
+                }
+            }
+        }
+        if($ExtraInfo)
+        { # extra information for other tools
+            if(my @Paths = keys(%UndefinedLibs))
+            {
+                my $LibString = "";
+                foreach (@Paths)
+                {
+                    my ($Dir, $Name) = separate_path($_);
+                    
+                    if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) {
+                        $LibString .= "-L".esc($Dir);
+                    }
+                    
+                    $Name = parse_libname($Name, "name", $OStarget);
+                    $Name=~s/\Alib//;
+                    
+                    $LibString .= "-l$Name";
+                }
+                writeFile($ExtraInfo."/libs-string", $LibString);
+            }
+        }
+    }
+    
     if(not $CheckHeadersOnly)
     {
         if($#LibPaths!=-1)
@@ -16417,6 +16546,180 @@
    %SystemObjects = ();
 }
 
+my %Prefix_Lib_Map=(
+ # symbols for autodetecting library dependencies (by prefix)
+    "pthread_" => ["libpthread"],
+    "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"],
+    "cairo_" => ["libcairo"],
+    "gtk_" => ["libgtk-x11-2.0"],
+    "atk_" => ["libatk-1.0"],
+    "gdk_" => ["libgdk-x11-2.0"],
+    "gl" => ["libGL"],
+    "glu" => ["libGLU"],
+    "popt" => ["libpopt"],
+    "Py" => ["libpython"],
+    "jpeg_" => ["libjpeg"],
+    "BZ2_" => ["libbz2"],
+    "Fc" => ["libfontconfig"],
+    "Xft" => ["libXft"],
+    "SSL_" => ["libssl"],
+    "sem_" => ["libpthread"],
+    "snd_" => ["libasound"],
+    "art_" => ["libart_lgpl_2"],
+    "dbus_g" => ["libdbus-glib-1"],
+    "GOMP_" => ["libgomp"],
+    "omp_" => ["libgomp"],
+    "cms" => ["liblcms"]
+);
+
+my %Pattern_Lib_Map=(
+    "SL[a-z]" => ["libslang"]
+);
+
+my %Symbol_Lib_Map=(
+ # symbols for autodetecting library dependencies (by name)
+    "pow" => "libm",
+    "fmod" => "libm",
+    "sin" => "libm",
+    "floor" => "libm",
+    "cos" => "libm",
+    "dlopen" => "libdl",
+    "deflate" => "libz",
+    "inflate" => "libz",
+    "move_panel" => "libpanel",
+    "XOpenDisplay" => "libX11",
+    "resize_term" => "libncurses",
+    "clock_gettime" => "librt"
+);
+
+sub find_SymbolLibs($$)
+{
+    my ($LibVersion, $Symbol) = @_;
+    
+    if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/)
+    { # debug symbols
+        return ();
+    }
+    
+    my %Paths = ();
+    
+    if(my $LibName = $Symbol_Lib_Map{$Symbol})
+    {
+        if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
+            $Paths{$Path} = 1;
+        }
+    }
+    
+    if(my $SymbolPrefix = getPrefix($Symbol))
+    {
+        if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) {
+            return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}};
+        }
+    
+        if(not keys(%Paths))
+        {
+            if(defined $Prefix_Lib_Map{$SymbolPrefix})
+            {
+                foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}})
+                {
+                    if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
+                        $Paths{$Path} = 1;
+                    }
+                }
+            }
+        }
+        
+        if(not keys(%Paths))
+        {
+            foreach my $Prefix (sort keys(%Pattern_Lib_Map))
+            {
+                if($Symbol=~/\A$Prefix/)
+                {
+                    foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}})
+                    {
+                        if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) {
+                            $Paths{$Path} = 1;
+                        }
+                    }
+                }
+            }
+        }
+    
+        if(not keys(%Paths))
+        {
+            if($SymbolPrefix)
+            { # try to find a library by symbol prefix
+                if($SymbolPrefix eq "inotify" and
+                index($Symbol, "\@GLIBC")!=-1)
+                {
+                    if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) {
+                        $Paths{$Path} = 1;
+                    }
+                }
+                else
+                {
+                    if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) {
+                        $Paths{$Path} = 1;
+                    }
+                }
+            }
+        }
+        
+        if(my @Paths = keys(%Paths)) {
+            $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths;
+        }
+    }
+    return keys(%Paths);
+}
+
+sub get_LibPath_Prefix($$)
+{
+    my ($LibVersion, $Prefix) = @_;
+    
+    $Prefix = lc($Prefix);
+    $Prefix=~s/[_]+\Z//g;
+    
+    foreach ("-2", "2", "-1", "1", "")
+    { # libgnome-2.so
+      # libxml2.so
+      # libdbus-1.so
+        if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) {
+            return $Path;
+        }
+    }
+    return "";
+}
+
+sub getPrefix($)
+{
+    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 getSymbolSize($$)
 { # size from the shared library
     my ($Symbol, $LibVersion) = @_;
@@ -16502,7 +16805,9 @@
             $Symbol=~s/[\@\$]+(.*)\Z//;
             push(@MnglNames1, $Symbol);
         }
-        elsif(index($Symbol, "?")==0) {
+        elsif(index($Symbol, "?")==0)
+        {
+            next if($tr_name{$Symbol});
             push(@MnglNames2, $Symbol);
         }
         else
@@ -16833,7 +17138,7 @@
     { # ldconfig default paths
         return $DefaultPath;
     }
-    foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
+    foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}})
     { # search in default linker directories
       # and then in all system paths
         if(-f $Dir."/".$Name) {
@@ -16923,30 +17228,42 @@
         }
         while(<LIB>)
         {
+            if($CheckUndefined)
+            {
+                if(not $IsNeededLib)
+                {
+                    if(/ U _([\w\$]+)\s*\Z/)
+                    {
+                        $UndefinedSymbols{$LibVersion}{$Lib_Path}{$1} = 1;
+                        next;
+                    }
+                }
+            }
+            
             if(/ [STD] _([\w\$]+)\s*\Z/)
             {
-                my $realname = $1;
+                my $Symbol = $1;
                 if($IsNeededLib)
                 {
                     if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName})
                     {
-                        $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name;
-                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
+                        $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
+                        $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
                     }
                 }
                 else
                 {
-                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
-                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
+                    $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name;
+                    $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1;
                     if($COMMON_LANGUAGE{$LibVersion} ne "C++")
                     {
-                        if(index($realname, "_Z")==0 or index($realname, "?")==0) {
+                        if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) {
                             setLanguage($LibVersion, "C++");
                         }
                     }
                     if($CheckObjectsOnly
                     and $LibVersion==1) {
-                        $CheckedSymbols{"Binary"}{$realname} = 1;
+                        $CheckedSymbols{"Binary"}{$Symbol} = 1;
                     }
                 }
             }
@@ -17087,6 +17404,12 @@
             { # read ELF entry
                 if($Ndx eq "UND")
                 { # ignore interfaces that are imported from somewhere else
+                    if($CheckUndefined)
+                    {
+                        if(not $IsNeededLib) {
+                            $UndefinedSymbols{$LibVersion}{$Lib_Path}{$Symbol} = 1;
+                        }
+                    }
                     next;
                 }
                 if($Bind eq "WEAK"
@@ -17217,23 +17540,23 @@
 sub detectSystemHeaders()
 {
     my @SysHeaders = ();
-    foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
+    foreach my $DevelPath (@{$SystemPaths{"include"}})
     {
         next if(not -d $DevelPath);
         # search for all header files in the /usr/include
         # with or without extension (ncurses.h, QtCore, ...)
-        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
-        foreach my $Link (cmd_find($DevelPath,"l","",""))
+        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f"));
+        foreach my $Link (cmd_find($DevelPath,"l"))
         { # add symbolic links
             if(-f $Link) {
                 push(@SysHeaders, $Link);
             }
         }
     }
-    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
+    foreach my $DevelPath (@{$SystemPaths{"lib"}})
     { # search for config headers in the /usr/lib
         next if(not -d $DevelPath);
-        foreach (cmd_find($DevelPath,"f","",""))
+        foreach (cmd_find($DevelPath,"f"))
         {
             if(not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs)/)
             {
@@ -17248,7 +17571,7 @@
 
 sub detectSystemObjects()
 {
-    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
+    foreach my $DevelPath (@{$SystemPaths{"lib"}})
     {
         next if(not -d $DevelPath);
         foreach my $Path (find_libs($DevelPath,"",""))
@@ -17354,7 +17677,7 @@
 sub registerObject_Dir($$)
 {
     my ($Dir, $LibVersion) = @_;
-    if($SystemPaths{"lib"}{$Dir})
+    if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}})
     { # system directory
         return;
     }
@@ -17432,10 +17755,10 @@
     {
         $Dest=~s/[\/\\]+\Z//g;
         my %Libs = ();
-        if($SystemPaths{"lib"}{$Dest})
+        if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}})
         { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
           # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
-            foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
+            foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2))
             { # all files and symlinks that match the name of a library
                 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
                 {
@@ -17455,7 +17778,7 @@
             }
             if($OSgroup eq "macos")
             { # shared libraries on MacOS X may have no extension
-                foreach my $Path (cmd_find($Dest,"f","",""))
+                foreach my $Path (cmd_find($Dest,"f"))
                 {
                     next if(ignore_path($Path));
                     next if(skip_lib($Path, $LibVersion));
@@ -17481,12 +17804,6 @@
     return (grep {$_ eq $Value} @{$Stack});
 }
 
-sub generateTemplate()
-{
-    writeFile("VERSION.xml", $DescriptorTemplate."\n");
-    printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
-}
-
 sub detectWordSize()
 {
     return "" if(not $GCC_PATH);
@@ -17535,7 +17852,8 @@
     return 0 if($V1 eq $V2);
     my @V1Parts = split(/\./, $V1);
     my @V2Parts = split(/\./, $V2);
-    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
+    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++)
+    {
         return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
         return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
     }
@@ -17589,33 +17907,33 @@
         }
     }
     # new dumps (>=1.22) have a personal versioning
-    my $DumpVersion = $ABI->{"ABI_DUMP_VERSION"};
+    my $DVersion = $ABI->{"ABI_DUMP_VERSION"};
     my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
-    if(not $DumpVersion)
+    if(not $DVersion)
     { # old dumps (<=1.21.6) have been marked by the tool version
-        $DumpVersion = $ToolVersion;
+        $DVersion = $ToolVersion;
     }
-    $UsedDump{$LibVersion}{"V"} = $DumpVersion;
-    if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
+    $UsedDump{$LibVersion}{"V"} = $DVersion;
+    if(majorVersion($DVersion) ne majorVersion($ABI_DUMP_VERSION))
     { # should be compatible with dumps of the same major version
-        if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
+        if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0)
         { # Don't know how to parse future dump formats
-            exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
+            exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)");
         }
-        elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
+        elsif(cmpVersions($DVersion, $TOOL_VERSION)>0 and not $ABI->{"ABI_DUMP_VERSION"})
         { # Don't know how to parse future dump formats
-            exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
+            exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)");
         }
         if($UseOldDumps)
         {
-            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
-                exitStatus("Dump_Version", "incompatible version \'$DumpVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
+            if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)<0) {
+                exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
             }
         }
         else
         {
-            my $Msg = "incompatible version \'$DumpVersion\' of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
-            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
+            my $Msg = "incompatible version \'$DVersion\' of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
+            if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
                 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
             }
             exitStatus("Dump_Version", $Msg);
@@ -18012,7 +18330,7 @@
 {
     my ($Path, $Type, $MaxDepth) = @_;
     # FIXME: correct the search pattern
-    return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
+    return cmd_find($Path, $Type, ".*\\.".$LIB_EXT."[0-9.]*", $MaxDepth, 1);
 }
 
 sub createDescriptor($$)
@@ -18132,7 +18450,7 @@
         $EnvPaths.=":".$ENV{"BETOOLS"};
     }
     my $Sep = ($OSgroup eq "windows")?";":":|;";
-    foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
+    foreach my $Path (split(/$Sep/, $EnvPaths))
     {
         $Path = path_format($Path, $OSgroup);
         $Path=~s/[\/\\]+\Z//g;
@@ -18142,36 +18460,42 @@
         { # do NOT use binaries from target system
             next;
         }
-        $DefaultBinPaths{$Path} = 1;
+        push_U(\@DefaultBinPaths, $Path);
     }
 }
 
 sub detect_inc_default_paths()
 {
     return () if(not $GCC_PATH);
-    my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
+    my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]);
     writeFile("$TMP_DIR/empty.h", "");
     foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`))
     { # detecting GCC default include paths
+        next if(index($Line, "/cc1plus ")!=-1);
+        
         if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
         {
             my $Path = simplify_path($1);
-            $Path=~s/[\/\\]+\Z//g;
+            $Path=~s/[\/\\]+\.?\Z//g;
             $Path = path_format($Path, $OSgroup);
-            if($Path=~/c\+\+|\/g\+\+\//)
+            if(index($Path, "c++")!=-1
+            or index($Path, "/g++/")!=-1)
             {
-                $DPaths{"Cpp"}{$Path}=1;
+                push_U($DPaths{"Cpp"}, $Path);
                 if(not defined $MAIN_CPP_DIR
                 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
                     $MAIN_CPP_DIR = $Path;
                 }
             }
-            elsif($Path=~/gcc/) {
-                $DPaths{"Gcc"}{$Path}=1;
+            elsif(index($Path, "gcc")!=-1) {
+                push_U($DPaths{"Gcc"}, $Path);
             }
             else
             {
-                next if($Path=~/local[\/\\]+include/);
+                if($Path=~/local[\/\\]+include/)
+                { # local paths
+                    next;
+                }
                 if($SystemRoot
                 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
                 { # The GCC include path for user headers is not a part of the system root
@@ -18179,7 +18503,7 @@
                   # or it is the internal cross-GCC path like arm-linux-gnueabi/include
                     next;
                 }
-                $DPaths{"Inc"}{$Path}=1;
+                push_U($DPaths{"Inc"}, $Path);
             }
         }
     }
@@ -18203,12 +18527,12 @@
     if($Search!~/gcc/) {
         $GSearch = 0;
     }
-    if(keys(%{$SystemPaths{"include"}}))
+    if(@{$SystemPaths{"include"}})
     { # <search_headers> section of the XML descriptor
       # do NOT search for systems headers
         $HSearch = 0;
     }
-    if(keys(%{$SystemPaths{"lib"}}))
+    if(@{$SystemPaths{"lib"}})
     { # <search_headers> section of the XML descriptor
       # do NOT search for systems headers
         $LSearch = 0;
@@ -18218,11 +18542,7 @@
         next if($Type eq "include" and not $HSearch);
         next if($Type eq "lib" and not $LSearch);
         next if($Type eq "bin" and not $BSearch);
-        foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
-        {
-            next if(not -d $Path);
-            $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
-        }
+        push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}});
     }
     if($OSgroup ne "windows")
     { # unix-like
@@ -18237,25 +18557,22 @@
               # 2. use host commands: ldconfig, readelf, etc.
                 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
             }
-            foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
-                $SystemPaths{$Type}{$Path} = 1;
-            }
+            push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1));
             if(-d $RootDir."/".$Type)
             { # if "/lib" is symbolic link
                 if($RootDir eq "/") {
-                    $SystemPaths{$Type}{"/".$Type} = 1;
+                    push_U($SystemPaths{$Type}, "/".$Type);
                 }
                 else {
-                    $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
+                    push_U($SystemPaths{$Type}, $RootDir."/".$Type);
                 }
             }
-            if(-d $UsrDir) {
-                foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
-                    $SystemPaths{$Type}{$Path} = 1;
-                }
+            if(-d $UsrDir)
+            {
+                push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1));
                 if(-d $UsrDir."/".$Type)
                 { # if "/usr/lib" is symbolic link
-                    $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
+                    push_U($SystemPaths{$Type}, $UsrDir."/".$Type);
                 }
             }
         }
@@ -18263,46 +18580,43 @@
     if($BSearch)
     {
         detect_bin_default_paths();
-        foreach my $Path (keys(%DefaultBinPaths)) {
-            $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
-        }
+        push_U($SystemPaths{"bin"}, @DefaultBinPaths);
     }
     # check environment variables
     if($OSgroup eq "beos")
     {
-        foreach (keys(%{$SystemPaths{"bin"}}))
+        if(my @Paths = @{$SystemPaths{"bin"}})
         {
-            if($_ eq ".") {
-                next;
-            }
-            foreach my $Path (cmd_find($_, "d", "bin", ""))
-            { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
-                $SystemPaths{"bin"}{$Path} = 1;
+            foreach (@Paths)
+            {
+                if($_ eq ".") {
+                    next;
+                }
+                # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
+                if(my @Dirs = sort cmd_find($_, "d", "bin")) {
+                    push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs);
+                }
             }
         }
         if($HSearch)
         {
-            foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
-            {
-                if(is_abs($Path)) {
-                    $DefaultIncPaths{$Path} = 1;
-                }
-            }
+            push_U(\@DefaultIncPaths, grep { is_abs($_) } (
+                split(/:|;/, $ENV{"BEINCLUDES"})
+                ));
         }
         if($LSearch)
         {
-            foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
-            {
-                if(is_abs($Path)) {
-                    $DefaultLibPaths{$Path} = 1;
-                }
-            }
+            push_U(\@DefaultLibPaths, grep { is_abs($_) } (
+                split(/:|;/, $ENV{"BELIBRARIES"}),
+                split(/:|;/, $ENV{"LIBRARY_PATH"})
+                ));
         }
     }
     if($LSearch)
     { # using linker to get system paths
         if(my $LPaths = detect_lib_default_paths())
         { # unix-like
+            my %Dirs = ();
             foreach my $Name (keys(%{$LPaths}))
             {
                 if($SystemRoot
@@ -18312,12 +18626,13 @@
                     next;
                 }
                 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
-                $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
+                if(my $Dir = get_dirname($LPaths->{$Name})) {
+                    $Dirs{$Dir} = 1;
+                }
             }
+            push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs));
         }
-        foreach my $Path (keys(%DefaultLibPaths)) {
-            $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
-        }
+        push_U($SystemPaths{"lib"}, @DefaultLibPaths);
     }
     if($BSearch)
     {
@@ -18341,15 +18656,15 @@
     }
     if($GSearch)
     { # GCC path and default include dirs
-        if(not $CrossGcc) {
+        if(not $CrossGcc)
+        { # try default gcc
             $GCC_PATH = get_CmdPath("gcc");
         }
         if(not $GCC_PATH)
         { # try to find gcc-X.Y
-            foreach my $Path (sort {$b=~/\/usr\/bin/ cmp $a=~/\/usr\/bin/}
-            keys(%{$SystemPaths{"bin"}}))
+            foreach my $Path (@{$SystemPaths{"bin"}})
             {
-                if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1))
+                if(my @GCCs = cmd_find($Path, "", ".*/gcc-[0-9.]*", 1, 1))
                 { # select the latest version
                     @GCCs = sort {$b cmp $a} @GCCs;
                     if(check_gcc($GCCs[0], "3"))
@@ -18379,25 +18694,26 @@
                 exitStatus("Error", "something is going wrong with the GCC compiler");
             }
         }
-        if(not $NoStdInc)
-        { # do NOT search in GCC standard paths
-            my %DPaths = detect_inc_default_paths();
-            %DefaultCppPaths = %{$DPaths{"Cpp"}};
-            %DefaultGccPaths = %{$DPaths{"Gcc"}};
-            %DefaultIncPaths = %{$DPaths{"Inc"}};
-            foreach my $Path (keys(%DefaultIncPaths)) {
-                $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
+        if($HSearch)
+        {
+            if(not $NoStdInc)
+            { # do NOT search in GCC standard paths
+                my %DPaths = detect_inc_default_paths();
+                @DefaultCppPaths = @{$DPaths{"Cpp"}};
+                @DefaultGccPaths = @{$DPaths{"Gcc"}};
+                @DefaultIncPaths = @{$DPaths{"Inc"}};
+                push_U($SystemPaths{"include"}, @DefaultIncPaths);
             }
         }
     }
     if($HSearch)
-    { # user include paths
+    { # users include paths
         my $IncPath = "/usr/include";
         if($SystemRoot) {
             $IncPath = $SystemRoot.$IncPath;
         }
         if(-d $IncPath) {
-            $UserIncPath{$IncPath}=1;
+            push_U(\@UsersIncPath, $IncPath);
         }
     }
 }
@@ -18444,7 +18760,7 @@
     return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
 }
 
-sub check_command($)
+sub checkCmd($)
 {
     my $Cmd = $_[0];
     return "" if(not $Cmd);
@@ -18487,34 +18803,44 @@
     return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
 }
 
-sub find_gcc_cxx_headers($)
+sub registerGccHeaders()
 {
-    my $LibVersion = $_[0];
-    return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
-    # detecting system header paths
-    foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
+    return if($Cache{"registerGccHeaders"}); # this function should be called once
+    
+    foreach my $Path (@DefaultGccPaths)
     {
-        foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
+        my @Headers = cmd_find($Path,"f");
+        @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
+        foreach my $HPath (@Headers)
         {
-            my $FileName = get_filename($HeaderPath);
-            next if($DefaultGccHeader{$FileName});
-            $DefaultGccHeader{$FileName} = $HeaderPath;
+            my $FileName = get_filename($HPath);
+            if(not defined $DefaultGccHeader{$FileName})
+            { # skip duplicated
+                $DefaultGccHeader{$FileName} = $HPath;
+            }
         }
     }
-    if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
+    $Cache{"registerGccHeaders"} = 1;
+}
+
+sub registerCppHeaders()
+{
+    return if($Cache{"registerCppHeaders"}); # this function should be called once
+    
+    foreach my $CppDir (@DefaultCppPaths)
     {
-        foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
+        my @Headers = cmd_find($CppDir,"f");
+        @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers;
+        foreach my $Path (@Headers)
         {
-            my @AllCppHeaders = cmd_find($CppDir,"f","","");
-            foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
-            {
-                my $FileName = get_filename($Path);
-                next if($DefaultCppHeader{$FileName});
+            my $FileName = get_filename($Path);
+            if(not defined $DefaultCppHeader{$FileName})
+            { # skip duplicated
                 $DefaultCppHeader{$FileName} = $Path;
             }
         }
     }
-    $Cache{"find_gcc_cxx_headers"} = 1;
+    $Cache{"registerCppHeaders"} = 1;
 }
 
 sub parse_libname($$$)
@@ -18751,16 +19077,6 @@
     writeFile($SaveTo, $SYMBOLS_LIST);
 }
 
-sub readModule($$)
-{
-    my ($Module, $Name) = @_;
-    my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
-    if(not -f $Path) {
-        exitStatus("Module_Error", "can't access \'$Path\'");
-    }
-    return readFile($Path);
-}
-
 sub add_target_libs($)
 {
     foreach (@{$_[0]}) {
@@ -18827,10 +19143,10 @@
         {
             $TargetVersion{$LibVersion} = $VerNum;
             if($DumpAPI) {
-                printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
+                printMsg("WARNING", "setting version number to $VerNum (use -vnum option to change it)");
             }
             else {
-                printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
+                printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion option to change it)");
             }
             return $TargetVersion{$LibVersion};
         }
@@ -18838,10 +19154,10 @@
     if($UsedAltDescr)
     {
         if($DumpAPI) {
-            exitStatus("Error", "version number is not set (use -vnum <num> option)");
+            exitStatus("Error", "version number is not set (use -vnum option)");
         }
         else {
-            exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
+            exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion option)");
         }
     }
 }
@@ -19233,6 +19549,29 @@
     { # headers info stored without paths in the dump
         $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
     }
+    if($ExtraDump)
+    { # add unmangled names to the ABI dump
+        my @Names = ();
+        foreach my $InfoId (keys(%{$SymbolInfo{1}}))
+        {
+            if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) {
+                push(@Names, $MnglName);
+            }
+        }
+        translateSymbols(@Names, 1);
+        foreach my $InfoId (keys(%{$SymbolInfo{1}}))
+        {
+            if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"})
+            {
+                if(my $Unmangled = $tr_name{$MnglName})
+                {
+                    if($MnglName ne $Unmangled) {
+                        $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled;
+                    }
+                }
+            }
+        }
+    }
     printMsg("INFO", "creating library ABI dump ...");
     my %ABI = (
         "TypeInfo" => $TypeInfo{1},
@@ -20042,11 +20381,16 @@
             unlink($COMMON_LOG_PATH);
         }
     }
+    if($ExtraInfo)
+    {
+        $CheckUndefined = 1;
+    }
     if($TestTool and $UseDumps)
     { # --test && --use-dumps == --test-dump
         $TestDump = 1;
     }
-    if($Help) {
+    if($Help)
+    {
         HELP_MESSAGE();
         exit(0);
     }
@@ -20054,11 +20398,13 @@
         INFO_MESSAGE();
         exit(0);
     }
-    if($ShowVersion) {
+    if($ShowVersion)
+    {
         printMsg("INFO", "ABI Compliance Checker (ACC) $TOOL_VERSION\nCopyright (C) 2012 ROSA 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) {
+    if($DumpVersion)
+    {
         printMsg("INFO", $TOOL_VERSION);
         exit(0);
     }
@@ -20129,8 +20475,8 @@
             my $Ret = readSystemDescriptor(readFile($DumpSystem));
             foreach (@{$Ret->{"Tools"}})
             {
-                $SystemPaths{"bin"}{$_} = 1;
-                $TargetTools{$_}=1;
+                push_U($SystemPaths{"bin"}, $_);
+                $TargetTools{$_} = 1;
             }
             if($Ret->{"CrossPrefix"}) {
                 $CrossPrefix = $Ret->{"CrossPrefix"};
@@ -20182,12 +20528,14 @@
         cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts());
         exit(0);
     }
-    if($GenerateTemplate) {
-        generateTemplate();
+    if($GenerateTemplate)
+    {
+        writeFile("VERSION.xml", $DescriptorTemplate."\n");
+        printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
         exit(0);
     }
     if(not $TargetLibraryName) {
-        exitStatus("Error", "library name is not selected (option -l <name>)");
+        exitStatus("Error", "library name is not selected (-l option)");
     }
     else
     { # validate library name