#!/usr/bin/env perl

#---------------------------------------------------------------------
#                          file information
#---------------------------------------------------------------------

# Name:     mtcompile-program.pl
# Purpose:  Linux Minetest build script
# License:  Creative Commons Attribution-NonCommercial-ShareAlike 4.0.
#           Attribution: OldCoder (Robert Kiraly), Poikilos (Jake Gus-
#           tafson), and the Final Minetest group.
# Revision: See program parameters section

#---------------------------------------------------------------------
#                           important note
#---------------------------------------------------------------------

# This software is provided on an  AS IS basis with ABSOLUTELY NO WAR-
# RANTY.  The  entire risk as to the  quality and  performance of  the
# software is with you.  Should the software prove defective,  you as-
# sume the cost of all necessary  servicing, repair or correction.  In
# no event will any of the developers,  or any other party, be  liable
# to anyone for damages arising out of use of the software, or inabil-
# ity to use the software.

#---------------------------------------------------------------------
#                              overview
#---------------------------------------------------------------------

                                # Label must be single-quoted here
my $USAGE_TEXT = << 'END_OF_USAGE_TEXT';
Usage: $PROGNAME --options --build

The "--build" switch is required. It needs to be specified on the com-
mand line or you'll get this  usage text.  The other switches are opt-
ional.

The command-line argument "build", specified without dashes, will also
work.

----------------------------------------------------------------------

Background information related to "builds":

1. Minetest,  or this version,  uses a combined source and  production
tree.  I.e.,  a single tree can serve both purposes until it's cleaned
up for distribution.

2. The  production tree is portable in the sense  that it can be moved
to different directories on a given system and  the program will still
work.

3. The production tree  isn't  portable in the sense that it'll run on
different systems unless the "--makeprod" option switch is used.

4. By default,  this script deletes the  source tree on each run,  un-
packs an  included source tarball,  and deletes unneeded "build" files
after a build is completed. The last step results in a pure production
as opposed to source tree.

Command-line  option switches  can be used  to modify  this  behavior.
Examples include "--noclean" and "--gitreset".

----------------------------------------------------------------------

Option switches:

--noclean       # If --noclean is specified,  this script tries to re-
                # use the existing source tree,  if there is one,  and
                # doesn't delete "build" files afterward.

                # The "--git*" and "--debug" switches  imply this swi-
                # tch.
                # Aliases: --notidy

--leveldb       # Enable LevelDB    (requires installed copy)

--postgresql    # Enable PostgreSQL (requires installed copy)
                # Aliases: --postgres

--redis         # Enable Redis      (requires installed copy)

--debug         # Build a "debug" version of the program  suitable for
                # use with "gdb".

--makeprod      # Build a  portable  production release  (ZIP file) of
                # Linux Minetest.  This is only needed  by  people who
                # wish to redistribute the program. The switch implies
                # --portable.  It isn't  compatible with  --noclean or
                # --debug.

--safe          # Don't delete existing source trees automatically.

# Select program[s] to build:

# In the following cases, "--server" and "--client" may both be speci-
# fied.

--classic --server
                # Build Final MT 4-based server
--classic --client
                # Build Final MT 4-based client

--finetest --server
                # Build Final MT MultiCraft-derived server
--finetest --client
                # Build Final MT MultiCraft-derived client

--trolltest --server
                # Build Trolltest server
--trolltest --client
                # Build Trolltest client

--help          # Display usage text and exit
                # Aliases: --usage

For full documentation, see "linux-minetest-kit.txt".
END_OF_USAGE_TEXT

#---------------------------------------------------------------------
#                            module setup
#---------------------------------------------------------------------

require 5.16.1    ;
use strict        ;
use Carp          ;
use warnings      ;
use Cwd;          ;
use Getopt::Long  ;
                                # Trap warnings
$SIG{__WARN__} = sub { die @_; };

#---------------------------------------------------------------------
#                           basic constants
#---------------------------------------------------------------------

use constant ZERO  => 0;        # Zero
use constant ONE   => 1;        # One
use constant TWO   => 2;        # Two

use constant FALSE => 0;        # Boolean FALSE
use constant TRUE  => 1;        # Boolean TRUE

#---------------------------------------------------------------------
#                         program parameters
#---------------------------------------------------------------------

my $PURPOSE  = 'Linux Minetest build script';
my $REVISION = '230805';
my $USE_LESS = TRUE;            # Flag: Use "less" for usage text

my $GITURL   = 'http://git.minetest.org/minetest/minetest.git';
my $IE       = 'Internal error';

#---------------------------------------------------------------------
#                          global variables
#---------------------------------------------------------------------

my $PROGNAME;                   # Program name without path
my @DirStack = ();              # Directory stack

#---------------------------------------------------------------------
#                        used by "--oldproto"
#---------------------------------------------------------------------

my $segment = << 'END';
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
set(VERSION_PATCH 17)
set(VERSION_TWEAK 1)
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")

# Change to false for releases
set(DEVELOPMENT_BUILD FALSE)

set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_TWEAK}")
if(VERSION_EXTRA)
	set(VERSION_STRING ${VERSION_STRING}-${VERSION_EXTRA})
elseif(DEVELOPMENT_BUILD)
	set(VERSION_STRING "${VERSION_STRING}-dev")
endif()

if (CMAKE_BUILD_TYPE STREQUAL Debug)
END

#---------------------------------------------------------------------
#                     low-level utility routines
#---------------------------------------------------------------------

sub pushd
{
    my ($dir) = @_;             # Relative or absolute directory path
    die unless -d $dir;
    push (@DirStack, getcwd());
    die unless chdir ($dir);
    undef;
}

#---------------------------------------------------------------------

sub popd
{
    my $dir = pop (@DirStack);
    die unless defined $dir;
    die unless -d $dir;
    die unless chdir ($dir);
    undef;
}

#---------------------------------------------------------------------

sub RunCmd
{
    my ($cmd) = @_;
    my $status = system $cmd;
       $status = ($status >> 8) & 0x0F;
    exit $status if $status;
    undef;
}

#---------------------------------------------------------------------

sub FixStr
{
    my ($str) = @_;
    $str = "" unless defined $str;
    $str =~ s@\s+@ @gs;
    $str =~ s@\s+\z@@s;
    $str =~ s@^\s+@@s;
    $str;
}

#---------------------------------------------------------------------

sub GetProgDir
{
    $PROGNAME    = $0;
    my $ProgTemp = $0;

    $PROGNAME =~ s@^.*/@@;

    while (defined (my $r = readlink ($ProgTemp)))
    {
        while ($r =~ s@^\./@@) {}
        die "$IE #203494\n" if $r =~ m@^\.\./@;
        $ProgTemp = $r;
    }

    while ($ProgTemp =~ s@^\./@@) {}

    if ($ProgTemp =~ m@/@)
    {
        die "$IE #595033: $ProgTemp\n" unless $ProgTemp =~ m@^/@;

        die "$IE #024839: $ProgTemp\n"
            unless $ProgTemp =~ s@/[^/]+\z@@;
    }
    else
    {
        $ProgTemp = ".";
    }

    my $cwd     = getcwd();
    chdir ($ProgTemp) || die;
    my $ProgDir = getcwd();
    chdir ($cwd) || die "$IE #048837\n";
    $ProgDir;
}

#---------------------------------------------------------------------
#                         usage-text routine
#---------------------------------------------------------------------

# "UsageText" prints usage text for the current program,  then termin-
# ates the program with exit status one.

#---------------------------------------------------------------------

sub UsageText
{
    $USAGE_TEXT =~ s@^\s+@@s;
    $USAGE_TEXT =~ s@\$PROGNAME@$PROGNAME@g;

    $USAGE_TEXT = << "END";     # "END" must be double-quoted here
$PROGNAME $REVISION - $PURPOSE

$USAGE_TEXT
END
    $USAGE_TEXT =~ s@\s*\z@\n@s;

    if ($USE_LESS && (-t STDOUT) && open (OFD, "|/usr/bin/less"))
    {
                                # "END" must be double-quoted here
        $USAGE_TEXT = << "END";
To exit this "help" text, press "q" or "Q".  To scroll up or down, use
PGUP, PGDN, or the arrow keys.

$USAGE_TEXT
END
        print OFD $USAGE_TEXT;
        close OFD;
    }
    else
    {
        print "\n", $USAGE_TEXT, "\n";
    }

    exit ONE;
}

#---------------------------------------------------------------------
#                            main routine
#---------------------------------------------------------------------

sub Main
{

#---------------------------------------------------------------------
# Misc. variables.

    my $cmd;                    # Shell command string
    my $str;                    # Scratch

#---------------------------------------------------------------------
# Mode flags.

# These may be modified, indirectly, by command-line switches.

    my $MAKEDEBUG    = FALSE ;
    my $OLDPROTO     = FALSE ;
    my $PORTABLE     = FALSE ;
    my $TIDYUP       = TRUE  ;
    my $MAKEPROD     = FALSE ;

#---------------------------------------------------------------------
# Command-line option flags.

    my $FlagBuild     = FALSE ;
    my $FlagClient    = FALSE ;
    my $FlagDebug     = FALSE ;
    my $FlagFinalMT4  = FALSE ;
    my $FlagHelp      = FALSE ;
    my $FlagLevelDB   = FALSE ;
    my $FlagMakeProd  = FALSE ;
    my $FlagNoClean   = FALSE ;
    my $FlagPostgres  = FALSE ;
    my $FlagRedis     = FALSE ;
    my $FlagSafe      = FALSE ;
    my $FlagServer    = FALSE ;
    my $FlagFinetest  = FALSE ;
    my $FlagTrolltest = FALSE ;

#---------------------------------------------------------------------
# Initial setup.

    select STDERR; $| = ONE;    # Force STDERR flush on write
    select STDOUT; $| = ONE;    # Force STDOUT flush on write

#---------------------------------------------------------------------
# Get absolute path for script directory.

# As a side effect, this function call initializes the global variable
# "$PROGNAME". Note that this must be done before "UsageText" is call-
# ed.

    my $THISDIR = &GetProgDir();

#---------------------------------------------------------------------
# Parse command-line arguments.

    for (@ARGV) { s@^build\z@--build@; }
    Getopt::Long::Configure ("bundling");

    exit ONE unless GetOptions
    (
        "build"         => \$FlagBuild      ,
        "classic"       => \$FlagFinalMT4   ,
        "client"        => \$FlagClient     ,
        "debug"         => \$FlagDebug      ,
        "finetest"      => \$FlagFinetest   ,
        "help"          => \$FlagHelp       ,
        "makeprod"      => \$FlagMakeProd   ,
        "noclean"       => \$FlagNoClean    ,
        "notidy"        => \$FlagNoClean    ,
        "postgres"      => \$FlagPostgres   ,
        "postgresql"    => \$FlagPostgres   ,
        "redis"         => \$FlagRedis      ,
        "safe"          => \$FlagSafe       ,
        "server"        => \$FlagServer     ,
        "trolltest"     => \$FlagTrolltest  ,
        "usage"         => \$FlagHelp       ,
        "vinetest"      => \$FlagFinetest   ,
    );
                                # Handle usage-text exit
    &UsageText() if !$FlagBuild || $FlagHelp || scalar (@ARGV);

#---------------------------------------------------------------------
# Handle misc. flag issues.

    die "Error: Specify one of:\n--classic --finetest --trolltest\n"
        unless $FlagFinalMT4 || $FlagFinetest || $FlagTrolltest;

    if (!$FlagClient && !$FlagServer)
    {
        print STDERR << 'END';
Error: Must specify --server and/or --client
END
        exit (ONE);
    }


#---------------------------------------------------------------------

    if ($FlagFinetest)
    {
        if ($FlagFinalMT4 || $FlagTrolltest)
        {
            print STDERR << 'END';
Error: You can only use one of: --classic --finetest --trolltest
END
            exit (ONE);
        }

        if ($FlagMakeProd)
        {
            print STDERR << 'END';
Error: --finetest doesn't support --makeprod yet
END
            exit (ONE);
        }
    }

#---------------------------------------------------------------------

    if ($FlagTrolltest)
    {
        if ($FlagFinalMT4 || $FlagFinetest)
        {
            print STDERR << 'END';
Error: You can only use one of: --classic --finetest --trolltest
END
            exit (ONE);
        }

        if ($FlagMakeProd)
        {
            print STDERR << 'END';
Error: --trolltest doesn't support --makeprod yet
END
            exit (ONE);
        }
    }

#---------------------------------------------------------------------

    if ($FlagFinalMT4)
    {
        if ($FlagFinetest || $FlagTrolltest)
        {
            print STDERR << 'END';
Error: You can only use one of: --classic --finetest --trolltest
END
            exit (ONE);
        }
    }

#---------------------------------------------------------------------

    $OLDPROTO = TRUE if $FlagFinalMT4;

#---------------------------------------------------------------------
# Confirm that script is running in the right place.

    if (!-d 'mtsrc')
    {
        print STDERR << 'END';
Error:  This script should be stored,  and executed,  in the directory
which contains the "mtsrc" directory.
END
        exit ONE;
    }

#---------------------------------------------------------------------
# Additional directory paths.

    my $BALLDIR      = "$THISDIR/mtsrc/newline" ;
    my $GAMEDIR      = "$THISDIR/mtsrc/game"    ;
    my $PRODDIR      = "$THISDIR/minetest"      ;
    my $TOOLS_PREFIX = "$THISDIR/toolstree"     ;
    my $WSRCDIR      = "$THISDIR/mtsrc/worlds"  ;

    my $BINDIR       = "$TOOLS_PREFIX/bin"      ;
    my $INCDIR       = "$TOOLS_PREFIX/include"  ;
    my $LIBDIR       = "$TOOLS_PREFIX/lib"      ;
    my $LIB64DIR     = "$TOOLS_PREFIX/lib64"    ;

#---------------------------------------------------------------------
# Misc. setup.

    $ENV {'PATH'} = "$BINDIR:" . $ENV {'PATH'};
    system "which g++";

#---------------------------------------------------------------------
# Handle some of the option flags.

    $MAKEDEBUG = TRUE  if $FlagDebug    ;
    $MAKEPROD  = TRUE  if $FlagMakeProd ;
    $TIDYUP    = FALSE if $FlagNoClean  ;

    if ($MAKEPROD)
    {
        $MAKEDEBUG = FALSE ;
        $PORTABLE  = TRUE  ;
        $TIDYUP    = TRUE  ;
    }

#---------------------------------------------------------------------
# Handle "--client" and/or "--server".

    my  $client_line = "-DBUILD_CLIENT=1" ;
    my  $server_line = "-DBUILD_SERVER=1" ;

    if ( $FlagClient && !$FlagServer)
    {
        $client_line = "-DBUILD_CLIENT=1" ;
        $server_line = "-DBUILD_SERVER=0" ;
    }

    if (!$FlagClient &&  $FlagServer)
    {
        $client_line = "-DBUILD_CLIENT=0" ;
        $server_line = "-DBUILD_SERVER=1" ;
    }

#---------------------------------------------------------------------
# Status messages.

    my $NUBDF = "not used by default in this version";

    print << 'END';
* sqlite3 (by default)
END

#---------------------------------------------------------------------
# Handle "--leveldb".

    my $leveldb_line = "-DENABLE_LEVELDB=0";

    if ($FlagLevelDB)
    {
        print "* leveldb (due to --leveldb)\n";
        $leveldb_line =~ s@0\z@1@;
    }
    else
    {
        print "  (skipping leveldb -- $NUBDF)\n";
    }

#---------------------------------------------------------------------
# Handle "--postgres".

    my $postgres_line = "-DENABLE_POSTGRESQL=0";

    if ($FlagPostgres)
    {
        print "* postgres (due to --postgresql)\n";
        $postgres_line =~ s@0\z@1@;
    }
    else
    {
        print "  (skipping postgresql -- $NUBDF)\n";
    }

#---------------------------------------------------------------------
# Handle "--redis".

    my $redis_line = "-DENABLE_REDIS=0";

    if ($FlagRedis)
    {
        print "* redis (due to --redis)\n";
        $redis_line =~ s@0\z@1@;
    }
    else
    {
        print "  (skipping redis -- $NUBDF)\n";
    }

#---------------------------------------------------------------------
# "--makeprod" requires the bootstrapped "gcc".

    if ($PORTABLE && !-f "$BINDIR/gcc")
    {
        print << 'END';

Error: For Linux portable mode (--makeprod), you need to build the in-
cluded  "gcc" 8 compiler.  To do so, run "mtcompile-libraries.sh" with
gcc-bootstrap mode enabled.
END
        exit ONE;
    }

#---------------------------------------------------------------------
# Identify "gcc" major release number.

    $str = "\n" . &FixStr (`gcc --version 2>&1`);
    my ($GCCVER) = $str =~ m@\ngcc.* (\d+)*\.\d+\.@;
    die "Error: Not able to identify gcc release\n"
        unless defined $GCCVER;

#---------------------------------------------------------------------
# Replace existing "minetest" directory.

    if (TRUE)
    {
        if ($FlagSafe && (-d 'minetest'))
        {
            print << 'END';

Error:  We  need  to delete  the  existing "minetest"  directory,  but
"--safe" is  specified.  If you'd like to preserve the directory, move
or rename it. Otherwise, drop the "--safe" switch.
END
            exit ONE;
        }

        $cmd = "";

        for my $base (qw (finetest-newline
                          minetest-newline
                          trolltest-newline))
        {
            $cmd .= << "END";
rm -fr  $PRODDIR $base*                         || exit 1
mkdir   $PRODDIR $base                          || exit 1
rmdir   $PRODDIR $base                          || exit 1
END
            $str =  `$cmd 2>&1`;
            $str =  "" unless defined $str;
            $str =~ s@\s+\z@@s;
            die "$str\n" if length $str;
        }

        $cmd .= << "END" if $FlagFinalMT4;
tar jxf $BALLDIR/minetest-newline.tar.bz2       || exit 1
mv               minetest-newline*  $PRODDIR    || exit 1
END
        $cmd .= << "END" if $FlagFinetest;
tar jxf $BALLDIR/finetest-newline.tar.bz2       || exit 1
mv               finetest-newline*  $PRODDIR    || exit 1
END
        $cmd .= << "END" if $FlagTrolltest;
tar jxf $BALLDIR/trolltest-newline.tar.bz2      || exit 1
mv               trolltest-newline* $PRODDIR    || exit 1
END
        &RunCmd ($cmd);
    }

#---------------------------------------------------------------------

    chdir ($PRODDIR) || die "$IE #505850\n";

#---------------------------------------------------------------------
# Sanity check.

    if (!-f 'CMakeLists.txt')
    {
        print << 'END';
Error: You're trying to build using a "minetest" directory that's mis-
sing a "CMakeLists.txt".  The directory was probably tidied up after a
previous build.

To  rebuild, delete, move, or  rename the "minetest" directory and try
again.
END
        exit ONE;
    }

#---------------------------------------------------------------------
# Delete leftover temporary files.

    $cmd = << 'END';
for x in \
    C.includecache                  \
    CXX.includecache                \
    CMakeCache.txt                  \
    CMakeCCompiler.cmake            \
    CMakeCXXCompiler.cmake          \
    CMakeDirectoryInformation.cmake \
    CMakeRuleHashes.txt             \
    CPackConfig.cmake               \
    CPackSourceConfig.cmake         \
    DependInfo.cmake                \
    Makefile2                       \
    TargetDirectories.txt           \
    build.make                      \
    depend.make                     \
    depend.internal                 \
    cmake_config.h                  \
    cmake_install.cmake             \
    flags.make                      \
    link.txt                        \
    progress.make                   \
    relink.txt
do
    rm -fr `find . -name $x` || exit 1
done
END
    &RunCmd ($cmd);

#---------------------------------------------------------------------
# Delete more temporary files.

    $cmd = << 'END';
rm -fr textures/base/pack/menu_header_old.png           || exit 1
rm -fr `find . -name Makefile | grep -v build/android`  || exit 1
rm -fr `find . -name \*.a`                              || exit 1
rm -fr `find . -name \*.log`                            || exit 1
rm -fr `find . -name \*.o`                              || exit 1
END
    &RunCmd ($cmd);

#---------------------------------------------------------------------
# Set paths for some library files.

    my $IRRLICHT_LIBRARY = "$LIBDIR/libIrrlicht.a"   ;
    my $SQLITE3_LIBRARY  = "$LIBDIR/libsqlite3.a"    ;

    my $LUA_LIBRARY      = `find $LIBDIR/ -name libluajit-5.1.so.2`;
    die unless $LUA_LIBRARY =~ m@^\S@;
    $LUA_LIBRARY =~ s@\s+\z@@s;

#---------------------------------------------------------------------
# Set "$XCFLAGS" (extra compiler flags).

    my $XCFLAGS = "-O2 -I$INCDIR";
       $XCFLAGS = "$XCFLAGS -g" if $MAKEDEBUG;
       $XCFLAGS = "-march=native $XCFLAGS" unless $PORTABLE;
       $XCFLAGS = "$XCFLAGS -Wl,-E -Wl,-L$LIBDIR -Wl,-R$LIBDIR";

       $XCFLAGS = "$XCFLAGS -Wl,-L$LIB64DIR -Wl,-R$LIB64DIR"
           if -d $LIB64DIR;

    print "XCFLAGS=$XCFLAGS\n";

#---------------------------------------------------------------------
# Get pathnames for "gcc" and "g++" compilers.

    my $WHICH_GCC = &FixStr (`which gcc` );
    my $WHICH_GPP = &FixStr (`which g++` );

    die unless -f $WHICH_GCC && -x $WHICH_GCC;
    die unless -f $WHICH_GPP && -x $WHICH_GPP;

#---------------------------------------------------------------------
# To be documented.

    if (FALSE)
    {
        my $CM = 'src/defaultsettings.cpp';

        open (IFD, "<$CM")  || die "Internal error 0766\n";
        my $SS   = $/;
        undef $/;
        my $data = <IFD>;
           $data = "" unless defined $data;
        $/       = $SS;
        close (IFD);

        my $ses = 'secure.enable_security';
        $data =~ s@"$ses", "true"@"$ses", "false"@;

        open (OFD, ">$CM")  || die "Internal error 0777\n";
        print OFD $data;
        close (OFD)         || die "Internal error 0779\n";
    }

#---------------------------------------------------------------------
# Handle "old protocol" mode.

    if ($OLDPROTO)
    {
        my $CM = 'src/network/networkprotocol.h';

        open (IFD, "<$CM")  || die "Internal error 0714\n";
        my $SS   = $/;
        undef $/;
        my $data = <IFD>;
           $data = "" unless defined $data;
        $/       = $SS;
        close (IFD);

        $data =~ s@(#define\s+LATEST_PROTOCOL_VERSION)\s+3\d\b@$1 32@;

        open (OFD, ">$CM")  || die "Internal error 0715\n";
        print OFD $data;
        close (OFD)         || die "Internal error 0716\n";
    }

#---------------------------------------------------------------------
# Delete existing binaries.

    system "rm -fr bin";
    system "mkdir  bin";

    if (0)                      # Not presently used
    {
        for my $oldexe (qw (minetest   minetestserver
                            multicraft multicraftserver
                            finetest   finetestserver
                            trolltest  trolltestserver
                            vinetest   vinetestserver))
        {
            unlink ("bin/$oldexe");
        }

        if ($FlagFinetest)
        {
            unlink ('bin/finetestserver'  ) if $FlagServer ;
            unlink ('bin/finetest'        ) if $FlagClient ;

            unlink ('bin/vinetestserver'  ) if $FlagServer ;
            unlink ('bin/vinetest'        ) if $FlagClient ;
        }

        if ($FlagTrolltest)
        {
            unlink ('bin/trolltestserver' ) if $FlagServer ;
            unlink ('bin/trolltest'       ) if $FlagClient ;
        }
    }    

#---------------------------------------------------------------------
# Run "cmake".

    $cmd = << "END";
cmake
-DCMAKE_BUILD_TYPE=release
-DCMAKE_C_COMPILER=$WHICH_GCC
-DCMAKE_CXX_COMPILER=$WHICH_GPP

-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=1
-DCMAKE_SKIP_INSTALL_RPATH=0
-DCMAKE_SKIP_RPATH=0

$client_line
$server_line

$leveldb_line
$postgres_line
$redis_line

-DENABLE_SOUND=1
-DENABLE_SPATIAL=0
-DENABLE_SYSTEM_JSONCPP=0
-DRUN_IN_PLACE=1

-DIRRLICHT_INCLUDE_DIR=$INCDIR/irrlicht
-DIRRLICHT_LIBRARY=$IRRLICHT_LIBRARY

-DLUA_INCLUDE_DIR=$INCDIR/luajit-2.1
-DLUA_LIBRARY=$LUA_LIBRARY

-DSQLITE3_INCLUDE_DIR=$INCDIR
-DSQLITE3_LIBRARY=$SQLITE3_LIBRARY

-DCMAKE_C_FLAGS="$XCFLAGS"
-DCMAKE_CXX_FLAGS="$XCFLAGS"
-DCMAKE_C_FLAGS_RELEASE="$XCFLAGS"
-DCMAKE_CXX_FLAGS_RELEASE="$XCFLAGS"
.
END
    $cmd = &FixStr ($cmd);
    &RunCmd ($cmd);

#---------------------------------------------------------------------
# Replace some "-l..." switches with absolute pathnames.

    $cmd = << "END";
sed -e "s:-lIrrlicht:$IRRLICHT_LIBRARY:g"
    -e "s:-lluajit-5.1:$LUA_LIBRARY:g"
    -e "s:-lsqlite3:$SQLITE3_LIBRARY:g"
END
    $cmd .= << 'END';
    -i `find . -type f -name link.txt`
END
    $cmd = &FixStr ($cmd);
    &RunCmd ($cmd);

#---------------------------------------------------------------------
# Build the program.

    my $NUMJOBS = &FixStr (`getconf _NPROCESSORS_ONLN`);
    die "$IE #458310\n" unless $NUMJOBS =~ m@^\d{1,3}\z@;

    $cmd = << "END";            # "END" must be double-quoted here
make clean
make -j $NUMJOBS
mkdir -p client/serverlist
mkdir -p games worlds
cp -p $BALLDIR/arrowkeys.txt .
END
    &RunCmd ($cmd);

#---------------------------------------------------------------------
# Add preloaded cache.

    $cmd = << "END";            # "END" must be double-quoted here
rm -fr cache                        || exit 1
tar jxf $BALLDIR/cachemedia.tar.bz2 || exit 1
END
    &RunCmd ($cmd);

#---------------------------------------------------------------------
# Add "_games".

    &pushd ('games');
    $cmd =  "";

    $cmd .= << "END";           # "END" must be double-quoted here
rm -fr           bucket_game        || exit 1
mkdir            bucket_game        || exit 1
rmdir            bucket_game        || exit 1
tar zxf $GAMEDIR/bucket_game.tgz    || exit 1

rm -fr           meselite_game      || exit 1
mkdir            meselite_game      || exit 1
rmdir            meselite_game      || exit 1
tar zxf $GAMEDIR/meselite_game.tgz  || exit 1
END

    &RunCmd ($cmd);
    &popd();

#---------------------------------------------------------------------
# Add worlds.

    &pushd ('worlds');

    for my $world (qw (bucketcity bytesize meselite))
    {
        system "rm -fr $world";

        $cmd = << "END";        # "END" must be double-quoted here
mkdir $world                        || exit 1
rmdir $world                        || exit 1
unzip -o $WSRCDIR/$world.zip        || exit 1

cd    $world                        || exit 1
mv ${world}_game game               || exit 1
sed -e 's/_game//' -i world.mt      || exit 1
cd    ..                            || exit 1
END
        &RunCmd ($cmd);
    }

    &popd();

#---------------------------------------------------------------------
# Delete and/or rename executable(s) as appropriate.

    if ($FlagFinetest)
    {
        if ($FlagServer)
        {
            rename ('bin/multicraftserver' ,
                    'bin/finetestserver'   ) ||
die "Error: --finetest server build failed\n";
        }

        if ($FlagClient)
        {
            rename ('bin/multicraft'       ,
                    'bin/finetest'         ) ||
die "Error: --finetest client build failed\n";
        }
    }

    if ($FlagTrolltest)
    {
        if ($FlagServer)
        {
            rename ('bin/minetestserver'   ,
                    'bin/trolltestserver'  ) ||
die "Error: --trolltest server build failed\n";
        }

        if ($FlagClient)
        {
            rename ('bin/minetest'         ,
                    'bin/trolltest'        ) ||
die "Error: --trolltest client build failed\n";
        }
    }

#---------------------------------------------------------------------
# Strip executable(s) as appropriate.

    if (!$MAKEDEBUG)
    {
        $cmd = << 'END';
cd bin
strip finetest  finetestserver  2> /dev/null || true
strip minetest  minetestserver  2> /dev/null || true
strip trolltest trolltestserver 2> /dev/null || true
END
        &RunCmd ($cmd);
    }

#---------------------------------------------------------------------
# Additional cleanup.

    if ($TIDYUP)
    {
        $cmd = << 'END';        # 'END' must be single-quoted here
rm -fr CMake* *cmake Makefile
rm -fr build *.md debug.txt lib src
rm -fr `find . -name .[a-z]\* | grep -v " " | grep -v '\.dummy'`
END
        &RunCmd ($cmd);
    }

#---------------------------------------------------------------------
# Finish required "--makeprod" operations.

    if ($PORTABLE)
    {
        my $M    = &FixStr (`uname -m`)     ;
        my $BITS = ($M eq "i686") ? 32 : 64 ;

        $cmd = << "END";        # "END" must be double-quoted here
rm -fr solib                        || exit 1
tar jxf $BALLDIR/solib$BITS.tar.bz2 || exit 1
END
        &RunCmd ($cmd);
        &pushd ('bin');

        for my $prog (qw (minetest minetestserver))
        {
            $cmd = << "END";    # "END" must be double-quoted here
rm -fr   $prog.bin                  || exit 1
mv $prog $prog.bin                  || exit 1
cp -p $BALLDIR/$prog.wrapper $prog  || exit 1
chmod 755                    $prog  || exit 1
END
            &RunCmd ($cmd);
        }

        &popd();

#---------------------------------------------------------------------

        if ($MAKEPROD)
        {
            chdir ($THISDIR) || die "$IE #505833\n";
            my $ZIPDIR  = "minetest-linux$BITS" ;
            my $ZIPFILE = "$ZIPDIR.zip"         ;

            $cmd = << "END";    # "END" must be double-quoted here
rm -fr      $ZIPDIR  $ZIPFILE   || exit 1
mv $PRODDIR $ZIPDIR             || exit 1
zip -ro9q   $ZIPFILE $ZIPDIR    || exit 1
rm -fr               $ZIPDIR    || exit 1
ls -l       $ZIPFILE            || exit 1
END
            &RunCmd ($cmd);
        }
    }

    print "Done\n";
    undef;
}

#---------------------------------------------------------------------
#                            main program
#---------------------------------------------------------------------

&Main();                        # Call the main routine
exit ZERO;                      # Normal exit
