1########################################################################### 2# A module to find system files and automatically generate include paths 3# 4# Copyright (C) 2015-2018 Andrey Ponomarenko's ABI Laboratory 5# 6# Written by Andrey Ponomarenko 7# 8# This library is free software; you can redistribute it and/or 9# modify it under the terms of the GNU Lesser General Public 10# License as published by the Free Software Foundation; either 11# version 2.1 of the License, or (at your option) any later version. 12# 13# This library is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16# Lesser General Public License for more details. 17# 18# You should have received a copy of the GNU Lesser General Public 19# License along with this library; if not, write to the Free Software 20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21# MA 02110-1301 USA 22########################################################################### 23use strict; 24 25loadModule("ElfTools"); 26 27my %Cache; 28 29my %BinUtils = map {$_=>1} ( 30 "c++filt", 31 "objdump", 32 "readelf" 33); 34 35# Header file extensions as described by gcc 36my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+|tcc|txx|x|inl|inc|ads|isph"; 37 38my %GlibcHeader = map {$_=>1} ( 39 "aliases.h", 40 "argp.h", 41 "argz.h", 42 "assert.h", 43 "cpio.h", 44 "ctype.h", 45 "dirent.h", 46 "envz.h", 47 "errno.h", 48 "error.h", 49 "execinfo.h", 50 "fcntl.h", 51 "fstab.h", 52 "ftw.h", 53 "glob.h", 54 "grp.h", 55 "iconv.h", 56 "ifaddrs.h", 57 "inttypes.h", 58 "langinfo.h", 59 "limits.h", 60 "link.h", 61 "locale.h", 62 "malloc.h", 63 "math.h", 64 "mntent.h", 65 "monetary.h", 66 "nl_types.h", 67 "obstack.h", 68 "printf.h", 69 "pwd.h", 70 "regex.h", 71 "sched.h", 72 "search.h", 73 "setjmp.h", 74 "shadow.h", 75 "signal.h", 76 "spawn.h", 77 "stdarg.h", 78 "stdint.h", 79 "stdio.h", 80 "stdlib.h", 81 "string.h", 82 "strings.h", 83 "tar.h", 84 "termios.h", 85 "time.h", 86 "ulimit.h", 87 "unistd.h", 88 "utime.h", 89 "wchar.h", 90 "wctype.h", 91 "wordexp.h" ); 92 93my %GlibcDir = map {$_=>1} ( 94 "arpa", 95 "bits", 96 "gnu", 97 "netinet", 98 "net", 99 "nfs", 100 "rpc", 101 "sys", 102 "linux" ); 103 104my %WinHeaders = map {$_=>1} ( 105 "dos.h", 106 "process.h", 107 "winsock.h", 108 "config-win.h", 109 "mem.h", 110 "windows.h", 111 "winsock2.h", 112 "crtdbg.h", 113 "ws2tcpip.h" 114); 115 116my %ObsoleteHeaders = map {$_=>1} ( 117 "iostream.h", 118 "fstream.h" 119); 120 121my %AlienHeaders = map {$_=>1} ( 122 # Solaris 123 "thread.h", 124 "sys/atomic.h", 125 # HPUX 126 "sys/stream.h", 127 # Symbian 128 "AknDoc.h", 129 # Atari ST 130 "ext.h", 131 "tos.h", 132 # MS-DOS 133 "alloc.h", 134 # Sparc 135 "sys/atomic.h" 136); 137 138my %ConfHeaders = map {$_=>1} ( 139 "atomic", 140 "conf.h", 141 "config.h", 142 "configure.h", 143 "build.h", 144 "setup.h" 145); 146 147my %LocalIncludes = map {$_=>1} ( 148 "/usr/local/include", 149 "/usr/local" ); 150 151my %OS_AddPath=( 152# These paths are needed if the tool cannot detect them automatically 153 "macos"=>{ 154 "include"=>[ 155 "/Library", 156 "/Developer/usr/include" 157 ], 158 "lib"=>[ 159 "/Library", 160 "/Developer/usr/lib" 161 ], 162 "bin"=>[ 163 "/Developer/usr/bin" 164 ] 165 }, 166 "beos"=>{ 167 # Haiku has GCC 2.95.3 by default 168 # try to find GCC>=3.0 in /boot/develop/abi 169 "include"=>[ 170 "/boot/common", 171 "/boot/develop" 172 ], 173 "lib"=>[ 174 "/boot/common/lib", 175 "/boot/system/lib", 176 "/boot/apps" 177 ], 178 "bin"=>[ 179 "/boot/common/bin", 180 "/boot/system/bin", 181 "/boot/develop/abi" 182 ] 183 } 184); 185 186my %RegisteredDirs; 187my %Header_ErrorRedirect; 188my %HeaderName_Paths; 189my %Header_Dependency; 190my @DefaultCppPaths; 191my @DefaultGccPaths; 192my @DefaultIncPaths; 193my @DefaultBinPaths; 194my %SystemHeaders; 195my %DefaultCppHeader; 196my %DefaultGccHeader; 197my @UsersIncPath; 198my %Header_Includes; 199my %Header_Includes_R; 200my %Header_ShouldNotBeUsed; 201my %RecursiveIncludes; 202my %Header_Include_Prefix; 203my @RecurInclude; 204 205my %Include_Paths = ( 206 "1"=>[], 207 "2"=>[] 208); 209 210my %Add_Include_Paths = ( 211 "1"=>[], 212 "2"=>[] 213); 214 215sub tryCmd($) 216{ 217 my $Cmd = $_[0]; 218 219 my @Options = ( 220 "--version", 221 "-help" 222 ); 223 foreach my $Opt (@Options) 224 { 225 my $TmpDir = $In::Opt{"Tmp"}; 226 my $Info = `$Cmd $Opt 2>\"$TmpDir/null\"`; 227 if($Info) { 228 return 1; 229 } 230 } 231 return 0; 232} 233 234sub searchTool($) 235{ 236 my $Name = $_[0]; 237 238 if(my @Paths = keys(%{$In::Opt{"TargetTools"}})) 239 { 240 foreach my $Path (@Paths) 241 { 242 if(-f join_P($Path, $Name)) { 243 return join_P($Path, $Name); 244 } 245 if(my $CrossPrefix = $In::Opt{"CrossPrefix"}) 246 { # user-defined prefix (arm-none-symbianelf, ...) 247 my $Candidate = join_P($Path, $CrossPrefix."-".$Name); 248 if(-f $Candidate) { 249 return $Candidate; 250 } 251 } 252 } 253 } 254 255 return undef; 256} 257 258sub syncWithGcc($) 259{ 260 my $Name = $_[0]; 261 if(my $GccPath = $In::Opt{"GccPath"}) 262 { 263 if($GccPath=~s/\bgcc(|\.\w+)\Z/$Name$1/) { 264 return $GccPath; 265 } 266 } 267 268 return undef; 269} 270 271sub getCmdPath($) 272{ 273 my $Name = $_[0]; 274 275 if(defined $Cache{"getCmdPath"}{$Name}) { 276 return $Cache{"getCmdPath"}{$Name}; 277 } 278 279 my $Path = searchTool($Name); 280 if(not $Path and $In::Opt{"OS"} eq "windows") { 281 $Path = searchTool($Name.".exe"); 282 } 283 284 if(not $Path and $BinUtils{$Name}) 285 { 286 if(my $CrossPrefix = $In::Opt{"CrossPrefix"}) { 287 $Path = searchCommand($CrossPrefix."-".$Name); 288 } 289 } 290 291 if(not $Path and $BinUtils{$Name}) 292 { 293 if(my $Cand = syncWithGcc($Name)) 294 { # sync with GCC 295 if($Cand=~/[\/\\]/) 296 { # path 297 if(-f $Cand) { 298 $Path = $Cand; 299 } 300 } 301 elsif($Cand = searchCommand($Cand)) 302 { # name 303 $Path = $Cand; 304 } 305 } 306 } 307 if(not $Path) { 308 $Path = searchCommand($Name); 309 } 310 if(not $Path and $In::Opt{"OS"} eq "windows") 311 { # search for *.exe file 312 $Path = searchCommand($Name.".exe"); 313 } 314 if($Path=~/\s/) { 315 $Path = "\"".$Path."\""; 316 } 317 return ($Cache{"getCmdPath"}{$Name} = $Path); 318} 319 320sub searchCommand($) 321{ 322 my $Name = $_[0]; 323 324 if(defined $Cache{"searchCommand"}{$Name}) { 325 return $Cache{"searchCommand"}{$Name}; 326 } 327 if(my $DefaultPath = getCmdPath_Default($Name)) { 328 return ($Cache{"searchCommand"}{$Name} = $DefaultPath); 329 } 330 foreach my $Path (@{$In::Opt{"SysPaths"}{"bin"}}) 331 { 332 my $CmdPath = join_P($Path,$Name); 333 if(-f $CmdPath) 334 { 335 if($Name=~/gcc/) { 336 next if(not checkGcc("3", $CmdPath)); 337 } 338 return ($Cache{"searchCommand"}{$Name} = $CmdPath); 339 } 340 } 341 return ($Cache{"searchCommand"}{$Name} = ""); 342} 343 344sub getCmdPath_Default($) 345{ # search in PATH 346 if(defined $Cache{"getCmdPath_Default"}{$_[0]}) { 347 return $Cache{"getCmdPath_Default"}{$_[0]}; 348 } 349 return ($Cache{"getCmdPath_Default"}{$_[0]} = getCmdPath_Default_I($_[0])); 350} 351 352sub getCmdPath_Default_I($) 353{ # search in PATH 354 my $Name = $_[0]; 355 356 my $TmpDir = $In::Opt{"Tmp"}; 357 358 if($Name=~/find/) 359 { # special case: search for "find" utility 360 if(`find \"$TmpDir\" -maxdepth 0 2>\"$TmpDir/null\"`) { 361 return "find"; 362 } 363 } 364 elsif($Name=~/gcc/) { 365 return checkGcc("3", $Name); 366 } 367 if(tryCmd($Name)) { 368 return $Name; 369 } 370 if($In::Opt{"OS"} eq "windows") 371 { 372 if(`$Name /? 2>\"$TmpDir/null\"`) { 373 return $Name; 374 } 375 } 376 foreach my $Path (@DefaultBinPaths) 377 { 378 if(-f $Path."/".$Name) { 379 return join_P($Path, $Name); 380 } 381 } 382 return ""; 383} 384 385sub checkSystemFiles() 386{ 387 if($Cache{"checkSystemFiles"}) 388 { # run once 389 return; 390 } 391 $Cache{"checkSystemFiles"} = 1; 392 393 my $LibExt = $In::Opt{"Ext"}; 394 my @SysHeaders = (); 395 396 foreach my $DevelPath (@{$In::Opt{"SysPaths"}{"lib"}}) 397 { 398 if(not -d $DevelPath) { 399 next; 400 } 401 402 my @Files = cmdFind($DevelPath,"f"); 403 foreach my $Link (cmdFind($DevelPath,"l")) 404 { # add symbolic links 405 if(-f $Link) { 406 push(@Files, $Link); 407 } 408 } 409 410 # search for headers in /usr/lib 411 my @Headers = grep { /\.h(pp|xx)?\Z|\/include\// } @Files; 412 @Headers = grep { not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs|perl|llvm)/ } @Headers; 413 push(@SysHeaders, @Headers); 414 415 # search for libraries in /usr/lib (including symbolic links) 416 my @Libs = grep { /\.$LibExt[0-9.]*\Z/ } @Files; 417 foreach my $Path (@Libs) 418 { 419 my $N = getFilename($Path); 420 $In::Opt{"SystemObjects"}{$N}{$Path} = 1; 421 $In::Opt{"SystemObjects"}{libPart($N, "name+ext")}{$Path} = 1; 422 } 423 } 424 425 foreach my $DevelPath (@{$In::Opt{"SysPaths"}{"include"}}) 426 { 427 if(not -d $DevelPath) { 428 next; 429 } 430 # search for all header files in the /usr/include 431 # with or without extension (ncurses.h, QtCore, ...) 432 push(@SysHeaders, cmdFind($DevelPath,"f")); 433 foreach my $Link (cmdFind($DevelPath,"l")) 434 { # add symbolic links 435 if(-f $Link) { 436 push(@SysHeaders, $Link); 437 } 438 } 439 } 440 getPrefixes_I(\@SysHeaders, \%SystemHeaders); 441} 442 443sub libPart($$) 444{ 445 my ($N, $T) = @_; 446 if(defined $Cache{"libPart"}{$T}{$N}) { 447 return $Cache{"libPart"}{$T}{$N}; 448 } 449 return ($Cache{"libPart"}{$T}{$N} = libPart_I(@_)); 450} 451 452sub libPart_I($$) 453{ 454 my ($N, $T) = @_; 455 456 my $Ext = $In::Opt{"Ext"}; 457 my $Target = $In::Opt{"Target"}; 458 459 if($Target eq "symbian") 460 { 461 if($N=~/(((.+?)(\{.+\}|))\.$Ext)\Z/) 462 { # libpthread{00010001}.dso 463 if($T eq "name") 464 { # libpthread{00010001} 465 return $2; 466 } 467 elsif($T eq "name+ext") 468 { # libpthread{00010001}.dso 469 return $1; 470 } 471 elsif($T eq "version") 472 { # 00010001 473 my $V = $4; 474 $V=~s/\{(.+)\}/$1/; 475 return $V; 476 } 477 elsif($T eq "short") 478 { # libpthread 479 return $3; 480 } 481 elsif($T eq "shortest") 482 { # pthread 483 return shortestName($3); 484 } 485 } 486 } 487 elsif($Target eq "windows") 488 { 489 if($N=~/((.+?)\.$Ext)\Z/) 490 { # netapi32.dll 491 if($T eq "name") 492 { # netapi32 493 return $2; 494 } 495 elsif($T eq "name+ext") 496 { # netapi32.dll 497 return $1; 498 } 499 elsif($T eq "version") 500 { # DLL version embedded 501 # at binary-level 502 return ""; 503 } 504 elsif($T eq "short") 505 { # netapi32 506 return $2; 507 } 508 elsif($T eq "shortest") 509 { # netapi 510 return shortestName($2); 511 } 512 } 513 } 514 else 515 { # unix 516 if($N=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/) 517 { # libSDL-1.2.so.0.7.1 518 # libwbxml2.so.0.0.18 519 # libopcodes-2.21.53-system.20110810.so 520 if($T eq "name") 521 { # libSDL-1.2 522 # libwbxml2 523 return $2; 524 } 525 elsif($T eq "name+ext") 526 { # libSDL-1.2.so 527 # libwbxml2.so 528 return $1; 529 } 530 elsif($T eq "version") 531 { 532 if(defined $7 533 and $7 ne "") 534 { # 0.7.1 535 return $7; 536 } 537 else 538 { # libc-2.5.so (=>2.5 version) 539 my $MV = $5; 540 $MV=~s/\A[\-\_]+//g; 541 return $MV; 542 } 543 } 544 elsif($T eq "short") 545 { # libSDL 546 # libwbxml2 547 return $3; 548 } 549 elsif($T eq "shortest") 550 { # SDL 551 # wbxml 552 return shortestName($3); 553 } 554 } 555 } 556 557 # error 558 return ""; 559} 560 561sub shortestName($) 562{ 563 my $Name = $_[0]; 564 # remove prefix 565 $Name=~s/\A(lib|open)//; 566 # remove suffix 567 $Name=~s/[\W\d_]+\Z//i; 568 $Name=~s/([a-z]{2,})(lib)\Z/$1/i; 569 return $Name; 570} 571 572sub detectDefaultPaths($$$$) 573{ 574 my ($HSearch, $LSearch, $BSearch, $GSearch) = (@_); 575 576 if($Cache{"detectDefaultPaths"}{$HSearch}{$LSearch}{$BSearch}{$GSearch}) 577 { # enter once 578 return; 579 } 580 $Cache{"detectDefaultPaths"}{$HSearch}{$LSearch}{$BSearch}{$GSearch} = 1; 581 582 if(@{$In::Opt{"SysPaths"}{"include"}}) 583 { # <search_headers> section of the XML descriptor 584 # do NOT search for systems headers 585 $HSearch = undef; 586 } 587 if(@{$In::Opt{"SysPaths"}{"lib"}}) 588 { # <search_libs> section of the XML descriptor 589 # do NOT search for systems libraries 590 $LSearch = undef; 591 } 592 593 foreach my $Type (keys(%{$OS_AddPath{$In::Opt{"OS"}}})) 594 { # additional search paths 595 next if($Type eq "include" and not $HSearch); 596 next if($Type eq "lib" and not $LSearch); 597 next if($Type eq "bin" and not $BSearch); 598 599 push_U($In::Opt{"SysPaths"}{$Type}, grep { -d $_ } @{$OS_AddPath{$In::Opt{"OS"}}{$Type}}); 600 } 601 if($In::Opt{"OS"} ne "windows") 602 { # unix-like 603 foreach my $Type ("include", "lib", "bin") 604 { # automatic detection of system "devel" directories 605 next if($Type eq "include" and not $HSearch); 606 next if($Type eq "lib" and not $LSearch); 607 next if($Type eq "bin" and not $BSearch); 608 609 my ($UsrDir, $RootDir) = ("/usr", "/"); 610 611 if(my $SystemRoot = $In::Opt{"SystemRoot"} 612 and $Type ne "bin") 613 { # 1. search for target headers and libraries 614 # 2. use host commands: ldconfig, readelf, etc. 615 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot); 616 } 617 618 push_U($In::Opt{"SysPaths"}{$Type}, cmdFind($RootDir,"d","*$Type*",1)); 619 620 if(-d $RootDir."/".$Type) 621 { # if "/lib" is symbolic link 622 if($RootDir eq "/") { 623 push_U($In::Opt{"SysPaths"}{$Type}, "/".$Type); 624 } 625 else { 626 push_U($In::Opt{"SysPaths"}{$Type}, $RootDir."/".$Type); 627 } 628 } 629 630 if(-d $UsrDir) 631 { 632 push_U($In::Opt{"SysPaths"}{$Type}, cmdFind($UsrDir,"d","*$Type*",1)); 633 if(-d $UsrDir."/".$Type) 634 { # if "/usr/lib" is symbolic link 635 push_U($In::Opt{"SysPaths"}{$Type}, $UsrDir."/".$Type); 636 } 637 } 638 } 639 } 640 if($BSearch) 641 { 642 detectBinDefaultPaths(); 643 push_U($In::Opt{"SysPaths"}{"bin"}, @DefaultBinPaths); 644 } 645 646 # check environment variables 647 if($In::Opt{"OS"} eq "beos") 648 { 649 foreach (my @Paths = @{$In::Opt{"SysPaths"}{"bin"}}) 650 { 651 if($_ eq ".") { 652 next; 653 } 654 # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/ 655 if(my @Dirs = sort cmdFind($_, "d", "bin")) { 656 push_U($In::Opt{"SysPaths"}{"bin"}, sort {getDepth($a)<=>getDepth($b)} @Dirs); 657 } 658 } 659 660 if($HSearch) 661 { 662 push_U(\@DefaultIncPaths, grep { isAbsPath($_) } ( 663 split(/:|;/, $ENV{"BEINCLUDES"}) 664 )); 665 } 666 667 if($LSearch) 668 { 669 push_U($In::Opt{"DefaultLibPaths"}, grep { isAbsPath($_) } ( 670 split(/:|;/, $ENV{"BELIBRARIES"}), 671 split(/:|;/, $ENV{"LIBRARY_PATH"}) 672 )); 673 } 674 } 675 if($LSearch) 676 { # using linker to get system paths 677 if(my $LPaths = detectLibDefaultPaths()) 678 { # unix-like 679 my %Dirs = (); 680 foreach my $Name (keys(%{$LPaths})) 681 { 682 if(my $SystemRoot = $In::Opt{"SystemRoot"}) 683 { 684 if($LPaths->{$Name}!~/\A\Q$SystemRoot\E\//) 685 { # wrong ldconfig configuration 686 # check your <sysroot>/etc/ld.so.conf 687 next; 688 } 689 } 690 691 $In::Opt{"LibDefaultPath"}{$Name} = $LPaths->{$Name}; 692 if(my $Dir = getDirname($LPaths->{$Name})) { 693 $Dirs{$Dir} = 1; 694 } 695 } 696 push_U($In::Opt{"DefaultLibPaths"}, sort {getDepth($a)<=>getDepth($b)} sort keys(%Dirs)); 697 } 698 push_U($In::Opt{"SysPaths"}{"lib"}, @{$In::Opt{"DefaultLibPaths"}}); 699 700 if(my $EDir = $In::Opt{"ExtraInfo"}) { 701 writeFile($EDir."/default-libs", join("\n", @{$In::Opt{"DefaultLibPaths"}})); 702 } 703 } 704 705 if($BSearch) 706 { 707 if($In::Opt{"CrossPrefix"}) 708 { 709 if(my $GccPath = getGccPath()) 710 { 711 $In::Opt{"GccPath"} = $GccPath; 712 if(my $D = getDirname($GccPath)) { 713 $In::Opt{"TargetTools"}{$D}=1; 714 } 715 } 716 } 717 } 718 719 if($GSearch and my $GccPath = getGccPath()) 720 { # GCC path and default include dirs 721 $In::Opt{"GccPath"} = $GccPath; 722 723 my $GccVer = dumpVersion($GccPath); 724 725 if($GccVer=~/\A\d+\.\d+\Z/) 726 { # on Ubuntu -dumpversion returns 4.8 for gcc 4.8.4 727 my $Info = `$GccPath --version`; 728 729 if($Info=~/gcc\s+(|\([^()]+\)\s+)(\d+\.\d+\.\d+)/) 730 { # gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 731 # gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6) 732 $GccVer = $2; 733 } 734 } 735 736 if($In::Opt{"OS"}=~/macos/) 737 { 738 my $Info = `$GccPath --version`; 739 740 if($Info=~/clang/i) { 741 printMsg("WARNING", "doesn't work with clang, please install GCC instead (and select it by -gcc-path option)"); 742 } 743 } 744 745 if($GccVer) 746 { 747 my $Target = dumpMachine($GccPath); 748 749 if($Target=~/linux/) { 750 setTarget("linux"); 751 } 752 elsif($Target=~/symbian/) { 753 setTarget("symbian"); 754 } 755 elsif($Target=~/solaris/) { 756 setTarget("solaris"); 757 } 758 759 $In::Opt{"GccTarget"} = $Target; 760 $In::Opt{"GccVer"} = $GccVer; 761 762 printMsg("INFO", "Using GCC $GccVer ($Target, target: ".getArch_GCC(1).")"); 763 764 # check GCC version 765 if($GccVer=~/\A(4\.8(|\.[012])|[67](\..*)?)\Z/ or cmpVersions($GccVer, "8")>=0) 766 { # GCC 4.8.[0-2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850 767 # GCC 6.[1-2].0: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78040 768 # GCC 7.1: still the same issue ... 769 # GCC 8: still the same issue ... 770 # ABICC 2.3: enable this for all future GCC versions 771 printMsg("WARNING", "May not work properly with GCC 4.8.[0-2], 6.* and higher due to bug #78040 in GCC. Please try other GCC versions with the help of --gcc-path=PATH option or create ABI dumps by ABI Dumper tool instead to avoid using GCC. Test selected GCC version first by -test option."); 772 $In::Opt{"GccMissedMangling"} = 1; 773 } 774 } 775 else { 776 exitStatus("Error", "something is going wrong with the GCC compiler"); 777 } 778 } 779 780 if($HSearch) 781 { 782 # GCC standard paths 783 if($In::Opt{"GccPath"} 784 and not $In::Opt{"NoStdInc"}) 785 { 786 my %DPaths = detectIncDefaultPaths(); 787 @DefaultCppPaths = @{$DPaths{"Cpp"}}; 788 @DefaultGccPaths = @{$DPaths{"Gcc"}}; 789 @DefaultIncPaths = @{$DPaths{"Inc"}}; 790 push_U($In::Opt{"SysPaths"}{"include"}, @DefaultIncPaths); 791 } 792 793 # users include paths 794 my $IncPath = "/usr/include"; 795 if(my $SystemRoot = $In::Opt{"SystemRoot"}) { 796 $IncPath = $SystemRoot.$IncPath; 797 } 798 if(-d $IncPath) { 799 push_U(\@UsersIncPath, $IncPath); 800 } 801 802 if(my $EDir = $In::Opt{"ExtraInfo"}) { 803 writeFile($EDir."/default-includes", join("\n", (@DefaultCppPaths, @DefaultGccPaths, @DefaultIncPaths))); 804 } 805 } 806 807 808} 809 810sub detectLibDefaultPaths() 811{ 812 my %LPaths = (); 813 814 my $TmpDir = $In::Opt{"Tmp"}; 815 816 if($In::Opt{"OS"} eq "bsd") 817 { 818 if(my $LdConfig = getCmdPath("ldconfig")) 819 { 820 foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TmpDir/null\"`)) 821 { 822 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) 823 { 824 my $Name = "lib".$1; 825 if(not defined $LPaths{$Name}) { 826 $LPaths{$Name} = $2; 827 } 828 } 829 } 830 } 831 else { 832 printMsg("WARNING", "can't find ldconfig"); 833 } 834 } 835 else 836 { 837 if(my $LdConfig = getCmdPath("ldconfig")) 838 { 839 if(my $SystemRoot = $In::Opt{"SystemRoot"} 840 and $In::Opt{"OS"} eq "linux") 841 { # use host (x86) ldconfig with the target (arm) ld.so.conf 842 if(-e $SystemRoot."/etc/ld.so.conf") { 843 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf"; 844 } 845 } 846 foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TmpDir/null\"`)) 847 { 848 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/) 849 { 850 my ($Name, $Path) = ($1, $2); 851 $Path=~s/[\/]{2,}/\//; 852 if(not defined $LPaths{$Name}) 853 { # get first element from the list of available paths 854 855 # libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 856 # libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6 857 # libstdc++.so.6 (libc6) => /usr/lib32/libstdc++.so.6 858 859 $LPaths{$Name} = $Path; 860 } 861 } 862 } 863 } 864 elsif($In::Opt{"OS"} eq "linux") { 865 printMsg("WARNING", "can't find ldconfig"); 866 } 867 } 868 return \%LPaths; 869} 870 871sub detectBinDefaultPaths() 872{ 873 my $EnvPaths = $ENV{"PATH"}; 874 if($In::Opt{"OS"} eq "beos") { 875 $EnvPaths.=":".$ENV{"BETOOLS"}; 876 } 877 my $Sep = ":|;"; 878 if($In::Opt{"OS"} eq "windows") { 879 $Sep = ";"; 880 } 881 882 foreach my $Path (split(/$Sep/, $EnvPaths)) 883 { 884 $Path = pathFmt($Path); 885 if(not $Path) { 886 next; 887 } 888 if(my $SystemRoot = $In::Opt{"SystemRoot"}) 889 { 890 if($Path=~/\A\Q$SystemRoot\E\//) 891 { # do NOT use binaries from target system 892 next; 893 } 894 } 895 push_U(\@DefaultBinPaths, $Path); 896 } 897} 898 899sub detectIncDefaultPaths() 900{ 901 my $GccPath = $In::Opt{"GccPath"}; 902 my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]); 903 904 my $TmpDir = $In::Opt{"Tmp"}; 905 writeFile("$TmpDir/empty.h", ""); 906 907 foreach my $Line (split(/\n/, `$GccPath -v -x c++ -E \"$TmpDir/empty.h\" 2>&1`)) 908 { # detecting GCC default include paths 909 if(index($Line, "/cc1plus ")!=-1) { 910 next; 911 } 912 913 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/) 914 { 915 my $Path = realpath_F($1); 916 if(index($Path, "c++")!=-1 917 or index($Path, "/g++/")!=-1) 918 { 919 push_U($DPaths{"Cpp"}, $Path); 920 if(not defined $In::Opt{"MainCppDir"} 921 or getDepth($In::Opt{"MainCppDir"})>getDepth($Path)) { 922 $In::Opt{"MainCppDir"} = $Path; 923 } 924 } 925 elsif(index($Path, "gcc")!=-1) { 926 push_U($DPaths{"Gcc"}, $Path); 927 } 928 else 929 { 930 if($Path=~/local[\/\\]+include/) 931 { # local paths 932 next; 933 } 934 if(my $SystemRoot = $In::Opt{"SystemRoot"}) 935 { 936 if($Path!~/\A\Q$SystemRoot\E(\/|\Z)/) 937 { # The GCC include path for user headers is not a part of the system root 938 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler 939 # or it is the internal cross-GCC path like arm-linux-gnueabi/include 940 next; 941 } 942 } 943 push_U($DPaths{"Inc"}, $Path); 944 } 945 } 946 } 947 unlink("$TmpDir/empty.h"); 948 return %DPaths; 949} 950 951sub registerGccHeaders() 952{ 953 if($Cache{"registerGccHeaders"}) 954 { # this function should be called once 955 return; 956 } 957 958 foreach my $Path (@DefaultGccPaths) 959 { 960 my @Headers = cmdFind($Path,"f"); 961 @Headers = sort {getDepth($a)<=>getDepth($b)} @Headers; 962 foreach my $HPath (@Headers) 963 { 964 my $FileName = getFilename($HPath); 965 if(not defined $DefaultGccHeader{$FileName}) 966 { # skip duplicated 967 $DefaultGccHeader{$FileName} = $HPath; 968 } 969 } 970 } 971 $Cache{"registerGccHeaders"} = 1; 972} 973 974sub registerCppHeaders() 975{ 976 if($Cache{"registerCppHeaders"}) 977 { # this function should be called once 978 return; 979 } 980 981 foreach my $CppDir (@DefaultCppPaths) 982 { 983 my @Headers = cmdFind($CppDir,"f"); 984 @Headers = sort {getDepth($a)<=>getDepth($b)} @Headers; 985 foreach my $Path (@Headers) 986 { 987 my $FileName = getFilename($Path); 988 if(not defined $DefaultCppHeader{$FileName}) 989 { # skip duplicated 990 $DefaultCppHeader{$FileName} = $Path; 991 } 992 } 993 } 994 $Cache{"registerCppHeaders"} = 1; 995} 996 997sub parseRedirect($$$) 998{ 999 my ($Content, $Path, $LVer) = @_; 1000 my @Errors = (); 1001 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) { 1002 push(@Errors, $1); 1003 } 1004 my $Redirect = ""; 1005 foreach (@Errors) 1006 { 1007 s/\s{2,}/ /g; 1008 if(/(only|must\ include 1009 |update\ to\ include 1010 |replaced\ with 1011 |replaced\ by|renamed\ to 1012 |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix) 1013 { 1014 $Redirect = $2; 1015 last; 1016 } 1017 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i) 1018 { 1019 $Redirect = $2; 1020 last; 1021 } 1022 elsif(/this\ header\ should\ not\ be\ used 1023 |programs\ should\ not\ directly\ include 1024 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header)) 1025 |is\ not\ supported\ API\ for\ general\ use 1026 |do\ not\ use 1027 |should\ not\ be\ (used|using) 1028 |cannot\ be\ included\ directly/ix and not /\ from\ /i) { 1029 $Header_ShouldNotBeUsed{$LVer}{$Path} = 1; 1030 } 1031 } 1032 if($Redirect) 1033 { 1034 $Redirect=~s/\A<//g; 1035 $Redirect=~s/>\Z//g; 1036 } 1037 return $Redirect; 1038} 1039 1040sub parseIncludes($$) 1041{ 1042 my ($Content, $Path) = @_; 1043 my %Includes = (); 1044 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*([<"].+?[">])[ \t]*//m) 1045 { # C/C++: include, Objective C/C++: import directive 1046 my $Header = $2; 1047 my $Method = substr($Header, 0, 1, ""); 1048 substr($Header, length($Header)-1, 1, ""); 1049 $Header = pathFmt($Header); 1050 if($Method eq "\"" or isAbsPath($Header)) 1051 { 1052 if(-e join_P(getDirname($Path), $Header)) 1053 { # relative path exists 1054 $Includes{$Header} = -1; 1055 } 1056 else 1057 { # include "..." that doesn't exist is equal to include <...> 1058 $Includes{$Header} = 2; 1059 } 1060 } 1061 else { 1062 $Includes{$Header} = 1; 1063 } 1064 } 1065 if($In::Opt{"ExtraInfo"}) 1066 { 1067 while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]+(\w+)[ \t]*//m) 1068 { # FT_FREETYPE_H 1069 $Includes{$2} = 0; 1070 } 1071 } 1072 return \%Includes; 1073} 1074 1075sub sortHeaders($$) 1076{ 1077 my ($H1, $H2) = @_; 1078 1079 $H1=~s/\.[a-z]+\Z//ig; 1080 $H2=~s/\.[a-z]+\Z//ig; 1081 1082 my $Hname1 = getFilename($H1); 1083 my $Hname2 = getFilename($H2); 1084 my $HDir1 = getDirname($H1); 1085 my $HDir2 = getDirname($H2); 1086 my $Dirname1 = getFilename($HDir1); 1087 my $Dirname2 = getFilename($HDir2); 1088 1089 $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 1090 $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; 1091 1092 if($_[0] eq $_[1] 1093 or $H1 eq $H2) { 1094 return 0; 1095 } 1096 elsif($H1=~/\A\Q$H2\E/) { 1097 return 1; 1098 } 1099 elsif($H2=~/\A\Q$H1\E/) { 1100 return -1; 1101 } 1102 elsif($HDir1=~/\Q$Hname1\E/i 1103 and $HDir2!~/\Q$Hname2\E/i) 1104 { # include/glib-2.0/glib.h 1105 return -1; 1106 } 1107 elsif($HDir2=~/\Q$Hname2\E/i 1108 and $HDir1!~/\Q$Hname1\E/i) 1109 { # include/glib-2.0/glib.h 1110 return 1; 1111 } 1112 elsif($Hname1=~/\Q$Dirname1\E/i 1113 and $Hname2!~/\Q$Dirname2\E/i) 1114 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 1115 return -1; 1116 } 1117 elsif($Hname2=~/\Q$Dirname2\E/i 1118 and $Hname1!~/\Q$Dirname1\E/i) 1119 { # include/hildon-thumbnail/hildon-thumbnail-factory.h 1120 return 1; 1121 } 1122 elsif($Hname1=~/(config|lib|util)/i 1123 and $Hname2!~/(config|lib|util)/i) 1124 { # include/alsa/asoundlib.h 1125 return -1; 1126 } 1127 elsif($Hname2=~/(config|lib|util)/i 1128 and $Hname1!~/(config|lib|util)/i) 1129 { # include/alsa/asoundlib.h 1130 return 1; 1131 } 1132 else 1133 { 1134 my $R1 = checkRelevance($H1); 1135 my $R2 = checkRelevance($H2); 1136 if($R1 and not $R2) 1137 { # libebook/e-book.h 1138 return -1; 1139 } 1140 elsif($R2 and not $R1) 1141 { # libebook/e-book.h 1142 return 1; 1143 } 1144 else 1145 { 1146 return (lc($H1) cmp lc($H2)); 1147 } 1148 } 1149} 1150 1151sub detectRealIncludes($$) 1152{ 1153 my ($AbsPath, $LVer) = @_; 1154 1155 if($Cache{"detectRealIncludes"}{$LVer}{$AbsPath} 1156 or keys(%{$RecursiveIncludes{$LVer}{$AbsPath}})) { 1157 return keys(%{$RecursiveIncludes{$LVer}{$AbsPath}}); 1158 } 1159 $Cache{"detectRealIncludes"}{$LVer}{$AbsPath}=1; 1160 1161 my $Path = callPreprocessor($AbsPath, "", $LVer); 1162 if(not $Path) { 1163 return (); 1164 } 1165 open(PREPROC, $Path); 1166 while(<PREPROC>) 1167 { 1168 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/) 1169 { 1170 my $Include = pathFmt($1); 1171 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) { 1172 next; 1173 } 1174 if($Include eq $AbsPath) { 1175 next; 1176 } 1177 $RecursiveIncludes{$LVer}{$AbsPath}{$Include} = 1; 1178 } 1179 } 1180 close(PREPROC); 1181 return keys(%{$RecursiveIncludes{$LVer}{$AbsPath}}); 1182} 1183 1184sub detectHeaderIncludes($$) 1185{ 1186 my ($Path, $LVer) = @_; 1187 1188 if(defined $Cache{"detectHeaderIncludes"}{$LVer}{$Path}) { 1189 return; 1190 } 1191 $Cache{"detectHeaderIncludes"}{$LVer}{$Path}=1; 1192 1193 if(not -e $Path) { 1194 return; 1195 } 1196 1197 my $Content = readFile($Path); 1198 if(my $Redirect = parseRedirect($Content, $Path, $LVer)) 1199 { # detect error directive in headers 1200 if(my $RedirectPath = identifyHeader($Redirect, $LVer)) 1201 { 1202 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) { 1203 $RedirectPath = identifyHeader(getFilename($Redirect), $LVer); 1204 } 1205 if($RedirectPath ne $Path) { 1206 $Header_ErrorRedirect{$LVer}{$Path} = $RedirectPath; 1207 } 1208 } 1209 else 1210 { # can't find 1211 $Header_ShouldNotBeUsed{$LVer}{$Path} = 1; 1212 } 1213 } 1214 if(my $Inc = parseIncludes($Content, $Path)) 1215 { 1216 foreach my $Include (keys(%{$Inc})) 1217 { # detect includes 1218 $Header_Includes{$LVer}{$Path}{$Include} = $Inc->{$Include}; 1219 1220 if(defined $In::Opt{"Tolerance"} 1221 and $In::Opt{"Tolerance"}=~/4/) 1222 { 1223 if(my $HPath = identifyHeader($Include, $LVer)) 1224 { 1225 $Header_Includes_R{$LVer}{$HPath}{$Path} = 1; 1226 } 1227 } 1228 } 1229 } 1230} 1231 1232sub fromLibc($) 1233{ # system GLIBC header 1234 my $Path = $_[0]; 1235 my ($Dir, $Name) = sepPath($Path); 1236 if($In::Opt{"Target"} eq "symbian") 1237 { 1238 if(getFilename($Dir) eq "libc" and $GlibcHeader{$Name}) 1239 { # epoc32/include/libc/{stdio, ...}.h 1240 return 1; 1241 } 1242 } 1243 else 1244 { 1245 if($Dir eq "/usr/include" and $GlibcHeader{$Name}) 1246 { # /usr/include/{stdio, ...}.h 1247 return 1; 1248 } 1249 } 1250 return 0; 1251} 1252 1253sub isLibcDir($) 1254{ # system GLIBC directory 1255 my $Dir = $_[0]; 1256 my ($OutDir, $Name) = sepPath($Dir); 1257 if($In::Opt{"Target"} eq "symbian") 1258 { 1259 if(getFilename($OutDir) eq "libc" 1260 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 1261 { # epoc32/include/libc/{sys,bits,asm,asm-*}/*.h 1262 return 1; 1263 } 1264 } 1265 else 1266 { # linux 1267 if($OutDir eq "/usr/include" 1268 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) 1269 { # /usr/include/{sys,bits,asm,asm-*}/*.h 1270 return 1; 1271 } 1272 } 1273 return 0; 1274} 1275 1276sub detectRecursiveIncludes($$) 1277{ 1278 my ($AbsPath, $LVer) = @_; 1279 if(not $AbsPath) { 1280 return (); 1281 } 1282 if(isCyclical(\@RecurInclude, $AbsPath)) { 1283 return keys(%{$RecursiveIncludes{$LVer}{$AbsPath}}); 1284 } 1285 my ($AbsDir, $Name) = sepPath($AbsPath); 1286 if(isLibcDir($AbsDir)) 1287 { # system GLIBC internals 1288 if(not $In::Opt{"ExtraInfo"}) { 1289 return (); 1290 } 1291 } 1292 if(keys(%{$RecursiveIncludes{$LVer}{$AbsPath}})) { 1293 return keys(%{$RecursiveIncludes{$LVer}{$AbsPath}}); 1294 } 1295 if($In::Opt{"OS"} ne "windows" 1296 and $Name=~/windows|win32|win64/i) { 1297 return (); 1298 } 1299 1300 if($In::Opt{"MainCppDir"} and $AbsPath=~/\A\Q$In::Opt{"MainCppDir"}\E/ and not $In::Opt{"StdcxxTesting"}) 1301 { # skip /usr/include/c++/*/ headers 1302 if(not $In::Opt{"ExtraInfo"}) { 1303 return (); 1304 } 1305 } 1306 1307 push(@RecurInclude, $AbsPath); 1308 if(grep { $AbsDir eq $_ } @DefaultGccPaths 1309 or (grep { $AbsDir eq $_ } @DefaultIncPaths and fromLibc($AbsPath))) 1310 { # check "real" (non-"model") include paths 1311 my @Paths = detectRealIncludes($AbsPath, $LVer); 1312 pop(@RecurInclude); 1313 return @Paths; 1314 } 1315 if(not keys(%{$Header_Includes{$LVer}{$AbsPath}})) { 1316 detectHeaderIncludes($AbsPath, $LVer); 1317 } 1318 foreach my $Include (keys(%{$Header_Includes{$LVer}{$AbsPath}})) 1319 { 1320 my $IncType = $Header_Includes{$LVer}{$AbsPath}{$Include}; 1321 my $HPath = ""; 1322 if($IncType<0) 1323 { # for #include "..." 1324 my $Candidate = join_P($AbsDir, $Include); 1325 if(-f $Candidate) { 1326 $HPath = realpath_F($Candidate); 1327 } 1328 } 1329 elsif($IncType>0 1330 and $Include=~/[\/\\]/) # and not findInDefaults($Include) 1331 { # search for the nearest header 1332 # QtCore/qabstractanimation.h includes <QtCore/qobject.h> 1333 my $Candidate = join_P(getDirname($AbsDir), $Include); 1334 if(-f $Candidate) { 1335 $HPath = $Candidate; 1336 } 1337 } 1338 if(not $HPath) { 1339 $HPath = identifyHeader($Include, $LVer); 1340 } 1341 next if(not $HPath); 1342 if($HPath eq $AbsPath) { 1343 next; 1344 } 1345 1346 #if($In::Opt{"Debug"}) 1347 #{ # boundary headers 1348 # if($HPath=~/vtk/ and $AbsPath!~/vtk/) 1349 # { 1350 # print STDERR "$AbsPath -> $HPath\n"; 1351 # } 1352 #} 1353 1354 $RecursiveIncludes{$LVer}{$AbsPath}{$HPath} = $IncType; 1355 if($IncType>0) 1356 { # only include <...>, skip include "..." prefixes 1357 $Header_Include_Prefix{$LVer}{$AbsPath}{$HPath}{getDirname($Include)} = 1; 1358 } 1359 foreach my $IncPath (detectRecursiveIncludes($HPath, $LVer)) 1360 { 1361 if($IncPath eq $AbsPath) { 1362 next; 1363 } 1364 my $RIncType = $RecursiveIncludes{$LVer}{$HPath}{$IncPath}; 1365 if($RIncType==-1) 1366 { # include "..." 1367 $RIncType = $IncType; 1368 } 1369 elsif($RIncType==2) 1370 { 1371 if($IncType!=-1) { 1372 $RIncType = $IncType; 1373 } 1374 } 1375 $RecursiveIncludes{$LVer}{$AbsPath}{$IncPath} = $RIncType; 1376 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LVer}{$HPath}{$IncPath}})) { 1377 $Header_Include_Prefix{$LVer}{$AbsPath}{$IncPath}{$Prefix} = 1; 1378 } 1379 } 1380 foreach my $Dep (keys(%{$Header_Include_Prefix{$LVer}{$AbsPath}})) 1381 { 1382 if($GlibcHeader{getFilename($Dep)} and keys(%{$Header_Include_Prefix{$LVer}{$AbsPath}{$Dep}})>=2 1383 and defined $Header_Include_Prefix{$LVer}{$AbsPath}{$Dep}{""}) 1384 { # distinguish math.h from glibc and math.h from the tested library 1385 delete($Header_Include_Prefix{$LVer}{$AbsPath}{$Dep}{""}); 1386 last; 1387 } 1388 } 1389 } 1390 pop(@RecurInclude); 1391 return keys(%{$RecursiveIncludes{$LVer}{$AbsPath}}); 1392} 1393 1394sub findInFramework($$$) 1395{ 1396 my ($Header, $Framework, $LVer) = @_; 1397 1398 if(defined $Cache{"findInFramework"}{$LVer}{$Framework}{$Header}) { 1399 return $Cache{"findInFramework"}{$LVer}{$Framework}{$Header}; 1400 } 1401 foreach my $Dependency (sort {getDepth($a)<=>getDepth($b)} keys(%{$Header_Dependency{$LVer}})) 1402 { 1403 if(getFilename($Dependency) eq $Framework 1404 and -f getDirname($Dependency)."/".$Header) { 1405 return ($Cache{"findInFramework"}{$LVer}{$Framework}{$Header} = getDirname($Dependency)); 1406 } 1407 } 1408 return ($Cache{"findInFramework"}{$LVer}{$Framework}{$Header} = ""); 1409} 1410 1411sub findInDefaults($) 1412{ 1413 my $Header = $_[0]; 1414 1415 if(defined $Cache{"findInDefaults"}{$Header}) { 1416 return $Cache{"findInDefaults"}{$Header}; 1417 } 1418 foreach my $Dir (@DefaultIncPaths, 1419 @DefaultGccPaths, 1420 @DefaultCppPaths, 1421 @UsersIncPath) 1422 { 1423 if(not $Dir) { 1424 next; 1425 } 1426 if(-f $Dir."/".$Header) { 1427 return ($Cache{"findInDefaults"}{$Header}=$Dir); 1428 } 1429 } 1430 return ($Cache{"findInDefaults"}{$Header} = ""); 1431} 1432 1433sub cmp_paths($$) 1434{ 1435 my ($Path1, $Path2) = @_; 1436 my @Parts1 = split(/[\/\\]/, $Path1); 1437 my @Parts2 = split(/[\/\\]/, $Path2); 1438 foreach my $Num (0 .. $#Parts1) 1439 { 1440 my $Part1 = $Parts1[$Num]; 1441 my $Part2 = $Parts2[$Num]; 1442 if($GlibcDir{$Part1} 1443 and not $GlibcDir{$Part2}) { 1444 return 1; 1445 } 1446 elsif($GlibcDir{$Part2} 1447 and not $GlibcDir{$Part1}) { 1448 return -1; 1449 } 1450 elsif($Part1=~/glib/ 1451 and $Part2!~/glib/) { 1452 return 1; 1453 } 1454 elsif($Part1!~/glib/ 1455 and $Part2=~/glib/) { 1456 return -1; 1457 } 1458 elsif(my $CmpRes = ($Part1 cmp $Part2)) { 1459 return $CmpRes; 1460 } 1461 } 1462 return 0; 1463} 1464 1465sub checkRelevance($) 1466{ 1467 my $Path = $_[0]; 1468 1469 if(my $SystemRoot = $In::Opt{"SystemRoot"}) { 1470 $Path = cutPrefix($Path, $SystemRoot); 1471 } 1472 1473 my $Name = lc(getFilename($Path)); 1474 my $Dir = lc(getDirname($Path)); 1475 1476 $Name=~s/\.\w+\Z//g; # remove extension (.h) 1477 1478 foreach my $Token (split(/[_\d\W]+/, $Name)) 1479 { 1480 my $Len = length($Token); 1481 next if($Len<=1); 1482 if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/) 1483 { # include/evolution-data-server-1.4/libebook/e-book.h 1484 return 1; 1485 } 1486 if($Len>=4 and index($Dir, $Token)!=-1) 1487 { # include/gupnp-1.0/libgupnp/gupnp-context.h 1488 return 1; 1489 } 1490 } 1491 return 0; 1492} 1493 1494sub checkFamily(@) 1495{ 1496 my @Paths = @_; 1497 if($#Paths<=0) { 1498 return 1; 1499 } 1500 my %Prefix = (); 1501 foreach my $Path (@Paths) 1502 { 1503 if(my $SystemRoot = $In::Opt{"SystemRoot"}) { 1504 $Path = cutPrefix($Path, $SystemRoot); 1505 } 1506 if(my $Dir = getDirname($Path)) 1507 { 1508 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix 1509 $Prefix{$Dir} += 1; 1510 $Prefix{getDirname($Dir)} += 1; 1511 } 1512 } 1513 foreach (sort keys(%Prefix)) 1514 { 1515 if(getDepth($_)>=3 1516 and $Prefix{$_}==$#Paths+1) { 1517 return 1; 1518 } 1519 } 1520 return 0; 1521} 1522 1523sub isAcceptable($$$) 1524{ 1525 my ($Header, $Candidate, $LVer) = @_; 1526 my $HName = getFilename($Header); 1527 if(getDirname($Header)) 1528 { # with prefix 1529 return 1; 1530 } 1531 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/) 1532 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/ 1533 return 1; 1534 } 1535 if(checkRelevance($Candidate)) 1536 { # allow to search for atk.h in /usr/include/atk-1.0/atk/ 1537 return 1; 1538 } 1539 if(checkFamily(getSystemHeaders($HName, $LVer))) 1540 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h 1541 # /usr/include/qt4/Qt/qsslconfiguration.h 1542 return 1; 1543 } 1544 if($In::Opt{"Target"} eq "symbian") 1545 { 1546 if($Candidate=~/[\/\\]stdapis[\/\\]/) { 1547 return 1; 1548 } 1549 } 1550 return 0; 1551} 1552 1553sub isRelevant($$$) 1554{ # disallow to search for "abstract" headers in too deep directories 1555 my ($Header, $Candidate, $LVer) = @_; 1556 my $HName = getFilename($Header); 1557 if($In::Opt{"Target"} eq "symbian") 1558 { 1559 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) { 1560 return 0; 1561 } 1562 } 1563 if($In::Opt{"Target"} ne "bsd") 1564 { 1565 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/) 1566 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h 1567 return 0; 1568 } 1569 } 1570 if($In::Opt{"Target"} ne "windows") 1571 { 1572 if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/) 1573 { # skip /usr/include/wine/msvcrt 1574 return 0; 1575 } 1576 } 1577 if(not getDirname($Header) 1578 and $Candidate=~/[\/\\]wx[\/\\]/) 1579 { # do NOT search in system /wx/ directory 1580 # for headers without a prefix: sstream.h 1581 return 0; 1582 } 1583 if($Candidate=~/c\+\+[\/\\]\d+/ and $In::Opt{"MainCppDir"} 1584 and $Candidate!~/\A\Q$In::Opt{"MainCppDir"}\E/) 1585 { # skip ../c++/3.3.3/ if using ../c++/4.5/ 1586 return 0; 1587 } 1588 if($Candidate=~/[\/\\]asm-/ 1589 and (my $Arch = getArch_GCC($LVer)) ne "unknown") 1590 { # arch-specific header files 1591 if($Candidate!~/[\/\\]asm-\Q$Arch\E/) 1592 {# skip ../asm-arm/ if using x86 architecture 1593 return 0; 1594 } 1595 } 1596 my @Candidates = getSystemHeaders($HName, $LVer); 1597 if($#Candidates==1) 1598 { # unique header 1599 return 1; 1600 } 1601 my @SCandidates = getSystemHeaders($Header, $LVer); 1602 if($#SCandidates==1) 1603 { # unique name 1604 return 1; 1605 } 1606 my $SystemDepth = 0; 1607 1608 if(my $SystemRoot = $In::Opt{"SystemRoot"}) { 1609 $SystemDepth = getDepth($SystemRoot); 1610 } 1611 1612 if(getDepth($Candidate)-$SystemDepth>=5) 1613 { # abstract headers in too deep directories 1614 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/ 1615 if(not isAcceptable($Header, $Candidate, $LVer)) { 1616 return 0; 1617 } 1618 } 1619 if($Header eq "parser.h" 1620 and $Candidate!~/\/libxml2\//) 1621 { # select parser.h from xml2 library 1622 return 0; 1623 } 1624 if(not getDirname($Header) 1625 and keys(%{$SystemHeaders{$HName}})>=3) 1626 { # many headers with the same name 1627 # like thread.h included without a prefix 1628 if(not checkFamily(@Candidates)) { 1629 return 0; 1630 } 1631 } 1632 return 1; 1633} 1634 1635sub selectSystemHeader($$) 1636{ # cache function 1637 if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) { 1638 return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}; 1639 } 1640 return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_)); 1641} 1642 1643sub selectSystemHeader_I($$) 1644{ 1645 my ($Header, $LVer) = @_; 1646 if(-f $Header) { 1647 return $Header; 1648 } 1649 if(isAbsPath($Header) and not -f $Header) 1650 { # incorrect absolute path 1651 return ""; 1652 } 1653 if(defined $ConfHeaders{lc($Header)}) 1654 { # too abstract configuration headers 1655 return ""; 1656 } 1657 my $HName = getFilename($Header); 1658 if($In::Opt{"OS"} ne "windows") 1659 { 1660 if(defined $WinHeaders{lc($HName)} 1661 or $HName=~/windows|win32|win64/i) 1662 { # windows headers 1663 return ""; 1664 } 1665 } 1666 if($In::Opt{"OS"} ne "macos") 1667 { 1668 if($HName eq "fp.h") 1669 { # pngconf.h includes fp.h in Mac OS 1670 return ""; 1671 } 1672 } 1673 1674 if(defined $ObsoleteHeaders{$HName}) 1675 { # obsolete headers 1676 return ""; 1677 } 1678 if($In::Opt{"OS"} eq "linux" 1679 or $In::Opt{"OS"} eq "bsd") 1680 { 1681 if(defined $AlienHeaders{$HName} 1682 or defined $AlienHeaders{$Header}) 1683 { # alien headers from other systems 1684 return ""; 1685 } 1686 } 1687 1688 foreach my $Path (@{$In::Opt{"SysPaths"}{"include"}}) 1689 { # search in default paths 1690 if(-f $Path."/".$Header) { 1691 return join_P($Path,$Header); 1692 } 1693 } 1694 1695 # register all headers in system include dirs 1696 checkSystemFiles(); 1697 1698 foreach my $Candidate (sort {getDepth($a)<=>getDepth($b)} 1699 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LVer)) 1700 { 1701 if(isRelevant($Header, $Candidate, $LVer)) { 1702 return $Candidate; 1703 } 1704 } 1705 # error 1706 return ""; 1707} 1708 1709sub getSystemHeaders($$) 1710{ 1711 my ($Header, $LVer) = @_; 1712 my @Candidates = (); 1713 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}})) 1714 { 1715 if(skipHeader($Candidate, $LVer)) { 1716 next; 1717 } 1718 push(@Candidates, $Candidate); 1719 } 1720 return @Candidates; 1721} 1722 1723sub isDefaultIncludeDir($) 1724{ 1725 my $Dir = $_[0]; 1726 $Dir=~s/[\/\\]+\Z//; 1727 return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths); 1728} 1729 1730sub identifyHeader($$) 1731{ # cache function 1732 my ($Header, $LVer) = @_; 1733 if(not $Header) { 1734 return ""; 1735 } 1736 $Header=~s/\A(\.\.[\\\/])+//g; 1737 if(defined $Cache{"identifyHeader"}{$LVer}{$Header}) { 1738 return $Cache{"identifyHeader"}{$LVer}{$Header}; 1739 } 1740 return ($Cache{"identifyHeader"}{$LVer}{$Header} = identifyHeader_I($Header, $LVer)); 1741} 1742 1743sub identifyHeader_I($$) 1744{ # search for header by absolute path, relative path or name 1745 my ($Header, $LVer) = @_; 1746 if(-f $Header) 1747 { # it's relative or absolute path 1748 return getAbsPath($Header); 1749 } 1750 elsif($GlibcHeader{$Header} and not $In::Opt{"GlibcTesting"} 1751 and my $HeaderDir = findInDefaults($Header)) 1752 { # search for libc headers in the /usr/include 1753 # for non-libc target library before searching 1754 # in the library paths 1755 return join_P($HeaderDir,$Header); 1756 } 1757 elsif(my $Path = $In::Desc{$LVer}{"IncludeNeighbors"}{$Header}) 1758 { # search in the target library paths 1759 return $Path; 1760 } 1761 elsif(defined $DefaultGccHeader{$Header}) 1762 { # search in the internal GCC include paths 1763 return $DefaultGccHeader{$Header}; 1764 } 1765 elsif(my $DefaultDir = findInDefaults($Header)) 1766 { # search in the default GCC include paths 1767 return join_P($DefaultDir,$Header); 1768 } 1769 elsif(defined $DefaultCppHeader{$Header}) 1770 { # search in the default G++ include paths 1771 return $DefaultCppHeader{$Header}; 1772 } 1773 elsif(my $AnyPath = selectSystemHeader($Header, $LVer)) 1774 { # search everywhere in the system 1775 return $AnyPath; 1776 } 1777 elsif($In::Opt{"OS"} eq "macos") 1778 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h" 1779 if(my $Dir = getDirname($Header)) 1780 { 1781 my $RelPath = "Headers\/".getFilename($Header); 1782 if(my $HeaderDir = findInFramework($RelPath, $Dir.".framework", $LVer)) { 1783 return join_P($HeaderDir, $RelPath); 1784 } 1785 } 1786 } 1787 # cannot find anything 1788 return ""; 1789} 1790 1791sub cmdFile($) 1792{ 1793 my $Path = $_[0]; 1794 1795 if(my $CmdPath = getCmdPath("file")) { 1796 return `$CmdPath -b \"$Path\"`; 1797 } 1798 return ""; 1799} 1800 1801sub getHeaderDeps($$) 1802{ 1803 my ($AbsPath, $LVer) = @_; 1804 1805 if(defined $Cache{"getHeaderDeps"}{$LVer}{$AbsPath}) { 1806 return @{$Cache{"getHeaderDeps"}{$LVer}{$AbsPath}}; 1807 } 1808 my %IncDir = (); 1809 detectRecursiveIncludes($AbsPath, $LVer); 1810 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LVer}{$AbsPath}})) 1811 { 1812 if(not $HeaderPath) { 1813 next; 1814 } 1815 if($In::Opt{"MainCppDir"} and $HeaderPath=~/\A\Q$In::Opt{"MainCppDir"}\E([\/\\]|\Z)/) { 1816 next; 1817 } 1818 my $Dir = getDirname($HeaderPath); 1819 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LVer}{$AbsPath}{$HeaderPath}})) 1820 { 1821 my $Dep = $Dir; 1822 if($Prefix) 1823 { 1824 if($In::Opt{"OS"} eq "windows") 1825 { # case insensitive seach on windows 1826 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) { 1827 next; 1828 } 1829 } 1830 elsif($In::Opt{"OS"} eq "macos") 1831 { # seach in frameworks 1832 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 1833 { 1834 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/) 1835 {# frameworks 1836 my ($HFramework, $HName) = ($1, $2); 1837 $Dep = $HFramework; 1838 } 1839 else 1840 {# mismatch 1841 next; 1842 } 1843 } 1844 } 1845 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) 1846 { # Linux, FreeBSD 1847 next; 1848 } 1849 } 1850 if(not $Dep) 1851 { # nothing to include 1852 next; 1853 } 1854 if(isDefaultIncludeDir($Dep)) 1855 { # included by the compiler 1856 next; 1857 } 1858 if(getDepth($Dep)==1) 1859 { # too short 1860 next; 1861 } 1862 if(isLibcDir($Dep)) 1863 { # do NOT include /usr/include/{sys,bits} 1864 next; 1865 } 1866 $IncDir{$Dep} = 1; 1867 } 1868 } 1869 $Cache{"getHeaderDeps"}{$LVer}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LVer); 1870 return @{$Cache{"getHeaderDeps"}{$LVer}{$AbsPath}}; 1871} 1872 1873sub sortIncPaths($$) 1874{ 1875 my ($ArrRef, $LVer) = @_; 1876 if(not $ArrRef or $#{$ArrRef}<0) { 1877 return $ArrRef; 1878 } 1879 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef}; 1880 @{$ArrRef} = sort {getDepth($a)<=>getDepth($b)} @{$ArrRef}; 1881 @{$ArrRef} = sort {sortDeps($b, $a, $LVer)} @{$ArrRef}; 1882 return $ArrRef; 1883} 1884 1885sub sortDeps($$$) 1886{ 1887 if($Header_Dependency{$_[2]}{$_[0]} 1888 and not $Header_Dependency{$_[2]}{$_[1]}) { 1889 return 1; 1890 } 1891 elsif(not $Header_Dependency{$_[2]}{$_[0]} 1892 and $Header_Dependency{$_[2]}{$_[1]}) { 1893 return -1; 1894 } 1895 return 0; 1896} 1897 1898sub registerHeader($$) 1899{ # input: absolute path of header, relative path or name 1900 my ($Header, $LVer) = @_; 1901 if(not $Header) { 1902 return ""; 1903 } 1904 if(isAbsPath($Header) and not -f $Header) 1905 { # incorrect absolute path 1906 exitStatus("Access_Error", "can't access \'$Header\'"); 1907 } 1908 if(skipHeader($Header, $LVer)) 1909 { # skip 1910 return ""; 1911 } 1912 if(my $Header_Path = identifyHeader($Header, $LVer)) 1913 { 1914 detectHeaderIncludes($Header_Path, $LVer); 1915 1916 if(defined $In::Opt{"Tolerance"} 1917 and $In::Opt{"Tolerance"}=~/3/) 1918 { # 3 - skip headers that include non-Linux headers 1919 if($In::Opt{"OS"} ne "windows") 1920 { 1921 foreach my $Inc (keys(%{$Header_Includes{$LVer}{$Header_Path}})) 1922 { 1923 if(specificHeader($Inc, "windows")) { 1924 return ""; 1925 } 1926 } 1927 } 1928 } 1929 1930 if(my $RHeader_Path = $Header_ErrorRedirect{$LVer}{$Header_Path}) 1931 { # redirect 1932 if($In::Desc{$LVer}{"RegHeader"}{$RHeader_Path}{"Identity"} 1933 or skipHeader($RHeader_Path, $LVer)) 1934 { # skip 1935 return ""; 1936 } 1937 $Header_Path = $RHeader_Path; 1938 } 1939 elsif($Header_ShouldNotBeUsed{$LVer}{$Header_Path}) 1940 { # skip 1941 return ""; 1942 } 1943 1944 if(my $HName = getFilename($Header_Path)) 1945 { # register 1946 $In::Desc{$LVer}{"RegHeader"}{$Header_Path}{"Identity"} = $HName; 1947 $HeaderName_Paths{$LVer}{$HName}{$Header_Path} = 1; 1948 } 1949 1950 if(($Header=~/\.(\w+)\Z/ and $1 ne "h") 1951 or $Header!~/\.(\w+)\Z/) 1952 { # hpp, hh, etc. 1953 $In::ABI{$LVer}{"Language"} = "C++"; 1954 $In::Opt{"CppHeaders"} = 1; 1955 } 1956 1957 if($Header=~/(\A|\/)c\+\+(\/|\Z)/) 1958 { # /usr/include/c++/4.6.1/... 1959 $In::Opt{"StdcxxTesting"} = 1; 1960 } 1961 1962 return $Header_Path; 1963 } 1964 return ""; 1965} 1966 1967sub registerDir($$$) 1968{ 1969 my ($Dir, $WithDeps, $LVer) = @_; 1970 $Dir=~s/[\/\\]+\Z//g; 1971 if(not $Dir) { 1972 return; 1973 } 1974 $Dir = getAbsPath($Dir); 1975 1976 my $Mode = "All"; 1977 if($WithDeps) 1978 { 1979 if($RegisteredDirs{$LVer}{$Dir}{1}) { 1980 return; 1981 } 1982 elsif($RegisteredDirs{$LVer}{$Dir}{0}) { 1983 $Mode = "DepsOnly"; 1984 } 1985 } 1986 else 1987 { 1988 if($RegisteredDirs{$LVer}{$Dir}{1} 1989 or $RegisteredDirs{$LVer}{$Dir}{0}) { 1990 return; 1991 } 1992 } 1993 $Header_Dependency{$LVer}{$Dir} = 1; 1994 $RegisteredDirs{$LVer}{$Dir}{$WithDeps} = 1; 1995 if($Mode eq "DepsOnly") 1996 { 1997 foreach my $Path (cmdFind($Dir,"d")) { 1998 $Header_Dependency{$LVer}{$Path} = 1; 1999 } 2000 return; 2001 } 2002 foreach my $Path (sort {length($b)<=>length($a)} cmdFind($Dir,"f")) 2003 { 2004 if($WithDeps) 2005 { 2006 my $SubDir = $Path; 2007 while(($SubDir = getDirname($SubDir)) ne $Dir) 2008 { # register all sub directories 2009 $Header_Dependency{$LVer}{$SubDir} = 1; 2010 } 2011 } 2012 if(isNotHeader($Path)) { 2013 next; 2014 } 2015 if(ignorePath($Path)) { 2016 next; 2017 } 2018 # Neighbors 2019 foreach my $Part (getPrefixes($Path)) { 2020 $In::Desc{$LVer}{"IncludeNeighbors"}{$Part} = $Path; 2021 } 2022 } 2023 if(getFilename($Dir) eq "include") 2024 { # search for "lib/include/" directory 2025 my $LibDir = $Dir; 2026 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) { 2027 registerDir($LibDir, $WithDeps, $LVer); 2028 } 2029 } 2030} 2031 2032sub getIncString($$) 2033{ 2034 my ($ArrRef, $Style) = @_; 2035 if(not $ArrRef or $#{$ArrRef}<0) { 2036 return ""; 2037 } 2038 2039 my $Str = ""; 2040 foreach (@{$ArrRef}) { 2041 $Str .= " ".includeOpt($_, $Style); 2042 } 2043 return $Str; 2044} 2045 2046sub getIncPaths($$) 2047{ 2048 my ($HRef, $LVer) = @_; 2049 2050 my @IncPaths = @{$Add_Include_Paths{$LVer}}; 2051 if($In::Desc{$LVer}{"AutoIncludePaths"}) 2052 { # auto-detecting dependencies 2053 my %Includes = (); 2054 foreach my $HPath (@{$HRef}) 2055 { 2056 foreach my $Dir (getHeaderDeps($HPath, $LVer)) 2057 { 2058 if($In::Desc{$LVer}{"SkipIncludePaths"}{$Dir}) { 2059 next; 2060 } 2061 if(my $SystemRoot = $In::Opt{"SystemRoot"}) 2062 { 2063 if($In::Desc{$LVer}{"SkipIncludePaths"}{$SystemRoot.$Dir}) { 2064 next; 2065 } 2066 } 2067 $Includes{$Dir} = 1; 2068 } 2069 } 2070 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $LVer)}) { 2071 push_U(\@IncPaths, $Dir); 2072 } 2073 } 2074 else 2075 { # user-defined paths 2076 @IncPaths = @{$Include_Paths{$LVer}}; 2077 } 2078 return \@IncPaths; 2079} 2080 2081sub searchForHeaders($) 2082{ 2083 my $LVer = $_[0]; 2084 2085 my $DescRef = $In::Desc{$LVer}; 2086 2087 # gcc standard include paths 2088 registerGccHeaders(); 2089 2090 if($In::ABI{$LVer}{"Language"} eq "C++" and not $In::Opt{"StdcxxTesting"}) 2091 { # c++ standard include paths 2092 registerCppHeaders(); 2093 } 2094 2095 # processing header paths 2096 my @HPaths = (); 2097 2098 if($DescRef->{"IncludePaths"}) { 2099 @HPaths = @{$DescRef->{"IncludePaths"}}; 2100 } 2101 2102 if($DescRef->{"AddIncludePaths"}) { 2103 @HPaths = (@HPaths, @{$DescRef->{"AddIncludePaths"}}); 2104 } 2105 2106 foreach my $Path (@HPaths) 2107 { 2108 my $IPath = $Path; 2109 if(my $SystemRoot = $In::Opt{"SystemRoot"}) 2110 { 2111 if(isAbsPath($Path)) { 2112 $Path = $SystemRoot.$Path; 2113 } 2114 } 2115 if(not -e $Path) { 2116 exitStatus("Access_Error", "can't access \'$Path\'"); 2117 } 2118 elsif(-f $Path) { 2119 exitStatus("Access_Error", "\'$Path\' - not a directory"); 2120 } 2121 elsif(-d $Path) 2122 { 2123 $Path = getAbsPath($Path); 2124 registerDir($Path, 0, $LVer); 2125 2126 if($DescRef->{"AddIncludePaths"} 2127 and grep {$IPath eq $_} @{$DescRef->{"AddIncludePaths"}}) { 2128 push(@{$Add_Include_Paths{$LVer}}, $Path); 2129 } 2130 else { 2131 push(@{$Include_Paths{$LVer}}, $Path); 2132 } 2133 } 2134 } 2135 2136 # registering directories 2137 my @Headers = keys(%{$DescRef->{"Headers"}}); 2138 @Headers = sort {$DescRef->{"Headers"}{$a}<=>$DescRef->{"Headers"}{$b}} @Headers; 2139 foreach my $Path (@Headers) 2140 { 2141 if(not -e $Path) { 2142 next; 2143 } 2144 $Path = getAbsPath($Path); 2145 if(-d $Path) { 2146 registerDir($Path, 1, $LVer); 2147 } 2148 elsif(-f $Path) 2149 { 2150 my $Dir = getDirname($Path); 2151 if(not grep { $Dir eq $_ } (@{$In::Opt{"SysPaths"}{"include"}}) 2152 and not $LocalIncludes{$Dir}) { 2153 registerDir($Dir, 1, $LVer); 2154 } 2155 } 2156 } 2157 2158 # clean memory 2159 %RegisteredDirs = (); 2160 2161 # registering headers 2162 my $Position = 0; 2163 foreach my $Path (@Headers) 2164 { 2165 if(isAbsPath($Path) and not -e $Path) { 2166 exitStatus("Access_Error", "can't access \'$Path\'"); 2167 } 2168 $Path = pathFmt($Path); 2169 if(isHeader($Path, 1, $LVer)) 2170 { 2171 if(my $HPath = registerHeader($Path, $LVer)) { 2172 $In::Desc{$LVer}{"RegHeader"}{$HPath}{"Pos"} = $Position++; 2173 } 2174 } 2175 elsif(-d $Path) 2176 { 2177 my @Registered = (); 2178 foreach my $P (cmdFind($Path,"f")) 2179 { 2180 if(ignorePath($P)) { 2181 next; 2182 } 2183 if(not isHeader($P, 0, $LVer)) { 2184 next; 2185 } 2186 if(my $HPath = registerHeader($P, $LVer)) { 2187 push(@Registered, $HPath); 2188 } 2189 } 2190 @Registered = sort {sortHeaders($a, $b)} @Registered; 2191 sortByWord(\@Registered, $In::Opt{"TargetLibShort"}); 2192 foreach my $P (@Registered) { 2193 $In::Desc{$LVer}{"RegHeader"}{$P}{"Pos"} = $Position++; 2194 } 2195 } 2196 elsif(not defined $In::Opt{"SkipUnidentified"}) { 2197 exitStatus("Access_Error", "can't identify \'$Path\' as a header file"); 2198 } 2199 } 2200 2201 if(defined $In::Opt{"Tolerance"} 2202 and $In::Opt{"Tolerance"}=~/4/) 2203 { # 4 - skip headers included by others 2204 foreach my $Path (keys(%{$In::Desc{$LVer}{"RegHeader"}})) 2205 { 2206 if(defined $Header_Includes_R{$LVer}{$Path}) { 2207 delete($In::Desc{$LVer}{"RegHeader"}{$Path}); 2208 } 2209 } 2210 } 2211 2212 if(not defined $In::Desc{$LVer}{"Include_Preamble"}) { 2213 $In::Desc{$LVer}{"Include_Preamble"} = []; 2214 } 2215 2216 if(my $HList = $DescRef->{"IncludePreamble"}) 2217 { # preparing preamble headers 2218 foreach my $Header (split(/\s*\n\s*/, $HList)) 2219 { 2220 if(isAbsPath($Header) and not -f $Header) { 2221 exitStatus("Access_Error", "can't access file \'$Header\'"); 2222 } 2223 $Header = pathFmt($Header); 2224 if(my $Header_Path = isHeader($Header, 1, $LVer)) 2225 { 2226 if(skipHeader($Header_Path, $LVer)) { 2227 next; 2228 } 2229 push_U($In::Desc{$LVer}{"Include_Preamble"}, $Header_Path); 2230 } 2231 elsif(not defined $In::Opt{"SkipUnidentified"}) { 2232 exitStatus("Access_Error", "can't identify \'$Header\' as a header file"); 2233 } 2234 } 2235 } 2236 2237 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LVer}})) 2238 { # set relative paths (for duplicates) 2239 if(keys(%{$HeaderName_Paths{$LVer}{$Header_Name}})>=2) 2240 { # search for duplicates 2241 my $FirstPath = (keys(%{$HeaderName_Paths{$LVer}{$Header_Name}}))[0]; 2242 my $Prefix = getDirname($FirstPath); 2243 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/) 2244 { # detect a shortest distinguishing prefix 2245 my $NewPrefix = $1; 2246 my %Identity = (); 2247 foreach my $Path (keys(%{$HeaderName_Paths{$LVer}{$Header_Name}})) 2248 { 2249 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) { 2250 $Identity{$Path} = $1; 2251 } 2252 } 2253 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LVer}{$Header_Name}})) 2254 { # all names are different with current prefix 2255 foreach my $Path (keys(%{$HeaderName_Paths{$LVer}{$Header_Name}})) { 2256 $In::Desc{$LVer}{"RegHeader"}{$Path}{"Identity"} = $Identity{$Path}; 2257 } 2258 last; 2259 } 2260 $Prefix = $NewPrefix; # increase prefix 2261 } 2262 } 2263 } 2264 2265 # clean memory 2266 %HeaderName_Paths = (); 2267 2268 foreach my $HName (keys(%{$In::Desc{$LVer}{"IncludeOrder"}})) 2269 { # ordering headers according to the descriptor 2270 my $PairName = $In::Desc{$LVer}{"IncludeOrder"}{$HName}; 2271 my ($Pos, $PairPos, $Path, $PairPath) = (-1, -1, undef, undef); 2272 2273 my @Paths = keys(%{$In::Desc{$LVer}{"RegHeader"}}); 2274 @Paths = sort {$In::Desc{$LVer}{"RegHeader"}{$a}{"Pos"}<=>$In::Desc{$LVer}{"RegHeader"}{$b}{"Pos"}} @Paths; 2275 2276 foreach my $HPath (@Paths) 2277 { 2278 if(getFilename($HPath) eq $PairName) 2279 { 2280 $PairPos = $In::Desc{$LVer}{"RegHeader"}{$HPath}{"Pos"}; 2281 $PairPath = $HPath; 2282 } 2283 if(getFilename($HPath) eq $HName) 2284 { 2285 $Pos = $In::Desc{$LVer}{"RegHeader"}{$HPath}{"Pos"}; 2286 $Path = $HPath; 2287 } 2288 } 2289 if($PairPos!=-1 and $Pos!=-1 2290 and int($PairPos)<int($Pos)) 2291 { 2292 my %Tmp = %{$In::Desc{$LVer}{"RegHeader"}{$Path}}; 2293 %{$In::Desc{$LVer}{"RegHeader"}{$Path}} = %{$In::Desc{$LVer}{"RegHeader"}{$PairPath}}; 2294 %{$In::Desc{$LVer}{"RegHeader"}{$PairPath}} = %Tmp; 2295 } 2296 } 2297 if(not keys(%{$In::Desc{$LVer}{"RegHeader"}})) { 2298 exitStatus("Error", "header files are not found in the ".$DescRef->{"Version"}); 2299 } 2300} 2301 2302sub addTargetHeaders($) 2303{ 2304 my $LVer = $_[0]; 2305 2306 foreach my $RegHeader (keys(%{$In::Desc{$LVer}{"RegHeader"}})) 2307 { 2308 my $RegDir = getDirname($RegHeader); 2309 $In::Desc{$LVer}{"TargetHeader"}{getFilename($RegHeader)} = 1; 2310 2311 if(not $In::Desc{$LVer}{"AutoIncludePaths"}) { 2312 detectRecursiveIncludes($RegHeader, $LVer); 2313 } 2314 2315 foreach my $RecInc (keys(%{$RecursiveIncludes{$LVer}{$RegHeader}})) 2316 { 2317 my $Dir = getDirname($RecInc); 2318 2319 if(familiarDirs($RegDir, $Dir) 2320 or $RecursiveIncludes{$LVer}{$RegHeader}{$RecInc}!=1) 2321 { # in the same directory or included by #include "..." 2322 $In::Desc{$LVer}{"TargetHeader"}{getFilename($RecInc)} = 1; 2323 } 2324 } 2325 } 2326} 2327 2328sub familiarDirs($$) 2329{ 2330 my ($D1, $D2) = @_; 2331 if($D1 eq $D2) { 2332 return 1; 2333 } 2334 2335 my $U1 = index($D1, "/usr/"); 2336 my $U2 = index($D2, "/usr/"); 2337 2338 if($U1==0 and $U2!=0) { 2339 return 0; 2340 } 2341 2342 if($U2==0 and $U1!=0) { 2343 return 0; 2344 } 2345 2346 if(index($D2, $D1."/")==0) { 2347 return 1; 2348 } 2349 2350 # /usr/include/DIR 2351 # /home/user/DIR 2352 2353 my $DL = getDepth($D1); 2354 2355 my @Dirs1 = ($D1); 2356 while($DL - getDepth($D1)<=2 2357 and getDepth($D1)>=4 2358 and $D1=~s/[\/\\]+[^\/\\]*?\Z//) { 2359 push(@Dirs1, $D1); 2360 } 2361 2362 my @Dirs2 = ($D2); 2363 while(getDepth($D2)>=4 2364 and $D2=~s/[\/\\]+[^\/\\]*?\Z//) { 2365 push(@Dirs2, $D2); 2366 } 2367 2368 foreach my $P1 (@Dirs1) 2369 { 2370 foreach my $P2 (@Dirs2) 2371 { 2372 if($P1 eq $P2) { 2373 return 1; 2374 } 2375 } 2376 } 2377 return 0; 2378} 2379 2380sub isHeaderFile($) 2381{ 2382 if($_[0]=~/\.($HEADER_EXT)\Z/i) { 2383 return $_[0]; 2384 } 2385 return 0; 2386} 2387 2388sub isNotHeader($) 2389{ 2390 if($_[0]=~/\.\w+\Z/ 2391 and $_[0]!~/\.($HEADER_EXT)\Z/i) { 2392 return 1; 2393 } 2394 return 0; 2395} 2396 2397sub getGccPath() 2398{ 2399 if(defined $In::Opt{"GccPath"}) { 2400 return $In::Opt{"GccPath"}; 2401 } 2402 2403 my $Path = undef; 2404 2405 if(my $CrossGcc = $In::Opt{"CrossGcc"}) 2406 { # --cross-gcc=arm-linux-gcc 2407 if(-e $CrossGcc) 2408 { # absolute or relative path 2409 $Path = getAbsPath($CrossGcc); 2410 } 2411 elsif($CrossGcc!~/\// and getCmdPath($CrossGcc)) 2412 { # command name 2413 $Path = $CrossGcc; 2414 } 2415 else { 2416 exitStatus("Access_Error", "can't access \'$CrossGcc\'"); 2417 } 2418 2419 if($Path=~/\s/) { 2420 $Path = "\"".$Path."\""; 2421 } 2422 } 2423 else 2424 { # try default gcc 2425 $Path = getCmdPath("gcc"); 2426 2427 if(not $Path) 2428 { # try to find gcc-X.Y 2429 foreach my $P (@{$In::Opt{"SysPaths"}{"bin"}}) 2430 { 2431 if(my @GCCs = cmdFind($P, "", '/gcc-[0-9.]*\Z', 1, 1)) 2432 { # select the latest version 2433 @GCCs = sort {$b cmp $a} @GCCs; 2434 if(checkGcc("3", $GCCs[0])) 2435 { 2436 $Path = $GCCs[0]; 2437 last; 2438 } 2439 } 2440 } 2441 } 2442 if(not $Path) { 2443 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH"); 2444 } 2445 } 2446 2447 return ($In::Opt{"GccPath"} = $Path); 2448} 2449 2450sub clearSysFilesCache($) 2451{ 2452 my $LVer = $_[0]; 2453 2454 %Cache = (); 2455 2456 delete($RecursiveIncludes{$LVer}); 2457 delete($Header_Include_Prefix{$LVer}); 2458 delete($Header_Includes{$LVer}); 2459 delete($Header_ErrorRedirect{$LVer}); 2460} 2461 2462sub dumpFilesInfo($) 2463{ # extra information for other tools 2464 my $LVer = $_[0]; 2465 my $EInfo = $In::Opt{"ExtraInfo"}; 2466 2467 writeFile($EInfo."/recursive-includes", Dumper($RecursiveIncludes{$LVer})); 2468 writeFile($EInfo."/direct-includes", Dumper($Header_Includes{$LVer})); 2469 2470 if(my @Redirects = keys(%{$Header_ErrorRedirect{$LVer}})) 2471 { 2472 my $REDIR = ""; 2473 foreach my $P1 (sort @Redirects) { 2474 $REDIR .= $P1.";".$Header_ErrorRedirect{$LVer}{$P1}."\n"; 2475 } 2476 writeFile($EInfo."/include-redirect", $REDIR); 2477 } 2478} 2479 2480sub callPreprocessor($$$) 2481{ 2482 my ($Path, $Inc, $LVer) = @_; 2483 2484 my $IncludeString=$Inc; 2485 if(not $Inc) { 2486 $IncludeString = getIncString(getIncPaths([$Path], $LVer), "GCC"); 2487 } 2488 2489 my $TmpDir = $In::Opt{"Tmp"}; 2490 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString, $LVer); 2491 my $Out = $TmpDir."/preprocessed.h"; 2492 system($Cmd." >\"$Out\" 2>\"$TmpDir/null\""); 2493 2494 return $Out; 2495} 2496 2497sub isHeader($$$) 2498{ 2499 my ($Header, $UserDefined, $LVer) = @_; 2500 if(-d $Header) { 2501 return 0; 2502 } 2503 if(-f $Header) { 2504 $Header = getAbsPath($Header); 2505 } 2506 else 2507 { 2508 if(isAbsPath($Header)) 2509 { # incorrect absolute path 2510 return 0; 2511 } 2512 if(my $HPath = identifyHeader($Header, $LVer)) { 2513 $Header = $HPath; 2514 } 2515 else 2516 { # can't find header 2517 return 0; 2518 } 2519 } 2520 if($Header=~/\.\w+\Z/) 2521 { # have an extension 2522 return isHeaderFile($Header); 2523 } 2524 else 2525 { 2526 if($UserDefined==2) 2527 { # specified on the command line 2528 if(cmdFile($Header)!~/HTML|XML/i) { 2529 return $Header; 2530 } 2531 } 2532 elsif($UserDefined) 2533 { # specified in the XML-descriptor 2534 # header file without an extension 2535 return $Header; 2536 } 2537 else 2538 { 2539 if(index($Header, "/include/")!=-1 2540 or cmdFile($Header)=~/C[\+]*\s+program/i) 2541 { # !~/HTML|XML|shared|dynamic/i 2542 return $Header; 2543 } 2544 } 2545 } 2546 return 0; 2547} 2548 2549return 1; 2550