1########################################################################### 2# Module for ABI Compliance Checker to compare Operating Systems 3# 4# Copyright (C) 2009-2011 Institute for System Programming, RAS 5# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) 6# Copyright (C) 2011-2012 ROSA Laboratory 7# Copyright (C) 2012-2016 Andrey Ponomarenko's ABI Laboratory 8# 9# Written by Andrey Ponomarenko 10# 11# This program is free software: you can redistribute it and/or modify 12# it under the terms of the GNU General Public License or the GNU Lesser 13# General Public License as published by the Free Software Foundation. 14# 15# This program is distributed in the hope that it will be useful, 16# but WITHOUT ANY WARRANTY; without even the implied warranty of 17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18# GNU General Public License for more details. 19# 20# You should have received a copy of the GNU General Public License 21# and the GNU Lesser General Public License along with this program. 22# If not, see <http://www.gnu.org/licenses/>. 23########################################################################### 24use strict; 25use File::Temp qw(tempdir); 26use Cwd qw(abs_path cwd); 27use Fcntl; 28 29my ($Debug, $Quiet, $LogMode, $CheckHeadersOnly, $SystemRoot, $GCC_PATH, 30$CrossPrefix, $TargetSysInfo, $TargetLibraryName, $CrossGcc, $UseStaticLibs, 31$NoStdInc, $CxxIncompat, $SkipUnidentified, $OStarget, $BinaryOnly, 32$SourceOnly, $DisableConstantsCheck); 33 34my $OSgroup = get_OSgroup(); 35my $TMP_DIR = tempdir(CLEANUP=>1); 36my $ORIG_DIR = cwd(); 37my $LIB_EXT = getLIB_EXT($OSgroup); 38 39my %SysDescriptor; 40my %Cache; 41my %NonPrefix; 42 43sub cmpSystems($$$) 44{ # -cmp-systems option handler 45 # should be used with -d1 and -d2 options 46 my ($SPath1, $SPath2, $Opts) = @_; 47 initModule($Opts); 48 if(not $SPath1) { 49 exitStatus("Error", "the option -d1 should be specified"); 50 } 51 elsif(not -d $SPath1) { 52 exitStatus("Access_Error", "can't access directory \'".$SPath1."\'"); 53 } 54 elsif(not -d $SPath1."/abi_dumps") { 55 exitStatus("Access_Error", "can't access directory \'".$SPath1."/abi_dumps\'"); 56 } 57 if(not $SPath2) { 58 exitStatus("Error", "the option -d2 should be specified"); 59 } 60 elsif(not -d $SPath2) { 61 exitStatus("Access_Error", "can't access directory \'".$SPath2."\'"); 62 } 63 elsif(not -d $SPath2."/abi_dumps") { 64 exitStatus("Access_Error", "can't access directory \'".$SPath2."/abi_dumps\'"); 65 } 66 # sys_dumps/<System>/<Arch>/... 67 my $SystemName1 = get_filename(get_dirname($SPath1)); 68 my $SystemName2 = get_filename(get_dirname($SPath2)); 69 70 my $SystemName1_P = $SystemName1; 71 my $SystemName2_P = $SystemName2; 72 73 $SystemName1=~s/_/ /g; 74 $SystemName2=~s/_/ /g; 75 76 # sys_dumps/<System>/<Arch>/... 77 my $ArchName = get_filename($SPath1); 78 if($ArchName ne get_filename($SPath2)) { 79 exitStatus("Error", "can't compare systems of different CPU architecture"); 80 } 81 if(my $OStarget_Dump = readFile($SPath1."/target.txt")) 82 { # change target 83 $OStarget = $OStarget_Dump; 84 $LIB_EXT = getLIB_EXT($OStarget); 85 } 86 my $GroupByHeaders = 0; 87 if(my $Mode = readFile($SPath1."/mode.txt")) 88 { # change mode 89 if($Mode eq "headers-only") 90 { # -headers-only mode 91 $CheckHeadersOnly = 1; 92 $GroupByHeaders = 1; 93 } 94 if($Mode eq "group-by-headers") { 95 $GroupByHeaders = 1; 96 } 97 } 98 my $SYS_REPORT_PATH = "sys_compat_reports/".$SystemName1_P."_to_".$SystemName2_P."/$ArchName"; 99 rmtree($SYS_REPORT_PATH); 100 my (%LibSoname1, %LibSoname2) = (); 101 foreach (split(/\n/, readFile($SPath1."/sonames.txt"))) 102 { 103 if(my ($LFName, $Soname) = split(/;/, $_)) 104 { 105 if($OStarget eq "symbian") { 106 $Soname=~s/\{.+\}//; 107 } 108 $LibSoname1{$LFName} = $Soname; 109 } 110 } 111 foreach (split(/\n/, readFile($SPath2."/sonames.txt"))) 112 { 113 if(my ($LFName, $Soname) = split(/;/, $_)) 114 { 115 if($OStarget eq "symbian") { 116 $Soname=~s/\{.+\}//; 117 } 118 $LibSoname2{$LFName} = $Soname; 119 } 120 } 121 my (%LibV1, %LibV2) = (); 122 foreach (split(/\n/, readFile($SPath1."/versions.txt"))) 123 { 124 if(my ($LFName, $V) = split(/;/, $_)) { 125 $LibV1{$LFName} = $V; 126 } 127 } 128 foreach (split(/\n/, readFile($SPath2."/versions.txt"))) 129 { 130 if(my ($LFName, $V) = split(/;/, $_)) { 131 $LibV2{$LFName} = $V; 132 } 133 } 134 my @Dumps1 = cmd_find($SPath1."/abi_dumps","f","*.abi",1); 135 my @Dumps2 = cmd_find($SPath2."/abi_dumps","f","*.abi",1); 136 137 my (%LibVers1, %LibVers2) = (); 138 my (%ShortNames1, %ShortNames2) = (); 139 foreach my $DPath (@Dumps1) 140 { 141 if(my $Name = isDump($DPath)) 142 { 143 my ($Soname, $V) = ($LibSoname1{$Name}, $LibV1{$Name}); 144 if(not $V) { 145 $V = parse_libname($Name, "version", $OStarget); 146 } 147 if($GroupByHeaders) { 148 $Soname = $Name; 149 } 150 $LibVers1{$Soname}{$V} = $DPath; 151 $ShortNames1{parse_libname($Soname, "short", $OStarget)}{$Soname} = 1; 152 } 153 } 154 foreach my $DPath (@Dumps2) 155 { 156 if(my $Name = isDump($DPath)) 157 { 158 my ($Soname, $V) = ($LibSoname2{$Name}, $LibV2{$Name}); 159 if(not $V) { 160 $V = parse_libname($Name, "version", $OStarget); 161 } 162 if($GroupByHeaders) { 163 $Soname = $Name; 164 } 165 $LibVers2{$Soname}{$V} = $DPath; 166 $ShortNames2{parse_libname($Soname, "short", $OStarget)}{$Soname} = 1; 167 } 168 } 169 my (%Added, %Removed) = (); 170 my (%ChangedSoname, %TestResults) = (); 171 my (%AddedShort, %RemovedShort) = (); 172 if(not $GroupByHeaders) 173 { 174 my %ChangedSoname_Safe = (); 175 foreach my $LName (sort keys(%LibSoname2)) 176 { # libcurl.so.3 -> libcurl.so.4 (search for SONAME by the file name) 177 # OS #1 => OS #2 178 if(defined $LibVers2{$LName}) 179 { # already registered 180 next; 181 } 182 my $Soname = $LibSoname2{$LName}; 183 if(defined $LibVers2{$Soname} 184 and defined $LibVers1{$LName}) 185 { 186 $LibVers2{$LName} = $LibVers2{$Soname}; 187 $ChangedSoname_Safe{$Soname}=$LName; 188 } 189 } 190 foreach my $LName (sort keys(%LibSoname1)) 191 { # libcurl.so.3 -> libcurl.so.4 (search for SONAME by the file name) 192 # OS #1 <= OS #2 193 if(defined $LibVers1{$LName}) 194 { # already registered 195 next; 196 } 197 my $Soname = $LibSoname1{$LName}; 198 if(defined $LibVers1{$Soname} 199 and defined $LibVers2{$LName}) { 200 $LibVers1{$LName} = $LibVers1{$Soname}; 201 } 202 } 203 if(not $GroupByHeaders) { 204 printMsg("INFO", "Checking added/removed libs"); 205 } 206 foreach my $LName (sort {lc($a) cmp lc($b)} keys(%LibVers1)) 207 { # removed libs 208 if(not is_target_lib($LName)) { 209 next; 210 } 211 if(not defined $LibVers1{$LName}) { 212 next; 213 } 214 my @Versions1 = keys(%{$LibVers1{$LName}}); 215 if($#Versions1>=1) 216 { # should be only one version 217 next; 218 } 219 if(not defined $LibVers2{$LName} 220 or not keys(%{$LibVers2{$LName}})) 221 { # removed library 222 if(not $LibSoname2{$LName}) 223 { 224 my $LSName = parse_libname($LName, "short", $OStarget); 225 $RemovedShort{$LSName}{$LName} = 1; 226 my $V = $Versions1[0]; 227 $Removed{$LName}{"version"} = $V; 228 229 my $ListPath = "info/$LName/symbols.html"; 230 my $FV = $SystemName1; 231 if($V) { 232 $FV = $V."-".$FV; 233 } 234 createSymbolsList($LibVers1{$LName}{$V}, 235 $SYS_REPORT_PATH."/".$ListPath, $LName, $FV, $ArchName); 236 $Removed{$LName}{"list"} = $ListPath; 237 } 238 } 239 } 240 foreach my $LName (sort {lc($a) cmp lc($b)} keys(%LibVers2)) 241 { # added libs 242 if(not is_target_lib($LName)) { 243 next; 244 } 245 if(not defined $LibVers2{$LName}) { 246 next; 247 } 248 my @Versions2 = keys(%{$LibVers2{$LName}}); 249 if($#Versions2>=1) 250 { # should be only one version 251 next; 252 } 253 if($ChangedSoname_Safe{$LName}) 254 { # changed soname but added the symbolic link for old-version library 255 next; 256 } 257 if(not defined $LibVers1{$LName} 258 or not keys(%{$LibVers1{$LName}})) 259 { # added library 260 if(not $LibSoname1{$LName}) 261 { 262 my $LSName = parse_libname($LName, "short", $OStarget); 263 $AddedShort{$LSName}{$LName} = 1; 264 my $V = $Versions2[0]; 265 $Added{$LName}{"version"} = $V; 266 267 my $ListPath = "info/$LName/symbols.html"; 268 my $FV = $SystemName2; 269 if($V) { 270 $FV = $V."-".$FV; 271 } 272 createSymbolsList($LibVers2{$LName}{$V}, 273 $SYS_REPORT_PATH."/".$ListPath, $LName, $FV, $ArchName); 274 $Added{$LName}{"list"} = $ListPath; 275 } 276 } 277 } 278 foreach my $LSName (keys(%AddedShort)) 279 { # changed SONAME 280 my @AddedSonames = sort keys(%{$AddedShort{$LSName}}); 281 next if($#AddedSonames!=0); 282 283 if(defined $RemovedShort{$LSName}) 284 { # removed old soname 285 my @RemovedSonames = sort keys(%{$RemovedShort{$LSName}}); 286 $ChangedSoname{$AddedSonames[0]} = $RemovedSonames[0]; 287 $ChangedSoname{$RemovedSonames[0]} = $AddedSonames[0]; 288 } 289 elsif(defined $ShortNames1{$LSName}) 290 { # saved old soname 291 my @Sonames = sort keys(%{$ShortNames1{$LSName}}); 292 $ChangedSoname{$AddedSonames[0]} = $Sonames[0]; 293 $ChangedSoname{$Sonames[0]} = $AddedSonames[0]; 294 } 295 } 296 } 297 298 my %SONAME_Changed = (); 299 my %SONAME_Added = (); 300 301 foreach my $LName (sort {lc($a) cmp lc($b)} keys(%LibVers1)) 302 { 303 if(not is_target_lib($LName)) { 304 next; 305 } 306 my @Versions1 = keys(%{$LibVers1{$LName}}); 307 if(not @Versions1 or $#Versions1>=1) 308 { # should be only one version 309 next; 310 } 311 my $LV1 = $Versions1[0]; 312 my $DPath1 = $LibVers1{$LName}{$LV1}; 313 my @Versions2 = keys(%{$LibVers2{$LName}}); 314 if($#Versions2>=1) 315 { # should be only one version 316 next; 317 } 318 my ($LV2, $LName2, $DPath2) = (); 319 my $LName_Short = parse_libname($LName, "name+ext", $OStarget); 320 if($LName2 = $ChangedSoname{$LName}) 321 { # changed SONAME 322 @Versions2 = keys(%{$LibVers2{$LName2}}); 323 if(not @Versions2 or $#Versions2>=1) { 324 next; 325 } 326 $LV2 = $Versions2[0]; 327 $DPath2 = $LibVers2{$LName2}{$LV2}; 328 329 if(defined $LibVers2{$LName}) 330 { # show old soname in the table 331 $TestResults{$LName}{"v1"} = $LV1; 332 $TestResults{$LName}{"v2"} = $LV1; 333 } 334 335 if(defined $LibVers2{$LName}) 336 { # do not count results 337 $SONAME_Added{$LName_Short} = 1; 338 } 339 $SONAME_Changed{$LName_Short} = 1; 340 $LName = $LName_Short; 341 } 342 elsif(@Versions2) 343 { 344 $LV2 = $Versions2[0]; 345 $DPath2 = $LibVers2{$LName}{$LV2}; 346 } 347 else 348 { # removed 349 next; 350 } 351 my $ACC_compare = "perl $0 -l $LName -d1 \"$DPath1\" -d2 \"$DPath2\""; 352 353 my $BinReportPath = "compat_reports/$LName/abi_compat_report.html"; 354 my $SrcReportPath = "compat_reports/$LName/src_compat_report.html"; 355 my $BinReportPath_Full = $SYS_REPORT_PATH."/".$BinReportPath; 356 my $SrcReportPath_Full = $SYS_REPORT_PATH."/".$SrcReportPath; 357 358 if($BinaryOnly) 359 { 360 $ACC_compare .= " -binary"; 361 $ACC_compare .= " -bin-report-path \"$BinReportPath_Full\""; 362 } 363 if($SourceOnly) 364 { 365 $ACC_compare .= " -source"; 366 $ACC_compare .= " -src-report-path \"$SrcReportPath_Full\""; 367 } 368 369 if($CheckHeadersOnly) { 370 $ACC_compare .= " -headers-only"; 371 } 372 if($GroupByHeaders) { 373 $ACC_compare .= " -component header"; 374 } 375 376 if($DisableConstantsCheck) { 377 $ACC_compare .= " -disable-constants-check"; 378 } 379 380 $ACC_compare .= " -skip-added-constants"; 381 $ACC_compare .= " -skip-removed-constants"; 382 383 if($Quiet) 384 { # quiet mode 385 $ACC_compare .= " -quiet"; 386 } 387 if($LogMode eq "n") { 388 $ACC_compare .= " -logging-mode n"; 389 } 390 elsif($Quiet) { 391 $ACC_compare .= " -logging-mode a"; 392 } 393 if($Debug) 394 { # debug mode 395 $ACC_compare .= " -debug"; 396 printMsg("INFO", "$ACC_compare"); 397 } 398 printMsg("INFO_C", "Checking $LName: "); 399 system($ACC_compare." 1>$TMP_DIR/null 2>$TMP_DIR/$LName.stderr"); 400 if(-s "$TMP_DIR/$LName.stderr") 401 { 402 my $ErrorLog = readFile("$TMP_DIR/$LName.stderr"); 403 chomp($ErrorLog); 404 printMsg("INFO", "Failed ($ErrorLog)"); 405 } 406 else 407 { 408 printMsg("INFO", "Ok"); 409 if($BinaryOnly) 410 { 411 $TestResults{$LName}{"Binary"} = readAttributes($BinReportPath_Full, 0); 412 $TestResults{$LName}{"Binary"}{"path"} = $BinReportPath; 413 } 414 if($SourceOnly) 415 { 416 $TestResults{$LName}{"Source"} = readAttributes($SrcReportPath_Full, 0); 417 $TestResults{$LName}{"Source"}{"path"} = $SrcReportPath; 418 } 419 $TestResults{$LName}{"v1"} = $LV1; 420 $TestResults{$LName}{"v2"} = $LV2; 421 } 422 423 my $HP1 = $SPath1."/headers/".$LName; 424 my $HP2 = $SPath2."/headers/".$LName; 425 426 if(-d $HP1 427 and -d $HP2 428 and my $RfcDiff = get_CmdPath("rfcdiff")) 429 { 430 my @Headers1 = cmd_find($HP1,"f"); 431 my @Headers2 = cmd_find($HP2,"f"); 432 433 my (%Files1, %Files2) = (); 434 435 foreach my $P (@Headers1) { 436 $Files1{get_filename($P)} = $P; 437 } 438 439 foreach my $P (@Headers2) { 440 $Files2{get_filename($P)} = $P; 441 } 442 443 my $Diff = ""; 444 foreach my $N (sort {lc($a) cmp lc($b)} keys(%Files1)) 445 { 446 my $Path1 = $Files1{$N}; 447 my $Path2 = undef; 448 449 if(defined $Files2{$N}) { 450 $Path2 = $Files2{$N}; 451 } 452 else { 453 next; 454 } 455 456 if(-s $Path1 == -s $Path2) 457 { 458 if(readFile($Path1) eq readFile($Path2)) { 459 next; 460 } 461 } 462 463 my $DiffOut = $TMP_DIR."/rfcdiff"; 464 465 if(-e $DiffOut) { 466 unlink($DiffOut); 467 } 468 469 my $Cmd_R = $RfcDiff." --width 80 --stdout \"$Path1\" \"$Path2\" >$DiffOut 2>/dev/null"; 470 qx/$Cmd_R/; # execute 471 472 if(-s $DiffOut) 473 { 474 my $Content = readFile($DiffOut); 475 if(length($Content)<3500 and $Content=~/The files are identical|No changes|Failed to create/i) { 476 next; 477 } 478 479 $Content=~s/<\!--(.|\n)+?-->\s*//g; 480 $Content=~s/\A((.|\n)+<body\s*>)((.|\n)+)(<\/body>(.|\n)+)\Z/$3/; 481 $Content=~s/(<td colspan=\"5\"[^>]*>)(.+)(<\/td>)/$1$3/; 482 $Content=~s/(<table) /$1 class='diff_tbl' /g; 483 484 $Content=~s&<td class="lineno" valign="top"></td>&&g; 485 $Content=~s&<td class="lineno"></td>&&g; 486 $Content=~s&<th></th>&&g; 487 $Content=~s&<td></td>&&g; 488 489 $Content=~s/(\Q$N\E)( )/$1 ($LV1-$SystemName1)$2/; 490 $Content=~s/(\Q$N\E)( )/$1 ($LV2-$SystemName2)$2/; 491 492 if($Diff) { 493 $Diff .= "<br/><br/>\n"; 494 } 495 $Diff .= $Content; 496 } 497 } 498 499 if($Diff) 500 { 501 my $Title = $LName.": headers diff between $LV1-$SystemName1 and $LV2-$SystemName2 versions"; 502 my $Keywords = $LName.", header, diff"; 503 my $Description = "Diff for header files between $LV1-$SystemName1 and $LV2-$SystemName2 versions of $LName"; 504 my $Styles = readModule("Styles", "HeadersDiff.css"); 505 506 my $Link = "This html diff was produced by <a href='http://tools.ietf.org/tools/rfcdiff/'>rfcdiff</a> 1.41."; 507 508 $Diff .= "<br/>"; 509 $Diff .= "<div style='width:100%;' align='left'>$Link</div>\n"; 510 511 $Diff = "<h1>Headers diff for <span style='color:Blue;'>$LName</span> between <span style='color:Red;'>$LV1-$SystemName1</span> and <span style='color:Red;'>$LV2-$SystemName2</span> versions</h1><br/><br/>".$Diff; 512 513 $Diff = "<table width='100%' cellpadding='0' cellspacing='0'><tr><td>$Diff</td></tr></table>"; 514 515 $Diff = composeHTML_Head($Title, $Keywords, $Description, $Styles, "")."\n<body>\n$Diff\n</body>\n</html>\n"; 516 517 my $Output = $SYS_REPORT_PATH."/headers_diff/$LName"; 518 writeFile($Output."/diff.html", $Diff); 519 } 520 } 521 } 522 523 my %TOTAL = (); 524 foreach my $LName (keys(%TestResults)) 525 { 526 if($SONAME_Changed{$LName}) { 527 next; 528 } 529 foreach my $Comp ("Binary", "Source") 530 { 531 if(not defined $TestResults{$LName}{$Comp}) { 532 next; 533 } 534 foreach my $Kind (keys(%{$TestResults{$LName}{$Comp}})) 535 { 536 if($Kind=~/_problems_(high|medium|low)/) { 537 $TOTAL{$LName}{$Comp} += $TestResults{$LName}{$Comp}{$Kind}; 538 } 539 } 540 } 541 } 542 543 my %META_DATA = (); 544 my %STAT = (); 545 foreach my $Comp ("Binary", "Source") 546 { 547 $STAT{$Comp}{"total"} = keys(%TestResults) - keys(%SONAME_Changed); 548 $STAT{$Comp}{"added"} = keys(%Added); 549 $STAT{$Comp}{"removed"} = keys(%Removed); 550 551 foreach ("added", "removed") 552 { 553 my $Kind = $_."_interfaces"; 554 foreach my $LName (keys(%TestResults)) 555 { 556 next if($SONAME_Changed{$LName}); 557 $STAT{$Comp}{$Kind} += $TestResults{$LName}{$Comp}{$_}; 558 } 559 push(@{$META_DATA{$Comp}}, $Kind.":".$STAT{$Comp}{$Kind}); 560 } 561 foreach my $T ("type", "interface") 562 { 563 foreach my $S ("high", "medium", "low") 564 { 565 my $Kind = $T."_problems_".$S; 566 foreach my $LName (keys(%TestResults)) 567 { 568 next if($SONAME_Changed{$LName}); 569 $STAT{$Comp}{$Kind} += $TestResults{$LName}{$Comp}{$Kind}; 570 } 571 push(@{$META_DATA{$Comp}}, $Kind.":".$STAT{$Comp}{$Kind}); 572 } 573 } 574 foreach my $LName (keys(%TestResults)) 575 { 576 next if($SONAME_Changed{$LName}); 577 foreach ("affected", "changed_constants") { 578 $STAT{$Comp}{$_} += $TestResults{$LName}{$Comp}{$_}; 579 } 580 if(not defined $STAT{$Comp}{"verdict"} 581 and $TestResults{$LName}{$Comp}{"verdict"} eq "incompatible") { 582 $STAT{$Comp}{"verdict"} = "incompatible"; 583 } 584 } 585 if(not defined $STAT{$Comp}{"verdict"}) { 586 $STAT{$Comp}{"verdict"} = "compatible"; 587 } 588 if($STAT{$Comp}{"total"}) { 589 $STAT{$Comp}{"affected"} /= $STAT{$Comp}{"total"}; 590 } 591 else { 592 $STAT{$Comp}{"affected"} = 0; 593 } 594 $STAT{$Comp}{"affected"} = show_number($STAT{$Comp}{"affected"}); 595 if($STAT{$Comp}{"verdict"}>1) { 596 $STAT{$Comp}{"verdict"} = 1; 597 } 598 push(@{$META_DATA{$Comp}}, "changed_constants:".$STAT{$Comp}{"changed_constants"}); 599 push(@{$META_DATA{$Comp}}, "tool_version:".get_dumpversion("perl $0")); 600 foreach ("removed", "added", "total", "affected", "verdict") { 601 @{$META_DATA{$Comp}} = ($_.":".$STAT{$Comp}{$_}, @{$META_DATA{$Comp}}); 602 } 603 } 604 605 my $SONAME_Title = "SONAME"; 606 if($OStarget eq "windows") { 607 $SONAME_Title = "DLL"; 608 } 609 elsif($OStarget eq "symbian") { 610 $SONAME_Title = "DSO"; 611 } 612 if($GroupByHeaders) 613 { # show the list of headers 614 $SONAME_Title = "Header File"; 615 } 616 617 my $SYS_REPORT = "<h1>"; 618 619 if($BinaryOnly and $SourceOnly) { 620 $SYS_REPORT .= "API compatibility"; 621 } 622 elsif($BinaryOnly) { 623 $SYS_REPORT .= "Binary compatibility"; 624 } 625 elsif($SourceOnly) { 626 $SYS_REPORT .= "Source compatibility"; 627 } 628 629 $SYS_REPORT .= " report between <span style='color:Blue;'>$SystemName1</span> and <span style='color:Blue;'>$SystemName2</span>"; 630 $SYS_REPORT .= " on <span style='color:Blue;'>".showArch($ArchName)."</span>\n"; 631 632 $SYS_REPORT .= "</h1>"; 633 $SYS_REPORT .= "<br/>\n"; 634 635 # legend 636 my $LEGEND = "<table class='legend'><tr>\n"; 637 $LEGEND .= "<td class='new' width='70px' style='text-align:left'>ADDED</td>\n"; 638 $LEGEND .= "<td class='passed' width='70px' style='text-align:left'>COMPATIBLE</td>\n"; 639 $LEGEND .= "</tr><tr>\n"; 640 $LEGEND .= "<td class='warning' style='text-align:left'>WARNING</td>\n"; 641 $LEGEND .= "<td class='failed' style='text-align:left'>INCOMPATIBLE</td>\n"; 642 $LEGEND .= "</tr></table>\n"; 643 644 $SYS_REPORT .= $LEGEND; 645 $SYS_REPORT .= "<br/>\n"; 646 647 my $Columns = 2; 648 649 my $Total = (keys(%TestResults) + keys(%Added) + keys(%Removed) - keys(%SONAME_Changed)); 650 my $HDiff = $SYS_REPORT_PATH."/headers_diff"; 651 652 $SYS_REPORT .= "<table class='summary'>\n"; 653 $SYS_REPORT .= "<tr>\n"; 654 $SYS_REPORT .= "<th rowspan='2'>$SONAME_Title<sup>$Total</sup></th>\n"; 655 if(not $GroupByHeaders) { 656 $SYS_REPORT .= "<th colspan='2'>Version</th>\n"; 657 } 658 if($BinaryOnly and $SourceOnly) { 659 $SYS_REPORT .= "<th colspan='2'>Compatibility</th>\n"; 660 } 661 else { 662 $SYS_REPORT .= "<th rowspan='2'>Compatibility</th>\n"; 663 } 664 $SYS_REPORT .= "<th rowspan='2'>Added<br/>Symbols</th>\n"; 665 $SYS_REPORT .= "<th rowspan='2'>Removed<br/>Symbols</th>\n"; 666 if(-d $HDiff) 667 { 668 $SYS_REPORT .= "<th rowspan='2'>Headers<br/>Diff</th>\n"; 669 $Columns += 1; 670 } 671 $SYS_REPORT .= "</tr>\n"; 672 673 $SYS_REPORT .= "<tr>\n"; 674 if(not $GroupByHeaders) { 675 $SYS_REPORT .= "<th class='ver'>$SystemName1</th><th class='ver'>$SystemName2</th>\n"; 676 } 677 if($BinaryOnly and $SourceOnly) { 678 $SYS_REPORT .= "<th>Binary</th><th>Source</th>\n"; 679 } 680 $SYS_REPORT .= "</tr>\n"; 681 my %RegisteredPairs = (); 682 683 foreach my $LName (sort {lc($a) cmp lc($b)} (keys(%TestResults), keys(%Added), keys(%Removed))) 684 { 685 next if($SONAME_Changed{$LName}); 686 my $LName_Short = parse_libname($LName, "name+ext", $OStarget); 687 my $Anchor = $LName; 688 $Anchor=~s/\+/p/g; # anchor for libFLAC++ is libFLACpp 689 $Anchor=~s/\~/-/g; # libqttracker.so.1~6 690 691 $SYS_REPORT .= "<tr>\n"; 692 $SYS_REPORT .= "<td class='object'>$LName<a name=\'$Anchor\'></a></td>\n"; 693 if(defined $Removed{$LName}) { 694 $SYS_REPORT .= "<td class='failed ver'>".printVer($Removed{$LName}{"version"})."</td>\n"; 695 } 696 elsif(defined $Added{$LName}) { 697 $SYS_REPORT .= "<td class='new'><a href='".$Added{$LName}{"list"}."'>added</a></td>\n"; 698 } 699 elsif(not $GroupByHeaders) 700 { 701 $SYS_REPORT .= "<td class='ver'>".printVer($TestResults{$LName}{"v1"})."</td>\n"; 702 } 703 my $SONAME_report = "<td colspan=\'$Columns\' rowspan='2'>\n"; 704 if($BinaryOnly and $SourceOnly) { 705 $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"; 706 } 707 elsif($BinaryOnly) { 708 $SONAME_report .= "SONAME has been <a href='".$TestResults{$LName_Short}{"Binary"}{"path"}."'>changed</a>\n"; 709 } 710 elsif($SourceOnly) { 711 $SONAME_report .= "SONAME has been <a href='".$TestResults{$LName_Short}{"Source"}{"path"}."'>changed</a>\n"; 712 } 713 $SONAME_report .= "</td>\n"; 714 715 if(defined $Added{$LName}) 716 { # added library 717 $SYS_REPORT .= "<td class='new ver'>".printVer($Added{$LName}{"version"})."</td>\n"; 718 $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($BinaryOnly); 719 $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($SourceOnly); 720 if($RegisteredPairs{$LName}) { 721 # do nothing 722 } 723 elsif(my $To = $ChangedSoname{$LName}) 724 { 725 $RegisteredPairs{$To}=1; 726 $SYS_REPORT .= $SONAME_report; 727 } 728 else 729 { 730 foreach (1 .. $Columns) { 731 $SYS_REPORT .= "<td>N/A</td>\n"; # colspan='5' 732 } 733 } 734 $SYS_REPORT .= "</tr>\n"; 735 next; 736 } 737 elsif(defined $Removed{$LName}) 738 { # removed library 739 $SYS_REPORT .= "<td class='failed'><a href='".$Removed{$LName}{"list"}."'>removed</a></td>\n"; 740 $SYS_REPORT .= "<td class='failed'>0%</td>\n" if($BinaryOnly); 741 $SYS_REPORT .= "<td class='failed'>0%</td>\n" if($SourceOnly); 742 if($RegisteredPairs{$LName}) { 743 # do nothing 744 } 745 elsif(my $To = $ChangedSoname{$LName}) 746 { 747 $RegisteredPairs{$To}=1; 748 $SYS_REPORT .= $SONAME_report; 749 } 750 else 751 { 752 foreach (1 .. $Columns) { 753 $SYS_REPORT .= "<td>N/A</td>\n"; # colspan='5' 754 } 755 } 756 $SYS_REPORT .= "</tr>\n"; 757 next; 758 } 759 elsif(defined $ChangedSoname{$LName}) 760 { # added library 761 $SYS_REPORT .= "<td class='ver'>".printVer($TestResults{$LName}{"v2"})."</td>\n"; 762 $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($BinaryOnly); 763 $SYS_REPORT .= "<td class='passed'>100%</td>\n" if($SourceOnly); 764 if($RegisteredPairs{$LName}) { 765 # do nothing 766 } 767 elsif(my $To = $ChangedSoname{$LName}) 768 { 769 $RegisteredPairs{$To}=1; 770 $SYS_REPORT .= $SONAME_report; 771 } 772 else 773 { 774 foreach (1 .. $Columns) { 775 $SYS_REPORT .= "<td>N/A</td>\n"; # colspan='5' 776 } 777 } 778 $SYS_REPORT .= "</tr>\n"; 779 next; 780 } 781 elsif(not $GroupByHeaders) 782 { 783 $SYS_REPORT .= "<td class='ver'>".printVer($TestResults{$LName}{"v2"})."</td>\n"; 784 } 785 786 my $BinCompatReport = $TestResults{$LName}{"Binary"}{"path"}; 787 my $SrcCompatReport = $TestResults{$LName}{"Source"}{"path"}; 788 789 if($BinaryOnly) 790 { 791 if($TestResults{$LName}{"Binary"}{"verdict"} eq "compatible") 792 { 793 my $Cl = "passed"; 794 if($TOTAL{$LName}{"Binary"}) { 795 $Cl = "warning"; 796 } 797 $SYS_REPORT .= "<td class=\'$Cl\'><a href=\'$BinCompatReport\'>100%</a></td>\n"; 798 } 799 else 800 { 801 my $Compatible = 100 - $TestResults{$LName}{"Binary"}{"affected"}; 802 my $Cl = "incompatible"; 803 if($Compatible>=90) { 804 $Cl = "warning"; 805 } 806 elsif($Compatible>=80) { 807 $Cl = "almost_compatible"; 808 } 809 $SYS_REPORT .= "<td class=\'$Cl\'><a href=\'$BinCompatReport\'>$Compatible%</a></td>\n"; 810 } 811 } 812 if($SourceOnly) 813 { 814 if($TestResults{$LName}{"Source"}{"verdict"} eq "compatible") 815 { 816 my $Cl = "passed"; 817 if($TOTAL{$LName}{"Source"}) { 818 $Cl = "warning"; 819 } 820 $SYS_REPORT .= "<td class=\'$Cl\'><a href=\'$SrcCompatReport\'>100%</a></td>\n"; 821 } 822 else 823 { 824 my $Compatible = 100 - $TestResults{$LName}{"Source"}{"affected"}; 825 my $Cl = "incompatible"; 826 if($Compatible>=90) { 827 $Cl = "warning"; 828 } 829 elsif($Compatible>=80) { 830 $Cl = "almost_compatible"; 831 } 832 $SYS_REPORT .= "<td class=\'$Cl\'><a href=\'$SrcCompatReport\'>$Compatible%</a></td>\n"; 833 } 834 } 835 if($BinaryOnly) 836 { # show added/removed symbols at binary level 837 # for joined and -binary-only reports 838 my $AddedSym=""; 839 if(my $Count = $TestResults{$LName}{"Binary"}{"added"}) { 840 $AddedSym="<a href='$BinCompatReport\#Added'>$Count new</a>"; 841 } 842 if($AddedSym) { 843 $SYS_REPORT.="<td class='new'>$AddedSym</td>\n"; 844 } 845 else { 846 $SYS_REPORT.="<td class='passed'>0</td>\n"; 847 } 848 my $RemovedSym=""; 849 if(my $Count = $TestResults{$LName}{"Binary"}{"removed"}) { 850 $RemovedSym="<a href='$BinCompatReport\#Removed'>$Count removed</a>"; 851 } 852 if($RemovedSym) { 853 $SYS_REPORT.="<td class='failed'>$RemovedSym</td>\n"; 854 } 855 else { 856 $SYS_REPORT.="<td class='passed'>0</td>\n"; 857 } 858 } 859 elsif($SourceOnly) 860 { 861 my $AddedSym=""; 862 if(my $Count = $TestResults{$LName}{"Source"}{"added"}) { 863 $AddedSym="<a href='$SrcCompatReport\#Added'>$Count new</a>"; 864 } 865 if($AddedSym) { 866 $SYS_REPORT.="<td class='new'>$AddedSym</td>\n"; 867 } 868 else { 869 $SYS_REPORT.="<td class='passed'>0</td>\n"; 870 } 871 my $RemovedSym=""; 872 if(my $Count = $TestResults{$LName}{"Source"}{"removed"}) { 873 $RemovedSym="<a href='$SrcCompatReport\#Removed'>$Count removed</a>"; 874 } 875 if($RemovedSym) { 876 $SYS_REPORT.="<td class='failed'>$RemovedSym</td>\n"; 877 } 878 else { 879 $SYS_REPORT.="<td class='passed'>0</td>\n"; 880 } 881 } 882 883 if(-d $HDiff) 884 { 885 if(-d $HDiff."/".$LName) { 886 $SYS_REPORT .= "<td><a href=\'headers_diff/$LName/diff.html\'>diff</a></td>\n"; 887 } 888 elsif(defined $Added{$LName} or defined $Removed{$LName}) { 889 $SYS_REPORT .= "<td>N/A</td>\n"; 890 } 891 else { 892 $SYS_REPORT .= "<td>Empty</td>\n"; 893 } 894 } 895 896 $SYS_REPORT .= "</tr>\n"; 897 } 898 899 $SYS_REPORT .= "</table>"; 900 901 my $Title = "$SystemName1 vs $SystemName2 compatibility report"; 902 my $Keywords = "compatibility, $SystemName1, $SystemName2, API, changes"; 903 my $Description = "API compatibility report between $SystemName1 and $SystemName2 on ".showArch($ArchName); 904 my $Styles = readModule("Styles", "CmpSystems.css"); 905 906 $SYS_REPORT = composeHTML_Head($Title, $Keywords, $Description, $Styles, "")."\n<body>\n<div>".$SYS_REPORT."</div>\n"; 907 $SYS_REPORT .= "<br/><br/>\n"; 908 $SYS_REPORT .= getReportFooter(); 909 $SYS_REPORT .= "</body></html>\n"; 910 911 if($SourceOnly) { 912 $SYS_REPORT = "<!-\- kind:source;".join(";", @{$META_DATA{"Source"}})." -\->\n".$SYS_REPORT; 913 } 914 if($BinaryOnly) { 915 $SYS_REPORT = "<!-\- kind:binary;".join(";", @{$META_DATA{"Binary"}})." -\->\n".$SYS_REPORT; 916 } 917 my $REPORT_PATH = $SYS_REPORT_PATH."/"; 918 if($BinaryOnly and $SourceOnly) { 919 $REPORT_PATH .= "compat_report.html"; 920 } 921 elsif($BinaryOnly) { 922 $REPORT_PATH .= "abi_compat_report.html"; 923 } 924 elsif($SourceOnly) { 925 $REPORT_PATH .= "src_compat_report.html"; 926 } 927 writeFile($REPORT_PATH, $SYS_REPORT); 928 printMsg("INFO", "\nSee detailed report:\n $REPORT_PATH"); 929} 930 931sub printVer($) 932{ 933 if($_[0] eq "") { 934 return 0; 935 } 936 return $_[0]; 937} 938 939sub getPrefix_S($) 940{ 941 my $Prefix = getPrefix($_[0]); 942 if(not $Prefix or defined $NonPrefix{lc($Prefix)}) { 943 return "NONE"; 944 } 945 return $Prefix; 946} 947 948sub problem_title($) 949{ 950 if($_[0]==1) { 951 return "1 change"; 952 } 953 else { 954 return $_[0]." changes"; 955 } 956} 957 958sub warning_title($) 959{ 960 if($_[0]==1) { 961 return "1 warning"; 962 } 963 else { 964 return $_[0]." warnings"; 965 } 966} 967 968sub readSystemDescriptor($) 969{ 970 my $Content = $_[0]; 971 $Content=~s/\/\*(.|\n)+?\*\///g; 972 $Content=~s/<\!--(.|\n)+?-->//g; 973 $SysDescriptor{"Name"} = parseTag(\$Content, "name"); 974 my @Tools = (); 975 if(not $SysDescriptor{"Name"}) { 976 exitStatus("Error", "system name is not specified (<name> section)"); 977 } 978 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "libs"))) 979 { # target libs 980 if(not -e $Path) { 981 exitStatus("Access_Error", "can't access \'$Path\'"); 982 } 983 $Path = get_abs_path($Path); 984 $Path=~s/[\/\\]+\Z//g; 985 $SysDescriptor{"Libs"}{$Path} = 1; 986 } 987 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) 988 { # target libs 989 if(not -d $Path) { 990 exitStatus("Access_Error", "can't access directory \'$Path\'"); 991 } 992 $Path = get_abs_path($Path); 993 $Path=~s/[\/\\]+\Z//g; 994 $SysDescriptor{"SearchLibs"}{$Path} = 1; 995 } 996 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_libs"))) 997 { # skip libs 998 $SysDescriptor{"SkipLibs"}{$Path} = 1; 999 } 1000 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "headers"))) 1001 { 1002 if(not -e $Path) { 1003 exitStatus("Access_Error", "can't access \'$Path\'"); 1004 } 1005 $Path = get_abs_path($Path); 1006 $Path=~s/[\/\\]+\Z//g; 1007 $SysDescriptor{"Headers"}{$Path} = 1; 1008 } 1009 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) 1010 { 1011 if(not -d $Path) { 1012 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1013 } 1014 $Path = get_abs_path($Path); 1015 $Path=~s/[\/\\]+\Z//g; 1016 $SysDescriptor{"SearchHeaders"}{$Path} = 1; 1017 } 1018 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) 1019 { 1020 if(not -d $Path) { 1021 exitStatus("Access_Error", "can't access directory \'$Path\'"); 1022 } 1023 $Path = get_abs_path($Path); 1024 $Path=~s/[\/\\]+\Z//g; 1025 $SysDescriptor{"Tools"}{$Path} = 1; 1026 push(@Tools, $Path); 1027 } 1028 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "gcc_options"))) 1029 { 1030 $Path=~s/[\/\\]+\Z//g; 1031 $SysDescriptor{"GccOpts"}{$Path} = 1; 1032 } 1033 if($SysDescriptor{"CrossPrefix"} = parseTag(\$Content, "cross_prefix")) 1034 { # <cross_prefix> section of XML descriptor 1035 $CrossPrefix = $SysDescriptor{"CrossPrefix"}; 1036 } 1037 elsif($CrossPrefix) 1038 { # -cross-prefix tool option 1039 $SysDescriptor{"CrossPrefix"} = $CrossPrefix; 1040 } 1041 $SysDescriptor{"Defines"} = parseTag(\$Content, "defines"); 1042 if($SysDescriptor{"Image"} = parseTag(\$Content, "image")) 1043 { # <image> 1044 # FIXME: isn't implemented yet 1045 if(not -f $SysDescriptor{"Image"}) { 1046 exitStatus("Access_Error", "can't access \'".$SysDescriptor{"Image"}."\'"); 1047 } 1048 } 1049 return {"Tools"=>\@Tools,"CrossPrefix"=>$CrossPrefix}; 1050} 1051 1052sub initModule($) 1053{ 1054 my $S = $_[0]; 1055 1056 $OStarget = $S->{"OStarget"}; 1057 $Debug = $S->{"Debug"}; 1058 $Quiet = $S->{"Quiet"}; 1059 $LogMode = $S->{"LogMode"}; 1060 $CheckHeadersOnly = $S->{"CheckHeadersOnly"}; 1061 1062 $SystemRoot = $S->{"SystemRoot"}; 1063 $GCC_PATH = $S->{"GCC_PATH"}; 1064 $TargetSysInfo = $S->{"TargetSysInfo"}; 1065 $CrossPrefix = $S->{"CrossPrefix"}; 1066 $TargetLibraryName = $S->{"TargetLibraryName"}; 1067 $CrossGcc = $S->{"CrossGcc"}; 1068 $UseStaticLibs = $S->{"UseStaticLibs"}; 1069 $NoStdInc = $S->{"NoStdInc"}; 1070 $CxxIncompat = $S->{"CxxIncompat"}; 1071 $SkipUnidentified = $S->{"SkipUnidentified"}; 1072 $DisableConstantsCheck = $S->{"DisableConstantsCheck"}; 1073 1074 $BinaryOnly = $S->{"BinaryOnly"}; 1075 $SourceOnly = $S->{"SourceOnly"}; 1076 1077 if(not $BinaryOnly and not $SourceOnly) 1078 { # default 1079 $BinaryOnly = 1; 1080 } 1081} 1082 1083sub check_list($$) 1084{ 1085 my ($Item, $Skip) = @_; 1086 return 0 if(not $Skip); 1087 foreach (@{$Skip}) 1088 { 1089 my $Pattern = $_; 1090 if(index($Pattern, "*")!=-1) 1091 { # wildcards 1092 $Pattern=~s/\*/.*/g; # to perl format 1093 if($Item=~/$Pattern/) { 1094 return 1; 1095 } 1096 } 1097 elsif(index($Pattern, "/")!=-1 1098 or index($Pattern, "\\")!=-1) 1099 { # directory 1100 if(index($Item, $Pattern)!=-1) { 1101 return 1; 1102 } 1103 } 1104 elsif($Item eq $Pattern 1105 or get_filename($Item) eq $Pattern) 1106 { # by name 1107 return 1; 1108 } 1109 } 1110 return 0; 1111} 1112 1113sub filter_format($) 1114{ 1115 my $FiltRef = $_[0]; 1116 foreach my $Entry (keys(%{$FiltRef})) 1117 { 1118 foreach my $Filt (@{$FiltRef->{$Entry}}) 1119 { 1120 if($Filt=~/[\/\\]/) { 1121 $Filt = path_format($Filt, $OSgroup); 1122 } 1123 } 1124 } 1125} 1126 1127sub readSysDescriptor($) 1128{ 1129 my $Path = $_[0]; 1130 my $Content = readFile($Path); 1131 my %Tags = ( 1132 "headers" => "mf", 1133 "skip_headers" => "mf", 1134 "skip_including" => "mf", 1135 "skip_include_paths" => "mf", 1136 "skip_libs" => "mf", 1137 "include_preamble" => "mf", 1138 "add_include_paths" => "mf", 1139 "gcc_options" => "m", 1140 "skip_symbols" => "m", 1141 "skip_types" => "m", 1142 "ignore_symbols" => "h", 1143 "non_prefix" => "h", 1144 "defines" => "s", 1145 "cxx_incompatible" => "s" 1146 ); 1147 my %DInfo = (); 1148 foreach my $Tag (keys(%Tags)) 1149 { 1150 if(my $TContent = parseTag(\$Content, $Tag)) 1151 { 1152 if($Tags{$Tag}=~/m/) 1153 { # multi-line (+order) 1154 my @Items = split(/\s*\n\s*/, $TContent); 1155 $DInfo{$Tag} = []; 1156 foreach my $Item (@Items) 1157 { 1158 if($Tags{$Tag}=~/f/) { 1159 $Item = path_format($Item, $OSgroup); 1160 } 1161 push(@{$DInfo{$Tag}}, $Item); 1162 } 1163 1164 } 1165 elsif($Tags{$Tag}=~/s/) 1166 { # single element 1167 $DInfo{$Tag} = $TContent; 1168 } 1169 else 1170 { # hash array 1171 my @Items = split(/\s*\n\s*/, $TContent); 1172 foreach my $Item (@Items) { 1173 $DInfo{$Tag}{$Item}=1; 1174 } 1175 } 1176 } 1177 } 1178 1179 if(defined $DInfo{"non_self_compiled"}) 1180 { # support for old ABI dumps 1181 $DInfo{"skip_including"} = $DInfo{"non_self_compiled"}; 1182 } 1183 1184 return \%DInfo; 1185} 1186 1187sub readSysInfo($) 1188{ 1189 my $Target = $_[0]; 1190 1191 if(not $TargetSysInfo) { 1192 exitStatus("Error", "system info path is not specified"); 1193 } 1194 if(not -d $TargetSysInfo) { 1195 exitStatus("Module_Error", "can't access \'$TargetSysInfo\'"); 1196 } 1197 # Library Specific Info 1198 my %SysInfo = (); 1199 if(-d $TargetSysInfo."/descriptors/") 1200 { 1201 foreach my $DPath (cmd_find($TargetSysInfo."/descriptors/","f","",1)) 1202 { 1203 my $LSName = get_filename($DPath); 1204 $LSName=~s/\.xml\Z//; 1205 $SysInfo{$LSName} = readSysDescriptor($DPath); 1206 } 1207 } 1208 else { 1209 printMsg("WARNING", "can't find \'$TargetSysInfo/descriptors\'"); 1210 } 1211 1212 # Exceptions 1213 if(check_gcc($GCC_PATH, "4.4")) 1214 { # exception for libstdc++ 1215 $SysInfo{"libstdc++"}{"gcc_options"} = ["-std=c++0x"]; 1216 } 1217 if($OStarget eq "symbian") 1218 { # exception for libstdcpp 1219 $SysInfo{"libstdcpp"}{"defines"} = "namespace std { struct nothrow_t {}; }"; 1220 } 1221 if($SysDescriptor{"Name"}=~/maemo/i) 1222 { # GL/gl.h: No such file 1223 $SysInfo{"libSDL"}{"skip_headers"}=["SDL_opengl.h"]; 1224 } 1225 1226 # Common Info 1227 my $SysCInfo = {}; 1228 if(-f $TargetSysInfo."/common.xml") { 1229 $SysCInfo = readSysDescriptor($TargetSysInfo."/common.xml"); 1230 } 1231 else { 1232 printMsg("Module_Error", "can't find \'$TargetSysInfo/common.xml\'"); 1233 } 1234 1235 my @CompilerOpts = (); 1236 if($SysDescriptor{"Name"}=~/maemo|meego/i) { 1237 push(@CompilerOpts, "-DMAEMO_CHANGES", "-DM_APPLICATION_NAME=\\\"app\\\""); 1238 } 1239 if(my @Opts = keys(%{$SysDescriptor{"GccOpts"}})) { 1240 push(@CompilerOpts, @Opts); 1241 } 1242 if(@CompilerOpts) 1243 { 1244 if(not $SysCInfo->{"gcc_options"}) { 1245 $SysCInfo->{"gcc_options"} = []; 1246 } 1247 push(@{$SysCInfo->{"gcc_options"}}, @CompilerOpts); 1248 } 1249 return (\%SysInfo, $SysCInfo); 1250} 1251 1252sub get_binversion($) 1253{ 1254 my $Path = $_[0]; 1255 if($OStarget eq "windows" 1256 and $LIB_EXT eq "dll") 1257 { # get version of DLL using "sigcheck" 1258 my $SigcheckCmd = get_CmdPath("sigcheck"); 1259 if(not $SigcheckCmd) { 1260 return ""; 1261 } 1262 my $VInfo = `$SigcheckCmd -nobanner -n $Path 2>$TMP_DIR/null`; 1263 $VInfo=~s/\s*\(.*\)\s*//; 1264 chomp($VInfo); 1265 1266 if($VInfo eq "n/a") { 1267 $VInfo = uc($VInfo); 1268 } 1269 1270 return $VInfo; 1271 } 1272 return ""; 1273} 1274 1275sub readBytes($) 1276{ 1277 sysopen(FILE, $_[0], O_RDONLY); 1278 sysread(FILE, my $Header, 4); 1279 close(FILE); 1280 my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header); 1281 return join("", @Bytes); 1282} 1283 1284sub dumpSystem($) 1285{ # -dump-system option handler 1286 # should be used with -sysroot and -cross-gcc options 1287 my $Opts = $_[0]; 1288 initModule($Opts); 1289 1290 my $SysName_P = $SysDescriptor{"Name"}; 1291 $SysName_P=~s/ /_/g; 1292 1293 my $SYS_DUMP_PATH = "sys_dumps/".$SysName_P."/".getArch(1); 1294 if(not $TargetLibraryName) { 1295 rmtree($SYS_DUMP_PATH); 1296 } 1297 my (@SystemLibs, @SysHeaders) = (); 1298 1299 foreach my $Path (keys(%{$SysDescriptor{"Libs"}})) 1300 { 1301 if(not -e $Path) { 1302 exitStatus("Access_Error", "can't access \'$Path\'"); 1303 } 1304 if(-d $Path) 1305 { 1306 if(my @SubLibs = find_libs($Path,"",1)) { 1307 push(@SystemLibs, @SubLibs); 1308 } 1309 $SysDescriptor{"SearchLibs"}{$Path}=1; 1310 } 1311 else 1312 { # single file 1313 push(@SystemLibs, $Path); 1314 $SysDescriptor{"SearchLibs"}{get_dirname($Path)}=1; 1315 } 1316 } 1317 foreach my $Path (keys(%{$SysDescriptor{"Headers"}})) 1318 { 1319 if(not -e $Path) { 1320 exitStatus("Access_Error", "can't access \'$Path\'"); 1321 } 1322 if(-d $Path) 1323 { 1324 if(my @SubHeaders = cmd_find($Path,"f","","")) { 1325 push(@SysHeaders, @SubHeaders); 1326 } 1327 $SysDescriptor{"SearchHeaders"}{$Path}=1; 1328 } 1329 else 1330 { # single file 1331 push(@SysHeaders, $Path); 1332 $SysDescriptor{"SearchHeaders"}{get_dirname($Path)}=1; 1333 } 1334 } 1335 my $GroupByHeaders = 0; 1336 if($CheckHeadersOnly) 1337 { # -headers-only 1338 $GroupByHeaders = 1; 1339 # @SysHeaders = optimize_set(@SysHeaders); 1340 } 1341 elsif($SysDescriptor{"Image"}) 1342 { # one big image 1343 $GroupByHeaders = 1; 1344 @SystemLibs = ($SysDescriptor{"Image"}); 1345 } 1346 writeFile($SYS_DUMP_PATH."/target.txt", $OStarget); 1347 my (%SysLib_Symbols, %SymbolGroup, %Symbol_SysHeaders, 1348 %SysHeader_Symbols, %SysLib_SysHeaders) = (); 1349 my (%Skipped, %Failed) = (); 1350 my (%SysHeaderDir_Used, %SysHeaderDir_SysHeaders) = (); 1351 my (%SymbolCounter, %TotalLibs) = (); 1352 my (%PrefixToLib, %LibPrefix, %PrefixSymbols) = (); 1353 1354 my %Glibc = map {$_=>1} ( 1355 "libc", 1356 "libpthread" 1357 ); 1358 my ($SysInfo, $SysCInfo) = readSysInfo($OStarget); 1359 1360 foreach (keys(%{$SysCInfo->{"non_prefix"}})) 1361 { 1362 $NonPrefix{$_} = 1; 1363 $NonPrefix{$_."_"} = 1; 1364 $NonPrefix{"_".$_} = 1; 1365 $NonPrefix{"_".$_."_"} = 1; 1366 } 1367 1368 if(not $GroupByHeaders) 1369 { 1370 if($Debug) { 1371 printMsg("INFO", localtime(time)); 1372 } 1373 printMsg("INFO", "Indexing sonames ...\n"); 1374 } 1375 my (%LibSoname, %SysLibVersion) = (); 1376 my %DevelPaths = map {$_=>1} @SystemLibs; 1377 foreach my $Path (sort keys(%{$SysDescriptor{"SearchLibs"}})) 1378 { 1379 foreach my $LPath (find_libs($Path,"",1)) { 1380 $DevelPaths{$LPath}=1; 1381 } 1382 } 1383 foreach my $LPath (keys(%DevelPaths)) 1384 { # register SONAMEs 1385 my $LName = get_filename($LPath); 1386 if(not is_target_lib($LName)) { 1387 next; 1388 } 1389 if($OSgroup=~/\A(linux|macos|freebsd)\Z/ 1390 and $LName!~/\Alib/) { 1391 next; 1392 } 1393 if(my $Soname = getSONAME($LPath)) 1394 { 1395 if($OStarget eq "symbian") 1396 { 1397 if($Soname=~/[\/\\]/) 1398 { # L://epoc32/release/armv5/lib/gfxtrans{000a0000}.dso 1399 $Soname = get_filename($Soname); 1400 } 1401 $Soname = lc($Soname); 1402 } 1403 if(not defined $LibSoname{$LName}) { 1404 $LibSoname{$LName}=$Soname; 1405 } 1406 if(-l $LPath and my $Path = realpath_F($LPath)) 1407 { 1408 my $Name = get_filename($Path); 1409 if(not defined $LibSoname{$Name}) { 1410 $LibSoname{$Name}=$Soname; 1411 } 1412 } 1413 } 1414 else 1415 { # windows and others 1416 $LibSoname{$LName}=$LName; 1417 } 1418 } 1419 my $SONAMES = ""; 1420 foreach (sort {lc($a) cmp lc($b)} keys(%LibSoname)) { 1421 $SONAMES .= $_.";".$LibSoname{$_}."\n"; 1422 } 1423 if(not $GroupByHeaders) { 1424 writeFile($SYS_DUMP_PATH."/sonames.txt", $SONAMES); 1425 } 1426 foreach my $LPath (sort keys(%DevelPaths)) 1427 { # register VERSIONs 1428 my $LName = get_filename($LPath); 1429 if(not is_target_lib($LName) 1430 and not is_target_lib($LibSoname{$LName})) { 1431 next; 1432 } 1433 if(my $BV = get_binversion($LPath)) 1434 { # binary version 1435 $SysLibVersion{$LName} = $BV; 1436 } 1437 elsif(my $PV = parse_libname($LName, "version", $OStarget)) 1438 { # source version 1439 $SysLibVersion{$LName} = $PV; 1440 } 1441 elsif(my $SV = parse_libname(getSONAME($LPath), "version", $OStarget)) 1442 { # soname version 1443 $SysLibVersion{$LName} = $SV; 1444 } 1445 elsif($LName=~/(\d[\d\.\-\_]*)\.$LIB_EXT\Z/) 1446 { # libfreebl3.so 1447 if($1 ne 32 and $1 ne 64) { 1448 $SysLibVersion{$LName} = $1; 1449 } 1450 } 1451 } 1452 my $VERSIONS = ""; 1453 foreach (sort {lc($a) cmp lc($b)} keys(%SysLibVersion)) { 1454 $VERSIONS .= $_.";".$SysLibVersion{$_}."\n"; 1455 } 1456 if(not $GroupByHeaders) { 1457 writeFile($SYS_DUMP_PATH."/versions.txt", $VERSIONS); 1458 } 1459 1460 # create target list 1461 my @SkipLibs = keys(%{$SysDescriptor{"SkipLibs"}}); 1462 if(my $CSkip = $SysCInfo->{"skip_libs"}) { 1463 push(@SkipLibs, @{$CSkip}); 1464 } 1465 if(@SkipLibs and not $TargetLibraryName) 1466 { 1467 my %SkipLibs = map {$_ => 1} @SkipLibs; 1468 my @Target = (); 1469 foreach my $LPath (@SystemLibs) 1470 { 1471 my $LName = get_filename($LPath); 1472 my $LName_Short = parse_libname($LName, "name+ext", $OStarget); 1473 if(not defined $SkipLibs{$LName_Short} 1474 and not defined $SkipLibs{$LName} 1475 and not check_list($LPath, \@SkipLibs)) { 1476 push(@Target, $LName); 1477 } 1478 } 1479 add_target_libs(\@Target); 1480 } 1481 1482 my %SysLibs = (); 1483 foreach my $LPath (sort @SystemLibs) 1484 { 1485 my $LName = get_filename($LPath); 1486 my $LSName = parse_libname($LName, "short", $OStarget); 1487 my $LRelPath = cut_path_prefix($LPath, $SystemRoot); 1488 if(not is_target_lib($LName)) { 1489 next; 1490 } 1491 if($OSgroup=~/\A(linux|macos|freebsd)\Z/ 1492 and $LName!~/\Alib/) { 1493 next; 1494 } 1495 if($OStarget eq "symbian") 1496 { 1497 if(my $V = parse_libname($LName, "version", $OStarget)) 1498 { # skip qtcore.dso 1499 # register qtcore{00040604}.dso 1500 delete($SysLibs{get_dirname($LPath)."\\".$LSName.".".$LIB_EXT}); 1501 my $MV = parse_libname($LibSoname{$LSName.".".$LIB_EXT}, "version", $OStarget); 1502 if($MV and $V ne $MV) 1503 { # skip other versions: 1504 # qtcore{00040700}.dso 1505 # qtcore{00040702}.dso 1506 next; 1507 } 1508 } 1509 } 1510 if(-l $LPath) 1511 { # symlinks 1512 if(my $Path = realpath_F($LPath)) { 1513 $SysLibs{$Path} = 1; 1514 } 1515 } 1516 elsif(-f $LPath) 1517 { 1518 if($Glibc{$LSName} 1519 and cmd_file($LPath)=~/ASCII/) 1520 { # GNU ld scripts (libc.so, libpthread.so) 1521 my @Candidates = cmd_find($SystemRoot."/lib","",$LSName.".".$LIB_EXT."*","1"); 1522 if(@Candidates) 1523 { 1524 my $Candidate = $Candidates[0]; 1525 if(-l $Candidate 1526 and my $Path = realpath_F($Candidate)) { 1527 $Candidate = $Path; 1528 } 1529 $SysLibs{$Candidate} = 1; 1530 } 1531 } 1532 else { 1533 $SysLibs{$LPath} = 1; 1534 } 1535 } 1536 } 1537 @SystemLibs = (); # clear memory 1538 1539 if(not keys(%SysLibs)) { 1540 exitStatus("Error", "can't find libraries"); 1541 } 1542 1543 if(not $CheckHeadersOnly) 1544 { 1545 if($Debug) { 1546 printMsg("INFO", localtime(time)); 1547 } 1548 if($SysDescriptor{"Image"}) { 1549 printMsg("INFO", "Reading symbols from image ...\n"); 1550 } 1551 else { 1552 printMsg("INFO", "Reading symbols from libraries ...\n"); 1553 } 1554 } 1555 1556 my %Syms = (); 1557 my @AllSyms = {}; 1558 my %ShortestNames = (); 1559 1560 foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) 1561 { 1562 my $LRelPath = cut_path_prefix($LPath, $SystemRoot); 1563 my $LName = get_filename($LPath); 1564 1565 $ShortestNames{$LPath} = parse_libname($LName, "shortest", $OStarget); 1566 1567 my $Res = readSymbols_Lib(1, $LPath, 0, "-Weak", 0, 0); 1568 1569 if(not keys(%{$Res}) and $TargetLibraryName) { 1570 exitStatus("Error", "can't find exported symbols in the library"); 1571 } 1572 1573 $Syms{$LPath} = $Res->{$LName}; 1574 push(@AllSyms, keys(%{$Syms{$LPath}})); 1575 } 1576 1577 my $Translate = translateSymbols(@AllSyms, 1); 1578 1579 my %DupSymbols = (); 1580 1581 foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) 1582 { 1583 my $LRelPath = cut_path_prefix($LPath, $SystemRoot); 1584 my $LName = get_filename($LPath); 1585 foreach my $Symbol (keys(%{$Syms{$LPath}})) 1586 { 1587 $Symbol=~s/[\@\$]+(.*)\Z//g; 1588 if($Symbol=~/\A(_Z|\?)/) 1589 { 1590 if(isPrivateData($Symbol)) { 1591 next; 1592 } 1593 if($Symbol=~/(C1|C2|D0|D1|D2)E/) 1594 { # do NOT analyze constructors 1595 # and destructors 1596 next; 1597 } 1598 my $Unmangled = $Translate->{$Symbol}; 1599 $Unmangled=~s/<.+>//g; 1600 if($Unmangled=~/\A([\w:]+)/) 1601 { # cut out the parameters 1602 my @Elems = split(/::/, $1); 1603 my ($Class, $Short) = ("", ""); 1604 $Short = $Elems[$#Elems]; 1605 if($#Elems>=1) 1606 { 1607 $Class = $Elems[$#Elems-1]; 1608 pop(@Elems); 1609 } 1610 # the short and class name should be 1611 # matched in one header file 1612 $SymbolGroup{$LRelPath}{$Class} = $Short; 1613 foreach my $Sym (@Elems) 1614 { 1615 if($SysCInfo->{"ignore_symbols"}{$Symbol}) 1616 { # do NOT match this symbol 1617 next; 1618 } 1619 $SysLib_Symbols{$LPath}{$Sym} = 1; 1620 if(my $Prefix = getPrefix_S($Sym)) 1621 { 1622 $PrefixToLib{$Prefix}{$LName} += 1; 1623 $LibPrefix{$LPath}{$Prefix} += 1; 1624 $PrefixSymbols{$LPath}{$Prefix}{$Sym} = 1; 1625 } 1626 $SymbolCounter{$Sym}{$LPath} = 1; 1627 1628 if(my @Libs = keys(%{$SymbolCounter{$Sym}})) 1629 { 1630 if($#Libs>=1) 1631 { 1632 foreach (@Libs) { 1633 $DupSymbols{$_}{$Sym} = 1; 1634 } 1635 } 1636 } 1637 } 1638 } 1639 } 1640 else 1641 { 1642 if($SysCInfo->{"ignore_symbols"}{$Symbol}) 1643 { # do NOT match this symbol 1644 next; 1645 } 1646 $SysLib_Symbols{$LPath}{$Symbol} = 1; 1647 if(my $Prefix = getPrefix_S($Symbol)) 1648 { 1649 $PrefixToLib{$Prefix}{$LName} += 1; 1650 $LibPrefix{$LPath}{$Prefix} += 1; 1651 $PrefixSymbols{$LPath}{$Prefix}{$Symbol} = 1; 1652 } 1653 $SymbolCounter{$Symbol}{$LPath} = 1; 1654 1655 if(my @Libs = keys(%{$SymbolCounter{$Symbol}})) 1656 { 1657 if($#Libs>=1) 1658 { 1659 foreach (@Libs) { 1660 $DupSymbols{$_}{$Symbol} = 1; 1661 } 1662 } 1663 } 1664 } 1665 } 1666 } 1667 1668 %Syms = (); 1669 %{$Translate} = (); 1670 1671 # remove minor symbols 1672 foreach my $LPath (keys(%SysLib_Symbols)) 1673 { 1674 my $SName = $ShortestNames{$LPath}; 1675 my $Count = keys(%{$SysLib_Symbols{$LPath}}); 1676 my %Prefixes = %{$LibPrefix{$LPath}}; 1677 my @Prefixes = sort {$Prefixes{$b}<=>$Prefixes{$a}} keys(%Prefixes); 1678 1679 if($#Prefixes>=1) 1680 { 1681 my $MaxPrefix = $Prefixes[0]; 1682 if($MaxPrefix eq "NONE") { 1683 $MaxPrefix = $Prefixes[1]; 1684 } 1685 my $Max = $Prefixes{$MaxPrefix}; 1686 my $None = $Prefixes{"NONE"}; 1687 1688 next if($None*100/$Count>=50); 1689 next if($None>=$Max); 1690 1691 foreach my $Prefix (@Prefixes) 1692 { 1693 next if($Prefix eq $MaxPrefix); 1694 my $Num = $Prefixes{$Prefix}; 1695 my $Rm = 0; 1696 1697 if($Prefix eq "NONE") { 1698 $Rm = 1; 1699 } 1700 else 1701 { 1702 if($Num*100/$Max<5) { 1703 $Rm = 1; 1704 } 1705 } 1706 1707 if($Rm) 1708 { 1709 next if($Prefix=~/\Q$MaxPrefix\E/i); 1710 next if($MaxPrefix=~/\Q$Prefix\E/i); 1711 next if($Prefix=~/\Q$SName\E/i); 1712 1713 foreach my $Symbol (keys(%{$PrefixSymbols{$LPath}{$Prefix}})) { 1714 delete($SysLib_Symbols{$LPath}{$Symbol}); 1715 } 1716 } 1717 } 1718 } 1719 } 1720 1721 %PrefixSymbols = (); # free memory 1722 1723 if(not $CheckHeadersOnly) { 1724 writeFile($SYS_DUMP_PATH."/debug/symbols.txt", Dumper(\%SysLib_Symbols)); 1725 } 1726 1727 my (%DupLibs, %VersionedLibs) = (); 1728 foreach my $LPath (sort keys(%DupSymbols)) 1729 { # match duplicated libs 1730 # libmenu contains all symbols from libmenuw 1731 my @Syms = keys(%{$SysLib_Symbols{$LPath}}); 1732 next if($#Syms==-1); 1733 if($#Syms+1==keys(%{$DupSymbols{$LPath}})) { 1734 $DupLibs{$LPath} = 1; 1735 } 1736 } 1737 foreach my $Prefix (keys(%PrefixToLib)) 1738 { 1739 my @Libs = keys(%{$PrefixToLib{$Prefix}}); 1740 @Libs = sort {$PrefixToLib{$Prefix}{$b}<=>$PrefixToLib{$Prefix}{$a}} @Libs; 1741 $PrefixToLib{$Prefix} = $Libs[0]; 1742 } 1743 1744 my %PackageFile = (); # to improve results 1745 my %FilePackage = (); 1746 my %LibraryFile = (); 1747 1748 if(0) 1749 { 1750 if($Debug) { 1751 printMsg("INFO", localtime(time)); 1752 } 1753 printMsg("INFO", "Reading info from packages ...\n"); 1754 if(my $Urpmf = get_CmdPath("urpmf")) 1755 { # Mandriva, ROSA 1756 my $Out = $TMP_DIR."/urpmf.out"; 1757 system("urpmf : >\"$Out\""); 1758 open(FILE, $Out); 1759 while(<FILE>) 1760 { 1761 chomp($_); 1762 if(my $M = index($_, ":")) 1763 { 1764 my $Pkg = substr($_, 0, $M); 1765 my $File = substr($_, $M+1); 1766 $PackageFile{$Pkg}{$File} = 1; 1767 $FilePackage{$File} = $Pkg; 1768 } 1769 } 1770 close(FILE); 1771 } 1772 } 1773 1774 if(keys(%FilePackage)) 1775 { 1776 foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) 1777 { 1778 my $LName = get_filename($LPath); 1779 my $LDir = get_dirname($LPath); 1780 my $LName_Short = parse_libname($LName, "name+ext", $OStarget); 1781 1782 my $Pkg = $FilePackage{$LDir."/".$LName_Short}; 1783 if(not $Pkg) 1784 { 1785 my $RPkg = $FilePackage{$LPath}; 1786 if(defined $PackageFile{$RPkg."-devel"}) { 1787 $Pkg = $RPkg."-devel"; 1788 } 1789 if($RPkg=~s/[\d\.]+\Z//g) 1790 { 1791 if(defined $PackageFile{$RPkg."-devel"}) { 1792 $Pkg = $RPkg."-devel"; 1793 } 1794 } 1795 } 1796 if($Pkg) 1797 { 1798 foreach (keys(%{$PackageFile{$Pkg}})) 1799 { 1800 if(index($_, "/usr/include/")==0) { 1801 $LibraryFile{$LPath}{$_} = 1; 1802 } 1803 } 1804 } 1805 1806 $LName_Short=~s/\.so\Z/.a/; 1807 if($Pkg = $FilePackage{$LDir."/".$LName_Short}) 1808 { # headers for static library 1809 foreach (keys(%{$PackageFile{$Pkg}})) 1810 { 1811 if(index($_, "/usr/include/")==0) { 1812 $LibraryFile{$LPath}{$_} = 1; 1813 } 1814 } 1815 } 1816 } 1817 } 1818 1819 my %HeaderFile_Path = (); 1820 1821 if($Debug) { 1822 printMsg("INFO", localtime(time)); 1823 } 1824 printMsg("INFO", "Reading symbols from headers ...\n"); 1825 foreach my $HPath (@SysHeaders) 1826 { 1827 $HPath = path_format($HPath, $OSgroup); 1828 if(readBytes($HPath) eq "7f454c46") 1829 { # skip ELF files 1830 next; 1831 } 1832 my $HRelPath = cut_path_prefix($HPath, $SystemRoot); 1833 my ($HDir, $HName) = separate_path($HRelPath); 1834 if(is_not_header($HName)) 1835 { # have a wrong extension: .gch, .in 1836 next; 1837 } 1838 if($HName=~/~\Z/) 1839 { # reserved copy 1840 next; 1841 } 1842 if(index($HRelPath, "/_gen")!=-1) 1843 { # telepathy-1.0/telepathy-glib/_gen 1844 # telepathy-1.0/libtelepathy/_gen-tp-constants-deprecated.h 1845 next; 1846 } 1847 if(index($HRelPath, "include/linux/")!=-1) 1848 { # kernel-space headers 1849 next; 1850 } 1851 if(index($HRelPath, "include/asm/")!=-1) 1852 { # asm headers 1853 next; 1854 } 1855 if(index($HRelPath, "/microb-engine/")!=-1) 1856 { # MicroB engine (Maemo 4) 1857 next; 1858 } 1859 if($HRelPath=~/\Wprivate(\W|\Z)/) 1860 { # private directories (include/tcl-private, ...) 1861 next; 1862 } 1863 if(index($HRelPath, "/lib/")!=-1) 1864 { 1865 if(not is_header_file($HName)) 1866 { # without or with a wrong extension 1867 # under the /lib directory 1868 next; 1869 } 1870 } 1871 my $Content = readFile($HPath); 1872 $Content=~s/\/\*(.|\n)+?\*\///g; 1873 $Content=~s/\/\/.*?\n//g; # remove comments 1874 $Content=~s/#\s*define[^\n\\]*(\\\n[^\n\\]*)+\n*//g; # remove defines 1875 $Content=~s/#[^\n]*?\n//g; # remove directives 1876 $Content=~s/(\A|\n)class\s+\w+;\n//g; # remove forward declarations 1877 # FIXME: try to add preprocessing stage 1878 foreach my $Symbol (split(/\W+/, $Content)) 1879 { 1880 next if(not $Symbol); 1881 $Symbol_SysHeaders{$Symbol}{$HRelPath} = 1; 1882 $SysHeader_Symbols{$HRelPath}{$Symbol} = 1; 1883 } 1884 $SysHeaderDir_SysHeaders{$HDir}{$HName} = 1; 1885 $HeaderFile_Path{get_filename($HRelPath)}{$HRelPath} = 1; 1886 } 1887 1888 # writeFile($SYS_DUMP_PATH."/debug/headers.txt", Dumper(\%SysHeader_Symbols)); 1889 1890 my %SkipDHeaders = ( 1891 # header files, that should be in the <skip_headers> section 1892 # but should be matched in the algorithm 1893 # MeeGo 1.2 Harmattan 1894 "libtelepathy-qt4" => ["TelepathyQt4/_gen", "client.h", 1895 "TelepathyQt4/*-*", "debug.h", "global.h", 1896 "properties.h", "Channel", "channel.h", "message.h"], 1897 ); 1898 filter_format(\%SkipDHeaders); 1899 if(not $GroupByHeaders) 1900 { 1901 if($Debug) { 1902 printMsg("INFO", localtime(time)); 1903 } 1904 printMsg("INFO", "Matching symbols ...\n"); 1905 } 1906 1907 foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) 1908 { # matching 1909 my $LName = get_filename($LPath); 1910 } 1911 1912 foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) 1913 { # matching 1914 my $LName = get_filename($LPath); 1915 my $LName_Short = parse_libname($LName, "name", $OStarget); 1916 my $LRelPath = cut_path_prefix($LPath, $SystemRoot); 1917 my $LSName = parse_libname($LName, "short", $OStarget); 1918 my $SName = $ShortestNames{$LPath}; 1919 1920 my @TryNames = (); # libX-N.so.M 1921 1922 if(my $Ver = $SysLibVersion{$LName}) 1923 { # libX-N-M 1924 if($LSName."-".$Ver ne $LName_Short) 1925 { 1926 push(@TryNames, $LName_Short."-".$Ver); 1927 #while($Ver=~s/\.\d+\Z//) { # partial versions 1928 # push(@TryNames, $LName_Short."-".$Ver); 1929 #} 1930 } 1931 } 1932 push(@TryNames, $LName_Short); # libX-N 1933 if($LSName ne $LName_Short) 1934 { # libX 1935 push(@TryNames, $LSName); 1936 } 1937 1938 if($LRelPath=~/\/debug\//) 1939 { # debug libs 1940 $Skipped{$LRelPath} = 1; 1941 next; 1942 } 1943 $TotalLibs{$LRelPath} = 1; 1944 $SysLib_SysHeaders{$LRelPath} = (); 1945 1946 my (%SymbolDirs, %SymbolFiles) = (); 1947 1948 foreach my $Symbol (sort {length($b) cmp length($a)} 1949 sort keys(%{$SysLib_Symbols{$LPath}})) 1950 { 1951 if($SysCInfo->{"ignore_symbols"}{$Symbol}) { 1952 next; 1953 } 1954 if(not $DupLibs{$LPath} 1955 and not $VersionedLibs{$LPath} 1956 and keys(%{$SymbolCounter{$Symbol}})>=2 1957 and my $Prefix = getPrefix_S($Symbol)) 1958 { # duplicated symbols 1959 if($PrefixToLib{$Prefix} 1960 and $PrefixToLib{$Prefix} ne $LName 1961 and not $Glibc{$LSName}) { 1962 next; 1963 } 1964 } 1965 if(length($Symbol)<=2) { 1966 next; 1967 } 1968 if($Symbol!~/[A-Z_0-9]/ 1969 and length($Symbol)<10 1970 and keys(%{$Symbol_SysHeaders{$Symbol}})>=3) 1971 { # undistinguished symbols 1972 # FIXME: improve this filter 1973 # signalfd (libc.so) 1974 # regcomp (libpcreposix.so) 1975 next; 1976 } 1977 if($Symbol=~/\A(_M_|_Rb_|_S_)/) 1978 { # _M_insert, _Rb_tree, _S_destroy_c_locale 1979 next; 1980 } 1981 if($Symbol=~/\A[A-Z][a-z]+\Z/) 1982 { # Clone, Initialize, Skip, Unlock, Terminate, Chunk 1983 next; 1984 } 1985 if($Symbol=~/\A[A-Z][A-Z]\Z/) 1986 { # BC, PC, UP, SP 1987 next; 1988 } 1989 if($Symbol=~/_t\Z/) 1990 { # pthread_mutex_t, wchar_t 1991 next; 1992 } 1993 my @SymHeaders = keys(%{$Symbol_SysHeaders{$Symbol}}); 1994 @SymHeaders = sort {lc($a) cmp lc($b)} @SymHeaders; # sort by name 1995 @SymHeaders = sort {length(get_dirname($a))<=>length(get_dirname($b))} @SymHeaders; # sort by length 1996 if(length($SName)>=3) 1997 { # sort candidate headers by name 1998 @SymHeaders = sort {$b=~/\Q$SName\E/i<=>$a=~/\Q$SName\E/i} @SymHeaders; 1999 } 2000 else 2001 { # libz, libX11 2002 @SymHeaders = sort {$b=~/lib\Q$SName\E/i<=>$a=~/lib\Q$SName\E/i} @SymHeaders; 2003 @SymHeaders = sort {$b=~/\Q$SName\Elib/i<=>$a=~/\Q$SName\Elib/i} @SymHeaders; 2004 } 2005 @SymHeaders = sort {$b=~/\Q$LSName\E/i<=>$a=~/\Q$LSName\E/i} @SymHeaders; 2006 @SymHeaders = sort {$SymbolDirs{get_dirname($b)}<=>$SymbolDirs{get_dirname($a)}} @SymHeaders; 2007 @SymHeaders = sort {$SymbolFiles{get_filename($b)}<=>$SymbolFiles{get_filename($a)}} @SymHeaders; 2008 foreach my $HRelPath (@SymHeaders) 2009 { 2010 my $HDir = get_dirname($HRelPath); 2011 my $HName = get_filename($HRelPath); 2012 2013 if(my $Group = $SymbolGroup{$LRelPath}{$Symbol}) 2014 { 2015 if(not $SysHeader_Symbols{$HRelPath}{$Group}) { 2016 next; 2017 } 2018 } 2019 my $Filter = 0; 2020 foreach (@TryNames) 2021 { 2022 if(my $Filt = $SysInfo->{$_}{"headers"}) 2023 { # search for specified headers 2024 if(not check_list($HRelPath, $Filt)) 2025 { 2026 $Filter = 1; 2027 last; 2028 } 2029 } 2030 if(my $Filt = $SysInfo->{$_}{"skip_headers"}) 2031 { # do NOT search for some headers 2032 if(check_list($HRelPath, $Filt)) 2033 { 2034 $Filter = 1; 2035 last; 2036 } 2037 } 2038 if(my $Filt = $SysInfo->{$_}{"skip_including"}) 2039 { # do NOT search for some headers 2040 if(check_list($HRelPath, $Filt)) 2041 { 2042 $SymbolDirs{$HDir}+=1; 2043 $SymbolFiles{$HName}+=1; 2044 $Filter = 1; 2045 last; 2046 } 2047 } 2048 } 2049 if($Filter) { 2050 next; 2051 } 2052 if(my $Filt = $SysCInfo->{"skip_headers"}) 2053 { # do NOT search for some headers 2054 if(check_list($HRelPath, $Filt)) { 2055 next; 2056 } 2057 } 2058 if(my $Filt = $SysCInfo->{"skip_including"}) 2059 { # do NOT search for some headers 2060 if(check_list($HRelPath, $Filt)) { 2061 next; 2062 } 2063 } 2064 2065 if(defined $LibraryFile{$LRelPath}) 2066 { # skip wrongly matched headers 2067 if(not defined $LibraryFile{$LRelPath}{$HRelPath}) 2068 { print "WRONG: $LRelPath $HRelPath\n"; 2069 # next; 2070 } 2071 } 2072 2073 $SysLib_SysHeaders{$LRelPath}{$HRelPath} = $Symbol; 2074 2075 $SysHeaderDir_Used{$HDir}{$LName_Short} = 1; 2076 $SysHeaderDir_Used{get_dirname($HDir)}{$LName_Short} = 1; 2077 2078 $SymbolDirs{$HDir} += 1; 2079 $SymbolFiles{$HName} +=1 ; 2080 2081 # select one header for one symbol 2082 last; 2083 } 2084 } 2085 2086 if(keys(%{$SysLib_Symbols{$LPath}}) 2087 and not $SysInfo->{$_}{"headers"}) 2088 { # try to match by name of the header 2089 if(length($SName)>=3) 2090 { 2091 my @Paths = (); 2092 foreach my $Path (keys(%{$HeaderFile_Path{$SName.".h"}}), keys(%{$HeaderFile_Path{$LSName.".h"}})) 2093 { 2094 my $Dir = get_dirname($Path); 2095 if(defined $SymbolDirs{$Dir} or $Dir eq "/usr/include") { 2096 push(@Paths, $Path); 2097 } 2098 } 2099 if($#Paths==0) 2100 { 2101 my $Path = $Paths[0]; 2102 if(not defined $SysLib_SysHeaders{$LRelPath}{$Path}) { 2103 $SysLib_SysHeaders{$LRelPath}{$Path} = "by name ($LSName)"; 2104 } 2105 } 2106 } 2107 } 2108 2109 if(not keys(%{$SysLib_SysHeaders{$LRelPath}})) 2110 { 2111 foreach (@TryNames) 2112 { 2113 if(my $List = $SysInfo->{$_}{"headers"}) 2114 { 2115 foreach my $HName (@{$List}) 2116 { 2117 next if($HName=~/[\*\/\\]/); 2118 if(my $HPath = selectSystemHeader($HName, 1)) 2119 { 2120 my $HRelPath = cut_path_prefix($HPath, $SystemRoot); 2121 $SysLib_SysHeaders{$LRelPath}{$HRelPath} = "by descriptor"; 2122 } 2123 } 2124 } 2125 } 2126 } 2127 2128 if(not keys(%{$SysLib_SysHeaders{$LRelPath}})) { 2129 $Failed{$LRelPath} = 1; 2130 } 2131 } 2132 2133 if(not $GroupByHeaders) 2134 { # matching results 2135 writeFile($SYS_DUMP_PATH."/debug/match.txt", Dumper(\%SysLib_SysHeaders)); 2136 writeFile($SYS_DUMP_PATH."/debug/skipped.txt", join("\n", sort keys(%Skipped))); 2137 writeFile($SYS_DUMP_PATH."/debug/failed.txt", join("\n", sort keys(%Failed))); 2138 } 2139 (%SysLib_Symbols, %SymbolGroup, %Symbol_SysHeaders, %SysHeader_Symbols) = (); # free memory 2140 if($GroupByHeaders) 2141 { 2142 if($SysDescriptor{"Image"} and not $CheckHeadersOnly) { 2143 @SysHeaders = keys(%{$SysLib_SysHeaders{$SysDescriptor{"Image"}}}); 2144 } 2145 %SysLib_SysHeaders = (); 2146 foreach my $Path (@SysHeaders) 2147 { 2148 if(my $Skip = $SysCInfo->{"skip_headers"}) 2149 { # do NOT search for some headers 2150 if(check_list($Path, $Skip)) { 2151 next; 2152 } 2153 } 2154 if(my $Skip = $SysCInfo->{"skip_including"}) 2155 { # do NOT search for some headers 2156 if(check_list($Path, $Skip)) { 2157 next; 2158 } 2159 } 2160 $SysLib_SysHeaders{$Path}{$Path} = 1; 2161 } 2162 if($CheckHeadersOnly) { 2163 writeFile($SYS_DUMP_PATH."/mode.txt", "headers-only"); 2164 } 2165 else { 2166 writeFile($SYS_DUMP_PATH."/mode.txt", "group-by-headers"); 2167 } 2168 } 2169 @SysHeaders = (); # clear memory 2170 2171 if($Debug) { 2172 printMsg("INFO", localtime(time)); 2173 } 2174 printMsg("INFO", "Generating XML descriptors ..."); 2175 my %Generated = (); 2176 my %CxxIncompat_L = (); 2177 foreach my $LRelPath (keys(%SysLib_SysHeaders)) 2178 { 2179 my $LName = get_filename($LRelPath); 2180 my $DPath = $SYS_DUMP_PATH."/descriptors/$LName.xml"; 2181 unlink($DPath); 2182 if(my @LibHeaders = keys(%{$SysLib_SysHeaders{$LRelPath}})) 2183 { 2184 my $LSName = parse_libname($LName, "short", $OStarget); 2185 my $LName_Short = parse_libname($LName, "name", $OStarget); 2186 my $LName_Shortest = parse_libname($LName, "shortest", $OStarget); 2187 if($GroupByHeaders) 2188 { # header short name 2189 $LSName = $LName; 2190 $LSName=~s/\.(.+?)\Z//; 2191 } 2192 2193 my (%DirsHeaders, %Includes, %MainDirs) = (); 2194 foreach my $HRelPath (@LibHeaders) 2195 { 2196 my $Dir = get_dirname($HRelPath); 2197 $DirsHeaders{$Dir}{$HRelPath} = 1; 2198 2199 if($Dir=~/\/\Q$LName_Shortest\E(\/|\Z)/i 2200 or $Dir=~/\/\Q$LName_Short\E(\/|\Z)/i) 2201 { 2202 if(get_filename($Dir) ne "include") 2203 { # except /usr/include 2204 $MainDirs{$Dir} += 1; 2205 } 2206 } 2207 } 2208 2209 if($#LibHeaders==0) 2210 { # one header at all 2211 $Includes{$LibHeaders[0]} = 1; 2212 } 2213 else 2214 { 2215 foreach my $Dir (keys(%DirsHeaders)) 2216 { 2217 if(keys(%MainDirs) and not defined $MainDirs{$Dir}) 2218 { # search in /X/ dir for libX headers 2219 if(get_filename($Dir) ne "include") 2220 { # except /usr/include 2221 next; 2222 } 2223 } 2224 my $DirPart = 0; 2225 my $TotalHeaders = keys(%{$SysHeaderDir_SysHeaders{$Dir}}); 2226 if($TotalHeaders) { 2227 $DirPart = (keys(%{$DirsHeaders{$Dir}})*100)/$TotalHeaders; 2228 } 2229 my $Neighbourhoods = keys(%{$SysHeaderDir_Used{$Dir}}); 2230 if($Neighbourhoods==1) 2231 { # one lib in this directory 2232 if(get_filename($Dir) ne "include" 2233 and $DirPart>=5) 2234 { # complete directory 2235 $Includes{$Dir} = 1; 2236 } 2237 else 2238 { # list of headers 2239 foreach (keys(%{$DirsHeaders{$Dir}})) { 2240 $Includes{$_} = 1; 2241 } 2242 } 2243 } 2244 elsif((keys(%{$DirsHeaders{$Dir}})*100)/($#LibHeaders+1)>5) 2245 { # remove 5% divergence 2246 if(get_filename($Dir) ne "include" 2247 and $DirPart>=50) 2248 { # complete directory if more than 50% 2249 $Includes{$Dir} = 1; 2250 } 2251 else 2252 { # list of headers 2253 foreach (keys(%{$DirsHeaders{$Dir}})) { 2254 $Includes{$_} = 1; 2255 } 2256 } 2257 } 2258 else 2259 { # noise 2260 foreach (keys(%{$DirsHeaders{$Dir}})) 2261 { # NOTE: /usr/include/libX.h 2262 if(/\Q$LName_Shortest\E/i) { 2263 $Includes{$_} = 1; 2264 } 2265 } 2266 } 2267 } 2268 } 2269 if($GroupByHeaders) 2270 { # one header in one ABI dump 2271 %Includes = ($LibHeaders[0] => 1); 2272 } 2273 my $LVersion = $SysLibVersion{$LName}; 2274 if($LVersion) 2275 { # append by system name 2276 $LVersion .= "-".$SysDescriptor{"Name"}; 2277 } 2278 else { 2279 $LVersion = $SysDescriptor{"Name"}; 2280 } 2281 my @Content = ("<version>\n $LVersion\n</version>"); 2282 2283 my @IncHeaders = sort keys(%Includes); 2284 2285 # sort files up 2286 @IncHeaders = sort {$b=~/\.h\Z/<=>$a=~/\.h\Z/} @IncHeaders; 2287 2288 # sort by name 2289 @IncHeaders = sort {sortHeaders($a, $b)} @IncHeaders; 2290 2291 # sort by library name 2292 sortByWord(\@IncHeaders, parse_libname($LName, "shortest", $OStarget)); 2293 2294 if(is_abs($IncHeaders[0]) or -f $IncHeaders[0]) { 2295 push(@Content, "<headers>\n ".join("\n ", @IncHeaders)."\n</headers>"); 2296 } 2297 else { 2298 push(@Content, "<headers>\n {RELPATH}/".join("\n {RELPATH}/", @IncHeaders)."\n</headers>"); 2299 } 2300 if($GroupByHeaders) 2301 { 2302 if($SysDescriptor{"Image"}) { 2303 push(@Content, "<libs>\n ".$SysDescriptor{"Image"}."\n</libs>"); 2304 } 2305 } 2306 else 2307 { 2308 if(is_abs($LRelPath) or -f $LRelPath) { 2309 push(@Content, "<libs>\n $LRelPath\n</libs>"); 2310 } 2311 else { 2312 push(@Content, "<libs>\n {RELPATH}/$LRelPath\n</libs>"); 2313 } 2314 } 2315 2316 # system 2317 if(my @SearchHeaders = sort keys(%{$SysDescriptor{"SearchHeaders"}})) { 2318 push(@Content, "<search_headers>\n ".join("\n ", @SearchHeaders)."\n</search_headers>"); 2319 } 2320 if(my @SearchLibs = sort keys(%{$SysDescriptor{"SearchLibs"}})) { 2321 push(@Content, "<search_libs>\n ".join("\n ", @SearchLibs)."\n</search_libs>"); 2322 } 2323 if(my @Tools = sort keys(%{$SysDescriptor{"Tools"}})) { 2324 push(@Content, "<tools>\n ".join("\n ", @Tools)."\n</tools>"); 2325 } 2326 if(my $Prefix = $SysDescriptor{"CrossPrefix"}) { 2327 push(@Content, "<cross_prefix>\n $Prefix\n</cross_prefix>"); 2328 } 2329 2330 # library 2331 my (@Skip, @SkipInc, @AddIncPath, @SkipIncPath, 2332 @SkipTypes, @SkipSymb, @Preamble, @Defines, @CompilerOpts) = (); 2333 2334 my @TryNames = (); 2335 if(my $Ver = $SysLibVersion{$LName}) 2336 { 2337 if($LSName."-".$Ver ne $LName_Short) { 2338 push(@TryNames, $LName_Short."-".$Ver); 2339 } 2340 } 2341 push(@TryNames, $LName_Short); 2342 if($LSName ne $LName_Short) { 2343 push(@TryNames, $LSName); 2344 } 2345 2346 # common 2347 if(my $List = $SysCInfo->{"include_preamble"}) { 2348 push(@Preamble, @{$List}); 2349 } 2350 if(my $List = $SysCInfo->{"skip_headers"}) { 2351 @Skip = (@Skip, @{$List}); 2352 } 2353 if(my $List = $SysCInfo->{"skip_including"}) { 2354 @SkipInc = (@SkipInc, @{$List}); 2355 } 2356 if(my $List = $SysCInfo->{"skip_symbols"}) { 2357 push(@SkipSymb, @{$List}); 2358 } 2359 if(my $List = $SysCInfo->{"gcc_options"}) { 2360 push(@CompilerOpts, @{$List}); 2361 } 2362 if($SysCInfo->{"defines"}) { 2363 push(@Defines, $SysCInfo->{"defines"}); 2364 } 2365 2366 # particular 2367 foreach (@TryNames) 2368 { 2369 if(my $List = $SysInfo->{$_}{"include_preamble"}) { 2370 push(@Preamble, @{$List}); 2371 } 2372 if(my $List = $SysInfo->{$_}{"skip_headers"}) { 2373 @Skip = (@Skip, @{$List}); 2374 } 2375 if(my $List = $SysInfo->{$_}{"skip_including"}) { 2376 @SkipInc = (@SkipInc, @{$List}); 2377 } 2378 if(my $List = $SysInfo->{$_}{"add_include_paths"}) { 2379 @AddIncPath = (@AddIncPath, @{$List}); 2380 } 2381 if(my $List = $SysInfo->{$_}{"skip_include_paths"}) { 2382 @SkipIncPath = (@SkipIncPath, @{$List}); 2383 } 2384 if(my $List = $SysInfo->{$_}{"skip_symbols"}) { 2385 push(@SkipSymb, @{$List}); 2386 } 2387 if(my $List = $SysInfo->{$_}{"skip_types"}) { 2388 @SkipTypes = (@SkipTypes, @{$List}); 2389 } 2390 if(my $List = $SysInfo->{$_}{"gcc_options"}) { 2391 push(@CompilerOpts, @{$List}); 2392 } 2393 if(my $List = $SysInfo->{$_}{"defines"}) { 2394 push(@Defines, $List); 2395 } 2396 if($SysInfo->{$_}{"cxx_incompatible"}) { 2397 $CxxIncompat_L{$LName} = 1; 2398 } 2399 } 2400 2401 # common other 2402 if($LSName=~/\AlibX\w+\Z/) 2403 { # add Xlib.h for libXt, libXaw, libXext and others 2404 push(@Preamble, "Xlib.h", "X11/Intrinsic.h"); 2405 } 2406 if($SkipDHeaders{$LSName}) { 2407 @SkipInc = (@SkipInc, @{$SkipDHeaders{$LSName}}); 2408 } 2409 if($SysDescriptor{"Defines"}) { 2410 push(@Defines, $SysDescriptor{"Defines"}); 2411 } 2412 2413 # add sections 2414 if(@Preamble) { 2415 push(@Content, "<include_preamble>\n ".join("\n ", @Preamble)."\n</include_preamble>"); 2416 } 2417 if(@Skip) { 2418 push(@Content, "<skip_headers>\n ".join("\n ", @Skip)."\n</skip_headers>"); 2419 } 2420 if(@SkipInc) { 2421 push(@Content, "<skip_including>\n ".join("\n ", @SkipInc)."\n</skip_including>"); 2422 } 2423 if(@AddIncPath) { 2424 push(@Content, "<add_include_paths>\n ".join("\n ", @AddIncPath)."\n</add_include_paths>"); 2425 } 2426 if(@SkipIncPath) { 2427 push(@Content, "<skip_include_paths>\n ".join("\n ", @SkipIncPath)."\n</skip_include_paths>"); 2428 } 2429 if(@SkipSymb) { 2430 push(@Content, "<skip_symbols>\n ".join("\n ", @SkipSymb)."\n</skip_symbols>"); 2431 } 2432 if(@SkipTypes) { 2433 push(@Content, "<skip_types>\n ".join("\n ", @SkipTypes)."\n</skip_types>"); 2434 } 2435 if(@CompilerOpts) { 2436 push(@Content, "<gcc_options>\n ".join("\n ", @CompilerOpts)."\n</gcc_options>"); 2437 } 2438 if(@Defines) { 2439 push(@Content, "<defines>\n ".join("\n ", @Defines)."\n</defines>"); 2440 } 2441 2442 writeFile($DPath, join("\n\n", @Content)); 2443 $Generated{$LRelPath} = 1; 2444 2445 # save header files to create visual diff later 2446 my $HSDir = $SYS_DUMP_PATH."/headers/".$LName; 2447 rmtree($HSDir); 2448 mkpath($HSDir); 2449 foreach my $H_P (@IncHeaders) 2450 { 2451 if(-f $H_P) { 2452 copy($H_P, $HSDir); 2453 } 2454 } 2455 } 2456 } 2457 printMsg("INFO", "Created descriptors: ".keys(%Generated)." ($SYS_DUMP_PATH/descriptors/)\n"); 2458 2459 if($Debug) { 2460 printMsg("INFO", localtime(time)); 2461 } 2462 printMsg("INFO", "Dumping ABIs:"); 2463 my %Dumped = (); 2464 my @Descriptors = cmd_find($SYS_DUMP_PATH."/descriptors","f","*.xml","1"); 2465 if(-d $SYS_DUMP_PATH."/descriptors" and $#Descriptors==-1) { 2466 printMsg("ERROR", "internal problem with \'find\' utility"); 2467 } 2468 foreach my $DPath (sort {lc($a) cmp lc($b)} @Descriptors) 2469 { 2470 my $DName = get_filename($DPath); 2471 my $LName = ""; 2472 if($DName=~/\A(.+).xml\Z/) { 2473 $LName = $1; 2474 } 2475 else { 2476 next; 2477 } 2478 if(not is_target_lib($LName) 2479 and not is_target_lib($LibSoname{$LName})) { 2480 next; 2481 } 2482 $DPath = cut_path_prefix($DPath, $ORIG_DIR); 2483 my $ACC_dump = "perl $0"; 2484 if($GroupByHeaders) 2485 { # header name is going here 2486 $ACC_dump .= " -l $LName"; 2487 } 2488 else { 2489 $ACC_dump .= " -l ".parse_libname($LName, "name", $OStarget); 2490 } 2491 $ACC_dump .= " -dump \"$DPath\""; 2492 if($SystemRoot) 2493 { 2494 $ACC_dump .= " -relpath \"$SystemRoot\""; 2495 $ACC_dump .= " -sysroot \"$SystemRoot\""; 2496 } 2497 my $DumpPath = "$SYS_DUMP_PATH/abi_dumps/$LName.abi"; 2498 $ACC_dump .= " -dump-path \"$DumpPath\""; 2499 my $LogPath = "$SYS_DUMP_PATH/logs/$LName.txt"; 2500 unlink($LogPath); 2501 $ACC_dump .= " -log-path \"$LogPath\""; 2502 if($CrossGcc) { 2503 $ACC_dump .= " -cross-gcc \"$CrossGcc\""; 2504 } 2505 if($CheckHeadersOnly) { 2506 $ACC_dump .= " -headers-only"; 2507 } 2508 if($UseStaticLibs) { 2509 $ACC_dump .= " -static-libs"; 2510 } 2511 if($GroupByHeaders) { 2512 $ACC_dump .= " -header $LName"; 2513 } 2514 if($NoStdInc 2515 or $OStarget=~/windows|symbian/) 2516 { # 1. user-defined 2517 # 2. windows/minGW 2518 # 3. symbian/GCC 2519 $ACC_dump .= " -nostdinc"; 2520 } 2521 if($CxxIncompat or $CxxIncompat_L{$LName}) { 2522 $ACC_dump .= " -cxx-incompatible"; 2523 } 2524 if($SkipUnidentified) { 2525 $ACC_dump .= " -skip-unidentified"; 2526 } 2527 if($Quiet) 2528 { # quiet mode 2529 $ACC_dump .= " -quiet"; 2530 } 2531 if($LogMode eq "n") { 2532 $ACC_dump .= " -logging-mode n"; 2533 } 2534 elsif($Quiet) { 2535 $ACC_dump .= " -logging-mode a"; 2536 } 2537 if($Debug) 2538 { # debug mode 2539 $ACC_dump .= " -debug"; 2540 printMsg("INFO", "$ACC_dump"); 2541 } 2542 printMsg("INFO_C", "Dumping $LName: "); 2543 system($ACC_dump." 1>$TMP_DIR/null 2>$TMP_DIR/$LName.stderr"); 2544 my $ErrCode = $?; 2545 appendFile("$SYS_DUMP_PATH/logs/$LName.txt", "The ACC parameters:\n $ACC_dump\n"); 2546 my $ErrCont = readFile("$TMP_DIR/$LName.stderr"); 2547 if($ErrCont) { 2548 appendFile("$SYS_DUMP_PATH/logs/$LName.txt", $ErrCont); 2549 } 2550 2551 if(filterError($ErrCont)) 2552 { 2553 if(get_CodeError($ErrCode>>8) eq "Invalid_Dump") { 2554 printMsg("INFO", "Empty"); 2555 } 2556 else { 2557 printMsg("INFO", "Errors (\'$SYS_DUMP_PATH/logs/$LName.txt\')"); 2558 } 2559 } 2560 elsif(not -f $DumpPath) { 2561 printMsg("INFO", "Failed (\'$SYS_DUMP_PATH/logs/$LName.txt\')"); 2562 } 2563 else 2564 { 2565 $Dumped{$LName}=1; 2566 printMsg("INFO", "Ok"); 2567 } 2568 } 2569 printMsg("INFO", "\n"); 2570 if(not $GroupByHeaders) 2571 { # general mode 2572 printMsg("INFO", "Total libraries: ".keys(%TotalLibs)); 2573 printMsg("INFO", "Skipped libraries: ".keys(%Skipped)." ($SYS_DUMP_PATH/skipped.txt)"); 2574 printMsg("INFO", "Failed to find headers: ".keys(%Failed)." ($SYS_DUMP_PATH/failed.txt)"); 2575 } 2576 printMsg("INFO", "Dumped ABIs: ".keys(%Dumped)." ($SYS_DUMP_PATH/abi_dumps/)"); 2577 printMsg("INFO", "The ".$SysDescriptor{"Name"}." system ABI has been dumped to:\n $SYS_DUMP_PATH"); 2578} 2579 2580sub filterError($) 2581{ 2582 my $Error = $_[0]; 2583 2584 if(not $Error) { 2585 return undef; 2586 } 2587 2588 my @Err = (); 2589 foreach my $L (split(/\n/, $Error)) 2590 { 2591 if($L!~/warning:/) { 2592 push(@Err, $L); 2593 } 2594 } 2595 2596 return join("\n", @Err); 2597} 2598 2599return 1; 2600