#!/usr/bin/perl -w # am2list02.pl # AIM: Load Makefile.am files from a given folder, and list the source files found ... # 22/09/2010 - Development abandoned for amsrcs04.pl, which does LOTS more # 24/08/2010 - Reviewed # 25/09/2007 - some improvements, and remove MSVC8 stuff # 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 $vers = "6"; my $pack = $0; my $perl_base = "C:\\GTools\\perl"; unshift(@INC,$perl_base); require 'logfile.pl' or die "Unable to load logfile.pl ...\n"; # log file stuff my ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $perl_base."\\temp.$pgmname.txt"; my $cwdir = getcwd(); my $static_lib = 0; my $write_new_dsp = 1; # write out DSP/DSW files my $load_log = 0; my $src_cfg = ''; my $root_dir = ''; my $def_in_folder = 'C:\Projects\ftgl-2.1.3'; ###my $def_in_folder = 'C:\FG\FGCOM\speex'; ###my $def_in_folder = 'C:\FG\FGCOM\iaxclient'; ###my $def_in_folder = 'F:\FG0910-4\fgms'; ###my $def_in_folder = 'F:\FG0910-4\flightgear'; ###my $def_in_folder = 'C:\FG0910-5\SimGear'; my @sources = (); # final list of SOURCES my @sources2 = (); # final list of SRCS my $verbose = 0; my $verbose2 = 0; my $verbose3 = 0; # debug my $debug_on = 0; my $dbg01 = 0; # show each config file being scanned ... my $dbg02 = 1; # show each makefile.am being scanned ... my $dbg03 = 1; # show list of contents my $dbg04 = 0; my $dbg05 = 0; my $dbg06 = 0; # show Storing configure_cond key my $dbg07 = 0; my $dbg08 = 0; # String constants. my $IGNORE_PATTERN = "^##([^#].*)?\$"; my $WHITE_PATTERN = "^[ \t]*\$"; my $COMMENT_PATTERN = "^#"; my $RULE_PATTERN = "^([\$a-zA-Z_.][-.a-zA-Z0-9_(){}/\$]*) *:([^=].*|)\$"; my $SUFFIX_RULE_PATTERN = "^\\.([a-zA-Z]+)\\.([a-zA-Z]+)\$"; my $MACRO_PATTERN = "^([A-Za-z][A-Za-z0-9_]*)[ \t]*([:+]?)=[ \t]*(.*)\$"; my $BOGUS_MACRO_PATTERN = "^([^ \t]*)[ \t]*([:+]?)=[ \t]*(.*)\$"; my $IF_PATTERN = "^if[ \t]+\([A-Za-z][A-Za-z0-9_]*\)[ \t]*\(#.*\)?\$"; my $ELSE_PATTERN = "^else[ \t]*\(#.*\)?\$"; my $ENDIF_PATTERN = "^endif[ \t]*\(#.*\)?\$"; my $PATH_PATTERN='(\\w|/|\\.)+'; # This will pass through anything not of the prescribed form. my $INCLUDE_PATTERN = "^include[ \t]+((\\\$\\\(top_srcdir\\\)/${PATH_PATTERN})|(\\\$\\\(srcdir\\\)/${PATH_PATTERN})|([^/\\\$]${PATH_PATTERN}))[ \t]*(#.*)?\$"; my $AM_CONDITIONAL_PATTERN = "AM_CONDITIONAL\\((\\w+)"; my $AM_INIT_AUTOMAKE = "AM_INIT_AUTOMAKE\\(([^,]+),[ \t]*([^)]+)"; # Hash table of AM_CONDITIONAL variables seen in configure. my %configure_cond = (); # This holds the names which are targets. These also appear in # %contents. my %targets = (); # This holds the line numbers at which various elements of # %contents are defined. my %content_lines = (); my %content_seen = (); # This maps the source extension of a suffix rule to its # corresponding output extension. my %suffix_rules = (); # Hash table of discovered configure substitutions. Keys are names, # values are `FILE:LINE' strings which are used by error message # generation. my %configure_vars = (); # This holds the set of included files. my @include_stack = (); my $vcond; my @conditional_stack = (); my %contents = (); my %conditional = (); # This holds our (eventual) exit status. We don't actually exit until # we have processed all input files - except when 'critical' ... my $exit_status = 0; my @make_input_list = (); my %make_list = (); # Names used in AC_CONFIG_HEADER call. @config_fullnames holds the # name which appears in AC_CONFIG_HEADER, colon and all. # @config_names holds the file names. @config_headers holds the '.in' # files. Ordinarily these are similar, but they can be different if # the weird "NAME:FILE" syntax is used. my @config_fullnames = (); my @config_names = (); my @config_headers = (); # Line number at which AC_CONFIG_HEADER appears in configure.ac. my $config_header_line = 0; # Relative location of top build directory. my $top_builddir = ''; my $relative_dir = '.'; my $output_vars = ''; my $output_trailer = ''; # List of Makefile.am's to process, and their corresponding outputs. my @input_files = (); my %output_files = (); # List of files in AC_OUTPUT without Makefile.am, and their outputs. my @other_input_files = (); my @var_list = (); my %am_vars = (); my %def_type = (); my @excluded_dirs = (); my @excluded_files = (); my $msvc_cflags = ""; my $msvc_threads = ""; my $msvc_libs = ""; my @extra_sources = (); my @extra_projects = (); my %used_inc_paths = (); my %used_lib_paths = (); # new variables my $msvc_dlibs = ""; my $msvc_rlibs = ""; my $in_debug = 0; my $in_release = 0; my $do_check = 0; my $def_cfg = "am2dsp.cfg"; my @msvc_dlibs_list = (); my @msvc_rlibs_list = (); my @msvc_libs_list = (); my @msvc_dlibs_paths = (); my @msvc_rlibs_paths = (); my @msvc_libs_paths = (); my @msvc_inc_paths = (); my @test_headers = ( 'zlib.h', 'AL/al.h', 'AL/alut.h', 'simgear/compiler.h', 'simgear/debug/logstream.hxx', 'plib/pu.h', 'Main/main.hxx', 'config.h', 'include/general.hxx', 'FGJSBBase.h'); my $add_groups = 0; # default to single, put duplicates 'Dupes' folder ... my @msvc_c_files = (); my @msvc_h_files = (); my @msvc_titles = (); # just to deal with duplicate names # EXTRA_DIST file lists from Makefile.am list my @msvc_c_extra = (); my @msvc_h_extra = (); my @msvc_o_extra = (); my $err_msg = ''; # am2dsp?.cfg define = AAA my %cfg_defines = (); # configure.ac equivalent my %def_defines = ( 'FG_JPEG_SERVER', 'ENABLE_JPEG_SERVER' ); # Extracted from AM_INIT_AUTOMAKE(package,version) my $dsp_package = 'TEMPONLY'; my $dsp_version = '0.2'; # other items my $warn = ''; my $act_am_file = ''; open_log($outfile); ### program variables my @warnings = (); my $os = $^O; sub show_warnings($) { my $val = shift; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } elsif ($val) { prt( "\nNo warnings issued.\n\n" ); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg) } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub add_group_start { my $dsp_name = shift; my $dsp_file = $root_dir . $dsp_name . '.dsp'; open(DSP, ">>$dsp_file") || mydie( "Can't append to $dsp_file: $!\n" ); print DSP "# Begin Group \"Source Files\"\n"; print DSP "\n"; print DSP "# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;h;hpp;hxx;hm;inl\"\n"; close(DSP); } sub add_group_end { my $dsp_name = shift; my $dsp_file = $root_dir . $dsp_name . '.dsp'; open(DSP, ">>$dsp_file") || mydie( "Can't append to $dsp_file: $!\n" ); print DSP "# End Group\n"; close(DSP); } sub exclude_dir { my $dir = shift; foreach my $d (@excluded_dirs) { if ($dir =~ "/$d/") { return 1; } } return 0; } sub exclude_file { my $file = shift; foreach my $f (@excluded_files) { if ($file =~ /$f/) { return 1; } } return 0; } sub add_2_msvc { my $flg = shift; if ($in_debug) { $msvc_dlibs .= $flg; } elsif ($in_release) { $msvc_rlibs .= $flg; } else { $msvc_libs .= $flg; } } sub add_2_libs { my $flg = shift; if ($in_debug) { push(@msvc_dlibs_list, $flg); } elsif ($in_release) { push(@msvc_rlibs_list, $flg); } else { push(@msvc_libs_list, $flg); } } sub add_2_libpaths { my $flg = shift; if ($in_debug) { push(@msvc_dlibs_paths, $flg); } elsif ($in_release) { push(@msvc_rlibs_paths, $flg); } else { push(@msvc_libs_paths, $flg); } } sub read_am2dsprc { my $rc_file = shift; prt( "Read project configuration file [$rc_file]... " ); if ( length($rc_file) && ( open( RC_FILE, $rc_file ) )) { prt( "Reading config [$rc_file] ...\n" ); } else { prt( "Can NOT open file.\n" ); return; } my $line = ''; my @cond_stack = (); while (defined($line = )) { chomp $line; if ($line =~ s/\\$//) { # continuation line $line .= "%"; $line .= ; redo unless eof(RC_FILE); } prt( "Processing line [$line] ...\n" ) if ($dbg06); next if $line =~ /^$/; # ignore blank lines next if $line =~ /^#/; # ignore comments if ($line =~ /exclude_dir\s*=\s*(\S+)/) { push( @excluded_dirs, $1 ); } elsif ($line =~ /exclude_file\s*=\s*(\S+)/) { my $f; ($f = $1) =~ s/\\/\\\\/g; # escape path separators, "\" -> "\\" push( @excluded_files, $f ); prt( "Excluding file: $f\n" ) if $verbose; } elsif ($line =~ /include_path\s*=\s*(\S+)/) { $msvc_cflags .= " /I \"$1\""; push(@msvc_inc_paths, $1); } elsif ($line =~ /define\s*=\s*(\S+)/) { if ($dbg04) { if (defined $def_defines{$1} ) { prt( "Got define of $1 ... which is $def_defines{$1} ...\n" ); $cfg_defines{$def_defines{$1}} = 1; # add configure.ac } else { prt( "Got define of $1 ...\n" ); } if ( defined $cfg_defines{$1} ) { prt( "Warning: cfg_defines of $1 already defined ...\n" ); } } $cfg_defines{$1} = 1; $msvc_cflags .= " /D \"$1\""; } elsif ($line =~ /lib_path\s*=\s*(\S+)/) { add_2_msvc( " /libpath:\"$1\"" ); add_2_libpaths( "$1" ); } elsif ($line =~ /add_lib\s*=\s*(\S+)/) { add_2_msvc( " $1.lib" ); add_2_libs( "$1.lib" ); } elsif ($line =~ /type\s*=\s*(\S+)/) { my ($type,$threads,$debug) = split /,/, $1; prt( "type=$type, threading=$threads, debug=$debug\n" ) if $verbose; if ($type =~ "ConsoleApplication") { $static_lib = 0 } elsif ($type =~ "StaticLibrary") { $static_lib = 1 } else { # Invalid type } my $flags = " /ML"; # single threaded. if ($threads =~ /Multithreaded/) { $flags = " /MT"; } elsif ($threads =~ /Singlethreaded/) { $flags = " /ML"; } else { # Invalid threading option. } if ($debug =~ /Debug/) { $flags .= "d"; } $msvc_cflags .= $flags; } elsif ($line =~ /add_source_file\s*=\s*(.*)/) { my $rule; ($rule = $1) =~ s/%/\n/g; push( @extra_sources, $rule ); } elsif ($line =~ /add_project\s*=\s*(.*)/) { push( @extra_projects, $1 ); } elsif ($line =~ /$IF_PATTERN/o) { my $ifcond = $1; if ($ifcond =~ /Debug/io) { prt( "Entering DEBUG ...\n" ) if $verbose2; $in_debug = 1; $in_release = 0; } elsif ($ifcond =~ /Release/io) { prt( "Entering RELEASE ...\n" ) if $verbose2; $in_release = 1; $in_debug = 0; } else { prt( "EEK! Got $ifcond ...\n" ); mydie( "Presently ONLY if switch is 'Debug' or 'Release'!\n" ); } push (@cond_stack, "\@" . $ifcond . "_TRUE\@"); } elsif ($line =~ /$ELSE_PATTERN/o) { if (! @cond_stack) { mydie( "else without if!\n" ); } elsif ($cond_stack[$#cond_stack] =~ /_FALSE\@$/) { mydie( "else after an else!\n" ); } else { if ($in_debug) { prt( "Switch to RELEASE ...\n" ) if $verbose2; $in_debug = 0; $in_release = 1; } else { prt( "Switch to DEBUG ...\n" ) if $verbose2; $in_debug = 1; $in_release = 0; } $cond_stack[$#cond_stack] =~ s/_TRUE\@$/_FALSE\@/; } } elsif ($line =~ /$ENDIF_PATTERN/o) { if (! @cond_stack) { mydie( "endif without if!\n" ); } prt( "Exit $cond_stack[$#cond_stack] ...\n" ) if $verbose2; pop (@cond_stack); $in_debug = 0; $in_release = 0; } } # end while close(RC_FILE); } sub scan_one_configure_file { my $filename = shift; prt( "\nScanning config file $filename\n" ) if $dbg01; open(CONFIGURE, $filename) || pgm_exit(1, "ERROR: can't open [$filename]: $!\nCurrently running in $cwdir ...\n" ); my $in_ac_output = 0; my $ac_output_line = ''; my $ff = ''; while () { # Remove comments from current line. s/\bdnl\b.*$//; s/\#.*$//; # Skip macro definitions. Otherwise we might be confused into # thinking that a macro that was only defined was actually # used. next if /AC_DEFUN/; # Follow includes. This is a weirdness commonly in use at # Cygnus and hopefully nowhere else. if (/sinclude\((.*)\)/ && -f ($root_dir . $1)) { $ff = $root_dir . $1; scan_one_configure_file ($ff); } if (! $in_ac_output && ( s/AC_OUTPUT\s*\(\[?// || s/AC_CONFIG_FILES\s*\(\[?// ) ) { $in_ac_output = 1; $ac_output_line = $.; } if ($in_ac_output) { my $closing = 0; if (s/[\]\),].*$//) { $in_ac_output = 0; $closing = 1; } # Look at potential Makefile.am's foreach (split) { # Must skip empty string for Perl 4. next if $_ eq "\\" || $_ eq ''; my ($local,$input,@rest) = split(/:/); if (! $input) { $input = $local; } else { $input =~ s/\.in$//; } $ff = $root_dir . $input . '.am'; if (-f $ff) { prt( "Adding $input [$ff] to make_input_list ...\n" ) if $verbose2; push(@make_input_list, $input); $make_list{$input} = join(':', ($local,@rest)); } else { prt( "Adding $input [$ff] to other_input_files ...\n" ) if $verbose2; # We have a file that automake should cause to be # rebuilt, but shouldn't generate itself. push (@other_input_files, $_); } } } # Handle configuration headers. A config header of `[$1]' # means we are actually scanning AM_CONFIG_HEADER from # aclocal.m4. if (/A([CM])_CONFIG_HEADER\s*\((.*)\)/ && $2 ne '[$1]') { &am_conf_line_error ($filename, $., "\`automake requires \`AM_CONFIG_HEADER', not \`AC_CONFIG_HEADER'") if $1 eq 'C'; $config_header_line = $.; my ($one_hdr); foreach $one_hdr (split (' ', $2)) { push (@config_fullnames, $one_hdr); if ($one_hdr =~ /^([^:]+):(.+)$/) { push (@config_names, $1); push (@config_headers, $2); } else { push (@config_names, $one_hdr); push (@config_headers, $one_hdr . '.in'); } } } if (/$AM_CONDITIONAL_PATTERN/o) { if ( defined $cfg_defines{$1} ) { # has been DEFINED in am2dsp?.cfg file prt( "Storing configure_cond key $1 ... value=2\n" ) if ($dbg06); $configure_cond{$1} = 2; } else { prt( "Storing configure_cond key $1 ... value=1\n" ) if ($dbg06); $configure_cond{$1} = 1; } } if (/$AM_INIT_AUTOMAKE/o) { $dsp_package = $1; $dsp_version = $2; } } close(CONFIGURE); } sub scan_configure { my $ff = $root_dir . 'configure.ac'; ###prt( "Call scan_one with $ff ...\n" ); scan_one_configure_file($ff); $ff = $root_dir . 'aclocal.m4'; ###prt( "Call scan_one with $ff ...\n" ); scan_one_configure_file($ff) if -f $ff; if (! @input_files) { prt( "Copying " . scalar @make_input_list . " make_input_list to input_files.\n" ) if $verbose2; @input_files = @make_input_list; %output_files = %make_list; } else { prt( "input_files has list of " . scalar @input_files . " ...\n" ) if $verbose2; } if ($verbose2) { my $cnt = scalar @input_files; prt( "\nOutput of $cnt input_files list ...\n" ); $cnt = 0; foreach $ff (@input_files) { $cnt++; prt( "$cnt $ff\n" ); } prt( "Done $cnt input_files list ...\n" ); } } sub read_main_am_file { my $am_file = shift; $act_am_file = $am_file; read_am_file($am_file); my @topdir = (); foreach (split(/\//, $relative_dir)) { next if $_ eq '.' || $_ eq ''; if ($_ eq '..') { pop @topdir; } else { push(@topdir, '..'); } } @topdir = ('.') if ! @topdir; my $top_builddir = join('/', @topdir); } sub read_am_file { my $am_file = shift; my ($am_name,$am_dir) = fileparse($am_file); $am_dir = path_u2d($cwdir) if ($am_dir =~ /^\.(\\|\/)$/); $am_dir .= "\\" if ( !($am_dir =~ /(\\|\/)$/) ); open( AM_FILE, $am_file ) or pgm_exit(1,"ERROR: Can NOT open [$am_file]: $!\n" ); my @lines = ; close AM_FILE; my ($line,$lnn,$i,$lncnt); $lncnt = scalar @lines; prt("\n") if ($dbg03 && ($am_file =~ /\.am$/i)); prt( "Processing $lncnt lines, from [$am_file]...\n" ) if $dbg02; my $saw_bk = 0; my $was_rule = 0; my $spacing = ''; my $comment = ''; my $last_var_name = ''; my $blank = 0; my $cond_true = 2; # undetermined ... my $curr_tline = ''; $lnn = 0; for ($i = 0; $i < $lncnt; $i++) { $lnn++; $line = trim_all($lines[$i]); if ($line =~ /$IGNORE_PATTERN/o) { # Merely delete comments beginning with two hashes. } elsif ($line =~ /$WHITE_PATTERN/o) { # Stick a single white line before the incoming macro or rule. $spacing = "\n"; $blank = 1; } elsif ($line =~ /$COMMENT_PATTERN/o) { # Stick comments before the incoming macro or rule. Make # sure a blank line preceeds first block of comments. $spacing = "\n" unless $blank; $blank = 1; $comment .= $spacing . $line; $spacing = ''; } else { $lnn-- if ($lnn); last; } } $output_vars .= $comment . "\n"; $comment = ''; $spacing = "\n"; my $source_suffix_pattern = ''; my $is_ok_macro = 0; $curr_tline = trim_all($line); for (; $i < $lncnt; $i++) { $lnn++; $line = trim_all($lines[$i]); prt( "$lnn [$line]\n" ) if ($dbg06); #$line .= "\n" unless substr ($line, -1, 1) eq "\n"; if ($line =~ /$IGNORE_PATTERN/o) { # Merely delete comments beginning with two hashes. } elsif ($line =~ /$WHITE_PATTERN/o) { # Stick a single white line before the incoming macro or rule. $spacing = "\n"; &am_line_error ($lnn, "blank line following trailing backslash") if $saw_bk; } elsif ($line =~ /$COMMENT_PATTERN/o) { # Stick comments before the incoming macro or rule. $comment .= $spacing . $line; $spacing = ''; &am_line_error ($lnn, "comment following trailing backslash") if $saw_bk; } elsif ($saw_bk) { # continuation of previous line(s) ... if ($was_rule) { $output_trailer .= join ('', @conditional_stack) . $line; $saw_bk = ($line =~ /\\$/) ? 1 : 0; } else { $saw_bk = ($line =~ /\\$/) ? 1 : 0; # Chop newline and backslash if this line is # continued. ensure trailing whitespace exists. #chop if $saw_bk; chop $line if $saw_bk; # decide if to be added to 'contents' ... my $add_it = 0; # assume NO if ( defined $contents{$last_var_name} ) { if ( @conditional_stack ) { if ( $conditional_stack[$#conditional_stack] =~ /_TRUE\@$/ ) { # we are in the if TRUE state #if ($cond_true == 1) { if ($cond_true > 0) { $add_it = 1; } } else { # we are in a FALSE state #if ($cond_true != 1) { if ($cond_true == 0) { $add_it = 1; } } } else { ###prt( "No conditional stack for this macro! lv=[$last_var_name] ". ### "add_it\n" ) if ($dbg06); $add_it = 1; # so add it } } else { # NO contents for this var prt( "NO contents for [$last_var_name]! ". "Technical this is an ERROR, but for now add_it...\n" ) if ($dbg06); $add_it = 1; } if ($add_it) { $contents{$last_var_name} .= ' ' unless $contents{$last_var_name} =~ /\s$/; $contents{$last_var_name} .= $line; if (@conditional_stack) { $conditional{$last_var_name} .= "e_cond_val ($line); } prt( "End $last_var_name = [". trim_all($contents{$last_var_name})."]...\n" ) if ( ! $saw_bk && $dbg06); } else { #prt( "Warning: Discarding this [$line] ... CHECK ME!\n" ) if ($dbg06); prt( "Warning: Discarding this [$curr_tline] ... CHECK ME!\n" ) if ($dbg06); my $msg = "CHECK: "; if ( defined $contents{$last_var_name} ) { $msg .= "defined contents $last_var_name "; if ( @conditional_stack ) { $msg .= "cond_true=$cond_true "; if ( $conditional_stack[$#conditional_stack] =~ /_TRUE\@$/ ) { # we are in the if TRUE state $msg .= "TRUE "; #if ($cond_true == 1) { $add_it = 1; } } else { # we are in a FALSE state $msg .= "FALSE "; #if ($cond_true != 1) { $add_it = 1; } } } } else { $msg .= "NOT defined contents $last_var_name "; } prt( "$msg\n" ); } } } elsif ($line =~ /$IF_PATTERN/o) { if ( defined $configure_cond{$1} ) { ###if ( defined $cfg_defines{$1} ) if ($configure_cond{$1} == 2) { prt( "Found if $1, and condition is TRUE (see cfg_defines) ...\n" ) if ($dbg06); $cond_true = 1; } else { prt( "Found if $1, but NOT in cfg_defines ...\n" ) if ($dbg06); $cond_true = 0; } } else { &am_line_error ($lnn, "$1 does not appear in AM_CONDITIONAL"); } push (@conditional_stack, "\@" . $1 . "_TRUE\@"); } elsif ($line =~ /$ELSE_PATTERN/o) { if (! @conditional_stack) { &am_line_error ($lnn, "else without if"); } elsif ($conditional_stack[$#conditional_stack] =~ /_FALSE\@$/) { &am_line_error ($lnn, "else after else"); } else { $conditional_stack[$#conditional_stack] =~ s/_TRUE\@$/_FALSE\@/; } } elsif ($line =~ /$ENDIF_PATTERN/o) { if (! @conditional_stack) { &am_line_error ($lnn, ": endif without if"); } else { pop @conditional_stack; } $cond_true = 2; # undetermined ... } elsif ($line =~ /$RULE_PATTERN/o) { # Found a rule. $was_rule = 1; if (defined $contents{$1} && (@conditional_stack ? ! defined $conditional{$1} : defined $conditional{$1})) { &am_line_error ($1, "$1 defined both conditionally and unconditionally"); } # Value here doesn't matter; for targets we only note # existence. $contents{$1} = 1; $targets{$1} = 1; my $cond_string = join ('', @conditional_stack); if (@conditional_stack) { if ($conditional{$1}) { &check_ambiguous_conditional ($1, $cond_string); $conditional{$1} .= ' '; } else { $conditional{$1} = ''; } $conditional{$1} .= $cond_string . ' 1'; } $content_lines{$1} = $lnn; $output_trailer .= $comment . $spacing . $cond_string . $line; $comment = $spacing = ''; $saw_bk = ($line =~ /\\$/) ? 1 : 0; # Check the rule for being a suffix rule. If so, store in # a hash. my $source_suffix; my $object_suffix; if (($source_suffix, $object_suffix) = ($1 =~ $SUFFIX_RULE_PATTERN)) { $suffix_rules{$source_suffix} = $object_suffix; prt( "Sources ending in .$source_suffix become .$object_suffix\n" ) if $verbose; $source_suffix_pattern = "(" . join('|', keys %suffix_rules) . ")"; } # FIXME: make sure both suffixes are in SUFFIXES? Or set # SUFFIXES from suffix_rules? } elsif ($is_ok_macro = (($line =~ /$MACRO_PATTERN/o) || ($line =~ /$BOGUS_MACRO_PATTERN/o)) ) { prt( "Found a macro definition. 1[$1] 2[$2] 3[$3] ...\n" ) if ($dbg06); $was_rule = 0; $last_var_name = $1; if (defined $contents{$1} && (@conditional_stack ? ! defined $conditional{$1} : defined $conditional{$1})) { &am_line_error ($1, "$1 defined both conditionally and unconditionally"); } my $value; if ($3 ne '' && substr ($3, -1) eq "\\") { $value = substr ($3, 0, length ($3) - 1); } else { $value = $3; } my $type = $2; if ($type eq '+') { if (! defined $contents{$last_var_name} && defined $configure_vars{$last_var_name}) { $contents{$last_var_name} = '@' . $last_var_name . '@'; } $contents{$last_var_name} .= ' ' . $value; } else { if ( defined $contents{$last_var_name} ) { if ( @conditional_stack ) { if ( $conditional_stack[$#conditional_stack] =~ /_TRUE\@$/ ) { # we are in the if TRUE state if ($cond_true == 1) { if ($dbg06) { if ( $contents{$last_var_name} ne $value ) { prt( "NB: [$last_var_name] = [$contents{$last_var_name}]" . " replaced with [$value] (am_file=$am_file line=$.)". (($line =~ /\\$/) ? "saw_bk" : "end") . "\n" ); } } $contents{$last_var_name} = $value; $content_lines{$last_var_name} = $lnn; } } else { # we are in the else FALSE state if ($cond_true != 1) { if ($dbg06) { if ( $contents{$last_var_name} ne $value ) { prt( "NB: [$last_var_name] = [$contents{$last_var_name}]" . " replaced with [$value] (am_file=$am_file line=$.)". (($line =~ /\\$/) ? "saw_bk" : "end") . "\n" ); } } $contents{$last_var_name} = $value; $content_lines{$last_var_name} = $lnn; } } } } else { prt( "First setting [$last_var_name] = [$value] " . "(am_file=$am_file line=$.) ". (($line =~ /\\$/) ? "saw_bk" : "end") . "\n" ) if ($dbg06); $contents{$last_var_name} = $value; # The first assignment to a macro sets the line # number. Ideally I suppose we would associate line # numbers with random bits of text. $content_lines{$last_var_name} = $lnn; } } my $cond_string = join ('', @conditional_stack); if (@conditional_stack) { my $found = 0; my $val; if ($conditional{$last_var_name}) { if ($type eq '+') { # If we're adding to the conditional, and it # exists, then we might want to simply replace # the old value with the new one. my (@new_vals, @cond_vals); @cond_vals = split (' ', $conditional{$last_var_name}); while (@cond_vals) { $vcond = shift (@cond_vals); push (@new_vals, $vcond); if (&conditional_same ($vcond, $cond_string)) { $found = 1; $val = (&unquote_cond_val (shift (@cond_vals)) . ' ' . $value); push (@new_vals, "e_cond_val ($val)); } else { push (@new_vals, shift (@cond_vals)); } } if ($found) { $conditional{$last_var_name} = join (' ', @new_vals); } } if (! $found) { &check_ambiguous_conditional ($last_var_name, $cond_string); $conditional{$last_var_name} .= ' '; $val = $value; } } else { $conditional{$last_var_name} = ''; $val = $contents{$last_var_name}; } if (! $found) { $conditional{$last_var_name} .= ($cond_string . ' ' . "e_cond_val ($val)); } } # FIXME: this doesn't always work correctly; it will group # all comments for a given variable, no matter where # defined. $am_vars{$last_var_name} = $comment . $spacing; $def_type{$last_var_name} = ($type eq ':') ? ':' : ''; push (@var_list, $last_var_name); $comment = $spacing = ''; $saw_bk = ($line =~ /\\$/) ? 1 : 0; # Error if bogus. &am_line_error ($., "bad macro name \`$last_var_name'") if ! $is_ok_macro; } elsif ($line =~ /$INCLUDE_PATTERN/o) { my ($path) = $1; if ($path =~ s/^\$\(top_srcdir\)\///) { push (@include_stack, "\$\(top_srcdir\)/$path"); } else { $path =~ s/\$\(srcdir\)\///; push (@include_stack, "\$\(srcdir\)/$path"); $path = $relative_dir . "/" . $path; } my $ff = $path; if (! -f $ff) { $ff = $am_dir.$path; } if (-f $ff) { read_am_file ($ff); } else { prtw("WARNING: Unable to find include file [$ff] [$path] [$am_dir]\n"); } } else { # This isn't an error; it is probably a continued rule. # In fact, this is what we assume. $was_rule = 1; $output_trailer .= ($comment . $spacing . join ('', @conditional_stack) . $line); $comment = $spacing = ''; $saw_bk = ($line =~ /\\$/) ? 1 : 0; } } $output_trailer .= $comment; &am_error ("unterminated conditionals: " . join (' ', @conditional_stack)) if (@conditional_stack); prt( "Done $lncnt lines, from [$am_file]...\n" ) if $dbg02; } sub initialize_per_input { # These two variables are used when generating each Makefile.in. # They hold the Makefile.in until it is ready to be printed. $output_vars = ''; $output_trailer = ''; # This holds the contents of a Makefile.am, as parsed by # read_am_file. %contents = (); # This holds the names which are targets. These also appear in # %contents. %targets = (); # For a variable or target which is defined conditionally, this # holds an array of the conditional values. The array is composed # of pairs of condition strings (the variables which configure # will substitute) and values (the value of a target is # meaningless). For an unconditional variable, this is empty. %conditional = (); # This holds the line numbers at which various elements of # %contents are defined. %content_lines = (); # This holds a 1 if a particular variable was examined. %content_seen = (); # This is the conditional stack. @conditional_stack = (); # This holds the set of included files. @include_stack = (); # This holds the "relative directory" of the current Makefile.in. # Eg for src/Makefile.in, this is "src". $relative_dir = ''; # This maps the source extension of a suffix rule to its # corresponding output extension. %suffix_rules = (); } # Quote a value in order to put it in $conditional. We need to quote # spaces, and we need to handle null strings, so that we can later # retrieve values by splitting on space. sub quote_cond_val { my ($val) = @_; $val =~ s/ /\001/g; $val =~ s/\t/\003/g; $val = "\002" if $val eq ''; return $val; } # this function seems MISSING! sub unquote_cond_val { my ($val) = @_; $val =~ s/\001/ /g; $val =~ s/\003/\t/g; $val = '' if $val eq "\002"; return $val; } # this function seems MISSING # if (&conditional_same ($vcond, $cond_string)) sub conditional_same { my ($cond, $when) = @_; if ($when =~ $cond) { return 1; } return 0; } # See if a conditional is true. Both arguments are conditional # strings. This returns true if the first conditional is true when # the second conditional is true. sub conditional_true_when { my ($cond, $when) = @_; # Check the easy case first. if ($cond eq $when) { return 1; } # Check each component of $cond, which looks @COND1@@COND2@. foreach my $comp (split ('@', $cond)) { # The way we split will give null strings between each # condition. next if ! $comp; if (index ($when, '@' . $comp . '@') == -1) { return 0; } } return 1; } # Check for an ambiguous conditional. This is called when a variable # or target is being defined conditionally. If we already know about # a definition that is true under the same conditions, then we have an # ambiguity. sub check_ambiguous_conditional { my ($var_name, $cond) = @_; my (@cond_vals) = split (' ', $conditional{$var_name}); while (@cond_vals) { my ($vcond) = shift (@cond_vals); shift (@cond_vals); if (&conditional_true_when ($vcond, $cond) || &conditional_true_when ($cond, $vcond)) { prt( "$var_name multiply defined in condition\n" ); } } } sub am_error { my $msg = shift; push(@warnings, $msg ); prt( "$msg\n" ); } sub am_line_error { my ($symbol, @args) = @_; prt( "am_line_error: am_file=[$act_am_file] sym=[$symbol] arg0=[$args[0]] ...\n" ) if ($dbg06); if ($symbol && "$symbol" ne '-1') { my ($file) = "${act_am_file}"; if ($symbol =~ /^\d+$/) { # SYMBOL is a line number, so just add the colon. $file .= ':' . $symbol; } elsif (defined $content_lines{$symbol}) { # SYMBOL is a variable defined in Makefile.am, so add the # line number we saved from there. $file .= ':' . $content_lines{$symbol}; } elsif (defined $configure_vars{$symbol}) { # SYMBOL is a variable defined in configure.ac, so add the # appropriate line number. $file = $configure_vars{$symbol}; } else { # Couldn't find the line number. } warn $file, ": ", join (' ', @args), "\n"; $exit_status = 1; } else { &am_error (@args); } } sub generate_dsw { my $name = shift; my $dsw_name = $root_dir . $name . '.dsw'; open(DSW, ">$dsw_name") || mydie( "Can't create $dsw_name: $!\n" ); prt( "Creating $dsw_name\n" ) if $verbose; print DSW <<"EOF"; Microsoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### EOF print DSW 'Project: ', "\"$name\"=\".\\", $name, ".dsp\" - Package Owner=<4>\n"; print DSW <<"EOF"; Package=<5> {{{ }}} Package=<4> {{{ }}} EOF foreach my $p (@extra_projects) { print DSW "###############################################################################\n\n"; my ($dsp,$name) = split ',', $p; prt( "Project $name=$dsp\n" ) if $verbose; print DSW "Project: \"$name\"=\"$dsp\" - Package Owner=<4>\n\n"; print DSW <<"EOF"; Package=<5> {{{ }}} Package=<4> {{{ }}} EOF } print DSW <<"EOF"; ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### EOF close(DSW); } sub expand_here { local $_ = shift; s/\%cflags\%/$msvc_cflags/g; s/\%libs\%/$msvc_libs/g; s/\%dlibs\%/$msvc_dlibs/g; s/\%rlibs\%/$msvc_rlibs/g; return $_; } sub console_app_dsp_init { my $name = shift; my $dsp_name = $root_dir . $name . '.dsp'; open(DSP, ">$dsp_name") || mydie( "Can't create $dsp_name: $!\n" ); prt( "Creating $dsp_name\n" ) if $verbose; print DSP expand_here(<<"EOF"); # Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=$name - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "$name.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "\$(CFG)" == "$name - Win32 Release" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c %cflags% # SUBTRACT CPP /YX # ADD RSC /l 0xc09 /d "NDEBUG" BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ws2_32.lib /nologo /subsystem:console /machine:I386 %libs% %rlibs% !ELSEIF "\$(CFG)" == "$name - Win32 Debug" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c %cflags% # ADD RSC /l 0xc09 /d "_DEBUG" BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD LINK32 kernel32.lib user32.lib winspool.lib comdlg32.lib gdi32.lib shell32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept %libs% %dlibs% !ENDIF # Begin Target # Name "$name - Win32 Release" # Name "$name - Win32 Debug" EOF close(DSP); } sub static_lib_dsp_init { my $name = shift; my $dsp_name = $root_dir . $name . '.dsp'; open(DSP, ">$dsp_name") || mydie( "Can't create $dsp_name: $!\n" ); prt( "Creating $dsp_name\n" ) if $verbose; print DSP expand_here(<<"EOF"); # Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 CFG=$name - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "$name.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "\$(CFG)" == "$name - Win32 Release" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /FD /c %cflags% # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ELSEIF "\$(CFG)" == "$name - Win32 Debug" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD CPP /nologo /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /FR /FD /GZ /c %cflags% # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ENDIF # Begin Target # Name "$name - Win32 Release" # Name "$name - Win32 Debug" EOF close(DSP); } sub dsp_add_source_rule { my ($fh,$dsp_name,$group,$file,$dup) = @_; print $fh "# Begin Source File\n"; print $fh "\n"; print $fh "SOURCE=$file\n"; if ($add_groups) { print $fh "\n"; print $fh "!IF \"\$(CFG)\" == \"$dsp_name - Win32 Release\"\n"; print $fh "\n"; print $fh "# PROP Intermediate_Dir \"Release\\$group\"\n"; print $fh "# PROP Exclude_From_Build 1\n" if exclude_file($file); print $fh "\n"; print $fh "!ELSEIF \"\$(CFG)\" == \"$dsp_name - Win32 Debug\"\n"; print $fh "\n"; print $fh "# PROP Intermediate_Dir \"Debug\\$group\"\n"; print $fh "# PROP Exclude_From_Build 1\n" if exclude_file($file); print $fh "\n"; print $fh "!ENDIF \n"; print $fh "\n"; } elsif ($dup) { add_dupes_dir( \*$fh, $dsp_name ); } print $fh "# End Source File\n"; } sub dsp_add_group { my ($dsp_name,$makefile) = @_; my $base_dir = './'; my $dsp_file = $root_dir . $dsp_name .'.dsp'; prt( "dsp_add_group: using dsp_name=$dsp_file, and makefile=$makefile ...\n" ) if $verbose2; initialize_per_input(); my $relative_dir = loc_dirname($makefile); my $dupe = 0; my @files = (); my $key = ''; my $group = 'Lib_Special'; my $file = ''; read_main_am_file($root_dir . $makefile . '.am'); # output the content found prt( "List of CONTENTS keys ...\n" ) if ($dbg03); foreach $key (keys %contents) { $file = trim_all($contents{$key}); if ($key =~ /(.+)_SOURCES$/) { prt( "SOURCES: $1 = $file\n" ) if ($dbg03); push(@sources, [$1, $file]); } elsif ($key =~ /^SRCS_(.+)/) { prt( "SRCS: $1 = $file\n" ) if ($dbg03); push(@sources2, [$1, $file]); } else { prt( "$key = $file\n" ) if ($dbg03); } } prt( "DONE List of CONTENTS keys ...\n" ) if ($dbg03); # preview the 'contents' to find 'group' # use 'noinst_LIBRARIES' macro foreach $key (keys %contents) { if ($key eq 'noinst_LIBRARIES') { @files = split(' ', $contents{$key}); foreach $file (@files) { if ($file =~ /^lib([\w-]+)\.a/) { $group = 'Lib_' . $1; prt( "Group set to [$group] ...\n" ) if ($dbg06); last; } } } } # now extract SOURCES from 'contents' hash foreach $key (sort keys %contents) { #if ($key eq "include_HEADERS") { #} # not found in Makefile.am files? if ($key =~ /^lib(.*)_a_SOURCES/) { $group = 'Lib_' . $1; @files = split(' ', $contents{$key}); foreach (@files) { my $src_dir = $base_dir . $relative_dir . '/'; $src_dir =~ s/\//\\/g; # fixup DOS path separators if (/^\$\(([^\)]*)\)$/) { # Found a variable. my $varname = $1; prt( "Expanding variable $varname ...\n" ) if ($dbg06); foreach (split(' ', $contents{$varname})) { $file = $src_dir . $_; $dupe = add_2_source_list( $file, $group ); } prt( "Done expanding variable $varname ...\n" ) if ($dbg06); } else { $file = $src_dir . $_; $dupe = add_2_source_list( $file, $group ); } } } #elsif ($key =~ /(.*)_SOURCES/) { elsif ($key eq "fgfs_SOURCES") { $group = 'main'; @files = split(' ', $contents{$key}); foreach (@files) { my $src_dir = $base_dir . $relative_dir . '/'; $src_dir =~ s/\//\\/g; # fixup DOS path separators $file = $src_dir . $_; $dupe = add_2_source_list( $file, $group ); } } else { # key is NOT ( Lib(.*)_a_SOURCES fgfs_SOURCES ) if (($key eq 'EXTRA_DIST')||($key eq 'fgjs_SOURCES')) { @files = split(' ', $contents{$key}); foreach my $fi (@files) { my $ext = file_extension($fi); $file = $base_dir . $relative_dir . '/' . $fi; $file =~ s/\//\\/g; # use DOS path sep if (is_c_source_ext($ext)) { push(@msvc_c_extra, $file); prt( "Added [$file] to C EXTRA list\n" ) if $verbose2; } elsif (is_h_source_ext($ext)) { push(@msvc_h_extra, $file); prt( "Added [$file] to H EXTRA list\n" ) if $verbose2; } else { push(@msvc_o_extra, $file); prt( "Added [$file] to other EXTRA list\n" ) if $verbose2; } } } elsif ($key eq 'noinst_HEADERS') { # JSBSim has put the HEADERS in HERE @files = split(' ', $contents{$key}); foreach (@files) { $file = $base_dir . $relative_dir . '/' . $_; $file =~ s/\//\\/g; # use DOS path sep $dupe = add_2_source_list( $file, $group ); } } } } } sub dsp_finish { my $dsp_name = shift; my $dsp_file = $root_dir . $dsp_name . '.dsp'; open(DSP, ">>$dsp_file") || mydie( "Can't append to $dsp_file: $!\n" ); foreach my $r (@extra_sources) { print DSP "# Begin Source File\n\n"; print DSP "$r\n"; print DSP "# End Source File\n"; } print DSP "# End Target\n"; print DSP "# End Project\n"; close(DSP); } # Return directory name of file. sub loc_dirname($) { my $file = shift; my ($name,$dir) = fileparse($file); return $dir; } sub add_2_used_libs { my ($fil,$in) = @_; if (exists( $used_lib_paths{$in} ) ) { my @incs = split(/\|/ , $used_lib_paths{$in}); my $got = 0; foreach my $i (@incs) { if ($i eq $fil) { $got = 1; last; } } if ( ! $got ) { $used_lib_paths{$in} .= '|'.$fil; # add new } } else { $used_lib_paths{$in} = $fil; # set first } } sub check_lib_paths { my $fil = shift; my $inc = ''; my $ff = ''; my $finc = ''; my $fincr = ''; my $fincd = ''; my $found1 = 0; my $found2 = 0; my $found3 = 0; foreach $inc (@msvc_libs_paths) { $ff = $root_dir . $inc; if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) { $ff .= '\\'; } $ff .= $fil; if( -f $ff ) { $finc = $inc; $found1 = 1; last; } } foreach $inc (@msvc_rlibs_paths) { $ff = $root_dir . $inc; if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) { $ff .= '\\'; } $ff .= $fil; if( -f $ff ) { $fincr = $inc; $found2 = 1; last; } } foreach $inc (@msvc_dlibs_paths) { $ff = $root_dir . $inc; if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) { $ff .= '\\'; } $ff .= $fil; if( -f $ff ) { $fincd = $inc; $found3 = 1; last; } } if( $found1 || $found2 || $found3 ) { prt( "Found [$fil] in [$finc] [$ff] ...\n" ) if ($verbose2 && $found1); prt( "Found [$fil] in [$fincr] [$ff] ...\n" ) if ($verbose2 && $found2); prt( "Found [$fil] in [$fincd] [$ff] ...\n" ) if ($verbose2 && $found3); add_2_used_libs( $fil, $finc ) if $found1; add_2_used_libs( $fil, $fincr ) if $found2; add_2_used_libs( $fil, $fincd ) if $found3; } else { prt( "WARNING: Unable to locate $fil ...\n" ) if $verbose2; } return ($found1 + $found2 + $found3); } sub check_inc_paths { my $fil = shift; my $inc = ''; my $ff = ''; my $found = 0; if( ! $found ) { foreach $inc (@msvc_inc_paths) { $ff = $root_dir . $inc; if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) { $ff .= '\\'; } $ff .= $fil; ### print "Checking for $fil in $ff ...\n" if $verbose9; if( -f $ff ) { if (exists( $used_inc_paths{$inc} ) ) { my @incs = split(/\|/ , $used_inc_paths{$inc}); my $got = 0; foreach my $i (@incs) { if ($i eq $fil) { $got = 1; last; } } if ( ! $got ) { $used_inc_paths{$inc} .= '|'.$fil; # add new } } else { $used_inc_paths{$inc} = $fil; # set first } $found = 1; last; } } } if( $found ) { prt( "Found $fil in $inc [$ff] ...\n" ) if $verbose2; } else { prt( "WARNING: Unable to locate $fil ...\n" ) if $verbose2; } return $found; } sub show_lib_found { my (@arr) = @_; foreach my $in (@arr) { if (exists( $used_lib_paths{$in} ) ) { my @ip = split(/\|/, $used_lib_paths{$in}); prt( "On path [$root_dir][$in] found ".scalar @ip." items ...\n" ); my $cntr = 0; $in .= '\\' if !($in =~ /(\\|\/)$/); foreach my $f (@ip) { $cntr++; prt( "$cntr ".$root_dir.$in.$f."\n" ); } } else { prt( "Warning: Found nothing on [$root_dir][$in] ...\n" ); } } } sub is_c_source_ext { my $fil = shift; my $fe = lc($fil); return 1 if (($fe eq 'c')||($fe eq 'cxx')||($fe eq 'cpp')); return 1 if (($fe eq '.c')||($fe eq '.cxx')||($fe eq '.cpp')); return 0; } sub is_h_source_ext { my $fil = shift; my $fe = lc($fil); return 1 if (($fe eq 'h')||($fe eq 'hxx')||($fe eq 'hpp')); return 1 if (($fe eq '.h')||($fe eq '.hxx')||($fe eq '.hpp')); return 0; } sub add_2_source_list { my ($fil, $grp) = @_; my $fe = file_extension($fil); my $ft = lc(file_title($fil)); my $src = ($grp . '|' . $fil . '|' . $ft); my $ret = 0; ###if (($fe eq 'c')||($fe eq 'cxx')||($fe eq 'cpp')) { if ( is_c_source_ext($fe) ) { prt( "Add $src to C list\n" ) if $verbose2; push(@msvc_c_files, $src); foreach my $tt (@msvc_titles) { # just to deal with duplicate names if( $tt eq $ft ) { $ret = 1; last; } } push(@msvc_titles, $ft); } else { prt( "Add $src to H list\n" ) if $verbose2; push(@msvc_h_files, $src); } return $ret; } sub add_dupes_dir { my ($fh, $pack) = @_; print $fh "\n"; print $fh "!IF \"\$(CFG)\" == \"$pack - Win32 Release\"\n"; print $fh "\n"; print $fh "# PROP Intermediate_Dir \"Release\\Dupes\"\n"; print $fh "\n"; print $fh "!ELSEIF \"\$(CFG)\" == \"$pack - Win32 Debug\"\n"; print $fh "\n"; print $fh "# PROP Intermediate_Dir \"Debug\\Dupes\"\n"; print $fh "\n"; print $fh "!ENDIF\n"; print $fh "\n"; } sub write_new_dsp { ###my $new_pack = 'FGFS'; my $new_pack = $dsp_package; my $src; my $dsp_file = $root_dir . $new_pack .'.dsp'; my @bits = (); my @done = (); my $group = ''; my $pgrp = ''; my $tit = ''; my $isdupe = 0; if ($static_lib) { static_lib_dsp_init($new_pack); } else { console_app_dsp_init($new_pack); } prt( "Appending to [$dsp_file] ...\n" ); open(DSP, ">>$dsp_file") || mydie( "Can't append to $dsp_file: $!\n" ); if ( ! $add_groups) { print DSP "# Begin Group \"Source Files\"\n"; print DSP "\n"; print DSP "# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\n"; } foreach $src (@msvc_c_files) { prt( "Processing $src from array ...\n" ) if $verbose2; @bits = split( /\|/, $src ); # get file title, name and group $group = 'Lib_' . $bits[0]; $tit = $bits[2]; $isdupe = 0; if ($add_groups && ($group ne $pgrp)) { print DSP "# Begin Group \"$group\"\n"; print DSP "\n"; print DSP "# PROP Default_Filter \"\"\n"; } else { # not adding groups, check duplicate names foreach my $tt (@done) { if( $tt eq $tit ) { $isdupe = 1; last; } } } dsp_add_source_rule(\*DSP, $new_pack, $group, $bits[1], $isdupe); if ( !$add_groups && $isdupe) { prt( "Processed a DUPLICATE $tit from array ...\n" ) if $verbose2; prt( "Bits = ".$bits[0]."|".$bits[1].'|'.$bits[2]. " ...\n" ) if $verbose2; } push(@done, $tit); if ($add_groups && ($group ne $pgrp)) { print DSP "# End Group\n"; } $pgrp = $group; } if ( !$add_groups) { print DSP "# End Group\n"; } # just the HEADER files print DSP "# Begin Group \"Header Files\"\n"; print DSP "\n"; print DSP "# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\n"; my $savgrp = $add_groups; $add_groups = 0; foreach $src (@msvc_h_files) { @bits = split( /\|/, $src ); # get file title, name and group $group = 'Lib_' . $bits[2]; dsp_add_source_rule(\*DSP, $new_pack, $group, $bits[1], 0); } print DSP "# End Group\n"; close(DSP); $add_groups = $savgrp; dsp_finish($new_pack); generate_dsw($new_pack); prt( "Done ".$root_dir.$new_pack." DSP and DSW files ...\n" ); } sub show_src_lists() { # prt( "SOURCES: $1 = $file\n" ); # push(@sources, [$1, $file]); # } elsif ($key =~ /^SRCS_(.+)/) { # prt( "SRCS: $1 = $file\n" ); # push(@sources2, [$1, $file]); my $scnt2 = scalar @sources2; my ($i,$obj,$fls); if ($scnt2) { prt( "\nGot $scnt2 SRCS, as follows ...\n" ); for ($i = 0; $i < $scnt2; $i++) { $obj = $sources2[$i][0]; $fls = $sources2[$i][1]; prt( "$obj = $fls\n" ); } } my $scnt = scalar @sources; if ($scnt) { prt( "\nGot $scnt SOURCES, as follows ...\n" ); for ($i = 0; $i < $scnt; $i++) { $obj = $sources[$i][0]; $fls = $sources[$i][1]; prt( "$obj = $fls\n" ); } } } parse_arguments(@ARGV); read_am2dsprc($src_cfg); scan_configure(); mydie( "$pack: no input_files, so no 'Makefile.am' found or specified\n" ) if ! @input_files; foreach my $amf (@input_files) { prt( "\nProcessing [$amf] from input_files array ...\n" ) if $verbose2; dsp_add_group($dsp_package, $amf) if !exclude_dir($amf); } if ($do_check) { check_includes(); } if ( $write_new_dsp ) { write_new_dsp(); # experimental NEW DSP separating source and headers } show_src_lists(); pgm_exit(0,""); # end of process ################################################## # Ensure argument exists, or die. sub require_argument { my ($arg, @arglist) = @_; pgm_exit(1,"ERROR: no argument given for option [$arg]\n" ) if ! @arglist; } sub give_little_help { prt("$pgmname: version 0.2.1 2010-09-22\n"); prt(" Suspended this script for now - see amsrcs04.pl for fuller implementation.\n"); prt("Usage: $pgmname [options] [directory]\n"); prt("Options:\n"); prt( " --help -h -? = This brief help!\n" ); prt( " --verbose -v[num] = Sets verbose mode. (-v2 & -v3 for MORE)\n" ); prt( " --package name - Set the DSP package name (default = $dsp_package)\n" ); prt( " --lib (or -l) - To create static library (Default is console app.)\n" ); prt( " --groups (or -g) - Output source into 'group' folders, as original!\n" ); prt( " --dir path - Establish input path for source, and the $def_cfg.\n" ); prt( " --check (or -c) - Check libraries, and some known include files, and exit.\n" ); prt( " --cfg path\\file - Use a specific configuration file, if not with source.\n" ); prt( " --msvc8 - Modify, or check, the vcproj files, if found.\n" ); prt( " --load-log (-ll) - Load log at end of script.\n"); prt("If no -dir , or 'bare' directory on command line, then current work folder assumed.\n"); } sub set_input_dir { my $cfg = shift; if ( !(($cfg =~ /\/$/) || ($cfg =~ /\\$/)) ) { $cfg .= '\\'; } my $fil = $cfg . $def_cfg; $src_cfg = $fil; $root_dir = $cfg; prt( "Using root path [$root_dir] ...\n" ); } sub parse_arguments { my @av = @_; my ($arg,$sarg); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); $sarg = lc($sarg); if (($sarg eq 'help') || ($sarg eq 'h') || ($sarg eq '?')) { give_little_help(); # show help and exit pgm_exit(0,"Help exit 0\n"); } elsif (($sarg eq 'verbose') || ($arg =~ /^v/)) { $verbose++; if ($sarg eq 'verbose') { # done inc } elsif ($sarg eq 'v2' ) { $verbose2 = 1; } elsif ($sarg eq 'v3' ) { $verbose3 = 1; } else { pgm_exit(1,"ERROR: Unknown verbal argument [$arg]!\n"); } } elsif ($sarg eq 'package' || $sarg eq 'p') { require_argument(@av); shift @av; $dsp_package = $av[0]; } elsif ($sarg eq 'lib' || $sarg eq 'l') { # Create a static library $static_lib = 1; } elsif ($sarg eq 'load-log' || $sarg eq 'll') { $load_log = 1; } elsif ($sarg eq 'dir') { require_argument(@av); shift @av; set_input_dir($av[0]); } elsif ($sarg eq 'check' || $sarg eq 'c') { $do_check = 1; # perform check and exit } elsif ($sarg eq 'cfg') { require_argument(@av); shift @av; $src_cfg = $av[0]; } elsif ($sarg eq 'dbg' ) { $verbose = 1; $verbose2 = 1; $verbose3 = 1; $dbg04 = 1; $dbg05 = 1; $dbg06 = 1; $dbg07 = 1; $dbg08 = 1; } elsif ($sarg eq 'groups' || $arg eq 'g') { $add_groups = 1; # use original 'group' folders ... } else { pmg_exit(1,"ERROR: unrecognised option [$arg]! Try -? for some information.\n" ); } } else { set_input_dir($arg); } shift @av; } if (length($root_dir) == 0) { set_input_dir(path_u2d($cwdir)); } } # eof - am2list02.pl