#!/usr/bin/perl -w # NAME: chkcmake02.pl # AIM: Original used to develop lib_cmakeread.pl, but later extended to tyr to find # and show an error in cmake syntax # 2016-10-07 - A review # 2014-04-02 - Some improvements # 02/05/2012 - Looking quite smooth ;=)) use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use File::Spec; # File::Spec->rel2abs($rel); # we are IN the SLN directory, get ABSOLUTE from 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"; require 'lib_cmakeread.pl' or die "Unable to load 'lib_cmakeread.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.7 2016-10-07"; # review # $VERS = "0.0.6 2014-01-18"; # start to reduce noisy debug output # $VERS = "0.0.5 2012-05-02"; # using/developing lib_cmakeread.pl # $VERS = "0.0.4 2012-04-26"; # load ALL 'CMakeModule' in advance, it it EXISTS # $VERS = "0.0.3 2012-04-22"; # $VERS = "0.0.2 2012-01-29"; # $VERS = "0.0.1 2011-10-25"; my $inc_all_cmake = 0; # 26/04/2012 - If there exists a folder 'CMakeModules' load ALL from here... my $load_log = 0; # 1=notepad(np), 2=editplus(ep) my $load_cmake_inst = 0; # process the cmake installation folders of ALL *.cmake found my $test_curr_file = 0; # see below for INPUT selected my $do_test_case = 0; # do ONLY specific canned test, written to test.cmake file... my $tmp_cmake = $temp_dir.$PATH_SEP."temp.cmake.txt"; my $temp_cmake = $temp_dir.$PATH_SEP."tempcmake.cmake"; my $dump_cmake_file = 1; # DUMP cleaned lines to a debug file dump_cmake() my $load_dump_file = 0; # load text in editor after writing file # options for dump output # ------------------------- my $add_line_nums = 1; my $add_if_depth = 1; my $add_uctag = 1; my $add_skipped_lines = 0; my $add_foreach_depth = 1; my $add_macro_depth = 1; my $add_tag_action = 0; # duplicate the file line '$tag($act'\)' # ------------------------- my $set_rh_debug = 0; # set ALL debug flags ON my $set_if_debug = 0; my $set_set_debug = 0; my $set_list_debug = 0; my $set_list_debug2 = 0; my $set_macro_debug = 0; # ${$rh}{'show_macro_dbg'} my $add_foreach_debug = 0; # DEBUG FOREACH - but problem found my $set_per_line_debug = 0; my $set_processing_debug = 1; my $set_processing_debug2 = 0; my $set_processing_debug3 = 0; my $show_if_actions = 1; # output IF actions at END my $show_set_items = 0; my $show_list_items = 0; my $write_directive_list = 0; my $show_macro_items = 0; my $show_function_items = 0; my $show_if_items = 0; # specific lines my $test_cmake_line1 = 0; my $test_cmake_line2 = 0; my $test_cmake_line3 = 0; my $test_cmake_line4 = 0; my $debug_level_proc = 0; # have defined 0x100 | 0x200 | 0x400; my $debug_level_load = $debug_level_proc; my $input_file = ''; my @in_files = (); my $def_file1 = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\AddFileDependencies.cmake'; my $def_file2 = 'C:\FGCVS\flightgear\source\CMakeLists.txt'; my $def_file3 = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\FindHDF5.cmake'; my $def_file4 = 'C:\FGCVS\flightgear\source\CMakeModules\FlightGearComponent.cmake'; my $def_file5 = 'C:\FGCVS\flightgear\source\CMakeModules\FindSimGear.cmake'; my $def_file6 = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\FindBoost.cmake'; my $def_file7 = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\CMakeDetermineCXXCompiler.cmake'; my $def_file8 = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\CMakeVerifyManifest.cmake'; my $def_file9 = 'C:\FGCVS\cmake\CMakeLists.txt'; #my $in_file = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\FindCUDA\run_nvcc.cmake'; #my $in_file = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\CPack.cmake'; #my $in_file = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\FindCUDA\run_nvcc.cmake'; #my $in_file = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\FindFLTK.cmake'; #my $in_file = 'C:\Program Files (x86)\CMake 2.8\share\cmake-2.8\Modules\Platform\Windows-cl.cmake'; my @test_files = ( "$def_file1", "$def_file2", "$def_file3" ); if ($test_curr_file) { #$input_file = $def_file9; push(@in_files,$def_file2); push(@in_files,$def_file9); #push(@in_files,$def_file2); } my $chk_line1 = 'STRING(REGEX REPLACE "\\\\\\\\" "/" FLTK_DIR_SEARCH1 "$ENV{PATH}")'; my $chk_line2 = 'string(REPLACE "\\"" "\\\\\\"" arg ${arg})'; my $chk_line3 = 'string(REPLACE "\\\\\\\\\\\\\\\\\\"" "\\"\\\\\"" "\\"\\\\\\\\\\\\\"" arg ${arg})'; my $chk_line4 = 'string(REPLACE "\\"\\\\\\\\\\\\\\"" "\\"" arg ${arg})'; ###my $in_file = ''; my $verbosity = 0; my $debug_on = 0; my $def_file = 'def_file'; my $out_xml = ''; ### program variables my @warnings = (); my $cwd = cwd(); my ($ref_hash); my @libs = (); my @exes = (); sub get_curr_ref_hash() { return $ref_hash; } 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) { my %dupes = (); my $cnt = scalar @warnings; prt( "\nShowing, up to $cnt WARNINGS...\n" ); $cnt = 0; foreach my $itm (@warnings) { if (!defined $dupes{$itm}) { $dupes{$itm} = 1; prt("$itm\n"); $cnt++; } } prt("Shown $cnt WARNINGS...\n"); } else { prt( "\nNo warnings issued.\n\n" ) if (VERB9()); } } sub get_proj_0($) { my $ra = shift; my ($ra2); my $projs = ''; foreach $ra2 (@{$ra}) { $projs .= "," if (length($projs)); $projs .= ${$ra2}[0]; } return $projs; } sub get_proj_lines($) { my $ra = shift; my ($ra2,$proj); my $lines = ''; my $cnt = scalar @{$ra}; my $maxlen = 0; my $len = 0; foreach $ra2 (@{$ra}) { $proj = ${$ra2}[0]; $len = length($proj); $maxlen = $len if ($len > $maxlen); } foreach $ra2 (@{$ra}) { $proj = ${$ra2}[0]; $proj .= ' ' while (length($proj) < $maxlen); $lines .= $proj; $lines .= " "; $lines .= ${$ra2}[1]; $lines .= "\n"; } return $lines; } sub close_dump() { my $rh = get_curr_ref_hash(); my ($msg); my $lcnt = scalar @libs; my $ecnt = scalar @exes; if (!defined ${$rh}{'CURR_DUMP_HANDLE'}) { return; } prt("Found $lcnt LIBS, and $ecnt EXES\n"); if (VERB5()) { $msg = get_proj_lines(\@libs); prt("\nLIBS:$lcnt:\n$msg") if ($lcnt); $msg = get_proj_lines(\@exes); prt("\nEXES:$ecnt:\n$msg") if ($ecnt); } elsif (VERB1()) { $msg = get_proj_0(\@libs); prt("LIBS:$lcnt: $msg\n") if ($lcnt); $msg = get_proj_0(\@exes); prt("EXES:$ecnt: $msg\n") if ($ecnt); } my $fh = ${$rh}{'CURR_DUMP_HANDLE'}; my $df = ${$rh}{'CURR_DUMP_NAME'}; print $fh "# End of DUMP $df\n"; close $fh; prt("Written DUMP to [$df]\n"); system($df) if ($load_dump_file); } sub split_act_to_proj_srcs($$$$) { my ($act,$rp,$rs,$lib) = @_; $act =~ s/\(//g; $act =~ s/\)//g; $act = trim_all($act); my @arr = split(/\s+/,$act); my $acnt = scalar @arr; my $i = 1; ${$rp} = $arr[0]; my $srcs = ''; if ($lib && ($acnt > 1)) { $srcs = $arr[$i]; if ($srcs =~ /^STATIC$/i) { ##${$rp} .= " STATIC"; $i++; } elsif ($srcs =~ /^SHARED$/) { ${$rp} .= " SHARED"; $i++; } } $srcs = ''; for (; $i < $acnt; $i++) { $srcs .= ',' if (length($srcs)); $srcs .= $arr[$i]; } ${$rs} = $srcs; return $acnt; } # if ($dump_cmake_file) - dump cleaned lines to a debug file sub dump_cmake($) { my $rh = shift; my ($fh); my ($rcln,$line,$clnn,$tag,$tdep); if (!defined ${$rh}{'CURR_DUMP_HANDLE'}) { if ( !open($fh,">$tmp_cmake") ) { # open the TEMP DUMP file pgm_exit(1,"ERROR: Unable to OPEN dump [$tmp_cmake]\n"); } ${$rh}{'CURR_DUMP_HANDLE'} = $fh; ${$rh}{'CURR_DUMP_NAME'} = $tmp_cmake; $line = "# Dianostic DUMP file created: "; $line .= lu_get_YYYYMMDD_hhmmss(time()); print $fh "$line\n" } $fh = ${$rh}{'CURR_DUMP_HANDLE'}; my $ara = ${$rh}{"ACT_RA"}; my $acnt = ${$rh}{"ACT_CNT"}; # = scalar @arr; my $rclines = ${$rh}{"CLEAN_LINES"}; my $cnt = scalar @{$rclines}; my $bfile = ${$rh}{'BASE_FILE'}; $line = "\nContents of [$bfile] $cnt 'cleaned' lines"; print $fh "$line\n"; $rcln = ${$rclines}[-1]; my $lnn = ${$rcln}[3]; my $frm = sprintf("%d",length($lnn)); $frm = '%'.$frm.'d'; my $idep = 0; my $ind = ''; my $isif = 0; my $pdep = 0; my $plnn = 1; my $endln = 0; my $fedep = 0; my $isfe = 0; my $pfedep = 0; my $comm = ''; my $cind = "\t"; my $mcdep = 0; my $pmcdep = 0; my $ismac = 0; my $act = ''; my $msg = ''; my ($proj,$srcs); foreach $rcln (@{$rclines}) { # 0 1 2 3 4 #push(@{$rclines},[$line,$ucdir,$action,$bgnln,$endln]); $line = ${$rcln}[0]; $tag = ${$rcln}[1]; $act = ${$rcln}[2]; $lnn = ${$rcln}[3]; $endln = ${$rcln}[4]; $ind = ''; $isif = 0; if ($add_uctag) { $comm = " # $tag $lnn:$endln"; } if ($add_if_depth) { if ($tag eq 'IF') { $pdep = $idep; $idep++; $isif = 1; } elsif ($tag eq 'ENDIF') { $idep-- if ($idep > 0); $pdep = $idep; $isif = 1; } elsif ($tag eq 'ELSE') { $isif = 2; } elsif ($tag eq 'ELSEIF') { $isif = 3; } #if ($isif) { # $ind = ' ' x $pdep; #} else { # $ind = ' ' x $idep; #} } $isfe = 0; if ($add_foreach_depth) { if ($tag eq 'FOREACH') { $isfe = 1; $pfedep = $fedep; $fedep++; } elsif ($tag eq 'ENDFOREACH') { $isfe = 1; $fedep-- if ($fedep); $pfedep = $fedep; } } # $add_macro_depth $ismac = 0; if ($add_macro_depth) { if ($tag eq 'MACRO') { $ismac = 1; $pmcdep = $mcdep; $mcdep++; } elsif ($tag eq 'ENDMACRO') { $ismac = 1; $mcdep-- if ($mcdep); $pmcdep = $mcdep; } } if ($add_if_depth || $add_foreach_depth || $add_macro_depth) { $tdep = 0; if ($isif) { $tdep += $pdep; } else { $tdep += $idep; } if ($isfe) { $tdep += $pfedep; } else { $tdep += $fedep; } if ($ismac) { $tdep += $pmcdep; } else { $tdep += $mcdep; } $ind = $cind x $tdep; } # collect the INFORMATION $msg = ''; if ($add_skipped_lines) { while ($plnn < $lnn) { if ($add_line_nums) { $clnn = sprintf($frm,$plnn); $msg .= "$clnn: # skipped\n"; } else { $msg .= "# skipped\n"; } $plnn++; } } if ($add_line_nums) { $clnn = sprintf($frm,$lnn); $msg .= "$clnn: $ind$line$comm\n"; if ($add_tag_action) { $msg .= "$clnn: $ind$tag$act\n"; } } else { $msg .= "$ind$line$comm\n"; if ($add_tag_action) { $msg .= "$ind$tag$act\n"; } } if ($add_skipped_lines) { while ($lnn < $endln) { $lnn++; if ($add_line_nums) { $clnn = sprintf($frm,$lnn); $msg .= "$clnn:\n"; } else { $msg .= "\n"; } } } if ($tag =~ /add_executable/i) { #prt("$line\n"); #prt("EXE $act\n"); split_act_to_proj_srcs($act,\$proj,\$srcs,0); prt("EXE $proj: $srcs\n") if (VERB9()); push(@exes,[$proj,$srcs,$rh]); } elsif ($tag =~ /add_library/i) { #prt("$line\n"); #prt("LIB $act\n"); split_act_to_proj_srcs($act,\$proj,\$srcs,1); prt("LIB $proj: $srcs\n") if (VERB9()); push(@libs,[$proj,$srcs,$rh]); } # output of the INFORMATION # ============================================ print $fh $msg; # ============================================ $plnn = $lnn + 1; # update line number } $line = "# eof - from [$bfile]"; print $fh "$line\n"; } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_dump(); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } # ================================================= # enventual LIBRARY functions # ================================================= sub get_cmake_install_paths_ra() { my $envstg = $ENV{"PATH"}; my ($path,$up,@arr,$ver,$tmp,$cnt); my @paths = (); #prt("ENV(PATH) = $envstg\n"); @arr = split(";",$envstg); $cnt = scalar @arr; #prt("Got $cnt paths to test...\n"); foreach $path (@arr) { #prt("Testing [$path]\n"); next if (length($path) == 0); if ($path =~ /CMake/i) { $path =~ s/(\\|\/)bin$//i; $ver = ''; if (-d $path) { #$up = path_d2u($path); $up = path_u2d($path); prt("Adding path [$up]\n"); @arr = split(/(\/|\\)+/,$up); foreach $tmp (@arr) { if ($tmp =~ /cmake/i) { $ver = $tmp; last; } } push(@paths,[$up,$ver]); } else { prtw("WARNING: Not a valid DIRECTORY! [$path]\n"); } } else { # prt("Not 'CMake' related!\n"); } } return \@paths; } sub scan_cmake_path($$); sub scan_cmake_path($$) { my ($path,$rh) = @_; # my @installed_files = (); # ${$rh}{'CMAKE_INSTALLED_FILES'} = \@installed_files; my $rif = ${$rh}{'CMAKE_INSTALLED_FILES'}; my @dirs = (); if (opendir(DIR,$path)) { my @files = readdir(DIR); closedir(DIR); my ($file,$ff); cmake_fix_directory(\$path); foreach $file (@files) { next if (($file eq '.')||($file eq '..')); $ff = $path.$file; if (-l $ff) { # ignore links } elsif (-d $ff) { push(@dirs,$ff); } elsif (-f $ff) { if ($file =~ /\.cmake$/i) { #prt("adding file [$ff]\n"); push(@{$rif},$ff); } } else { prtw("WARNING: Unable to find file [$ff]!\n"); } } foreach $path (@dirs) { scan_cmake_path($path,$rh); } } else { prtw("WARNING: Unable to open directory [$path]!\n"); } } my $common_cmake_directory = ''; sub get_cmake_common_directory($) { my $fil1 = shift; my $fil2 = $common_cmake_directory; my $len1 = length($fil1); my $len2 = length($fil2); if ($len2) { my $comm = ''; my ($i,$ch1,$ch2); for ($i = 0; (($i < $len1) && ($i < $len2)); $i++) { $ch1 = substr($fil1,$i,1); $ch2 = substr($fil2,$i,1); last if ($ch1 ne $ch2); $comm .= $ch1; } $common_cmake_directory = $comm; } else { $common_cmake_directory = $fil1 if ($len1); } } sub scan_cmake_install_paths($) { my $rh = shift; if (!defined ${$rh}{'CMAKE_INSTALLED_FILES'}) { pgm_exit(1,"ERROR: Ref has passed does not define 'CMAKE_INSTALLED_FILES'!\n"); } my ($i,$path,$ver); my $rval = 0; my $rp = get_cmake_install_paths_ra(); my $cnt = scalar @{$rp}; if ($cnt) { for ($i = 0; $i < $cnt; $i++) { $path = ${$rp}[$i][0]; scan_cmake_path($path,$rh); } my $rif = ${$rh}{'CMAKE_INSTALLED_FILES'}; foreach $path (@{$rif}) { get_cmake_common_directory($path); } ${$rh}{'CMAKE_INSTALLED_PATH'} = $common_cmake_directory; } else { prtw("WARNING: Found NO Cmake install paths!\n"); $rval = 1; } return $rval; } # ================================================= sub is_a_loaded_macro($$$$) { my ($tag,$rh,$rargs,$rmacro) = @_; my $dbg_flag = get_cmake_dbg_flag($rh); my $iret = 0; my $rmh = ${$rh}{'CMAKE_MACROS'}; # if (defined ${$rma}{$mac}) { # 0 1 # ${$rma}{$mac} = [$args,$macro]; my $min = 0; my $max = 32; my ($mac,$len,$rma,$args,$macro); my @arr = keys(%{$rmh}); my $cnt = scalar @arr; # prt("\nDisplay of $cnt MACROS collected...\n"); foreach $mac (@arr) { $rma = ${$rmh}{$mac}; $args = ${$rma}[0]; $macro = ${$rma}[1]; #prt("$mac $args [$macro}\n"); if ($tag eq uc($mac)) { $iret = 1; ${$rargs} = $args; ${$rmacro} = $macro; last; } } #if ($tag eq 'ADD_CMAKEONLY_TEST') { # if ($iret) { # prtw("WARNING: MACRO [$tag] NOT PROCESSED, FOUND in\n[".join(" ",sort @arr)."]!\n"); # } else { # prtw("WARNING: MACRO [$tag] NOT FOUND in\n[".join(" ",sort @arr)."]????\n"); # } #} return $iret; } sub clean_cmake_action($) { my $act = shift; $act =~ s/^\(//; $act =~ s/\)$//; #$act = trim_all($act); return $act; } sub cmake_clean_action($) { my $act = shift; $act =~ s/^\(//; $act =~ s/\)$//; $act = trim_all($act); # 04/05/2012 CAN NOT DO THIS - consider the case of mutiple tokens, like # "${VAR}" MATCHES "this" - has quote begin and end. BUT MUST NOT BE REMOVED #if (($act =~ /^\"/) && ($act =~ /\"$/)) { # $act = substr($act,1,length($act)-2); # if ($act =~ /^".*"$/); # $act = trim_all($act); #} return $act; } sub process_clean_ref_array($) { # was process_cmake_script($) my $rh = shift; if (!defined ${$rh}{'BASE_FILE'}) { pgm_exit(1,"ERROR: Ref hash does NOT define 'BASE_FILE'!\n"); } my $bfile = ${$rh}{'BASE_FILE'}; if (!defined ${$rh}{"CLEAN_LINES"}) { prtw("WARNING: No 'CLEAN_LINES' in ref hash. No [$bfile] processing!\n"); return 1; } my $rclines = ${$rh}{"CLEAN_LINES"}; my $csrc = ${$rh}{'CURR_LINE_SOURCE'}; my $cnt = scalar @{$rclines}; my $dbg_flag = 0; if (defined ${$rh}{'CURR_DBG_FLAG'}) { $dbg_flag = ${$rh}{'CURR_DBG_FLAG'}; } else { ${$rh}{'CURR_DBG_FLAG'} = $debug_level_proc; } my $src = $bfile; my $dbg = 0; if ($csrc eq $bfile) { $dbg = ${$rh}{'show_process_dbg'}; } else { # prt("\n") if ($dbg_flag & 0x100);; $src = $csrc; $dbg = ${$rh}{'show_process_dbg2'}; } prt("[d100] Processing $cnt lines, from [$src]...\n") if (($dbg_flag & 0x100) && $dbg); # 0 1 2 3 4 # push(@{$rclines},[$line,$tag,$action,$bln,$eln]); my ($i,$line,$tag,$action,$func,$bln,$eln,$act,@arr,$tmp,$args,$macro); ${$rh}{"ACT_LCNT"} = $cnt; # lines to process for ($i = 0; $i < $cnt; $i++) { $line = ${$rclines}[$i][0]; next if ($line =~ /^\@/); # skip these for now '@something@ $tag = ${$rclines}[$i][1]; $action = ${$rclines}[$i][2]; $bln = ${$rclines}[$i][3]; $eln = ${$rclines}[$i][4]; $act = cmake_clean_action($action); #$act = clean_cmake_action($action); @arr = space_split($act); ${$rh}{"ACT_TAG"} = $tag; ${$rh}{"ACT_ACT"} = $act; ${$rh}{"ACT_RA"} = \@arr; ${$rh}{"ACT_LNN"} = $bln; ${$rh}{"ACT_LNN"} .= ":$eln" if ($bln != $eln); ${$rh}{"ACT_LINE"} = $line; ${$rh}{"ACT_CNT"} = scalar @arr; ${$rh}{'ACT_I'} = $i; # current line position prt("[d80] $bln:$eln: $line\n") if (${$rh}{'per_line_dbg'}); if (is_a_loaded_macro($tag,$rh,\$args,\$macro)) { prt("[d100] Run MACRO NOT YET CODED! [$tag $args \n[$macro]]\n") if (($dbg_flag & 0x100) && ${$rh}{'show_macro_dbg'}); } elsif (is_a_known_directive($tag)) { $tmp = join(" ",@arr); #if ($tag eq 'LIST') { # prt("[d200] Processing DIRECTIVE [$tag] $i of $cnt ($action) ($tmp) $bln:$eln [$src]\n") if ($dbg_flag & 0x200); #} $func = get_directive_function($tag); # ======================================= $func->($rh); # CALL THE FUNCTION HANDLER # ======================================= $i = ${$rh}{'ACT_I'}; # potentially updated line position ###prt("[d400] Done DIRECTIVE [$tag] $i of $cnt\n") if ($dbg_flag & 0x400); } else { my $rdirh = ${$rh}{'new_directives_found'}; # process_clean_ref_array; was process_cmake_script: adding to \%directives if NOT FOUND if (defined ${$rdirh}{$tag}) { ${$rdirh}{$tag}++; ${$rh}{'warnings_avoided'}++; } else { ${$rdirh}{$tag} = 1; prtw("WARNING: [$tag] is NOT a known directive, nor loaded MACRO act [$action] [$bfile]$bln:$eln\n"); } } } } sub process_cmake_file($) { my $rh = shift; my $dbg_flag = get_cmake_dbg_flag($rh); my $ff = ${$rh}{'BASE_FILE'}; # $test_file; my $rflh = ${$rh}{'CMAKE_FILES_LOADED'}; # process_cmake_file: = \%cmake_files_loaded; if (defined ${$rflh}{$ff}) { # already loaded - silently forget it return; } ${$rflh}{$ff} = 1; my $fcnt = scalar keys(%{$rflh}); if (load_cmake_script_file($rh)) { prtw("WARNING: process_cmake_file: Failed to load [$ff]\n"); } else { my $rclines = ${$rh}{"CLEAN_LINES"}; my $rcnt = ${$rh}{"ACT_LCNT"}; my $cnt = scalar @{$rclines}; prt("$fcnt: process_cmake_file: [$ff] ok, $cnt of $rcnt lines\n") if (${$rh}{'show_process_dbg3'}); if ($cnt) { dump_cmake($rh) if ($dump_cmake_file); ${$rh}{'CURR_DBG_FLAG'} = $debug_level_proc; process_clean_ref_array($rh); # was process_cmake_script($rh); # from process_cmake_file } ### prt("process_cmake_file: done [$ff]\n") if (${$rh}{'show_process_dbg'}); } } sub process_in_file($$) { my ($ff,$rh) = @_; ${$rh}{'BASE_FILE'} = $ff; # $test_file; ${$rh}{'CURR_LINE_SOURCE'} = $ff; # set FILE source ${$rh}{'CURR_DBG_FLAG'} = -1 if (!defined ${$rh}{'CURR_DBG_FLAG'}); process_cmake_file($rh); } sub process_test_file($$) { my ($ff,$rh) = @_; ${$rh}{'BASE_FILE'} = $ff; ${$rh}{'CURR_LINE_SOURCE'} = $ff; # set FILE source ${$rh}{'CURR_DBG_FLAG'} = -1 if (!defined ${$rh}{'CURR_DBG_FLAG'}); process_cmake_file($rh); } sub test_load_installed_cmake($) { my $rh = shift; my @a = (); my $svdebug = 0; $svdebug = ${$rh}{'CURR_DBG_FLAG'} if (defined ${$rh}{'CURR_DBG_FLAG'}); # set the DEBUG for the INSTALL LOAD my $dbg_flag = -1; $dbg_flag &= ~(0x8000); $dbg_flag = 0; $dbg_flag |= 0x100; ${$rh}{'CMAKE_INSTALLED_FILES'} = \@a; ${$rh}{'CURR_DBG_FLAG'} = $dbg_flag; scan_cmake_install_paths($rh); my $rif = ${$rh}{'CMAKE_INSTALLED_FILES'}; my $cnt = scalar @{$rif}; prt("Got $cnt files to load...\n"); my ($ff); my ($dir,$i,$ch); foreach $ff (@{$rif}) { process_in_file($ff,$rh); } my $rmh = ${$rh}{'CMAKE_MACROS'}; my $mcnt = scalar keys(%{$rmh}); my $rfh = ${$rh}{'CMAKE_FUNCTIONS'}; my $fcnt = scalar keys(%{$rfh}); prt("Done loading $cnt files... $cnt dirs, $mcnt macs, $fcnt funcs\n"); $dir = ${$rh}{'CMAKE_INSTALLED_PATH'}; prt("Common cmake 'install' directory [$dir]\n"); ${$rh}{'CURR_DBG_FLAG'} = $svdebug; } sub do_cmake_subdirectories($) { my $rh = shift; my $dbg_flag = get_cmake_dbg_flag($rh); # ADD_SUBDIRECTORY # my %subdirs = (); # ${$rh}{'CMAKE_SUBDIRS'} = \%subdirs; #my %subs_done = (); # ${$rh}{'CMAKE_SUBSDONE'} = \%subs_done; my $rsh = ${$rh}{'CMAKE_SUBDIRS'}; my $rsd = ${$rh}{'CMAKE_SUBSDONE'}; my $max = scalar keys(%{$rsh}); my $done = scalar keys(%{$rsd}); my ($i,$sd,$todo,$rsa,$key,$ff); while ($max != $done) { $todo = $max - $done; prt("[d100] ADD_SUBDIRECTORIES: Now loading $todo files from subdirectories added...\n") if (($dbg_flag & 0x100) && ${$rh}{'show_addsub_dbg'}); #for ($i = 0; $i < $max; $i++) { foreach $key (keys %{$rsh}) { $rsa = ${$rsh}{$key}; # push(@{$rsubs},[$item1,$ff]); #$sd = ${$rsa}[$i][0]; #$ff = ${$rsa}[$i][1]; $sd = ${$rsa}[0]; $ff = ${$rsa}[1]; if (!defined ${$rsd}{$ff}) { ${$rsd}{$ff} = 1; ###process_in_file($ff,$rh); process_test_file($ff,$rh); } } $max = scalar keys(%{$rsh}); $done = scalar keys(%{$rsd}); } } sub test_lines($) { my $rh = shift; #my $chk_line1 = 'STRING(REGEX REPLACE "\\\\" "/" FLTK_DIR_SEARCH1 "$ENV{PATH}")'; #my $chk_line2 = 'string(REPLACE "\"" "\\\"" arg ${arg})'; my @arr = (); ${$rh}{'BASE_FILE'} = "TEST LINES"; ${$rh}{'CURR_DBG_FLAG'} = -1; ${$rh}{"BASE_LINES"} = \@arr; if ($test_cmake_line1) { @arr = (); push(@arr,$chk_line1); ${$rh}{'BASE_FILE'} = "TEST LINE 1"; process_cmake_raw_lines($rh); } if ($test_cmake_line2) { @arr = (); push(@arr,$chk_line2); ${$rh}{'BASE_FILE'} = "TEST LINE 2"; process_cmake_raw_lines($rh); } if ($test_cmake_line3) { @arr = (); push(@arr,$chk_line3); ${$rh}{'BASE_FILE'} = "TEST LINE 3"; process_cmake_raw_lines($rh); } if ($test_cmake_line4) { @arr = (); push(@arr,$chk_line4); ${$rh}{'BASE_FILE'} = "TEST LINE 4"; process_cmake_raw_lines($rh); } } # $rih = ${$rh}{'CMAKE_SETMACROS'}; sub list_set_items($) { my $rh = shift; my $rih = ${$rh}{'CMAKE_SETMACROS'}; my @arr = keys(%{$rih}); my $cnt = scalar @arr; my ($set,$rsi,$val,$min,$len,$max); $min = 0; $max = 32; foreach $set (@arr) { $len = length($set); $min = $len if ($len > $min); last if ($min > $max); } $min = $max if ($min > $max); prt("\nDisplay of $cnt SET items, and their value...\n"); foreach $set (sort @arr) { $rsi = ${$rih}{$set}; $val = join(" ",@{$rsi}); $set .= ' ' while (length($set) < $min); prt("$set = [$val]\n"); } prt("Done display of $cnt SET items, and their value...\n"); } # $rli = ${$rh}{'CMAKE_LISTS'}; sub list_list_items($) { my $rh = shift; my $rih = ${$rh}{'CMAKE_LISTS'}; my @arr = keys(%{$rih}); my $cnt = scalar @arr; my ($set,$rsi,$val,$min,$len,$max); $min = 0; $max = 32; foreach $set (@arr) { $len = length($set); $min = $len if ($len > $min); last if ($min > $max); } prt("\nDisplay of $cnt LIST items, and their value...\n"); foreach $set (sort @arr) { $rsi = ${$rih}{$set}; $val = join(" ",@{$rsi}); $set .= ' ' while (length($set) < $min); prt("$set = [$val]\n"); } prt("Done display of $cnt LIST items, and their value...\n"); } sub get_body() { my $txt = <; close INF; foreach $line (@lines) { if ($line =~ /^sub\s+fn_(\w+)\W/) { $tmp = $1; $subs_found{$tmp} = 1; } } } @arr = keys(%subs_found); $cnt = scalar @arr; prt("Found $cnt existing directive subs...\n"); $msg = ''; @arr = keys(%{$rdirh}); $cnt = scalar @arr; prt("Collected $cnt directives...\n"); foreach $dir (sort @arr) { if (!defined $subs_found{$dir}) { $msg .= "sub fn_$dir {\n$body\n}\n"; } } $msg .="\nmy \%directive_hash = ("; foreach $dir (sort @arr) { $line = " '$dir' "; $line .= " " while (length($line) < $min); $tmp = "fn_$dir"; $msg .= "\n $line=> \\\&$tmp,"; } $msg =~ s/,$//g; $msg .= "\n);\n"; write2file($msg,$outdirs); prt("Written directives hash to [$outdirs]\n"); } sub list_macro_items($) { # if ($show_macro_items); my $rh = shift; my $rmh = ${$rh}{'CMAKE_MACROS'}; # if (defined ${$rma}{$mac}) { # 0 1 # ${$rma}{$mac} = [$args,$macro]; my $min = 0; my $max = 32; my ($mac,$len,$rma,$args,$macro); my @arr = sort keys(%{$rmh}); my $cnt = scalar @arr; prt("\nDisplay of $cnt MACROS collected...\n"); foreach $mac (@arr) { $rma = ${$rmh}{$mac}; $args = ${$rma}[0]; $macro = ${$rma}[1]; prt("$mac $args [$macro}\n"); } prt("\nDone display of $cnt MACROS collected...\n"); } sub list_function_items($) { # if ($show_function_items); my $rh = shift; } sub set_specific_debug($) { my $rh = shift; ${$rh}{'CURR_DBG_FLAG'} = $debug_level_load; set_rh_debug_flags($rh,1) if ($set_rh_debug); set_foreach_debug_flags($rh,1) if ($add_foreach_debug); ${$rh}{'show_if_diags'} = 1 if ($set_if_debug); ${$rh}{'show_list_dbg'} = 1 if ($set_list_debug); ${$rh}{'show_list_dbg2'} = 1 if ($set_list_debug2); ${$rh}{'warn_list_no_code'} = 1 if ($set_list_debug2); ${$rh}{'show_set_dbg'} = 1 if ($set_set_debug); ${$rh}{'per_line_dbg'} = 1 if ($set_per_line_debug); ${$rh}{'show_process_dbg'} = 1 if ($set_processing_debug); ${$rh}{'show_process_dbg2'} = 1 if ($set_processing_debug2); ${$rh}{'show_process_dbg3'} = 1 if ($set_processing_debug3); ${$rh}{'show_macro_dbg'} = 1 if ($set_macro_debug); } sub scan_cmake_modules_path($$) { my ($itm,$rh) = @_; cmake_fix_directory(\$itm); my $mdir = $itm."CMakeModules"; if ((-d $mdir) && $inc_all_cmake) { my $rif = ${$rh}{'CMAKE_INSTALLED_FILES'}; my $pcnt = scalar @{$rif}; prt("Scanning module path [$mdir]...\n") if (VERB9()); scan_cmake_path($mdir,$rh); my $cnt = scalar @{$rif} - $pcnt; prt("Got $cnt files to load from [$mdir]\n") if (VERB9()); foreach my $ff (@{$rif}) { process_in_file($ff,$rh); } } else { prt("Module path [$mdir] does not exist...\n") if (VERB9()); } } sub process_item($$) { my ($itm,$rh) = @_; if (-f $itm) { my ($n,$d) = fileparse($itm); ${$rh}{'CMAKE_SOURCE_DIR'} = $d; ${$rh}{'CMAKE_BINARY_DIR'} = $d."build"; scan_cmake_modules_path($d,$rh); process_in_file($itm,$rh); } elsif (-d $itm) { if (opendir( DIR, $itm)) { my @files = readdir(DIR); closedir(DIR); cmake_fix_directory(\$itm); my ($fil,$ff,$mdir); foreach $fil (@files) { if ($fil =~ /^CMakeLists\.txt$/i) { ${$rh}{'CMAKE_SOURCE_DIR'} = $itm; ${$rh}{'CMAKE_BINARY_DIR'} = $itm."build"; scan_cmake_modules_path($itm,$rh); $ff = $itm.$fil; process_in_file($ff,$rh); } } } } do_cmake_subdirectories($rh); } sub process_inputs($) { my $rh = shift; test_load_installed_cmake($rh) if ($load_cmake_inst); if (@in_files) { my $f = scalar @in_files; prt("Loading $f input files...\n"); foreach $f (@in_files) { process_item($f,$rh); } } else { prt("No input files to load...\n"); } if (length($input_file) && (-f $input_file)) { prt("Loading file $input_file...\n"); process_item($input_file,$rh); } else { prt("No valid input file to load... [$input_file]\n") if (VERB9()); } do_cmake_subdirectories($rh); } sub cmake_parse_if($$) { my ($act,$rh) = @_; my $rdh = ${$rh}{'CMAKE_DEFINES'}; my $rta = cmake_token_split($act); my $res = 0; my ($tok,$val,$tmp,$str1,$str2,$cnt); my @braces = (); my @resarr = (); my $oper = ''; my $isstr = 0; my @vals = (); my @svals = (); my @ops = (); $str1 = ''; $str2 = ''; $cnt = 0; foreach $tok (@{$rta}) { if ($tok =~ /\$\{(\w+)\}/) { # a macro token $tmp = $1; if (defined ${$rdh}{$tmp}) { $val = ${$rdh}{$tmp}; $vals[$cnt] = ${$rdh}{$tmp}; $svals[$cnt] = "${$rdh}{$tmp}"; } elsif (cmake_macro_sub(\$tok,$rh)) { $val = $tok; $vals[$cnt] = $tok; $svals[$cnt] = "$tok"; } else { $val = 0; $vals[$cnt] = 0; $svals[$cnt] = ""; } $cnt++; } elsif ($tok =~ /\$ENV\{(\w+)\}/) { # an enviroment token $tmp = $1; if (exists $ENV{$tmp}) { $tmp = $ENV{$tmp}; } else { $tmp = 0; } $vals[$cnt] = $tmp; $svals[$cnt] = "$tmp"; $cnt++; # elsif (($txt =~ /^AND$/i)||($txt =~ /^OR$/i)||($txt =~ /^NOT$/i)||($txt =~ /^STREQUAL$/i)) { } elsif ($tok eq 'AND') { $oper = $tok; push(@ops,$tok); } elsif ($tok eq 'OR') { $oper = $tok; push(@ops,$tok); } elsif ($tok eq 'NOT') { $oper = $tok; push(@ops,$tok); } elsif ($tok eq 'STREQUAL') { $oper = $tok; $isstr = 1; push(@ops,$tok); } elsif ($tok eq 'MATCHES') { $oper = $tok; $isstr = 1; push(@ops,$tok); } elsif ($tok =~ /^\w+$/) { # also a macro? $tmp = "\${$tok}"; if (defined ${$rdh}{$tok}) { $val = ${$rdh}{$tok}; } elsif (!cmake_macro_sub(\$tmp,$rh)) { $val = $tmp; } else { $val = 0; } $vals[$cnt] = $val; $svals[$cnt] = ($val == 0) ? "" : "$val"; $cnt++; } else { # what is this } } return $res; } sub list_if_actions($) { # if ($show_if_actions) my $rh = shift; my $riftags = ${$rh}{'CMAKE_IFTAGS'}; my $rifma = ${$rh}{'CMAKE_IFACTS'}; ### push(@{$ria},$act); ### ${$rh}{'CURR_IN_IF'}++; # bump IF counter ### push(@{$rifstk},[$act,$lnn]); my ($txt,$i,$ch,$tag,%mods,$ra2,@arr,$lcnt,$tmp,$bfile,$lnn,$msg); $tag = ''; %mods = (); ###my $rta = cmake_token_split($act) ##my $rta = cmake_token_split_ra($ra); # ($txt =~ /\W*\$\{MSVC_VERSION\}/) { # if(${CMAKE_VERSION} VERSION_GREATER 2.8.4) # elsif (($txt =~ /^AND$/i)||($txt =~ /^OR$/i)||($txt =~ /^NOT$/i)||($txt =~ /^STREQUAL$/i)) { my $rdh = ${$rh}{'CMAKE_DEFINES'}; my $idcnt = 0; @arr = keys(%{$riftags}); $ch = scalar @arr; my @macros = (); my $mcnt = 0; my @envs = (); my $ecnt = 0; my @itags = (); my $tcnt = 0; ###my @lines = (); my %dupes = (); #push(@{$ria},[$act,$bfile,$lnn]); foreach $ra2 (@{$rifma}) { $tag = ${$ra2}[0]; $bfile = ${$ra2}[1]; $lnn = ${$ra2}[2]; if (!defined $dupes{$tag}) { $dupes{$tag} = [$tag,$bfile,$lnn]; ##push(@linesm,[$tag,$bfile,$lnn]); } } ###$lcnt = scalar @linesm; $lcnt = scalar keys(%dupes); foreach $tag (@arr) { # 0 1 2 # push(@{$ra2},[{%mods},$bfile,$lnn]); # $ra2 = ${$riftags}{$tag}; if ($tag =~ /^__MACRO_/) { $tag =~ s/^__MACRO_//; push(@macros,$tag); $mcnt++; } elsif ($tag =~ /^__ENV_/) { $tag =~ s/^__ENV_//; push(@envs,$tag); $ecnt++; } else { push(@itags,$tag); $tcnt++; } } if ( ($ch == 0) && ($mcnt == 0) && ($ecnt == 0) && ($tcnt == 0) ) { return; } prt("List of $ch IF tags... $mcnt macros, $ecnt environment, and $tcnt others... from $lcnt lines\n"); prt("TAGS: ${tcnt}\n".join(" ", sort @itags)."\n"); #prt("ENV: ${ecnt}\n".join("\n", sort @envs)."\n"); prt("\nENV: ${ecnt}\n"); foreach $tag (sort @envs) { prt("\$ENV{$tag}\n"); } #prt("MACROS: ${mcnt}\n".join("\n", sort @macros)."\n"); prt("\nMACROS: ${mcnt}\n"); $idcnt = 0; foreach $tag (sort @macros) { $tmp = $tag; if (defined ${$rdh}{$tag}) { $idcnt++; ##$tmp = ${$rdh}{$tag}; ##prt("\${$tag} = [$tmp]\n"); } elsif (cmake_macro_sub(\$tmp,$rh)) { ${$rdh}{$tag} = $tmp; $idcnt++; } else { prt("\${$tag}\n"); } } prt("With $idcnt evaluated in 'CMAKE_DEFINES', or SET or LISTS\n"); foreach $tag (sort @macros) { if (defined ${$rdh}{$tag}) { ##$idcnt++; $tmp = ${$rdh}{$tag}; prt("\${$tag} eval to [$tmp]\n"); } else { ##prt("\${$tag}\n"); } } #prt("\nLINES: ${lcnt}\n".join("\n", sort @lines)."\n"); prt("\nIF LINES: ${lcnt}\n"); $idcnt = 0; my @lines = sort keys(%dupes); #foreach $tag (@lines) { # $ra2 = $dupes{$tag}; # my $rta = cmake_token_split($act) # #} foreach $tag (@lines) { $ra2 = $dupes{$tag}; $bfile = ${$ra2}[1]; $lnn = ${$ra2}[2]; $msg = ''; if (defined ${$rdh}{$tag}) { $idcnt++; ##$tmp = ${$rdh}{$tag}; ##prt("IF($tag) eval [$tmp]\n"); } else { my $rta = cmake_token_split($tag); my $tc = scalar @{$rta}; $msg = "($tc)"; if ($tc > 1) { my $ntag = ''; my $ltmp = ''; foreach $tmp (@{$rta}) { $ntag .= ' ' if (length($ntag)); $ntag .= $tmp; $ltmp = $tmp; } if ($ltmp ne $ntag) { $msg = "(=$tc)"; } else { prt("IF($ntag) CHECK CHANGE\n"); } } #$res = cmake_parse_if($tag,$rh); prt("IF($tag) $msg [$bfile]$lnn\n"); } } prt("With $idcnt evaluated from 'CMAKE_DEFINES'\n"); foreach $tag (@lines) { $ra2 = $dupes{$tag}; $bfile = ${$ra2}[1]; $lnn = ${$ra2}[2]; if (defined ${$rdh}{$tag}) { ##$idcnt++; $tmp = ${$rdh}{$tag}; prt("IF($tag) eval [$tmp] [$bfile]$lnn\n"); } else { ##prt("IF($tag)\n"); } } } sub show_new_directives($) { my $rh = shift; my $rndh = ${$rh}{'new_directives_found'}; # = \%new_directives; my @arr = sort keys(%{$rndh}); my $cnt = scalar @arr; if ($cnt) { prt("WARNING: Found $cnt NEW directives - in \${\$rh}{'new_directives_found'}\n[".join(" ",@arr)."]\n"); #prt("my \%new_cmake_directives = (\n"); #$ch = ','; #for ($i = 0; $i < $cnt; $i++) { # $dir = $arr[$i]; # prt(" '$dir' => \\\&hand$ch\n"); # $ch = '' if (($i + 1) == $cnt); #} #prt(");\n"); #prt("# Listed $cnt directives...\n"); } } sub output_list_items($) { my $rh = shift; list_macro_items($rh) if ($show_macro_items); list_function_items($rh) if ($show_function_items); list_set_items($rh) if ($show_set_items); list_list_items($rh) if ($show_list_items); list_directives($rh) if ($write_directive_list); list_if_actions($rh) if ($show_if_actions); my $rflh = ${$rh}{'CMAKE_FILES_LOADED'}; # output_list_items: show total load count = \%cmake_files_loaded; my $cnt = scalar keys(%{$rflh}); prt("Loaded a total of $cnt files...\n"); } # ---- write a test case ---- sub write_test_case($$) { my ($fil,$rh) = @_; my $txt = < (-o) = Write output to this file.\n"); prt("\n"); prt(" Original used to help develop lib_cmakeread.pl, but subsequently used\n"); prt(" to test and report errors in cmake syntax, since cmake generally only\n"); prt(" reached EOF, without reporting where the problem started.\n"); prt(" Lots of switches that have no option yet, so very much a WIP!\n"); prt("\n"); } 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 = 2; 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 { $arg = File::Spec->rel2abs($arg); push(@in_files,$arg); if ((! -f $arg) && (! -d $arg)) { pgm_exit(1,"ERROR: Unable to find in file or folder [$arg]! Check name, location...\n"); } prt("Added [$arg] to input files...\n") if (VERB1()); } shift @av; } if (!@in_files && !$load_cmake_inst && !length($input_file)) { pgm_exit(1,"ERROR: No input files or directories found in command!\n"); } if (VERB9()) { $debug_level_proc = -1; # have defined 0x100 | 0x200 | 0x400; $debug_level_load = -1; $set_rh_debug = 1; set_specific_debug($ref_hash); prt("Got VERB9() so have set maximum debug ON\n"); } } # eof - chkcmake02.pl