root/juggler/tags/2.0_alpha_2/configure.pl

Revision 12036, 24.2 kB (checked in by patrickh, 6 years ago)

Blanket copyright update.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/env perl
2
3 # ************** <auto-copyright.pl BEGIN do not edit this line> **************
4 #
5 # VR Juggler is (C) Copyright 1998-2003 by Iowa State University
6 #
7 # Original Authors:
8 #   Allen Bierbaum, Christopher Just,
9 #   Patrick Hartling, Kevin Meinert,
10 #   Carolina Cruz-Neira, Albert Baker
11 #
12 # This library is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU Library General Public
14 # License as published by the Free Software Foundation; either
15 # version 2 of the License, or (at your option) any later version.
16 #
17 # This library is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 # Library General Public License for more details.
21 #
22 # You should have received a copy of the GNU Library General Public
23 # License along with this library; if not, write to the
24 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 # Boston, MA 02111-1307, USA.
26 #
27 # -----------------------------------------------------------------
28 # File:          $RCSfile$
29 # Date modified: $Date$
30 # Version:       $Revision$
31 # -----------------------------------------------------------------
32 #
33 # *************** <auto-copyright.pl END do not edit this line> ***************
34
35 use 5.005;
36
37 use strict 'vars';
38 use vars qw($base_dir $module $CONFIG_ARGS $PATH_ARGS $HOST_ARGS $FEATURE_ARGS
39             $CUSTOM_ARGS $LAST_ARG_GROUP $OS $Win32 $CFG_LOAD_FUNC);
40 use vars qw(%MODULES);
41
42 use Cwd qw(chdir getcwd);
43 use File::Basename;
44 use File::Path;
45 use Getopt::Long;
46 use Pod::Usage;
47
48 BEGIN
49 {
50    $base_dir = (fileparse("$0"))[1];
51 }
52
53 use lib("$base_dir");
54 use JugglerConfigure;
55
56 # Subroutine prototypes.
57 sub mergeArgArrays($$);
58 sub loadDefaultArgs($);
59 sub configureModule($);
60 sub regenModuleInfo($);
61 sub generateMakefile(;$);
62 sub generateReconfig($@);
63 sub listModules();
64 sub printHelp();
65 sub getConfigureHelp($$);
66 sub parseOutput($$);
67 sub getPlatform();
68 sub getRelativePath($$);
69
70 %MODULES = ();
71
72 my $all_help      = 0;
73 my $cfg           = "juggler.cfg";
74 my $user_cfg      = '';
75 $module           = '';
76 my $script_help   = 0;
77 my $manual        = 0;
78 my $regen         = 0;
79 my $mod_list      = 0;
80 my $args_file     = 'acdefaults.cfg';
81 my $args_mod_file = 'acdefaults.pl';
82 my $user_args     = '';
83 my $user_args_mod = '';
84 my $no_user_args  = 0;
85
86 $CONFIG_ARGS    = 0;
87 $PATH_ARGS      = 1;
88 $HOST_ARGS      = 2;
89 $FEATURE_ARGS   = 3;
90 $CUSTOM_ARGS    = 4;
91 $LAST_ARG_GROUP = 5;
92
93 $CFG_LOAD_FUNC = undef;
94 $OS            = '';
95
96 my @save_argv = @ARGV;
97
98 Getopt::Long::Configure('pass_through');
99 GetOptions('help|?' => \$script_help, 'cfg=s' => \$user_cfg,
100            'module=s' => \$module, 'all-help' => \$all_help,
101            'manual' => \$manual, 'regen' => \$regen, 'modlist' => \$mod_list,
102            'args=s' => \$user_args, 'argsmod=s' => \$user_args_mod,
103            'noargs' => \$no_user_args, 'os=s' => \$OS)
104    or pod2usage(2);
105
106 # Print the help output and exit if --help was on the command line.
107 pod2usage(1) if $script_help;
108 pod2usage(-exitstatus => 0, -verbose => 2) if $manual;
109
110 die "ERROR: No configuration given\n" unless $cfg || $user_cfg;
111
112 $Win32 = 1 if $ENV{'OS'} && $ENV{'OS'} =~ /Windows/;
113
114 # On Windows, the command-line arguments can confuse the Cygwin shell.  For
115 # example, the character used to separate paths is ';', but the shell sees
116 # that as a statement separator.  We can deal with this by ensuring that the
117 # shell interprets command-line arguments as literal strings (i.e., by
118 # putting quotes around each argument).
119 if ( $Win32 )
120 {
121    for ( my $i = 0; $i <= $#save_argv; $i++ )
122    {
123       $save_argv[$i] = "\"$save_argv[$i]\"";
124    }
125
126    for ( my $i = 0; $i <= $#ARGV; $i++ )
127    {
128       $ARGV[$i] = "\"$ARGV[$i]\"";
129    }
130 }
131
132 my $cfg_load = ("$user_cfg" eq "") ? "$base_dir/$cfg" : "$user_cfg";
133 %MODULES = JugglerConfigure::parseConfigFile("$cfg_load");
134
135 listModules() && exit(0) if $mod_list;
136 printHelp() && exit(0) if $all_help;
137
138 if ( $regen )
139 {
140    if ( $module )
141    {
142       die "ERROR: No such module $module in $cfg!\n"
143          unless defined($MODULES{"$module"});
144
145       regenModuleInfo("$module");
146       generateMakefile("$module");
147    }
148    elsif ( $JugglerConfigure::DEFAULT_MODULE &&
149            defined($MODULES{"$JugglerConfigure::DEFAULT_MODULE"}) )
150    {
151       regenModuleInfo("$JugglerConfigure::DEFAULT_MODULE");
152       generateMakefile("$JugglerConfigure::DEFAULT_MODULE");
153    }
154    else
155    {
156       foreach ( keys(%MODULES) )
157       {
158          regenModuleInfo("$_");
159       }
160
161       generateMakefile();
162    }
163 }
164 else
165 {
166    my $cache_file_set = 0;
167
168    foreach ( @ARGV )
169    {
170       if ( /-cache-f/ )
171       {
172          $cache_file_set = 1;
173          last;
174       }
175    }
176
177    # Unless the user passed --noargs, try to find default argument values.
178    unless ( $no_user_args )
179    {
180       my $args_mod = ("$user_args_mod" eq "") ? "$base_dir/$args_mod_file"
181                                               : "$user_args_mod";
182
183       # Figure out what argument file to load, if any.  If the user specified
184       # a file name on the command line, it will be in $user_args.  Otherwise,
185       # we fall back on $base_dir/$args_file.
186       my $args_load = ("$user_args" eq "") ? "$base_dir/$args_file"
187                                            : "$user_args";
188
189       if ( -r "$args_mod" )
190       {
191          require "$args_mod";
192
193          if ( $CFG_LOAD_FUNC )
194          {
195             my @default_args = &$CFG_LOAD_FUNC();
196             mergeArgArrays(\@ARGV, \@default_args);
197          }
198       }
199       elsif ( -r "$args_load" )
200       {
201          loadDefaultArgs("$args_load");
202       }
203    }
204
205    if ( ! $cache_file_set )
206    {
207       my $cwd = getcwd();
208       push(@ARGV, "--cache-file=$cwd/config.cache");
209    }
210
211    # Configure the module named on the command line.
212    if ( $module )
213    {
214       die "ERROR: No such module $module in $cfg!\n"
215          unless defined($MODULES{"$module"});
216
217       generateReconfig("$module", @save_argv);
218       configureModule("$module");
219       generateMakefile("$module");
220    }
221    # If no module was named on the command line but we do have a default
222    # module, configure it.
223    elsif ( $JugglerConfigure::DEFAULT_MODULE &&
224            defined($MODULES{"$JugglerConfigure::DEFAULT_MODULE"}) )
225    {
226       generateReconfig("$JugglerConfigure::DEFAULT_MODULE", @save_argv);
227       configureModule("$JugglerConfigure::DEFAULT_MODULE");
228       generateMakefile("$JugglerConfigure::DEFAULT_MODULE");
229    }
230    # If neither of the above will do, just configure every module we know
231    # about from the input file.
232    else
233    {
234       generateReconfig('', @save_argv);
235
236       foreach ( keys(%MODULES) )
237       {
238          configureModule("$_");
239       }
240
241       generateMakefile();
242    }
243 }
244
245 exit(0);
246
247 # =============================================================================
248 # Subroutines follow.
249 # =============================================================================
250
251 sub mergeArgArrays ($$)
252 {
253    my $dest_list   = shift;
254    my $source_list = shift;
255
256    foreach ( @$source_list )
257    {
258       # Strip leading and trailing whitespace.
259       s/^\s+//;
260       s/\s+$//;
261       next if /^$/;   # Just to be safe...
262       
263       # Only add the argument if it is not already on the command line.
264       m/^(--[^=]+)/;
265       push(@$dest_list, "$_") unless grep(/$1/, @$dest_list);
266    }
267 }
268
269 sub loadDefaultArgs ($)
270 {
271    my $args_load = shift;
272
273    if ( open(ARGS_FILE, "$args_load") )
274    {
275       print "Loading default arguments from $args_load ...\n";
276       my $args_contents = '';
277
278       while ( <ARGS_FILE> )
279       {
280          s/#.*$//;           # Strip comments
281          next if /^\s*$/;    # Skip blank lines
282          $args_contents .= "$_";
283       }
284
285       close(ARGS_FILE) or warn "WARNING: Could not close $args_load: $!\n";
286
287       my $platform = getPlatform();
288
289       while ( "$args_contents" ne '' )
290       {
291          my @args_list = ();
292
293          # Read in the arguments for all platforms.
294          if ( $args_contents =~ /^\s*all\s*{(.+?)}\s*/si )
295          {
296             @args_list     = split(m|$/|, "$1");
297             $args_contents = $';
298          }
299          # Read in the arguments for the current platform.
300          elsif ( $args_contents =~ /^\s*$platform\s*{(.+?)}\s*/sio )
301          {
302             @args_list     = split(m|$/|, "$1");
303             $args_contents = $';
304          }
305          # Skip a platform that does not match $platform.
306          elsif ( $args_contents =~ /^\s*(\S+)\b\s*{(.+?)}\s*/s )
307          {
308             print "Skipping $1\n";
309             $args_contents = $';
310          }
311
312          mergeArgArrays(\@ARGV, \@args_list);
313       }
314    }
315    else
316    {
317       warn "WARNING: Coult not read from $args_load: $!\n";
318    }
319 }
320
321 sub configureModule ($)
322 {
323    my $module_name = shift;
324
325    my $cwd = getcwd();
326    my $safe_cwd;
327
328    if ( $Win32 )
329    {
330       $safe_cwd = `cygpath -w $cwd`;
331       chomp($safe_cwd);
332       $safe_cwd =~ s/\\/\//g;
333    }
334    else
335    {
336       $safe_cwd = "$cwd";
337    }
338
339    die "ERROR: No module $module_name defined\n"
340       unless defined($MODULES{"$module_name"});
341
342    # Use ksh to run configure if we are on Solaris.  Otherwise, use sh
343    my $shell = ((getPlatform() =~ /solaris/i) ? 'ksh' : '/bin/sh');
344
345    my $depencency;
346    foreach $depencency ( $MODULES{"$module_name"}->getDependencies() )
347    {
348       my $mod_path = $depencency->getPath();
349
350       mkpath("$mod_path", 1, 0755) unless -d "$mod_path";
351
352       # Do not try to proceed with $dependency unless we can chdir to
353       # $mod_path.
354       unless ( chdir("$mod_path") )
355       {
356          warn "WARNING: Could not chdir to $mod_path: $!\n";
357          next;
358       }
359
360       my $src_root;
361
362       # Dependeing on the value of $base_dir, assign $src_root such that it
363       # is an absolute path.
364       # XXX: This creates a problem on Win32 with $(srcdir) in generated
365       # makefiles!  Win32 utilities will not understand the Cygwin path, but
366       # they would understand a relative path...
367       if ( $base_dir =~ /^\// )
368       {
369          $src_root = "$base_dir";
370       }
371       else
372       {
373          $src_root = "$cwd/$base_dir";
374       }
375
376       # Ensure $src_root isn't terminated with a '/'.
377       $src_root =~ s/\/$//;
378
379       # If we're being run in Win32, force a relative path for $src_root
380       my $cfg_exec = "$src_root/$mod_path/configure";
381       if ($Win32)
382       {
383          $cfg_exec = getRelativePath(getcwd(), $cfg_exec);
384       }
385
386       print "Running $shell $cfg_exec @ARGV\n";
387       system("$shell $cfg_exec @ARGV 2>&1") == 0
388          or die "Configuration of $module_name in $ENV{'PWD'} failed\n" .
389                 "Check $ENV{'PWD'}/config.log for details\n";
390
391       my %mod_env = $depencency->getEnvironment();
392       foreach ( keys(%mod_env) )
393       {
394          my $env_val = $depencency->getEnvironmentValue($_);
395
396          if ( /_CONFIG$/ )
397          {
398             $ENV{"$_"}    = "$cwd/$mod_path/$env_val";
399             $ENV{'PATH'} .= ":$cwd/$mod_path";
400          }
401          elsif ( /_BASE_DIR$/ )
402          {
403             if ( "$env_val" eq "instlinks" )
404             {
405                $ENV{"$_"} = "$safe_cwd/instlinks";
406             }
407             else
408             {
409                $ENV{"$_"} = "$env_val";
410             }
411          }
412          else
413          {
414             $ENV{"$_"} = "$env_val";
415          }
416       }
417
418       $ENV{'USE_BASE_DIR'} = 'yes';
419
420       chdir("$cwd");
421    }
422 }
423
424 sub regenModuleInfo ($)
425 {
426    my $module_name = shift;
427
428    my $cwd = getcwd();
429
430    die "ERROR: No module $module_name defined\n"
431       unless defined($MODULES{"$module_name"});
432
433    my $depencency;
434    foreach $depencency ( $MODULES{"$module_name"}->getDependencies() )
435    {
436       my $mod_path = $depencency->getPath();
437
438       chdir("$mod_path")
439          or die "WARNING: Could not chdir to $mod_path\n";
440       system("./config.status 2>&1") == 0
441          or die "Regeneration for $module_name in $ENV{'PWD'} failed\n";
442       chdir("$cwd");
443    }
444 }
445
446 sub generateMakefile (;$)
447 {
448    my $gen_module = shift || '';
449
450    open(INPUT, "$base_dir/Makefile.in")
451       or die "ERROR: Could not read from $base_dir/Makefile.in: $!\n";
452
453    my $input_file;
454    while ( <INPUT> )
455    {
456       $input_file .= "$_";
457    }
458
459    close(INPUT);
460
461    my $modules;
462    my @module_array;
463
464    if ( $gen_module )
465    {
466       foreach ( $MODULES{"$gen_module"}->getDependencies() )
467       {
468          $modules .= $_->getPath() . " ";
469       }
470    }
471    else
472    {
473       my $mod_name;
474       foreach $mod_name ( keys(%MODULES) )
475       {
476          my $temp_mod;
477          foreach $temp_mod ( $MODULES{"$mod_name"}->getDependencies() )
478          {
479             $modules .= $temp_mod->getPath() . " ";
480          }
481       }
482    }
483
484    warn "WARNING: No modules defined!\n" unless $modules;
485
486    my $cwd = getcwd();
487    chdir("$base_dir");
488    $input_file =~ s/\@JUGGLER_PROJECTS\@/$modules/g;
489
490    if ( $Win32 )
491    {
492       # Get the Win32-friendly versions of these paths.  Then change the \'s
493       # to /'s just to be safe.
494       my $win_pwd = `cygpath -w $ENV{'PWD'}`;
495       my $win_cwd = `cygpath -w $cwd`;
496       chomp($win_pwd);
497       chomp($win_cwd);
498
499       $win_pwd =~ s/\\/\//g;
500       $win_cwd =~ s/\\/\//g;
501
502       $input_file =~ s/\@JUGGLERROOT_ABS\@/$win_pwd/g;
503       $input_file =~ s/\@topdir\@/$win_cwd/g;
504    }
505    else
506    {
507       $input_file =~ s/\@JUGGLERROOT_ABS\@/$ENV{'PWD'}/g;
508       $input_file =~ s/\@topdir\@/$cwd/g;
509    }
510
511    chdir("$cwd");
512
513    print "Generating Makefile\n";
514    open(OUTPUT, "> Makefile") or die "ERROR: Could not create Makefile: $!\n";
515    print OUTPUT "$input_file";
516    close(OUTPUT) or warn "WARNING: Failed to save Makefile: $!\n";
517 }
518
519 sub generateReconfig ($@)
520 {
521    my $gen_module = shift;
522    my @arg_list   = @_;
523
524    my $modules;
525
526    open(RECONFIG, "> reconfig");
527
528    if ( $gen_module )
529    {
530       foreach ( $MODULES{"$gen_module"}->getDependencies() )
531       {
532          print RECONFIG "(cd " . $_->getPath() . " && rm -f config.status " .
533                         "config.cache config.log)\n"
534       }
535    }
536    else
537    {
538       my $mod_name;
539       foreach $mod_name ( keys(%MODULES) )
540       {
541          foreach ( $MODULES{"$mod_name"}->getDependencies() )
542          {
543             print RECONFIG "(cd " . $_->getPath() . " && rm -f config.status " .
544                            "config.cache config.log)\n"
545          }
546       }
547    }
548
549    print RECONFIG "rm -f config.cache\n";
550    print RECONFIG "$0 ", "@arg_list \n";
551    close(RECONFIG);
552    chmod(0755, "reconfig");
553 }
554
555 sub listModules ()
556 {
557    my $mod_name;
558    foreach $mod_name ( keys(%MODULES) )
559    {
560       print "$mod_name";
561
562 #      if ( $#{$MODULES{"$mod_name"}} != -1 )
563 #      {
564 #         print " (Requires:";
565 #
566 #         my $dep_ref;
567 #         foreach $dep_ref ( @{$MODULES{"$mod_name"}} )
568 #         {
569 #            print " ${$dep_ref}{'path'}";
570 #         }
571 #
572 #         print ")";
573 #      }
574
575       print "\n";
576    }
577
578    return 1;
579 }
580
581 sub printHelp ()
582 {
583    my @help_output = ();
584
585    # Initialize the references that are contained within @help_output.
586    my $i;
587    for ( $i = 0; $i < $LAST_ARG_GROUP; $i++ )
588    {
589       $help_output[$i] = {};
590    }
591
592    if ( $module )
593    {
594       getConfigureHelp("$module", \@help_output);
595    }
596    elsif ( $JugglerConfigure::DEFAULT_MODULE &&
597            defined($MODULES{"$JugglerConfigure::DEFAULT_MODULE"}) )
598    {
599       getConfigureHelp("$JugglerConfigure::DEFAULT_MODULE", \@help_output);
600    }
601    else
602    {
603       foreach ( keys(%MODULES) )
604       {
605          getConfigureHelp("$_", \@help_output);
606       }
607    }
608
609    for ( $i = 0; $i < $LAST_ARG_GROUP; $i++ )
610    {
611       SWITCH:
612       {
613          if ( $i == $CONFIG_ARGS )
614          {
615             print "Configuration:\n";
616             last SWITCH;
617          }
618
619          if ( $i == $PATH_ARGS )
620          {
621             print "Directory and file names:\n";
622             last SWITCH;
623          }
624
625          if ( $i == $HOST_ARGS )
626          {
627             print "Host type:\n";
628             last SWITCH;
629          }
630
631          if ( $i == $FEATURE_ARGS )
632          {
633             print "Features and packages:\n";
634             last SWITCH;
635          }
636
637          if ( $i == $CUSTOM_ARGS )
638          {
639             print "--enable and --with options recognized:\n";
640             last SWITCH;
641          }
642       }
643
644       foreach ( sort(keys(%{$help_output[$i]})) )
645       {
646          print "  ${$help_output[$i]}{$_}\n";
647       }
648    }
649
650    print "\n";
651
652    print "Modules that may be built:\n";
653    foreach ( keys(%MODULES) )
654    {
655       print "\t$_\n";
656    }
657
658    print "\nDefault module is $JugglerConfigure::DEFAULT_MODULE\n"
659       if $JugglerConfigure::DEFAULT_MODULE;
660
661    return 1;
662 }
663
664 sub getConfigureHelp ($$)
665 {
666    my $mod_name    = shift;
667    my $arg_arr_ref = shift;
668
669    foreach ( $MODULES{"$mod_name"}->getDependencies() )
670    {
671       next unless -x "$base_dir/$$_{'path'}/configure";
672
673       open(CFG_OUTPUT, "$base_dir/$$_{'path'}/configure --help |");
674
675       my $cfg_output;
676       while ( <CFG_OUTPUT> )
677       {
678          $cfg_output .= "$_";
679       }
680
681       close(CFG_OUTPUT);
682
683       parseOutput("$cfg_output", $arg_arr_ref);
684    }
685 }
686
687 sub parseOutput ($$)
688 {
689    my $string      = shift;
690    my $arg_arr_ref = shift;
691
692    my $arg_group;
693
694    while ( $string !~ /^\s*$/s )
695    {
696       if ( $string =~ /^Configuration:\s*/s )
697       {
698          $arg_group = $CONFIG_ARGS;
699          $string = $';
700       }
701       elsif ( $string =~ /^Directory.*?:\s*/s )
702       {
703          $arg_group = $PATH_ARGS;
704          $string = $';
705       }
706       elsif ( $string =~ /^Host.*?:\s*/s )
707       {
708          $arg_group = $HOST_ARGS;
709          $string = $';
710       }
711       elsif ( $string =~ /^Features.*?:\s*/s )
712       {
713          $arg_group = $FEATURE_ARGS;
714          $string = $';
715       }
716       elsif ( $string =~ /^--enable and --with.*?:\s*/s )
717       {
718          $arg_group = $CUSTOM_ARGS;
719          $string = $';
720       }
721       elsif ( $string =~ /^\s*(--\w+,\s+--\w+)/s ||
722               $string =~ /^\s*(--[\w-]+)\W/s )
723       {
724          my $param = "$1";
725          ${$$arg_arr_ref[$arg_group]}{"$param"} = '';
726
727          my $temp_string = "$string";
728
729          if ( $temp_string =~ /($param.+?)\s+(--)/s ||
730               $temp_string =~ /($param.+?)\s*$/s )
731          {
732             my $desc = "$1";
733             my $remainder = "$2$'";
734
735             if ( $desc =~ /^(\w.+?:)$/m )
736             {
737                $desc = $`;
738                $remainder = "$1\n$remainder";
739             }
740
741             ${$$arg_arr_ref[$arg_group]}{"$param"} = "$desc";
742             $string = "$remainder";
743          }
744       }
745       elsif ( $string =~ /^(Usage|Options).*$/m )
746       {
747          $string = $';
748       }
749       # Match anything else and strip it from the output.
750       elsif ( $string =~ /^.*$/m )
751       {
752          $string = $';
753       }
754
755       $string =~ s/^\s*//s;
756    }
757 }
758
759 sub getPlatform ()
760 {
761    my $platform = "unknown";
762
763    # Prefer the user-defined platform type over any auto-detected value.
764    if ( "$OS" ne '' )
765    {
766       $platform = "$OS";
767    }
768    elsif ( defined($ENV{'OS'}) )
769    {
770       $platform = "$ENV{'OS'}";
771    }
772    elsif ( defined($ENV{'OSTYPE'}) )
773    {
774       $platform = "$ENV{'OSTYPE'}";
775    }
776    elsif ( defined($ENV{'OS_TYPE'}) )
777    {
778       $platform = "$ENV{'OS_TYPE'}";
779    }
780    elsif ( defined($ENV{'HOSTTYPE'}) )
781    {
782       $platform = "$ENV{'HOSTTYPE'}";
783    }
784    # As a last resort, fall back on the use of uname(1).
785    else
786    {
787       chomp($platform = `uname -s`);
788    }
789
790    # XXX: This is a hack to deal with weird OS strings such as "linux-gnu".
791    # We just make the platform be "linux" unless the user set the platform
792    # type on the command line.
793    $platform = 'linux' if ! $OS && $platform =~ /linux/i;
794
795    return $platform;
796 }
797
798 sub getHostname ()
799 {
800    my $hostname = '';
801
802    if ( defined($ENV{'HOSTNAME'}) )
803    {
804       $hostname = "$ENV{'HOSTNAME'}";
805    }
806    else
807    {
808       chomp($hostname = `hostname`);
809    }
810
811    return $hostname;
812 }
813
814 #
815 # getRelativePath(wd, target)
816 # Given a working directory, returns the relative path to the target file.
817 #
818 sub getRelativePath ($$)
819 {
820    my ($wd, $target) = @_;
821
822    my @wd = split(/\//, $wd);
823    my @target = split(/\//, $target);
824
825    # Remove matching directory elements from both @wd and @target
826    while ((scalar(@wd) > 0) && (scalar(@target) > 0) && ($wd[0] eq $target[0]))
827    {
828       shift(@wd);
829       shift(@target);
830    }
831
832    # For each remaining part of the wd, prefix a .. to the target
833    foreach my $dir (@wd)
834    {
835       unshift(@target, '..');
836    }
837
838    return join('/', @target);
839 }
840
841 __END__
842
843 =head1 NAME
844
845 configure.pl
846
847 =head1 SYNOPSIS
848
849 This script acts as the "glue" for a collection of Autoconf-based configure
850 scripts.  Based on a configuration file, it is capable of building a
851 dependency tree and running the configure scripts in the correct order such
852 that the dependencies are satisfied correctly.  Note that all modules must
853 be capable of having dependencies satisfied based entirely on the results
854 of running a dependent module's configure script.
855
856 =head1 DESCRIPTION
857