#!/usr/bin/perl
############################################################################
# $Id$
#
# Creates a Makefile from a template and a project file.
#
# Copyright (C) 1996-2000 by Trolltech 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.
#
# Modifications added by Geoff Brimhall<brimhall@pobox.com> at
# http://tmake.sourceforge.net
#
# Some important, global variables in tmake:
#   cpp_ext   C++ extension added to moc output (.cpp)
#   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)
#   uic_decl   Uic extension for generated declaration file: x.ui -> x.h
#   uic_impl   Uic extension for generated implementation file: x.ui -> x.cpp
#   uic_cmd   The uic command in your makefile, $(UIC)
#   uic_decl_path   The path where the generated decl files from uic files are created, $(INTERFACE_DECL_PATH)
#   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.
#
############################################################################

{
package TM;

$TMAKE_VERSION = "2.12";

# set $verbose = 1 to see *all* processing to STDERR
$verbose   = 0;
$cpp_ext   = "cpp";
$moc_aware   = 0;
$moc_pre   = "moc_";
$moc_ext   = "moc";
$moc_cmd   = '$(MOC)';
$uic_decl   = "h";
$uic_impl   = "cpp";
$uic_cmd   = '$(UIC)';
$uic_decl_path = '$(INTERFACE_DECL_PATH)';
%uic_dependency   = ();
$depend_path   = "";
$nodepend   = 0;
$output_count   = 0;
$notrim_whitespace = 0;
$really_unix   = ( -f "/bin/uname" || -f "/usr/bin/uname" ) ? 1 : 0;
$is_unix   = 0;
$linebreak   = "\\";
$dir_sep   = "\\";
%init_project = ();
%func_already_called = ();
$OUTPUT = "";

sub init
{
   $template_name   = "";
   $project_name   = "";
   %project   = ();
   $depend_path_fixed = 0;
   %init_project = ();

   $project{'OBJ_EXT'}     = "obj";
   $project{'OUTBASE'}     = "Makefile";
   $project{'RECURSE'}     = 1;

   &tmake_verb("Version $TMAKE_VERSION (runtime environment: " .
       ($really_unix ? "Unix" : "Win32") . ")\n" );

   &check_unix();

   # First ARGV processing pass, to calculate TMAKEPATH:
   foreach my $index ( 0 .. $#ARGV )
      {
      if ( $ARGV[$index] =~ /-l[i]?[b]?/i ) {
         &tmake_verb("Caught -lib = $ARGV[$index + 1]");
         $ENV{'TMAKEPATH'} = $ARGV[$index + 1]; }
      }

   my $tmake_dir = $0;
   $tmake_dir =~ s-(.*[/\\]).*-$1-;
   $tmake_dir =~ s-(.*)[/\\]$-$1-;
   $tmake_dir =~ s-(.*[/\\]).*-$1-;
   my $platform = lc($^O);
   $platform =~ /^mswin/ && ( $platform = "win32" );
   my $gcc_platform = $platform."-g++";

   $project{'TMAKEPATH'}   = $ENV{'TMAKEPATH'} . ";"
                           . $ENV{"HOME"} . "/.tmake/;"
                           . $tmake_dir . "lib/$ENV{'TMAKEPATH'};"
                           . $tmake_dir . "lib/$gcc_platform;"
                           . $tmake_dir . "/usr/lib/tmake-$TMAKE_VERSION/$gcc_platform;";

   my $tmake_conf_path = &find_template("tmake.conf");
   my $tmake_dir = $tmake_conf_path;
   $tmake_dir =~ s-(.*[/\\]).*$-$1-;
   $tmake_dir =~ s-[/\\]$-;-;
   $project{'TMAKEPATH'} = $tmake_dir;
   
   &ScanProject( $tmake_conf_path );

   # Second ARGV processing pass:
   while ( @ARGV ) {            # parse command line args
      $_ = shift @ARGV;

      if ( s/^-// ) {

         if ( /^e(.*)/ ) {
            $text = "";
            eval(  ($1 eq "") ? shift @ARGV : $1 );
            die $@ if $@;
            print $text . "\n" if ($text ne ""); }

         elsif ( /^type$/ ) {
            $_ = shift @ARGV;
            if ( ! /(make|kdevelop|msvstudio|dev\-c\+\+)/ ) {
               &tmake_error("Invalid output type \"$_\": $!"); }
            $project{'OUTTYPE'} = $_; }

         elsif ( /^t(.*)/ ) {
            $project{'TEMPLATE'} = ($1 eq "") ? shift @ARGV : $1; }

         elsif ( /^l(.*)/i ) {
            shift @ARGV; }

         elsif ( /^r(.*)/i ) {
            $project{'RECURSE'}++; }

         elsif ( /^o(.*)/ ) {
            my $outfile_value = ($1 eq "") ? shift @ARGV : $1;
            if ($outfile_value eq "-") {
               $project{'STDOUT'}++; }
            else {
               my ($out_file, $out_end) = ($outfile_value =~ /\/?(\w+)(\.\w+)?$/ ) ;
               $project{"OUTFILE"} = $outfile_value; 
               $project{"OUTBASE"} = $out_file; 
               $project{"OUTEXT"} = $out_end; }
            $project{"RECURSE"}--;}

         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;
            $project_name = $pf; }

         elsif ( /^unix$/ ) {
            $project{'PLATFORM_OS'} = "unix";
            &check_unix(); }

         elsif ( /^win32$/ ) {
          $project{'PLATFORM_OS'} = "win32";
          &check_unix(); }

         elsif ( /^n(.*)$/ ) {
          $nodepend = 1; }         # don't generate dependencies 

         elsif ( /^v(.*)$/ ) {
            $verbose = 1; }

         else {
            &tmake_usage(); } }

      elsif ( /^\s*((?:[^:\s]*?:)?)(\w+)\s*(\+=|\*=|\-=|\/=|=)/ ) {
         my($arg) = $_;
         Project( $arg ); }         # manual project setting

      else {
         $project_name = $_; } } 

   if ( ! ($project_name =~ /\.pro$/i) && -f &fix_path($project_name . ".pro") ) {
      $project_name .= ".pro"; }

   if ( $project{"TEMPLATE"} eq "" ) {
       $project{"TEMPLATE"} = "default"; }

   %init_project = %project;
}

sub iterate_subdirs
{
   if ( ! $project{'RECURSE'} ) {
      return; }

   my ($subdirs) = @_;
   if ($subdirs) {
      foreach my $subdir (split('\s', $subdirs)) {
#     my $backdir .= "../" until ( $subdir =~ m!/!g );
      local *SUBDIR;
      opendir(SUBDIR, $subdir) || die "Cannot open directory $subdir: $!";
      my @subdir_pro = grep { /\.pro$/i && -f "$subdir/$_" } readdir(SUBDIR);
      closedir SUBDIR;
      foreach my $subpro (@subdir_pro) {
         &output_build_file($subpro, $subdir); } } }
}

sub output_build_file
{
   my ($pf, $subdir) = @_;

   if ( $subdir eq "." )
      { $subdir = ""; }
   
   if ( $subdir )
      { $subdir .= "/"; }

   %project = %init_project;
   %func_already_called = ();
   $OUTPUT = "";
   
   $project{'PROJECT'} = $subdir . $pf;
   
   &check_unix();

   if ( !&ScanProject($project{'PROJECT'}) ) {
      &tmake_error("Cannot open project file \"$project{'PROJECT'}\""); } 
   
   my ($po) = ($pf =~ /^(\S+)\.pro$/);

   if ( ! defined ($project{'TARGET'}) ) {
      $project{'TARGET'} = $po; }

   &IncludeTemplate($project{'TEMPLATE'});

   if ( ! defined($project{'STDOUT'}) ) {
      if ( ! defined ($project{'OUTEXT'}) && defined ($project{'TMAKE_OUTEXT'}) ) {
         $project{'OUTEXT'} = $project{'TMAKE_OUTEXT'}; }

      my $outfile = $subdir . ($project{'OUTEXT'} ? $po.$project{'OUTEXT'} : $project{'OUTBASE'});
      local *OUT;
      open(OUT,">" . &fix_path($outfile)) ||
         &tmake_error("Cannot create \"$project{'STDOUT'}\": $!");
      print OUT $OUTPUT;
      close (OUT);
      }

   &iterate_subdirs($project{'SUBDIRS'});
}

##############################################################################
# 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($set_r) = @_;
   my($r);
   $r = 0;
    
    if ( $set_r ) {
       $r = $set_r; }
    else {  
    if ( $project{'PLATFORM_OS'} ) {
       if ( $project{'PLATFORM_OS'} =~ /win32/ ) {
          $r = 0; }
       else {
          $r = 1; }}
    elsif ( $project{'TMAKEPATH'} ) {
       if ( $project{'TMAKEPATH'} =~ /win32/ ) {
          $r = 0; }
       else {
          $r = 1; }}
    else {       
       $r = $really_unix;}
       }
   
   if ( $r ) {
            &tmake_verb("PLATFORM_OS = unix");
       $is_unix = 1;
            $dir_sep = "/";
       $project{'OBJ_EXT'} = "o";}
   else {
            &tmake_verb("PLATFORM_OS = win32");
       $is_unix = 0;
       $project{'OBJ_EXT'} = "obj";
            $dir_sep = "\\";}
    
    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($project{'TEMPLATE_BASE'}) || ($project{'TEMPLATE_BASE'} eq "") ) {
      $tb = ""; }
   else {
      $tb = $project{'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
{
   if ( $func_already_called{'StdInit'} )
      {return;}
   $func_already_called{'StdInit'}++;

   my($p);
   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"});

   $project{"UICDECLS"}=  &UicDecls($project{"INTERFACES"});
   $project{"UICIMPLS"}=  &UicImpls($project{"INTERFACES"});
   $project{"UICOBJECTS"}=  &Objects($project{"INTERFACES"});
   #    $project{"HEADERS"}.=  " " . &UicDecls($project{"INTERFACES"});
   #    $project{"SOURCES"}.=  " " . &UicImpls($project{"INTERFACES"});
   $project{"OBJECTS"}.=  " " . &Objects($project{"INTERFACES"});

   foreach $m ( $project{"INTERFACES"} ) {
      $decl = $m;
      $decl =~ s/\.ui$/\.$uic_decl/;
      $impl = $m;
      $impl =~ s/\.ui$/\.$uic_impl/;
      $uic_dependency{ $impl } = $decl . " ${linebreak}\n\t\t" . $m; }

   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{"OBJMOC"} . " " . &Objects( &MocSources($project{"INTERFACES"} ) );
      $p =~ s/^\s+//;
      $p =~ s/\s+$//;
      $project{"OBJMOC"} = $p;
      
      #$p = $project{"SRCMOC"} . " " . &MocSources($project{"INTERFACES"} );
      
      $p = $project{"_HDRMOC"} . " " . &MocSources($project{"INTERFACES"} ) . " " . $project{"_SRCMOC"};
      $p =~ s/^\s+//;
      $p =~ s/\s+$//;
      $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_var_condition(cond)
#
# Internal function for Project().
# Checks the condition and returns 1 if it is met, otherwise 0.
# The condition can be a platform decriptor (e.g. win32,unix), a
# possible CONFIG item (e.g. release) or several condition vars
# ANDed (':') together.
#
# Examples:
#    win32:SOURCES += win32specific.cpp
#    unix:debug:SOURCES += unixdebug.cpp

sub project_var_condition {
    my($c) = @_;
    return 1 if !defined($c) || ($c eq "");
    if ( $c =~ /(^.*?):(.*$)/ ) {
   my($c1,$c2) = ($1,$2);
   return &project_var_condition($c1) &&
          &project_var_condition($c2);
    } else {
   if ( $c eq "unix" ) {
       return 0 if !$is_unix;
   } elsif ( $c eq "win32" ) {
       return 0 if $is_unix;
   } elsif ( ($c ne $tmake_platform) && !Config($c) ) {
       return 0;
   }
    }
    return 1;
}


#
# 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*((?:(?:[\w\-+]+\s*:\s*){1,10})?)(\w+)\s*(\+=|\*=|\-=|\/=|=)// ) {
       $if_var = $1;
       if ( $if_var ne "" ) {
      $if_var =~ s/\s//g;
      chop $if_var;
      return "" if !&project_var_condition($if_var);
       }
       $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\s*//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 ( <TMP> ) {
   $line++;
   s/\#.*//;            # strip comment
   s/^\s+//;            # strip white space
   s/\s+$//;
   if ( /^\s*((?:(?:(?:[\w\-\+]+\s*:\s*){1,10})?)\w+\s*(\+|\-|\*|\/)?=)/ ) {
##   if ( /^\s*((?:(?:[^:\s]*?:)?)\w+\s*(\+|\-|\*|\/)?=)/ ) {
##DEBUG   
       $var = $1;            # var also contains the ".="
       s/^.*?=\s*//;
       if ( /^\<\<(.*)$/ ) {
      $endmark = $1;
      $val = "";
      while ( <TMP> ) {
          $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;
}

##############################################################################
# User functions
##############################################################################

#
# ComputeConfigDependencies()
#
# Based on the config parameters specified, 
#    1) Ensure they make sense, 
#    2) Update TMAKE_xxx flags to include values from tmake.conf.
#

sub ComputeConfigDependencies 
{
   if ( $func_already_called{'ComputeConfigDependencies'} )
      {return;}
   $func_already_called{'ComputeConfigDependencies'}++;

   if ( !defined( $project{'OUTTYPE'} ) ) { 
      $project{'OUTTYPE'} = "make";}
   if (Config("qtopia")) {
      Project('CONFIG *= qt'); }
   if ( !Project("INTERFACE_DECL_PATH") ) {
      Project('INTERFACE_DECL_PATH = .' ); }
   if ( Project("TMAKE_LIB_FLAG") && !Config("staticlib") ) {
      Project('CONFIG *= dll'); } 
   elsif ( Project("TMAKE_APP_FLAG") || Config("dll") ) {
      Project('CONFIG -= staticlib'); }
   if ( Project("TMAKE_INCDIR") ) {
      AddIncludePath(Project("TMAKE_INCDIR")); }
   if ( Project("TMAKE_LIBDIR") ) {
      Project('TMAKE_LIBDIR_FLAGS *= -L$$TMAKE_LIBDIR'); }
   if ( Config("qt") || Config("opengl") ) {
      Project('CONFIG *= x11lib');
      if ( Config("opengl") ) {
         Project('CONFIG *= x11inc'); }}
   if ( Config("x11") ) {
      Project('CONFIG *= x11lib');
      Project('CONFIG *= x11inc');}
   
   if (Config("qtopia")) {
      AddIncludePath(Project("TMAKE_INCDIR_QT"));
      AddIncludePath(Project("TMAKE_INCDIR_QTOPIA"));
      Project('TMAKE_LIBDIR_FLAGS *= -L$(QPEDIR)/lib');
      if (!Config("qdesktop")) {
         if (Config("qpe")) {
            Project('TMAKE_LIBS *= -lqpe'); }
         else {
            Project('TMAKE_LIBS *= -lqpe');
            Project('TMAKE_LIBS *= $$TMAKE_LIBS_QTOPIA'); }}
      Project('CONFIG *= qt'); }
   
   if ( Config("warn_off") ) {
      Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_WARN_OFF');
      Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_WARN_OFF'); } 
   elsif ( Config("warn_on") ) {
      Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_WARN_ON');
      Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_WARN_ON'); }

   if ( Config("thread") ) {
      if ( Config("qt") ) {
         Project('DEFINES += QT_THREAD_SUPPORT'); }
      Project("TMAKE_CFLAGS_THREAD") &&
         Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_THREAD');
      Project("TMAKE_CXXFLAGS_THREAD") &&
         Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_THREAD');
      AddIncludePath(Project("TMAKE_INCDIR_THREAD"));
      Project('TMAKE_LIBS *= $$TMAKE_LIBS_THREAD');
      Project("TMAKE_LFLAGS_THREAD") &&
         Project('TMAKE_LFLAGS += $$TMAKE_LFLAGS_THREAD');
      if ( Config("debug") ) {
         if ( Config("dll") ) {
            Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_MT_DLLDBG');
            Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_MT_DLLDBG'); } 
         else {
            Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_MT_DBG');
            Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_MT_DBG'); }}
      else {
         if ( Config("dll") ) {
            Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_MT_DLL');
            Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_MT_DLL'); } 
         else {
            Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_MT');
            Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_MT'); }}}
   else {
      Project('TMAKE_LIBS *= $$TMAKE_LIBS_ONE_THREAD'); }

   if ( Config("debug") ) {
      Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_DEBUG');
      Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_DEBUG');
      Project('TMAKE_LFLAGS += $$TMAKE_LFLAGS_DEBUG'); } 
   elsif ( Config("release") ) {
      Project('TMAKE_CFLAGS += $$TMAKE_CFLAGS_RELEASE');
      Project('TMAKE_CXXFLAGS += $$TMAKE_CXXFLAGS_RELEASE');
      Project('TMAKE_LFLAGS += $$TMAKE_LFLAGS_RELEASE'); }

   if ( Config("qt") ) {
      Project('CONFIG *= moc');
      AddIncludePath(Project("TMAKE_INCDIR_QT"));
      if ( !Config("debug") ) {
         Project('DEFINES += NO_DEBUG'); }
      if ( !(((Project("TARGET") eq "qt") || (Project("TARGET") eq "qt-mt") ||
              (Project("TARGET") eq "qte") || (Project("TARGET") eq "qte-mt")) &&
               Project("TMAKE_LIB_FLAG")) ) {
         Project("TMAKE_LIBDIR_QT") &&
            Project('TMAKE_LIBDIR_FLAGS *= -L$$TMAKE_LIBDIR_QT');
         if (Config("thread") && Project("TMAKE_LIBS_QT_THREAD")) {
            Project('TMAKE_LIBS *= $$TMAKE_LIBS_QT_THREAD'); } 
         else {
            Project('TMAKE_LIBS *= $$TMAKE_LIBS_QT');
            if ( !$really_unix && Project("TMAKE_QT_DLL") ) {
               my $qtver =FindHighestLibVersion($ENV{"QTDIR"} . "/lib", "qt");
               if (Config("thread")) {
                  Project("TMAKE_LIBS /= s/qt.lib/qt-mt${qtver}.lib/"); }
               else {
                  Project("TMAKE_LIBS /= s/qt.lib/qt${qtver}.lib/"); }
               if ( !Config("dll") ) {
                   Project('TMAKE_LIBS *= $$TMAKE_LIBS_QT_DLL'); }}}}
      if (Config("qtopia") || Config("qdesktop")) {
         AddIncludePath('$(QPEDIR)/include');
         Project('DEPENDPATH *= $(QPEDIR)/include .');
         if ( !$is_unix ) { 
            IncludeTemplate($ENV{"QPEDIR"}."\\src\\libvers"); }}}
   
   if ( Config("opengl") ) {
      AddIncludePath(Project("TMAKE_INCDIR_OPENGL"));
      Project("TMAKE_LIBDIR_OPENGL") &&
         Project('TMAKE_LIBDIR_FLAGS *= -L$$TMAKE_LIBDIR_OPENGL');
      Project('TMAKE_LIBS *= $$TMAKE_LIBS_OPENGL'); }
   if ( Config("x11inc") ) {
      AddIncludePath(Project("TMAKE_INCDIR_X11")); }
   if ( Config("x11lib") ) {
      Project("TMAKE_LIBDIR_X11") &&
         Project('TMAKE_LIBDIR_FLAGS *= -L$$TMAKE_LIBDIR_X11');
      Project('TMAKE_LIBS *= $$TMAKE_LIBS_X11');}

   if ( Config("moc") ) {
      $moc_aware = 1; }
   
   Project('TMAKE_FILETAGS = HEADERS SOURCES TARGET DESTDIR $$FILETAGS');
   
   if ( Config("embedded") && Project("PRECOMPH") ) {
      Project('SOURCES = allmoc.cpp $$SOURCES');
      $project{'HEADERS_ORIG'} = Project('HEADERS');
      $project{'HEADERS'} = "";}

   if ( Config("dll") ) {
      Project("TMAKE_LFLAGS_SHAPP") || 
         ($project{"TMAKE_LFLAGS_SHAPP"} = $project{"TMAKE_LFLAGS_SHLIB"}); 
      Project('TMAKE_CFLAGS *= $$TMAKE_CFLAGS_SHLIB' );
         Project('TMAKE_CXXFLAGS *= $$TMAKE_CXXFLAGS_SHLIB' ); 
      Project('TMAKE_LFLAGS_CONSOLE_ANY = $$TMAKE_LFLAGS_CONSOLE_DLL');
      Project('TMAKE_LFLAGS_WINDOWS_ANY = $$TMAKE_LFLAGS_WINDOWS_DLL'); } 
   else {
      Project('TMAKE_LFLAGS_CONSOLE_ANY = $$TMAKE_LFLAGS_CONSOLE');
      Project('TMAKE_LFLAGS_WINDOWS_ANY = $$TMAKE_LFLAGS_WINDOWS'); }

   if ( Project("TMAKE_APP_FLAG") ) {
      Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_SHAPP'); } 
   else {
      Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_SHLIB'); }

   if ( Config("console") ) {
      Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_CONSOLE_ANY');
      Project('TMAKE_LIBS   *= $$TMAKE_LIBS_CONSOLE'); } 
   else {
      Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_WINDOWS_ANY');
      Project('TMAKE_LIBS   *= $$TMAKE_LIBS_WINDOWS'); } 

   $project{'TMAKE_LIBS'} = $project{'LIBS'} . ' ' . $project{'TMAKE_LIBS'};

   if ( !$is_unix ) {
      Project('TMAKE_FILETAGS = HEADERS SOURCES DEF_FILE RC_FILE TARGET TMAKE_LIBS LIBS DESTDIR DLLDESTDIR $$FILETAGS');
      foreach ( split(/\s/,Project("TMAKE_FILETAGS")) ) {
         $project{$_} =~ s-[/\\]+-\\-g; } }
   
   if ( Project("DEF_FILE") ) {
      Project('TMAKE_LFLAGS *= /DEF:$$DEF_FILE'); }
   if ( Project("RC_FILE") ) {
      if ( Project("RES_FILE") ) {
         tmake_error("Both .rc and .res file specified.\n" .
                     "Please specify one of them, not both."); }
      $project{"RES_FILE"} = $project{"RC_FILE"};
      $project{"RES_FILE"} =~ s/\.rc$/.res/i;
      Project('TARGETDEPS += $$RES_FILE'); }
   if ( Project("RES_FILE") ) {
      Project('TMAKE_LIBS *= $$RES_FILE');}
}

#
# ComputeCompilerFlags()
#

sub ComputeCompilerFlags 
{
   $project{'DEFINES_PREFIX'} || ($project{'DEFINES_PREFIX'} = '-D');
   $project{'INCLUDE_PREFIX'} || ($project{'INCLUDE_PREFIX'} = '-I');
   if ( Config("staticlib") ) {
      $project{'TMAKE_BLD_CMD'} = $project{'TMAKE_LIB_CMD'}; }
   else {
      $project{'TMAKE_BLD_CMD'} = $project{'TMAKE_LINK_CMD'}; }

   my $quote = $project{'INCLUDE_QUOTE'};
   my $prefix = $project{'DEFINES_PREFIX'};
   $project{'TMAKE_DEFINES'} = &ExpandGlue("DEFINES",$prefix.$quote,$quote.' '.$prefix.$quote,$quote);
   $project{'TMAKE_CFLAGS'} .= ' '.$project{'TMAKE_DEFINES'};
   $project{'TMAKE_CXXFLAGS'} .= ' '.$project{'TMAKE_DEFINES'};
   $text = "";
   $quote = $project{'INCLUDE_QUOTE'};
   $prefix = $project{'INCLUDE_PREFIX'};
   $project{'TMAKE_INCPATH'} = &ExpandGlue("INCPATH",$prefix.$quote,$quote.' '.$prefix.$quote,$quote);
   $text = "";
   #print(STDERR "$project{'TMAKE_INCPATH'}\n");
}
  
#
# ComputeUnixTargetVersions()
#
# Calculates the versioned TARGET names for unix
#

sub ComputeUnixTargetVersions 
{
  if ( $func_already_called{'ComputeUnixTargetVersions'} )
    {return;}
  $func_already_called{'ComputeUnixTargetVersions'}++;

#  Compute VERSION:
   $project{"VERSION"} || ($project{"VERSION"} = "1.0.0");
   if ( $project{"TMAKE_HPUX_SHLIB"} ) {
      $project{"VERSION"} = $project{"VERSION"} =~ /(\d+)\./;}
#  Compute TARGET_EXT, TARGETA_EXT, TARGET_PREFIX:
   if ( !$project{"TARGET_EXT"} ) {
      if ( Config("dll") ) {
         if ( $project{"TMAKE_HPUX_SHLIB"} ) {
            Project('TARGET_EXT = .sl');}
               else {  
            Project('TARGET_EXT = .so');}
         Project('TARGETA_EXT = .a');}
      if ( Config("staticlib") ) {
         Project('TARGET_EXT = .a');}}
   if ( defined($project{'TMAKE_LIB_FLAG'}) ) {
      $project{'TARGET_PREFIX'} || ($project{'TARGET_PREFIX'} = 'lib')}
#  Compute TARGET, TARGETA, TARGET_SONAME, TARGET_VERSIONS:
   $project{'__TARGET'} = $project{'TARGET_PREFIX'} . $project{'TARGET'};
   $project{'_TARGET'} = $project{'__TARGET'};
   $project{'TARGET'} = $project{'DESTDIR'} . $project{'_TARGET'} . $project{'TARGET_EXT'};
   if ( Config("dll") ) {
      $project{'TARGET_SONAME'} = $project{'_TARGET'} . $project{'TARGET_EXT'} . "." . $project{'VERSION'};
      $project{'TARGETA'} = $project{'DESTDIR'} . $project{'_TARGET'} . $project{'TARGETA_EXT'};
      $project{'_TARGET'} = $project{'DESTDIR'} . $project{'_TARGET'};
      $t_v = $project{'TARGET'} .= "." . $project{'VERSION'};
      while ( $t_v =~ /(\S+)\.\d+$/ && $project{'_TARGET'} le $1 ) {
         $project{'TARGET_VERSIONS'} .= $1 . " "; $t_v = $1; } }
#  Compute TMAKE_LFLAGS_SONAME:
   if ( Config("dll") ) {
      Project("TMAKE_LFLAGS_SONAME") &&
         ($project{'TMAKE_LFLAGS_SONAME'} .= $project{'TARGET_SONAME'});
      Project('TMAKE_LFLAGS *= $$TMAKE_LFLAGS_SONAME'); }

   &ComputeCompilerFlags();
}

#
# ComputeWin32TargetVersions()
#
# Calculates the versioned TARGET names for win32
#

sub ComputeWin32TargetVersions 
{
  if ( $func_already_called{'ComputeWin32TargetVersions'} )
    {return;}
  $func_already_called{'ComputeWin32TargetVersions'}++;

#! Compute VERSION:
   if ( defined($project{"TMAKE_LIB_FLAG"}) ) {
      $project{"VERSION"} = $project{"VERSION"} =~ /(\d+)\./;}
#! Compute TARGET_EXT, TARGETA_EXT, TARGET_PREFIX:
   if ( !$project{"TARGET_EXT"} ) {
      $project{'TARGET_EXT'} = ".exe";
      if ( Config("dll") ) {
         $project{'TARGET_EXT'} = "." . $project{'VERSION'} . "dll";}
      if ( Config("staticlib") ) {
         $project{'TARGET_EXT'} = ".lib";}}
#! Compute TARGET, TARGETA, TARGET_SONAME, TARGET_VERSIONS:
   $project{'TARGET_LST'} = $project{'TARGET'}.'.lst';
   $project{'__TARGET'} = $project{'TARGET_PREFIX'} . $project{'TARGET'};
   $project{'_TARGET'} = $project{'DESTDIR'} . $project{'__TARGET'};
   $project{'TARGET'} = $project{'_TARGET'} . $project{'TARGET_EXT'};

   &ComputeCompilerFlags();
}

#
# 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);
   $project{'TEMPLATE_BASE'} = $t_name;
   $project{'TEMPLATE_BASE'} =~ s-(.*[/\\]).*-$1-;

   &tmake_verb("Reading the template $t_name");
   open(T,&fix_path($t_name)) ||
      &tmake_error("Cannot open template file \"$t_name\"");

   my $eval_string = "";
   my $string_ref = \$eval_string;

   while ( <T> ) {
      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 ( <T> ) {
               $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*$/);

         $eval_string = $saveline . $text . "\n";
         $string_ref = \$eval_string; }
      else {            # something else
         $string_ref = \$_; }

      if ( $output_count <= 0 ) {
         if ( defined ( $project{'STDOUT'} ) ) {
            print STDOUT $$string_ref; }
         else {
            $OUTPUT .= $$string_ref; } } }

   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 = "<a-b-c>"
#

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
#
#   ExpandPath("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 $pf = $project{'PROJECT'};
   my $a = "tmake $pf";
   if ( $nodepend ) {
      $a .= " -nodepend"; }
   if ( $project{'OUTFILE'} ) {
     $text = "tmake: $project{'OUTFILE'}\n\n$project{'OUTFILE'}: $pf\n\t";
     $a .= " -o $project{'OUTFILE'}"; }
   else {
      $text = "tmake:\n\t"; }
   $text .= $a
}


#
# Objects(files)
#
# Replaces any extension with .o ($project{'OBJ_EXT'}).
#

sub Objects
{
   local($_) = @_;
   my(@a);
   @a = split(/\s+/,$_);
   foreach ( @a ) {
      s-\.\w+$-.$project{OBJ_EXT}-;
      if ( defined($project{"OBJECTS_DIR"}) ) {
         s-^.*[\\/]--;
         $_ = $project{"OBJECTS_DIR"} . $_; } }
   return join(" ",@a);
}

#
# UicImpls(files)
#
# Replaces any extension with .h ($uic_impl).
#

sub UicImpls {
    local($_) = @_;
    my(@a);
    @a = split(/\s+/,$_);
    foreach ( @a ) {
   s-\.\w+$-.${uic_impl}-;
    }
    return join(" ",@a);
}

#
# UicDecls(files)
#
# Replaces any extension with .cpp ($uic_decl).
#

sub UicDecls {
    local($_) = @_;
    my(@a);
    @a = split(/\s+/,$_);
    foreach ( @a ) {
   s-\.\w+$-.${uic_decl}-;
    }
    return join(" ",@a);
}

#
# MocSources(files)
#
# Only useful for uic files!
#
# Replaces any extension with .cpp ($cpp_ext) and adds moc_ ($moc_pre)
#

sub MocSources {
    local($_) = @_;
    my( @a, $t, $h, $f );
    @a = split(/\s+/,$_);
    foreach $t ( @a ) {
   $h = $t;
   $h =~ s-\.\w+$-.${uic_decl}-;
    $f = $t;
    $t =~ s-^(.*[/\\])?([^/\\]*?)\.(\w+)$-$1${moc_pre}$2.${cpp_ext}-;
   if ( defined($project{"MOC_DIR"}) ) {
     $t =~ s-^.*[\\/]--;
     $t = $project{"MOC_DIR"} . $t;
   }
   $moc_output{$h} = $t;
    $moc_input{$t}  = $h;
    }
    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 = <TMP>;
       close(TMP);
       $n = 0;
       @lines = split(/\n/,$contents);
       grep( /tmake\s+ignore\s+Q_OBJECT/ && $n--, @lines );
       $contents =~ s-//.*\n--g;      # strip C/C++ comments
       $contents =~ s-/\*.*?\*/--gs;
       @lines = split(/\n/,$contents);
       grep( /(^|\W)(Q_OBJECT)|(Q_COMPONENT)(\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};
   }
   if ( defined($uic_dependency{ $s } ) ) {
       $d = $uic_dependency{ $s };
   } else {
       $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$c";
   }
   $text .= "\n\n";
    }
    chomp $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;
}

#
# BuildUicSrc(files)
#
# Builds the uic source files from interface definitions
#

sub BuildUicSrc {
    my($f) = @_;
    my(@v,$m,$o);
    @v = split(/\s+/,$f);
    foreach $m ( @v ) {
   $decl = $m;
   $decl =~ s/\.ui$/\.$uic_decl/;
   $impl = $m;
   $impl =~ s/\.ui$/\.$uic_impl/;
   $text .= "$decl: $m\n\t$uic_cmd $m -o $uic_decl_path/$decl\n\n";
   $fulldecl = $decl;
   $decl =~ s/.*\///; # No path - use -I... to find it.
   if ( ! ( $fulldecl eq $decl ) ) {
     $text .= "$decl: $m\n\t$uic_cmd $m -o $decl\n\n";
   }
   $text .= "$impl: $m\n\t$uic_cmd $m -i $decl -o $impl\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;
       }
   } elsif ( $f =~ /(-mt(?:\d+)nc)\.lib$/i ) {
       $v = $1;
       if ( $highest eq "" || $v gt $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;
   $_ = <TMP>;
   s-//.*\n-\n-g;
   s-/\*.*?\*/--gs;         # strip C/C++ comments
   @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";
       my $headerfile = $1;
       my $hfile = $headerfile;
       $hfile =~ s/\+/\\\+/g;
       $full_path{$headerfile} ||= &fix_path( $headerfile )
         if ( $project{"UICDECLS"} =~ /\b$hfile\b/ );
   }
   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.
# Also expands $(...) environment variables (god for $(QTDIR)).
#

sub fix_path {
    my($p) = @_;
    if ( $really_unix ) {
   $p =~ s-\\-/-g;
    } else {
   $p =~ s-/-\\-g;
    }
    $p =~ s/\$\(([^)]*)\)/$ENV{$1}/gs;
    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);
}

sub tmake_query_win32_registry
{
  my ($reg_key) = @_;
  my $reg_key_exists = 0;
  my $reg_value = 0;
  require Config;
  my $OS = $Config::Config{'osname'};
  if ( $OS =~ /Win/i )
    {
      require Win32::Registry;
      $reg_key_exists = $::HKEY_CURRENT_USER->Open($reg_key,$reg_value);
      &tmake_verb("REG_VALUE $reg_key = $reg_key_exists");
    }
  return $reg_key_exists;
}

1;
}

if ($] < 5.0) {
    &TM::tmake_error("This program requires perl version 5 or newer");
}

&TM::init();

if ( $TM::project_name )
   {
   &TM::output_build_file($TM::project_name, "");   
   }
else
   {
   &TM::iterate_subdirs(".");   
   }

&TM::tmake_verb("Done!");
exit 0;                  # finished!

