summaryrefslogtreecommitdiff
path: root/infrastructure
diff options
context:
space:
mode:
Diffstat (limited to 'infrastructure')
-rw-r--r--infrastructure/BoxPlatform.pm78
-rwxr-xr-xinfrastructure/buildenv-testmain-template.cpp144
-rwxr-xr-xinfrastructure/makebuildenv.pl1126
-rwxr-xr-xinfrastructure/makedistribution.pl312
-rwxr-xr-xinfrastructure/makeparcels.pl166
-rwxr-xr-xinfrastructure/setupexternal.pl55
-rw-r--r--infrastructure/tests/common_tests.pl178
7 files changed, 2059 insertions, 0 deletions
diff --git a/infrastructure/BoxPlatform.pm b/infrastructure/BoxPlatform.pm
new file mode 100644
index 00000000..4c8280a3
--- /dev/null
+++ b/infrastructure/BoxPlatform.pm
@@ -0,0 +1,78 @@
+package BoxPlatform;
+use Exporter;
+@ISA = qw/Exporter/;
+@EXPORT = qw/$build_os $make_command $bsd_make $platform_define $gcc_v3 $gcc_v4 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra/;
+
+BEGIN
+{
+
+ # which OS are we building under?
+ $build_os = `uname`;
+ chomp $build_os;
+ # Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1
+ # Box Backup tried on Win2000,XP only :)
+ $build_os = 'CYGWIN' if $build_os =~ m/CYGWIN/;
+
+ $make_command = ($build_os ne 'Darwin')?'make':'bsdmake';
+ $bsd_make = ($build_os ne 'Linux' && $build_os ne 'CYGWIN');
+ $platform_define = 'PLATFORM_'.uc($build_os);
+
+ # blank extra flags by default
+ $platform_compile_line_extra = '';
+ $platform_link_line_extra = '';
+
+ # compiler version?
+ $gcc_v3 = 0;
+ $gcc_v4 = 0;
+ open COMPILER,"gcc -v 2>&1 |" or die "Can't open gcc -v";
+ while(<COMPILER>)
+ {
+ $gcc_v3 = 1 if (m/version gcc 3/ || m/gcc version 3/ || m/gcc \(GCC\) 3/i || m/gcc.Version\s+3/i);
+ $gcc_v4 = 1 if (m/version gcc 4/ || m/gcc version 4/ || m/gcc \(GCC\) 4/i || m/gcc.Version\s+4/i);
+ }
+ close COMPILER;
+ $gcc_v3 = 1 if $gcc_v4; # hacks are about the same
+
+ # get version
+ open VERSION,"VERSION.txt";
+ $product_version = <VERSION>;
+ chomp $product_version;
+ $product_name = <VERSION>;
+ chomp $product_name;
+ close VERSION;
+
+ # where to put the files
+ $install_into_dir = '/usr/local/bin';
+
+ # if it's Darwin,
+ if($build_os eq 'Darwin')
+ {
+ # see how many processors there are, and set make flags accordingly
+ my $cpus = `sysctl hw.ncpu`;
+ if($cpus =~ m/hw.ncpu:\s(\d+)/ && $1 > 1)
+ {
+ print "$1 processors detected, will set make to perform concurrent jobs\n";
+ $sub_make_options = ' -j '.($1 + 1);
+ }
+
+ # test for fink installation
+ if(-d '/sw/include' && -d '/sw/lib')
+ {
+ print "Fink installation detected, will use headers and libraries\n";
+ $platform_compile_line_extra = '-I/sw/include ';
+ $platform_link_line_extra = '-L/sw/lib ';
+ }
+ }
+}
+
+sub make_flag
+{
+ if($bsd_make)
+ {
+ return "-D $_[0]"
+ }
+ return $_[0].'=1';
+}
+
+1;
+
diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp
new file mode 100755
index 00000000..36cc4da0
--- /dev/null
+++ b/infrastructure/buildenv-testmain-template.cpp
@@ -0,0 +1,144 @@
+//
+// AUTOMATICALLY GENERATED FILE
+// do not edit
+//
+
+
+// --------------------------------------------------------------------------
+//
+// File
+// Name: testmain.template.h
+// Purpose: Template file for running tests
+// Created: 2003/07/08
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include "stdio.h"
+#include <exception>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "MemLeakFindOn.h"
+
+int test(int argc, const char *argv[]);
+
+#ifdef NDEBUG
+ #define MODE_TEXT "release"
+#else
+ #define MODE_TEXT "debug"
+#endif
+
+int failures = 0;
+
+int filedes_open_at_beginning = -1;
+
+int count_filedes()
+{
+ int c = 0;
+
+ // See how many file descriptors there are with values < 256
+ for(int d = 0; d < 256; ++d)
+ {
+ if(::fcntl(d, F_GETFD) != -1)
+ {
+ // File descriptor obviously exists
+ ++c;
+ }
+ }
+
+ return c;
+}
+
+bool checkfilesleftopen()
+{
+ if(filedes_open_at_beginning == -1)
+ {
+ // Not used correctly, pretend that there were things left open so this gets invesitgated
+ return true;
+ }
+
+ // make sure syslog log file is closed, if it was opened
+ ::closelog();
+
+ // Count the file descriptors open
+ return filedes_open_at_beginning != count_filedes();
+}
+
+int main(int argc, const char *argv[])
+{
+ // Start memory leak testing
+ MEMLEAKFINDER_START
+
+ // If there is more than one argument, then the test is doing something advanced, so leave it alone
+ bool fulltestmode = (argc == 1);
+
+ if(fulltestmode)
+ {
+ // Count open file descriptors for a very crude "files left open" test
+ filedes_open_at_beginning = count_filedes();
+
+ // banner
+ printf("Running test TEST_NAME in " MODE_TEXT " mode...\n");
+ }
+ try
+ {
+ int returncode = test(argc, argv);
+
+ // check for memory leaks, if enabled
+ #ifdef BOX_MEMORY_LEAK_TESTING
+ if(memleakfinder_numleaks() != 0)
+ {
+ failures++;
+ printf("FAILURE: Memory leaks detected\n");
+ printf("==== MEMORY LEAKS =================================\n");
+ memleakfinder_reportleaks();
+ printf("===================================================\n");
+ }
+ #endif
+
+ if(fulltestmode)
+ {
+ bool filesleftopen = checkfilesleftopen();
+ if(filesleftopen)
+ {
+ failures++;
+ printf("IMPLICIT TEST FAILED: Something left files open\n");
+ }
+ if(failures > 0)
+ {
+ printf("FAILED: %d tests failed\n", failures);
+ }
+ else
+ {
+ printf("PASSED\n");
+ }
+ }
+
+ return returncode;
+ }
+ catch(std::exception &e)
+ {
+ printf("FAILED: Exception caught: %s\n", e.what());
+ return 1;
+ }
+ catch(...)
+ {
+ printf("FAILED: Unknown exception caught\n");
+ return 1;
+ }
+ if(fulltestmode)
+ {
+ if(checkfilesleftopen())
+ {
+ printf("WARNING: Files were left open\n");
+ }
+ }
+}
+
diff --git a/infrastructure/makebuildenv.pl b/infrastructure/makebuildenv.pl
new file mode 100755
index 00000000..99455cc2
--- /dev/null
+++ b/infrastructure/makebuildenv.pl
@@ -0,0 +1,1126 @@
+#!/usr/bin/perl
+use strict;
+use Symbol;
+
+my @modules;
+my %module_dependency;
+my %module_library_link_opts;
+my %header_dependency;
+
+$|=1;
+
+
+# note: Mac OS X resource forks and .DS_Store files are explicity ignored
+
+print "Box build environment setup.\n\nChecking environment...\n";
+
+
+my $implicit_dep = 'lib/common';
+
+# work out platform variables
+use lib 'infrastructure';
+use BoxPlatform;
+
+# don't allow old versions of openssl by default.
+my $old_version_of_openssl_ok = 0;
+
+# keep copy of command line args
+my $makebuildenv_args = join(' ',@ARGV);
+
+# do command line arguments
+my $compile_line_extra = $platform_compile_line_extra;
+my $link_line_extra = $platform_link_line_extra;
+for(@ARGV)
+{
+ if($_ eq 'allow-old-openssl')
+ {
+ $old_version_of_openssl_ok = 1;
+ next;
+ }
+ my ($k,$v) = split /:/,$_,2;
+ if($k eq 'compile')
+ {
+ $compile_line_extra .= $v . ' ';
+ }
+ elsif($k eq 'link')
+ {
+ $link_line_extra .= $v . ' ';
+ }
+ elsif($k eq 'openssl')
+ {
+ # assume that the bin/lib/include dirs are under the specified path
+ chop $v if ($v =~ /\/$/);
+ $compile_line_extra = "-I$v/include $compile_line_extra";
+ $link_line_extra = "-L$v/lib $link_line_extra";
+ }
+ else
+ {
+ die "invalid option $_ specified on command line"
+ }
+}
+
+# make sure local files directory exists
+unless(-d 'local')
+{
+ mkdir 'local',0755;
+}
+
+
+# flags about the environment
+my %env_flags;
+# messages on test failure
+my $test_failure_text;
+
+# run all tests
+{
+ opendir DIR,'infrastructure/tests' or die "Can't read the tests directory";
+ my @tests = grep {m/_tests\.pl\Z/} readdir DIR;
+ closedir DIR;
+ for(@tests)
+ {
+ require "infrastructure/tests/$_";
+ }
+}
+
+
+# ---- LINUX start --------------------------------------------------------------------------
+# do configuration on Linux... find out what's available, and configure appropraitely.
+if($build_os eq 'Linux')
+{
+ # setup the basic library translation flags -- these will omit those libraries from the compile line
+ $env_flags{'LIBTRANS_-lreadline'} = '';
+ $env_flags{'LIBTRANS_-lLINUX_DB'} = '';
+
+ my $curses_lib = '-lcurses';
+ if((!exists($env_flags{'curses_PRESENT'})) && exists($env_flags{'ncurses_PRESENT'}))
+ {
+ # got to use ncurses instead...
+ $env_flags{'LIBTRANS_-lcurses'} = '-lncurses';
+ $curses_lib = '-lncurses';
+ }
+
+ my ($linux_readline_h, $linux_db_h);
+ my $db_ver = -1;
+
+ open H_FILES,"find /usr/include |" or die "Can't open find";
+ while(<H_FILES>)
+ {
+ chomp;
+
+ if(m~/readline.h\Z~)
+ {
+ my $rlh = strip_h_name($_);
+ if(check_readline_h($rlh,$curses_lib))
+ {
+ $linux_readline_h = $rlh;
+ # allow readline library to be used
+ delete $env_flags{'LIBTRANS_-lreadline'};
+ }
+ }
+ if(m~/db(|_1\d+).h\Z~)
+ {
+ # version?
+ my $dv = 0;
+ $dv = $1 if m~(\d+)/db~;
+ my $fn = $_;
+
+ # check this file mentions dbopen
+ open DB_H,$_ or die "Can't open $_";
+ my $found = 0;
+ while(<DB_H>)
+ {
+ if(m/dbopen/)
+ {
+ $found = 1;
+ last;
+ }
+ }
+ close DB_H;
+ next unless $found;
+
+ # see if this version works
+ print("Checking db version...\n");
+ my $db_h = strip_h_name($fn);
+ my $db_lib = 'db';
+ $db_lib .= $db_ver if $db_ver > 0;
+ if(!check_db_lib($db_h, $db_lib))
+ {
+ # try another
+ $db_lib = 'db';
+ next unless check_db_lib($db_h, $db_lib)
+ }
+
+ # good version?
+ if($dv > $db_ver)
+ {
+ $linux_db_h = $db_h;
+ $db_ver = $dv;
+ $env_flags{'LIBTRANS_-lLINUX_DB'} = '-l'.$db_lib;
+ }
+ }
+ }
+ print "Finished checking headers\n";
+ close H_FILES;
+
+ # write the platform file accordingly and tell the user what's happened.
+ open LIN,">local/_linux_platform.h" or die "Can't open file for writing";
+ if($linux_readline_h eq '')
+ {
+ print("---------------------\nWARNING: readline isn't installed\n---------------------\n");
+ print LIN "#define PLATFORM_READLINE_NOT_SUPPORTED\n";
+
+ }
+ else
+ {
+ open RL_H,">local/_linux_readline.h" or die "Can't open file for writing";
+ print RL_H "#include <$linux_readline_h>\n";
+ my $hist = $linux_readline_h;
+ $hist =~ s/readline\.h/history.h/;
+ print RL_H "#include <$hist>\n";
+ close RL_H;
+ }
+ if($linux_db_h eq '')
+ {
+ print("---------------------\nWARNING: db is not installed -- will run in reduced efficiency mode without it.\n---------------------\n");
+ print LIN "#define PLATFORM_BERKELEY_DB_NOT_SUPPORTED\n";
+ }
+ else
+ {
+ open DB_H,">local/_linux_db.h" or die "Can't open file for writing";
+ print DB_H "#include <$linux_db_h>\n";
+ close DB_H;
+ }
+ close LIN;
+}
+sub strip_h_name
+{
+ my $i = $_[0];
+ $i =~ s~\A/usr/include/~~;
+ return $i;
+}
+sub check_readline_h
+{
+ my ($h,$curses_lib) = @_;
+ print "Check readline from $h...\n";
+ my $hist = $h;
+ $hist =~ s/readline\.h/history.h/;
+ open READLINEH,">readlineh.cpp" or die "Can't open readline test file for writing";
+ print READLINEH <<__E;
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <$h>
+#include <$hist>
+int main(int argc, char *argv[])
+{
+ using_history();
+ add_history(0);
+ readline(0);
+ return 0;
+}
+__E
+ close READLINEH;
+ # attempt to compile
+ my $r = system("g++ readlineh.cpp -lreadline $curses_lib -o readlineh $compile_line_extra $link_line_extra 2>/dev/null >/dev/null");
+ # delete test files
+ unlink 'readlineh';
+ unlink 'readlineh.cpp';
+ return $r == 0; # compilation succeeded
+}
+sub check_db_lib
+{
+ my ($h,$db) = @_;
+ open TESTDBLIB,">testdblib.cpp" or die "Can't open db test file for writing";
+ print TESTDBLIB <<__E;
+#include <$h>
+int main(int argc, char *argv[])
+{
+ DB *dbp = 0;
+ dbp = dbopen(0, 0, 0, DB_HASH, 0);
+ dbp->close(dbp);
+ DBT data;
+ dbp->put(dbp, &data, &data, 0);
+ dbp->get(dbp, &data, &data, 0);
+ return 0;
+}
+__E
+ close TESTDBLIB;
+ # attempt to compile
+ my $r = system("g++ testdblib.cpp -l$db -o testdblib $compile_line_extra $link_line_extra 2>/dev/null >/dev/null");
+ # delete test files
+ unlink 'testdblib';
+ unlink 'testdblib.cpp';
+ return $r == 0; # compilation succeeded
+}
+# ---- LINUX end --------------------------------------------------------------------------
+
+# print "Flag: $_\n" for(keys %env_flags);
+
+# check the version of openssl installed
+if(!exists $env_flags{'OPENSSL_OK'})
+{
+ # failed somehow...
+
+ # is an old version present?
+ my $old_version = (exists $env_flags{'OLD_OPENSSL_OK'});
+
+ if(!$old_version && !-e '/usr/include/openssl/evp.h')
+ {
+ # headers not installed?
+ print "\n\nERROR: OpenSSL library and headers need to be installed.\n\nSee documentation on web site if you need to add extra search paths.\n\n";
+ exit(1);
+ }
+ else
+ {
+ if($old_version)
+ {
+ if($old_version_of_openssl_ok)
+ {
+ print "\n\nWARNING: Configuring for old version of OpenSSL.\nPerformance will be lower than with version 0.9.7\n\n";
+ $compile_line_extra .= '-DPLATFORM_OLD_OPENSSL ';
+ }
+ else
+ {
+ # tell user how they might try anyway with an old version of openssl
+ print <<__E;
+
+===============================================================================
+
+You appear to have a version of OpenSSL installed which is less than 0.9.7.
+
+It is possible to configure to use this old version, but performance will be
+lower than if you have 0.9.7 -- the later version is recommended.
+
+If you wish to use this old version, repeat the configuration with the extra
+argument 'allow-old-openssl', like this:
+
+ ./configure allow-old-openssl
+
+* Please do not distribute binary packages with this option enabled.
+
+* Please do not distribute ports which set this option by default.
+
+IMPORTANT: Support for older versions of OpenSSL should be considered
+experimental. It is not recommended for production use, but provided to allow
+easier evaluation of this software before installing the latest OpenSSL.
+
+===============================================================================
+
+__E
+ exit(1);
+ }
+ }
+ else
+ {
+ print "\n\nERROR: You need to install OpenSSL, preferably at least version 0.9.7.\n\n";
+ print "If you believe you have installed OpenSSL, check that the headers are installed\nas well ('dev' packages?)\n\nSee documentation on web site if you need to add extra search paths.\n\n";
+ exit(1);
+ }
+ }
+}
+
+
+# finished checking the environment
+print "done\n\n";
+
+
+# seed autogen code
+print "Seeding autogen code...\n";
+open FINDAUTOGEN,"find . -follow -name Makefile.extra |" or die "Can't use find for locating files";
+while(<FINDAUTOGEN>)
+{
+ chomp;
+ my $file = $_;
+ $file =~ m~\A(.+)/[^/]+\Z~;
+ my $dir = $1;
+ open FL,$file or die "Can't open $_ for reading";
+ my %vars;
+ my $do_cmds = 0;
+ while(<FL>)
+ {
+ chomp;
+ if(m/\A(.+)\s+=\s+(.+)\Z/)
+ {
+ # is a variable
+ $vars{$1} = $2;
+ next;
+ }
+ next unless m/\S/;
+ if(m/AUTOGEN SEEDING/)
+ {
+ $do_cmds = 1;
+ }
+ elsif(m/\A\S/)
+ {
+ $do_cmds = 0 if $do_cmds == 2;
+ }
+ else
+ {
+ # command, run it?
+ if($do_cmds)
+ {
+ $do_cmds = 2; # flag something has been done
+
+ # subsitute variables, repeatedly
+ my $c = $_;
+ $c =~ s/\A\s+//;
+ while(1)
+ {
+ my $did_subst = 0;
+
+ for my $k (keys %vars)
+ {
+ $did_subst = 1 if $c =~ s/\$\($k\)/$vars{$k}/g;
+ }
+
+ last unless $did_subst;
+ }
+
+ # run command
+ die "Couldn't run command $c" unless (0 == system("(cd $dir; $c)"))
+ }
+ }
+ }
+ close FL;
+}
+close FINDAUTOGEN;
+print "done\n\n";
+
+
+# open test mail program template file
+my $test_template_file = 'infrastructure/buildenv-testmain-template.cpp';
+open FL,$test_template_file or die "Can't open test template file\n";
+my $test_template;
+read FL,$test_template,-s $test_template_file;
+close FL;
+
+
+# extra platform defines
+my $extra_platform_defines = '';
+if($gcc_v3 && !$gcc_v4)
+{
+ $extra_platform_defines .= ' -DPLATFORM_GCC3'
+}
+if($gcc_v4)
+{
+ $extra_platform_defines .= ' -DPLATFORM_GCC4'
+}
+
+# read in module definitions file, and any files it includes
+my @modules_files;
+sub read_modules_file
+{
+ my ($mf) = @_;
+ my $f = gensym;
+ open $f,$mf or die "Can't open modules file '$mf'\n";
+ while(<$f>)
+ {
+ if(m/\AINCLUDE\s+(\S+)\Z/)
+ {
+ # include another file
+ read_modules_file($1)
+ }
+ else
+ {
+ push @modules_files,$_
+ }
+ }
+ close $f;
+}
+read_modules_file('modules.txt');
+
+# prepare directories...
+mkdir "release",0755;
+mkdir "debug",0755;
+
+# is the library code in another directory?
+my $external_lib = readlink('lib');
+if($external_lib ne '')
+{
+ # adjust to root of the library distribution
+ $external_lib =~ s!/lib\Z!!;
+ $external_lib = '../'.$external_lib;
+ # make symlinks
+ make_obj_symlink('debug');
+ make_obj_symlink('release');
+}
+sub make_obj_symlink
+{
+ my $m = $_[0];
+ my $target = $external_lib."/$m/lib/";
+ my $link = "$m/lib";
+ # check link
+ if(-e $link)
+ {
+ if(-l $link)
+ {
+ if(readlink($link) ne $target)
+ {
+ print "Warning: replacing $link with new link to $target\n";
+ unlink $link;
+ }
+ }
+ else
+ {
+ die "$link already exists, but it isn't a symbolic link"
+ }
+ }
+ if(!-e $link)
+ {
+ symlink $target,$link or die "Can't make $m/lib symlink";
+ }
+}
+
+print "Scanning code...\n";
+
+my $modules_omitted = 0;
+
+# process lines in flattened modules files
+for(@modules_files)
+{
+ # clean up line
+ chomp; s/\A\s+//; s/#.*\Z//; s/\s+\Z//; s/\s+/ /g;
+ next unless m/\S/;
+
+ # omit bits on some platforms?
+ next if m/\AEND-OMIT/;
+ if(m/\AOMIT:(.+)/)
+ {
+ if($1 eq $build_os)
+ {
+ $modules_omitted = 1;
+ while(<MODULES>)
+ {
+ last if m/\AEND-OMIT/;
+ }
+ }
+ next;
+ }
+
+ # split up...
+ my ($mod, @deps_i) = split / /;
+
+ # ignore this module?
+ next if ignore_module($mod);
+
+ # deps for this platform
+ my @deps;
+ for(@deps_i)
+ {
+ my ($dep,$exclude_from) = split /!/;
+ # generic library translation
+ $dep = $env_flags{'LIBTRANS_'.$dep} if exists($env_flags{'LIBTRANS_'.$dep});
+ next if $dep eq '';
+ if($exclude_from =~ m/\A\+(.+)\Z/)
+ {
+ $exclude_from = $1;
+ my $inc = 0;
+ for(split /,/,$exclude_from)
+ {
+ $inc = 1 if $_ eq $build_os
+ }
+ push @deps,$dep if $inc
+ }
+ else
+ {
+ my $inc = 1;
+ for(split /,/,$exclude_from)
+ {
+ $inc = 0 if $_ eq $build_os
+ }
+ push @deps,$dep if $inc
+ }
+ }
+
+ # check directory exists
+ die "Module $mod can't be found\n" unless -d $mod;
+
+ # and put in lists
+ push @modules,$mod;
+ my @md; # module dependencies
+ my @lo; # link line options
+ for(@deps)
+ {
+ if(/\A-l/)
+ {
+ push @lo,$_
+ }
+ else
+ {
+ push @md,$_ unless ignore_module($_)
+ }
+ }
+ $module_dependency{$mod} = [$implicit_dep,@md];
+ $module_library_link_opts{$mod} = [@lo];
+
+ # make directories, but not if we're using an external library and this a library module
+ my ($s,$d) = split /\//,$mod;
+ if($s ne 'lib' || $external_lib eq '')
+ {
+ mkdir "release/$s",0755;
+ mkdir "release/$s/$d",0755;
+ mkdir "debug/$s",0755;
+ mkdir "debug/$s/$d",0755;
+ }
+}
+
+# make dirs for implicit dep
+mkdir "release/$implicit_dep",0755;
+mkdir "debug/$implicit_dep",0755;
+
+# write a list of all the modules we've configured to use
+open CONFIGURED_MODS,'>local/modules.h' or die "Can't write configured modules list";
+print CONFIGURED_MODS <<__E;
+// automatically generated file, do not edit
+#ifndef _CONFIGURED_MODULES__H
+#define _CONFIGURED_MODULES__H
+__E
+for($implicit_dep,@modules)
+{
+ my $m = $_;
+ $m =~ s~/~_~;
+ print CONFIGURED_MODS "#define MODULE_$m\n";
+}
+print CONFIGURED_MODS <<__E;
+#endif // _CONFIGURED_MODULES__H
+__E
+close CONFIGURED_MODS;
+
+
+# now make a list of all the .h files we can find, recording which module they're in
+my %hfiles;
+for my $mod (@modules, $implicit_dep)
+{
+ opendir DIR,$mod;
+ my @items = readdir DIR;
+ closedir DIR;
+
+ # add in items from autogen directories, and create output directories
+ {
+ my @autogen_items;
+
+ for my $di (@items)
+ {
+ if($di =~ m/\Aautogen/ && -d "$mod/$di")
+ {
+ # Read items
+ my $d = "$mod/$di";
+ opendir DIR,$d;
+ my @i = readdir DIR;
+ closedir DIR;
+ for(@i)
+ {
+ next if m/\A\./;
+ push @autogen_items,"$di/$_"
+ }
+ }
+ }
+ @items = (@items, @autogen_items);
+ }
+
+ for(grep /\.h\Z/i, @items)
+ {
+ next if /\A\._/; # Temp Mac OS Resource hack
+ die "Header file $_ already used in module ".$hfiles{$_}."\n" if exists $hfiles{$_};
+ $hfiles{$_} = $mod
+ }
+}
+
+for my $mod (@modules, $implicit_dep)
+{
+ opendir DIR,$mod;
+ for my $h (grep /\.h\Z/i, readdir DIR)
+ {
+ next if /\A\._/; # Temp Mac OS Resource hack
+
+ open FL,"$mod/$h" or die "can't open $mod/$h";
+ my $f;
+ read FL,$f,-s "$mod/$h";
+ close FL;
+
+ while($f =~ m/\#include\s+"([^"]+?)"/g)
+ {
+ my $i = $1;
+ # ignore autogen exceptions
+ next if $i =~ m/\Aautogen_.+?Exception.h\Z/;
+ # record dependency
+ ${$header_dependency{$h}}{$i} = 1 if exists $hfiles{$i};
+ }
+ }
+ closedir DIR;
+}
+
+print "done\n\nGenerating Makefiles...\n";
+
+
+# Then write a makefile for each module
+for my $mod (@modules, $implicit_dep)
+{
+ print $mod,"\n";
+
+ my ($type,$name) = split /\//,$mod;
+
+ # add additional files for tests
+ if($type eq 'test')
+ {
+ my $testmain = $test_template;
+ $testmain =~ s/TEST_NAME/$name/g;
+ open TESTMAIN,">$mod/_main.cpp" or die "Can't open test main file for $mod for writing\n";
+ print TESTMAIN $testmain;
+ close TESTMAIN;
+
+ # test file...
+ sub writetestfile
+ {
+ my ($filename,$runcmd,$module) = @_;
+ open TESTFILE,">$filename" or die "Can't open test script file for $module for writing\n";
+ print TESTFILE "#!/bin/sh\necho TEST: $module\n";
+ if(-d "$module/testfiles")
+ {
+ print TESTFILE <<__E;
+echo Removing old test files...
+rm -rf testfiles
+echo Copying new test files...
+cp -p -R ../../../$module/testfiles .
+__E
+ }
+ if(-e "$module/testextra")
+ {
+ open FL,"$module/testextra" or die "Can't open $module/testextra";
+ while(<FL>) {print TESTFILE}
+ close FL;
+ }
+ print TESTFILE "$runcmd\n";
+ close TESTFILE;
+ }
+
+ writetestfile("$mod/_t", './test $1 $2 $3 $4 $5', $mod);
+ writetestfile("$mod/_t-gdb", 'gdb ./test', $mod);
+
+ }
+
+ my @all_deps_for_module;
+ {
+ # work out what dependencies need to be run
+ my @deps_raw;
+ sub add_mod_deps
+ {
+ my ($arr_r,$nm) = @_;
+ if($#{$module_dependency{$nm}} >= 0)
+ {
+ push @$arr_r,@{$module_dependency{$nm}};
+ for(@{$module_dependency{$nm}})
+ {
+ add_mod_deps($arr_r,$_)
+ }
+ }
+ }
+ add_mod_deps(\@deps_raw, $mod);
+ # and then dedup and reorder them
+ my %d_done;
+ for(my $a = $#deps_raw; $a >= 0; $a--)
+ {
+ if(!exists $d_done{$deps_raw[$a]})
+ {
+ # insert
+ push @all_deps_for_module, $deps_raw[$a];
+ # mark as done
+ $d_done{$deps_raw[$a]} = 1;
+ }
+ }
+ }
+
+
+ # make include path
+ my $include_paths = join(' ',map {'-I../../'.$_} @all_deps_for_module);
+
+ # is target a library?
+ my $target_is_library = ($type ne 'bin' && $type ne 'test');
+
+ # make target name
+ my $end_target = $name;
+ $end_target .= '.a' if $target_is_library;
+ $end_target = 'test' if $type eq 'test';
+ # adjust for outdir
+ $end_target = '$(OUTDIR)/' . $end_target;
+
+ # start the makefile
+ my $mk_name_extra = ($bsd_make)?'':'X';
+ open MAKE,">$mod/Makefile".$mk_name_extra or die "Can't open Makefile for $mod\n";
+ my $debug_link_extra = ($target_is_library)?'':'../../debug/lib/debug/debug.a';
+ print MAKE <<__E;
+#
+# AUTOMATICALLY GENERATED FILE
+# do not edit!
+#
+#
+CXX = g++
+AR = ar
+RANLIB = ranlib
+.ifdef RELEASE
+CXXFLAGS = -DNDEBUG -O2 -Wall $include_paths -D$platform_define$extra_platform_defines -DBOX_VERSION="\\"$product_version\\""
+OUTBASE = ../../release
+OUTDIR = ../../release/$mod
+DEPENDMAKEFLAGS = -D RELEASE
+VARIENT = RELEASE
+.else
+CXXFLAGS = -g -Wall $include_paths -D$platform_define$extra_platform_defines -DBOX_VERSION="\\"$product_version\\""
+OUTBASE = ../../debug
+OUTDIR = ../../debug/$mod
+DEPENDMAKEFLAGS =
+VARIENT = DEBUG
+.endif
+
+__E
+
+ # read directory
+ opendir DIR,$mod;
+ my @items = readdir DIR;
+ closedir DIR;
+
+ # add in items from autogen directories, and create output directories
+ {
+ my @autogen_items;
+ for my $di (@items)
+ {
+ if($di =~ m/\Aautogen/ && -d "$mod/$di")
+ {
+ # Read items
+ my $d = "$mod/$di";
+ opendir DIR,$d;
+ my @i = readdir DIR;
+ closedir DIR;
+ for(@i)
+ {
+ next if m/\A\./;
+ push @autogen_items,"$di/$_"
+ }
+
+ # output directories
+ mkdir "release/$mod/$di",0755;
+ mkdir "debug/$mod/$di",0755;
+ }
+ }
+ @items = (@items, @autogen_items);
+ }
+
+ # first, obtain a list of depenencies within the .h files
+ my %headers;
+ for my $h (grep /\.h\Z/i, @items)
+ {
+ open FL,"$mod/$h";
+ my $f;
+ read FL,$f,-s "$mod/$h";
+ close FL;
+
+ while($f =~ m/\#include\s+"([^"]+?)"/g)
+ {
+ ${$headers{$h}}{$1} = 1 if exists $hfiles{$1};
+ }
+ }
+
+ # ready for the rest of the details...
+ my $make;
+
+ # then... do the cpp files...
+ my @obj_base;
+ for my $cpp (@items)
+ {
+ next unless $cpp =~ m/\A(.+)\.cpp\Z/i;
+ next if $cpp =~ /\A\._/; # Temp Mac OS Resource hack
+
+ # store for later
+ my $base = $1;
+ push @obj_base,$base;
+
+ # get the file...
+ open FL,"$mod/$cpp";
+ my $f;
+ read FL,$f,-s "$mod/$cpp";
+ close FL;
+
+ my %dep;
+
+ while($f =~ m/\#include\s+"([^"]+?)"/g)
+ {
+ insert_dep($1, \%dep) if exists $hfiles{$1};
+ }
+
+ # output filename
+ my $out_name = '$(OUTDIR)/'.$base.'.o';
+
+ # write the line for this cpp file
+ $make .= $out_name.': '.join(' ',$cpp,map
+ { ($hfiles{$_} eq $mod)?$_:'../../'.$hfiles{$_}."/$_" } keys %dep)."\n";
+ $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra -c $cpp -o $out_name\n\n";
+
+ }
+
+ my $has_deps = ($#{$module_dependency{$mod}} >= 0);
+# ----- # always has dependencies with debug library
+ $has_deps = 1;
+
+ # Depenency stuff
+ my $deps_makeinfo;
+ if($has_deps)
+ {
+ if($bsd_make)
+ {
+ $deps_makeinfo = <<'__E';
+.BEGIN::
+.ifndef NODEPS
+. if $(.TARGETS) == ""
+__E
+ }
+ else
+ {
+ # gnu make
+ $deps_makeinfo = <<'__E';
+.PHONY: dep_modules
+dep_modules:
+ifndef NODEPS
+ifeq ($(strip $(.TARGETS)),)
+__E
+ }
+
+ # run make for things we require
+ for my $dep (@all_deps_for_module)
+ {
+ $deps_makeinfo .= "\t\t(cd ../../$dep; $make_command$sub_make_options \$(DEPENDMAKEFLAGS) -D NODEPS)\n";
+ }
+ $deps_makeinfo .= ".\tendif\n.endif\n\n";
+ }
+ print MAKE $deps_makeinfo if $bsd_make;
+
+ # get the list of library things to add -- in order of dependency so things link properly
+ my $lib_files = join(' ',map {($_ =~ m/lib\/(.+)\Z/)?('$(OUTBASE)/'.$_.'/'.$1.'.a'):undef} (reverse(@all_deps_for_module)));
+
+ # need to see if the extra makefile fragments require extra object files
+ # or include any more makefiles
+ my @objs = @obj_base;
+ my @makefile_includes;
+
+ additional_objects_from_make_fragment("$mod/Makefile.extra", \@objs, \@makefile_includes);
+ additional_objects_from_make_fragment("$mod/Makefile.extra.$build_os", \@objs, \@makefile_includes);
+
+ my $o_file_list = join(' ',map {'$(OUTDIR)/'.$_.'.o'} @objs);
+ print MAKE $end_target,': ',$o_file_list;
+ print MAKE ' dep_modules' if !$bsd_make;
+ print MAKE " ",$lib_files unless $target_is_library;
+ print MAKE "\n";
+
+ # stuff to make the final target...
+ if($target_is_library)
+ {
+ # make a library archive...
+ print MAKE "\t(echo -n > $end_target; rm $end_target)\n";
+ print MAKE "\t\$(AR) -q $end_target $o_file_list\n";
+ print MAKE "\t\$(RANLIB) $end_target\n";
+ }
+ else
+ {
+ # work out library options
+ # need to be... least used first, in absolute order they appear in the modules.txt file
+ my @libops;
+ sub libops_fill
+ {
+ my ($m,$r) = @_;
+ push @$r,$_ for(@{$module_library_link_opts{$m}});
+ libops_fill($_,$r) for(@{$module_dependency{$m}});
+ }
+ libops_fill($mod,\@libops);
+ my $lo = '';
+ my %ldone;
+ for(@libops)
+ {
+ next if exists $ldone{$_};
+ $lo .= ' '.$_;
+ $ldone{$_} = 1;
+ }
+
+ # link line...
+ print MAKE "\t\$(CXX) $link_line_extra -o $end_target $o_file_list $lib_files$lo\n";
+ }
+ # tests need to copy the test file over
+ if($type eq 'test')
+ {
+ print MAKE "\tcp _t \$(OUTDIR)/t\n\tchmod u+x \$(OUTDIR)/t\n";
+ print MAKE "\tcp _t-gdb \$(OUTDIR)/t-gdb\n\tchmod u+x \$(OUTDIR)/t-gdb\n";
+ }
+ # dependency line?
+ print MAKE "\n";
+
+ # module dependcies for GNU make?
+ print MAKE $deps_makeinfo if !$bsd_make;
+
+ # print the rest of the file
+ print MAKE $make,"\n";
+
+ # and a clean target
+ print MAKE "clean:\n\t-rm -rf \$(OUTDIR)/*\n.\tifndef SUBCLEAN\n";
+ for my $dep (@all_deps_for_module)
+ {
+ print MAKE "\t(cd ../../$dep; $make_command \$(DEPENDMAKEFLAGS) -D SUBCLEAN clean)\n";
+ }
+ print MAKE ".\tendif\n";
+
+ # include any extra stuff
+ print MAKE "\n\n";
+ if(-e "$mod/Makefile.extra")
+ {
+ print MAKE ".include <Makefile.extra>\n\n";
+ }
+ if(-e "$mod/Makefile.extra.$build_os")
+ {
+ print MAKE ".include <Makefile.extra.$build_os>\n\n";
+ }
+ for(@makefile_includes)
+ {
+ print MAKE ".include <$_>\n\n";
+ }
+
+ # and finally a target for rebuilding the build system
+ print MAKE "\nbuildsystem:\n\t(cd ../..; perl ./infrastructure/makebuildenv.pl $makebuildenv_args)\n\n";
+
+ close MAKE;
+
+ if(!$bsd_make)
+ {
+ # need to post process this into a GNU makefile
+ open MAKE,">$mod/Makefile";
+ open MAKEB,"$mod/MakefileX";
+
+ while(<MAKEB>)
+ {
+ s/\A\.\s*(ifdef|else|endif|ifndef)/$1/;
+ s/\A\.\s*include\s+<(.+?)>/include $1/;
+ s/-D\s+(\w+)/$1=1/;
+ print MAKE;
+ }
+
+ close MAKEB;
+ close MAKE;
+ unlink "$mod/MakefileX";
+ }
+}
+
+print "\nType 'cd <module_dir>; $make_command' to build a module\n\n";
+
+print $test_failure_text;
+
+if($modules_omitted)
+{
+ print "\nNOTE: Some modules have been omitted on this platform\n\n"
+}
+
+sub insert_dep
+{
+ my ($h,$dep_r) = @_;
+
+ # stop random recusion
+ return if exists $$dep_r{$h};
+
+ # insert more depencies
+ insert_dep($_,$dep_r) for keys %{$header_dependency{$h}};
+
+ # mark this one as a dependency
+ $$dep_r{$h} = 1;
+}
+
+
+sub additional_objects_from_make_fragment
+{
+ my ($fn,$objs_r,$include_r) = @_;
+
+ if(-e $fn)
+ {
+ open FL,$fn or die "Can't open $fn";
+
+ while(<FL>)
+ {
+ chomp;
+ if(m/link-extra:\s*(.+)\Z/)
+ {
+ my @o = split /\s+/,$1;
+ for(@o)
+ {
+ push @$objs_r,$1 if m/\A(.+)\.o\Z/;
+ }
+ }
+ elsif(m/include-makefile:\s*(\S+)/)
+ {
+ push @$include_r,$1
+ }
+ }
+
+ close FL;
+ }
+}
+
+
+sub ignore_module
+{
+ exists $env_flags{'IGNORE_'.$_[0]}
+}
+
+# how to run a test
+sub do_test
+{
+ my %t = @_;
+
+ print $t{'Name'},':';
+ open TEST_CODE,">envtest.cpp" or die "Can't open envtest.cpp for writing";
+ print TEST_CODE $t{'Code'};
+ close TEST_CODE;
+ my $result = (system("g++ envtest.cpp ".$t{'TestCompileFlags'}." -o envtest $compile_line_extra $link_line_extra 2>/dev/null >/dev/null") == 0);
+ if($result && exists $t{'RunCode'})
+ {
+ $result = 0 unless (system('./envtest') == 0);
+ }
+ unlink 'envtest.cpp';
+ unlink 'envtest';
+ print $result?" yes\n":" no\n";
+ if($result)
+ {
+ # success
+ if(exists $t{'SuccessFlags'})
+ {
+ for(@{$t{'SuccessFlags'}})
+ {
+ my ($k,$v) = split /=>/,$_;
+ $v = 1 if $v eq '';
+ $env_flags{$k} = $v
+ }
+ }
+ $compile_line_extra .= $t{'SuccessCompileFlags'}.' ' if exists $t{'SuccessCompileFlags'};
+ $link_line_extra .= $t{'SuccessLinkFlags'}.' ' if exists $t{'SuccessLinkFlags'};
+ }
+ else
+ {
+ # aborting failure?
+ if(exists $t{'AbortOnFailure'})
+ {
+ print $t{'FailureText'};
+ print "\nAborting configuration, cannot build in this environment.\n";
+ exit(1);
+ }
+
+ # failure
+ if(exists $t{'FailureFlags'})
+ {
+ for(@{$t{'FailureFlags'}})
+ {
+ my ($k,$v) = split /=>/,$_;
+ $v = 1 if $v eq '';
+ $env_flags{$k} = $v
+ }
+ }
+ $compile_line_extra .= $t{'FailureCompileFlags'}.' ' if exists $t{'FailureCompileFlags'};
+ $link_line_extra .= $t{'FailureLinkFlags'}.' ' if exists $t{'FailureLinkFlags'};
+ $test_failure_text .= $t{'FailureText'} if exists $t{'FailureText'};
+ }
+ $result
+}
+
+
+
diff --git a/infrastructure/makedistribution.pl b/infrastructure/makedistribution.pl
new file mode 100755
index 00000000..712b068c
--- /dev/null
+++ b/infrastructure/makedistribution.pl
@@ -0,0 +1,312 @@
+#!/usr/bin/perl
+use strict;
+use Symbol;
+
+# comment string for various endings
+my %comment_chars = ('cpp' => '// ', 'h' => '// ', 'pl' => '# ', 'pm' => '# ', '' => '# ');
+
+# other extensions which need text copying, just to remove the private stuff
+my %text_files = ('txt' => 1);
+
+# files which don't get the license added
+my %no_license = (); # 'filename' => 1
+
+# ----------------------------------------------
+
+# filled in from the manifest file
+my %no_license_dir = ();
+
+# distribution name
+my $distribution = $ARGV[0];
+die "No distribution name specified on the command line" if $distribution eq '';
+my $dist_root = "distribution/$distribution";
+
+# check distribution exists
+die "Distribution '$distribution' does not exist" unless -d $dist_root;
+
+# get version
+open VERSION,"$dist_root/VERSION.txt" or die "Can't open $dist_root/VERSION.txt";
+my $version = <VERSION>;
+chomp $version;
+my $archive_name = <VERSION>;
+chomp $archive_name;
+close VERSION;
+
+# consistency check
+die "Archive name '$archive_name' is not equal to the distribution name '$distribution'"
+ unless $archive_name eq $distribution;
+
+# make initial directory
+my $base_name = "$archive_name-$version";
+system "rm -rf $base_name";
+system "rm $base_name.tgz";
+mkdir $base_name,0755;
+
+# get license file
+open LICENSE,"$dist_root/LICENSE.txt" or die "Can't open $dist_root/LICENSE.txt";
+my $license_f;
+read LICENSE,$license_f,100000;
+close LICENSE;
+my @license = ('distribution '.$base_name,'',split(/\n/,$license_f));
+
+# copy files, make a note of all the modules included
+my %modules_included;
+my $private_sections_removed = 0;
+my $non_distribution_sections_removed = 0;
+sub copy_from_list
+{
+ my $list = $_[0];
+ open LIST,$list or die "Can't open $list";
+
+ while(<LIST>)
+ {
+ next unless m/\S/;
+ chomp;
+ my ($src,$dst) = split /\s+/;
+ $dst = $src if $dst eq '';
+ if($src eq 'MKDIR')
+ {
+ # actually we just need to make a directory here
+ mkdir "$base_name/$dst",0755;
+ }
+ elsif($src eq 'NO-LICENSE-IN-DIR')
+ {
+ # record that this directory shouldn't have the license added
+ $no_license_dir{$dst} = 1;
+ }
+ elsif($src eq 'REPLACE-VERSION-IN')
+ {
+ replace_version_in($dst);
+ }
+ elsif(-d $src)
+ {
+ $modules_included{$_} = 1;
+ copy_dir($src,$dst);
+ }
+ else
+ {
+ copy_file($src,$dst);
+ }
+ }
+
+ close LIST;
+}
+copy_from_list("distribution/COMMON-MANIFEST.txt");
+copy_from_list("$dist_root/DISTRIBUTION-MANIFEST.txt");
+
+# Copy in the root directory and delete the DISTRIBUTION-MANIFEST file
+(system("cp $dist_root/*.* $base_name/") == 0)
+ or die "Copy of root extra files failed";
+unlink "$base_name/DISTRIBUTION-MANIFEST.txt"
+ or die "Delete of DISTRIBUTION-MANIFEST.txt file failed";
+
+# produce a new modules file
+my $modules = gensym;
+open $modules,"modules.txt" or die "Can't open modules.txt for reading";
+open MODULES_OUT,">$base_name/modules.txt";
+
+while(<$modules>)
+{
+ # skip lines for modules which aren't included
+ next if m/\A(\w+\/\w+)\s/ && !exists $modules_included{$1};
+
+ # skip private sections
+ unless(skip_non_applicable_section($_, $modules, 'modules.txt'))
+ {
+ # copy line to out files
+ print MODULES_OUT
+ }
+}
+
+close MODULES_OUT;
+close $modules;
+
+# report on how many private sections were removed
+print "Private sections removed: $private_sections_removed\nNon-distribution sections removed: $non_distribution_sections_removed\n";
+
+# tar it up
+system "tar cf - $base_name | gzip -9 - > $base_name.tgz";
+
+sub copy_file
+{
+ my ($fn,$dst_fn) = @_;
+
+ my $ext;
+ $ext = $1 if $fn =~ m/\.(\w+)\Z/;
+
+ # licenses not used in this directory?
+ my $license_in_dir = 1;
+ $dst_fn =~ m~\A(.+)/[^/]+?\Z~;
+ $license_in_dir = 0 if exists $no_license_dir{$1};
+
+ # licensed or not?
+ if(exists $comment_chars{$ext} && !exists $no_license{$fn} && $license_in_dir)
+ {
+ my $b = $comment_chars{$ext};
+
+ # copy as text, inserting license
+ my $in = gensym;
+ open $in,$fn;
+ open OUT,">$base_name/$dst_fn";
+
+ my $first = <$in>;
+ if($first =~ m/\A#!/)
+ {
+ print OUT $first;
+ $first = '';
+ }
+
+ # write license
+ for(@license)
+ {
+ print OUT $b,$_,"\n"
+ }
+
+ if($first ne '')
+ {
+ print OUT $first;
+ }
+
+ while(<$in>)
+ {
+ unless(skip_non_applicable_section($_, $in, $fn))
+ {
+ print OUT
+ }
+ }
+
+ close OUT;
+ close $in;
+ }
+ else
+ {
+ if(exists $text_files{$ext})
+ {
+ # copy this as text, to remove private stuff
+ my $in = gensym;
+ open $in,$fn;
+ open OUT,">$base_name/$dst_fn";
+
+ while(<$in>)
+ {
+ unless(skip_non_applicable_section($_, $in, $fn))
+ {
+ print OUT
+ }
+ }
+
+ close OUT;
+ close $in;
+ }
+ else
+ {
+ # copy as binary
+ system 'cp',$fn,"$base_name/$dst_fn"
+ }
+ }
+
+ # make sure perl scripts are marked as executable, and other things aren't
+ if($ext eq 'pl' || $ext eq '')
+ {
+ system 'chmod','a+x',"$base_name/$dst_fn"
+ }
+ else
+ {
+ system 'chmod','a-x',"$base_name/$dst_fn"
+ }
+}
+
+sub skip_non_applicable_section
+{
+ my ($l, $filehandle, $filename) = @_;
+ if($l =~ m/BOX_PRIVATE_BEGIN/)
+ {
+ # skip private section
+ print "Removing private section from $filename\n";
+ $private_sections_removed++;
+ while(<$filehandle>) {last if m/BOX_PRIVATE_END/}
+
+ # skipped something
+ return 1;
+ }
+ elsif($l =~ m/IF_DISTRIBUTION\((.+?)\)/)
+ {
+ # which distributions does this apply to?
+ my $applies = 0;
+ for(split /,/,$1)
+ {
+ $applies = 1 if $_ eq $distribution
+ }
+ unless($applies)
+ {
+ # skip section?
+ print "Removing distribution specific section from $filename\n";
+ $non_distribution_sections_removed++;
+ while(<$filehandle>) {last if m/END_IF_DISTRIBUTION/}
+ }
+ # hide this line
+ return 1;
+ }
+ elsif($l =~ m/END_IF_DISTRIBUTION/)
+ {
+ # hide these lines
+ return 1;
+ }
+ else
+ {
+ # no skipping, return this line
+ return 0;
+ }
+}
+
+sub copy_dir
+{
+ my ($dir,$dst_dir) = @_;
+
+ # copy an entire directory... first make sure it exists
+ my @n = split /\//,$dst_dir;
+ my $d = $base_name;
+ for(@n)
+ {
+ $d .= '/';
+ $d .= $_;
+ mkdir $d,0755;
+ }
+
+ # then do each of the files within in
+ opendir DIR,$dir;
+ my @items = readdir DIR;
+ closedir DIR;
+
+ for(@items)
+ {
+ next if m/\A\./;
+ next if m/\A_/;
+ next if m/\AMakefile\Z/;
+ next if m/\Aautogen/;
+ next if !-f "$dir/$_";
+
+ copy_file("$dir/$_","$dst_dir/$_");
+ }
+}
+
+sub replace_version_in
+{
+ my ($file) = @_;
+
+ my $fn = $base_name . '/' . $file;
+ open IN,$fn or die "Can't open $fn";
+ open OUT,'>'.$fn.'.new' or die "Can't open $fn.new for writing";
+
+ while(<IN>)
+ {
+ s/###DISTRIBUTION-VERSION-NUMBER###/$version/g;
+ print OUT
+ }
+
+ close OUT;
+ close IN;
+
+ rename($fn.'.new', $fn) or die "Can't rename in place $fn";
+}
+
diff --git a/infrastructure/makeparcels.pl b/infrastructure/makeparcels.pl
new file mode 100755
index 00000000..6cd3e8f2
--- /dev/null
+++ b/infrastructure/makeparcels.pl
@@ -0,0 +1,166 @@
+#!/usr/bin/perl
+
+use strict;
+use lib 'infrastructure';
+use BoxPlatform;
+
+my $os_suffix = '';
+if($build_os eq 'OpenBSD')
+{
+ $os_suffix = `uname -r`;
+ $os_suffix =~ tr/0-9//cd;
+}
+
+my @parcels;
+my %parcel_contents;
+
+open PARCELS,"parcels.txt" or die "Can't open parcels file";
+{
+ my $cur_parcel = '';
+ while(<PARCELS>)
+ {
+ chomp; s/#.+\Z//; s/\s+\Z//; s/\s+/ /g;
+ next unless m/\S/;
+
+ # omit bits on some platforms?
+ next if m/\AEND-OMIT/;
+ if(m/\AOMIT:(.+)/)
+ {
+ if($1 eq $build_os)
+ {
+ while(<PARCELS>)
+ {
+ last if m/\AEND-OMIT/;
+ }
+ }
+ next;
+ }
+
+ # new parcel, or a new parcel definition?
+ if(m/\A\s+(.+)\Z/)
+ {
+ push @{$parcel_contents{$cur_parcel}},$1
+ }
+ else
+ {
+ $cur_parcel = $_;
+ push @parcels,$_;
+ }
+ }
+}
+close PARCELS;
+
+# create parcels directory
+mkdir "parcels",0755;
+mkdir "parcels/scripts",0755;
+
+# write master makefile
+
+open MAKE,">Makefile" or die "Can't open master Makefile for writing";
+
+print MAKE <<__E;
+#
+# AUTOMATICALLY GENERATED FILE
+# do not edit!
+#
+#
+
+__E
+
+print MAKE "all:\t",join(' ',map {parcel_target($_)} @parcels),"\n\n";
+
+print MAKE "clean:\n";
+for my $parcel (@parcels)
+{
+ print MAKE "\trm -rf ",parcel_dir($parcel),"\n";
+ print MAKE "\trm -f ",parcel_target($parcel),"\n";
+}
+print MAKE "\n";
+
+print MAKE "test:\trelease/common/test\n\nrelease/common/test:\n\t./runtest.pl ALL release\n\n";
+
+my $release_flag = BoxPlatform::make_flag('RELEASE');
+
+for my $parcel (@parcels)
+{
+ my $target = parcel_target($parcel);
+ print MAKE $target,":\n";
+
+ my $dir = parcel_dir($parcel);
+ print MAKE "\tmkdir $dir\n";
+
+ open SCRIPT,">parcels/scripts/install-$parcel" or die "Can't open installer script for $parcel for writing";
+ print SCRIPT "#!/bin/sh\n\n";
+
+ for(@{$parcel_contents{$parcel}})
+ {
+ my ($type,$name) = split /\s+/;
+
+ if($type eq 'bin')
+ {
+ my $exeext = ($build_os eq 'CYGWIN')?'.exe':'';
+ print MAKE "\t(cd bin/$name; $make_command $release_flag)\n";
+ print MAKE "\tcp release/bin/$name/$name$exeext $dir\n";
+ }
+ elsif ($type eq 'script')
+ {
+ print MAKE "\tcp $name $dir\n";
+ # remove path from script name
+ $name =~ m~/([^/]+)\Z~;
+ $name = $1;
+ }
+
+ print SCRIPT "install $name $install_into_dir\n";
+ }
+
+ close SCRIPT;
+
+ chmod 0755,"parcels/scripts/install-$parcel";
+
+ my $root = parcel_root($parcel);
+ print MAKE "\tcp parcels/scripts/install-$parcel $dir\n";
+ print MAKE "\t(cd parcels; tar cf - $root | gzip -9 - > $root.tgz )\n";
+
+ print MAKE "\n";
+
+ print MAKE "install-$parcel:\n";
+ print MAKE "\t(cd $dir; ./install-$parcel)\n\n";
+}
+
+print MAKE <<__E;
+install:
+ cat local/install.msg
+
+__E
+
+close MAKE;
+
+open INSTALLMSG,">local/install.msg" or die "Can't open install message file for writing";
+print INSTALLMSG <<__E;
+
+Parcels need to be installed separately, and as root. Type one of the following:
+
+__E
+
+for(@parcels)
+{
+ print INSTALLMSG " make install-".$_."\n";
+}
+print INSTALLMSG "\n";
+
+close INSTALLMSG;
+
+sub parcel_root
+{
+ $product_name.'-'.$product_version.'-'.$_[0].'-'.$build_os.$os_suffix
+}
+
+sub parcel_dir
+{
+ 'parcels/'.parcel_root($_[0])
+}
+
+sub parcel_target
+{
+ parcel_dir($_[0]).'.tgz'
+}
diff --git a/infrastructure/setupexternal.pl b/infrastructure/setupexternal.pl
new file mode 100755
index 00000000..e21403e1
--- /dev/null
+++ b/infrastructure/setupexternal.pl
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+use strict;
+
+# This script links in the essential directories and processes various
+# files to allow the Box libraries to be used in projects outside the main
+# box library tree.
+
+# directories to link through
+my @linkdirs = qw/lib infrastructure/;
+
+# ----------------------------------------------------
+
+my $libdir = $ARGV[0];
+die "Provided library dir $libdir does not exist" unless -d $libdir;
+
+# Check and remove links from the directory, then add new symlinks
+for my $d (@linkdirs)
+{
+ if(-e $d)
+ {
+ die "In project, $d is not a symbolic link"
+ unless -l $d;
+ print "Removing existing symlink $d\n";
+ unlink $d;
+ }
+ my $link_target = "$libdir/$d";
+ print "Add symlink $d -> $link_target\n";
+ die "Can't create symlink $d" unless
+ symlink $link_target, $d;
+}
+
+# Copy and create a base modules file which includes all the libraries
+print "Create new modules_base.txt file\n";
+open OUT,">modules_base.txt" or die "Can't open modules_base.txt file for writing";
+print OUT <<__E;
+#
+# Automatically generated file, do not edit
+#
+# Source: $libdir/modules.txt
+#
+
+__E
+
+open IN,"$libdir/modules.txt" or die "Can't open $libdir/modules.txt for reading";
+
+while(<IN>)
+{
+ if(m/\A(lib\/.+?)\s/)
+ {
+ print OUT
+ }
+}
+
+close IN;
+close OUT;
diff --git a/infrastructure/tests/common_tests.pl b/infrastructure/tests/common_tests.pl
new file mode 100644
index 00000000..454f09c7
--- /dev/null
+++ b/infrastructure/tests/common_tests.pl
@@ -0,0 +1,178 @@
+
+# perl fragment, not directly runnable
+
+{
+ # test for a C++ compiler
+ do_test('Name' => 'Compiler 1',
+ 'AbortOnFailure' => 1,
+ 'FailureText' => <<__E,
+
+================
+
+You do not appear to have the g++ compiler installed. Please fix and try again.
+(Tested for C++ compilation and use of standard STL C++ library.)
+
+Some distributions rename the g++ compiler to something including the version number,
+and fail to create a symlink to the expected name. Investigate this if you believe
+you have the C++ compiler installed.
+
+================
+
+__E
+ 'Code' => <<__E);
+#include <string>
+int main(int argc, char *argv[])
+{
+ std::string str;
+ str = "Test";
+ str += "_test";
+}
+__E
+
+ # test for a properly working C++ compiler
+ do_test('Name' => 'Compiler 2',
+ 'AbortOnFailure' => 1,
+ 'RunCode' => 1,
+ 'FailureText' => <<__E,
+
+================
+
+The C++ compiler fails basic C++ tests. It is impossible to compile and deploy this
+software on this platform.
+
+Some less common platforms do not have a working C++ implementation, especially
+regarding modern language features such as exceptions. A basic test failed. It is
+unlikely that you will be able to use this software without fixing the compiler.
+
+You could try a later version of the compiler, if available.
+
+================
+
+__E
+ 'Code' => <<__E);
+#include <string>
+class test_class
+{
+public:
+ test_class(const char *str) : mString(str) {}
+ ~test_class() {}
+private:
+ std::string mString;
+};
+int main(int argc, char *argv[])
+{
+ try
+ {
+ throw test_class("Test exception");
+ }
+ catch(test_class &e)
+ {
+ return 0;
+ }
+ return 1;
+}
+__E
+
+ # test for any version of OpenSSL
+ do_test('Name' => 'OpenSSL 1',
+ 'SuccessFlags' => ['OLD_OPENSSL_OK'],
+ 'TestCompileFlags' => '-lcrypto ',
+ 'Code' => <<__E);
+#include <openssl/evp.h>
+int main(int argc, char *argv[])
+{
+ EVP_CipherInit(0, 0, 0, 0, 0);
+ return 0;
+}
+__E
+
+ # test for new version of OpenSSL
+ do_test('Name' => 'OpenSSL 2',
+ 'SuccessFlags' => ['OPENSSL_OK'],
+ 'TestCompileFlags' => '-lcrypto ',
+ 'Code' => <<__E);
+#include <openssl/evp.h>
+int main(int argc, char *argv[])
+{
+ EVP_CipherInit_ex(0, 0, 0, 0, 0, 0);
+ return 0;
+}
+__E
+
+ # Linux is always more fun
+ if($build_os eq 'Linux')
+ {
+ # see if curses is available
+ sub curses_test
+ {
+ my $c = $_[0];
+ do_test('Name' => $c,
+ 'SuccessFlags' => [$c.'_PRESENT'],
+ 'TestCompileFlags' => '-l'.$c.' ',
+ 'Code' => <<__E);
+#include <curses.h>
+int main(int argc, char *argv[])
+{
+ initscr(); cbreak(); noecho();
+ nonl();
+ intrflush(stdscr, 0);
+ keypad(stdscr, 0);
+ return 0;
+}
+__E
+ }
+ curses_test('curses');
+ curses_test('ncurses');
+
+ # see if LFS support is available
+ do_test('Name' => 'Linux LFS support',
+ 'RunCode' => 1,
+ 'TestCompileFlags' => '-D_FILE_OFFSET_BITS=64 ',
+ 'SuccessCompileFlags' => '-D_FILE_OFFSET_BITS=64',
+ 'Code' => <<__E);
+#include <sys/types.h>
+#include <sys/stat.h>
+int main(int argc, char *argv[])
+{
+ struct stat st;
+ if(sizeof(st.st_size) == 8 && sizeof(off_t) == 8)
+ {
+ return 0;
+ }
+ return 1;
+}
+__E
+
+ }
+
+ # USE_MALLOC doesn't work on some < gcc3 platforms
+ if(!$gcc_v3)
+ {
+ do_test('Name' => 'USE_MALLOC',
+ 'FailureCompileFlags' => '-DPLATFORM_STL_USE_MALLOC_BROKEN',
+ 'FailureText' => <<__E,
+
+================
+WARNING: The implementation of the C++ STL on this platform may have a flaw
+which causes it to apparently leak memory, and this flaw cannot be worked
+around.
+
+When running the daemons, check their memory usage does not constantly
+increase. The STL flaw can cause excessive memory use.
+================
+
+__E
+ 'Code' => <<__E);
+#define __USE_MALLOC
+#include <string>
+int main(int argc, char *argv[])
+{
+ std::string s;
+ s = "test";
+}
+__E
+ }
+}
+
+
+1;