# -*- CPerl -*-
eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
    & eval 'exec perl -S $0 $argv:q'
    if 0;

# configure script for OpenDDS
# Distributed under the OpenDDS License.
# See: http://www.opendds.org/license.html

use Getopt::Long;
use Dumpvalue;
use File::Spec;
use File::Copy;
require File::Temp;
use File::Temp ();
use FileHandle;
use Cwd;
use strict;

## Version of OCI's TAO to download
my $tao_version = '2.2a';

## faster, and hopefully more reliable extraction:
$Archive::Extract::PREFER_BIN = 1;

## arg processing and usage

my @specs = # Array of array-refs, each inner array is an option group which
            # has the format [Group Description, Opt1 Spec, Opt1 Description,
            # Opt2 Spec, Opt2 Description, ...]
  (
   ['Options controlling the configure script:',
    'help|h|?', 'Show this help and exit',
    'verbose|v', 'Trace script execution',
    'dry-run|n', 'Don\'t do anything',
   ],
   ['Build platform and compiler:',
    'host=s', 'Host (auto detect: linux, win32, solaris, macosx)',
    'compiler=s', 'Compiler (auto detect / guess by searching PATH)',
    'target=s', 'Cross-compile target (none)',
    'prefix=s', 'Installation prefix (none)',
   ],
   ['Build flags:',
    'debug!', 'Debugging (yes)',
    'optimize!', 'Optimization (no)',
    'inline!', 'Inlining (yes)',
    'static!', 'Static libraries (no)',
    'ipv6!', 'IPv6 support (no)',
   ],
   ['Required dependencies for OpenDDS:',
    'ace=s', 'ACE (use ACE_ROOT, ../ACE_wrappers, or download)',
    'tao=s', 'TAO (use TAO_ROOT, ACE_ROOT/TAO, or download)',
   ],
   ['Advanced ACE+TAO configuration:',
    'configh=s@', 'Extra text for config.h',
    'macros=s@', 'Extra text for platform_macros.GNU',
    'features=s@', 'Extra text for default.features',
    'mpcopts=s', 'Extra command-line args for MPC (if MPC is run)',
   ],
   ['Optional dependencies for OpenDDS:',
    'java:s', 'Java development kit (use JAVA_HOME)',
    'jboss:s', 'JBoss application server (use JBOSS_HOME)',
    'ant:s', 'Ant for JBoss (use ANT_HOME)',
    'wireshark:s', 'Wireshark (use WIRESHARK_SRC)',
    'glib:s', 'GLib for wireshark (use GLIB_ROOT)',
    'qt:s', 'Qt (use QTDIR)',
    'qt-include:s', 'Qt include dir (use QT4_INCDIR or QTDIR/include)',
    'boost:s', 'Boost (use BOOST_ROOT)',
    'boost-version:s', 'Boost version (only if needed to find headers)',
   ],
   ['Minimizing OpenDDS:',
    'built-in-topics!', 'Built-in Topics (yes)',
    'content-subscription!', 'Content-Subscription Profile (yes)',
    'content-filtered-topic!', 'ContentFilteredTopic (CS Profile) (yes)',
    'multi-topic!', 'MultiTopic (CS Profile) (yes)',
    'query-condition!', 'QueryCondition (CS Profile) (yes)',
    'ownership-profile!', 'Ownership Profile (yes)',
    'ownership-kind-exclusive!', 'Exclusive Ownership (Ownership Profile) (yes)',
    'object-model-profile!', 'Object Model Profile (yes)',
    'persistence-profile!', 'Persistence Profile (yes)',
    'tests!', 'Build tests, examples, and performance tests (yes)',
   ],
  );

sub iterate {
  my $callback = shift;
  for my $group (@specs) {
    for my $n (1 .. (scalar @{$group} / 2)) {
      my $opt = ${$group}[$n * 2 - 1];
      my $descr = ${$group}[$n * 2];
      my ($optkey) = ($opt =~ /([\w-]+)/);
      &$callback(${$group}[0], $opt, $descr, $optkey, @_);
    }
  }
}

sub usage {
  my $current;
  my $ver;
  open VER, 'dds/Version.h' or die "can't open dds/Version.h, stopped";
  while (<VER>) {
    $ver = $1 if /#define DDS_VERSION "([^"]+)"/;
  }
  close VER;
  print <<EOT;
Welcome to OpenDDS version $ver

Options for this script are listed below, with the default behavior described
in parens after the option description.
Boolean options can take the form "--opt" or "--no-opt", the more commonly
needed one (the one that changes the default behavior) is shown below.
Options that require arguments are shown as "--opt=VAL"  Options with optional
arguments are shown as "--opt[=VAL]".  Options that can be repeated with
cumulative effect are shown with a trailing "...".
EOT
  iterate(sub {
            my ($group, $opt, $descr, $optkey) = @_;
            if ($group ne $current) {
              $current = $group;
              print "\n$group\n";
            }
            $optkey .= '=VAL' if $opt =~ /=s/;
            $optkey .= '[=VAL]' if $opt =~ /:s/;
            $optkey = "[no-]$optkey"
              if ($opt =~ /!$/ && $descr =~ / \(yes\)$/);
            $optkey .= '...' if $opt =~ /s\@$/;
            print "--$optkey" . ' ' x (27 - length $optkey) . " $descr\n";
          }
         );
  exit 1;
}

my %opts = ();

## set defaults

my @getopts = ();
iterate(sub {
          my ($group, $opt, $descr, $optkey) = @_;
          if ($descr =~ / \(yes\)$/) {
            $opts{$optkey} = 1;
          }
          push @getopts, $opt;
        }
       );

if (! -r 'rules.dds.GNU') {
  print "ERROR: this script must be run from its own directory\n";
  exit 1;
}

GetOptions(\%opts, @getopts) or usage();
usage() if $opts{'help'};

if ($opts{'verbose'}) {
  print "Options:\n";
  new Dumpvalue()->dumpValue(\%opts);
}

## host

sub get_host {
  if ($^O eq 'darwin') {
    return 'macosx';
  }
  elsif ($^O eq 'MSWin32') {
    return 'win32';
  }
  else {
    return $^O; # solaris, linux match what we expect
  }
}

my %platforminfo =
  ('win32' => {
               'compilers' => ['cl'],
               'libpath' => 'PATH',
              },
   'macosx' => {
                'compilers' => ['g++'],
                'libpath' => 'DYLD_LIBRARY_PATH',
               },
   'solaris' => {
                 'compilers' => ['CC', 'g++'],
                 'libpath' => 'LD_LIBRARY_PATH',
                 'aceplatform' => 'sunos5_$COMP', # $COMP = sunc++ or g++
                 'aceconfig' => 'sunos$UNAMER', # $UNAMER = `uname -r`
                },
   'linux' => {
               'compilers' => ['g++'],
               'libpath' => 'LD_LIBRARY_PATH',
              },
  );

$opts{'host'} = get_host() unless $opts{'host'};
if (!exists $platforminfo{$opts{'host'}}) {
  die "ERROR: unknown host $opts{'host'}, stopped";
}
print "host system is: $opts{'host'}\n" if $opts{'verbose'};
if ($opts{'host'} eq 'macosx') {
  my $vers = `sw_vers -productVersion`;
  $vers =~ /10\.(\d+)\.?/;
  my %versToName = (5 => 'leopard', 6 => 'snowleopard', 7 => 'lion', 8 => 'mountainlion');
  if (!exists $versToName{$1}) {
    die "ERROR: Unknown/unsupported Mac OS X version: $1, stopped";
  }
  $opts{'host_version'} = $versToName{$1};
  print "Mac OS X version is: $opts{'host_version'}\n" if $opts{'verbose'};
}

my ($slash, $exeext) = ($opts{'host'} eq 'win32') ? ('\\', '.exe') : ('/', '');

sub which {
  my $file = shift;
  for my $p (File::Spec->path()) {
    if (-x "$p/$file") {
      return "$p/$file";
    }
    elsif ($opts{'host'} eq 'win32' && -x "$p/$file.exe") {
      return "$p/$file.exe";
    }
  }
  return undef;
}

## compiler

sub get_compiler {
  print "Auto-detecting compiler\n" if $opts{'verbose'};
  for my $stdcomp (@{$platforminfo{$opts{'host'}}->{'compilers'}}) {
    my $path = which($stdcomp);
    if ($path) {
      print "Found $stdcomp at: $path\n" if $opts{'verbose'};
      return $stdcomp;
    }
  }
  return undef;
}

if ($opts{'compiler'}) {
  my $standard = 0;
  for my $stdcomp (@{$platforminfo{$opts{'host'}}->{'compilers'}}) {
    $standard = 1 if $opts{'compiler'} eq $stdcomp;
  }
  $opts{'nonstdcompiler'} = 1 unless $standard;
}
else {
  $opts{'compiler'} = get_compiler();
  if (!defined $opts{'compiler'}) {
    die "Can't find a compiler, set PATH or run this script with the ".
      "--compiler option.\n" . ($slash eq '\\' ? "  For Microsoft Visual C++, ".
                                "run this script from the Visual Studio ".
                                "Command Prompt.\n" : '') . "Stopped";
  }
}
print "compiler is: $opts{'compiler'}\n" if $opts{'verbose'};

if ($opts{'compiler'} =~ /cl(\.exe)?$/i) {
  my $savepath = $ENV{'PATH'};
  my $clpath = which($opts{'compiler'});
  if ($clpath) {
    $clpath =~ s/vc\\bin(\\(x86_)?amd64)?/common7\\ide/i;
    $ENV{'PATH'} .= ";$clpath";
  }
  my %vers = (13 => 'vc71', 14 => 'vc8', 15 => 'vc9', 16 => 'vc10');
  open(CL, "\"$opts{'compiler'}\" /v 2>&1 |");
  while (<CL>) {
    if (/Compiler Version (\d+)\./) {
      if (!exists $vers{$1}) {
        die "Unknown or unsupported Visual C++ compiler version: $1\nStopped";
      }
      $opts{'compiler_version'} = $vers{$1};
      last;
    }
  }
  close CL;
  if (!$opts{'compiler_version'}) {
    die "Could not detect Visual C++ version, try running this script from\n" .
      "the Visual Studio Command Prompt.\nStopped";
  }
  $ENV{'PATH'} = $savepath;
  print "detected Visual C++ version: $opts{'compiler_version'}\n"
    if $opts{'verbose'};
}

## target

if ($opts{'target'}) {
  die "Cross-compilation is not yet supported with this script (--target)\n";
}

## DDS_ROOT

my %extraENV;
sub setenv {
  my($name, $val) = @_;
  $val = Cwd::abs_path($val) if -d $val;
  $val =~ s!/!\\!g if $slash eq '\\';
  $ENV{$name} = $extraENV{$name} = $val;
  print "Setting $name to $val\n" if $opts{'verbose'};
}

setenv('DDS_ROOT', '.');

## ace

if ($opts{'ace'}) {
  if (!-r $opts{'ace'} . '/ace/ACE.h') {
    die "Can't find ACE at $opts{'ace'}\n";
  }
  setenv('ACE_ROOT', $opts{'ace'});
}
elsif ($ENV{'ACE_ROOT'} && !-r $ENV{'ACE_ROOT'} . '/ace/ACE.h') {
  die "Can't find ACE at $ENV{'ACE_ROOT'}\n";
}
elsif (!$ENV{'ACE_ROOT'} && -r '../ACE_wrappers/ace/ACE.h'
       && -r '../ACE_wrappers/TAO/tao/ORB.h') {
  setenv('ACE_ROOT', '../ACE_wrappers');
  setenv('TAO_ROOT', $ENV{'ACE_ROOT'} . $slash . 'TAO');
}

## tao

if ($opts{'tao'}) {
  if (!-r $opts{'tao'} . '/tao/ORB.h') {
    die "Can't find TAO at $opts{'tao'}\n";
  }
  setenv('TAO_ROOT', $opts{'tao'});
}
elsif ($ENV{'TAO_ROOT'} && !-r $ENV{'TAO_ROOT'} . '/tao/ORB.h') {
  die "Can't find TAO at $ENV{'TAO_ROOT'}\n";
}
elsif (!$ENV{'TAO_ROOT'} && $ENV{'ACE_ROOT'}
       && -r $ENV{'ACE_ROOT'} . '/TAO/tao/ORB.h') {
  setenv('TAO_ROOT', $ENV{'ACE_ROOT'} . $slash . 'TAO');
}

## Download ACE+TAO

if (!$ENV{'ACE_ROOT'} || !$ENV{'TAO_ROOT'}) {
  my $urlbase = 'http://download.ociweb.com/TAO-' . $tao_version . '/';
  my $file = 'ACE+TAO-' . $tao_version . '_with_latest_patches_NO_makefiles.'
    . ($slash eq '/' ? 'tar.gz' : 'zip');
  my $download_message = "Downloading ACE+TAO " . $tao_version . " with latest patches";
  if (-r $file) {
    print "Using ACE+TAO source package $file\n" if $opts{'verbose'};
  }
  else {
    eval {require LWP::UserAgent;};
    if ($@) {
      if (which('wget')) {
        print $download_message . " (using wget)\n";
        if ($opts{'dry-run'}) {
          print "Dry-run: would run wget $urlbase$file\nExiting\n";
          exit 1;
        }
        if (system("wget $urlbase$file")) {
          die "ERROR from wget, stopped";
        }
      }
      elsif (which('curl')) {
        print $download_message . " (using curl)\n";
        if ($opts{'dry-run'}) {
          print "Dry-run: would run curl $urlbase$file -o $file\nExiting\n";
          exit 1;
        }
        if (system("curl $urlbase$file -o $file")) {
          die "ERROR from curl, stopped";
        }
      }
      else {
        die "Can't download ACE+TAO using LWP, wget, or curl.\nDownload it ".
          "from $urlbase$file, place the file here\n, and re-run the script.\n";
      }
    }
    else {
      my $ua = LWP::UserAgent->new;
      $ua->env_proxy;
      print $download_message . "\n";
      if ($opts{'dry-run'}) {
        print "Dry-run: would LWP::UserAgent get $urlbase$file\nExiting\n";
        exit 1;
      }
      my $response = $ua->get($urlbase . $file, ':content_file' => $file);
      if ($response->is_error) {
        die $response->message . "\nstopped";
      }
    }
  }

  print "Extracting archive $file\n";
  eval {require Archive::Extract;};
  if ($@) {
    my $ddsroot = getcwd;
    chdir('..');
    my $err = 1;
    if ($slash eq '/') {
      if ($opts{'dry-run'}) {
        print "Dry-run: would run " . ($^O eq 'solaris' ? 'g' : '') .
          "tar xzf $ddsroot/$file\nExiting\n";
        exit 1;
      }
      $err = system(($^O eq 'solaris' ? 'g' : '') . "tar xzf $ddsroot/$file");
    }
    if ($err) {
      die "Can't extract $file, extract it to " . Cwd::abs_path('.') .
        "\nand run this script again.\nStopped";
    }
    chdir($ddsroot);
  }
  else {
    my $ae = Archive::Extract->new('archive' => $file);
    if ($opts{'dry-run'}) {
      print "Dry-run: would Archive::Extract $file\nExiting\n";
      exit 1;
    }
    if (!$ae->extract('to' => '..')) {
      die $ae->error . "\nstopped";
    }
  }

  setenv('ACE_ROOT', '../ACE_wrappers');
  setenv('TAO_ROOT', $ENV{'ACE_ROOT'} . $slash . 'TAO');
}

print "Using ACE_ROOT: $ENV{'ACE_ROOT'}\n" if $opts{'verbose'};
print "Using TAO_ROOT: $ENV{'TAO_ROOT'}\n" if $opts{'verbose'};
my $tao_maj = 1;
open TAOVER, $ENV{'TAO_ROOT'} . '/VERSION' or die "can't open TAO VERSION\n";
while (<TAOVER>) {
  if (/^This is TAO version (\d)/) {
    $tao_maj = $1;
    last;
  }
}
close TAOVER;

## Configure ACE+TAO

sub backup_and_open {
  my $file = shift;
  if (!$opts{'dry-run'} && -r $file) {
    my $backup = (-e $file . '.bak') ? ($file . '.bak') : $file . ".bak.$$";
    copy($file, $backup);
    print "WARNING: overwriting existing $file (saved a backup copy as " .
      "$backup)\n";
  }
  if ($opts{'dry-run'}) {
    return File::Temp->new(UNLINK => 1);
  }
  my $fh = new FileHandle;
  open $fh, ">$file" or die "Can't write to $file, stopped";
  return $fh;
}

my $wrote_df = 0;

if (-r "$ENV{'ACE_ROOT'}/ace/config.h") {
  print "ACE_ROOT/ace/config.h exists, skipping configuration of ACE+TAO\n";
}
else {
  $opts{'optimize'} = 0 if !exists $opts{'optimize'};
  my $pi = $platforminfo{$opts{'host'}};

  # config.h
  my $CFGH = backup_and_open("$ENV{'ACE_ROOT'}/ace/config.h");
  for my $line (@{$opts{'configh'}}) {
    print $CFGH "$line\n";
  }
  my $cfg = $opts{'host'};
  if ($pi->{'aceconfig'}) {
    $cfg = $pi->{'aceconfig'};
    $cfg =~ s/\$UNAMER/my $u = `uname -r`; chomp $u; $u/e;
  }
  $cfg .= '-' . $opts{'host_version'} if $opts{'host_version'};
  print $CFGH "#include \"ace/config-$cfg.h\"\n";
  close $CFGH;
  print "Wrote config.h\n" if $opts{'verbose'};

  # default.features
  if ($opts{'ipv6'} || $opts{'features'}) {
    my $DF = backup_and_open("$ENV{'ACE_ROOT'}/bin/MakeProjectCreator/config" .
                             "/default.features");
    $wrote_df = 1;
    print $DF "ipv6=1\n" if $opts{'ipv6'};
    for my $f (@{$opts{'features'}}) {
      print $DF "$f\n";
    }
    $DF->close;
    print "Wrote default.features\n" if $opts{'verbose'};
  }

  # platform_macros.GNU
  if ($slash eq '/') {
    my $PMG = backup_and_open("$ENV{'ACE_ROOT'}/include/makeinclude" .
                               "/platform_macros.GNU");
    for my $line (@{$opts{'macros'}}) {
      print $PMG "$line\n";
    }
    for my $key ('debug', 'optimize', 'inline', 'static', 'ipv6') {
      if (exists $opts{$key}) {
        my $macro = ($key eq 'static') ? 'static_libs_only' : $key;
        print $PMG "$macro = $opts{$key}\n";
      }
    }
    if ($opts{'prefix'}) {
      print $PMG "INSTALL_PREFIX=" . $opts{'prefix'} . "\n";
    }
    my $plat = $opts{'host'};
    if ($pi->{'aceplatform'}) {
      $plat = $pi->{'aceplatform'};
      $plat =~ s/\$COMP/($opts{'compiler'} =~ m!CC!) ? 'sunc++' : 'g++'/e;
    }
    $plat .= '_' . $opts{'host_version'} if $opts{'host_version'};
    print $PMG "include \$(ACE_ROOT)/include/makeinclude/platform_$plat.GNU\n";
    if ($opts{'nonstdcompiler'}) {
      for my $var ('CC', 'CXX', 'LD') {
        print $PMG "$var = $opts{'compiler'}\n";
      }
    }
    $PMG->close;
    print "Wrote platform_macros.GNU\n" if $opts{'verbose'};
  }
}

## Optional OpenDDS dependencies

my %optdep =
# %opts key =>    [env var,         sanity check,          MPC feature]
  ('java' =>      ['JAVA_HOME',     'include/jni.h',             'java'],
   'jboss' =>     ['JBOSS_HOME',    'lib/jboss-common.jar'],
   'ant' =>       ['ANT_HOME',      'bin/ant'],
   'wireshark' => ['WIRESHARK_SRC', 'epan/packet.h',             'wireshark'],
   'glib' =>      ['GLIB_ROOT',     'include/glib-2.0/glib.h'],
   'qt' =>        ['QTDIR',         '',                          'qt4'],
   'boost' =>     ['BOOST_ROOT',    'include/boost/version.hpp', 'boost'],
  );

if (exists $opts{'java'}) {
  if ($opts{'static'}) {
    die "ERROR: --static can't be used with --java\n";
  }
  setenv('JAVA_PLATFORM', $opts{'host'});
}

sub env_from_opt {
  my $key = shift;
  my $e = shift;
  if ($opts{$key} && (!$ENV{$e} || $opts{$key} ne $ENV{$e})) {
    setenv($e, $opts{$key});
  }
}

if (exists $opts{'boost'} && exists $opts{'boost-version'}) {
  env_from_opt('boost', $optdep{'boost'}->[0]);
  env_from_opt('boost-version', 'BOOST_VERSION');
  if ($ENV{'BOOST_VERSION'}
      && !-r $ENV{'BOOST_ROOT'} . '/' . $optdep{'boost'}->[1]
      && -r $ENV{'BOOST_ROOT'} . '/include/' . $ENV{'BOOST_VERSION'}
      . '/boost/version.hpp') {
    $optdep{'boost'}->[1] = ''; # skip sanity check in for-loop below
  }
}

my @features;
for my $key(keys %optdep) {
  if (exists $opts{$key}) {
    print "Enabling $key\n" if $opts{'verbose'};
    my ($e, $s, $m) = @{$optdep{$key}};
    env_from_opt($key, $e);
    if ($s && !-r $ENV{$e} . '/' . $s) {
      die "Can't find $key at $ENV{$e} (using $s)\n";
    }
    push(@features, $m) if $m;
  }
}

if (exists $opts{'jboss'} && !exists $opts{'java'}) {
  die "--java is required for --jboss (OpenDDS JMS Provider)\n";
}

if (exists $opts{'jboss'} && !exists $opts{'ant'}) {
  die "--ant is required for --jboss (OpenDDS JMS Provider)\n";
}

if (exists $opts{'wireshark'} && !exists $opts{'glib'}) {
  die "--glib is required for --wireshark\n";
}

if ($opts{'qt-include'}) {
  setenv('QT4_INCDIR', $opts{'qt-include'});
}

if (exists $opts{'qt'} && !-r ($ENV{'QT4_INCDIR'} ? $ENV{'QT4_INCDIR'} :
                               "$ENV{'QTDIR'}/include")
    . '/QtCore/qconfig.h') {
  die "Can't find qt at " . ($ENV{'QT4_INCDIR'} ? $ENV{'QT4_INCDIR'} :
                             $ENV{'QTDIR'}) . "\nstopped";
}

## PATH and LD_LIBRARY_PATH

$extraENV{'PATH'} = [$ENV{'ACE_ROOT'} . $slash . 'bin',
                     $ENV{'DDS_ROOT'} . $slash . 'bin'];

my $libpaths = [$ENV{'ACE_ROOT'} . $slash . 'lib',
                $ENV{'DDS_ROOT'} . $slash . 'lib'];

my $libvarname = $platforminfo{$opts{'host'}}->{'libpath'};
if (exists $extraENV{$libvarname}) {
  push(@{$extraENV{$libvarname}}, @$libpaths);
}
else {
  $extraENV{$libvarname} = $libpaths;
}

## Run MPC (if needed)

for my $feat (qw/built-in-topics content-subscription content-filtered-topic
                 multi-topic query-condition ownership-profile
                 ownership-kind-exclusive object-model-profile
                 persistence-profile/) {
  if (exists $opts{$feat} && !$opts{$feat}) {
    my $f = $feat;
    $f =~ s/-/_/g;
    push(@features, "$f=0");
  }
}

my $needmpc = scalar @features ? 1 : 0;
if ($needmpc && $slash eq '/') {
  print "Creating user_macros.GNU with MPC feature settings\n"
    if $opts{'verbose'};
  my $UM = backup_and_open('user_macros.GNU');
  for my $feat (@features) {
    print $UM ($feat =~ /=/ ? $feat : "$feat=1"), "\n";
  }
  $UM->close;
}

my $tests = 1;
($needmpc, $tests) = (1, 0) if (exists $opts{'tests'} && !$opts{'tests'});

my $buildtao = 0;
$needmpc = $buildtao = 1 if !-x "$ENV{'ACE_ROOT'}/bin/tao_idl$exeext";

if ($slash eq '/' && ($needmpc || !-r 'GNUmakefile')) {
  $needmpc = 'gnuace';
}
elsif ($slash ne '/' && ($needmpc || !-r 'DDS.sln')) {
  $needmpc = $opts{'compiler_version'};
}

if ($needmpc) {
  if (!$ENV{'MPC_ROOT'} && -r $ENV{'ACE_ROOT'} . '/MPC/MPC.ico') {
    setenv('MPC_ROOT', $ENV{'ACE_ROOT'} . $slash . 'MPC');
  }
  elsif (!$ENV{'MPC_ROOT'}) {
    die "Can't find MPC.  Please set MPC_ROOT or make sure MPC exists in the\n".
      "'MPC' directory under ACE_ROOT ($ENV{'ACE_ROOT'}), stopped";
  }

  if (@features) {
    my $df_file =
      "$ENV{'ACE_ROOT'}/bin/MakeProjectCreator/config/default.features";
    my $DF = $wrote_df
      ? ($opts{'dry-run'} ? File::Temp->new(UNLINK => 1)
                          : new FileHandle(">>$df_file"))
      : backup_and_open($df_file);
    for my $f (@features) {
      print $DF ($f =~ /=/ ? $f : "$f=1"), "\n";
    }
    $DF->close;
    if ($opts{'verbose'}) {
      print '' . ($wrote_df ? 'Appended to' : 'Wrote') . " default.features\n";
    }
  }

  my $ws = 'DDS.mwc';
  if (!$tests && $buildtao) {
    $ws = 'DDS_TAO.mwc';
  }
  elsif (!$tests && !$buildtao) {
    $ws = 'DDS_no_tests.mwc';
  }
  elsif ($buildtao) {
    $ws = 'DDS_TAO_all.mwc';
  }

  if ($tao_maj == 2 && $ws =~ /TAO/) {
    $ws =~ s/TAO/TAOv2/;
  }

  my $static = ($opts{'static'} && $slash ne '/') ? '-static' : '';

  if (!defined $ENV{'CIAO_ROOT'}) {
    setenv('CIAO_ROOT', 'dont_use_ciao'); # otherwise MPC.cfg includes /MPC
  }

  print 'Running MPC to generate ', ($needmpc eq 'gnuace' ? 'makefiles' :
                                     'project files'), ".\n";
  my $mwcargs = "-type $needmpc $ws $static " . $opts{'mpcargs'};
  print "mwc command line: $mwcargs\n"
    if $opts{'verbose'};
  if (!$opts{'dry-run'}) {
    if (system("perl $ENV{'ACE_ROOT'}/bin/mwc.pl $mwcargs") != 0) {
      die "Error from MPC, stopped";
    }
  }

  $ws =~ s/\.mwc$/.sln/;
  $opts{'solution_file'} = $ws;
}
elsif ($opts{'compiler_version'}) { #win32, using DDS release package projects
  $opts{'solution_file'} = 'DDS' . ($opts{'static'} ? '_Static' : '') .
    ($opts{'compiler_version'} ne 'vc71' ? "_$opts{'compiler_version'}" : '') .
      '.sln';
}

## Create setenv.sh and "master" GNUmakefile

my %specific =
  ($slash eq '/' ?
   ('ext' => 'sh', 'export' => 'export', 'pathsep' => ':', 'refpre' => '${',
    'refpost' => '}') :
   ('ext' => 'cmd', 'export' => 'set', 'pathsep' => ';', 'refpre' => '%',
    'refpost' => '%')
  );

my $MK = undef;
if ($slash eq '/') {
  if (!$opts{'dry-run'} && !-r 'GNUmakefile.dist') {
    move('GNUmakefile', 'GNUmakefile.dist');
  }
  $MK = backup_and_open('GNUmakefile');
}

my $SE = backup_and_open('setenv.' . $specific{'ext'});
for my $key (keys %extraENV) {
  if (UNIVERSAL::isa($extraENV{$key}, 'ARRAY')) {
    print $SE "$specific{'export'} $key=",
      join($specific{'pathsep'}, @{$extraENV{$key}}), $specific{'pathsep'},
        $specific{'refpre'}, $key, $specific{'refpost'}, "\n";
    if ($MK) {
      print $MK "export $key := ",
        join($specific{'pathsep'}, @{$extraENV{$key}}), $specific{'pathsep'},
          $specific{'refpre'}, $key, $specific{'refpost'}, "\n";
    }
  }
  else {
    print $SE "$specific{'export'} $key=$extraENV{$key}\n";
    if ($MK) {
      print $MK "export $key := $extraENV{$key}\n";
    }
  }
}

$SE->close;
print "Wrote setenv.$specific{'ext'}\n" if $opts{'verbose'};

if ($MK) {
  print $MK "include GNUmakefile.dist\n";
  $MK->close;
  print "Wrote GNUmakefile, wrapping orignial GNUmakefile.dist\n"
    if $opts{'verbose'};
}

## Final message

print "Completed configuring OpenDDS, next ";
if ($slash eq '/') {
  print "run '", ($^O eq 'solaris' ? 'g' : ''), "make'";
}
else {
  print "build '", $opts{'solution_file'}, "' using the '",
    ($opts{'optimize'} ? 'Release' : 'Debug'), "' configuration";
}
print " to compile OpenDDS", ($buildtao ? ' and ACE+TAO' : '') ,".\n",
  "You can use the generated setenv.$specific{'ext'} script to set ",
  "environment variables for\nfuture shell sessions.\n";
if ($slash ne '/') {
  print "Start Visual Studio from this command prompt so that it inherits ",
    "the correct\nenvironment variables.\n";
}
