showsln.pl to HTML.

index -|- end

Generated: Sat Oct 24 16:35:28 2020 from showsln.pl 2020/07/14 65.8 KB. text copy

#!/usr/bin/perl -w
# NAME: showsln.pl
# AIM: Read a MSVC solution file, and details the project
# 08/07/2020 - Review in Dell03, and some enhancement
# 18/12/2013 - Adjust what is shown by 'verbosity'
# 20/05/2013 - Works well ;=)) Time for some improvemments
# 17/05/2013 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 XML::Simple;
use Data::Dumper;
use Cwd;
my $os = $^O;
my $perl_dir = '/home/geoff/bin';
my $PATH_SEP = '/';
my $temp_dir = '/tmp';
if ($os =~ /win/i) {
    $perl_dir = 'C:\GTools\perl';
    $temp_dir = $perl_dir;
    $PATH_SEP = "\\";
}
unshift(@INC, $perl_dir);
require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n";
# log file stuff
our ($LF);
my $pgmname = $0;
if ($pgmname =~ /(\\|\/)/) {
    my @tmpsp = split(/(\\|\/)/,$pgmname);
    $pgmname = $tmpsp[-1];
}
my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt";
open_log($outfile);

# user variables
my $VERS = "0.0.2 2020-07-08";
#my $VERS = "0.0.1 2013-03-17";
my $load_log = 0;
my $in_file = '';
my $verbosity = 0;
my $out_file = '';
my $tmp_cmake_list = $temp_dir.$PATH_SEP."CMakeLists.txt";
my $del_opt_libs = 1;
my $del_GL_libs = 1;
my $del_dbg_libs = 1;
my $del_special_cmake = 1;
my $del_optional_defines = 1;
my $rel_dir = '';

# ### DEBUG ###
my $debug_on = 0;
my $def_file = 'C:\FG\18\fltk-1.3.2\ide\VisualC2010\fltk.sln';
##my $def_file = 'C:\FG\18\fltk-1.3.2\ide\VisualC2010\adjuster.vcxproj';
my $dbg_sl_01 = 0;
my $dbg_sl_02 = 0;
my $dbg_sl_03 = 0;
my $dbg_sl_14 = 0;
my $dbg_sl_15 = 0;
my $dbg_sl_16 = 0;

### program variables
my @warnings = ();
my $cwd = cwd();
my ($g_name,$g_sln_path,$g_ext); # get the NAME, and SOLUTION PATH (should be ABSOLUTE, NOT relative)

sub VERB1() { return $verbosity >= 1; }
sub VERB2() { return $verbosity >= 2; }
sub VERB5() { return $verbosity >= 5; }
sub VERB9() { return $verbosity >= 9; }

sub show_warnings($) {
    my ($val) = @_;
    if (@warnings) {
        prt( "\nGot ".scalar @warnings." WARNINGS...\n" );
        foreach my $itm (@warnings) {
           prt("$itm\n");
        }
        prt("\n");
    } else {
        prt( "\nNo warnings issued.\n\n" ) if (VERB9());
    }
}

sub pgm_exit($$) {
    my ($val,$msg) = @_;
    if (length($msg)) {
        $msg .= "\n" if (!($msg =~ /\n$/));
        prt($msg);
    }
    show_warnings($val);
    close_log($outfile,$load_log);
    exit($val);
}


sub prtw($) {
   my ($tx) = shift;
   $tx =~ s/\n$//;
   prt("$tx\n");
   push(@warnings,$tx);
}

sub is_sln_ext($) {
    my ($fil) = shift;
    my ($nm, $dir, $ext) = fileparse( $fil, qr/\.[^.]*/ );
    my $lce = lc($ext);
    if ($lce eq '.sln') {
        return 1;
    }
    return 0;
}

sub mycmp_nc_sort {
   return -1 if (lc($a) lt lc($b));
   return 1 if (lc($a) gt lc($b));
   return 0;
}
sub mycmp_nc_fn_only {
    my ($f1,$d1,$e1) = fileparse($a, qr/\.[^.]*/);
    my ($f2,$d2,$e2) = fileparse($b, qr/\.[^.]*/);
    return -1 if (lc($f1) lt lc($f2));
    return  1 if (lc($f1) gt lc($f2));
    return 0;
}

sub is_vcproj_ext($) {
    my ($fil) = shift;
    my ($nm, $dir, $ext) = fileparse( $fil, qr/\.[^.]*/ );
    my $lce = lc($ext);
    return 1 if ($lce eq '.vcproj');
    return 0;
}

sub is_vcxproj_ext($) {
    my $fil = shift;
    my ($nm, $dir, $ext) = fileparse( $fil, qr/\.[^.]*/ );
    my $lce = lc($ext);
    return 1 if ($lce eq '.vcxproj');   # 24/11/2010 VC10 support
    return 0;
}

my %Level_1 = (
      'ItemGroup' => 2,
      'xmlns' => 1,
      'Import' => 2,
      'ImportGroup' => 2,
      'PropertyGroup' => 2,
      'DefaultTargets' => 1,
      'ToolsVersion' => 1,
      'ItemDefinitionGroup' => 2
      );
my %ItemGourp = (
    'ProjectConfiguration' => 2,
    'ClCompile' => 2, # arr of hash 'Include' => '..\\..\\test\\CubeMain.cxx'
    'CustomBuild' => 2,
    'ProjectReference' => 2
    );

my %ItemDefinitionGroup = (
    'Midl' => 3, # 'HeaderFileName' => {}, 'TargetEnvironment' => 'Win32', 'TypeLibraryName' => '.\\CubeView__0/CubeView.tlb',
        # 'PreprocessorDefinitions' => '_DEBUG;%(PreprocessorDefinitions)'
    'ResourceCompile' => 3, # 'Culture' => '0x0409', 'PreprocessorDefinitions' => '_DEBUG;%(PreprocessorDefinitions)'
    'Condition' => 1, #'\'$(Configuration)|$(Platform)\'==\'Debug|Win32\'',
    'Link' => 3,
    #'ProgramDatabaseFile' => '$(IntDir)$(TargetName).pdb',
    # 'GenerateDebugInformation' => 'true',
    # 'AdditionalDependencies' => 'opengl32.lib;comctl32.lib;%(AdditionalDependencies)',
    # 'TargetMachine' => 'MachineX86',
    # 'IgnoreSpecificDefaultLibraries' => 'libcd;%(IgnoreSpecificDefaultLibraries)',
    # 'SubSystem' => 'Windows',
    # 'DataExecutionPrevention' => {},
    # 'RandomizedBaseAddress' => 'false',
    # 'SuppressStartupBanner' => 'true',
    #  'OutputFile' => '../../test/CubeViewd.exe',
    # 'AdditionalLibraryDirectories' => '..\\..\\lib;%(AdditionalLibraryDirectories)'
    'ClCompile' => 3
    # 'Optimization' => 'Disabled',
    # 'CompileAs' => 'Default',
    # 'DebugInformationFormat' => 'ProgramDatabase',
    # 'SuppressStartupBanner' => 'true',
    # 'PrecompiledHeader' => {},
    # 'RuntimeLibrary' => 'MultiThreadedDebugDLL',
    #'PreprocessorDefinitions' => '_CRT_SECURE_NO_DEPRECATE;WIN32;_DEBUG;_WINDOWS;WIN32_LEAN_AND_MEAN;VC_EXTRA_LEAN;WIN32_EXTRA_LEAN;%(PreprocessorDefinitions)',
    # 'AdditionalIncludeDirectories' => '.;..\\..\\zlib;..\\..\\png;..\\..\\jpeg;../..;%(AdditionalIncludeDirectories)'
);

my %master_hash = ();   # collect ALL information into here

########################################################################
##### CMake Stuff
my $libcmake = '';
my $execmake = '';
my $tot_libs = 0;
my $tot_exes = 0;
my $proj_title = 'temp';
my $ver_maj = 4;
my $ver_min = 0;
my $ver_pt  = 0;
my $ver_rc  = '';
my $ver_msg = 'FIX ME';
my $tot_files = 0;
my $tot_lines = 0;
my $add_options = 0;    # add options around each componets, -O
my $opt_list = '';
my $add_static_runtime = 1;
my %include_dirs = ();
my @add_inc_dirs = ();

sub add_options_block($) {
    my $type = shift;
    my $txt = <<EOF;

# Allow developer to select is Dynamic or static library built
set( LIB_TYPE STATIC )  # set default static
option( BUILD_SHARED_LIB "Set ON to build shared Library (DLL)" $type )
EOF
    #if ($add_one_lib) {
    #    $txt .= "# Turn ON to combine libraries into EXE - above shared library MUST be OFF!\n";
    #    $txt .= "option( BUILD_AS_ONE \"Set ON to build as one combine library into EXE\" OFF )\n";
    #}
    if ($add_options && length($opt_list)) {
        $txt .= $opt_list;
    }
    $txt .= "\n";
    return $txt;
}

sub get_unix_defs {
    my $txt = <<EOF;

if(CMAKE_COMPILER_IS_GNUCXX)
    set( WARNING_FLAGS -Wall )
endif()

if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 
   set( WARNING_FLAGS "-Wall -Wno-overloaded-virtual" )
endif() 
EOF
    return $txt;
}

sub add_static_runtime() {
    my $txt = <<EOF;
    option( USE_STATIC_RUNTIME "Set ON to change /MD(DLL) to /MT(static)" ON )
    if (USE_STATIC_RUNTIME)
        set(CompilerFlags
            CMAKE_CXX_FLAGS
            CMAKE_CXX_FLAGS_DEBUG
            CMAKE_CXX_FLAGS_RELEASE
            CMAKE_C_FLAGS
            CMAKE_C_FLAGS_DEBUG
            CMAKE_C_FLAGS_RELEASE
            )
        foreach(CompilerFlag \${CompilerFlags})
            string(REPLACE "/MD" "/MT" \${CompilerFlag} "\${\${CompilerFlag}}")
        endforeach()    
        message(STATUS "Using /MT STATIC runtime")
    else ()
        message(STATUS "Using /MD DYNAMIC runtime")
    endif ()
EOF
    return $txt;
}

sub get_msvc_defs {
    my $txt = <<EOF;

if(WIN32 AND MSVC)
    # turn off various warnings - none needed in this compile
    set(WARNING_FLAGS "\${WARNING_FLAGS} /wd4996")
    # foreach(warning 4244 4251 4267 4275 4290 4786 4305)
    #     set(WARNING_FLAGS "\${WARNING_FLAGS} /wd\${warning}")
    # endforeach(warning)
    # other flags -DNOMINMAX  -D_SCL_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS
    set( MSVC_FLAGS "-D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS" )
    # if (\${MSVC_VERSION} EQUAL 1600)
    #    set( MSVC_LD_FLAGS "/FORCE:MULTIPLE" )
    # endif (\${MSVC_VERSION} EQUAL 1600)
    #set( NOMINMAX 1 )
    # to distinguish between debug and release libs
    set( CMAKE_DEBUG_POSTFIX "d" )
EOF
    $txt .= add_static_runtime() if ($add_static_runtime);
    return $txt;
}

sub get_mingw_defs {
    my $txt = <<EOF;
    #if(MINGW)
        # need to specifically handle rc files, like
        # resource compilation for mingw
        #ADD_CUSTOM_COMMAND(OUTPUT \${CMAKE_CURRENT_BINARY_DIR}/test_rc.o
        #                   COMMAND windres.exe -I\${CMAKE_CURRENT_SOURCE_DIR}
        #                                       -i\${CMAKE_CURRENT_SOURCE_DIR}/test.rc
        #                                       -o \${CMAKE_CURRENT_BINARY_DIR}/test_rc.o)
        #SET(test_EXE_SRCS \${test_EXE_SRCS} \${CMAKE_CURRENT_BINARY_DIR}/test_rc.o)
    #else(MINGW)
        #SET(test_EXE_SRCS \${test_EXE_SRCS} test.rc)
    #endif(MINGW)
EOF
    return $txt;
}

sub get_other_defs {
    my $txt = <<EOF;
else()
    # items for unix
endif()

set( CMAKE_C_FLAGS "\${CMAKE_C_FLAGS} \${WARNING_FLAGS} \${MSVC_FLAGS} -D_REENTRANT" )
set( CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} \${WARNING_FLAGS} \${MSVC_FLAGS} -D_REENTRANT" )
set( CMAKE_EXE_LINKER_FLAGS "\${CMAKE_EXE_LINKER_FLAGS} \${MSVC_LD_FLAGS}" )

# configuration file, if needed
# configure_file( \${CMAKE_SOURCE_DIR}/config.h.cmake \${CMAKE_BINARY_DIR}/config.h )
# add_definitions( -DHAVE_CONFIG_H )
# include_directories( \${CMAKE_BINARY_DIR} )

if(BUILD_SHARED_LIB)
   set(LIB_TYPE SHARED)
   message(STATUS "*** Building DLL library \${LIB_TYPE}")
else()
   message(STATUS "*** Option BUILD_SHARED_LIB is OFF \${LIB_TYPE}")
endif()

EOF

    if (@add_inc_dirs) {
        my ($dir);
        $txt .= "# User added include directories...\n";
        foreach $dir (@add_inc_dirs) {
            $txt .= "include_directories( $dir )\n";
        }
    }

   my @dirs = sort keys( %include_dirs );
    if (@dirs) {
        my ($dir);
        $txt .= "# Other suggested include directories...\n";
       foreach $dir (@dirs) {
          $txt .= "#include_directories( $dir )\n";
       }
       $txt .= "\n" 
    }

    return $txt;
}

sub get_definitions_block {
    my $txt = get_unix_defs();
    $txt .= get_msvc_defs();
    #if ($add_extra_info) {
    #    $txt .= get_mingw_defs();
    #}
    $txt .= get_other_defs();
    return $txt;
}


sub get_cmake_root() {
    my $cmake_root = "# CMakeLists.txt, generated by $pgmname, on ";
    $cmake_root .= lu_get_YYYYMMDD_hhmmss(time())."\n";
    $cmake_root .= "# Beginning with $in_file,\n";
    $cmake_root .= "# processed $tot_files 'sln' files, $tot_lines lines, for $tot_libs libs & $tot_exes exes.\n";
    #if ($add_extra_info) {
    #    $cmake_root .= get_info_block();
    #}
    $cmake_root .= "cmake_minimum_required( VERSION 3.6 )\n\n";
    $cmake_root .= "# CMakeScripts or use the ones that come by default with CMake.\n";
    $cmake_root .= "# set(CMAKE_MODULE_PATH \${CMAKE_SOURCE_DIR}/CMakeModules \${CMAKE_MODULE_PATH})\n\n";
    $cmake_root .= "project( $proj_title )\n\n";
    # 20200531 - try 'configure.ac' read 
    # ====================================
    $cmake_root .= "# The version number. *** $ver_msg ***\n";
    $cmake_root .= "set( ${proj_title}_MAJOR $ver_maj )\n";
    $cmake_root .= "set( ${proj_title}_MINOR $ver_min )\n";
    $cmake_root .= "set( ${proj_title}_POINT $ver_pt )\n";
    if (length($ver_rc)) {
        $cmake_root .= "set( ${proj_title}_RC $ver_rc )\n";
    }
    $cmake_root .= add_options_block("OFF");
    $cmake_root .= get_definitions_block();
    return $cmake_root;
}

sub out_cmake_list() {
    my $cmake = get_cmake_root();
    my $ind = '    ';

    $cmake .= "#################################################\n";
    $cmake .= "##### LIBRARIES $tot_libs #####\n";
    $cmake .= "#################################################\n";
    if (length($libcmake)) {
        $cmake .= $libcmake;
    } else {
        # 30/04/2015 - even add this is no libraries
        $cmake .= "#add_library( \$\{name\} [type] \$\{\$\{name\}_SRCS\} \$\{\$\{name\}_HDRS\} )\n";
        $cmake .= "#list(APPEND add_LIBS \$\{name\})\n";
        $cmake .= "# deal with install, if any...\n"; 
        $cmake .= "#install( TARGETS \$\{name\}\n";
        $cmake .= "#".$ind."RUNTIME DESTINATION bin\n";
        $cmake .= "#".$ind."LIBRARY DESTINATION lib\n";
        $cmake .= "#".$ind."ARCHIVE DESTINATION lib )\n";
        $cmake .= "#install(FILES \$\{\$\{name\}_HDRS\} DESTINATION include)\n";
    }
    $cmake .= "\n";
    $cmake .= "#################################################\n";
    $cmake .= "##### EXECUTABLES $tot_exes #####\n";
    $cmake .= "#################################################\n";
    if (length($execmake)) {
        $cmake .= $execmake;
    } else {
        $cmake .= "#add_executable( \$\{name\} [type] \$\{\$\{name\}_SRCS\} \$\{\$\{name\}_HDRS\} )\n";
        $cmake .= "#if(add_LIBS)\n";
        $cmake .= "#$ind target_link_libraries( \$\{name\} \${add_LIBS} )\n";
        $cmake .= "#endif ()\n";
        $cmake .= "#if (MSVC)\n";
        $cmake .= "#$ind set_target_properties( \$\{name\} PROPERTIES DEBUG_POSTFIX d )\n";
        $cmake .= "#endif ()\n";
        $cmake .= "#install( TARGETS \$\{name\} DESTINATION bin )\n";
    }
    $cmake .= "\n";
    $cmake .= "# eof\n";

    if (length($out_file) == 0) {
        $out_file = $tmp_cmake_list;
        prt("Setting DEFAULT ouput file, since no -o <file> given!\n");
    }
    rename_2_old_bak($out_file);
    write2file($cmake,$out_file);
    prt("CMake string written to [$out_file]\n");
}

########################################################################

sub process_xml_file($$$) {
    my ($inf,$proj,$num) = @_;
    if (! -f $inf ) {
        pgm_exit(1,"ERROR: Unable to find file [$inf]\n"); 
    }
    if (! open INF, "<$inf") {
        pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); 
    }
    my @lines = <INF>;
    close INF;
    my $lncnt = scalar @lines;
    $tot_files++;
    $tot_lines += $lncnt;
    my $line = join("",@lines);
    my $xml = new XML::Simple; # (ForceArray => 0);
    my $data = $xml->XMLin($line);
    #my $data = $xml->XMLin($inf);
    ##prt(Dumper($data));
    ##$load_log = 2;
    my ($key,$val,$typ,$acnt,$rt,$righ,@arr,$item,$tmp);
    my ($rcmpa);
    my ($rca,$src);
    my ($rpph,$ppc,$rppa,$ff);
    my %SOURCES = ();
    my %FF_SRCS = ();
    my %HEADERS = ();
    my %FF_HDRS = ();
    my @a = ();
    my %pp = ();
    my %aid = (); # 'AdditionalIncludeDirectories'
    my %ald = ();
    my %adl = ();
    my $config = '';
    my $subsystem = '';
    $ff = File::Spec->rel2abs($inf);
    my ($inam,$idir) = fileparse($ff);
    foreach $key (keys %Level_1) {
        $typ = $Level_1{$key};
        if (defined ${$data}{$key}) {
            $val = ${$data}{$key};
            $rt = ref($val);
            if ($typ == 1) {
                prt("$key = $val\n") if (VERB9());
            } elsif ($typ == 2) {
                # this is an ARRAY
                if ($rt eq 'ARRAY') {
                    $acnt = scalar @{$val};
                    prt("$key is arrays with $acnt members...\n") if (VERB9());
                    if ($key eq 'ItemGroup') {
                        # this is where we SHOULD find the SOURCES
                        foreach $righ (@{$val}) {
                            if (defined ${$righ}{'ClCompile'}) {
                                $rcmpa = ${$righ}{'ClCompile'};
                                $rt = ref($rcmpa);
                                if ($rt eq 'ARRAY') {
                                    foreach $rca (@{$rcmpa}) {
                                        $item = 'Include';
                                        if (defined ${$rca}{$item}) {
                                            $src = ${$rca}{$item};
                                            $SOURCES{$src} = 1;
                                            $ff = File::Spec->rel2abs($idir.$src);
                                            $FF_SRCS{$ff} = 1;
                                        }
                                        $item = 'PreprocessorDefinitions';
                                        if (defined ${$rca}{$item}) {
                                            $rppa = ${$rca}{$item};
                                            foreach $rpph (@{$rppa}) {
                                                if (defined ${$rpph}{'content'}) {
                                                    $ppc = ${$rpph}{'content'};
                                                    $ppc =~ s/\%\(PreprocessorDefinitions\)//;
                                                    $pp{$ppc} = 1 if (length($ppc));
                                                }
                                            }
                                        }
                                        $item = 'AdditionalIncludeDirectories';
                                        if (defined ${$rca}{$item}) {
                                            $rppa = ${$rca}{$item};
                                            foreach $rpph (@{$rppa}) {
                                                if (defined ${$rpph}{'content'}) {
                                                    $ppc = ${$rpph}{'content'};
                                                    $ppc =~ s/\%\(AdditionalIncludeDirectories\)//;
                                                    $aid{$ppc} = 1 if (length($ppc));
                                                }
                                            }
                                        }
                                    }
                                } elsif ($rt eq 'HASH') {
                                    $rca = $rcmpa;
                                    $item = 'Include';
                                    if (defined ${$rca}{$item}) {
                                        $src = ${$rca}{$item};
                                        $SOURCES{$src} = 1;
                                        $ff = File::Spec->rel2abs($idir.$src);
                                        $FF_SRCS{$ff} = 1;
                                    }
                                    $item = 'PreprocessorDefinitions';
                                    if (defined ${$rca}{$item}) {
                                        $rppa = ${$rca}{$item};
                                        foreach $rpph (@{$rppa}) {
                                            if (defined ${$rpph}{'content'}) {
                                                $ppc = ${$rpph}{'content'};
                                                $ppc =~ s/\%\(PreprocessorDefinitions\)//;
                                                $pp{$ppc} = 1 if (length($ppc));
                                            }
                                        }
                                    }
                                    $item = 'AdditionalIncludeDirectories';
                                    if (defined ${$rca}{$item}) {
                                        $rppa = ${$rca}{$item};
                                        foreach $rpph (@{$rppa}) {
                                            if (defined ${$rpph}{'content'}) {
                                                $ppc = ${$rpph}{'content'};
                                                $ppc =~ s/\%\(AdditionalIncludeDirectories\)//;
                                                $aid{$ppc} = 1 if (length($ppc));
                                            }
                                        }
                                    }

                                }
                            } elsif (defined ${$righ}{'ClInclude'}) {
                                $rcmpa = ${$righ}{'ClInclude'};
                                $rt = ref($rcmpa);
                                if ($rt eq 'ARRAY') {
                                    foreach $rca (@{$rcmpa}) {
                                        $item = 'Include';
                                        if (defined ${$rca}{$item}) {
                                            $src = ${$rca}{$item};
                                            $ff = File::Spec->rel2abs($idir.$src);
                                            $HEADERS{$src} = 1;
                                            if (-f $ff) {
                                                $FF_HDRS{$ff} = 1;
                                            } else {
                                                prtw("WARNING:[v9]: Failed to find '$ff`, '$src'\n") if (VERB9());
                                            }
                                        }
                                    }
                                } elsif ($rt eq 'HASH') {
                                    $rca = $rcmpa;
                                    $item = 'Include';
                                    if (defined ${$rca}{$item}) {
                                        $src = ${$rca}{$item};
                                        $HEADERS{$src} = 1;
                                        $ff = File::Spec->rel2abs($idir.$src);
                                        if (-f $ff) {
                                            $FF_HDRS{$ff} = 1;
                                        } else {
                                            prtw("WARNING:[v9]: Failed to find '$ff`, '$src'\n") if (VERB9());
                                        }
                                    }
                                }
                            }

                        }
                    } elsif ($key eq 'ItemDefinitionGroup') {
                        foreach $righ (@{$val}) {
                            if (defined ${$righ}{'Link'}) {
                                $rcmpa = ${$righ}{'Link'};
                                $rt = ref($rcmpa);
                                if ($rt eq 'HASH') {
                                    foreach $rca (keys %{$rcmpa}) {
                                        $ppc = ${$rcmpa}{$rca};
                                        if ($rca eq 'AdditionalDependencies') {
                                            $ppc =~ s/\%\(AdditionalDependencies\)//;
                                            @a = split(';',$ppc);
                                            foreach $ppc (@a) {
                                                $adl{$ppc} = 1 if (length($ppc));
                                            }
                                        } elsif ($rca eq 'AdditionalLibraryDirectories') {
                                            $ppc =~ s/\%\(AdditionalLibraryDirectories\)//;
                                            @a = split(';',$ppc);
                                            foreach $ppc (@a) {
                                                $ald{$ppc} = 1 if (length($ppc));
                                            }
                                        } elsif ($rca eq 'SubSystem') {
                                            $subsystem = $ppc if (length($ppc));
                                        }
                                    }
                                }
                            } elsif (defined ${$righ}{'ClCompile'}) {
                                $rcmpa = ${$righ}{'ClCompile'};
                                $rt = ref($rcmpa);
                                if ($rt eq 'ARRAY') {
                                    foreach $rca (@{$rcmpa}) {
                                        $item = 'PreprocessorDefinitions';
                                        if (defined ${$rca}{$item}) {
                                            $rppa = ${$rca}{$item};
                                            foreach $rpph (@{$rppa}) {
                                                if (defined ${$rpph}{'content'}) {
                                                    $ppc = ${$rpph}{'content'};
                                                    $ppc =~ s/\%\(PreprocessorDefinitions\)//;
                                                    $pp{$ppc} = 1 if (length($ppc));
                                                }
                                            }
                                        }
                                        $item = 'AdditionalIncludeDirectories';
                                        if (defined ${$rca}{$item}) {
                                            $rppa = ${$rca}{$item};
                                            foreach $rpph (@{$rppa}) {
                                                if (defined ${$rpph}{'content'}) {
                                                    $ppc = ${$rpph}{'content'};
                                                    $ppc =~ s/\%\(AdditionalIncludeDirectories\)//;
                                                    $aid{$ppc} = 1 if (length($ppc));
                                                }
                                            }
                                        }
                                    }
                                } elsif ($rt eq 'HASH') {
                                    $rca = $rcmpa;
                                    $item = 'PreprocessorDefinitions';
                                    if (defined ${$rca}{$item}) {
                                        $rppa = ${$rca}{$item};
                                        $rt = ref($rppa);
                                        if ($rt eq 'ARRAY') {
                                            foreach $rpph (@{$rppa}) {
                                                if (defined ${$rpph}{'content'}) {
                                                    $ppc = ${$rpph}{'content'};
                                                    $ppc =~ s/\%\(PreprocessorDefinitions\)//;
                                                    $pp{$ppc} = 1 if (length($ppc));
                                                }
                                            }
                                        } elsif ($rt eq 'HASH') {
                                            $rpph = $rppa;
                                            if (defined ${$rpph}{'content'}) {
                                                $ppc = ${$rpph}{'content'};
                                                $ppc =~ s/\%\(PreprocessorDefinitions\)//;
                                                $pp{$ppc} = 1 if (length($ppc));
                                            }
                                        } elsif ($rt eq '') {
                                            $ppc = $rppa;
                                            $ppc =~ s/\%\(PreprocessorDefinitions\)//;
                                            $pp{$ppc} = 1 if (length($ppc));
                                        }
                                    }
                                    $item = 'AdditionalIncludeDirectories';
                                    if (defined ${$rca}{$item}) {
                                        $rppa = ${$rca}{$item};
                                        $rt = ref($rppa);
                                        if ($rt eq 'ARRAY') {
                                            foreach $rpph (@{$rppa}) {
                                                if (defined ${$rpph}{'content'}) {
                                                    $ppc = ${$rpph}{'content'};
                                                    $ppc =~ s/\%\(AdditionalIncludeDirectories\)//;
                                                    $aid{$ppc} = 1 if (length($ppc));
                                                }
                                            }
                                        } elsif ($rt eq 'HASH') {
                                            $rpph = $rppa;
                                            if (defined ${$rpph}{'content'}) {
                                                $ppc = ${$rpph}{'content'};
                                                $ppc =~ s/\%\(AdditionalIncludeDirectories\)//;
                                                $aid{$ppc} = 1 if (length($ppc));
                                            }
                                        } elsif ($rt eq '') {
                                            $ppc = $rppa;
                                            $ppc =~ s/\%\(AdditionalIncludeDirectories\)//;
                                            $aid{$ppc} = 1 if (length($ppc));
                                        }
                                    }
                                }
                            }
                        }
                    } elsif ($key eq 'PropertyGroup') {
                        $rt = ref($val);
                        if ($rt eq 'ARRAY') {
                            foreach $righ (@{$val}) {
                                $rt = ref($righ);
                                if ($rt eq 'HASH') {
                                    # Application, DynamicLibrary, StaticLibrary
                                    $item = 'ConfigurationType';
                                    if (defined ${$righ}{$item}) {
                                        $ppc = ${$righ}{$item};
                                        if (length($config)) {
                                            @a = split(';',$config);
                                            foreach $src (@a) {
                                                if ($src eq $ppc) {
                                                    $ppc = '';
                                                    last;
                                                }
                                            }
                                            $config .= ";$ppc" if (length($ppc));
                                        } else {
                                            $config = $ppc if (length($ppc));
                                        }
                                    }
                                }

                            }
                        }
                    }
                } else {
                    prt("$key: expected array, but got [$rt]\n");
                }
            }
        } else {
            prt("Key $key not found in xml!\n");
        }
    }
    my $splproj = 0;
    # =====================================================================
    # show what was found in this file
    # A CONSOLE APP SHOWS: AppType: Application;Console
    # A WINDOWS APP SHOWS: AppType: Application;Windows
    # A SHARED  DLL SHOWS: AppType: DynamicLibrary;Windows
    # A STATIC  LIB SHOWS: AppType: StaticLibrary;
    if (($proj eq 'ALL_BUILD')||($proj eq 'INSTALL')||($proj eq 'ZERO_CHECK')) {
        prt("[v9]: $proj: AppType: $config;$subsystem\n") if (VERB9()); # if (length($config)||length($subsystem));
        $splproj = 1;
    } else {
        prt("[v1]: $proj:$num: AppType: $config;$subsystem\n") if (VERB1()); # if (length($config)||length($subsystem));
    }
    #####################################################
    $master_hash{$proj}->{inputfile} = $inf;
    $master_hash{$proj}->{apptype} = "$config;$subsystem";
    my ($relpath,%bs);
    my ($n,$d,$ext);
    # ===================================================================
    # DEAL with the SOURCES if any
    ##############################
    ###@a = sort mycmp_nc_fn_only keys(%SOURCES);
    @a = sort mycmp_nc_fn_only keys(%FF_SRCS);
    if (length($rel_dir)) {
        # need to get relative path to this directory
        %bs = ();
        foreach $key (@a) {
            $tmp = $key;
            ($n,$d) = fileparse($key);
            $relpath = get_rel_dos_path($d,$rel_dir);
            $key = $relpath.$n;
            prt("[v9]: $tmp -> $key\n") if (VERB9());
            $bs{$key} = 1;
        }
        ### @a = sort mycmp_nc_fn_only keys(%bs);
        @a = sort mycmp_nc_sort keys(%bs);
    }
    $master_hash{$proj}->{sources} = [@a];
    $tmp = scalar @a;
    if ($tmp) {
        prt("[v1]: $proj:$num: $tmp Sources:\n") if (VERB1());
        prt("[v5]: ".join("\n",@a)."\n") if (VERB5());
    } elsif (!$splproj) {
        prtw("WARNING: $proj:$num: No sources found.\n"); # if (VERB5());
    }
    # DEAL with the HEADER if any
    ##############################
    ###@a = sort mycmp_nc_fn_only keys(%HEADERS);
    @a = sort mycmp_nc_fn_only keys(%FF_HDRS);
    if (length($rel_dir)) {
        # need to get relative path to this directory
        %bs = ();
        foreach $key (@a) {
            $tmp = $key;
            ($n,$d) = fileparse($key);
            $relpath = get_rel_dos_path($d,$rel_dir);
            $key = $relpath.$n;
            prt("[v9]: $tmp -> $key\n") if (VERB9());
            $bs{$key} = 1;
        }
        ### @a = sort mycmp_nc_fn_only keys(%bs);
        @a = sort mycmp_nc_sort keys(%bs);
    }
    $master_hash{$proj}->{headers} = [@a];
    $tmp = scalar @a;
    if ($tmp) {
        prt("$proj:$num: $tmp Headers:\n") if (VERB1());
        prt(join("\n",@a)."\n") if (VERB5());
    } elsif (!$splproj) {
        prtw("WARNING: $proj:$num: No headers found.\n") if (VERB5());
    }

    # ====================================================================
    # deal with PREPROCESSOR instruction - try to reduce to minimum
    ####################################
    # drop known items
    my %drop_outs = (
        '_WINDOWS' => 1,
        '_DEBUG'   => 1, 
        'NDEBUG'   => 1,
        'WIN32_LEAN_AND_MEAN' => 1,
        'WIN32' => 1,
        'WIN32_EXTRA_LEAN' => 1,
        'VC_EXTRA_LEAN' => 1,
        '_CRT_SECURE_NO_DEPRECATE' => 1,
        '__CRT_NONSTDC_NO_WARNINGS' => 1,
        '_SCL_SECURE_NO_WARNINGS' => 1,
        '_CRT_SECURE_NO_WARNINGS' => 1 );

    my %drop_optional = (
        '_REENTRANT' => 1,          # also maybe optional
        '_USE_MATH_DEFINES' => 1,   # maybe should be optional
        'NOMINMAX' => 1 );          

    @a = keys %pp;
    %pp = ();
    foreach $key (@a) {
        $key = trim_all($key);
        @arr = split(";",$key);
        foreach $key (@arr) {
            $key = trim_all($key);
            next if (defined $drop_outs{$key});
            if (length($key)) {
                if ($del_special_cmake) {
                    next if ($key =~ /^CMAKE_INTDIR=/);
                }
                if ($del_optional_defines) {
                    next if (defined $drop_optional{$key});
                }
                $pp{$key} = 1;
            }
        }
    }
    @a = sort keys %pp;
    $master_hash{$proj}->{preprocs} = [@a];
    if (@a) {
        prt("$proj:$num: PreProcs: ".join(";",@a)."\n") if (VERB5());
    }
    # ====================================================================


    # ====================================================================
    # LIKEWISE - remove all duplicates, sort, and ensure DOS
    ##################################
    @a = keys %aid; # 'AdditionalIncludeDirectories'
    %aid = ();
    foreach $key (@a) {
        $key = trim_all($key);
        next if (length($key) == 0);
        @arr = split(";",$key);
        foreach $key (@arr) {
            $key = trim_all($key);
            if (length($key)) {
                $key = path_u2d($key);
                $aid{$key} = 1;
            }
        }
    }
    @a = sort mycmp_nc_sort keys(%aid); # 'AdditionalIncludeDirectories'
    if (length($rel_dir)) {
        # need to get relative path to this directory
        %bs = ();
        foreach $key (@a) {
            $ff = File::Spec->rel2abs($idir.$key);
            $relpath = get_rel_dos_path($ff,$rel_dir);
            $relpath =~ s/\\$//;
            prt("[v9]:aid: $key -> $ff -> $relpath\n") if (VERB9());
            $bs{$relpath} = 1;
        }
        ###@a = sort mycmp_nc_fn_only keys(%bs);
        @a = sort mycmp_nc_sort keys(%bs);
    }

    $master_hash{$proj}->{addincs} = [@a];
    if (@a) {
        prt("[v2]: $proj:$num: AddIncs: ".join(";",@a)."\n") if (VERB2());
    }
    # ====================================================================

    
    # ====================================================================
    # would like to DROP all standard windows libraries 
    my %win_libraries = (
        'ole32.lib' => 1,
        'shell32.lib' => 1,
        'uuid.lib' => 1,
        'kernel32.lib' => 1,
        'oleaut32.lib' => 1,
        'user32.lib' => 1,
        'winspool.lib' => 1,
        'gdi32.lib' => 1 );
    my %opt_libraries = (
        'advapi32.lib' => 1,
        'comdlg32.lib' => 1,
        'winmm.lib' => 1 );    # maybe not this????
    my %gl_libraries = (
        'opengl32.lib' => 1,
        'glu32.lib' => 1 );

    # AND maybe drop a library used twice where the second is just with a 'd'
    # appended, and maybe optionally remove all paths, and add any path
    # to the additional library directories
    @a = keys %adl;
    %adl = ();
    foreach $key (@a) {
        $key = trim_all($key);
        next if (length($key) == 0);
        @arr = split(/\s+/,$key);
        foreach $key (@arr) {
            $key = trim_all($key);
            if (length($key)) {
                $key = path_u2d($key);
                ($key,$d) = fileparse($key); # get the NAME only
                next if (length($key) == 0);
                $src = lc($key);
                next if (defined $win_libraries{$src});
                if ($del_opt_libs) {
                    next if (defined $opt_libraries{$src});
                }
                if ($del_GL_libs) {
                    next if (defined $gl_libraries{$src});
                }
                $adl{$key} = 1;
            }
        }
    }
    if ($del_dbg_libs) {
        @a = keys %adl;
        @arr = ();
        foreach $key (@a) {
            ($n,$d,$ext) = fileparse($key, qr/\.[^.]*/);
            if ((length($n) > 2) && ($n =~ /d$/i)) {
                $n =~ s/d$//i;   # remove trailing 'd'
                $src = $n.$ext# get name without 'd'
                next if (defined $adl{$src}); # skip if we have that name
            }
            push(@arr,$key);
        }
        %adl = ();
        foreach $key (@arr) {
            next if (length($key) == 0);
            $adl{$key} = 1;
        }
    }
    @a = sort mycmp_nc_sort keys(%adl);
    $master_hash{$proj}->{libdeps} = [@a];
    if (@a) {
         if (VERB9()) {
            prt("$proj: LibDeps: ".join(" ",@a)."\n");
         } elsif (VERB2()) {
             my %h = ();
             foreach $key (@a) {
                 $h{$key} = 1;
             }
             @a = sort mycmp_nc_sort keys(%h);
             prt("$proj: LibDeps: ".join(" ",@a)."\n");
         }
    }
    # ====================================================================

    # ====================================================================
    # Additional LIBRARY directories
    @a = keys %ald;
    %ald = ();
    foreach $key (@a) {
        $key = trim_all($key);
        next if (length($key) == 0);
        @arr = split(";",$key);
        foreach $key (@arr) {
            $key = trim_all($key);
            if (length($key)) {
                $key = path_u2d($key);
                $ald{$key} = 1;
            }
        }
    }
    @a = sort mycmp_nc_sort keys(%ald);
    $master_hash{$proj}->{libdirs} = [@a];
    if (@a) {
        prt("$proj: LibDirs: ".join(";",@a)."\n") if (VERB2());
    }
    ###pgm_exit(1,"");
}

sub fix_rel_path2($$) {
    my ($root,$rel) = @_;
    my $cd = cwd();
    my ($fp,$msg,$tmp);
    if (chdir($root)) {
        $fp = File::Spec->rel2abs($rel);    # we are IN the SLN directory, get ABSOLUTE from RELATIVE
        chdir($cd); # and get us back to where we were...
        $msg = "1:File::Spec:";
    } else {
        $fp = fix_rel_path3($root.$rel,'fix_rel_path2'); # else use internal service
        $msg = "2:fix_rel_path3:"
    }
    if (-f $fp) {
        $msg .= " ok";
    } else {
        $msg .= " NOT FOUND";
        if ($fp =~ /\\SimGear\.cs\\/) {
            $tmp = $fp;
            $tmp =~ s/\\SimGear\.cs\\/\\SimGear-cs\\/;
            if (-f $tmp) {
                $fp = $tmp;
                $msg = "ok $msg";
            }
        }
        if ($msg =~ /^1/) {
            $tmp = fix_rel_path3($root.$rel,'fix_rel_path2'); # else use internal service
            if (-f $tmp) {
                $fp = $tmp;
                $msg .= ", but OK with fix_rel_path3!!!";
            } else {
                $msg .= ", NOR from fix_rel_path3 [$tmp]"
            }
        }
    }
    prt("From: [$root] [$rel], got [$fp] $msg\n") if ($dbg_sl_14);
    return $fp; # hopefully, return ABSOLUTE path
}

# Read and store contents of SOLUTION (.sln) file
# 22/04/2008 - Extract DEPENDENCIES from solution file, and add to DSW output
# 24/11/2010 - Support for VC10 XML files
sub process_SLN_file2($) {
   my ($sln_fil_in) = shift;
   my ($cnt, $line, $vers, @arr, $mver, $par, $ff, $itmnum);
   my ($projname, $projfile, $projff, $gotproj, $relpath);
   my ($tnm,$tpth);
   my ($inproj, $tline, $projid, $inpdeps, $projdeps);
    my ($nmdeps, $depid, $pn, $fnd, $list);
    my ($msg,$text,$dspfile,$fdspfil,$name);
    my $fil = File::Spec->rel2abs($sln_fil_in);
   open IF, "<$fil" or mydie( "ERROR: Unable to open [$fil]... $! ...\n" );
   my @lines = <IF>;
   close IF;
   $cnt = scalar @lines;
    $tot_files++;
    $tot_lines += $cnt;
   ($g_name,$g_sln_path,$g_ext) = fileparse( $fil, qr/\.[^.]*/ ); # fileparse($fil); # get the NAME, and SOLUTION PATH (should be ABSOLUTE, NOT relative)
    my %hash = ();
    my %sln_projects = ();
    my %sln_projpath = ();
    my %sln_depends = ();
    my %sln_projids = ();
    my %missed_vcprojs = ();
   prt( "\nProcessing $cnt lines ... n=[$g_name] p=[$g_sln_path] ...\n" ) if (VERB2());
    if ($proj_title eq 'temp') {
        $proj_title = $g_name; # this seems a better choice
    }
   $projname = '';
   $projfile = '';
   $projff = '';
   $gotproj = 0;
   $inproj = 0;
   $inpdeps = 0;
   foreach $line (@lines) {
      $tline = trim_all($line);
      if ($line =~ /.+Format\s+Version\s+(\d+\.\d+)$/i) {
         $vers = $1;   # get n.nn version
         @arr = split(/\./,$vers);
         $mver = $arr[0];
         prt( "Is MSVC Version $mver ...\n" );
      } elsif ($line =~ /^Project\s*\(/) {
         # seek like 
            #Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ALL_BUILD", "ALL_BUILD.vcxproj", "{4BB0374F-3B6E-4EC8-9BE0-4BE8947B80E3}"
         #Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "abyss", "abyss.vcproj", "{8B384B8A-2B72-4DC4-8DF1-E3EF32F18850}"
            #Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fgadmin", "fgadmin\fgadmin.vcxproj", "{7004E589-7EA0-4AFD-B432-3D5E00B55049}"
            #   ProjectSection(ProjectDependencies) = postProject
            #      {22540CD3-D3CA-4C86-A773-80AEEE3ACDED} = {22540CD3-D3CA-4C86-A773-80AEEE3ACDED}
            #   EndProjectSection
            #EndProject
         prt( "[v9]: Got project [$tline] ...\n" ) if (VERB9);
         $inproj = 1;
         @arr = split( '=', $line );
         $cnt = scalar @arr;
         if ($cnt == 2) {
            $par = $arr[1]; # get 2nd part, like say '"abyss", "abyss.vcproj", "{8B384B8A-2B72-4DC4-8DF1-E3EF32F18850}"'
            @arr = split(',', $par);
            $cnt = scalar @arr;
            if ($cnt == 3) {
               $projname = strip_quotes(trim_all($arr[0])); # project NAME
               $projfile = strip_quotes(trim_all($arr[1])); # vcproj FILE
               $projid   = strip_quotes(trim_all($arr[2])); # project ID
               $projff   = fix_rel_path2($g_sln_path,$projfile); # return ABSOLUTE
               # if ((length($projname)) && (is_vcproj_ext($projfile)) && (-f $projff)) {
                    # 01/12/2010 - Remove need for the file to EXIST
               #if ((length($projname)) && (is_vcproj_ext($projfile)) ) {
               if ((length($projname)) && (is_vcproj_ext($projfile) || is_vcxproj_ext($projfile)) ) {
                        if (-f $projff) {
                            # and file
                        } else {
                            $missed_vcprojs{$projname} = $projff;
                        }
                  $gotproj = 1;
                  ($tnm,$tpth,$text) = fileparse($projff,qr/\.[^.]*/);
                        $fdspfil = $tpth.$tnm.".dsp";   # this is a DSP EQUIVALENT to the vcproj location
                        # BUT, we may have been given a DIFFERENT DSP output dir through
                        # -dsp=<dir> ($out_dsp_dir) and $g_had_dsp, and maybe '-fix-rel' ($fix_rel_paths)
                        #if ($g_had_dsp) {
                        #    $fdspfil = $out_dsp_dir;
                        #    $fdspfil .= "\\" if ( !($fdspfil =~ /(\\|\/)$/) );
                        #   $fdspfil .= $tnm.".dsp";
                        #}
                  $relpath = get_rel_dos_path($tpth, $g_sln_path);
                  ($tnm,$tpth,$text) = fileparse($projfile,qr/\.[^.]*/);
                        $dspfile = $tpth.$tnm.".dsp";
                  prt( "Got PROJECT name=$projname, file=[$projfile], ff=[$projff], rel=[$relpath].\n" ) if ($dbg_sl_01);
                  if (defined $sln_projects{$projname}) {
                     mydie( "A PROBLEM: Already GOT this project name $projname!!!\n" );
                  } else {
                     $sln_projects{$projname} = $projff;
                     # $sln_projpath{$projname} = $relpath; # can be BLANK, or say 'BvMath/'
                            #                           0         1       2        3        4
                     $sln_projpath{$projname} = [$projfile,$projff,$relpath,$dspfile,$fdspfil]; # relative project file, like '..\alut\path\alut.vcproj'
                     prt( "Stored \$sln_projpath{$projname} = [0:$projfile,1:$projff,2:$relpath,3:$dspfile,4:$fdspfil]\n") if ($dbg_sl_15);
                     $sln_projids{$projname}  = $projid;
                     $sln_depends{$projname}  = '';   # start dependencies, if any
                            if ($dbg_sl_16) {
                                my $msg = $projname;
                                $msg .= ' ' while (length($msg) < 24);
                                $msg .= $projid;
                                prt("$msg\n");
                            }
                  }
                        ### pgm_exit(1,"TEMP EXIT");
               } else {
                  $msg = "WARNING: ";
                  if (!length($projname)) {
                     $msg .= "Failed to get a project name! ";
                  } elsif ( !is_vcproj_ext($projfile) && !is_vcxproj_ext($projfile)) {
                     $msg .= "Name [$projfile] NOT a VCPROJ nor VCXPROJ name! ";
                  } else {
                     $msg .= "Unable to locate file [$projff]! ";
                  }
                  $msg .= " Line is (trimmed)\n$tline";
                        prtw("$msg\n");
               }
            } else {
               prtw( "Warning: Part 2 of Project line did NOT split into 3 on comma!???\n" );
            }
         } else {
            prtw( "Warning: Project line did NOT split in 2 on equal sign!???\n" );
         }

         # to switch on $tryharder requires additional work on parsing this line
         # =====================================================================
         prtw("WARNING: line [$line] ...\n") if (!$gotproj);
         # =====================================================================
      } elsif ($inproj) {
         # in the Project section - look for END of section, and DEPENDENCIES
         # ProjectSection(ProjectDependencies)
         if ($tline eq 'EndProject') {
         ###if ($line =~ /^EndProject\s*/)
            $inproj = 0;
         } else {
            if ($inpdeps) {
               if ($tline eq 'EndProjectSection' ) {
                  $inpdeps = 0;
               } else {
                  # collect dependencies
                  @arr = split( '=', $line );
                  $cnt = scalar @arr;
                  if ($cnt == 2) {
                     $arr[0] = trim_all($arr[0]);
                     $arr[1] = trim_all($arr[1]);
                     if ($arr[0] eq $arr[1]) {
                        $projdeps = $sln_depends{$projname};   # extract dependencies, if any
                        $projdeps .= '|' if (length($projdeps));
                        $projdeps .= $arr[0];
                        prt( "$pgmname: Proj $projname, dependant on $arr[0] ...\n" ) if ($dbg_sl_02);
                        ##prt( "Proj $projname, dependant on $projdeps ...\n" );
                        $sln_depends{$projname} = $projdeps;
                     } else {
                        prtw( "Warning: Found different IDS '$arr[0]' NE '$arr[1]'!!! \n" );
                     }
                  } else {
                     prtw( "Warning: Project DEPENDENCY line did NOT split in 2 on equal sign!???\n" );
                     prtw( "line=$line" );
                  }
               }
            } elsif ($line =~ /ProjectSection\s*\(\s*ProjectDependencies\s*\)/) {
               $inpdeps = 1;
            }
         }
      }
   }
   ### prt( "Done $fil ... got ".scalar @proj_files." project files ...\n" ) if (VERB9);
    $cnt = 0;
    my $cmcnt = 0;
   foreach $projname (keys %sln_projects) {
        if (($projname eq 'ALL_BUILD')||($projname eq 'INSTALL')||($projname eq 'ZERO_CHECK')) {
            $cmcnt++;
        } else {
            $cnt++;
        }
    }
   prt( "Done $fil ... of ".scalar keys(%sln_projects)." items got $cnt project file(s)...\n" ) if (VERB9());
   # resolve dependencies, if possible - warn if NOT ...
   #resolve_depends();
    # Have STORED
    # $sln_projects{$projname} = $projff;
   # $sln_projpath{$projname} = $relpath; # can be BLANK, or say 'BvMath/'
    #                           0         1       2        3        4
   #$sln_projpath{$projname} = [$projfile,$projff,$relpath,$dspfile,$fdspfil]; # relative project file, like '..\alut\path\alut.vcproj'
   #prt( "Stored \$sln_projpath{$projname} = [0:$projfile,1:$projff,2:$relpath,3:$dspfile,4:$fdspfil]\n") if ($dbg_sl_15);
   # $sln_projids{$projname}  = $projid;
   # $sln_depends{$projname}  = '';   # start dependencies, if any
   foreach $projname (keys %sln_projects) {
      $projdeps = $sln_depends{$projname};
      if (length($projdeps)) {
         # there is LENGTH, convert giant CID to simple project names
         @arr = split( /\|/, $projdeps );   # split em up
         $cnt = scalar @arr;   # get count of split
         #prt( "Proj $projname, depends on $cnt = $projdeps ...\n" );
         $nmdeps = '';   # build simple NAME set
         foreach $depid (@arr) {
                # find project MATCHING that ID, in full list of IDs
                $fnd = 0;
                $list = '';
            foreach $pn (keys %sln_projids) {
               if ($pn ne $projname) {
                  $projid = $sln_projids{$pn};
                        $list .= "|$projid";
                  if ($depid eq $projid) {
                     $nmdeps .= '|' if (length($nmdeps));
                     $nmdeps .= $pn;
                            $fnd = 1;
                     last;
                  }
               }
            }
                if (!$fnd) {
                    prtw("Warning: Failed to FIND [$depid], in list \n[$list]\n!");
                }
         }
         @arr = split( /\|/, $nmdeps );
         prt( "$pgmname: proj $projname, depends on $nmdeps ...\n" ) if ($dbg_sl_03);
         if ($cnt != scalar @arr) {   # YEEK - Does NOT match - OH WELL
            prtw( "WARNING: proj [$projname] with depends [$projdeps] Failed to get SAME count $cnt - got ".scalar @arr." on split [$nmdeps]\n" );
                pgm_exit(1,"");
         }
         $sln_depends{$projname} = $nmdeps;
      }
   }
    # ====================================================================
    $hash{'SOLUTION'} = $fil;   # keep the SOLUTION files also
    $hash{'PROJECTS'} = { %sln_projects };
    $hash{'PROJPATH'} = { %sln_projpath };  # array refs [$projfile,$projff,$relpath]
    $hash{'DEPENDS'}  = { %sln_depends  };
    $hash{'PROJIDS'}  = { %sln_projids };
    $hash{'MISSED_FILES'} = { %missed_vcprojs }; # not found on DISK
    return \%hash;
}


sub process_in_file($) {
    my ($inf) = @_;
    my ($file);
    my ($proj,$d,$e) = fileparse($inf, qr/\.[^.]*/ );
    if (is_sln_ext($inf)) {
        my $rh = process_SLN_file2($inf);
        if (defined ${$rh}{'PROJECTS'}) {
            my $rph = ${$rh}{'PROJECTS'};
            my @arr = sort keys(%{$rph});
            my $cnt = 0;
            my $totcnt = scalar @arr;
            foreach $proj (@arr) {
                if ( !(($proj eq 'ALL_BUILD')||($proj eq 'INSTALL')||($proj eq 'ZERO_CHECK')) ) {
                    $cnt++;
                }
            }
            prt("Of $totcnt items found $cnt project(s) in $inf\n");
            $cnt = 0;
            foreach $proj (@arr) {
                $file = ${$rph}{$proj};
                $cnt++;
                prt("\nProject:$cnt: $proj, File: $file\n") if (VERB9());
                process_xml_file($file,$proj,$cnt);
                ### $load_log = 2;
            }
        } else {
            prt(Dumper($rh));
        }
    } elsif (is_vcxproj_ext($inf)) {
        prt("\nProject: $proj, File: $inf\n"); # if (VERB9());
        process_xml_file($inf,$proj,1);
    } else {
        prt("Can ONLY handle .sln or .vcxproj file, not [$e]! FIX ME!!!\n");
    }
}

sub process_in_file_simp($) {
    my ($inf) = @_;
    if (! open INF, "<$inf") {
        pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); 
    }
    my @lines = <INF>;
    close INF;
    my $lncnt = scalar @lines;
    prt("Processing $lncnt lines, from [$inf]...\n");
    my ($line,$inc,$lnn);
    $lnn = 0;
    foreach $line (@lines) {
        chomp $line;
        $lnn++;
        if ($line =~ /\s*#\s*include\s+(.+)$/) {
            $inc = $1;
            prt("$lnn: $inc\n");
        }
    }
}

sub src_matching_proj($$$) {
    my ($proj,$ra,$rsrc) = @_;
    my ($src,$n,$d,$e);
    foreach $src (@{$ra}) {
        ($n,$d,$e) = fileparse($src, qr/\.[^.]*/ );
        if ($n eq $proj) {
            ${$rsrc} = $src;
            return 1;
        }
    }
    return 0;
}


sub show_ref_hash($$$$) {
    my ($proj,$num,$typ,$rph) = @_;
    my ($ra,$cnt,$out,$src,$rh,$cnt2,$cnt3,$ri);
    my $inf = ${$rph}{'inputfile'};
    my $target_incs = '';
    my $cmake = "\n";
    $cmake .= "# from $inf\n";
    prt("\n") if (VERB1());
    prt("$proj:$num: AppType: $typ, from $inf\n");
    #$master_hash{$proj}->{sources} = [@a];
    $ra = ${$rph}{'sources'};
    $cnt = scalar @{$ra};
    if (VERB2()) {
        prt("$proj:$num: Sources:\n".join("\n",@{$ra})."\n");
    } elsif (VERB1()) {
        prt("$proj:$num: Sources: ".join(" ",@{$ra})."\n");
    }
    $cnt2 = 0;
    if (defined ${$rph}{'headers'}) {
        $rh = ${$rph}{'headers'};
        $cnt2 = scalar @{$rh};
        if (VERB2()) {
            prt("$proj:$num: Headers:\n".join("\n",@{$rh})."\n");
        } elsif (VERB1()) {
            prt("$proj:$num: Headers: ".join(" ",@{$rh})."\n");
        }
    } elsif (VERB2()) {
        prt("$proj:$num: Headers: none\n");
    }

    # aid: 'AdditionalIncludeDirectories'
    #$master_hash{$proj}->{addincs} = [@a];
    $ri = ${$rph}{'addincs'};
    $cnt3 = scalar @{$ri};
    if ($cnt3) {
        # $target_incs = join(" ",@{$ri});
        # $target_incs = path_d2u($target_incs);
        # target_include_directories( ${name} PRIVATE $<BUILD_INTERFACE:ext/optparse> )
        foreach $src (@{$ri}) {
            $src = path_d2u($src);
            $target_incs .= "\n    <BUILD_INTERFACE:$src>";
        }
        if (VERB2()) {
            prt("$proj:$num: AddIncs:\n".join("\n",@{$ri})."\n");
        } elsif (VERB1()) {
            prt("$proj:$num: AddIncs: ".join(";",@{$ri})."\n");
        }
    }

    if ($cnt) {
        my $ind = '   ';
        if (!src_matching_proj($proj,$ra,\$src)) {
            $src = ${$ra}[0]; # NO same named src - just use first
        }
        my ($n,$d) = fileparse($src);
        my $dir = path_d2u($d);
        $dir =~ s/\/$//;    #strip trailing path sep.
        my $opt = "BUILD_".uc($proj);
        $opt =~ s/-/_/g;
        if ($add_options) {
            $cmake .= "if ($opt)\n";
            $opt_list .= "option( $opt \"Set OFF to not build this component\" ON )\n";
        }
        $cmake .= "set(name $proj)\n";
        $cmake .= "set(dir $dir)\n";    # check me
      $include_dirs{$dir} = 1;
        $cmake .= "set( \$\{name\}_SRCS\n";
        foreach $src (@{$ra}) {
            $src = path_d2u($src);
            ($n,$d) = fileparse($src);
            $d =~ s/\/$//;
            if ($d eq $dir) {
                $cmake .= $ind."\$\{dir\}/$n\n";
            } else {
                $cmake .= $ind."$src\n";
            }
        }
        $cmake .= "$ind)\n";
        if ($cnt2) {
            $cmake .= "set( \$\{name\}_HDRS\n";
            foreach $src (@{$rh}) {
                $src = path_d2u($src);
                ($n,$d) = fileparse($src);
                $d =~ s/\/$//;
                if ($d eq $dir) {
                    $cmake .= $ind."\$\{dir\}/$n\n";
                } else {
                    $cmake .= $ind."$src\n";
                }
            }
            $cmake .= "$ind)\n";
        }
        if ($typ =~ /Library/i) {
            $out = \$libcmake;
            if ($cnt2) {
                $cmake .= "add_library( \$\{name\} \$\{LIB_TYPE\} \$\{\$\{name\}_SRCS\} \$\{\$\{name\}_HDRS\} )\n";
            } else {
                $cmake .= "add_library( \$\{name\} \$\{LIB_TYPE\} \$\{\$\{name\}_SRCS\} )\n";
            }
            if ($cnt3) { # aid: # 'AdditionalIncludeDirectories'
                $cmake .= "target_include_directories( \$\{name\} PRIVATE $target_incs\n    )\n";
            }
            $cmake .= "list(APPEND add_LIBS \$\{name\})\n";
            $cmake .= "# deal with install, if any...\n"; 
            $cmake .= "#install( TARGETS \$\{name\}\n";
            $cmake .= "#".$ind."RUNTIME DESTINATION bin\n";
            $cmake .= "#".$ind."LIBRARY DESTINATION lib\n";
            $cmake .= "#".$ind."ARCHIVE DESTINATION lib )\n";
            $cmake .= "#install(FILES \$\{\$\{name\}_HDRS\} DESTINATION include)\n";
        } else {
            $out = \$execmake;
            if ($cnt2) {
                $cmake .= "add_executable( \$\{name\} \$\{\$\{name\}_SRCS\} \$\{\$\{name\}_HDRS\} )\n";
            } else {
                $cmake .= "add_executable( \$\{name\} \$\{\$\{name\}_SRCS\})\n";
            }
            if ($cnt3) { # aid: # 'AdditionalIncludeDirectories'
                $cmake .= "target_include_directories( \$\{name\} PRIVATE $target_incs)\n";
            }
            $cmake .= "if(add_LIBS)\n";
            $cmake .= "$ind target_link_libraries( \$\{name\} \${add_LIBS} )\n";
            $cmake .= "endif ()\n";
            $cmake .= "if (MSVC)\n";
            $cmake .= "$ind set_target_properties( \$\{name\} PROPERTIES DEBUG_POSTFIX d )\n";
            $cmake .= "endif ()\n";
            $cmake .= "#install( TARGETS \$\{name\} DESTINATION bin )\n";
        }
        if ($add_options) {
            $cmake .= "endif ($opt)\n";
        }
        $cmake .= "\n";
        ${$out} .= $cmake;
    }
    # $master_hash{$proj}->{preprocs} = [@a];
    $ra = ${$rph}{'preprocs'};
    prt("$proj:$num: PreProcs: ".join(";",@{$ra})."\n") if (VERB5());
    #$master_hash{$proj}->{libdeps} = [@a];
    $ra = ${$rph}{'libdeps'};
    #prt("$proj: LibDeps: ".join(" ",@{$ra})."\n");  # if (VERB5());
    #$master_hash{$proj}->{libdirs} = [@a];
    $ra = ${$rph}{'libdirs'};
    #prt("$proj: LibDirs: ".join(";",@{$ra})."\n");  # if (VERB5());

}



sub show_master_hash($) {
    my $rh = shift;
    # ====================================================================
    # A CONSOLE APP SHOWS: AppType: Application;Console
    # A WINDOWS APP SHOWS: AppType: Application;Windows
    # A SHARED  DLL SHOWS: AppType: DynamicLibrary;Windows
    # A STATIC  LIB SHOWS: AppType: StaticLibrary;
    #$master_hash{$proj}->{apptype} = $config;$subsystem;
    my @arr = sort mycmp_nc_sort keys(%{$rh});
    my $cnt = scalar @arr;
    my ($proj,$rph,$typ,$ra);
    prt("\nshow_master_hash: $cnt projects, from '$in_file'...\n");
    # static libs first
    my $num = 0;
    foreach $proj (@arr) {
        $rph = ${$rh}{$proj};
        $typ = ${$rph}{'apptype'};
        if ($typ =~ /Library/) {
            $num++;
            $tot_libs++;
            show_ref_hash($proj,$num,$typ,$rph);
        }
    }
    # show other than static libs
    foreach $proj (@arr) {
        $rph = ${$rh}{$proj};
        $typ = ${$rph}{'apptype'};
        if ( !($typ =~ /Library/) ) {
            $num++;
            $tot_exes++;
            show_ref_hash($proj,$num,$typ,$rph);
        }
    }
}


#########################################
### MAIN ###
parse_args(@ARGV);
process_in_file($in_file);
show_master_hash(\%master_hash);
out_cmake_list();
pgm_exit(0,"");
########################################

sub need_arg {
    my ($arg,@av) = @_;
    pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av);
}

sub parse_args {
    my (@av) = @_;
    my ($arg,$sarg,@arr,$len,$tmp);
    while (@av) {
        $arg = $av[0];
        if ($arg =~ /^-/) {
            $sarg = substr($arg,1);
            $sarg = substr($sarg,1) while ($sarg =~ /^-/);
            if (($sarg =~ /^h/i)||($sarg eq '?')) {
                give_help();
                pgm_exit(0,"Help exit(0)");
            } elsif ($sarg =~ /^v/) {
                if ($sarg =~ /^v.*(\d+)$/) {
                    $verbosity = $1;
                } else {
                    while ($sarg =~ /^v/) {
                        $verbosity++;
                        $sarg = substr($sarg,1);
                    }
                }
                prt("Verbosity = $verbosity\n") if (VERB1());
            } elsif ($sarg =~ /^l/) {
                if ($sarg =~ /^ll/) {
                    $load_log = 2;
                } else {
                    $load_log = 1;
                }
                prt("Set to load log at end. ($load_log)\n") if (VERB1());
            } elsif ($sarg =~ /^o/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $out_file = $sarg;
                prt("Set out file to [$out_file].\n") if (VERB1());
            } elsif ($sarg =~ /^p/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $proj_title = $sarg;
                prt("Set out project title to [$proj_title].\n") if (VERB1());
            } elsif ($sarg =~ /^r/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $rel_dir = File::Spec->rel2abs($sarg);
                if (-d $rel_dir) {
                    prt("Set relative directory to [$rel_dir].\n") if (VERB1());
                } else {
                    pgm_exit(1,"ERROR: Rel directory does NOT exist [$rel_dir]! [$sarg]\n");
                }
            } elsif ($sarg =~ /^V/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                @arr = split(/\./,$sarg);
                $len = scalar @arr;
                if ($len < 3) {
                    pgm_exit(1,"ERROR: Invalid version [$sarg]! Did not split in 3 on '.' - got $len?\n");
                }
                $ver_maj = $arr[0];
                $ver_min = $arr[1];
                $ver_pt = $arr[2];
                if ($len > 3) {
                    $ver_rc = $arr[3];
                }
                $ver_msg = "* check me *";
                prt("Set version to '$ver_maj.$ver_min.$ver_pt\n") if (VERB1());
            } elsif ($sarg =~ /^A/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                @arr = split(";",$sarg);
                $len = 0;
                foreach $tmp (@arr) {
                    push(@add_inc_dirs,$tmp);
                    $len++;
                }
                prt("Added $len include directories, to cmake.\n") if (VERB1());
            } elsif ($sarg =~ /^O/) {
                $add_options = 1;
                prt("Set to add options around each component.\n") if (VERB1());
            } elsif ($sarg =~ /^S/) {
                $add_static_runtime = 0;
                prt("Turned OFF the add static runtime option.\n") if (VERB1());
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            if (length($in_file) ==  0) {
                $in_file = $arg;
                prt("Set input file to [$in_file]\n") if (VERB1());
            } else {
                pgm_exit(1,"ERROR: Already have an in file '$in_file'! What is this [$arg]!\n");
            }
        }
        shift @av;
    }

    if ($debug_on) {
        prtw("WARNING: DEBUG is ON!\n");
        if ((length($in_file) ==  0) && $debug_on) {
            $in_file = $def_file;
            prt("Set DEFAULT input to [$in_file]\n");
            $load_log = 2;
        }
    }
    if (length($in_file) ==  0) {
        pgm_exit(1,"ERROR: No input files found in command!\n");
    }
    if (! -f $in_file) {
        pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n");
    }
}

sub give_help {
    prt("$pgmname: version $VERS\n");
    prt("Usage: $pgmname [options] in-file\n");
    prt("Options:\n");
    prt(" --help      (-h or -?) = This help, and exit 0.\n");
    prt(" --verb[n]         (-v) = Bump [or set] verbosity. def=$verbosity\n");
    prt(" --load            (-l) = Load LOG at end. ($outfile)\n");
    prt(" --rel <dir>       (-r) = Output sources relative to this directory.\n");
    prt(" --out <file>      (-o) = Write cmake output to this file.\n");
    prt(" --proj <name>     (-p) = Set the project name. (def=$proj_title)\n");
    prt(" --VERS <ver>      (-V) = Give version in dot.sep.form, maj.min.pts, like 1.2.3, to use in CMakeLists.txt.\n");
    prt(" --ADD <dir[;dir]> (-A) = Add these include directories, semi-colon sep, to cmake.\n");
    prt(" --OPTIONS         (-O) = Add an 'option' like if (BUILD_<name>) around each component.\n");
    prt(" --STATIC          (-S) = Do NOT add the static runtime option. (def=$add_static_runtime)\n");
    prt("\n");
    prt(" Accept an input solution file, or a single <proj>.vcxproj, and process it,\n");
    prt(" extracting separate projects, and their sources, and write a CMakeLists.txt\n");
    prt(" to build the project(s).\n");


}

# eof - showsln.pl

index -|- top

checked by tidy  Valid HTML 4.01 Transitional