#!/usr/bin/perl -w # NAME: chklinklog.pl # AIM: Check the Link: entry of the MSVC10 'log' file use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Cwd; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt"; open_log($outfile); # user variables my $VERS = "0.0.2 2012-11-11"; ###my $VERS = "0.0.1 2012-01-06"; my $load_log = 0; my $in_file = ''; my $verbosity = 0; my $out_xml = ''; my $strip_bom = 1; my $show_link = 0; # --Link (-L) = Show link items, and libraries. my $show_sources = 0; # --Sources (-S) = Show compiled sources. my $show_opts = 0; # --Options (-O) = Show compiler options. my $new_line = 1; ### program variables my @warnings = (); my $cwd = cwd(); my %file_hash = (); # *** DEBUG ONLY *** my $debug_on = 1; #my $def_file = 'C:\FG\17\build-atlas\Atlas.dir\Release\Atlas.log'; my $def_file = 'C:\FG\17\Atlas\projects\msvc\Release\Atlas\atlas.log'; #my $def_file = 'C:\FG\17\Atlas\projects\msvc\Debug\Atlas\atlas.log'; #my $def_file = 'C:\Users\user\Downloads\John-fgfs-01.log'; # my $def_file = 'C:\FG\10\flightgear\build\utils\GPSsmooth\GPSsmooth.dir\Debug\GPSsmooth.log'; my @BOM_list = ( [ "UTF-8", 3, [0xEF,0xBB,0xBF ] ], # 239 187 191 [ "UTF-16 (BE)", 2, [0xFE,0xFF ] ], # 254 255 [ "UTF-16 (LE)", 2, [0xFF,0xFE ] ], # 255 254 [ "UTF-32 (BE)", 4, [0x00,0x00,0xFE,0xFF] ], # 0 0 254 255 [ "UTF-32 (LE)", 4, [0xFF,0xFE,0x00,0x00] ], # 255 254 0 0 [ "UTF-7a" , 4, [0x2B,0x2F,0x76,0x38] ], # 2B 2F 76 39 2B 2F 76 2B 2B 2F 76 2F [ "UTF-7b" , 4, [0x2B,0x2F,0x76,0x39] ], # 2B 2F 76 39 2B 2F 76 2B 2B 2F 76 2F [ "UTF-7c" , 4, [0x2B,0x2F,0x76,0x2B] ], # 2B 2F 76 39 2B 2F 76 2B 2B 2F 76 2F [ "UTF-7d" , 4, [0x2B,0x2F,0x76,0x2F] ], # 2B 2F 76 39 2B 2F 76 2B 2B 2F 76 2F [ "UTF-1" , 3, [0xF7,0x64,0x4C ] ], # 247 100 76 [ "UTF-EBCDIC" , 4, [0xDD,0x73,0x66,0x73] ], # 221 115 102 115 [ "SCSU" , 3, [0x0E,0xFE,0xFF ] ], # 14 254 255 [ "BOCU-1" , 3, [0xFB,0xEE,0x28 ] ], # 251 238 40 [ "GB-18030" , 4, [0x84,0x31,0x95,0x33] ] # 132 49 149 51 ); my %LINK_OPTS = ( "ALIGN" => -2, # :# "ALLOWBIND" => -1, # [:NO] "ALLOWISOLATION" => -1, # [:NO] "ASSEMBLYDEBUG" => -1, # [:DISABLE] "ASSEMBLYLINKRESOURCE" => -2, # :filename "ASSEMBLYMODULE" => -2, # :filename "ASSEMBLYRESOURCE" => -2, # :filename[,[name][,PRIVATE]] "BASE" => -2, # :{address[,size]|@filename,key} "CLRIMAGETYPE" => -2, # :{IJW|PURE|SAFE} "CLRLOADEROPTIMIZATION" => -2, # :{SD|MD|MDH|NONE} "CLRSUPPORTLASTERROR" => -2, # [:{NO|SYSTEMDLL}] "CLRTHREADATTRIBUTE" => -2, # :{STA|MTA|NONE} "CLRUNMANAGEDCODECHECK" => -2, # [:NO] "DEBUG" => -2, "DEF" => 1, # :filename "DEFAULTLIB" => 1, # :library "DELAY" => -2, # :{NOBIND|UNLOAD} "DELAYLOAD" => -2, # :dll "DELAYSIGN" => -1, # [:NO] "DLL" => -1, "DRIVER" => -1, # [:{UPONLY|WDM}] "DYNAMICBASE" => -1, # [:NO] "ENTRY" => -2, #:symbol "ERRORREPORT" => -2, # :{NONE|PROMPT|QUEUE|SEND} "EXPORT" => -2, # :symbol "FIXED" => -1, # [:NO] "FORCE" => -1, # [:{MULTIPLE|UNRESOLVED}] "FUNCTIONPADMIN" => -1, # [:size] "HEAP" => -2, # :reserve[,commit] "IDLOUT" => -2, # :filename "IGNOREIDL" => -1, "IMPLIB" => -2, # :filename "INCLUDE" => -2, # :symbol "INCREMENTAL" => -1, # [:NO] "KEYCONTAINER" => -2, # :name "KEYFILE" => -2, # :filename "LARGEADDRESSAWARE" => -1, #[:NO] "LIBPATH" => -2, # :dir "LTCG" => -1, # [:{NOSTATUS|PGINSTRUMENT|PGOPTIMIZE|PGUPDATE|STATUS}] "MACHINE" => -2, # :{ARM|EBC|IA64|MIPS|MIPS16|MIPSFPU|MIPSFPU16|SH4|THUMB|X64|X86} "MANIFEST" => -1, # [:NO] "MANIFESTDEPENDENCY" => -2, # :manifest dependency "MANIFESTFILE" => -2, # :filename "MANIFESTUAC" => -2, # [:{NO|UAC fragment}] "MAP" => -2, # [:filename] "MAPINFO" => -2, # :{EXPORTS} "MERGE" => -2, # :from=to "MIDL" => -2, # :@commandfile "NOASSEMBLY" => -1, "NODEFAULTLIB" => -1, # [:library] "NOENTRY" => -1, "NOLOGO" => -1, "NXCOMPAT" => -1, # [:NO] "OPT" => -2, # :{ICF[=iterations]|NOICF|NOREF|REF} "ORDER" => -2, # :@filename "OUT" => 1, # :filename "PDB" => -2, # :filename "PDBSTRIPPED" => -2, # :filename "PGD" => -2, # :filename "PROFILE" => -1, "RELEASE" => -1, "SAFESEH" => -1, #[:NO] "SECTION" => -2, # :name,[[!]{DEKPRSW}][,ALIGN=#] "STACK" => -2, # :reserve[,commit] "STUB" => -2, # :filename "SUBSYSTEM" => 1, # :{BOOT_APPLICATION|CONSOLE|EFI_APPLICATION|EFI_BOOT_SERVICE_DRIVER|EFI_ROM|EFI_RUNTIME_DRIVER| #NATIVE|POSIX|WINDOWS|WINDOWSCE}[,#[.##]] "SWAPRUN" => -2, #:{CD|NET} "TLBID" => -2, # :# "TLBOUT" => -2, # :filename "TSAWARE" => -1, # [:NO] "VERBOSE" => -1, # [:{ICF|LIB|REF|SAFESEH}] "VERSION" => -1, # :#[.#] "WX" => -1 # [:NO] ); # compiler flags my %compile_flags = ( 'nologo' => 0, 'W3' => 0, 'Gm' => 0, 'GR' => 0, 'GX' => 0, 'ZI' => 0, 'Od' => 0, 'MTd' => 0, 'I' => 1, 'D' => 1, 'FD' => 0, 'GZ' => 0, 'c' => 0, 'O2' => 0, 'MT' => 0 ); sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { prt( "\nNo warnings issued.\n\n" ) if (VERB9()); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub line_has_bom($$) { my ($line,$rname) = @_; my $max = scalar @BOM_list; my $len = length($line); my ($i,$j,$name,$cnt,$ra,$ch,$val); for ($i = 0; $i < $max; $i++) { $name = $BOM_list[$i][0]; # name $cnt = $BOM_list[$i][1]; # length $ra = $BOM_list[$i][2]; # ref array of values if ($len > $cnt) { # make sure line length GT BOM for ($j = 0; $j < $cnt; $j++) { $ch = substr($line,$j,1); # extract CHAR $val = ord($ch); # get VALUE last if ($val != ${$ra}[$j]); # compare } if ($j == $cnt) { # if ALL values found ${$rname} = $name; # give back 'name' return $cnt; # and return count } } } return 0; # no BOM found } sub remove_utf_bom($$) { my ($ff,$ra) = @_; my $line = ${$ra}[0]; # get first line my $name = ''; my $len = line_has_bom($line,\$name); if ($len) { $line = substr($line,$len); # truncate line ${$ra}[0] = $line; # and return minus BOM my ($nm,$dr) = fileparse($ff); # just show name prt("NOTE: File [$nm] is $name encoding. BOM($len) removed.\n"); } } sub load_file_lines($$) { my ($ff,$ra) = @_; my $lncnt = 0; if (open INF, "<$ff") { @{$ra} = ; close INF; $lncnt = scalar @{$ra}; remove_utf_bom($ff,$ra) if ($strip_bom); } else { prtw("WARNING: Unable to open [$ff]!\n"); } return $lncnt; } sub process_in_file($) { my ($inf) = @_; my @lines = (); load_file_lines($inf,\@lines); my $lncnt = scalar @lines; prt("Processing $lncnt lines, from [$inf]...\n"); my ($i,$line,$inc,$lnn,$inbuild,$len,$tag,$j,$lkcnt,$ch,$inquot,$item,$msg,$lval); my ($cnt,$ind); $lnn = 0; my @libs = (); my (@arr, @srcs, @opts); for ($i = 0; $i < $lncnt; $i++) { $line = $lines[$i]; chomp $line; $lnn++; if ($line =~ /^Build\s(.+)$/) { $inc = $1; if ($inc =~ /started/) { $inbuild = 1; } prt("$lnn: $line\n"); } elsif ($inbuild) { # lines of interest if ($line =~ /^\s*Link:/) { # link lines $i++; $lkcnt = 0; for (; $i < $lncnt; $i++) { $line = $lines[$i]; chomp $line; $lnn++; if ($line =~ /^\s+/) { $len = length($line); $tag = ''; if ($lkcnt == 0) { for ($j = 0; $j < $len; $j++) { $ch = substr($line,$j,1); if ($ch =~ /\s/) { $tag .= $ch if (length($tag)); } elsif ($ch eq '/') { $tag = trim_tailing($tag); prt("Link tool: [$tag]\n"); last; } else { $tag .= $ch; } } } $lkcnt++; $tag = ''; $inquot = 0; $item = ''; for (; $j < $len; $j++) { $ch = substr($line,$j,1); if ($inquot) { $tag .= $ch; $inquot = 0 if ($ch eq '"'); } else { if ($ch =~ /\s/) { if ( length($tag) || length($item) ) { if (length($item)) { if ($item =~ /^\//) { $item =~ s/^\///; $msg = 'NF'; $lval = 1; if (defined $LINK_OPTS{$item}) { $msg = 'ok'; $lval = $LINK_OPTS{$item}; } else { $item = uc($item); if (defined $LINK_OPTS{$item}) { $msg = 'ok'; $lval = $LINK_OPTS{$item}; } } if ($lval > 0) { if (length($tag)) { prt("OPT: /$item val $tag $msg\n"); } else { prt("OPT: /$item $msg\n"); } } } else { if ($tag =~ /\.lib$/i) { push(@libs,"$item$tag"); } else { prt("$item$tag\n"); } } } else { if ($tag =~ /^\//) { $tag =~ s/^\///; $msg = 'NF'; $lval = 1; if (defined $LINK_OPTS{$tag}) { $msg = 'ok'; $lval = $LINK_OPTS{$tag}; } prt("OPT: /$tag $msg\n") if ($lval > 0); } else { if ($tag =~ /\.lib$/i) { push(@libs,$tag); } else { prt("$tag\n"); } } } } $tag = ''; $item = ''; } elsif ($ch eq '"') { $inquot = 1; $tag .= $ch; } else { if (($ch =~ /\W/)&&(length($item)==0)) { $item = $tag; $tag = $ch; } else { $tag .= $ch; } } } } } else { last; } } } elsif ($line =~ /^.+(\\|\/)CL\.exe\s+/) { $ind = index($line,'CL.exe '); if ($ind > 0) { $line = substr($line,$ind + 7); } prt($line) if (VERB9()); @arr = space_split($line); $cnt = scalar @arr; for ($j = 0; $j < $cnt; $j++) { $item = $arr[$j]; if ($item =~ /^(-|\/)/) { if (($item eq '/D') || ($item eq '-D') || ($item eq '/I') || ($item eq '-I')){ if (($j + 1) < $cnt) { $j++; $item .= ' '.$arr[$j]; } } push(@opts,$item); } else { push(@srcs,$item); } } } } } if (@libs) { @libs = sort @libs; $len = scalar @libs; prt("LIBS: $len\n"); if (VERB5()) { foreach $tag (@libs) { prt("$tag\n"); } } } if (@opts) { @opts = sort @opts; $len = scalar @opts; prt("OPTS: $len\n"); if (VERB5()) { foreach $tag (@opts) { prt("$tag\n"); } } } if (@srcs) { @srcs = sort @srcs; $len = scalar @srcs; prt("SRCS: $len\n"); if (VERB5()) { foreach $tag (@srcs) { prt("$tag\n"); } } } my %h = (); $h{'libs'} = \@libs; $h{'opts'} = \@opts; $h{'srcs'} = \@srcs; my $rh = \%file_hash; ${$rh}{$inf} = \%h; } sub show_file_hash() { my $rh = \%file_hash; my ($key,$val,$k2,$ra,$cnt,$item,$show,$line,$len1,$len2); my $lnmax = 85; foreach $key (keys %{$rh}) { $val = ${$rh}{$key}; prt("File: $key\n"); foreach $k2 (keys %{$val}) { $ra = ${$val}{$k2}; $cnt = scalar @{$ra}; prt("$k2: $cnt items\n"); $show = 0; if ($show_link && ($k2 eq 'libs')) { $show = 1; # --Link (-L) = Show link items, and libraries. } if ($show_sources && ($k2 eq 'srcs')) { $show = 1; # --Sources (-S) = Show compiled sources. } if ($show_opts && ($k2 eq 'opts')) { $show = 1; # --Options (-O) = Show compiler options. } if ($show) { $line = ''; foreach $show (@{$ra}) { $len1 = length($show); $len2 = length($line); if ($len2 && ((($len1 + $len2) > $lnmax) || $new_line)) { prt("$line\n"); $line = ''; $len2 = 0; } $line .= " " if ($len2); $line .= $show; } prt("$line\n") if (length($line)); } } } } ######################################### ### MAIN ### parse_args(@ARGV); process_in_file($in_file); show_file_hash(); pgm_exit(0,""); ######################################## sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my ($arg,$sarg); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v.*(\d+)$/) { $verbosity = $1; } else { while ($sarg =~ /^v/) { $verbosity++; $sarg = substr($sarg,1); } } prt("Verbosity = $verbosity\n") if (VERB1()); } elsif ($sarg =~ /^l/) { $load_log = 1; prt("Set to load log at end.\n") if (VERB1()); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_xml = $sarg; prt("Set out file to [$out_xml].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = $arg; prt("Set input to [$in_file]\n") if (VERB1()); } shift @av; } if ((length($in_file) == 0) && $debug_on) { $in_file = $def_file; prt("Set DEFAULT input to [$in_file]\n"); $load_log = 1; $show_opts = 1; } if (length($in_file) == 0) { pgm_exit(1,"ERROR: No input files found in command!\n"); } if (! -f $in_file) { pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n"); } } #sub look_for() { # my $txt = < C:\FG\10\flightgear\build\src\FDM\JSBSim\Debug\JSBSimd.lib #FinalizeBuildStatus: # Deleting file "JSBSim.dir\Debug\JSBSim.unsuccessfulbuild". # Touching "JSBSim.dir\Debug\JSBSim.lastbuildstate". #Done Building Project "C:\FG\10\flightgear\build\src\FDM\JSBSim\JSBSim.vcxproj" (build target(s)). # #Build succeeded. # #Time Elapsed 00:01:12.90 #*** OR *** #Build started 30/03/2012 18:03:44. #Project "C:\FG\10\flightgear\build\utils\GPSsmooth\GPSsmooth.vcxproj" on node 2 (build target(s)). #InitializeBuildStatus: # Touching "GPSsmooth.dir\Debug\GPSsmooth.unsuccessfulbuild". #CustomBuild: # All outputs are up-to-date. #ClCompile: # All outputs are up-to-date. #ManifestResourceCompile: # All outputs are up-to-date. #Link: # c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\link.exe /ERRORREPORT:PROMPT /OUT:"C:\FG\10\flightgear\build\utils\GPSsmooth\Debug\GPSsmooth.exe" /INCREMENTAL /NOLOGO /FORCE:MULTIPLE kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib C:\FG\10\3rdparty\lib\sgenvironmentd.lib C:\FG\10\3rdparty\lib\sgnasald.lib C:\FG\10\3rdparty\lib\sgtsyncd.lib C:\FG\10\3rdparty\lib\sgbucketd.lib C:\FG\10\3rdparty\lib\sgrouted.lib C:\FG\10\3rdparty\lib\sgiod.lib C:\FG\10\3rdparty\lib\sgseriald.lib C:\FG\10\3rdparty\lib\sgmathd.lib C:\FG\10\3rdparty\lib\sgpropsd.lib C:\FG\10\3rdparty\lib\sgstructured.lib C:\FG\10\3rdparty\lib\sgtimingd.lib C:\FG\10\3rdparty\lib\sgxmld.lib C:\FG\10\3rdparty\lib\sgmiscd.lib C:\FG\10\3rdparty\lib\sgthreadsd.lib C:\FG\10\3rdparty\lib\sgdebugd.lib C:\FG\10\3rdparty\lib\sgmagvard.lib C:\FG\10\3rdparty\lib\zlib1.lib ws2_32.lib /MANIFEST /ManifestFile:"GPSsmooth.dir\Debug\GPSsmooth.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\FG\10\flightgear\build\utils\GPSsmooth\Debug\GPSsmooth.pdb" /SUBSYSTEM:CONSOLE /STACK:"10000000" /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"C:/FG/10/flightgear/build/utils/GPSsmooth/Debug/GPSsmooth.lib" /MACHINE:X86 GPSsmooth.dir\Debug\GPSsmooth.exe.embed.manifest.res # GPSsmooth.dir\Debug\gps.obj # GPSsmooth.dir\Debug\gps_main.obj /machine:X86 /debug #LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/FORCE' specification #gps_main.obj : error LNK2019: unresolved external symbol "void __cdecl sgdMakeCoordMat4(double (* const)[4],double,double,double,double,double,double)" (?sgdMakeCoordMat4@@YAXQAY03NNNNNNN@Z) referenced in function "void __cdecl sgdMakeCoordMat4(double (* const)[4],double const * const,double const * const)" (?sgdMakeCoordMat4@@YAXQAY03NQBN1@Z) #sgtimingd.lib(timestamp.obj) : error LNK2019: unresolved external symbol __imp__timeGetTime@0 referenced in function "public: void __thiscall SGTimeStamp::stamp(void)" (?stamp@SGTimeStamp@@QAEXXZ) #C:\FG\10\flightgear\build\utils\GPSsmooth\Debug\GPSsmooth.exe : fatal error LNK1120: 2 unresolved externals #Done Building Project "C:\FG\10\flightgear\build\utils\GPSsmooth\GPSsmooth.vcxproj" (build target(s)) -- FAILED. # #Build FAILED. # #Time Elapsed 00:00:00.53 #EOF # return $txt; #} sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] in-file\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. def=$verbosity\n"); prt(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --Link (-L) = Show link items, and libraries. (def=$show_link)\n"); prt(" --Sources (-S) = Show compiled sources. (def=$show_sources)\n"); prt(" --Options (-O) = Show compiler options. (def=$show_opts)\n"); prt(" --out (-o) = Write output to this file.\n"); } # eof - chklinklog.pl