Generated: Sun Aug 21 11:10:36 2011 from amsrcs04-new.pl 2010/09/29 68.3 KB.
#!/usr/bin/perl -w # NAME: amsrcs04.pl # AIM: To scan a GNU configure.ac, or configure.in input file, for output Makefiles, then # successifly scan the Maekfile.am (or .in) files, and create a DSP file foreach LIBRARY, # or PROGRAMS found in this make file san, then finally a DSW file. # ======================================================================================= # NOTE: This is NOT really a follow on from amsrcs03.pl ;=(( # This is a COMPLETE rewrite using lib_acscan.pl, and lib_amscan.pl # ======================================================================================= # History: Growing upwards... # 28/09/2010 Conditionals in the Makefile.am are stored, BUT when it comes to choosing the # correct sustitution, was just the FIRST TRUE always CHOSEN. # Added the option like - # --cond item[:1|0] (-c) = Define a conditional to be applied during parsing. # Revert to previous, if no conditional defined by user, but write a temp/missed_cond_list.txt # for items NOT defined. # 23/09/2010:19/09/2010 - Lots of updates, changes, additions # 08/09/2010 geoff mclane http://geoffair.net/mperl 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 RELATIVE use Cwd; my $perl_sdir = 'C:\GTools\perl'; unshift(@INC, $perl_sdir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl'! Check location and \@INC content.\n"; require 'lib_acscan.pl' or die "Unable to load 'lib_acscan.pl'! Check location and \@INC content.\n"; require 'lib_amscan.pl' or die "Unable to load 'lib_amscan.pl'! Check location and \@INC content.\n"; require 'lib_dsphdrs.pl' or die "Unable to load 'lib_dsphdrs.pl'! Check location and \@INC content.\n"; require 'lib_vcscan.pl' or die "Unable to load 'lib_vcscan.pl'! Check location and \@INC content.\n"; require 'lib_params.pl' or die "Unable to load 'lib_params.pl'! Check location and \@INC content.\n"; require 'lib_srcscan.pl' or die "Unable to load 'lib_srcscan.pl'! Check location and \@INC content.\n"; my $my_version = "version 0.4.8 2010-09-28"; # log file stuff my ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $perl_sdir."\\temp.$pgmname.txt"; open_log($outfile); my $perl_temp_dir = $perl_sdir."\\temp"; # user variables my $load_log = 0; my $conf_file = $perl_temp_dir."\\temp.$pgmname.conf"; my $no_conf_write = 0; my $amlistfile = $perl_temp_dir."\\amlist.txt"; my $write_am_list = 1; my $verbosity = 0; my $temp_copy_bat = $perl_temp_dir."\\tempcopy.bat"; my $miss_mac_file = $perl_temp_dir."\\missed_mscro_list.txt"; my $missing_list_file = $perl_temp_dir."\\missed_defined_list.txt"; my $missed_source_list = $perl_temp_dir."\\missed_source_list.txt"; my $missed_cond_list = $perl_temp_dir."\\missed_cond_list.txt"; my $show_per_file = 1; # ========================================================== # test projects my $debug_on = 0; # run with DEFAULT, if no other input... my $def_file = 'C:\Projects\libxml2\configure.in'; my $def_targ = ''; #my $def_file = 'C:\Projects\giflib\configure.ac'; #my $def_file = 'C:\Projects\pcre\configure.ac'; #my $def_targ = 'C:\Projects\giflib\msvc'; #my $def_targ = ''; #my $def_file = 'C:\Projects\libsigc\libsigc++-2.2.8\configure.ac'; #my $def_targ = 'C:\Projects\libsigc\libsigc++-2.2.8\msvc'; #my $def_name = 'pcre'; my $def_name = ''; # ============================================================ my %g_default_condits = ( # default conditionals "USE_GLUT" => "TRUE", "ENABLE_JPEG_SERVER" => "FALSE", "ENABLE_SP_FDM" => "TRUE" ); ######################################## ### SHARED RESOURCES, VALUES ### ======================== our $fix_relative_sources = 1; our %g_user_subs = (); # supplied by USER INPUT our %g_user_condits = (); # conditionals supplied by the user # Auto output does the following - # For libaries # Debug: '/out:"lib\barD.lib"' # Release:'/out:"lib\barD.lib"' # for programs # Debug: '/out:"bin\fooD.exe"' # Release:'/out:"bin\foo.exe"' # This also 'adds' missing 'include' files #Bit: 1: Use 'Debug\$proj_name', and 'Release\$proj_name' for intermediate and out directories #Bit: 2: Set output to lib, or bin, and names to fooD.lib/foo.lib or barD.exe/bar.exe #Bit: 4: Set program dependence per library output directories #Bit: 8: Add 'msvc' to input file directory, if no target directory given #Bit: 16: Add program library dependencies, if any, to DSW file output. #Bit: 32: Add all necessary headers to the DSP file. That is scan the sources for #include "foo.h", etc. #Bit: 64: Write a blank header group even there are no header files for that component. #Bit: 128: Add defined item of HAVE_CONFIG_H to all DSP files. #Bit: These can be given as an integer, or the form 2+8, etc. Note using -1 sets ALL bits on. #Bit: Bit 32 really slows down the DSP creation, since it involves scanning every line of the sources. my $auto_max_bit = 128; our $auto_on_flag = -1; #Bit: ALL ON by default = ${$rparams}{'CURR_AUTO_ON_FLAG'} #my ($g_in_name, $g_in_dir); #my ($root_file, $root_folder); #sub get_root_dir() { return $root_folder; } our $exit_value = 0; # But SOME Makefile.am will use specific 'paths' so the above can FAIL to find # a file, so the following two 'try harder' options, will do a full 'root' # directory SCAN, and search for the file of that name in the scanned files our $try_harder = 1; our $try_much_harder = 1; # ============================================================================== our $process_subdir = 0; our $warn_on_plus = 0; # ============================================================================== # NOTE: Usually a Makefile.am contains SOURCE file names 'relative' to itself, # which is usually without any path. This options ADDS the path to the # Makefile.am, and then substracts the 'root' path, to get a SOURCE file # relative to the 'root' configure.ac, which is what is needed if the DSP # is to be placed in a $target_dir, and we want the file relative to that our $add_rel_sources = 1; our $target_dir = ''; # ============================================================================== our $ignore_EXTRA_DIST = 0; our $added_in_init = ''; our $supp_make_in = 0; # Support Makefile.in scanning our $project_name = ''; # ***TBD*** a name to override any ac scanned name of the project ### ======================== my $proj_incs = '/I "."'; my $proj_rt = 'D'; # ie use /MD and /MDd my $proj_defs = '/D "_CRT_SECURE_NO_WARNINGS"'; # NOTE: For user includes, usually also NEED 'libpath' # like $proj_libD .= " /libpath:\"Debug\" foo.lib"; # like $proj_libR .= " /libpath:\"Release\" foo.lib"; # OR # like $proj_lib .= " /libpath:\"lib\"; # like $proj_libD .= " fooD.lib"; # like $proj_libR .= " foo.lib"; # sub in line ADD LINK32 kernel32.lib ... -NEW_LIBS- /nologo ... my $proj_libs = 'Winmm.lib ws2_32.lib'; my $proj_libD = ''; my $proj_libR = ''; # NOTE: This is for say '/out:"bin\foo.exe"' or '/out:"lib\bar.lib"' my $proj_outputR = ''; my $proj_outputD = ''; # object output, and the default for other things if NOT specifically stated my $proj_interR = '"Release"'; my $proj_interD = '"Debug"'; ### program variables my @warnings = (); my $cwd = cwd(); my $os = $^O; my $conf_string = ''; my $only_dry_run = 0; my $in_file = ''; my $curr_command = ''; ######################################### ### DEBUG STUFF ### # Debug items SHARED with LIBRARY - note use of 'our' - to adjust this list # must also adjust the lib_acscan.pl library!!! our $dbg_lac01 = 0; # prt( "[01] scan_..._file: Reading $file\n" ) if $dbg_lac01; and more our $dbg_lac02 = 0; # show EACH line prt( "[02] $lnn: $cline... for each read line. our $dbg_lac03 = 0; # prt( "[03] Variable [$key] = [$nval]\n" ) our $dbg_lac04 = 0; # prt( "[04] Split to $vlen components ...\n" ) our $dbg_lac05 = 0; # prt( "[05] Substitute [$key] = [$nval]\n" ) if ($v1 ne $v2)) our $dbg_lac06 = 0; # prt( "[06] $.: Should JOIN lines? - [$cline]\n" ) and more... our $dbg_lac07 = 0; # prt( "[07] $.: Got AC_INIT = [$1]\n" ) and AC_DEFIN... etc our $dbg_lac08 = 0; # prt( "[08] Got ac_output_line = $. [$rawline]\n" ) plus accumulation our $dbg_lac09 = 0; # prt( "[01|09] Adding $input [$ff] to mk_inp_list ...\n" ) our $dbg_lac10 = 0; # prt( "[01|10] Adding $input [$ff] to other_input_files ...\n" ) our $dbg_lac11 = 0; # prt( "[11] Storing configure_cond key $1 ... value=2\n" ), and more our $dbg_lac12 = 0; # prt( "[12] $.: 1=[$1] = 2=[$2] NOT USED [$cline]\n" ) our $dbg_lac13 = 0; # prt("[13] $lnn: Failed on MACRO [$blk], in file [$file]\n") our $dbg_lac14 = 0; # show each MACRO split in FULL our $dbg_lac15 = 0; # Show each AC MACRO accumulation... our $dbg_lac16 = 0; # Show back slash accumulation... our $dbg_lac17 = 0; # show all substitutions our $dbg_lac18 = 0; # show setting or replacing each macro with value our $dbg_lac19 = 0; # unused at present our $dbg_lac20 = 0; # prt("[20] Directory SEARCH for [$test], found $fcnt... my $dbg_lac_check = 20; ######################################### # DEBUG for lib_amscan.pl our $dbg_s01 = 0; # show each file line, in form "[01] $i2: [$line]" our $dbg_s02 = 0; # show extraction from hash, like "Listing $acnt keys in hash ..." our $dbg_s03 = 0; # show "Find sources for $val LIBRARY keys ...\n" and MORE our $dbg_s04 = 0; # show prt( "LIBRARY [$ky] has SOURCES [$val] our $dbg_s05 = 0; # show prt( "$am ". ((-f $am) ? "ok" : "no find!") our $dbg_s06 = 0; # show prt( "Opened cond_stack with [".$cond_stack[$#cond_stack]."] $fil our $dbg_s07 = 0; # add new line before 'Processing $cnt lines..., as does 08 also... our $dbg_s08 = 0; # show prt( "Processing $cnt lines from $fil ... our $dbg_s09 = 0; # show prt( "Got $cnt subdirectories [$slist] ... our $dbg_s10 = 0; # show prtw("WARNING:1: No substitution for [$ms] found in hash ... our $dbg_s11 = 0; # show target: gathering of lines... our $dbg_s12 = 0; # show setting key=value in hash, during am file scan our $dbg_s13 = 0; # show initial substitution, during am file scan our $dbg_s14 = 0; # similar to about, but only show NO sub FOUND our $dbg_s15 = 0; # List each source, for each project... our $dbg_s16 = 0; # Like [02] list ALL keys showing dispostion our $dbg_s17 = 0; # Out CHECK ME - SHOULD THIS ITEMS BE INCLUDED for a prog,lib,src key, now skipped! our $dbg_s18 = 0; # show change due to adding relative directory our $dbg_s19 = 0; # show finds found by directory searching... our $dbg_s20 = 0; # output list of sources and header from dir scan, NOT included in a project our $dbg_s21 = 0; # prt("\n[21] Seeking 'all' or 'default' in $cnt keys...\n"), and MORE... our $dbg_s22 = 0; # show '[22]CHANGED:1: key [gatomic_c] cond [FALSE] Was [gatomic-gcc.c], now [gatomic.c] FALSE, plus my $am_check_tot = 22; sub VERB1() { return ($verbosity > 0); } sub VERB2() { return ($verbosity > 1); } sub VERB5() { return ($verbosity > 4); } sub VERB9() { return ($verbosity > 8); } my $project_dbg_write = 0; sub set_all_dbg_on() { ac_set_all_dbg_on(); am_set_all_dbg_on(); } sub set_all_dbg_off() { ac_set_all_dbg_off(); am_set_all_dbg_off(); } sub set_max_debug_on() { $verbosity = 10; $project_dbg_write = -1; set_all_dbg_on(); #ac_set_dbg_extra(); prt("[debug_on] Have set MAXIMUM debug output...\n"); } sub wait_key() { prt("Any key to continue...\n"); my $char = <>; } # ***TBD*** this is NOW not called - see show_missing_subs2() instead # but perhaps this is better, in that it als adds those added automatically # but this is a 'conflict' between g_user_sub, and common_sub to be resolved sub show_missing_subs($) { my ($rsnf) = @_; if ($dbg_s13 || $dbg_s14) { my @arr = keys %{$rsnf}; my ($cnt,$txt,$key,$fil,$val,%hash,$msg); $txt = ''; if (@arr) { $cnt = scalar @arr; prt("[13|14] There are at least $cnt missing substitutions.\n"); $txt = "# [13|14] There are at least $cnt missing substitutions.\n"; if ($show_per_file) { %hash = (); foreach $key (@arr) { $fil = ${$rsnf}{$key}; push(@{$hash{$fil}},$key); } foreach $fil (keys %hash) { $val = $hash{$fil}; $cnt = scalar @{$val}; $txt .= "\n# Missing $cnt from file [$fil]\n"; prt("Missing $cnt ["); $msg = ''; foreach $key (sort @{$val}) { $txt .= "-m $key \"\"\n"; $msg .= ', ' if (length($msg)); $msg .= $key; } prt("$msg] from file [$fil]\n"); } } else { foreach $key (sort @arr) { $fil = ${$rsnf}{$key}; prt("Missing [$key], in [$fil]\n"); $txt .= "-m $key \"\"\n"; } } } else { prt("[13|14] There are NO missing substitutions.\n"); } @arr = split(/\s/,$added_in_init); $cnt = scalar @arr; if ($cnt) { prt("But note ADDED $cnt items, during init..."); if (length($miss_mac_file) && (length($txt))) { $txt .= "\n# Note the following set of $cnt items were added during init...\n"; %hash = (); init_common_subs2(\%hash,0); $cnt = 0; foreach $key (@arr) { if (defined $hash{$key}) { $val = $hash{$key}; if ( (length($val) == 0) || ($val =~ /^\s+$/) ) { $val = '""'; } $txt .= "-m $key $val\n"; $cnt++; } } prt(" also now added to response file..."); } prt("\n"); } if (length($miss_mac_file) && (length($txt))) { write2file($txt,$miss_mac_file); prt("Written list for use as '-r $miss_mac_file' response file, after correction.\n"); } } } # ============================================= sub show_warnings($) { my $val = shift; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { prt("No warnings issued.\n"); } } sub show_missing_conds() { my $rparams = get_ref_params(); my $rmc = ${$rparams}{'REF_MISSED_CONDITIONS'}; my $cnt = scalar keys(%{$rmc}); if ($cnt) { if (VERB1()) { prt("[v1] List of $cnt missing conditionals...\n"); } else { prt("Would list $cnt missing conditionals... if verbose >= 1\n"); } my ($key,$val,$msg,@arr,$num,%dupes); $msg = "# List of $cnt missing conditionals...\n"; $msg .= "# If used ONLY in TRUE or FALSE, then parameter should be correct.\n"; $msg .= "# but if used TRUE and FALSE, then must select 0 or 1 only.\n"; $cnt = 0; foreach $key (sort keys %{$rmc}) { $cnt++; $val = ${$rmc}{$key}; @arr = split(/\|/,$val); %dupes = (); foreach $num (@arr) { $dupes{$num} = 1; } @arr = sort keys(%dupes); $val = ''; foreach $num (@arr) { $val .= '|' if (length($val)); $val .= $num; } $num = '0|1'; if (scalar @arr == 1) { if ($val eq 'FALSE') { $num = 0; } elsif ($val eq 'TRUE') { $num = 1; } else { $num .= '?'; } } else { $msg .= "# TO BE SELECTED\n"; } $msg .= "-c $key:$num\n"; prt(" $cnt: $key $num ($val)\n") if (VERB1()); } if (length($missed_cond_list)) { write2file($msg,$missed_cond_list); prt("Written list of $cnt missing conditionals to [$missed_cond_list]\n"); } } else { prt("No missing conditionals listed.\n"); } } sub show_missing_subs2($) { my ($val) = shift; my $rparams = get_ref_params(); my $rsnf = ${$rparams}{'CURR_SUBS_NOT_FOUND'}; my @arr = keys %{$rsnf}; my $cnt = scalar @arr; my $msg = ''; #if ($dbg_lac13) { my ($key,$fil); if ($cnt) { $cnt = scalar @arr; prt("There are at least $cnt missing substitutions. "); if ($dbg_lac13) { prt("\n"); } else { prt("Use '-d 113' to view list...\n"); } foreach $key (sort @arr) { $fil = ${$rsnf}{$key}; prt("Missing [$key], in [$fil]\n") if ($dbg_lac13); $msg .= "-m $key \"\"\n"; } if (length($missing_list_file)) { write2file($msg,$missing_list_file); prt("List written to file [$missing_list_file] for review...\n"); } } else { prt("[13] There are NO missing substitutions.\n") if ($val == 0); } #@arr = split $added_in_init; #$cnt = scalar @arr; #prt("But note added $cnt, [$added_in_init] in init...\n") if (length($added_in_init)); #} elsif ($cnt && ($val == 0)) { # prt("There are at least $cnt missing substitutions. Use '-d 13' to view.\n"); #} if (defined ${$rparams}{'TOTAL_LINE_COUNT'} && defined ${$rparams}{'CURR_BEGIN_TIME'}) { $cnt = ${$rparams}{'TOTAL_LINE_COUNT'}; $key = time(); $fil = $key - ${$rparams}{'CURR_BEGIN_TIME'}; prt("Scanned a total of ".get_nn($cnt)." lines of source, in ".secs_HHMMSS($fil)." secs...\n"); } } sub pgm_exit($$) { my ($val,$msg) = @_; show_missing_conds() if ($val == 0); show_missing_subs2($val) if ($val != 2); if (length($conf_string) && ($val == 0) && !$no_conf_write) { write2file($conf_string,$conf_file); prt("Written configuration to [$conf_file]\n"); } show_warnings($val) if ($val != 2); if (length($msg)) { prt("Current CMD: [$curr_command]\n") if (length($curr_command)); prt("\a\n") if ($msg =~ /^ERROR/); $msg =~ s/\n$//; $msg .= " time:".localtime(time())."\n"; prt("$msg\n"); } else { prt("Current CMD: [$curr_command] time [".localtime(time())."]\n"); } close_log($outfile,$load_log); exit($val); } my %warnings_done = (); my $last_warning = ''; sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; # avoid REPETATIVE warnings prt("$tx\n") if ($tx ne $last_warning); $last_warning = $tx; if (!defined $warnings_done{$tx}) { $warnings_done{$tx} = 1; push(@warnings,$tx); } } sub write_to_am_list($$) { my ($ff,$ok) = @_; if (length($amlistfile) && $write_am_list) { my $dff = path_u2d($ff); my ($nm,$dir) = fileparse($ff); my $typ = 3; if ($ok) { my $lcid = lc(path_u2d(get_root_dir())); # g_in_dir my $lcfd = lc($dir); if ($lcid eq $lcfd) { $typ = 1; } else { $typ = 2; } } if (-f $amlistfile) { if (open INF, "<$amlistfile") { my @lines = <INF>; close INF; my ($line,@arr,$cnt,$fff); my $lcinf = lc($dff); foreach $line (@lines) { chomp $line; @arr = split(/\s/,$line); $cnt = scalar @arr; if ($cnt == 2) { $fff = lc($arr[1]); if ($fff eq $lcinf) { return; } } } } append2file("$typ $dff\n",$amlistfile); } else { write2file("$typ $dff\n",$amlistfile); } } } sub process_ac_file($) { my ($rparams) = @_; my $inf = ${$rparams}{'CURR_FILE'}; return if (! -f $inf); #($g_in_name, $g_in_dir) = fileparse($inf); prt("Scanning [$inf] file...\n"); scan_configure_ac_file($rparams,0); # ====================================================== show_ac_hash($rparams); return $rparams; } #==================================================== # do NOT know WHY I have 2 subs that do the SAME thing # sub sub_root_folder AND sub_root_dir($) sub sub_common_folder { my ($fil,$root) = @_; my $lfil = lc(path_u2d($fil)); my $lrot = lc(path_u2d($root)); my $len1 = length($lfil); my $len2 = length($lrot); my ($i); for ($i = 0; (($i < $len1)&&($i < $len2)); $i++) { if (substr($lfil,$i,1) ne substr($lrot,$i,1)) { last; } } return substr($fil,$i); } sub sub_root_folder { my ($fil) = shift; my $rd = get_root_dir(); return sub_common_folder($fil,$rd); } sub begins_with { my ($rt, $pt) = @_; my $ln = length($rt); my ($i); if (length($pt) >= $ln) { for ($i = 0; $i < $ln; $i++) { return 0 if (substr($rt,$i,1) ne substr($pt,$i,1)); } return 1; # does indeed begin with... } return 0; } sub sub_first_from_second_if($$) { my ($d1,$d2) = @_; if (being_with($d1,$d2)) { $d2 = substr($d2, length($d1)); } return $d2; } # VARIOUS FIXES FOR THE FILE NAME # 1. ensure ALL DOS format # 2. remove any simple dot relative, like '.\' from beginning # 3. if given a FULL PATH name, remove C:\FG\20\FlightGear # 4. if a relative name, remove FligthGear # 5. if any removal, ensure any beginning '\' is removed sub sub_root_dir($) { my ($ff) = shift; # = $a_dir.$src $ff = path_u2d($ff); my $rd = get_root_dir(); if (begins_with($rd, $ff)) { $ff = substr($ff, length($rd)); } return $ff; } sub process_one_am_file($); sub process_one_am_file($) { my ($rparams) = @_; my $fil = ${$rparams}{'AM_FILE'}; $fil = fix_rel_path3($fil,'process_one_am_file'); my $sfil = sub_root_folder($fil); ###return if (defined ${$ramsdone}{$fil}); ###my %h; ###${$ramsdone}{$fil} = \%h; my $ramh = am_process_AM_file($rparams,0); my $ramsdone = ${$rparams}{'REF_AMS_DONE'}; ${$ramsdone}{$fil} = $ramh; my ($p_tit,$p_dir,$p_ext) = fileparse( $fil, qr/\.[^.]*/ ); my $do_subs = ${$rparams}{'PROCESS_SUBDIR'}; if ($do_subs && (defined ${$ramh}{'SUBDIRS'})) { my $slist = ${$ramh}{'SUBDIRS'}; my @ar = split(/\s/,$slist); my $cnt = scalar @ar; prt( "[09] Got $cnt subdirectories [$slist] ...from [$sfil]\n" ) if ($dbg_s09); foreach my $dir (@ar) { my $am = $p_dir.$dir.'\Makefile.am'; $am = path_u2d($am); $am =~ s/\\\\/\\/g while ($am =~ /\\\\/); my $sam = sub_root_folder($am); if (-f $am) { prt( "[05] Processing AM file [$am], from [$fil] ...\n" ) if ($dbg_s05); ${$rparams}{'AM_FILE'} = $am; # DOS form ensured process_one_am_file($rparams); ${$rparams}{'AM_FILE'} = $fil; } else { prtw( "[05] WARNING: AM [$am] NOT FOUND! in [$dir], from [$fil]!\n" ) if ($dbg_s05); } } } return $ramh; } sub process_an_am_file($) { my ($rparams) = @_; my $rh = process_one_am_file($rparams); # iteratively process the Makefile.am files #list_to_arrays($fil,\%g_programs,\%g_libraries,\%g_ams_done); #list_to_arrays($rparams); ##write_temp_dsp($dsp_outfile); } # [dbg_v40] STORE:1: In rcfgs (ra)[Release], [-NEW_OUTD-], [Release|Win32], & $dsp_sub_sub ] ) # [dbg_v40] STORE:2: In rcfgs (ra)[Debug], [-NEW_OUTD-], [Debug|Win32], & $dsp_sub_sub ] ) sub set_default_configs_2($) { my ($rh) = @_; #my $var1 = "-NEW_OUTD-"; my $var1 = ""; my $rcfgs = get_project_configs($rh); # 'PROJECT_CFGS' my ($dsp_sub_sub,$confname,$conf); $dsp_sub_sub = get_default_sub3(0); $confname = 'Release'; $conf = 'Release|WIN32'; push(@{$rcfgs}, [ $confname, $var1, $conf, $dsp_sub_sub ]); # ONLY STORE OF 'PROJECT_CFGS' ${$rh}{'PROJECT_CCNT'}++; # count of stored 'PROJECT_CFGS $dsp_sub_sub = get_default_sub3(1); $confname = 'Debug'; $conf = 'Debug|WIN32'; push(@{$rcfgs}, [ $confname, $var1, $conf, $dsp_sub_sub ]); # ONLY STORE OF 'PROJECT_CFGS' ${$rh}{'PROJECT_CCNT'}++; # count of stored 'PROJECT_CFGS } # ########################################################### # get DSP replacement values # ========================== sub get_user_rt($$) { my ($flag,$line) = @_; my $urt = ''; if ($proj_rt eq 'D') { if ($flag == 1) { $urt = '/MD'; } else { $urt = '/MDd'; } } else { if ($flag == 1) { $urt = '/MT'; } else { $urt = '/MTd'; } } return $urt; } # NOTE: Bit 1 == Release, else Debug sub get_user_libs($$) { my ($flag,$line) = @_; my $var1 = $proj_libs; if ($flag & 1) { if (length($proj_libR)) { $var1 .= " " if (length($var1)); $var1 .= $proj_libR; } } elsif (length($proj_libD)) { $var1 .= " " if (length($var1)); $var1 .= $proj_libD; } return $var1; } sub get_user_incs($$) { my ($flag,$line) = @_; return $proj_incs; } sub get_user_defs($$) { my ($flag,$line) = @_; return $proj_defs; } # Auto output does the following - # For libaries # Debug: '/out:"lib\barD.lib"' # Release:'/out:"lib\barD.lib"' # for programs # Debug: '/out:"bin\fooD.exe"' # Release:'/out:"bin\foo.exe"' # our $auto_on_flag = BITS = ${$rparams}{'CURR_AUTO_ON_FLAG'} sub get_user_output($$) { my ($flag,$line) = @_; if ($flag & 1) { if (length($proj_outputR)) { $line = $proj_outputR; } } elsif (length($proj_outputD)) { $line = $proj_outputD; } return $line; } sub get_user_inter($$) { my ($flag,$line) = @_; if ( $flag & 1 ) { if (length($proj_interR)) { $line = $proj_interR; } } elsif (length($proj_interD)) { $line = $proj_interD; } return $line; } # setting defines and include sub add_defined_item($) { my $txt = shift; $txt = '/D "'.$txt.'"'; $proj_defs .= ' ' if (length($proj_defs)); $proj_defs .= $txt; $proj_defs = eliminate_dupes($proj_defs); prt("Added [$txt] to compiler defines.\n"); } sub add_include_item($) { my $txt = shift; $txt = '/I "'.$txt.'"'; $proj_incs .= ' ' if (length($proj_incs)); $proj_incs .= $txt; $proj_incs = eliminate_dupes($proj_incs); prt("Added [$txt] to compiler includes.\n"); } # ########################################################### # ========================== sub valid_rp_hash($) { my $rp = shift; my @arr = qw(PROJECT_NAME PROJECT_TYPE PROJECT_TARGET PROJECT_DBG_WRITE PROJECT_FIX_REL); my ($key); foreach $key (@arr) { if (!defined ${$rp}{$key}) { prt("ERROR: $key NOT defined in project hash\n"); return 0; } } return 1; } sub fix_dir_string($) { my ($rdir) = @_; if (! ( ${$rdir} =~ /(\\|\/)$/) ) { ${$rdir} .= "\\"; } } sub is_same_file($$) { my ($f1,$f2) = @_; my $len = length($f1); return 0 if ($len != length($f2)); my ($i,$c1,$c2); for ($i = 0; $i < $len; $i++) { $c1 = lc(substr($f1,$i,1)); $c2 = lc(substr($f2,$i,1)); return 0 if ($c1 ne $c2); } return 1; } my @missed_dir_cmp = (); sub mark_in_dir_scan($$) { my ($rparams,$relfile) = @_; return if (! ${$rparams}{'CURR_DONE_SCAN'} ); #my $dir = ${$rparams}{'CURR_FILE_DIR'}; my $dir = ${$rparams}{'TARGET_DIR'}; fix_dir_string(\$dir); my $ff = $dir.$relfile; $ff = path_u2d($ff); $ff = fix_rel_path($ff); my $rda = ${$rparams}{'CURR_DIR_SCAN'}; my $cnt = scalar @{$rda}; my ($i,$file); ### prt("Mark in dir scan [$relfile] [$ff] of $cnt files...\n"); for ($i = 0; $i < $cnt; $i++) { $file = ${$rda}[$i][1]; # get FULL FILE if (is_same_file($ff,$file)) { # 0 1 2 3 #push(@{$rda},[$file,$ff,0,0]); ${$rda}[$i][2] = 1; last; } } if ($i >= $cnt) { push(@missed_dir_cmp,$ff); ### prt("Missed in dir scan [$relfile] [$ff] in $i files...\n"); } } sub create_proj_dsp($$$$) { my ($fil,$odir,$rparams,$rp) = @_; if (!valid_rp_hash($rp)) { prtw("WARNING: INTERNAL ERROR: 'project' HAS NOT valid! Check script!\n"); return; } my $auto_on = ${$rparams}{'CURR_AUTO_ON_FLAG'}; my $proj_name = ${$rp}{'PROJECT_NAME'}; my $proj_type = ${$rp}{'PROJECT_TYPE'}; my $rinp_srcs = ${$rp}{'PROJECT_SOURCES'}; my $proj_targ = ${$rp}{'PROJECT_TARGET'}; my $dbg_write = ${$rp}{'PROJECT_DBG_WRITE'}; #my $temp_copy_bat = ${$rp}{'PROJECT_COPY_BAT'}; my $fix_rel = ${$rp}{'PROJECT_FIX_REL'}; my ($nm,$dr,$ex) = fileparse($fil, qr/\.[^.]*/ ); my $hr = get_default_ref_hash($fil); # this it the VERSION 1 my ($line,$key,$group,$filter,$ok,$rdir,$cfil,$cdir,$sfil,$tdsp,$msg); my ($name,$type,$i,$conf,$rh2,$flag,$cnt,$i2); my ($confname,$var1,$rcfgs); $name = $proj_name; $tdsp = $odir; $tdsp .= "\\" if (!($tdsp =~ /(\\|\/)$/)); $tdsp .= $proj_name.".dsp"; $key = 'PROJECT_NAME'; ${$hr}{$key} = $proj_name; #$key = 'PROJECT_TYPE'; $key = 'PROJECT_APTP'; if ( get_app_type_4_short($proj_type, \$type) ) { ${$hr}{$key} = $type; prt("[v2] Set project type to [$type], from [$proj_type]\n") if (VERB2()); } else { pgm_exit(1,"ERROR: Unable to get project type from [$proj_type]! Only 'CA', 'SL', 'DLL', 'WA'!\n"); } ${$rp}{'PROJECT_DSP'} = $tdsp; ${$rp}{'PROJECT_DSP_TMP'} = $fil; my @sources = (); foreach $line (@{$rinp_srcs}) { $ok = 0; if ($fix_rel) { ($cfil,$cdir) = fileparse($line); # $rdir = get_relative_path($cdir,$odir); $rdir = get_rel_dos_path($cdir,$odir); $sfil = $rdir.$cfil; #prt("From [$line], to [$proj_targ], got rel [$sfil]\n"); prt("[v5] for [$line],\n to [$proj_targ], got\n") if (VERB5()); } else { $sfil = $line; } prt("[v2] Relative source [$sfil]\n") if (VERB2()); mark_in_dir_scan($rparams,$line); if (is_c_source_extended($line)) { # if (($line =~ /\.cxx$/i) || ($line =~ /\.c$/i) || ($line =~ /\.cpp$/i) || ($line =~ /\.cc$/i)) $filter = get_def_src_filt(); $group = get_def_src_grp(); $ok = 1; } elsif (is_h_source_extended($line)) { # elsif ( ($line =~ /\.hxx$/i) || ($line =~ /\.h$/i) || ($line =~ /\.hpp$/i) ) $filter = get_def_hdr_filt(); $group = get_def_hdr_grp(); $ok = 1; } elsif (is_resource_file($line)) { $filter = get_def_rcs_filt(); $group = get_def_rcs_grp(); $ok = 1; } if ($ok) { #push(@sources, [ $line, $group, $filter, 0, '' ]); push(@sources, [ $sfil, $group, $filter, 0, '' ]); } else { prtw("WARNING: CHECK Discarded [$line]\n"); } } if (@sources) { $key = 'PROJECT_SRCS'; ${$hr}{$key} = [@sources]; } else { pgm_exit(1,"ERROR: Project: [$proj_name] No sources!!!\n"); } set_default_configs_2($hr); # set Release and Debug $key = 'PROJECT_CFGS'; if (defined ${$hr}{$key}) { $rcfgs = ${$hr}{$key}; $cnt = scalar @{$rcfgs}; prt( "[v5] Got $cnt CONFIGS...\n" ) if (VERB5()); for ($i = 0; $i < $cnt; $i++) { $i2 = $i + 1; # 0 1 2 3 # Debug -NEW_OUTD- Debug|WIN32 # push(@{$rcfgs}, [ $confname, $var1, $conf, $dsp_sub_sub ]); $confname = ${$rcfgs}[$i][0]; #$var1 = ${$rcfgs}[$i][1]; # has no meaning!!! $conf = ${$rcfgs}[$i][2]; $rh2 = ${$rcfgs}[$i][3]; if (($conf =~ /Release/i)||($confname =~ /Release/i)) { $flag = 1; } elsif (($conf =~ /Debug/i)||($confname =~ /Debug/i)) { $flag = 2; } else { pgm_exit(1,"ERROR: Can NOT set config type as 'Release' or 'Debug'! Got [$conf] [$confname]\n"); } prt("[v5] $i2: [$conf] [$confname] ($flag)\n") if (VERB5()); foreach $key (keys %{$rh2}) { $line = ${$rh2}{$key}; $var1 = $line; # start the SAME $msg = ''; if ($key eq '-NEW_OUT-') { # of form '/out:"bin\foo.exe"' $var1 = ${$rp}{'PROJECT_USER_OUTS'}->($flag,$line);; } elsif (($key eq '-NEW_OUTD-') || ($key eq '-NEW_INTER-')) { # Intermediate or Output DIRECTORY $var1 = get_user_inter($flag,$line); if ($auto_on & 1) { if ($proj_name =~ /[\w\.-]+/) { if ($var1 eq '"Debug"') { $var1 = "\"Debug\\$proj_name\""; } elsif ($var1 eq '"Release"') { $var1 = "\"Release\\$proj_name\""; } } else { prtw("WARNING: auto_on_flag=$auto_on, but prog name [$proj_name] NOT just [an,.,-]??? CHECK ME\n"); } } } elsif ($key eq '-NEW_POST-') { # -NEW_POST- = [] } elsif ($key eq '-NEW_INCS-') { $var1 = get_user_incs($flag,$line); # -NEW_INCS- = [] } elsif ($key eq '-NEW_LIBS-') { $var1 = ''; if (($proj_type ne 'SL') && ($proj_type ne 'DLL')) { # $var1 = get_user_libs($flag,$line); # -NEW_LIBS- = [Winmm.lib ws2_32.lib] # $var1 = ${$rparams}{'CURR_USER_LIBS'}->($flag,$line); $var1 = ${$rp}{'PROJECT_USER_LIBS'}->($flag,$line); # = ${$rparams}{'CURR_USER_LIBS'}; # normal fetch for 'libraries' } } elsif ($key eq '-NEW_DEFS-') { $var1 = get_user_defs($flag,$line); # -NEW_DEFS- = [/D "_CRT_SECURE_NO_WARNINGS"] } elsif ($key eq '-NEW_RT-') { $var1 = get_user_rt($flag,$line); # -NEW_RT- = [/MT] } else { prtw("WARNING: Key [$key] NOT in if table!?!?\n"); } if ($line ne $var1) { $msg = "changed to [$var1]"; ${$rh2}{$key} = $var1; } prt("[v9] $key = [$line] $msg\n") if (VERB9()); } } } else { pgm_exit(1,"INTERNAL ERROR: Hash does NOT have key [$key]!\n"); } if ($only_dry_run) { prt("Write of DSP to [$fil] AVOIDED, due to DRY RUN ON!\n") if ($dbg_write); return; } # prt("Writing DSP...\n"); if ( write_hash_to_DSP3( $fil, $hr, $dbg_write ) ) { prt("Written DSP to [$fil]\n") if ($dbg_write); } else { prt("WARNING: FAILED TO WRITE DSP FILE!\n"); } } # ================================================================ # ***TBD*** could preprocess the sources, and add 'missed' headers # ================================================================ sub write_project_DSP_DSW_files($) { my ($rparams) = @_; my $rph = ${$rparams}{'REF_PROJECTS_HASH'}; my $cnt = scalar keys(%{$rph}); my ($key,$rp,$val,$val2,$dsp,$msg,$n,$d); $key = 'PROJECT_NAME'; # should have been set by AC_INIT(...) MACRO my $proj_name = 'tempprojname'; if (defined ${$rparams}{$key}) { $proj_name = ${$rparams}{$key}; } my $auto_on = ${$rparams}{'CURR_AUTO_ON_FLAG'}; prt("\nCreating DSP files for $cnt projects [$proj_name]...\n"); if (VERB9()) { foreach $key (keys %{$rph}) { $rp = ${$rph}{$key}; $val = ${$rp}{'PROJECT_NAME'}; $val2 = '<FAILED>'; my $proj_type = ${$rp}{'PROJECT_TYPE'}; get_app_type_4_short(${$rp}{'PROJECT_TYPE'}, \$val2); $dsp = ${$rp}{'PROJECT_USER_OUTS'}->(1,""); prt("[v9] key [$key] name [$val] [$val2] [$dsp]\n"); } } #my @project_list = (); foreach $key (keys %{$rph}) { $rp = ${$rph}{$key}; $val = ${$rp}{'PROJECT_NAME'}; $val2 = $perl_temp_dir."\\temp.$val.dsp"; prt("\nCreate DSP for project [$val]...\n") if ($project_dbg_write); ${$rp}{'PROJECT_TARGET'} = $target_dir; ${$rp}{'PROJECT_DBG_WRITE'} = $project_dbg_write; #${$rp}{'PROJECT_COPY_BAT'} = $temp_copy_bat; ${$rp}{'PROJECT_FIX_REL'} = 0; # source array already FIXED, relative to $target_dir create_proj_dsp($val2,$target_dir,$rparams,$rp); $dsp = ${$rp}{'PROJECT_DSP'}; # name dsp tempdsp # project_list 0 1 2 #push(@project_list,[ $tmp, $dsp, $out ]); #push(@project_list, [ $val, $dsp, $val2 ]); } $rph = ${$rparams}{'REF_PROJECTS_HASH'}; my $dswreal = "$proj_name.dsw"; my $dswfull = $target_dir.$dswreal; my $dswtemp = $perl_temp_dir."\\temp.$dswreal"; my $cbtemp = $temp_copy_bat; # = $perl_temp_dir."\\tempcopy.bat"; $cnt = scalar keys(%{$rph}); if ($cnt) { if ($only_dry_run) { prt("\nSummary of $cnt project DSP files that would be written, if NOT DRY RUN!\n"); } elsif (VERB1()) { prt("\n[v1] Summary of $cnt project DSP files written...\n"); } } else { prt("\nEEK! It looks like NO project DSP files written!\n"); } my $dswtxt = get_dsw_head(); my $cbtxt = "\@echo Copy of $cnt DSP, plus the DSW to target directory\n"; $cbtxt .= "\@echo Target is [$target_dir]\n"; $cbtxt .= "\@if EXIST $target_dir".". goto GOTTARG\n"; $cbtxt .= "\@echo ERROR: Appears TARGET directory does NOT EXIST!\n"; $cbtxt .= "\@goto END\n"; $cbtxt .= ":GOTTARG\n"; $cbtxt .= "\@if \"\%TEMPNP\%x\" == \"yesx\" (\n"; $cbtxt .= "\@echo Due to TEMPNP, will unconditionally OVERWRITE existing files, if any.\n"; $cbtxt .= ") else (\n"; $cbtxt .= "\@echo Setting TEMPNP=yes in the environment will skip more pauses, if file exists.\n"; $cbtxt .= ")\n"; $cbtxt .= "\@echo *** CONTINUE? ***\n"; $cbtxt .= "\@pause\n"; my $lab = ''; $cnt = 0; foreach $key (keys %{$rph}) { my $rp = ${$rph}{$key}; my $nm = ${$rp}{'PROJECT_NAME'}; my $dsp = "$nm.dsp"; $val = ${$rp}{'PROJECT_DSP'}; ($n,$d) = fileparse($val); $val2 = ${$rp}{'PROJECT_DSP_TMP'}; $val = '"'.$val.'"' if ($val =~ /[\s\+]+/); $val2 = '"'.$val2.'"' if ($val2 =~ /[\s\+]+/); $cnt++; $lab = "DOCOPY$cnt"; $cbtxt .= "\@if NOT EXIST $val goto $lab\n"; $cbtxt .= "\@if \"\%TEMPNP\%x\" == \"yesx\" goto $lab\n"; $cbtxt .= "\@echo Warning: File [$val] ALREADY EXISTS! *** OVERWRITE? ***\n"; $cbtxt .= "\@pause\n"; $cbtxt .= ":$lab\n"; $cbtxt .= "\@echo Copying $n...\n"; $cbtxt .= "\@copy $val2 $val >nul\n"; $dswtxt .= get_proj_begin( $nm, $dsp ); # INSERT PROJECT DEPENDENCIES *** $msg = 'NO depends'; if (defined ${$rp}{'PROJECT_DEPENDS'}) { if ($auto_on & 16) { my $rpda = ${$rp}{'PROJECT_DEPENDS'}; $msg = 'with deps ['; foreach $nm (@{$rpda}) { $dswtxt .= " Begin Project Dependency\n"; $dswtxt .= " Project_Dep_Name $nm\n"; $dswtxt .= " End Project Dependency\n"; $msg .= " $nm"; } $msg .= ']'; } else { $msg .= "add depend NOT enabled (16)"; } } $dswtxt .= get_proj_end(); prt("Project [$key], for [".sub_root_dir(strip_quotes($val))."]\n written [$val2] $msg\n") if (VERB1()); } if ($cnt) { $dswtxt .= get_dsw_tail(); $cnt++; $lab = "DOCOPY$cnt"; $val = $dswfull; ($n,$d) = fileparse($val); $val2 = $dswtemp; $val = '"'.$val.'"' if ($val =~ /[\s\+]+/); $val2 = '"'.$val2.'"' if ($val2 =~ /[\s\+]+/); prt("For project [$proj_name] DSW [".sub_root_dir(strip_quotes($val))."]\n") if (VERB1()); $cbtxt .= "\@if NOT EXIST $val goto $lab\n"; $cbtxt .= "\@if \"\%TEMPNP\%x\" == \"yesx\" goto $lab\n"; $cbtxt .= "\@echo Warning: File [$val] ALREADY EXISTS! *** OVERWRITE? ***\n"; $cbtxt .= "\@pause\n"; $cbtxt .= ":$lab\n"; $cbtxt .= "\@echo Copying $n...\n"; $cbtxt .= "\@copy $val2 $val >nul\n"; $cbtxt .= "\@echo All $cnt copied, done...\n"; $cbtxt .= "\@echo Change to [$target_dir], and run MSVC... Good luck ;=))\n"; $cbtxt .= ":END\n"; if ($only_dry_run) { prt(" would write [$dswtemp]...if NOT DRY RUN\n") if (VERB1()); } else { rename_2_old_bak_plus($dswtemp); write2file($dswtxt,$dswtemp); prt(" written [$dswtemp]...\n") if (VERB1()); write2file($cbtxt,$cbtemp); prt("Written BATCH file [$cbtemp], to COPY the $cnt 'temp' DSW/DSP files\n to TARGET [$target_dir]... "); if (-d $target_dir) { prt("ok\n"); } else { prt("WARNING: DOES NOT EXIST!\n"); } } } else { prt("No project DSP files written, nor a DSW! Sorry...\n"); } } sub process_am_list($) { my ($rparams) = @_; my ($key,$val,$cnt,$ky2,$val2,$len,$min,$ff,$ok); my $inf = ${$rparams}{'CURR_FILE'}; my $rh = ${$rparams}{'CURR_HASH'}; my $supp_make_in = ${$rparams}{'SUPP_MAKE_IN'}; my ($in_name, $in_dir) = fileparse($inf); $key = 'A_MAKE_INPUT_LIST'; if (defined ${$rh}{$key}) { $val = ${$rh}{$key}; $cnt = scalar @{$val}; prt("\nprocess_am_list: $key with $cnt items in array...\n"); # try to get the ROOT AM FILE foreach $ky2 (@{$val}) { $ff = $in_dir.$ky2.".am"; if (-f $ff) { if (!($ky2 =~ /(\\|\/)/)) { ${$rparams}{'ROOT_AM_FILE'} = $ff; last; } } elsif ($supp_make_in) { $ff = $in_dir.$ky2.".in"; if (-f $ff) { if (!($ky2 =~ /(\\|\/)/)) { ${$rparams}{'ROOT_AM_FILE'} = $ff; last; } } } } foreach $ky2 (@{$val}) { $ff = path_u2d($in_dir.$ky2.".am"); if (-f $ff) { $ok = ".am ok"; ${$rparams}{'AM_FILE'} = $ff; } elsif ($supp_make_in) { $ff = path_u2d($in_dir.$ky2.".in"); if (-f $ff) { $ok = ".in ok"; ${$rparams}{'AM_FILE'} = $ff; } else { $ok = "'am' or 'in' NOT FOUND [$ff]"; } } else { $ok = "'am' NOT FOUND [$ff]"; } if ($ok =~ /ok/) { process_an_am_file($rparams); } else { prtw("WARNING: Missing AM File: [$ky2] $ok\n"); } } } if (defined ${$rparams}{'ROOT_AM_FILE'}) { ${$rparams}{'AM_FILE'} = ${$rparams}{'ROOT_AM_FILE'}; } } sub get_perl_temp_dir() { if (! -d $perl_temp_dir) { mkdir $perl_temp_dir; if (! -d $perl_temp_dir) { pgm_exit(1,"ERROR: Unable to create directory [$perl_temp_dir]\nMaybe there is already a file of that name, or...\n"); } } } sub do_sanity_check() { pgm_exit(1,"ERROR: Problem with lib_acscan DEBUG!\n") if (ac_get_dbg_range() != $dbg_lac_check); pgm_exit(1,"ERROR: Problem with lib_amscan DEBUG!\n") if (am_get_dbg_range() != $am_check_tot ); get_perl_temp_dir(); } sub module_intialisation($) { my ($fil) = @_; #my $auto_on = ${$rparams}{'CURR_AUTO_ON_FLAG'}; set_blank_header_group() if ($auto_on_flag & 64); # my $proj_defs = '/D "_CRT_SECURE_NO_WARNINGS"'; add_defined_item('HAVE_CONFIG_H') if ($auto_on_flag & 128); my $rparams = init_common_subs($fil); ${$rparams}{'CURR_MISSED_SOURCES'} = $missed_source_list; return $rparams; } ######################################### ### MAIN ### # check the DEBUG stuff is ok do_sanity_check(); parse_args(@ARGV); my $rph = module_intialisation($in_file); # establish $root_folder, and init %g_common_subs process_ac_file($rph); # mainly to get substitutions, and get the Makefile AM file output list process_am_list($rph); # process EACH Makefile.AM individually am_list_to_arrays($rph); # move the AM information into 'project' HASHES write_project_DSP_DSW_files($rph); # write the 'project' HASHES to DSP, and finally a DSW am_out_dir_scan_info($rph); pgm_exit($exit_value,"Normal exit(0)"); ######################################## ### COMMAND LINE PARSING ### sub show_dbg_ranges() { my ($max,$tmp); $max = ac_get_dbg_range(); prt(" --dbg <num> (-d) = Set DEBUG flag of this value.\n"); prt(" For AC lib_acscan, numbers in range 101 to 1$max\n"); $max = am_get_dbg_range(); prt(" For AM lib_amscan, numbers in range 201 to 2$max\n"); $tmp = ac_get_dbg_stg(); prt(" Presently $tmp are ON in lib_acscan.\n") if (length($tmp)); $tmp = am_get_dbg_stg(); prt(" Presently $tmp are ON in lib_amscan.\n") if (length($tmp)); prt(" Additional text setting are 'all', 'none', 'extra', and 'help'.\n"); } sub give_help { my ($tmp); prt("$pgmname: $my_version\n"); prt("Usage: $pgmname [options] in-file\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --auto on|off (-a) = Automate certain preferred outputs. Use '-a help' for more.\n"); prt(" --cond item (-c) = Define a conditional item. Can add [:1|0]. Default is 1 (TRUE).\n"); show_dbg_ranges(); prt(" --DEF <FGFS> (-D) = Add a defined macro, like '/D \"FGFS\"', to the DSP compile.\n"); prt(" --INC <path> (-I) = Add an include macro, like '/I \"path\"', to the DSP compile.\n"); prt(" --LIB <set> (-L) = Add a dependant libraries, to programs being built.\n"); prt(" --load-log (-l) = Load log file at end. (def=".($load_log ? "On" : "Off").")\n"); prt(" --mac item val (-m) = Store a MACRO, item=value, for substitution. (use '-d 13' to list missing).\n"); prt(" --name <name> (-n) = Overrride any name in the AC_INIT/AM_INIT_AUTOMAKE.\n"); prt(" --previous (-p) = Load previous commands from [$conf_file]\n") if (-f $conf_file); prt(" --resp <file> (-r) = Commands from a reponse/input file.\n"); # prt(" --ROOT <dir> (-R) = Set the project ROOT directory.\n"); prt(" --supp_in (-s) = Suupport Makefile.in, if NO Makefile.am. (def=$supp_make_in)\n"); prt(" --targ <dir> (-t) = Establish a target directory for the DSW/DSP files.\n"); prt(" --verbosity (-v) = Bump verbosity of this module. Default [$verbosity] to 9 (-vvvvvvvvv)\n"); prt(" --wr_dbg <num> (-w) = Add debug during the DSP write output. Bit values. -1 for all.\n"); prt("Purpose:\n"); prt(" Scan the input file as a configure.ac file, then scan the Makefile.am entries indicated by the\n"); prt(" AC_OUTPUT macro, and output MSVC DSW/DSP build files for the contents found.\n"); prt("NOTES:\n"); prt(" Auto output does the following, and more: For libaries: D:'/out:\"lib\\barD.lib\"'; R:\n"); prt(" '/out:\"lib\\barD.lib\"'. For programs: D:'/out:\"bin\\fooD.exe\"'; R:'/out:\"bin\\foo.exe\"'\n"); prt(" Use '-a help' for fuller list of this 'auto' feature BIT effects.\n"); prt(" The LIB <set> consists of <name:path:[D|R|B]>. The 'path' can be blank, absolute, or relative\n"); prt(" to the 'target' directory of the program DSP. D=Debug, R=Release, B=Both\n"); prt(" Do NOT add the /D or /I to the macro defined or included. This will be added internally,\n"); prt(" and note the upper case for -D, -I and -L.\n"); prt(" Setting a macro is 3 entries, like '-m item value', thus if set a blank is required, use\n"); prt(" '-m item \"\"'. Macros substitutions found missing are written to the file\n"); prt(" [$miss_mac_file] for review, and then using as a '-r <file>' response input file.\n"); prt(" The debug switch is strictly for that. It adds no functionality, just a noisier output,\n"); prt(" and thus allow a DEBUG view of what the script 'saw', and 'did' to potentially\n"); prt(" 'fix' the script.\n"); prt(" Unless there are two commands using the same letter, normally case, and after the first\n"); prt(" letter are ignored.\n"); } sub show_dbg_help() { my $file = $0; my ($line,$max,$tmp,$cnt,$tmp2); show_dbg_ranges(); if (open INF, "<$file") { my @lines = <INF>; close INF; prt(" Detailed list, with some 'notes' indicating what each does.\n"); $cnt = 0; my @ac_dbg = (); my @am_dbg = (); foreach $line (@lines) { $line = trim_all($line); if ($line =~ /^our\s+\$dbg_lac(\d+)\s*=\s*\d+\s*;\s*#(.+)$/) { $tmp = $1; $tmp2 = $2; push(@ac_dbg,"1$tmp: $tmp2"); $cnt++; } elsif ($line =~ /^our\s+\$dbg_s(\d+)\s*=\s*\d+\s*;\s*#(.+)$/) { $tmp = $1; $tmp2 = $2; push(@am_dbg,"2$tmp: $tmp2"); $cnt++; } } if ($cnt) { if (@ac_dbg) { $cnt = scalar @ac_dbg; prt("For DEBUG of AC file scan... $cnt\n"); foreach $tmp (@ac_dbg) { prt(" $tmp\n"); } } else { prt("PROBLEM: NO lib_acscan ADDITIONAL debug HELP!\n"); } if (@am_dbg) { $cnt = scalar @am_dbg; prt("For DEBUG of AM file scans... $cnt\n"); foreach $tmp (@am_dbg) { prt(" $tmp\n"); } } else { prt("PROBLEM: NO lib_amscan ADDITIONAL debug HELP!\n"); } prt("NOTE: Adding DEBUG output only serves to DEBUG what the script 'saw', and 'did'!\n"); } else { prt("\nPROBLEM: Found no \$dbg?? vars in file [$file], so NO DEBUG ADDITIONAL HELP!\n"); } } else { prt("ERROR: Unable to open file [$file], so NO ADDITIONAL DEBUG HELP!\n"); } } sub local_strip_both_quotes($) { my $txt = shift; if ($txt =~ /^'(.+)'$/) { return $1; } if ($txt =~ /^"(.+)"$/) { return $1; } return '' if ($txt eq '""'); return '' if ($txt eq "''"); #prt("Stripping [$txt] FAILED\n"); return $txt; } my $in_input_file = 0; sub load_input_file($$) { my ($arg,$file) = @_; if (open INF, "<$file") { my @lines = <INF>; close INF; my @carr = (); my ($line,@arr,$tmp); foreach $line (@lines) { $line = trim_all($line); next if (length($line) == 0); next if ($line =~ /^#/); @arr = split(/\s/,$line); foreach $tmp (@arr) { $tmp = local_strip_both_quotes($tmp); push(@carr,$tmp); } } $in_input_file++; parse_args(@carr); $in_input_file--; } else { pgm_exit(1,"ERROR: Unable to 'open' file [$file]!\n") } } sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have following argument!\n") if (!@av); } sub add_2_commands($) { my ($ra) = @_; # = \@av my ($itm); foreach $itm (@{$ra}) { $curr_command .= ' ' if (length($curr_command)); $curr_command .= $itm; } } sub show_auto_help() { my $file = $0; my ($line,$max,$tmp,$cnt,$tmp2); my $auto_on = $auto_on_flag; if (open INF, "<$file") { my @lines = <INF>; close INF; prt("Bit list, with some 'notes', indicating what each BIT does.\n"); $cnt = 0; foreach $line (@lines) { chomp $line; if ($line =~ /\#Bit:/) { prt("$line\n"); $cnt++; } } prt("ERROR: Not able to find auto on flag lines!\n") if ($cnt == 0); } else { prt("Unable to open file [$file], no auto help NOT available!\n"); } $tmp = 1; $tmp2 = ''; while ($tmp) { if ($auto_on & $tmp) { $tmp2 .= ' ' if (length($tmp2)); $tmp2 .= "$tmp"; } $tmp = $tmp << 1; last if ($tmp > $auto_max_bit); } prt("Current auto on = $auto_on. Bits: [$tmp2]\n"); pgm_exit(0,"End AUTO help ($cnt)\n"); } sub set_auto_flag($$) { my ($arg,$sarg) = @_; my $ok = -1; my $num = 0; if ($sarg =~ /^\d+\+\d+/) { my @arr = split(/\+/,$sarg); $num = 0; foreach (@arr) { $num += $_; } $sarg = $num; } if ($sarg =~ /^-(\d+)$/) { $num = $1; $num *= -1; $ok = 1; } elsif ($sarg =~ /^(\d+)$/) { $num = $1; if ($num > 0) { $ok = 1; } else { $ok = 0; } } else { if ($sarg =~ /^on$/i) { $ok = 1; $num = -1; } elsif ($sarg =~ /^off$/i) { $ok = 0; $num = 0; } elsif ($sarg =~ /^help$/i) { show_auto_help(); } else { pgm_exit(1,"ERROR: Unknown command '$arg $sarg'! Can only be 'on', 'off', or integer. (or -1 for all)\n"); } } if ($ok == 1) { $ok = 'ON'; $auto_on_flag = $num; } else { $auto_on_flag = $num; $ok = 'OFF'; } prt("Set auto on flag $ok ($auto_on_flag)\n"); } # like $proj_lib .= " /libpath:\"lib\"; # like $proj_libD .= " fooD.lib"; # like $proj_libR .= " foo.lib"; # sub in line ADD LINK32 kernel32.lib ... -NEW_LIBS- /nologo ... #my $proj_libs = 'Winmm.lib ws2_32.lib'; #my $proj_libD = ''; #my $proj_libR = ''; sub add_user_libs($$) { my ($arg,$libs) = @_; my @arr = split(":",$libs); my $cnt = scalar @arr; my ($lib,$path,$dest,$rtarg,$stg,$typ); if ($cnt == 3) { $lib = strip_quotes($arr[0]); $path = strip_quotes($arr[1]); $dest = $arr[2]; if ($dest eq 'D') { $rtarg = \$proj_libD; $typ = 'Debug'; } elsif ($dest eq 'R') { $rtarg = \$proj_libR; $typ = 'Release'; } elsif ($dest eq 'B') { $rtarg = \$proj_libs; $typ = 'Both'; } else { pgm_exit(1,"ERROR: For '$arg $libs', the 3rd item MUST be 'D', 'R', or 'B', NOT '$dest'!\n"); } if ($lib =~ /\s/) { $stg = "\"$lib\""; } else { $stg = "$lib"; } if (length($path)) { $stg .= " /libpath:\"$path\""; } if (length(${$rtarg})) { ${$rtarg} .= ' '; } ${$rtarg} .= $stg; prt("Added '$stg' to $typ program library dependence.\n"); } else { pgm_exit(1,"ERROR: For '$arg $libs', the 'set' did NOT split into 3 items!\n". " The LIB <set> consists of <name:path:[D|R|B]>. The 'path' can be blank, absolute, or relative\n". " to the 'target' directory of the program DSP. D=Debug, R=Release, B=Both\n"); } } sub set_cond_item($$) { my ($arg,$sarg) = @_; my @arr = split(":",$sarg); my $item = $arr[0]; my $val = 'TRUE'; my ($tmp); if (scalar @arr > 1) { $tmp = $arr[1]; if ( ($tmp =~ /^\d+$/) && (($tmp == 1)||($tmp == 0)) ) { $val = 'FALSE' if ($tmp == 0); } else { pgm_exit(2,"ERROR: Argument can only be $item + :1 or :0, not [$tmp]\n"); } } if (defined $g_user_condits{$item}) { prt("Resetting conditional [$item] to [$val]\n"); } else { prt("Setting conditional [$item] to [$val]\n"); } $g_user_condits{$item} = $val; # stored as ${$rparams}{'REF_DEF_CONDITIONS'} } sub parse_args { my (@av) = @_; my ($arg,$sarg,$tmp,$rngac,$rngam); add_2_commands(\@av); 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(); $conf_string = ""; pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^a/) { need_arg(@av); shift @av; $sarg = $av[0]; set_auto_flag($arg,$sarg); } elsif ($sarg =~ /^c/) { need_arg(@av); shift @av; $sarg = $av[0]; set_cond_item($arg,$sarg); } elsif ($sarg =~ /^D/) { need_arg(@av); shift @av; $sarg = $av[0]; add_defined_item($sarg); $conf_string .= "$arg $sarg\n"; } elsif ($sarg =~ /^d/) { need_arg(@av); shift @av; $sarg = $av[0]; $conf_string .= "$arg $sarg\n"; if ($sarg =~ /^(\d+)$/) { $tmp = $1; $rngac = ac_get_dbg_range(); $rngam = am_get_dbg_range(); if (($tmp > 200) && (($tmp - 200) <= $rngam)) { if (am_set_dbg_var($tmp - 200)) { prt("Set AM lib Debug $tmp ON!\n"); } else { pgm_exit(1,"ERROR: FAILED to set AM lib Debug $tmp ON!\n"); } } elsif (($tmp > 100) && (($tmp - 100) <= $rngac)) { if (ac_set_dbg_var($tmp - 100)) { prt("Set AC lib Debug $tmp ON!\n"); } else { pgm_exit(1,"ERROR: FAILED to set AC lib Debug $tmp ON!\n"); } } else { $rngac += 100; $rngam += 200; pgm_exit(1,"ERROR: Invalid argument [$arg $sarg]! Is numerical, but not range 101 to $rngac, nor 202 to $rngam!\n"); } } else { if ($sarg =~ /^help$/i) { show_dbg_help(); $conf_string = ""; pgm_exit(0,"DEBUG Help exit(0)\n"); } elsif ($sarg =~ /^all$/i) { prt("Setting ALL debug ON!\n"); set_all_dbg_on(); } elsif ($sarg =~ /^none$/i) { prt("Setting ALL debug OFF!\n"); set_all_dbg_off(); } elsif ($sarg =~ /^dry-run$/i) { prt("Setting DRY RUN ONLY!\n"); $only_dry_run = 1; } elsif ($sarg =~ /^extra$/i) { prt("Setting ALL debug ON, plus EXTRA!\n"); set_max_debug_on(); } else { pgm_exit(1,"ERROR: Invalid argument [$arg $sarg]! Not numerical, nor 'all', 'none', or 'help' !\n"); } } } elsif ($sarg =~ /^I/) { need_arg(@av); shift @av; $sarg = $av[0]; add_include_item($sarg); $conf_string .= "$arg $sarg\n"; } elsif ($sarg =~ /^l/) { $conf_string .= "$arg\n"; $load_log = 1; } elsif ($sarg =~ /^L/) { need_arg(@av); shift @av; $sarg = $av[0]; add_user_libs($arg,$sarg); $conf_string .= "$arg $sarg\n"; } elsif ($sarg =~ /^m/i) { # store a macro need_arg(@av); shift @av; $sarg = $av[0]; need_arg(@av); shift @av; $tmp = $av[0]; $g_user_subs{$sarg} = $tmp; # supplied by USER INPUT prt("Set MACRO [$sarg] = [$tmp] in common subs...\n"); $tmp = '""' if ((length($tmp) == 0)||($tmp =~ /^\s+$/)); $conf_string .= "$arg $sarg $tmp\n"; } elsif ($sarg =~ /^n/i) { need_arg(@av); shift @av; $sarg = $av[0]; $project_name = $sarg; prt("Set default over-all project name to [$project_name]\n"); } elsif ($sarg =~ /^p/i) { if (-f $conf_file) { prt("Loading previous commands from [$conf_file]\n"); load_input_file($arg,$conf_file); $no_conf_write = 1; } else { pgm_exit(1,"ERROR: No previous config file [$conf_file] to load!\n"); } } elsif ($sarg =~ /^r/) { need_arg(@av); shift @av; $sarg = $av[0]; prt("Loading from response file [$sarg]...\n"); load_input_file($arg,$sarg); } elsif ($sarg =~ /^s/) { $supp_make_in = 1; prt("Added support for Makefile.in.\n"); } elsif ($sarg =~ /^t/i) { # target directory for DSP file(s) need_arg(@av); shift @av; $sarg = $av[0]; $target_dir = File::Spec->rel2abs($sarg); $fix_relative_sources = 1; prt("Set to TARGET folder to [$target_dir].\n"); } elsif ($sarg =~ /^v/i) { while ($sarg =~ /^v/i) { $verbosity++; $sarg = substr($sarg,1); } prt("Set verbosity to [$verbosity]\n"); } elsif ($sarg =~ /^w/i) { need_arg(@av); shift @av; $sarg = $av[0]; $project_dbg_write = $sarg; prt("Set write debug to $project_dbg_write\n"); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = File::Spec->rel2abs($arg); if (-f $in_file) { $conf_string .= "$in_file\n"; prt("Set input to [$in_file]\n"); } else { pgm_exit(1,"ERROR: Unable to locate file [$in_file]! Check name, location...\n"); } } shift @av; } if (!$in_input_file) { if ((length($in_file) == 0) && $debug_on) { my @carr = (); push(@carr,"-d"); push(@carr,"extra"); #push(@carr,"-d"); push(@carr,"dry-run"); push(@carr,"$def_file"); # for libxm2 push(@carr,"-s"); # $supp_make_in = 1; # Support Makefile.in scanning push(@carr,"-I"); push(@carr,"..\\include"); push(@carr,"-D"); push(@carr,"LIBXML_STATIC"); push(@carr,"-m"); push(@carr,'THREAD_W32'); push(@carr,'Win32'); push(@carr,"-d"); push(@carr,113); # for libgif #push(@carr,"-I"); push(@carr,"..\\lib"); #push(@carr,"-I"); push(@carr,"..\\windows"); # for sigc++ # $g_user_subs{'SIGCXX_API_VERSION'} = 2; # supplied by USER INPUT # for pcre #push(@carr,"-s"); # $supp_make_in = 1; # Support Makefile.in scanning #push(@carr,"-D"); push(@carr,"PCRE_STATIC"); #push(@carr,"-l\n"); # $load_log = 1; if ((length($target_dir) == 0) && length($def_targ)) { push(@carr,"-t"); push(@carr,"$def_targ"); # $target_dir = $def_targ; } if (length($def_name) && (length($project_name) == 0)) { push(@carr,"-n"); push(@carr,$def_name); } $in_input_file++; parse_args(@carr); $in_input_file--; } if (length($in_file) == 0) { pgm_exit(2,"ERROR: No 'configure.ac' input file found in command!\n"); } if (! -f $in_file) { pgm_exit(2,"ERROR: Can NOT find file [$in_file]! Check name, location!\n"); } } #wait_key(); } # ============================================================================================= # TO BE DONE - ***TBD*** Other items thought of, but not yet implemented # # - Adding headers - ok this is good, but most headers get attached to the LIBRARIES, # since they are processed FIRST. There should be a better scheme for this. But can not # immediately see how to handle it yet. # And in one instance in Glib-1.24.2 I saw one header added twice - I though I had BLOCK this! # AND, since I now know all the headers included by a file, the script SHOULD make sure # the additional include directories is updated to find this/these headers. # # - noinst_PROGRAMS, check_PROGRAMS versus bin_PROGRAMS # Maybe the DSP for no-install prograsm could be still written, BUT not included in # the main DSW file. Maybe a 2nd DSW file could be written for these 'check' and 'no-install' # programs. # # - There are times when combining some static libraries could be good, but care should be taken with # this, because this separation is important in most cases. Maybe # --join a:b:c d (-j) = Join projects named 'a', 'b', and 'c', and make a project 'd' # # - config.h - When it is noted that the source uses a 'config.h', maybe generate a common file # in the target directory, and make sure it is added to the most important library/programs, if pos. # # - missing source - certain Makefile.am will have a $host switch to INCLUDE say MAC or Windows # sources in say a library, but these will not always get picked up and put in the library. # Conversely, sometimes say MAC items will get picked up when they should not. Need a way to # (a) Force the INCLUSION of certain source to a project, and # (b) Force the EXCLUSION of certain sources from a project. # These sources are presently only written to the $missed_source_list file, # but this seems now well handled, at least partially, by the new --cond item:[0|1] option # # Be able to ADD use dependencies to the DSW file, especially for additional libraries that # may NOT be in a LDADD entries - like they are only for WIN32 # Maybe --PROJ <dep) (-P) = Project dependence added to DSW file. # # An idea to force ALL libraries to be compiled first would be to add a 'dummy' application, # and add dependence of each library to it... # # ============================================================================================= # eof - amsrcs04.pl