#!/usr/bin/perl -w # NAME: cmakeinstall.pl # AIM: Given a cmake_install.cmake file, check and advise the install location, # and what will be installed. ALL FAILED!!! ABANDONED, but some good cmake parsing stuff # 2019-02-23 - Another try, and FIX, and very simple too... added some [v?] msgs... # 14/04/2015 - Allow a DIRECTORY or FILE input, using 'cmake_install.cmake' if DIR # 13/04/2015 - May now have it working... use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use File::stat; # to get the file date and size 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.5 2019-02-23"; #my $VERS = "0.0.4 2015-04-14"; #my $VERS = "0.0.3 2015-04-13"; #my $VERS = "0.0.2 2014-01-13"; my $load_log = 0; my $in_file = ''; my $verbosity = 0; my $out_file = ''; my %set_commands = (); my @to_install = (); my $show_all = 0; # ### DEBUG ### my $debug_on = 0; my $def_file = 'F:\FG\18\build-assimp\cmake_install.cmake'; my $def_file2 = 'F:\Projects\build-szip\cmake_install.cmake'; ### program variables my @warnings = (); my $cwd = cwd(); 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); } # make sure the line has no open brackets sub full_cmake_line($) { my ($line) = shift; my $len = length($line); my $inquot = 0; my $inbrac = 0; my ($i,$ch,$qc); for ($i = 0; $i < $len; $i++) { $ch = substr($line,$i,1); if ($inbrac) { if ($inquot) { $inquot = 0 if ($ch eq $qc); } elsif ($ch eq '"') { $inquot = 1; $qc = $ch; } elsif ($ch eq ')') { $inbrac--; if ($inbrac == 0) { return 1; } } } else { if ($inquot) { $inquot = 0 if ($ch eq $qc); } elsif ($ch eq '"') { $inquot = 1; $qc = $ch; } elsif ($ch eq '(') { $inbrac++; } } } return 0; } #my %set_commands = (); sub do_replacement($) { my $txt = shift; my $ntxt = ''; my ($i,$ch,$len,$i2,$nc,$key); $len = length($txt); my $dn_sub = 0; for ($i = 0; $i < $len; $i++) { $i2 = $i + 1; $ch = substr($txt,$i,1); $nc = ($i2 < $len) ? substr($txt,$i2,1) : ''; if (($ch eq '$')&&($nc eq '{')) { $key = ''; $i += 2; for (; $i < $len; $i++) { #$i2 = $i + 1; $ch = substr($txt,$i,1); #$nc = ($i2 < $len) ? substr($txt,$i2,1) : ''; if ($ch eq '}') { last; } else { $key .= $ch; } } if (length($key) && (defined $set_commands{$key})) { $ntxt .= $set_commands{$key}; $dn_sub = 1; } else { $ntxt .= '$'.'{'.$key.'}'; } } else { $ntxt .= $ch; } } return $ntxt; } sub do_replacements($) { my $txt = shift; my $ntxt = do_replacement($txt); if (($txt ne $ntxt) && ($ntxt =~ /\$\{.+\}/)) { $ntxt = do_replacement($ntxt); } return $ntxt; } sub process_in_file($); my $shown_diff = 0; my $shown_glob = 0; my $shown_remove = 0; my $shown_rpathc = 0; my $shown_rpathr = 0; sub process_in_file($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; close INF; my $lncnt = scalar @lines; prt("\n[v1] Processing $lncnt lines, from [$inf]...\n") if (VERB1()); my ($i,$i2,$line,$inc,$lnn,$len,$tmp,@arr,$cnt,$val,$msg,$key,$j,$act,$dest,$type,$files,$var); $lnn = 0; my $man_files = ''; for ($i = 0; $i < $lncnt; $i++) { $lnn++; $line = $lines[$i]; chomp $line; $line = trim_all($line); $len = length($line); next if ($len == 0); next if ($line =~ /^\s*\#/); $i2 = $i + 1; while (!full_cmake_line($line) && ($i2 < $lncnt)) { prt("$lnn: NOT COMPLETE - $line\n") if (VERB9()); $lnn++; $i++; $i2 = $i + 1; $tmp = $lines[$i]; chomp $tmp; $tmp = trim_all($tmp); $len = length($tmp); next if ($len == 0); $line .= " $tmp"; } #prt("$lnn: $line\n"); if ($line =~ /^IF\s*\((.+)\)/i) { $tmp = $1; prt("$lnn: IF COND '$tmp'\n") if (VERB5()); } elsif ($line =~ /^ELSE/i) { } elsif ($line =~ /^ENDIF/i) { } elsif ($line =~ /^SET\s*\((.+)\)/i) { $tmp = $1; @arr = space_split($tmp); $cnt = scalar @arr; $key = $arr[0]; $msg = "$lnn: SET $key to "; $val = ''; if ($cnt > 1) { for ($j = 1; $j < $cnt; $j++) { $tmp = $arr[$j]; $tmp = trim_all($tmp); $tmp = strip_double_quotes($tmp); if (length($tmp)) { $msg .= "$tmp "; $val .= ';' if (length($val)); $val .= $tmp; } else { $msg .= "NOTHING "; } } } else { $msg .= "nothing"; } prt("$msg\n") if (VERB5()); if (length($val)) { $set_commands{$key} = $val; } elsif (defined $set_commands{$key}) { delete $set_commands{$key}; } } elsif ($line =~ /^MESSAGE\s*\((.+)\)/i) { $tmp = $1; } elsif ($line =~ /^INCLUDE\s*\(\s*(.+)\s*\)/i) { $tmp = $1; $tmp = strip_double_quotes($tmp); if (-f $tmp) { prt("Processing INCLUDE $tmp\n") if (VERB1()); process_in_file($tmp); } else { prtw("WARNING: Unable to stat file $tmp\n"); } } elsif ($line =~ /^STRING\s*\((.+)\)/i) { $tmp = $1; } elsif ($line =~ /^FILE\s*\((.+)\)/i) { $tmp = $1; @arr = space_split($tmp); $cnt = scalar @arr; $key = $arr[0]; $msg = "$lnn:$cnt: FILE( $key "; $val = ''; $act = ''; $dest = ''; $type = ''; $files = ''; for ($j = 0; $j < $cnt; $j++) { $tmp = strip_double_quotes($arr[$j]); $tmp = do_replacements($tmp) if ($tmp =~ /\$/); $msg .= "$tmp "; if ($j == 0) { $act = $tmp; if ($act =~ /^INSTALL$/ ) { # ok } elsif (($act =~ /^WRITE/)||($act =~ /^APPEND/)) { # ok if (($j + 1) < $cnt) { $j++; $tmp = strip_double_quotes($arr[$j]); $type = do_replacements($tmp) if ($tmp =~ /\$/); $msg .= "$type "; $j++; for (; $j < $cnt; $j++) { $tmp = strip_double_quotes($arr[$j]); $tmp = do_replacements($tmp) if ($tmp =~ /\$/); $msg .= "$tmp "; $man_files .= ';' if (length($man_files)); $man_files .= $tmp; } } else { pgm_exit(1, "$line not handled! no TYPE *** FIX ME ***\n"); } } elsif ($act =~ /^DIFFERENT$/ ) { if (!$shown_diff) { prt("$lnn: $line, in $inf\n"); prtw("WARNING: FILE action DIFFERENT not completed!\n"); } $shown_diff++; last; # skip this action } elsif ($act =~ /^GLOB$/ ) { if (!$shown_glob) { prt("$lnn: $line, in $inf\n"); prtw("WARNING: FILE action GLOB not completed!\n"); } $shown_glob++; last; } elsif ($act =~ /^REMOVE$/ ) { if (!$shown_remove) { prt("$lnn: $line, in $inf\n"); prtw("WARNING: FILE action REMOVE not completed!\n"); } $shown_remove++; last; } elsif ($act =~ /^RPATH_CHECK$/ ) { if (!$shown_rpathc) { prt("$lnn: $line, in $inf\n"); prtw("WARNING: FILE action RPATH_CHECK not implemennted!\n"); } $shown_rpathc++; last; } elsif ($act =~ /^RPATH_REMOVE$/ ) { if (!$shown_rpathr) { prt("$lnn: $line, in $inf\n"); prtw("WARNING: FILE action RPATH_REMOVE not implemennted!\n"); } $shown_rpathr++; last; } else { pgm_exit(1, "FILE action $tmp not handled! *** FIX ME ***\n"); } } elsif ($tmp =~ /^DESTINATION$/) { if (($j + 1) < $cnt) { $j++; $dest = strip_double_quotes($arr[$j]); $msg .= "$dest "; } else { pgm_exit(1, "$line not handled! no DESTINATION *** FIX ME ***\n"); } } elsif ($tmp =~ /^TYPE$/) { if (($j + 1) < $cnt) { $j++; $type = strip_double_quotes($arr[$j]); $msg .= "$type "; } else { pgm_exit(1, "$line not handled! no TYPE *** FIX ME ***\n"); } } elsif ($tmp =~ /^OPTIONAL$/) { # just ignore this - usually OPTIONAL FILES } elsif ($tmp =~ /^FILES$/) { # very important - install SOURCES... if (($j + 1) < $cnt) { $j++; # CMAKE_INSTALL_MANIFEST_CONTENT for (; $j < $cnt; $j++) { $tmp = strip_double_quotes($arr[$j]); $tmp = do_replacements($tmp) if ($tmp =~ /\$/); $files .= ';' if (length($files)); $files .= $tmp; $msg .= "$tmp "; if ( defined $set_commands{CMAKE_INSTALL_MANIFEST_CONTENT} ) { $set_commands{CMAKE_INSTALL_MANIFEST_CONTENT} .= ";$tmp"; } else { $set_commands{CMAKE_INSTALL_MANIFEST_CONTENT} = $tmp; } } } else { pgm_exit(1, "$line not handled! no TYPE *** FIX ME ***\n"); } } else { pgm_exit(1, "$lnn: $tmp NOT handled! line '$line' *** FIX ME ***\n"); } } $msg .= ")"; if (length($dest) && length($files)) { push(@to_install, [$dest,$files]); } prt("$msg\n") if (VERB5()); } elsif ($line =~ /^FOREACH\s*\((.+)\)/i) { $tmp = $1; prt("$lnn: FOREACH '$tmp'\n") if (VERB5()); } elsif ($line =~ /^ENDFOREACH/i) { } elsif ($line =~ /^EXECUTE_PROCESS/i) { } elsif ($line =~ /^LIST\s*\(\s*(.+)\s*\)/i) { $tmp = $1; @arr = space_split($tmp); $cnt = scalar @arr; $act = $arr[0]; if ($act eq 'APPEND') { for ($j = 1; $j < $cnt; $j++) { if ($j == 1) { $var = $arr[$j]; $var = do_replacements($var) if ($var =~ /\$/); } else { $tmp = strip_double_quotes($arr[$j]); $tmp = do_replacements($tmp) if ($tmp =~ /\$/); if (defined $set_commands{$var}) { $set_commands{$var} = ";$tmp"; } else { $set_commands{$var} = $tmp; } } } } else { prtw("WARNING: $lnn: LIST action $act NOT HANDLED! *** FIX ME ***\n"); } } else { prtw("WARNING: $lnn: '$line' NOT processed *** FIX ME ***\n"); } } prt("[v2] Done $lncnt lns, of [$inf]...\n") if (VERB2()); ###$load_log = 1; } sub show_set_commands() { my @arr = sort keys %set_commands; my ($key,$val,@a2,$show); foreach $key (@arr) { $show = 0; $val = $set_commands{$key}; if ($key eq 'CMAKE_INSTALL_MANIFEST_CONTENT') { @a2 = split(/;+/,$val); $val = "\n".join("\n",@a2); $show = 1; } elsif ($key eq 'CMAKE_INSTALL_PREFIX') { $show = 1; } else { $show = 1 if (VERB9()); } prt("$key = $val\n") if ($show); } } sub show_install() { my $cnt = scalar @to_install; my ($i,$ra,$src,$dst,@arr,$tmp,@a2,$ra2); my %installs = (); my $itot = 0; prt("[v1] print $cnt installs...\n") if (VERB1()); for ($i = 0; $i < $cnt; $i++) { $ra = $to_install[$i]; $dst = ${$ra}[0]; $dst = do_replacements($dst) if ($dst =~ /\$/); $installs{$dst} = []; } for ($i = 0; $i < $cnt; $i++) { $ra = $to_install[$i]; $dst = ${$ra}[0]; $src = ${$ra}[1]; $dst = do_replacements($dst) if ($dst =~ /\$/); $src = do_replacements($src) if ($src =~ /\$/); $ra2 = $installs{$dst}; @arr = split(/;+/,$src); foreach $tmp (@arr) { push(@{$ra2},$tmp); $itot++; } } my ($sbs,$sbd,$df,$tms,$tmd,$res,$len); my ($n,$d); prt("From $cnt items, got $itot files to install...\n"); for ($i = 0; $i < $cnt; $i++) { $ra = $to_install[$i]; $dst = ${$ra}[0]; $src = ${$ra}[1]; $dst = do_replacements($dst) if ($dst =~ /\$/); $src = do_replacements($src) if ($src =~ /\$/); @arr = split(/;+/,$src); ut_fix_rpath_per_os(\$dst); ut_fix_directory(\$dst); foreach $tmp (@arr) { ut_fix_rpath_per_os(\$tmp); ($n,$d) = fileparse($tmp); $df = $dst.$n; $sbs = stat($tmp); $sbd = stat($df); prt("compare $tmp $df\n") if (VERB1()); if (VERB9()) { show_file_stat($df,1); show_file_stat($tmp,1); } } } @a2 = sort keys %installs; my $minlen = 0; foreach $dst (@a2) { $ra2 = $installs{$dst}; foreach $tmp (@{$ra2}) { $len = length($tmp); $minlen = $len if ($len > $minlen); } } my @backups = (); # process by DESTINATION folder - like root\bin, lib, include, share\man\man3, share\pkgconfig\zlib.pc foreach $dst (@a2) { $ra2 = $installs{$dst}; ut_fix_rpath_per_os(\$dst); prt("\nINSTALL to $dst\n"); #if ($sb = stat($dst)) { #if (-d $dst) { ut_fix_directory(\$dst); foreach $tmp (@{$ra2}) { ut_fix_rpath_per_os(\$tmp); ($n,$d) = fileparse($tmp); $df = $dst.$n; $sbs = stat($tmp); $sbd = stat($df); if ($sbs && $sbd) { # got BOTH, source and destination $tms = $sbs->mtime; $tmd = $sbd->mtime; if ($tms == $tmd) { # 2019-02-24 correction $res = 'Up-to-date'; } elsif ($tms > $tmd) { $res = 'needs install'; push(@backups, [$dst,$n]); } else { $res = "NEW - needs install!"; } #prt(" $tmp $tms $tmd\n"); if (($tmp =~ /MinSizeRel/)||($tmp =~ /RelWithDebInfo/)) { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp $res\n") if ($show_all || VERB9()); } else { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp $res\n"); } } elsif ($sbs) { # got SOURCE only if (($tmp =~ /MinSizeRel/)||($tmp =~ /RelWithDebInfo/)) { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp NEED INSTALL\n") if ($show_all || VERB9()); } else { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp NEED INSTALL\n"); } } elsif ($sbd) { # got DESTINATION only if (($tmp =~ /MinSizeRel/)||($tmp =~ /RelWithDebInfo/)) { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp POS DELETE\n") if ($show_all || VERB9()); } else { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp POS DELETE\n"); } } else { # Hmmm, neither SOURCE not DESTINATION if (($tmp =~ /MinSizeRel/)||($tmp =~ /RelWithDebInfo/)) { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp NOT FOUND!\n") if ($show_all || VERB9()); } else { $tmp .= ' ' while (length($tmp) < $minlen); prt(" $tmp NOT FOUND!\n"); } } } #} else { # foreach $tmp (@{$ra2}) { # prt(" $tmp\n"); # } #} } $tmp = scalar @backups; if ($tmp > 0) { prt("Potential $tmp overwrites, before backup...\n"); if (VERB2()) { $minlen = 0; foreach $ra (@backups) { $dst = ${$ra}[0]; if ($dst =~ /\/\\$/) { $dst =~ s/\/\\$//; } $n = ${$ra}[1]; $len = length($n); $minlen = $len if ($len > $minlen); } foreach $ra (@backups) { $dst = ${$ra}[0]; $n = ${$ra}[1]; $tmp = $dst.$n; # prt(" [v2] $tmp\n"); # if ($dst =~ /[\/\\]+$/) { # $dst =~ s/\/\\$//; # } $len = length($dst); if ($len > 0) { $dst = substr($dst,0,$len - 1); } $n .= ' ' while (length($n) < $minlen); prt(" [v2] $n to $dst\n"); } } } } ######################################### ### MAIN ### parse_args(@ARGV); process_in_file($in_file); show_set_commands() if (VERB5()); show_install(); 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); my $verb = VERB2(); 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); } } $verb = VERB2(); prt("Verbosity = $verbosity\n") if ($verb); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if ($verb); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; prt("Set out file to [$out_file].\n") if ($verb); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { if (-d $arg) { $sarg = $arg.$PATH_SEP."cmake_install.cmake"; if (-f $sarg) { $in_file = $sarg; prt("Set input to [$in_file]\n") if ($verb); } else { pgm_exit(1,"Error: Can NOT locate $sarg!\n"); } } elsif ( -f $arg) { $in_file = $arg; prt("Set input to [$in_file]\n") if ($verb); } else { pgm_exit(1,"arg $arg is NOT a directory, nor file!\n"); } } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_file) == 0) { $in_file = $def_file; prt("Set DEFAULT input to [$in_file]\n"); } } 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 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(" --out (-o) = Write output to this file.\n"); } # eof - template.pl