#!/usr/bin/perl
#< lib_cmake.pl - 20120418 - Take a project hash, and write a CMakeLists.txt file
# 11/07/2013 - Avoid duplicate component names
# 27/06/2013 - Better grouping in cmake gen - remove double newlines - in lib_cmake.pl
# 29/04/2012 - Moved CMake READ to its OWN library
# 28/04/2012 - begin adding CMake READING
# 23/04/2012 - starting to look SOLID ;=))
use strict;
use warnings;
my $os = $^O;
my $PATH_SEP = '/';
if ($os =~ /win/i) {
    $PATH_SEP = "\\";
}

my @my_cmake_proj_hashes = ();

our ($RLO_MSG,$RLO_PRJ,$RLO_VAL,$RLO_NAM,$RLO_EXC);

my $add_exe_install = 1;
my $add_exe_postfix = "d";
my $add_lib_install = 1;
my $use_single_inc_list = 1;    # 18/05/2012 put back to a SINGLE list
my $add_target_msg = 0; # add diagnostic message output
my $max_set_line_len = 70;
my $def_to_shared = 0;
my $add_proj_bin_dir = 0; # This worked for SOME, but not all - need to locate header, and put relative path
my $use_just_file_name = 1;
my $project_version = '';

sub get_cmake_proj_hash_ref() { return \@my_cmake_proj_hashes; }
sub set_cmake_exe_install($) { $add_exe_install = shift; }
sub set_cmake_exe_postfix($) { $add_exe_postfix = shift; }
sub set_cmake_lib_install($) { $add_lib_install = shift; }
sub set_cmake_def_library($) { $def_to_shared = shift; }
sub set_cmake_add_bin_dir($) { $add_proj_bin_dir = shift; }
sub set_project_version($)   { $project_version = shift; }

sub set_rpath_per_os($) {
    my $rff = shift;
    my $ff = ${$rff};
    $ff = ($os =~ /win/i) ? path_u2d($ff) : path_d2u($ff);
    ${$rff} = $ff;
}

my $max_output_line = 95;
sub set_max_output_line($) { $max_output_line = shift; }
sub max_output_line($) {
    my $line = shift;
    my $len = length($line);
    if ($len > $max_output_line) {
        my $hlen = ($max_output_line - 3) / 2;
        $line = substr($line,0,$hlen)."...".substr($line,($len-$hlen));
    }
    return $line;
}


# my @keys_used = qw(PROJECT_ROOT PROJECT_CFGS PROJECT_NAME PROJECT_APTP PROJECT_SRCS PROJECT_AM_FILE);
sub test_ref_hash($$$$$$$) {
    my ($rh,$rpr,$rcfg,$rpn,$rpt,$rps,$ram) = @_;
    my ($tmp,$cnt);
    my $key = 'PROJECT_ROOT';
    if (defined ${$rh}{$key}) {
        ${$rpr} = ${$rh}{$key};
    } else {
        prt("CMAKE:ERROR:1: $key not set in HASH!\n");
        return 1;
    }
    $key = 'PROJECT_CFGS';
    if (defined ${$rh}{$key}) {
        $tmp = ${$rh}{$key};
        $cnt = scalar @{$tmp};
        if ($cnt > 0) {
            ${$rcfg} = $tmp;
        } else {
            prt("CMAKE:ERROR:2: $key is set in HASH, but ZERO cfgs!\n");
            return 1;
        }
    } else {
        prt("CMAKE:ERROR:2: $key not set in HASH!\n");
        return 1;
    }
    $key = 'PROJECT_NAME';
    if (defined ${$rh}{$key}) {
        ${$rpn} = ${$rh}{$key};
    } else {
        prt("CMAKE:ERROR:3: $key not set in HASH!\n");
        return 1;
    }
    #$key = 'PROJECT_TYPE';
    $key = 'PROJECT_APTP';
    if (defined ${$rh}{$key}) {
        $tmp = ${$rh}{$key};
        if ($tmp && (length($tmp) > 0)) {
            ${$rpt} = $tmp;
        } else {
            prt("CMAKE:ERROR:4: $key set in HASH, but NO LENGTH!\n");
            return 1;
        }
    } else {
        prt("CMAKE:ERROR:4: $key not set in HASH!\n");
        return 1;
    }
    $key = 'PROJECT_SRCS';
    if (defined ${$rh}{$key}) {
        $tmp = ${$rh}{$key}; # = [@vc_c_sources] or [@dsp_sources];
        $cnt = scalar @{$tmp};
        if ($cnt > 0) {
            ${$rps} = $tmp;
        } else {
            prt("CMAKE:ERROR:5: $key is set in HASH, but ZERO sources!\n");
            return 1;
        }
    } else {
        prt("CMAKE:ERROR:5: $key not set in HASH!\n");
        return 1;
    }
    $key = 'PROJECT_AM_FILE';
    if (defined ${$rh}{$key}) {
        $tmp = ${$rh}{$key};
        $cnt = length($tmp);
        if ($cnt > 0) {
            ${$ram} = $tmp;
        } else {
            prt("CMAKE:ERROR:6: $key is set in HASH, but ZERO length!\n");
            return 1;
        }
    } else {
        prt("CMAKE:ERROR:6: $key not set in HASH!\n");
        return 1;
    }
    ###$key = 'CURR_AUTO_ON_FLAG';
    ###if (defined ${$rh}{$key}) {
    ###    $tmp = ${$rh}{$key};
    ###} else {
    ###    prt("CMAKE:ERROR:7: $key not set in HASH!\n");
    ###    return 1;
    ###}

    return 0;
}

sub do_hash_cmake_test($) {
    my $rh = shift;
    my ($proot,$rcfgs,$pname,$ptype,$psrcs,$amfile,$ao);
    return 1 if (test_ref_hash($rh,\$proot,\$rcfgs,\$pname,\$ptype,\$psrcs,\$amfile));
    return 0;   # success
}

sub get_gui_message_txt() {
    my $txt = <<EOF;

if(UNIX)
  if(APPLE)
    set(GUI "Cocoa")
  else(APPLE)
    set(GUI "X11")
  endif(APPLE)
else(UNIX)
  if(WIN32)
    set(GUI "Win32")
  else(WIN32)
    set(GUI "Unknown")
  endif(WIN32)
endif(UNIX)
message("*** GUI system is \${GUI} ***")

EOF
    return $txt;
}

sub get_definitions_block {
    my $txt = <<EOF;
if(CMAKE_COMPILER_IS_GNUCXX)
    set( WARNING_FLAGS -Wall )
endif(CMAKE_COMPILER_IS_GNUCXX)

if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 
   set( WARNING_FLAGS "-Wall -Wno-overloaded-virtual" )
endif() 

if(WIN32 AND MSVC)
    # turn off various warnings
    set(WARNING_FLAGS "\${WARNING_FLAGS} /wd4996")
    # foreach(warning 4244 4251 4267 4275 4290 4786 4305)
    #     set(WARNING_FLAGS "\${WARNING_FLAGS} /wd\${warning}")
    # endforeach(warning)

    set( MSVC_FLAGS "-DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -D__CRT_NONSTDC_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 lib
    set( CMAKE_DEBUG_POSTFIX "d" )
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}" )

# add_definitions( -DHAVE_CONFIG_H )

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

EOF
    return $txt;
}

my %defines_added = (
    'NOMINMAX' => 1,
    '_USE_MATH_DEFINES' => 2,
    '_CRT_SECURE_NO_WARNINGS' => 3,
    '_SCL_SECURE_NO_WARNINGS' => 4,
    '__CRT_NONSTDC_NO_WARNINGS' => 5,
    'HAVE_CONIFG_H' => 6
    );


sub get_last_directory($) {
    my $dir = shift;
    $dir = path_u2d($dir);
    $dir =~ s/\\$//;
    $dir =~ s/^\\//;
    my @arr = split(/\\/,$dir);
    return $arr[-1];
}

sub is_in_depends($$) {
    my ($lib,$rpda) = @_;
    my ($tst);
    foreach $tst (@{$rpda}) {
        return 1 if ($tst eq $lib);
        # if windows
        return 1 if (lc($tst) eq lc($lib));
        if ($lib =~ /d$/i) {
            $lib =~ s/d$//i;
            return 1 if ($tst eq $lib);
            # if windows
            return 1 if (lc($tst) eq lc($lib));
        }
    }
    return 0;
}

# $tmp = path_d2u($tmp);
# # $cmake .= "FIND_LIBRARY( GETOPT_LIBRARY NAMES $val PATHS $tmp )\n";
# # $cmake .= "TARGET_LINK_LIBRARIES( $pname \${GETOPT_LIBRARY} )\n";
# $cmake .= "FIND_LIBRARY( GETOPT_DEBUG_LIBRARY NAMES $val2 PATHS $tmp )\n";
# $cmake .= "FIND_LIBRARY( GETOPT_RELEASE_LIBRARY NAMES $val PATHS $tmp )\n";
# $cmake .= "TARGET_LINK_LIBRARIES( $pname debug \${GETOPT_DEBUG_LIBRARY} optimized \${GETOPT_RELEASE_LIBRARY} )\n";
# CMake Warning (dev) at tools/CMakeLists.txt:132 (TARGET_LINK_LIBRARIES):
#  Link library type specifier "debug" is followed by specifier "optimized"
#  instead of a library name.  The first specifier will be ignored.
# This warning is for project developers.  Use -Wno-dev to suppress it.
# It appears if need to find more than ONE library this needs to be done SEPARATELY
# BUT could NOT get that RIGHT exactly, so a third try
# could MAYBE add
# INSTALL_RPATH_USE_LINK_PATH Add paths to linker search and installed rpath.
# INSTALL_RPATH_USE_LINK_PATH is a boolean that if set to true will append directories 
# in the linker search path and outside the project to the INSTALL_RPATH. 

# also LINK_DIRECTORIES() like -
# LINK_DIRECTORIES(C:/external/lib)
# ADD_EXECUTABLE(Main main.cpp)
# but then I read
# The best way to do this is to not use LINK_DIRECTORIES.   Instead use 
# target_link_libraries, and give the FULL path to the library you want to 
# link to.  CMake should then do the right thing.
my $temp_count = 0;
my %find_rlibs = ();
my %find_dlibs = ();
sub get_cmake_lib_finds($) {
    my ($rp) = @_;
    my $pnm = ${$rp}{'PROJECT_NAME'};
    my $ptyp = ${$rp}{'PROJECT_TYPE'};
    my $rpda = ${$rp}{'PROJECT_DEPENDS'};
    my $inst = ${$rp}{'PROJECT_INST'};  # install indication like noinst_LIBRARIES, sbin_PROGRAMS
    my $rels = get_proj_libs_rel($rp);
    my $dbgs = get_proj_libs_dbg($rp);
    if (VERB9()) {
        prt("[v9] For project [$pnm] [$ptyp]\n");
        prt("Release libs [$rels]\n");
        prt("Debug   libs [$dbgs]\n");
    }
    my ($itm,$lcitm,@arr,$i);
    my %dpaths = ();
    my %dnames = ();
    my %rpaths = ();
    my %rnames = ();
    my %duperel = ();
    my %dupedbg = ();
    @arr = space_split($rels);
    foreach $itm (@arr) {
        $itm = trim_all($itm);
        next if (length($itm) == 0);
        $lcitm = lc($itm);
        next if (defined $duperel{$lcitm});
        $duperel{$lcitm} = 1;
        if ($itm =~ /^\/libpath:/i) {
            $itm = strip_quotes(substr($itm,9));
            set_rpath_per_os(\$itm);
            $rpaths{$itm} = 1;
        ###} elsif (is_win_library($itm)) {
            # what to do about these try nothing
        } else {
            my ($n,$d,$e) = fileparse($itm, qr/\.[^.]*/);
            if (!is_in_depends($n,$rpda)) {
                $rnames{$itm} = 1;
            }
        }
    }
    @arr = space_split($dbgs);
    foreach $itm (@arr) {
        $itm = trim_all($itm);
        next if (length($itm) == 0);
        $lcitm = lc($itm);
        next if (defined $dupedbg{$lcitm});
        $dupedbg{$lcitm} = 1;
        if ($itm =~ /^\/libpath:/i) {
            $itm = strip_quotes(substr($itm,9));
            $dpaths{$itm} = 1;
        ###} elsif (is_win_library($itm)) {
        ###    # what about these??? tyr do nothing
        } else {
            my ($n,$d,$e) = fileparse($itm, qr/\.[^.]*/);
            if (!is_in_depends($n,$rpda)) {
                $dnames{$itm} = 1;
            }
        }
    }

    # check counts
    my @rarr = sort keys(%rnames);
    my @darr = sort keys(%dnames);
    my $rcnt = scalar @rarr;
    my $dcnt = scalar @darr;
    if (($rcnt == 0)&&($dcnt == 0)) {
        return '';  # nothing to add
    }
    if (($rcnt == 0)&& $dcnt) {
        prtw("WARNING:$pnm: Have no REL libraries but $dcnt DBG!!! R:[$rels] D:[$dbgs]\n");
        return '';
    }
    if ($rcnt && ($dcnt == 0)) {
        prtw("WARNING:$pnm: Have no DBG libraries but $rcnt REL!!! R:[$rels] D:[$dbgs]\n");
        return '';
    }
    if ($rcnt != $dcnt) {
        prtw("WARNING:$pnm: Have $rcnt REL libraries but $dcnt DBG!!! R:[$rels] D:[$dbgs]\n");
        return '';
    }

    my $cmake = '';
    my $dvar = uc($pnm)."_DEBUG_LIBRARY";
    my $rvar = uc($pnm)."_RELEASE_LIBRARY";
    my ($rlib,$dlib);
    # $rcnt and $dcnt are the SAME so...
    if ($rcnt == 1) {
        $i = 0;
        $rlib = $rarr[$i];
        $dlib = $darr[$i];
        if (defined $find_rlibs{$rlib}) {
            $rvar = $find_rlibs{$rlib};
        } else {
            $find_rlibs{$rlib} = $rvar; # save for next if any
            $cmake .= "find_library( $rvar $rlib ";
            @arr = keys(%rpaths);
            if (@arr) {
                $cmake .= "PATHS ";
                foreach $itm (@arr) {
                    ### set_rpath_per_os(\$itm);
                    $itm = path_d2u($itm);  # cmake LIKES unix paths, ;=)), else must ESCAPE the '\', like "\\"
                    $itm = '"'.$itm.'"' if ($itm =~ /\s/);  # add QUOTES only if path contains a SPACE
                    $cmake .= "$itm ";
                }
            }
            $cmake .= ")\n";
        }
        # Debug library processing
        if (defined $find_dlibs{$dlib}) {
            $dvar = $find_dlibs{$dlib};
        } else {
            $find_dlibs{$dlib} = $dvar;
            $cmake .= "find_library( $dvar $dlib ";
            @arr = keys(%dpaths);
            if (@arr) {
                $cmake .= "PATHS ";
                foreach $itm (@arr) {
                    $itm = path_d2u($itm);  # cmake LIKES unix paths, ;=)), else must ESCAPE the '\', like "\\"
                    $itm = '"'.$itm.'"' if ($itm =~ /\s/);  # add QUOTES only if path contains a SPACE
                    $cmake .= "$itm ";
                }
            }
            $cmake .= ")\n";
        }
        $cmake .= "message( \"Proj $pnm, found debug \${".$dvar."} optimized \${".$rvar."} libraries.\" )\n"
            if (VERB9() || $add_target_msg);
        $cmake .= "target_link_libraries( $pnm debug \${".$dvar."} optimized \${".$rvar."} )\n\n";
    } else {
        my ($tdvar,$trvar);
        for ($i = 0; $i < $rcnt; $i++) {
            # Release library processing (to a 'temp' var)
            $temp_count++;  # cmake REFUSES to refind something, so MUST change the name each time !!!
            $tdvar = "TEMP".$temp_count."_DEBUG_LIBRARY";
            $trvar = "TEMP".$temp_count."_RELEASE_LIBRARY";
            $rlib = $rarr[$i];
            $dlib = $darr[$i];
            if (defined $find_rlibs{$rlib}) {
                $trvar = $find_rlibs{$rlib};
            } else {
                $find_rlibs{$rlib} = $trvar;
                $cmake .= "\nfind_library( $trvar $rlib ";
                @arr = keys(%rpaths);
                if (@arr) {
                    $cmake .= "PATHS ";
                    foreach $itm (@arr) {
                        $itm = path_d2u($itm);  # cmake LIKES unix paths, ;=)), else must ESCAPE the '\', like "\\"
                        $itm = '"'.$itm.'"' if ($itm =~ /\s/);  # add QUOTES only if path contains a SPACE
                        $cmake .= "$itm ";
                    }
                }
                $cmake .= ")\n";
            }
            # Debug library processing (to a 'temp' var)
            if (defined $find_dlibs{$dlib}) {
                $tdvar = $find_dlibs{$dlib};
            } else {
                $find_dlibs{$dlib} = $tdvar;
                $cmake .= "find_library( $tdvar $dlib ";
                @arr = keys(%dpaths);
                if (@arr) {
                    $cmake .= "PATHS ";
                    foreach $itm (@arr) {
                        $itm = path_d2u($itm);  # cmake LIKES unix paths, ;=)), else must ESCAPE the '\', like "\\"
                        $itm = '"'.$itm.'"' if ($itm =~ /\s/);  # add QUOTES only if path contains a SPACE
                        $cmake .= "$itm ";
                    }
                }
                $cmake .= ")\n";
            }
            $cmake .= "message( \"Proj $pnm, found debug \${".$tdvar."} optimized \${".$trvar."} libraries.\" )\n"
                if (VERB9() || $add_target_msg);
            $cmake .= "set( $rvar \${$rvar} \${$trvar} )\n";
            $cmake .= "set( $dvar \${$dvar} \${$tdvar} )\n";
        }
        $cmake .= "\ntarget_link_libraries( $pnm\n";
        $cmake .= "   debug \${".$dvar."}\n";
        $cmake .= "   optimized \${".$rvar."} )\n\n";
    }
    return $cmake;
}


sub debug_enum_ref_proj_hash($) {
    my ($rparams) = @_;
    my $rex = ${$rparams}{'AM_EXCLUDED_DIRS'}; # get stored EXCLUDED directory HASH (if any!)
    my $rph = ${$rparams}{'REF_PROJECTS_HASH'};
    my $rlib_lists = ${$rparams}{'REF_LIB_LISTS'};  # make list of LIBRARIES written
    my %depends = ();
    my $cnt = scalar keys(%{$rph});
    my ($key,$rp,$val,$pnm,$ptype,$msg,$isexcl,$rpda,$nm2,$tmp,$inst);
    my ($rhash,$am_file);
    $cnt = 0;
    foreach $key (keys %{$rph}) {
        $rp = ${$rph}{$key};
        $val = ${$rp}{'PROJECT_NAME'};
        $pnm = $val;
        $ptype = ${$rp}{'PROJECT_TYPE'};
        $inst  = ${$rp}{'PROJECT_INST'};
        $rhash = ${$rp}{'PROJECT_AM_RHASH'}; # get PROJECT hash
        $am_file = ${$rhash}{':_AM_FILE_SRC_:'}; # get AM file name
        $msg = get_EXCLUDE_msg($rparams,$rp,$rex);
        $isexcl = ($msg =~ /EXCLUDE/) ? 1 : 0;
        $msg = '[';
        if (defined ${$rp}{'PROJECT_DEPENDS'}) {
            $rpda = ${$rp}{'PROJECT_DEPENDS'};
            # $msg .= ' with deps [';
            # CHECK if this is NOT EXCLUDED
            foreach $nm2 (@{$rpda}) {
                $msg .= "$nm2 ";
                if (defined ${$rlib_lists}{$nm2}) {
                    $tmp = ${$rlib_lists}{$nm2};
                    if (${$tmp}[$RLO_MSG] =~ /EXCLUDE/) {
                        prtw("WARNING: Dependent name [$nm2] is EXCLUDED!\n");
                    }
                    ${$tmp}[$RLO_VAL] = 1;
                    ${$rlib_lists}{$nm2} = $tmp;
                } else {
                    prtw("WARNING: This name [$nm2] NOT in LIBRARY LIST!\n");
                }
                # now, joined, done just before this, can ADD to excluded, so...
                # if ( is_project_all_excluded($nm2) )
                if ( is_dependency_excluded($rparams,$pnm,$isexcl,$nm2) ) {
                    $msg .= " EXCLUDED";
                } elsif (!defined $depends{$nm2}) {
                    $depends{$nm2} = 1;
                }
            }
            $msg = trim_all($msg);
        }
        $msg .= ']';
        $cnt++;
        prt("$cnt: [$val] [$ptype] $msg AM [$am_file]\n");
    }
    prt("Done list of $cnt items...\n\n");
}

sub find_in_directory_scan($$) {
    my ($rparams,$file) = @_;
    return '' if (!${$rparams}{'CURR_DONE_SCAN'});
    my $rda = ${$rparams}{'CURR_DIR_SCAN'};
    #              0     1   2 3
    #push(@{$rda},[$file,$ff,0,0]);
    my $cnt = scalar @{$rda};
    my ($i,$ra,$tst,$lcf);
    $lcf = lc($file);
    for ($i = 0; $i < $cnt; $i++) {
        $ra = ${$rda}[$i];
        return ${$ra}[1] if ($file eq ${$ra}[0]);
        return ${$ra}[1] if ($lcf eq lc(${$ra}[0]));
    }
    return '';
}

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 "Build Shared Library" $type )

EOF
    return $txt;
}

# CMakeLists.txt GENERATION
# my @keys_used = qw(PROJECT_ROOT PROJECT_CFGS PROJECT_NAME PROJECT_APTP PROJECT_SRCS PROJECT_AM_FILE);
# FIX20120522 - YIKES: Some projects, like libxml2 for example, have programs/libraries in the 'root'
# At present 2 CMakeLists.txt files are written - temp..txt and temp.root.txt
# BUT obviously these two items SHOULD BE MERGED - maybe it is just ok to 'tack' temp..txt 
# onto the end of temp.root.txt... try that
# ${$rhash}{':_AM_FILE_SRC_:'} = $fil;  Makefile.am full path
# ${$rp}{'PROJECT_SOURCES'} = \@srcs;  # console application source
# ${$rph}{$key} = $rp;
# $rhash = ${$roph}{$key}; # extract from PROGRAM hash
# ${$rp}{'PROJECT_AM_RHASH'} = $rhash; # add to PROJECT hash
# $am_file = ${$rhash}{':_AM_FILE_SRC_:'}; # get AM file name
# 05/11/2012 - Write to ONLY ONE CMakeLists.txt
# =========================================
sub write_project_cmake_files($) {
    my $rparams = shift;
    my $prhs = get_cmake_proj_hash_ref();
    my $cnt = scalar @{$prhs};  # = @my_cmake_proj_hashes;
    prt("\nStarted CMake write for $cnt projects...\n");
    return 1 if ($cnt == 0); # failed
    my ($rh,$proot,$rcfgs,$pname,$ptype,$psrcs,$amfile,$name,$amdir);
    my ($ra,@arr,$rp,$val,$rpda,$nm2,$tmp,$msg,$pnm,$isexcl,$pst);
    my ($var,$cmake,$tmpout,$rsa,$inst,$tdir);
    my ($rprojsh);
    my ($pkey);
    my $errs = '';
    $errs .= "No 'AM_EXCLUDED_DIRS' " if (!defined ${$rparams}{'AM_EXCLUDED_DIRS'});
    $errs .= "No 'ROOT_FOLDER' " if (!defined ${$rparams}{'ROOT_FOLDER'});
    $errs .= "No 'PROJECT_NAME_MASTER' " if (!defined ${$rparams}{'PROJECT_NAME_MASTER'});
    if (defined ${$rparams}{'REF_PROJECTS_HASH'}) {
        $rprojsh = ${$rparams}{'REF_PROJECTS_HASH'};
        @arr = keys(%{$rprojsh});
        $cnt = scalar @arr;
        if ($cnt) {
            foreach $pkey (keys %{$rprojsh}) {
                $rp = ${$rprojsh}{$pkey};
                if (!defined ${$rp}{'PROJECT_NAME'}) {
                    $errs .= "At least one proj with no 'PROJECT_NAME' ";
                    last;
                }
            }
        } else {
            $errs .= "No count of REF_PROJECTS_HASH ";
        }
    #} else {
    #    $errs .= "No 'REF_PROJECTS_HASH' ";
    }
    $errs .= "No 'REF_LIB_LISTS' " if (!defined ${$rparams}{'REF_LIB_LISTS'});  # make list of LIBRARIES written
    if (length($errs)) {
        prt("ABORTING cmake write due to errors [$errs]\n");
        return 1;
    }
    ### my $rex = process_hoh_subs($rparams);   # get EXCLUDED sub-directories
    my $rex = ${$rparams}{'AM_EXCLUDED_DIRS'}; # get stored EXCLUDED directory HASH (if any!)
    my $proj_root = ${$rparams}{'ROOT_FOLDER'};
    ###my $proj_root = '';
    my $proj_title = ${$rparams}{'PROJECT_NAME_MASTER'};

    my $ihdrp = get_inst_hdr_path(); # { return $inst_hdr_path; } = 'include'
    my $ilibp = get_inst_lib_path(); # { return $inst_lib_path; } my $inst_lib_path = 'lib';
    my $ibinp = get_inst_hdr_bin();  # { return $inst_bin_path; } my $inst_bin_path = 'bin';

    ###my $proj_title = '';
    my $auto_on = get_curr_auto_flag(); # $auto_on_flag;
    $cnt = 0;
    my %am_hash = ();
    my %depends = ();
    my $rlib_lists = ${$rparams}{'REF_LIB_LISTS'};  # make list of LIBRARIES written
    my $write_cmake_files = get_write_cmake_files();

    # Establish USER include directories
    my %usrincs = ();   # -NEW_INCS-
    my $glob_user_incs = get_user_incs("NOT USED","*NO*PROJECT*NAME*"); # get GLOBAL user INCS
    @arr = space_split($glob_user_incs);
    foreach $tmp (@arr) {
        next if ($tmp =~ /^\/I/);
        $tmp = strip_quotes($tmp);
        $tmp = trim_all($tmp);
        next if (length($tmp) == 0);
        ##$tmp = path_d2u($tmp);
        set_rpath_per_os(\$tmp);
        $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
        $usrincs{$tmp} = 1;
    }
    my %usrdefs = ();   # -NEW_DEFS-
    my $glob_user_defs = get_user_defs("NOT USED",,"*NO*PROJECT*NAME*"); # get GLOBAL user DEFS
    @arr = space_split($glob_user_defs);
    foreach $tmp (@arr) {
        next if ($tmp =~ /^\/D/);
        $tmp = strip_quotes($tmp);
        $tmp = trim_all($tmp);
        next if (length($tmp) == 0);
        next if (defined $defines_added{$tmp});
        $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
        next if (defined $defines_added{$tmp});
        $usrdefs{$tmp} = 1;
    }

    $cnt = 0;
    ###foreach $rh (@g_cmake_proj_hashes) {
    ###    if (!test_ref_hash($rh,\$proot,\$rcfgs,\$pname,\$ptype,\$psrcs,\$amfile)) {
    ###        $proj_title = ${$rh}{'PROJECT_TITLE'};
    ###        $proj_root  = ${$rh}{'PROJECT_ROOT'};
    ###        last;
    ###    }
    ###}
    # 13/05/2012 - ERROR if NO project title
    if ((length($proj_title) == 0)||($proj_title =~ /^\s+$/)||($proj_title =~ /\s/)) {
        pgm_exit(1,"ERROR: Have NO (or bad) project title [$proj_title]!\nCan ONLY abort!\n");
    }

    # pre-process the set of per project REF HASH
    my %sub_dirs = ();  # no longer needed, but things set here MUST be added to SOURCES
    my ($rhash,$am_file);
    #foreach $rh (@my_cmake_proj_hashes) {
    foreach $rh (@{$prhs}) {
        ### show_ref_hash($rh,1);
        $cnt++;
        if (test_ref_hash($rh,\$proot,\$rcfgs,\$pname,\$ptype,\$psrcs,\$amfile)) {
            prtw("WARNING:$cnt: HASH REF INVALID!\n");
        } else {
            if (length($amfile) == 0) {
                prtw("WARNING: $cnt: [$pname] [$ptype] [$amdir] AM filename nul!\n");
                next;
            }
            ($name,$amdir) = fileparse($amfile);    # we have the AM file directory
            # $proot = ${$rh}{'PROJECT_FDIR'};
            $amdir = my_sub_common_folder($amdir,$proj_root); # subtract the project root - hmmm WHY???
            $amdir =~ s/(\\|\/)$//;
            $msg = 'NF';
            $pst = '';
            my @deps = ();
            my ($pkey);
            foreach $pkey (keys %{$rprojsh}) {
                $rp = ${$rprojsh}{$pkey};
                $pnm = ${$rp}{'PROJECT_NAME'};
                if ($pnm eq $pname) {
                    ${$rh}{'PROJECT_RP'} = $rp; # all keep REF PROJECT HASH in REF HASH
                    $rhash = ${$rp}{'PROJECT_AM_RHASH'}; # get PROJECT hash
                    $am_file = ${$rhash}{':_AM_FILE_SRC_:'}; # get AM file name
                    prtw("WARNING: Got conflickting AM files [$am_file] vs [$amfile]!\n") if ($amfile ne $am_file);
                    $sub_dirs{$amdir} = 1; # $amdir added to SOURCES
                    $pst = ${$rp}{'PROJECT_TYPE'};
                    $inst = ${$rp}{'PROJECT_INST'};
                    $msg = get_EXCLUDE_msg($rparams,$rp,$rex);
                    $isexcl = ($msg =~ /EXCLUDE/) ? 1 : 0;
                    prt("[v9] cmake: proj_name [$pname], from [$am_file]\n") if (VERB9());
                    # $tmp = get_user_incs("NOT USED",$pname); # -NEW_INCS- for this project
                    $tmp = get_project_incs($pname); # -NEW_INCS- for this project
                    $val = '';
                    if (length($tmp)) {
                        @arr = space_split($tmp);
                        foreach $tmp (@arr) {
                            next if ($tmp =~ /^\/I/);
                            $tmp = strip_quotes($tmp);
                            $tmp = trim_all($tmp);
                            next if (length($tmp) == 0);
                            $tmp = path_d2u($tmp);  # cmake LIKES unix paths
                            $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
                            next if (defined $usrincs{$tmp});   # already in GLOBAL
                            $val .= ' ' if (length($val));
                            $val .= $tmp;
                        }
                    }
                    prtw("WARNING: By project user INCLUDES [$val] pesently NOT ADDED!\n") if (length($val));

                    $tmp = get_project_defs($pname); # -NEW_DEFS- for this project
                    $val = '';
                    if (length($tmp)) {
                        @arr = space_split($tmp);
                        foreach $tmp (@arr) {
                            next if ($tmp =~ /^\/I/);
                            $tmp = strip_quotes($tmp);
                            $tmp = trim_all($tmp);
                            next if (length($tmp) == 0);
                            $tmp = path_d2u($tmp);  # cmake LIKES unix paths
                            $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
                            $val .= ' ' if (length($val));
                            $val .= $tmp;
                        }
                    }
                    prtw("WARNING: By project user DEFINES [$val] pesently NOT ADDED!\n") if (length($val));

                    $msg = '[';
                    if (defined ${$rp}{'PROJECT_DEPENDS'}) {
                        $rpda = ${$rp}{'PROJECT_DEPENDS'};
                        # $msg .= ' with deps [';
                        # CHECK if this is NOT EXCLUDED
                        foreach $nm2 (@{$rpda}) {
                            $msg .= "$nm2 ";
                            if (defined ${$rlib_lists}{$nm2}) {
                                $tmp = ${$rlib_lists}{$nm2};
                                if (${$tmp}[$RLO_MSG] =~ /EXCLUDE/) {
                                    prtw("WARNING: Dependent name [$nm2] is EXCLUDED!\n");
                                }
                                ${$tmp}[$RLO_VAL] = 1;
                                ${$rlib_lists}{$nm2} = $tmp;
                            } else {
                                prtw("WARNING: This name [$nm2] NOT in LIBRARY LIST!\n");
                            }
                            # now, joined, done just before this, can ADD to excluded, so...
                            # if ( is_project_all_excluded($nm2) )
                            if ( is_dependency_excluded($rparams,$pnm,$isexcl,$nm2) ) {
                                $msg .= " EXCLUDED";
                            } else {
                                push(@deps,$nm2);
                                $depends{$nm2} = 1;
                            }
                        }
                        $msg = trim_all($msg);
                    }
                    $msg .= ']';
                    $msg = 'No Depends' if ($msg eq '[]');
                    last;
                }
            }
            ${$rh}{'PROJECTS_DEPENDS_ARRAY'} = \@deps;
            #if (is_project_all_excluded($pname)) {  # if the PROJECT is EXCLUDED forget it
            #    prt("$cnt: EXCLUDED [$pname] $pst"."[$ptype] [$amdir] $msg\n"); #  if (VERB5());
            #} else {
                $am_hash{$amdir} = [] if (!defined $am_hash{$amdir});
                $ra = $am_hash{$amdir};
                push(@{$ra},$rh);   # get REF HASH on a SUBDIRECTORY BASIS
                prt("$cnt: [$pname] $pst"."[$ptype] [$amdir] $msg\n") if (VERB5()); # || $dbg_cmake);
            #}
        }
    }   # foreach $rh (@{$prhs})

    # NOW each REF HASH has been stored PER SOURCE DIRECTORY in a REF ARRAY
    @arr = sort keys(%am_hash);
    $cnt = scalar @arr;
    my $subcount = 0;
    foreach $tmp (@arr) {
        $tmp = trim_all($tmp);
        next if (length($tmp) == 0);
        $subcount++;
    }
    prt("\nCMake Project [$proj_title], root [$proj_root], with $cnt SUBDIRS ($subcount)\n");
    my ($inc_dirs);
    ### my %cmake_thash = ();   # CMakeFile.txt text hash, per (tmp) output file
    ### my %cmake_files = ();   # mapping REAL file to tmp output file
    my $pgmname = get_pgmname();
    my $lib_type = ($def_to_shared ? "ON" : "OFF");
    my $cmake_root = "\n# $proj_root"."CMakeLists.txt, generated $pgmname, on ";
    $cmake_root .= lu_get_YYYYMMDD_hhmmss(time())."\n\n";
    $cmake_root .= "cmake_minimum_required( VERSION 2.6.4 )\n\n";
    $cmake_root .= "project( $proj_title )\n\n";
    $cmake_root .= "# The version number.\n";
    # This VERSION may be given in a command
    # =======================================================
    if (length($project_version)) {
        @arr = split(/\./,$project_version);
        $tmp = scalar @arr;
        $cmake_root .= "# ### NOTE: *** CHECK ME *** $project_version\n";
        $cmake_root .= "set( ${proj_title}_VERSION_MAJOR ".$arr[0]." )\n";
        if ($tmp > 1) {
            $cmake_root .= "set( ${proj_title}_VERSION_MINOR ".$arr[1]." )\n";
        } else {
            $cmake_root .= "set( ${proj_title}_VERSION_MINOR 0 )\n";
        }
        if ($tmp > 2) {
            $cmake_root .= "set( ${proj_title}_VERSION_POINT ".$arr[2]." )\n\n";
        } else {
            $cmake_root .= "set( ${proj_title}_VERSION_POINT 0 )\n\n";
        }
    } else {
        $cmake_root .= "# ### NOTE: *** FIX ME ***\n";
        $cmake_root .= "set( ${proj_title}_VERSION_MAJOR 1 )\n";
        $cmake_root .= "set( ${proj_title}_VERSION_MINOR 2 )\n";
        $cmake_root .= "set( ${proj_title}_VERSION_POINT 3 )\n\n";
    }
    $cmake_root .= add_options_block($lib_type);
    $cmake_root .= get_definitions_block();

    # setup global DEFINES
    @arr = keys(%usrdefs);
    $val = '';
    foreach $tmp (@arr) {
        $tmp = trim_all($tmp);
        next if (length($tmp) == 0);
        next if (defined $defines_added{$tmp});
        $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
        $defines_added{$tmp} = 1;
        $val .= ' ' if (length($val));
        $val .= "-D$tmp";
    }
    $cmake_root .= "add_definitions( $val )\n" if (length($val));

    # setup INCLUDE directories
    @arr = keys(%usrincs);
    $inc_dirs = '';
    my @last_dirs = (); # 20120524 - always put /3rdparty/ LAST
    foreach $tmp (@arr) {
        $tmp = trim_all($tmp);
        next if (length($tmp) == 0);
        $tmp = path_d2u($tmp);
        if ( !($tmp =~ /^\w{1}:(\\|\/)/) ) {
            # not absolute - add prefix
            $tmp = "\${PROJECT_BINARY_DIR}/$tmp";
        }
        $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
        if ($tmp =~ /(\\|\/)3rdParty(\\|\/)/i) {
            push(@last_dirs,$tmp);
        } else {
            $inc_dirs .= ' ' if (length($inc_dirs));
            $inc_dirs .= $tmp;
        }
    }
    if (@last_dirs) {
        $inc_dirs .= ' ' if (length($inc_dirs));
        $inc_dirs .= join(" ",@last_dirs);
    }

    my ($minn,$mint,$len,$dnm,$typ,$deps,$scnt,$xit);
    my ($var2,$slist,$hlist,$val2);   # separate by is_c_source_extended() or is_h_source()
    @arr = sort keys(%sub_dirs);
    $val = '';
    @last_dirs = ();    # clear last
    foreach $tmp (@arr) {
        $tmp = trim_all($tmp);
        next if (length($tmp) == 0);
        $tmp = path_d2u($tmp); # cmake LIKES unix paths   # or s/\\/\\\\/g;
        #if ( !($tmp =~ /^\w{1}:\//) ) {
        #    # not absolute - add prefix
        #   $tmp .= "\${PROJECT_BINARY_DIR}/$tmp";
        #}
        $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
        if ($tmp =~ /(\\|\/)3rdParty(\\|\/)/i) {
            push(@last_dirs,$tmp);
        } else {
            $val .= ' ' if (length($val));
            $val .= $tmp;
        }
    }
    if (@last_dirs) {
        $val .= ' ' if (length($val));
        $val .= join(" ",@last_dirs);
    }

    #$cmake_root .= "INCLUDE_DIRECTORIES( SYSTEM $inc_dirs )\n" if (length($inc_dirs));
    #$cmake_root .= "message( \"*** Current binary directory [\${PROJECT_BINARY_DIR}] ***\" )\n";
    $cmake_root .= "\ninclude_directories( SYSTEM \"\${PROJECT_BINARY_DIR}\" $val )\n\n";
    ### $cmake_root .= "ADD_SUBDIRECTORY( $val )\n";    # NO WAY - seems each must ONLY BE ONE AT A TIME
    my %added_subs = ();
    # these sub-directories pushed into @arr/@sub_dirs have to be added to the sources
    #foreach $tmp (@arr) {
    #    $tmp = trim_all($tmp);
    #    next if (length($tmp) == 0);
    #    $tmp = path_d2u($tmp); # or =~ s/\\/\\\\/g;
    #    next if (defined $added_subs{$tmp});  # skip if already added
    #    $added_subs{$tmp} = 1;
    #    $tmp = '"'.$tmp.'"' if ($tmp =~ /\s/);
    #    $cmake_root .= "add_subdirectory( $tmp )\n";    # Add ONE AT A TIME
    #}

    # NOTE: Fully EXCLUDED projects are NOT in the REF ARRAY for EACH HASH directory of the SOURCE
    $minn = 0;
    $mint = 0;
    my ($am_key);
    foreach $am_key (keys %am_hash) {
        $ra = $am_hash{$am_key};
        foreach $rh (@{$ra}) {
            if ( ! test_ref_hash($rh,\$proot,\$rcfgs,\$pname,\$ptype,\$psrcs,\$amfile) ) {
                $len = length($pname);
                $minn = $len if ($len > $minn);
                $len = length($ptype);
                $mint = $len if ($len > $mint);
            }
        }
    }

    my $PATH_SEP = get_PATH_SEP();
    my $dsp_out_dir = get_dsp_out_dir();
    my %added_lists = ();
    my $add_2_root = ''; # AVOID 2 CMakeLists.txt - temp..txt and temp.root.txt
    my $cmake_libs = '';
    my $cmake_exes = '';
    my @srcarr = ();
    my @hdrarr = ();
    my ($line);
    my $indent = 3;
    my $lib_count = 0;
    my $exe_count = 0;
    my $dn_lib = 0;
    my $dn_exe = 0;
    my %dupe_names = ();
    my ($prjname,$dcnt);
    foreach $am_key (sort keys %am_hash) {
        $ra = $am_hash{$am_key};
        $cnt = scalar @{$ra};
        $amdir = $proj_root.$am_key.$PATH_SEP."CMakeLists.txt";
        if (length($am_key)) {
            $tmp = $am_key;
            $tmp = path_d2u($tmp); # cmake LIKES unix paths   # or s/\\/\\\\/g;
            $added_lists{$tmp} = 1; # this is again sort of EACH subdirectory
        }
        $tmp = $am_key;
        $tmp =~ s/\\/_/g;
        $tmpout = $dsp_out_dir;
        ut_fix_dir_string(\$tmpout);
        $tmpout .= "temp.$tmp.txt";
        ### if ((defined $cmake_thash{$tmpout}) || (defined $cmake_files{$tmpout}))  {
        ###    pgm_exit(1,"ERROR: A hash has like a DUPLICATE key [$am_key]! Check how to make [$tmpout] UNIQUE!\n");
        ###}

        prt("cmake: $amdir has $cnt projects\n");
        # set INTITAL CMakeLists.txt entry
        $tmp = "";
        # $tmp = "\n# $amdir, generated by $pgmname on ".lu_get_YYYYMMDD_hhmmss(time())."\n\n";
        #$tmp .= "include_directories( \"\${PROJECT_BINARY_DIR}\" $inc_dirs )\n\n";
        #$tmp .= "INCLUDE_DIRECTORIES( \${PROJECT_BINARY_DIR}\ )\n";
        #$tmp .= "INCLUDE_DIRECTORIES( $inc_dirs )\n" if (length($inc_dirs));
        #$tmp .= "\n";
        #if (length($am_key)) {
        #    $cmake_thash{$tmpout} = $tmp;   # start cmake text for this file
        #    $cmake_files{$tmpout} = $amdir; # map 'tmp' to real target file
        #} else {
        ##    $add_2_root .= $tmp; # $key of NO length == root stuff
        #}
        foreach $rh (@{$ra}) {
            if ( ! test_ref_hash($rh,\$proot,\$rcfgs,\$pname,\$ptype,\$psrcs,\$amfile) ) {
                #if (is_project_all_excluded($pname)) {  # if the PROJECT is EXCLUDED forget it
                #    prtw("WARNING: An EXCLUDED project has been added! FIX THIS\n");
                #    next;
                #}
                $dn_lib = 0;
                $dn_exe = 0;
                $prjname = $pname;
                $dcnt = 0;
                while (defined $dupe_names{$prjname}) {
                    $dcnt++;
                    $prjname = $pname.$dcnt;
                }
                $dupe_names{$prjname} = $pname;

                $rp = ${$rh}{'PROJECT_RP'}; # extract $rp; # all keep REF PROJECT HASH in REF HASH
                $inst = ${$rp}{'PROJECT_INST'};
                $cmake = '';
                $rpda = ${$rh}{'PROJECTS_DEPENDS_ARRAY'}; # = \@deps; # Project DEPENDS array - can be none
                $deps = '';
                my %extra_libs = ();
                foreach $tmp (@{$rpda}) {
                    $deps .= ' ' if (length($deps));
                    $deps .= $tmp;
                    $extra_libs{$tmp} = 1;                     
                }

                my ($amn,$amd) = fileparse($amfile);    # we have the AM file directory
                # $proot = ${$rh}{'PROJECT_FDIR'};
                $amd = my_sub_common_folder($amd,$proj_root); # subtract the project root - hmmm WHY???
                if (length($amd)) {
                    $amd .= '/' if (!($amd =~ /(\\|\/)$/));
                }
                #$cmake .= "MESSAGE(\"Current build directory \${CMAKE_CURRENT_BUILD_DIR}\")\n";
                #$cmake .= "INCLUDE_DIRECTORIES( \"\${CMAKE_CURRENT_BUILD_DIR}\" )\n";
                #$cmake .= "MESSAGE(\"Current binary directory [\${PROJECT_BINARY_DIR}]\")\n";
                #$cmake .= "INCLUDE_DIRECTORIES( \"\${PROJECT_BINARY_DIR}\" )\n";

                $var = $prjname."_SRCS";
                $var2 = $prjname."_HDRS";
                $slist = '';
                $hlist = '';
                $scnt = 0;
                my %dupes = ();
                ##                0      1       2        3
                #push(@sources, [ $sfil, $group, $filter, $xit, '' ]);   # ${$rph}{'PROJECT_SRCS'}
                my $relhlist = '';
                my $hcnt = 0;
                @srcarr = ();   # clear source array
                @hdrarr = ();
                foreach $rsa (@{$psrcs}) {
                    $tmp = ${$rsa}[0];
                    $xit = ${$rsa}[3];
                    next if ($xit);     # excluded SOURCE file
                    my ($n,$d) = fileparse($tmp);
                    next if ($n eq 'unistd.h'); # why MUST I exclude this?????? TODO
                    if (!defined $dupes{$n}) {
                        $dupes{$n} = 1;
                        if (is_c_source_extended($tmp)) {
                            $slist .= ' ' if (length($slist));
                            $slist .= path_d2u($amd.$n);
                            push(@srcarr,path_d2u($amd.$n)); # store in SOURCE
                            $scnt++;
                        } elsif (is_h_source($tmp)) {
                            $hlist .= ' ' if (length($hlist));
                            $hlist .= path_d2u($amd.$n);
                            ###$scnt++;
                            $relhlist .= ' ' if (length($relhlist));
                            $relhlist .= path_d2u($tmp);
                            $hcnt++;
                        } else {
                            prtw("WARNING: SOURCE [$tmp] NOT ADDED! Not 'C' or 'H'! WHat is IT?\n");
                        }
                    }
                }
                prt("cmake: project [$prjname] has $scnt sources, $hcnt headers\n");
                prt("cmake: sources: [$slist] headers [$relhlist]\n");
                if ($scnt) {
                    @hdrarr = ();   # header array
                    if (length($relhlist)) {
                        @arr = space_split($relhlist);
                        $relhlist = '';
                        foreach $tmp (@arr) {
                            if ($use_just_file_name) {
                                ($tmp,$tdir) = fileparse($tmp);
                                $tmp = path_d2u($amd.$tmp);
                                $relhlist .= "$tmp ";
                                push(@hdrarr,"$tmp");
                            } else {
                                $tmp = path_d2u($tmp);
                                # TODO **TBD** really need to LOCATE this HEADER, in source
                                # and ADD appropriate relative path to it!
                                if ($add_proj_bin_dir) {
                                    $relhlist .= "\${PROJECT_BINARY_DIR}/$tmp ";
                                    push(@hdrarr,"\${PROJECT_BINARY_DIR}/$tmp");
                                } else {
                                    $relhlist .= "$tmp ";
                                    push(@hdrarr,"$tmp");
                                }
                            }
                        }
                    }
                    $msg = '';
                    $cmake .= "\n# Project [$prjname] [$ptype] [$inst], with $scnt sources.";
                    $cmake .= " $hcnt hdrs." if ($hcnt);
                    @arr = keys(%extra_libs);
                    if (@arr) {
                        $tmp = scalar @arr;
                        $cmake .= " deps [".join(" ",@arr)."]$tmp";
                    }
                    $cmake .= "\n";
                    if (length($slist)) {
                        ###$msg .= "set( $var $slist )\n";
                        $line = '';
                        $msg .= "set( $var ";
                        foreach $tmp (@srcarr) {
                            $line .= "$tmp ";
                            if (length($line) > $max_set_line_len) {
                                $msg .= "$line\n";
                                $line = ' ' x $indent;  # indent say 3 spaces
                            }
                        }
                        if (length($line) > $indent) {
                            $msg .= $line;
                        } else {
                            $msg =~ s/\n$//;    # clear new line
                        }
                        $msg .= ")\n";
                    }
                    if (length($relhlist)) {
                        ###$msg .= "set( $var2 $relhlist )\n";
                        $msg .= "set( $var2 ";
                        $line = ''; # clear line accumulation
                        foreach $tmp (@hdrarr) {
                            $line .= "$tmp ";
                            if (length($line) > $max_set_line_len) {
                                $msg .= "$line\n";
                                $line = ' ' x $indent;  # indent
                            }
                        }
                        if (length($line) > $indent) {
                            $msg .= $line;
                        } else {
                            $msg =~ s/\n$//;    # remove trailing new line
                        }
                        $msg .= ")\n";
                    }
                    $cmake .= "$msg";   # add it to cmake
                    ### prt("$msg\n");

                    if ($ptype eq 'Console Application') {
                        # DO AN EXE
                        # =========
                        $msg = "add_executable( $prjname ";
                        $msg .= "\${$var} " if (length($slist));
                        $msg .= "\${$var2} " if (length($hlist));
                        $msg .= ")\n";
                        $cmake .= "$msg";
                        $dn_exe = 1;
                        # if (($proj_type ne 'SL') && ($auto_on & 16) && ($auto_on & 2048)) {
                        if (($auto_on & 16) && ($auto_on & 2048)) {
                            # target_link_libraries(mylib public1 public2 PRIVATE private1 private2)
                            # $cmake .= "TARGET_LINK_LIBRARIES( $pname PRIVATE getopt.lib )\n";
                            # need to eliminate (s) system libs, (b) dependent libs, in $rpda (ref proj dep array),
                            # and separate balance into lib and path
                            $tmp = get_cmake_lib_finds($rp);
                            if (length($tmp)) {
                                $cmake .= $tmp;
                                prt("$tmp\n") if (VERB9());
                            } else {
                                prt("Project [$pname] has NO dependent libraries.\n") if (VERB9());
                            }
                        } else {
                            prtw("WARNING: ((\$auto_on & 16) && (\$auto_on & 2048)) bit NOT set, so NO library FIX! value is [$auto_on]\n");
                        }

                        $cmake .= "target_link_libraries( $prjname \${add_LIBS} )\n";
                        # try - AND IT WORKED - phew ;=))
                        # set_target_properties (helloDemo PROPERTIES DEBUG_POSTFIX "d")
                        if (length($add_exe_postfix)) {
                            # we have a CMAKE_DEBUG_POSTFIX for an EXE
                            $msg = "set_target_properties( $prjname PROPERTIES DEBUG_POSTFIX \"$add_exe_postfix\" )\n";
                            $cmake .= $msg;
                        }

                        $msg = "install(TARGETS $prjname DESTINATION $ibinp)\n";
                        $msg .= "install(FILES \${$var2} DESTINATION $ihdrp)\n" if (length($hlist));
                        if ($inst =~ /noinst/) {
                            $cmake .= "# NO INSTALL [$inst]\n";
                        } else {
                            $cmake .= $msg if ($add_exe_install);
                        }
                        $exe_count++;
                    } elsif ($ptype eq 'Static Library') {
                        # DO A STATIC LIBRARY
                        # ===================
                        $lib_count++;
                        $dn_lib = 1;
                        $msg = "add_library( $prjname \${LIB_TYPE} ";
                        $msg .= "\${$var} " if (length($slist));
                        $msg .= "\${$var2} " if (length($hlist));
                        $msg .= ")\n";
                        $cmake .= "$msg";
                        # # add the install targets
                        # ==============================================
                        # DEAL WITH LIBRARY INSTALL
                        # ==============================================
                        # install (TARGETS Hello DESTINATION lib)
                        # install (FILES ${HELLO_HDRS} DESTINATION include)
                        # $msg = "install(TARGETS $pname DESTINATION $ilibp)\n";
                        $msg = "# deal with install \n";
                        $msg .= "install( TARGETS $prjname\n";
                        $msg .= "         RUNTIME DESTINATION bin\n";
                        $msg .= "         LIBRARY DESTINATION lib\n";
                        $msg .= "         ARCHIVE DESTINATION lib )\n";
                        # install( FILES ${apr_HEADERS} DESTINATION include )
                        # OOPS, sometimes the header can be 'local', like
                        # tiffconf.h, tif_config.h are in "\${PROJECT_BINARY_DIR}, and NOT in
                        # "\${PROJECT_SOURCE_DIR}/libtiff where CMake will think they should be...
                        if ($use_single_inc_list) {
                            $msg .= "install(FILES \${$var2} DESTINATION $ihdrp)\n" if (length($hlist));
                        } elsif (length($hlist)) {
                            my ($itm,$hfile);
                            my @narr = ();
                            my @sarr = ();
                            @arr = space_split($hlist);
                            foreach $itm (@arr) {
                                # maybe get each file from the scan list, or
                                if (length($am_key)) {
                                    $hfile = $proj_root.$am_key.$PATH_SEP.$itm;
                                } else {
                                    $hfile = $proj_root.$itm;
                                }
                                if (-f $hfile) {
                                    push(@narr,$itm);   # found in 'normal' place
                                } else {
                                    push(@sarr,"\${PROJECT_BINARY_DIR}/$itm");
                                }
                            }
                            $msg .= "install(FILES ".join(" ",@narr)." DESTINATION $ihdrp)\n" if (@narr);
                            $msg .= "install(FILES ".join(" ",@sarr)." DESTINATION $ihdrp)\n" if (@sarr);
                            #if ($pname eq 'tiff') {
                            #    prt("Need to examine this list [$hlist], and have separate installs!\n");
                            #   prt("$msg\n");
                            #    pgm_exit(1,"TEMP EXIT");
                            #}
                        }
                        if ($inst =~ /noinst/) {
                            $cmake .= "# NO INSTALL [$inst]\n";
                        } else {
                            $cmake .= $msg if ($add_lib_install);
                        }
                        $cmake .= "list(APPEND add_LIBS $pname)\n";
                    } else {
                        # OTHERS TODO ***TBD***
                        prtw("WARNING: Unhandled project type [$ptype]! FIX ME! 3\n");
                    }
                    @arr = keys %extra_libs;
                    if (@arr) {
                        $cmake .= "target_link_libraries( $prjname ";
                        $cmake .= join(" ",@arr);
                        $cmake .= " )\n";
                    }
                    ### $cmake .= "\n"; # separate from the next

                    # STORE THIS CMAKE TEXT UNDER THE FILE NAME
                    # =========================================
                    ## if (length($am_key)) {
                    ##    $cmake_thash{$tmpout} .= $cmake;    # accumulate the CMake text
                    ##} else {
                    # ONLY A SINGLE ROOT CMAKELISTS.TXT DONE
                    ###$add_2_root .= $cmake;
                    if ($dn_exe) {
                        $cmake_exes .= $cmake;
                    } elsif ($dn_lib) {
                        $cmake_libs .= $cmake;
                    }
                    ##}
                    # =========================================

                    # display ONLY
                    # -------------------------------------------------
                    $dnm = $prjname;
                    $typ = $ptype;
                    $dnm .= ' ' while (length($dnm) < $minn);
                    $typ .= ' ' while (length($typ) < $mint);
                    $msg = " $dnm [$typ] srcs $scnt";
                    $msg .= ", deps [$deps]" if (length($deps));
                    prt("$msg\n");
                    prt($cmake) if (VERB9());
                    # ------------------------------------------------
                    $cmake = '';    # clean this 'cmake'
                } else {
                    prtw("WARNING: No SOURCES found for [$prjname]!\n");
                }
            }
        }   # foreach $rh
    }

    # this SHOULD have been done before her, but better late than never
    # compare ADDED subdirectories - my %added_subs = ();
    # with ADDED CMakeLists.txt files - my %added_lists = ();
    # Added SUBDIRS
    # contrib/addtiffo contrib/dbs contrib/iptcutil libtiff port test tools
    # Added CMAKE LISTS
    # contrib/addtiffo contrib/dbs libtiff port tools
    my ($skey);
    foreach $skey (keys %added_subs) {
        next if (length($skey) == 0);   # donot deal with a blank
        if (!defined $added_lists{$skey}) {
            # need to generate a CMakeLists.txt for here
            $tmp = $skey;
            $tmp =~ s/\\/_/g;
            $tmp =~ s/\//_/g;
            $tmpout = $dsp_out_dir;
            ut_fix_dir_string(\$tmpout);
            $tmpout .= "temp.$tmp.txt";
            ## if ((defined $cmake_thash{$tmpout}) || (defined $cmake_files{$tmpout}))  {
            ##    pgm_exit(1,"ERROR: A hash has like a DUPLICATE key [$skey]! Check how to make [$tmpout] UNIQUE!\n");
            ## }
            ## $amdir = $proj_root.$skey.$PATH_SEP."CMakeLists.txt";
            ## set INTITAL CMakeLists.txt entry
            ## $tmp = "\n# $amdir, generated by $pgmname on ".lu_get_YYYYMMDD_hhmmss(time())."\n\n";
            $tmp = "# $amdir - deliberately BLANK\n\n";

            ## $cmake_thash{$tmpout} = $tmp;   # start cmake text for this file
            ## $cmake_files{$tmpout} = $amdir; # map 'tmp' to real target file
            $add_2_root .= $tmp;
        }
    }

    if ($write_cmake_files) {
        my $target_dir = ${$rparams}{'TARGET_DIR'};
        my $battxt = "\@setlocal\n";
        $battxt .= "\@set COUNT=0\n";
        my ($real);
        $cnt = 0;
        @arr = ();
        #foreach $tmp (keys %cmake_thash) {
        #    $val = $cmake_thash{$tmp};
        #    $real = $cmake_files{$tmp};
        #    $val .= "\n# eof\n";
        #    $battxt .= "\@set /A COUNT+=1\n";
        #    $battxt .= "\@copy \"$tmp\" \"$real\" >nul\n";
        #    write2file($val,$tmp);
        #    $cnt++;
        #    prt("$cnt: Written [$tmp] for [$real]\n");
        #    push(@arr,$real);
        #}
        $cmake_root .= $cmake_libs;
        $cmake_root .= "\n##########################################################\n";
        $cmake_root .= $cmake_exes;
        $cmake_root .= $add_2_root;

        # FINALISE CMakeLists.txt for ROOT
        $cmake_root .= "\n# eof\n";
        $tmpout = $dsp_out_dir;
        ut_fix_dir_string(\$tmpout);
        $tmpout .= "temp.root.$proj_title.txt";
        $real = $proj_root."CMakeLists.txt";
        # $tmpout = $dsp_out_dir.$PATH_SEP."temp.root.$proj_title.txt";
        write2file($cmake_root,$tmpout);
        push(@arr,$real);
        $cnt++;
        prt("$cnt: Written final [$tmpout] for [$real]\n");
        $battxt .= "\@set /A COUNT+=1\n";
        $battxt .= "\@copy \"$tmpout\" \"$real\" >nul\n";
        $battxt .= "\@echo Copied \%COUNT\% CMakeLists.txt files into place\n";
        # Write a simple CMakeLists.txt list to
        $tmpout = $dsp_out_dir;
        ut_fix_dir_string(\$tmpout);
        $tmpout .= "temp.list.$proj_title.txt";
        write2file(join("\n",@arr)."\n",$tmpout);
        $real = $target_dir."cmakelist.txt";
        $battxt .= "\@copy \"$tmpout\" \"$real\" >nul\n";
        $battxt .= "\@echo And copied a list file '$real'.\n";

        $tmp = "C:\\MDOS";
        $tmpout = $dsp_out_dir;
        $tmpout = $tmp if (-d $tmp);
        ut_fix_dir_string(\$tmpout);
        $tmpout .= "tempcmake.bat";
        write2file($battxt,$tmpout);
        prt("Written [$tmpout] batch file to copy CMake files into place.\n");
    } else {
        prt("Write CMake CMakeLists.txt files disabled. Used -cmake to enable.\n");
    }
    # pgm_exit(1,"TEMP EXIT");
    return 0;   # success
}

1;

# eof
