#!/usr/bin/perl -w # NAME: gencmake.pl # AIM: Given an input folder, roughly generate a CMakeLists.txt from what is seem # 01/06/2020 - Update CMake version to 3.6, and add in-source check # 2018-02-15 - Do better finding 'main' # 28/04/2015 - add WinMain WIN32 EXE type # 09/12/2014 - Try to do ALL libraries first, then the executable # 30/11/2014 - Leave out extra info, unless requested, and # if just ONE source file - instead of naming by the folder name, use the name of that 1 source... # 28/09/2014 - bug fix -n repeated, missing -i... FIXED # 18/06/2014 - Small enhancements # 31/07/2012 - Added *.rc files to sources # 09/07/2012 - Initial cut use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use File::Spec; # File::Spec->rel2abs($rel); # we are IN the SLN directory, get ABSOLUTE from use Cwd; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n"; require 'lib_params.pl' or die "Unable to load 'lib_params.pl'! Check location and \@INC content.\n"; require 'lib_amscan.pl' or die "Unable to load 'lib_amscan.pl'! Check location and \@INC content.\n"; require 'lib_chkmain.pl' or die "Unable to load 'lib_chkmain.pl' Check paths in \@INC...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt"; open_log($outfile); # user variables my $VERS = "0.0.7 2020-06-01"; # add -V vers ### $VERS = "0.0.6 2015-04-28"; # add WinMain WIN32 type ### $VERS = "0.0.5 2014-12-09"; # out LIBS first, then EXE ### $VERS = "0.0.4 2014-09-28"; # bug fix ### $VERS = "0.0.3 2014-06-18"; # small improvements ### $VERS = "0.0.2 2012-07-31"; # add *.rc files also ### $VERS = "0.0.1 2012-07-09"; my $load_log = 0; my $in_directory = ''; my $verbosity = 0; my $out_file = $temp_dir.$PATH_SEP."CMakeLists.txt"; # my $tmp_cmake_list = $temp_dir.$PATH_SEP."temp.CMakeLists.txt"; my $proj_title = ''; my $add_am_files = 0; my $add_extra_info = 0; my $add_one_lib = 0; # TODO: cmake coding the make this happen my @add_inc_dirs = (); my @supp_warnings = (); my $add_options = 0; # add options around each componets, -O my $ver_msg = 'FIX ME'; my $ver_maj = 3; my $ver_min = 0; my $ver_pts = 0; my $add_fatal_insrc = 1; my $add_static_runtime = 1; # DEBUG my $debug_on = 0; my $def_dir = 'C:\GTools\tools\versinfo'; ###my $def_dir = 'C:\FG\16\fgms-1-x'; #my $def_dir = 'C:\Users\user\Downloads\temp7\Tools\MainLine'; ### program variables my @warnings = (); my $cwd = cwd(); my %files_found = (); my %c_files_found = (); my %h_files_found = (); my %am_files_found = (); my $total_dirs = 0; my $total_c_files = 0; my $total_h_files = 0; my $total_am_files = 0; my $TYP_NONE = 0; # well not defined my $TYP_C = 1; # .c .cpp, .cxx my $TYP_H = 2; # .h .hpp, .hxx my $TYP_RC = 3; # .rc my $TYP_AM = 4; # Makefile.am ### shared ### SHARED RESOURCES, VALUES ### ======================== our $fix_relative_sources = 1; our %g_user_subs = (); # supplied by USER INPUT our %g_user_condits = (); # conditionals supplied by the user # Auto output does the following - # For libaries # Debug: '/out:"lib\barD.lib"' # Release:'/out:"lib\barD.lib"' # for programs # Debug: '/out:"bin\fooD.exe"' # Release:'/out:"bin\foo.exe"' # This also 'adds' missing 'include' files #Bit: 1: Use 'Debug\$proj_name', and 'Release\$proj_name' for intermediate and out directories #Bit: 2: Set output to lib, or bin, and names to fooD.lib/foo.lib or barD.exe/bar.exe #Bit: 4: Set program dependence per library output directories #Bit: 8: Add 'msvc' to input file directory, if no target directory given #Bit: 16: Add program library dependencies, if any, to DSW file output. #Bit: 32: Add all necessary headers to the DSP file. That is scan the sources for #include "foo.h", etc. #Bit: 64: Write a blank header group even there are no header files for that component. #Bit: 128: Add defined item of HAVE_CONFIG_H to all DSP files. #Bit: 256: Exclude projects in SUBDIRS protected by a DEFINITION macro, else include ALL. #Bit: 512: Unconditionally add ANY libraries build, and NOT excluded to the last application #Bit:1024: If NO users conditional, do sustitution, if at all possible, regardless of TRUE or FALSE #Bit:2048: Add User -L dependent libraries to each application #Bit: These can be given as an integer, or the form 2+8, etc. Note using -1 sets ALL bits on. #Bit: Bit 32 really slows down the DSP creation, since it involves scanning every line of the sources. my $auto_max_bit = 512; our $auto_on_flag = -1; #Bit: ALL ON by default = ${$rparams}{'CURR_AUTO_ON_FLAG'} sub get_curr_auto_flag() { return $auto_on_flag; } #my ($g_in_name, $g_in_dir); #my ($root_file, $root_folder); #sub get_root_dir() { return $root_folder; } our $exit_value = 0; # But SOME Makefile.am will use specific 'paths' so the above can FAIL to find # a file, so the following two 'try harder' options, will do a full 'root' # directory SCAN, and search for the file of that name in the scanned files our $try_harder = 0; our $try_much_harder = 0; # ============================================================================== our $process_subdir = 0; our $warn_on_plus = 0; # ============================================================================== # NOTE: Usually a Makefile.am contains SOURCE file names 'relative' to itself, # which is usually without any path. This options ADDS the path to the # Makefile.am, and then substracts the 'root' path, to get a SOURCE file # relative to the 'root' configure.ac, which is what is needed if the DSP # is to be placed in a $target_dir, and we want the file relative to that our $add_rel_sources = 1; our $target_dir = ''; # ============================================================================== our $ignore_EXTRA_DIST = 0; our $added_in_init = ''; our $supp_make_in = 0; # Support Makefile.in scanning our $project_name = ''; # a name to override any ac scanned name of the project ###my $dsp_files_skipped = 0; ### ============================= # offsets into REF_LIB_LIST array our $RLO_MSG = 0; our $RLO_PRJ = 1; our $RLO_VAL = 2; our $RLO_NAM = 3; our $RLO_EXC = 4; ### ============================= my $dsp_out_dir = ''; my $write_cmake_files = 0; my $write_dsp_files = 0; sub get_PATH_SEP() { return $PATH_SEP; } sub get_pgmname() { return $pgmname; } sub get_dsp_out_dir() { return $dsp_out_dir; } sub get_write_cmake_files() { return $write_cmake_files; } sub get_write_dsp_files() { return $write_dsp_files; } ########################################################### my %excluded_files = (); my %excluded_dirs = ( 'CVS' => 1, ".git" => 1, ".svn" => 1, ".hg" => 1, "CMakeFiles" => 1 ); sub is_excluded_file($) { my $fil = shift; my $iret = 0; if ($os =~ /win/i) { my $lcfil = lc($fil); my @arr = keys(%excluded_files); my ($tst,$lctst); foreach $tst (@arr) { $lctst = lc($tst); if ($lcfil eq $lctst) { #prt("Setting EXCLUDED [$fil] [$lcfil]\n"); $iret = 1; last; } } } else { $iret = 1 if (defined $excluded_files{$fil}); } #prt("In exclude [$iret]\n") if($fil eq 'DumpTar-scaps.c'); return $iret; } sub is_excluded_dir($) { my $fil = shift; my $iret = 0; if ($os =~ /win/i) { my $lcfil = lc($fil); my @arr = keys(%excluded_dirs); my ($tst,$lctst); foreach $tst (@arr) { $lctst = lc($tst); if ($lcfil eq $lctst) { $iret = 1; last; } } } else { $iret = 1 if (defined $excluded_dirs{$fil}); } return $iret; } 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 conv_2_cmake($) { my $txt = shift; $txt =~ s/\s/_/g; $txt =~ s/-/_/g; $txt =~ s/__/_/g; return $txt; } sub process_in_file($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; 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 get_short_form($$) { my ($fil1,$fil2) = @_; my $len1 = length($fil1); my $len2 = length($fil2); if ($len1 > $len2) { my ($ch1,$ch2,$i); for ($i = 0; $i < $len2; $i++) { $ch1 = substr($fil1,$i,1); $ch2 = substr($fil2,$i,1); last if ($ch1 ne $ch2); } $fil1 = substr($fil1,$i); $fil1 =~ s/^(\\|\/)//; #prt("Lengths fil1=$len1 and fil2=$len2 - return $fil1\n"); } else { ##prt("Lengths fil1=$len1 and fil2=$len2\n"); } return $fil1; } sub sub_base_dir($) { my $fil1 = shift; my $fil2 = $in_directory; return get_short_form($fil1,$fil2); } sub sub_root_folder($) { my $fil1 = shift; my $fil2 = $in_directory; return get_short_form($fil1,$fil2); } my $dirs_skipped = 0; sub process_in_dir($); sub process_in_dir($) { my $dir = shift; if (! opendir(DIR,$dir)) { pgm_exit(1,"ERROR: Unable to open directory [$dir]!\n"); } my @files = readdir(DIR); closedir(DIR); my ($file,$ff,$sf,$excl); my @dirs = (); ut_fix_directory(\$dir); $total_dirs++; foreach $file (@files) { next if ($file eq '.'); next if ($file eq '..'); $ff = $dir.$file; if (-d $ff) { if (is_excluded_dir($file)) { $dirs_skipped++; } else { push(@dirs,$ff); } } else { next if (is_excluded_file($file)); $sf = sub_base_dir($ff); # if C/C++ source if (is_c_source($file)) { $total_c_files++; $files_found{$ff} = $TYP_C; $c_files_found{$ff} = $sf; } elsif (is_h_source($file)) { $total_h_files++; $h_files_found{$ff} = $sf; $files_found{$ff} = $TYP_H; } elsif ($file =~ /\.rc$/i) { $total_c_files++; $files_found{$ff} = $TYP_RC; $c_files_found{$ff} = $sf; } elsif ($file eq 'Makefile.am') { if ($add_am_files) { $total_am_files++; $am_files_found{$ff} = $TYP_AM; $files_found{$ff} = $TYP_AM; } } else { $files_found{$ff} = 0; } } } foreach $ff (@dirs) { process_in_dir($ff); } } my %files_by_dir = (); sub add_options_block($) { my $type = shift; my $txt = <; close FIL; my ($line,$len,$lncnt,$i,$i2,$tmp,$cnt,$sf); $lncnt = scalar @lines; $sf = sub_base_dir($ff); prt("Doing $lncnt lines from [$sf] "); my @nlines = (); for ($i = 0; $i < $lncnt; $i++) { $i2 = $i + 1; $line = $lines[$i]; chomp $line; $line = trim_all($line); $len = length($line); next if ($len == 0); next if ($line =~ /^\#/); while (($line =~ /\\$/)&&($i2 < $lncnt)) { $line =~ s/\\$//; $line .= ' ' if ($line =~ /\S$/); $i++; $i2 = $i + 1; $tmp = $lines[$i]; chomp $tmp; $tmp = trim_all($tmp); next if ($tmp =~ /^\#/); $line .= $tmp; } push(@nlines,$line); } $cnt = scalar @nlines; prt("reduced to $cnt.\n"); ${$rh}{$ff} = \@nlines; } } sub load_am_file($$) { my ($ff,$rh) = @_; my $rparams = init_common_subs($ff); # note: sets ROOT_FOLDER - where a CMakeLists.txt could be written ${$rparams}{'AM_FILE'} = $ff; am_process_AM_file($rparams,0); ${$rh}{$ff} = $rparams; # keep collection of Makefile.am loaded per file name } # find 'main' or '_tmain' sub chk_for_main($) { my $fil = shift; if (!open FIL,"<$fil") { return 0; } my @lines = ; close FIL; my ($line,$i,$ch,$nc,$pc,$incom,$len,$i2,$lnn,$nline); $incom = 0; $ch = ''; my $got_main = 0; my $msg = ''; my @main = (); my $cnt = chkmain_in_linearray($fil,\@main,\@lines); if ($cnt) { $got_main = 1; my ($fnd,$man,$msg); prt("Found $cnt 'main' references in $fil...\n") if (VERB5()); for ($i = 0; $i < $cnt; $i++) { $fnd = $main[$i][0]; $man = $main[$i][1]; $msg = $main[$i][2]; prt("$fnd $man $msg\n") if (VERB9()); } return $got_main; } $lnn = 0; foreach $line (@lines) { $lnn++; chomp $line; $line = trim_all($line); $len = length($line); next if ($len == 0); next if ($line =~ /^\#/); # 20180215 - Skip directives $ch = ''; $nline = ''; for ($i = 0; $i < $len; $i++) { $i2 = $i + 1; $pc = $ch; $ch = substr($line,$i,1); $nc = ($i2 < $len) ? substr($line,$i2,1) : ''; if ($incom) { $incom = 0 if (($pc eq '*')&&($ch eq '/')); } else { if (($ch eq '/') && ($nc eq '*')) { $incom = 1; } elsif (($ch eq '/') && ($nc eq '/')) { last; # forget this line } # if not in comment, add to $nline $nline .= $ch if (!$incom); #if ($nline =~ /\bmain\b/) { # $got_main = 1; # $msg = "$lnn:$i2: Found 'main' [$nline]\n file [$fil]\n"; # last; if ($nline =~ /\b_tmain\b/) { $got_main = 1; $msg = "$lnn:$i2: Found '_tmain' [$nline]\n file [$fil]\n"; last; } elsif ($nline =~ /\bDllMain\b/) { $got_main = 2; $msg = "$lnn:$i2: Found 'DllMain' [$nline]\n file [$fil]\n"; last; } elsif ($nline =~ /\bWinMain\b/) { $got_main = 4; $msg = "$lnn:$i2: Found 'WinMain' [$nline]\n file [$fil]\n"; last; } elsif ($nline =~ /\bCWinApp\b/) { $got_main = 4; $msg = "$lnn:$i2: Found 'CWinApp' [$nline]\n file [$fil]\n"; last; } } } last if ($got_main); } if (length($msg) && VERB9()) { prt($msg); } return $got_main; } sub process_files_found() { my $libcmake = ''; my $execmake = ''; my $rcmake = \$libcmake; my @files = sort keys(%files_found); my $cnt = scalar @files; prt("From $total_dirs directories scanned, skipped $dirs_skipped, found $cnt files... C/C++=$total_c_files, Hdrs=$total_h_files,am=$total_am_files\n"); my ($ff,$type,$n,$d,$ra,$i,$name,$dir,$sf,$ccnt,$hcnt,$var1,$var2,$got_main,$gm,$tmp); my ($nm,$dr,$dcnt,$do,$sd,$msg); my $ind = ' '; my $min_len = 40; my $opt_list = ''; foreach $ff (@files) { $sf = path_d2u(sub_base_dir($ff)); $type = $files_found{$ff}; ($n,$d) = fileparse($ff); $files_by_dir{$d} = [] if (!defined $files_by_dir{$d}); $ra = $files_by_dir{$d}; my %h = (); $got_main = 0; if ($type == $TYP_AM) { # skip for now as info NOT yet used ### load_am_file($ff,\%h) } elsif ($type == $TYP_C) { $got_main = chk_for_main($ff); prt("Found 'main' in [$ff] [$sf]\n") if ($got_main && VERB5()); } # 0 1 2 3 4 push(@{$ra},[$n,$type,$sf,\%h,$got_main]); } # eliminate directories with NO source files $cnt = scalar keys(%files_by_dir); prt("Sorted into $cnt sub-directories...\n"); my @elim = (); my @carr = (); my @harr = (); my @rcarr = (); foreach $d (keys %files_by_dir) { $ra = $files_by_dir{$d}; $cnt = scalar @{$ra}; $do = $d; $d =~ s/(\\|\/)$//; ($name,$dir) = fileparse($d); @carr = (); @harr = (); @rcarr = (); $got_main = 0; for ($i = 0; $i < $cnt; $i++) { $n = ${$ra}[$i][0]; $type = ${$ra}[$i][1]; $sf = ${$ra}[$i][2]; #$rh = ${$ra}[$i][3]; if ($type == $TYP_C) { push(@carr,$sf); } elsif ($type == $TYP_H) { push(@harr,$sf); } elsif ($type == $TYP_RC) { push(@rcarr,$sf); } elsif ($type == $TYP_AM) { #$rh = load_am_file( } } $ccnt = scalar @carr; $ccnt += scalar @harr; $ccnt += scalar @rcarr; push(@elim,$do) if ($ccnt == 0); } foreach $do (@elim) { delete $files_by_dir{$do}; } $cnt = scalar keys(%files_by_dir); $dcnt = $cnt; prt("\nRemaining $dcnt sub-directories...\n"); my %unique = (); my $ucnt = 0; my $exetyp = ''; my $isexe = 0; my $tot_libs = 0; my $tot_exes = 0; foreach $d (keys %files_by_dir) { $ra = $files_by_dir{$d}; $cnt = scalar @{$ra}; $d =~ s/(\\|\/)$//; ($name,$dir) = fileparse($d); $sd = sub_root_folder($d); @carr = (); @harr = (); @rcarr = (); $got_main = 0; for ($i = 0; $i < $cnt; $i++) { $n = ${$ra}[$i][0]; $type = ${$ra}[$i][1]; $sf = ${$ra}[$i][2]; #$rh = ${$ra}[$i][3]; $gm = ${$ra}[$i][4]; if ($type == $TYP_C) { push(@carr,$sf); } elsif ($type == $TYP_H) { push(@harr,$sf); } elsif ($type == $TYP_RC) { push(@rcarr,$sf); } elsif ($type == $TYP_AM) { #$rh = load_am_file( } } $ccnt = scalar @carr; $hcnt = scalar @harr; if (@carr) { $isexe = 0; $got_main = 0; $tmp = 'no main'; $exetyp = ''; for ($i = 0; $i < $cnt; $i++) { $type = ${$ra}[$i][1]; if ($type == $TYP_C) { $gm = ${$ra}[$i][4]; if ($gm & 1) { $tmp = 'GOT MAIN'; $got_main = $gm; $isexe = 1; last; } elsif ($gm & 2) { $tmp = 'GOT DLLMAIN'; $got_main = $gm; last; } elsif ($gm & 4) { $tmp = 'GOT WINMAIN'; $got_main = $gm; $exetyp = 'WIN32'; $isexe = 1; last; } } } prt("Processing directory [$d] $tmp [$got_main]\n") if (VERB2()); if ($ccnt == 1) { # 20141130: just ONE source file - instead of naming by the folder name, # use the name of that 1 source... $sf = $carr[0]; ($name,$dr,$nm) = fileparse($sf, qr/\.[^.]*/); } # keep libraries and executables SEPARATE - ouput LIBS first, then EXES if (($got_main & 1)||($got_main & 4)) { $rcmake = \$execmake; } else { $rcmake = \$libcmake; } $name = 'tester' if ($name =~ /^test$/i); # =========================================== # 20141209 - Make sure 'name' is unique if (defined $unique{$name}) { $ucnt = 1; my $tname = $name.$ucnt; while (defined $unique{$tname}) { $ucnt++; $tname = $name.$ucnt; } $name = $tname; } $unique{$name} = 1; # =========================================== ${$rcmake} .= "\n# $name "; if ($isexe) { # (got_main & 1)||($got_main & 4)) ${$rcmake} .= "EXECUTABLE"; } else { ${$rcmake} .= "LIBRARY"; if ($got_main & 2) { ${$rcmake} .= " SHARED(DLL)"; } } ${$rcmake} .= " from [$sd],\n"; ${$rcmake} .= "# have $ccnt C/C++ sources,"; if (@rcarr) { ${$rcmake} .= " ".scalar @rcarr." rc,"; } ${$rcmake} .= " $hcnt headers"; ${$rcmake} .= "\n"; ################################### my $opt = "ADD_".uc($name); $opt =~ s/-/_/g; if ($add_options) { ${$rcmake} .= "if ($opt)\n"; $opt_list .= "option( $opt \"Set ON to build this component\" OFF )\n"; } # SET name and directory ${$rcmake} .= "set(name ${name})\n"; $sf = $carr[0]; ($nm,$dr) = fileparse($sf); $dr =~ s/(\\|\/)$//; ${$rcmake} .= "set(dir $dr)\n"; ################################### if ($dcnt == 1) { $sf = $carr[0]; #($nm,$dr) = fileparse($sf); #$dr =~ s/(\\|\/)$//; #${$rcmake} .= "set(dir $dr)\n"; $var1 = "\$\{name\}_SRCS"; ${$rcmake} .= "set($var1\n"; foreach $sf (@carr) { ($nm,$dr) = fileparse($sf); ${$rcmake} .= $ind."\$\{dir\}/$nm\n"; } # 20120731 - Add *.rc files to SOURCES! foreach $sf (@rcarr) { ($nm,$dr) = fileparse($sf); ${$rcmake} .= $ind."\$\{dir\}/$nm\n"; } ${$rcmake} .= $ind.")\n"; } else { $var1 = "\$\{name\}_SRCS"; ${$rcmake} .= "set($var1\n"; foreach $sf (@carr) { #${$rcmake} .= " $sf\n"; ($nm,$dr) = fileparse($sf); ${$rcmake} .= $ind."\$\{dir\}/$nm\n"; } # 20120731 - Add *.rc files to SOURCES! foreach $sf (@rcarr) { #${$rcmake} .= " $sf\n"; ($nm,$dr) = fileparse($sf); ${$rcmake} .= $ind."\$\{dir\}/$nm\n"; } ${$rcmake} .= $ind.")\n"; } $var2 = ''; if (@harr) { $var2 = "\$\{name\}_HDRS"; if ($dcnt == 1) { ${$rcmake} .= "set($var2\n"; foreach $sf (@harr) { ($nm,$dr) = fileparse($sf); ${$rcmake} .= $ind."\$\{dir\}/$nm\n"; } ${$rcmake} .= $ind.")\n"; } else { $var2 = "\$\{name\}_HDRS"; ${$rcmake} .= "set($var2\n"; foreach $sf (@harr) { #${$rcmake} .= " $sf\n"; ($nm,$dr) = fileparse($sf); ${$rcmake} .= $ind."\$\{dir\}/$nm\n"; } ${$rcmake} .= $ind.")\n"; } } if ($isexe) { # ($got_main & 1)||($got_main & 4) $tot_exes++; $msg = "Adding EXECUTABLE for [$name],"; $msg .= ' ' while (length($msg) < $min_len); $msg .= " in $sd."; prt("$msg\n"); ${$rcmake} .= "add_executable( \$\{name\} "; ${$rcmake} .= " $exetyp " if (length($exetyp)); if ($dcnt == 1) { ${$rcmake} .= "\$\{$var1\} "; ${$rcmake} .= "\$\{$var2\} " if (length($var2)); ${$rcmake} .= ")\n"; ${$rcmake} .= "if (add_LIBS)\n"; ${$rcmake} .= $ind."target_link_libraries( \$\{name\} \${add_LIBS} )\n"; ${$rcmake} .= "endif ()\n"; ${$rcmake} .= "if (MSVC)\n"; ${$rcmake} .= $ind."set_target_properties( \$\{name\} PROPERTIES DEBUG_POSTFIX d )\n"; ${$rcmake} .= "endif ()\n"; } else { ${$rcmake} .= "\${$var1} "; ${$rcmake} .= "\${$var2} " if (length($var2)); ${$rcmake} .= ")\n"; ${$rcmake} .= "if (add_LIBS)\n"; ${$rcmake} .= $ind."target_link_libraries( \$\{name\} \${add_LIBS} )\n"; ${$rcmake} .= "endif ()\n"; ${$rcmake} .= "if (MSVC)\n"; ${$rcmake} .= $ind."set_target_properties( \$\{name\} PROPERTIES DEBUG_POSTFIX d )\n"; ${$rcmake} .= "endif ()\n"; } ${$rcmake} .= "# deal with install, if any...\n"; ${$rcmake} .= "#install( TARGETS \$\{name\} DESTINATION bin )\n"; } else { $tot_libs++; $msg = "Adding LIBRARY for [$name],"; $msg .= ' ' while (length($msg) < $min_len); $msg .= " in $sd."; prt("$msg\n"); if ($dcnt == 1) { ${$rcmake} .= "add_library( \$\{name\} \$\{LIB_TYPE\} \$\{$var1\} "; ${$rcmake} .= "\$\{$var2\} " if (length($var2)); ${$rcmake} .= ")\n"; } else { ${$rcmake} .= "add_library( \$\{name\} "; if ($got_main & 2) { ${$rcmake} .= "SHARED "; } ${$rcmake} .= "\${$var1} "; ${$rcmake} .= "\${$var2} " if (length($var2)); ${$rcmake} .= ")\n"; } ${$rcmake} .= "list(APPEND add_LIBS \$\{name\})\n"; ${$rcmake} .= "# deal with install, if any...\n"; ${$rcmake} .= "#install( TARGETS \$\{name\}\n"; ${$rcmake} .= "#".$ind."RUNTIME DESTINATION bin\n"; ${$rcmake} .= "#".$ind."LIBRARY DESTINATION lib\n"; ${$rcmake} .= "#".$ind."ARCHIVE DESTINATION lib )\n"; ${$rcmake} .= "#install(FILES \$\{\$\{name\}_HDRS\} DESTINATION include)\n"; ###${$rcmake} .= "list(APPEND add_LIBS \$\{name\})\n"; } if ($add_options) { ${$rcmake} .= "endif ($opt)\n"; } } } my $cmake = ''; ############################################## if ($add_options) { if (length($opt_list) > 0) { $cmake .= "\n"; $cmake .= $opt_list; $cmake .= "\n"; } else { prtw("WARNING: Got add options, -O, but no list created!\n"); } } ############################################# $cmake .= "# Total libs $tot_libs, exes $tot_exes\n"; $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 .= "#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 .= "##### EXECUTABLE $tot_exes #####\n"; $cmake .= "#################################################\n"; if (length($execmake)) { $cmake .= $execmake; } else { $cmake .= "# install( TARGETS \$\{name\} DESTINATION bin )\n"; } if (length($cmake)) { $var1 = get_cmake_root(); $cmake = $var1.$cmake."\n\n# eof\n"; #if (length($out_file) == 0) { # $out_file = $tmp_cmake_list; # prt("Setting DEFAULT ouput file, since no -o given!\n"); #} rename_2_old_bak($out_file); write2file($cmake,$out_file); prt("CMake string written to [$out_file]\n"); } } ######################################### ### MAIN ### parse_args(@ARGV); process_in_dir($in_directory); process_files_found(); pgm_exit(0,""); ######################################## my $in_input = 0; sub set_excluded_files($) { my $arg = shift; my @arr = split(';',$arg); my ($fil); my $cnt = 0; foreach $fil (@arr) { $excluded_files{$fil} = 1; $cnt++; } prt("Add $cnt files to excluded list\n") if (VERB1()); if (VERB9()) { prt("Excluded file list is [".join(" ",@arr)."]\n"); } } sub set_excluded_dirs($) { my $arg = shift; my @arr = split(';',$arg); my ($fil); my $cnt = 0; foreach $fil (@arr) { $excluded_dirs{$fil} = 1; $cnt++; } prt("Add $cnt directories to excluded list\n") if (VERB1()); if (VERB9()) { prt("Excluded dir list is [".join(" ",@arr)."]\n"); } } sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub load_input_file($) { my $file = shift; if (!open INP, "<$file") { pgm_exit(1,"ERROR: Unable to open input file [$file]\n"); } my @lines = ; close INP; my @lnarr = (); my ($line,$len,@arr,$itm); my @args = (); foreach $line (@lnarr) { chomp $line; $len = trim_all($line); next if ($len == 0); next if ($line =~ /^\s*\#/); @arr = space_split($line); foreach $itm (@arr) { last if ($itm =~ /^\#/); # skip trailing comments $itm = strip_quotes($itm); # strip any quotes push(@args,$itm); } } if (@args) { $in_input++; parse_args(@args); $in_input--; } } sub parse_args { my (@av) = @_; my ($arg,$sarg,@arr,$len); 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 =~ /^i/) { need_arg(@av); shift @av; $sarg = $av[0]; load_input_file($sarg); } elsif ($sarg =~ /^I/) { $add_extra_info = 1; } 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 =~ /^lll/) { $load_log = 3; } elsif ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if (VERB1()); } elsif ($sarg =~ /^n/) { need_arg(@av); shift @av; $sarg = $av[0]; $proj_title = $sarg; prt("Set project name to [$proj_title].\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 =~ /^x/) { need_arg(@av); shift @av; $sarg = $av[0]; set_excluded_files($sarg); } elsif ($sarg =~ /^X/) { need_arg(@av); shift @av; $sarg = $av[0]; set_excluded_dirs($sarg); } 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_pts = $arr[2]; $ver_msg = "check me"; prt("Set version to '$ver_maj.$ver_min.$ver_pts\n") if (VERB1()); } elsif ($sarg =~ /^a/) { need_arg(@av); shift @av; $sarg = $av[0]; push(@add_inc_dirs,$sarg); } elsif ($sarg =~ /^O/) { $add_options = 1; prt("Set to add options around each component.\n") if (VERB1()); } elsif ($sarg =~ /^F/) { $add_fatal_insrc = 0; prt("Turned OFF the fatal in-source build check.\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 { $in_directory = File::Spec->rel2abs($arg); prt("Set input to [$in_directory]\n") if (VERB1()); } shift @av; } if ($in_input) { return; } if ((length($in_directory) == 0) && $debug_on) { $in_directory = $def_dir; prt("Set DEFAULT input to [$in_directory]\n"); $load_log = 2; } #if ((length($out_file) == 0) && $debug_on) { # $out_file = $tmp_cmake_list; #} if (length($in_directory) == 0) { pgm_exit(1,"ERROR: No input directory found in command!\n"); } if (! -d $in_directory) { pgm_exit(1,"ERROR: Unable to find directory [$in_directory]! Check name, location...\n"); } if (length($proj_title) == 0) { my $tmp = $in_directory; $tmp =~ s/(\\|\/)$//; my ($n,$d) = fileparse($tmp); $proj_title = conv_2_cmake($n); prt("Set DEFAULT project name to [$proj_title]\n"); } if (length($target_dir) == 0) { $target_dir = $in_directory; prt("Set DEFAULT target to [$target_dir]\n"); } } sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] in-directory\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --add incdir (-a) = Add these include directories to cmake.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. (def=$verbosity)\n"); prt(" --VERSION (-V) = Give version in dot.sep.form, maj.min.pts, like 1.2.3, to use in CMakeLists.txt.\n"); prt(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --input (-i) = Take commands from an input (response) file.\n"); prt(" --Info (-I) = Add extra information to cmake file.\n"); prt(" --Fatal (-F) = Do NOT add the fatal in-source build check. (def=$add_fatal_insrc)\n"); prt(" --Static (-S) = Do NOT add the static runtime option. (def=$add_static_runtime)\n"); prt(" --name (-n) = Set 'project' name, otherwise name of directory will be used.\n"); prt(" --defs (-d) = Add definitions to CMakeLists.txt\n"); prt(" --out (-o) = Write output to this file. Any existing file will be renamed old/bak.\n"); prt(" Def=$out_file\n"); prt(" --OPTIONS (-O) = Add an 'option' if (ADD_) around each component.\n"); prt(" --xclude (-x) = Semicolon separated list of files to exclude.\n"); prt(" --Xclude (-X) = Semicolon separated list of directories to exclude.\n"); prt("\n"); prt(" Given a input sources directory, and sub-directories, find all source files, and\n"); prt(" attempt to guess at what to build. The root CMakeLists.txt generated may need manual fixing\n"); } # eof - gencmake.pl