#!/usr/bin/perl ############################################################################ # # # Creates a Makefile from a template and a project file. # # Copyright (C) 1996-1998 by Troll Tech AS. All rights reserved. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, provided # that this copyright notice appears in all copies. # No representations are made about the suitability of this software for any # purpose. It is provided "as is" without express or implied warranty. # # # Some important, global variables in tmake: # cpp_ext C++ extension added to moc output (.cpp) # obj_ext Object file extension (.o on Unix, .obj otherwise) # moc_aware Will scan for files containing Qt signals/slots # moc_pre Moc prefix for generated moc file: x.h -> moc_x.cpp # moc_ext Moc extension for generated moc file: x.cpp -> x.moc # moc_cmd The moc command in your makefile, $(MOC) # linebreak Line break character (\) # dir_sep Directory separator (/ on Unix, \ on Windows) # is_unix Autodetected. If not Unix, assume Windows (Win32). # # If you need to customize any of these settings, do it before # calling StdInit() in the template file. # ############################################################################ $TMAKE_VERSION = "1.3"; if ($] < 5.0) { &tmake_error("This program requires perl version 5 or newer"); } $cpp_ext = "cpp"; $moc_aware = 0; $moc_pre = "moc_"; $moc_ext = "moc"; $moc_cmd = '$(MOC)'; $linebreak = "\\"; $really_unix = &check_unix(); $is_unix = $really_unix; $dir_sep = $is_unix ? "/" : "\\"; $obj_ext = $is_unix ? "o" : "obj"; $depend_path = ""; $nodepend = 0; $output_count = 0; $notrim_whitespace = 0; $read_tmakeconf = 0; $template_name = ""; $project_name = ""; $outfile = ""; %project = (); $eval_quit = 0; $project{"TMAKEPATH"} = $ENV{"TMAKEPATH"} . ";" . $ENV{"HOME"} . "/.tmake/"; while ( @ARGV ) { # parse command line args $_ = shift @ARGV; if ( s/^-// ) { if ( /^e(.*)/ ) { if ( ! $read_tmakeconf ) { $read_tmakeconf = 1; &ScanProject( &find_template("tmake.conf") ); } $text = ""; eval( ($1 eq "") ? shift @ARGV : $1 ); die $@ if $@; print $text . "\n" if ($text ne ""); $eval_quit = 1; } elsif ( /^t(.*)/ ) { $template_name = ($1 eq "") ? shift @ARGV : $1; } elsif ( /^o(.*)/ ) { $outfile = ($1 eq "") ? shift @ARGV : $1; ($outfile eq "-") && ($outfile = ""); if ( $outfile ne "" ) { open(STDOUT,">" . fix_path($outfile)) || &tmake_error("Can't create \"$outfile\""); } } elsif ( /^p(.*)/ ) { # # The -p option is obsolete and will be removed in the next # tmake release. # &tmake_warning( "-p option obsolete, instead use \"tmake file1.pro file2.pro ...\""); my($pf) = ($1 eq "") ? shift @ARGV : $1; if ( ! $read_tmakeconf ) { $read_tmakeconf = 1; &ScanProject( &find_template("tmake.conf") ); } if ( ! ($pf =~ /\.pro$/i) && -f fix_path($pf . ".pro") ) { $pf .= ".pro"; } if ( $project_name eq "" ) { $project_name = $pf; $project{"PROJECT"} = $project_name; $project{"PROJECT"} =~ s/\.pro$//i; $project{"TARGET"} = $project{"PROJECT"}; } if ( !&ScanProject($pf) ) { &tmake_error("Can't open project file \"$pf\""); } } elsif ( /^unix$/ ) { $is_unix = 1; $dir_sep = "/"; $obj_ext = "o"; } elsif ( /^win32$/ ) { $is_unix = 0; $dir_sep = "\\"; $obj_ext = "obj"; } elsif ( /^nodepend$/ ) { $nodepend = 1; # don't generate dependencies } elsif ( /^v$/ ) { $verbose = 1; } else { &tmake_usage(); } } elsif ( /^\s*((?:[^:\s]*?:)?)(\w+)\s*(\+=|\*=|\-=|\/=|=)/ ) { if ( ! $read_tmakeconf && ! (/^\s*TMAKEPATH/) ) { $read_tmakeconf = 1; &ScanProject( &find_template("tmake.conf") ); } Project( $_ ); # manual project setting } else { my($pf) = $_; if ( ! $read_tmakeconf ) { $read_tmakeconf = 1; &ScanProject( &find_template("tmake.conf") ); } if ( ! ($pf =~ /\.pro$/i) && -f fix_path($pf . ".pro") ) { $pf .= ".pro"; } if ( $project_name eq "" ) { $project_name = $pf; $project{"PROJECT"} = $project_name; $project{"PROJECT"} =~ s/\.pro$//i; $project{"TARGET"} = $project{"PROJECT"}; } if ( !&ScanProject($pf) ) { &tmake_error("Can't open project file \"$pf\""); } } } &tmake_verb("Version $TMAKE_VERSION (runtime environment: " . ($really_unix ? "Unix" : "Win32") . ")\n" ); if ( $eval_quit ) { &tmake_verb("Done!"); exit 0; } ($project_name eq "") && &tmake_usage(); if ( $template_name eq "" ) { $template_name = $project{"TEMPLATE"} ? $project{"TEMPLATE"} : "default.t"; } $template_name = &find_template($template_name); &IncludeTemplate($template_name); &tmake_verb("Done!"); exit 0; # finished! ############################################################################## # Subroutines from here ############################################################################## # # tmake_usage() # # Prints a message about program usage and exits # sub tmake_usage { print STDERR "Usage:\n tmake [options] project-files\n"; print STDERR "Options:\n"; print STDERR " -e expr Evaluate expression, ignore template file\n"; print STDERR " -nodepend Don't generate dependency information\n"; print STDERR " -o file Write output to file\n"; print STDERR " -t file Specify a template file\n"; print STDERR " -unix Create output for Unix (auto detects)\n"; print STDERR " -v Verbose/debug mode\n"; print STDERR " -win32 Create output for Win32 (auto detects)\n"; exit 1; } # # tmake_error(msg) # # Prints the message and exits # sub tmake_error { my($msg) = @_; print STDERR "tmake error: " . $msg . "\n"; exit 1; } # # tmake_warning(msg) # # Prints the warning message # sub tmake_warning { my($msg) = @_; print STDERR "tmake warning: " . $msg . "\n"; } # # tmake_verb() # # Prints a verbose message # sub tmake_verb { my($msg) = @_; $verbose && print STDERR "tmake: " . $msg . "\n"; } # # check_unix() # # Returns 1 if this is a Unix, 0 otherwise. # sub check_unix { my($r); $r = 0; if ( -f "/bin/uname" ) { $r = 1; (-f "\\bin\\uname") && ($r = 0); } if ( -f "/usr/bin/uname" ) { $r = 1; (-f "\\usr\\bin\\uname") && ($r = 0); } return $r; } # # find_template(filename) # # Looks for the template file. # 1. search the current directory # 2. search the directories in TMAKEPATH # 3. search in $HOME/.tmake # sub find_template { my($filename) = @_; my($tb,$d,$p,@dirs); if ( !defined($template_base) || ($template_base eq "") ) { $tb = ""; } else { $tb = $template_base . ";"; } $d = $tb . $project{"TMAKEPATH"}; @dirs = (""); push @dirs, &split_path( $d ); $filename .= ".t" unless ($filename =~ /\.\w+$/); for $d ( @dirs ) { $p = $d . $filename; if ( -f fix_path($p) ) { if ( $filename eq "tmake.conf" ) { $tmake_platform = $d; $tmake_platform =~ s-.*[/\\]([^/\\]*)[/\\]-$1-; &tmake_verb("Detected platform $tmake_platform"); } return $p; } return ($d . $filename) if ( -f fix_path($d . $filename) ); } &tmake_error("Template file " . $filename . " not found"); } ############################################################################## # User functions ############################################################################## # # StdInit() # # Standard initialization # sub StdInit { my($p); return if $stdinit_done; $stdinit_done = 1; if ( defined($project{"OBJECTS_DIR"}) ) { $project{"OBJECTS_DIR"} = FixPath($project{"OBJECTS_DIR"}); &mkdirp($project{"OBJECTS_DIR"},0777); } if ( defined($project{"MOC_DIR"}) ) { $project{"MOC_DIR"} = FixPath($project{"MOC_DIR"}); &mkdirp($project{"MOC_DIR"},0777); } if ( defined($project{"DESTDIR"}) ) { $project{"DESTDIR"} = FixPath($project{"DESTDIR"}); &mkdirp($project{"DESTDIR"},0777); } $project{"OBJECTS"} = &Objects($project{"SOURCES"}); if ( $moc_aware ) { $project{"_HDRMOC"} = &list_moc($project{"HEADERS"},$moc_pre,$cpp_ext); $project{"_SRCMOC"} = &list_moc($project{"SOURCES"},"",$moc_ext); $project{"OBJMOC"} = &Objects($project{"_HDRMOC"}); $p = $project{"_HDRMOC"} . " " . $project{"_SRCMOC"}; $p =~ s/(^\s+|\s+$)//g; $project{"SRCMOC"} = $p; } &AddIncludePath(""); } sub FixPath { my($p) = @_; if ( !defined($p) || ($p eq "") || ($p eq ".") ) { $p = ""; } else { $p .= $dir_sep; $p =~ s-[\\/]+-${dir_sep}-g; } return $p; } # # Config(name) # # Returns true if the project variable CONFIG contains the # configuration name. # sub Config { my($name) = @_; return $project{"CONFIG"} =~ /\b\Q$name\E\b/; } # # DisableOutput() # # Disables tmake output. Must be restored by calling a corresponding # EnableOutput(). # sub DisableOutput { $output_count++; } # # EnableOutput() # # Enables tmake output again after DisableOutput() has been called. # sub EnableOutput { $output_count--; } # # Now() - sets $text # # Sets $text to the current date and time. # sub Now { my($sec,$min,$hour,$mday,$mon,$year); ($sec,$min,$hour,$mday,$mon,$year) = localtime(time()); $text = sprintf("%02d:%02d, %4d/%02d/%02d", $hour, $min, 1900+$year, 1+$mon, $mday); } # # expand_project_var(var) # # Internal function for Project(). # Expands a project value string. # sub expand_project_var { my($v) = @_; my($c); return "" if !defined($v); $c = 0; while ( $c < 100 ) { # expand $$ if ( $v =~ s/(\$\$\w+)/\035/ ) { $_ = $1; s/\$\$//g; if ( !defined($project{$_}) ) { $v =~ s/\035//g; } else { $v =~ s/\035/$project{$_}/g; } $c++; } else { $c = 100; } } return $v; } # # Project(strings) # # This is a powerful function for setting or reading project variables. # Returns the resulting project variables (joined with space between). # # Get a project variable: # $s = Project("TEMPLATE"); -> $s = "TEMPLATE" # # Set a project variable: # Project("TEMPLATE = lib"); -> TEMPLATE = lib # Project("CONFIG =";) -> CONFIG empty # # Append to a project variable: # Project("CONFIG = qt"); -> CONFIG = qt # Project("CONFIG += debug"); -> CONFIG = qt debug # # Append to a project variable if it does not contain the value already: # Project("CONFIG = qt release"); -> CONFIG = qt release # Project("CONFIG *= qt"); -> CONFIG = qt release # Project("CONFIG *= opengl"); -> CONFIG = qt release opengl # # Subtract from a project variable: # Project("THINGS = abc xyz"); -> THINGS = abc xyz # Project("THINGS -= abc"); -> THINGS = xyz # # Search/replace on a project variable: # Project("CONFIG = tq opengl"); -> CONFIG = tq opengl # Project("CONFIG /= s/tq/qt/"); -> CONFIG = qt opengl # # The operations can be performed on several project variables at a time. # # Project("TEMPLATE = app", "CONFIG *= opengl", "THINGS += klm"); # sub Project { my @settings = @_; my($r,$if_var,$t,$s,$v,$p,$c); $r = ""; foreach ( @settings ) { $v = $_; if ( $v =~ s/^\s*([^:\r\n]+:)?(\w+)\s*(\+=|\*=|\-=|\/=|=)// ) { $if_var = $1; if ( $if_var ne "" ) { chop $if_var; if ( $if_var eq "unix" ) { return "" if !$is_unix; } elsif ( $if_var eq "win32" ) { return "" if $is_unix; } elsif ( ($if_var ne $tmake_platform) && !Config($if_var) ) { return ""; } } $t = $2; $s = $3; if ( ! $notrim_whitespace ) { $v =~ s/^\s+//; # trim white space $v =~ s/\s+$//; } $v = expand_project_var($v); $p = $project{$t}; if ( $s ne "=" && $v eq "" ) { # nothing to append, subtract or sed } elsif ( $s eq "=" ) { # set variable $p = $v; } elsif ( $s eq "+=" ) { # append if ( $p eq "" ) { $p = $v; } else { $p .= " " . $v; } } elsif ( $s eq "*=" ) { # append if not contained if ( !($p =~ /(?:^|\s)\Q$v\E(?:\s|$)/) ) { if ( $p eq "" ) { $p = $v; } else { $p .= " " . $v; } } } elsif ( $s eq "-=" ) { # subtract $p =~ s/$v//g; } elsif ( $s eq "/=" ) { # sed $cmd = '$p =~ ' . $v; eval $cmd; } $project{$t} = expand_project_var($p); } else { $p = expand_project_var($project{$v}); } if ( $p ne "" ) { $r = ($r eq "") ? $p : ($r . " " . $p); } } return $r; } # # Substitute(string) # # This function substitutes project variables in a text. # # Example: # Substitute('The project name is "$$PROJECT"') # sub Substitute { my($subst) = @_; $text = expand_project_var($subst); return $text; } # # ScanProject(file) # # Scans a project file. Inserts project variables into the global # associative project array. # sub ScanProject { my($file) = @_; my($var,$val,@v,$more,$line,$endmark); $var = ""; $line = 0; open(TMP,fix_path($file)) || return 0; &tmake_verb("Reading the project file $file"); while ( ) { $line++; s/\#.*//; # strip comment s/^\s+//; # strip white space s/\s+$//; if ( /^(([^:\r\n]+:)?\w+\s*(\+|\-|\*|\/)?=)/ ) { $var = $1; # var also contains the ".=" s/^.*?=\s*//; if ( /^\<\<(.*)$/ ) { $endmark = $1; $val = ""; while ( ) { $line++; if ( /^\Q$endmark\E$/ ) { $endmark = ""; last; } $val .= $_; } if ( $endmark ne "" ) { tmake_error("$file:$line: End marker $endmark not found"); } chop $val if ( $val ne "" ); $notrim_whitespace++; Project( $var . $val ); $notrim_whitespace--; $var = ""; $_ = ""; } } if ( $var ne "" ) { $more = ( $_ =~ s/\s*\\\s*$// ); # more if \ at end of line push( @v, split( /\s+/, $_ ) ); if ( ! $more ) { $val = join(" ",@v); Project( $var . $val ); $var = ""; @v = (); } } elsif ( $_ ne "" ) { tmake_error("$file:$line: Syntax error"); } } close(TMP); &tmake_verb("Done reading the project file $file"); return 1; } # # IncludeTemplate(template_name) # # Includes and processes a template file. # # Below, we read the template file and executes any perl code found. # Perl code comes after "#$". The variable $text contains the text # to replace the perl code that was executed. # Template comments begin with "#!". # sub IncludeTemplate { my($t_name) = @_; my($cmd,$cmd_block,$cmd_end,$is_cmd_block,$saveline,$spaceonly); local($text); local(*T); $t_name = &find_template($t_name); if ( $tmake_template_dict{$t_name} ) { &tmake_error("Cyclic template inclusion for $t_name"); } else { $tmake_template_dict{$t_name} = 1; } $template_base = $t_name; $template_base =~ s-(.*[/\\]).*-$1-; &tmake_verb("Reading the template $t_name"); open(T,fix_path($t_name)) || &tmake_error("Can't open template file \"$t_name\""); while ( ) { if ( /\#\!/ ) { # tmake comment s/\s*\#\!.*//; next if /^$/; } if ( /\#\$(\{)?\s*(.*)\n/ ) { # code $cmd = $2; $is_cmd_block = defined($1) && ($1 eq "{"); s/\#\$.*\n//; if ( $is_cmd_block ) { # code block #${ ... $saveline = $_; $cmd_block = $cmd; $cmd_end = 0; while ( ) { $cmd = $_; $cmd =~ s/\s*\#\!.*//; # tmake comment if ( $cmd =~ /^\s*\#\$\}/ ) { $_ = ""; $cmd_end = 1; last; } $cmd =~ s/^\s*\#(\$)?\s*//; $cmd_block .= $cmd; } $cmd_end || &tmake_error('#$} expected but not found'); $cmd = $cmd_block; $_ = $saveline; } $spaceonly = /^\s*$/; $saveline = $_; &tmake_verb("Evaluate: $cmd"); $text = ""; eval $cmd; die $@ if $@; next if $spaceonly && ($text =~ /^\s*$/); print $saveline . $text . "\n" if $output_count <= 0; } else { # something else print if $output_count <= 0; } } close( T ); } # # Expand(var) - appends to $text # # Expands a list of $project{} variables with a space character between them. # sub Expand { my @vars = @_; my($t); $t = Project(@vars); if ( $text eq "" ) { $text = $t; } elsif ( $t ne "" ) { $text .= " " . $t; } return $text; } # # ExpandGlue(var,prepend,glue,append) - appends to $text # # Expands a $project{} variable, splits on whitespace # and joins with $glue. $prepend is put at the start # of the string and $append is put at the end of the # string. The resulting string becomes "" if the project # var is empty or not defined. # # Example: # # The project file defines: # SOURCES = a b c # # ExpandGlue("SOURCES","<","-",">") # # The result: # $text = "" # sub ExpandGlue { my($var,$prepend,$glue,$append) = @_; my($t,$v); $v = Project($var); if ( $v eq "" ) { $t = ""; } else { $t = $prepend . join($glue,split(/\s+/,$v)) . $append; } if ( $text eq "" ) { $text = $t; } elsif ( $t ne "" ) { $text .= " " . $t; } return $text; } # # ExpandList(var) - sets $text. # # Suitable for expanding HEADERS = ... etc. in a Makefile # sub ExpandList { my($var) = @_; return ExpandGlue($var,""," ${linebreak}\n\t\t",""); } # # ExpandPath(var,prepend,glue,append) - appends to $text # # Expands a $project{} variable, splits on either ';' or # whitespace and joins with $glue. $prepend is put at the # start of the string and $append is put at the end of the # string. The resulting string becomes "" if the project # variable is empty or not defined. # # If the variable contains at least one semicolon or tmake # is running on Windows, the resulting items are put in # double-quotes. # # Example: # # The project file defines: # INCLUDEPATH = "C:\qt\include;c:\program files\msdev\include # # ExpandGlue("INCLUDEPATH","-I","-I","") # # The result: # $text = -I"c:\qt\include" -I"c:\program files\msdev\include" # sub ExpandPath { my($var,$prepend,$glue,$append) = @_; my($t,$v); my($s); $v = Project($var); if ( $v eq "" ) { $t = ""; } else { if ( $v =~ /;/ || !$is_unix ) { $prepend .= '"'; $glue = '"' . $glue . '"'; $append = '"' . $append; } if ( $v =~ /;/ ) { $t = $prepend . join($glue,split(/;+/,$v)) . $append; } else { $t = $prepend . join($glue,split(/\s+/,$v)) . $append; } } if ( $text eq "" ) { $text = $t; } elsif ( $t ne "" ) { $text .= " " . $t; } return $text; } # # TmakeSelf() # # Generates makefile rule to regenerate the makefile using tmake. # sub TmakeSelf { my $a = "tmake $project_name"; if ( $nodepend ) { $a .= " -nodepend"; } if ( $outfile ) { $text = "tmake: $outfile\n\n$outfile: $project_name\n\t"; $a .= " -o $outfile"; } else { $text = "tmake:\n\t"; } $text .= $a } # # Objects(files) # # Replaces any extension with .o ($obj_ext). # sub Objects { local($_) = @_; my(@a); @a = split(/\s+/,$_); foreach ( @a ) { s-\.\w+$-.${obj_ext}-; if ( defined($project{"OBJECTS_DIR"}) ) { s-^.*[\\/]--; $_ = $project{"OBJECTS_DIR"} . $_; } } return join(" ",@a); } # # list_moc(files,prefix,extension) # # Scans all files and selects all files that contain Q_OBJECT. # Insert a prefix before the filename and replaces the filename extention. # sub list_moc { my($files,$pre,$ext) = @_; my(@v,@m,@lines,$contents,$n,$f,$t); @v = split(/\s+/,$files); undef $/; foreach $f ( @v ) { if ( open(TMP,fix_path($f)) ) { $contents = ; close(TMP); $n = 0; @lines = split(/\n/,$contents); grep( /tmake\s+ignore\s+Q_OBJECT/ && $n--, @lines ); $contents =~ s-/\*.*?\*/--gs; # strip C/C++ comments $contents =~ s-//.*\n--g; @lines = split(/\n/,$contents); grep( /(^|\W)Q_OBJECT(\W|$)/ && $n++, @lines ); if ( $n > 0 ) { $t = $f; $t =~ s-^(.*[/\\])?([^/\\]*?)\.(\w+)$-$1${pre}$2.${ext}-; if ( defined($project{"MOC_DIR"}) ) { $t =~ s-^.*[\\/]--; $t = $project{"MOC_DIR"} . $t; } $moc_output{$f} = $t; $moc_input{$t} = $f; push(@m,$t); } $contents = ""; } } $/ = "\n"; return join(" ",@m); } # # BuildObj(objects,sources) # # Builds the object files. # sub BuildObj { my($obj,$src) = @_; my(@objv,$srcv,$i,$s,$o,$d,$c,$comp,$cimp); @objv = split(/\s+/,$obj); @srcv = split(/\s+/,$src); for $i ( 0..$#objv ) { $s = $srcv[$i]; $o = $objv[$i]; next if $s eq ""; $text .= $o . ": " . $s; if ( defined($moc_output{$s}) && ($moc_output{$s} ne "") ) { $text .= " ${linebreak}\n\t\t" . $moc_output{$s}; } $d = &make_depend($s); $text .= " ${linebreak}\n\t\t" . $d if $d ne ""; if ( ($s =~ /\.c$/) ) { $comp = "TMAKE_RUN_CC"; $cimp = "TMAKE_RUN_CC_IMP"; } else { $comp = "TMAKE_RUN_CXX"; $cimp = "TMAKE_RUN_CXX_IMP"; } if ( defined($project{"OBJECTS_DIR"}) || !defined($project{$cimp}) ) { $c = $project{$comp}; $c =~ s/\$src/$s/; $c =~ s/\$obj/$o/; $text .= "\n\t$c"; } $text .= "\n\n"; } chop $text; } # # BuildMocObj(objects,sources) # # Builds the moc object files. # sub BuildMocObj { my($obj,$src) = @_; my(@objv,$srcv,$i,$s,$o,$hdr,$d); @objv = split(/\s+/,$obj); @srcv = split(/\s+/,$src); for $i ( 0..$#objv ) { $s = $srcv[$i]; $o = $objv[$i]; $hdr = $moc_input{$srcv[$i]}; $text .= $o . ": " . $s . " ${linebreak}\n\t\t" . $hdr; $d = &make_depend($hdr); $text .= " ${linebreak}\n\t\t" . $d if $d ne ""; if ( defined($project{"OBJECTS_DIR"}) || defined($project{"MOC_DIR"})|| !defined($project{"TMAKE_RUN_CXX_IMP"}) ) { $c = $project{"TMAKE_RUN_CXX"}; $c =~ s/\$src/$s/; $c =~ s/\$obj/$o/; $text .= "\n\t$c"; } $text .= "\n\n"; } chop $text; } # # BuildMocSrc(files) # # Builds the moc source files from headers and sources. # sub BuildMocSrc { my($f) = @_; my(@v,$m,$o); @v = split(/\s+/,$f); foreach $m ( @v ) { $o = $moc_output{$m}; if ( defined($o) && ($o ne "") ) { $text .= "$o: $m\n\t$moc_cmd $m -o $o\n\n"; } } chop $text; } # # AddIncludePath(path) # # Adds path to the current include path, $project{"INCLUDEPATH"}. # sub AddIncludePath { my($path) = @_; my($p); if ( $project{"INCPATH"} && ($project{"INCPATH"} =~ /(?:^|\s)\Q$path\E(?:\s|$)/) ) { return; } $project{"INCLUDEPATH"} = "" if !defined($project{"INCLUDEPATH"}); if ( !defined($project{"INCPATH_SEP"}) ) { if ( $project{"INCLUDEPATH"} =~ /;/ ) { $project{"INCPATH_SEP"} = ";"; } else { $project{"INCPATH_SEP"} = " "; } } $p = $project{"INCLUDEPATH"}; $p = ($p && $path) ? ($p . ";" . $path) : ($p . $path); $project{"INCLUDEPATH"} = $p; $p = join($project{"INCPATH_SEP"},&split_path($p)); $p =~ s=[\\/]($project{"INCPATH_SEP"}|$)=$project{"INCPATH_SEP"}=g; $project{"INCPATH"} = $p; } # # FindHighestLibVersion(dir,name) # # Returns the newest library version. Scans all the files in the specifies # directory and returns the highest version number. # # Used on Windows only. # # Example: # FindHighestLibVersion("c:\qt\lib","qt") returns "200" if # the c:\qt\lib directory contains qt141.lib and qt200.lib. # sub FindHighestLibVersion { my($dir,$name) = @_; my(@files,$f,$v,$highest); $highest = ""; @files = find_files($dir,"${name}.*\.lib"); for $f ( @files ) { if ( $f =~ /(\d+)\.lib/i ) { $v = $1; if ( $highest eq "" || $v > $highest ) { $highest = $v; } } } return $highest; } # # Finds files. # # Examples: # find_files("/usr","\.cpp$",1) - finds .cpp files in /usr and below # find_files("/tmp","^#",0) - finds #* files in /tmp # sub find_files { my($dir,$match,$descend) = @_; my($file,$p,@files); local(*D); $dir =~ s=\\=/=g; ($dir eq "") && ($dir = "."); if ( opendir(D,fix_path($dir)) ) { if ( $dir eq "." ) { $dir = ""; } else { ($dir =~ /\/$/) || ($dir .= "/"); } foreach $file ( readdir(D) ) { next if ( $file =~ /^\.\.?$/ ); $p = $dir . $file; if ( $is_unix ) { ($file =~ /$match/) && (push @files, $p); } else { ($file =~ /$match/i) && (push @files, $p); } if ( $descend && -d $p && ! -l $p ) { push @files, &find_files($p,$match,$descend); } } closedir(D); } return @files; } # # make_depend(file) # # Returns a list of included files. # Uses the global $depend_path variable. # sub make_depend { my($file) = @_; my($i,$count); if ( $nodepend ) { return ""; } if ( ! $depend_path_fixed ) { $depend_path_fixed = 1; if ( defined($project{"DEPENDPATH"}) ) { $depend_path = $project{"DEPENDPATH"}; } else { $depend_path = ""; } $count = 0; while ( $count < 100 ) { if ( $depend_path =~ s/(\$[\{\(]?\w+[\}\)]?)/035/ ) { $_ = $1; s/[\$\{\}\(\)]//g; $depend_path =~ s/035/$ENV{$_}/g; } else { $count = 100; } } @dep_path = &split_path($depend_path); } @cur_dep_path = @dep_path; if ( $file =~ /(.*[\/\\])/ ) { $dep_curdir = $1; push @cur_dep_path, $dep_curdir; } else { $dep_curdir = ""; } $dep_file = $file; &canonical_dep($file); %dep_dict = (); $i = &build_dep($file); chop $i; $i =~ s=/=$dir_sep=g unless $is_unix; $i =~ s=([a-zA-Z]):/=//$1/=g if (defined($gnuwin32) && $gnuwin32); return join(" ${linebreak}\n\t\t",split(/ /,$i) ); } # # build_dep() - Internal for make_depend() # sub build_dep { my($file) = @_; my(@i,$a,$n); $a = ""; return $a if !(defined $depend_dict{$file}); @i = split(/ /,$depend_dict{$file}); for $n ( @i ) { if ( !defined($dep_dict{$n}) && defined($full_path{$n}) ) { $dep_dict{$n} = 1; $a .= $full_path{$n} . " " . &build_dep($n); } } return $a; } # # canonical_dep(file) - Internal for make_depend() # # Reads the file and all included files recursively. # %depend_dict associates a file name to a list of included files. # sub canonical_dep { my($file) = @_; my(@inc,$i); @inc = &scan_dep($file); if ( @inc ) { $depend_dict{$file} = join(" ",@inc); for $i ( @inc ) { &canonical_dep($i) if !defined($depend_dict{$i}); } } } # # scan_dep(file) - Internal for make_depend() # # Returns an array of included files. # sub scan_dep { my($file) = @_; my($dir,$path,$found,@allincs,@includes,%incs); $path = $file; @includes = (); return @includes if $file =~ /\.$moc_ext$/; # avoid .moc files if ( ! (-f fix_path($path)) ) { $found = 0; for $dir ( @cur_dep_path ) { $path = $dir . $file; last if ( $found = (-f fix_path($path)) ); } return @includes if ! $found; } undef $/; if ( open(TMP,fix_path($path)) ) { $full_path{$file} = $path; $_ = ; s-/\*.*?\*/--gs; # strip C/C++ comments s-//.*\n-\n-g; @allincs = split(/\n/,$_); @allincs = grep(/^\s*#\s*include/,@allincs); foreach ( @allincs ) { # all #include lines next if !(/^\s*#\s*include\s+[<"]([^>"]*)[>"]/) || defined($incs{$1}); push(@includes,$1); $incs{$1} = "1"; } close(TMP); } $/ = "\n"; return @includes; } # # split_path(path) # # Splits a path containing : (Unix) or ; (MSDOS, NT etc.) separators. # Returns an array. # sub split_path { my($p) = @_; my($s,@d); @d = (); return @d if !defined($p) || $p eq ""; $p =~ s=:=;=g if $is_unix; $p =~ s=[/\\]+=/=g; if ( !($p =~ /;/) ) { $p =~ s/\s+/;/g; } $p =~ s/\s*;\s*/;/g; while( $p =~ /(?:(?:[^\"\;][^\;]*;*)|(?:\"[^\"]*\";*))/g ) { $s = $&; $s =~ s=\"==g; $s =~ s=[\s\;]+$==g; $s =~ s=([^/:])$=$1/=g; $s =~ s=/=$dir_sep=g unless $is_unix; push @d, $s; } return @d; } # # fix_path(path) # # Converts all '\' to '/' if this really seems to be a Unix box. # sub fix_path { my($p) = @_; if ( $really_unix ) { $p =~ s-\\-/-g; } else { $p =~ s-/-\\-g; } return $p; } # # mkdirp(filename,mode) - Internal for StdInit() # # Creates the directory specified by $filename, with permissions # specified by mode (as modified by umask). Recursively calls # mkdir, similar to 'mkdir -p'. # sub mkdirp { my($filename,$mode) = @_; if ( $filename =~ /\$\(\w+\)/ ) { # ignore "$(something)" return 0; } $filename =~ s-[\\:/]+-/-g; if ( -d $filename ) { return 1; } $filename =~ m-^((.*)/)?(.*)-; if ( defined($2) && ! mkdirp($2,$mode) ) { return 0; } return mkdir($filename,$mode); }