diff --git a/doc/mtcompile-program-local.md b/doc/mtcompile-program-local.md new file mode 100644 index 0000000..71ed839 --- /dev/null +++ b/doc/mtcompile-program-local.md @@ -0,0 +1,71 @@ +# mtcompile-program-local.py + +## Differences from mtcompile-program.pl + +### Added +- Use $HOME/git/minetest if present INSTEAD of newline + +### Removed +- EdgyTest options are mostly not present. +- FlagFakeMT4 options are mostly not present. +- FlagOldProto options are mostly not present. + + +## Known Issues +- [ ] Detect the number of cores instead of using `NUMJOBS = 2` + (enforce a range of 1 to 3 like the original?) + + +## Code History +``` +# $HOME/Downloads/git/felisPasseridae/Perl2Python/perl2python.pl $HOME/.config/EnlivenMinetest/linux-minetest-kit/mtcompile-program.pl > $HOME/git/locktopia/linux-minetest-kit-patched/mtcompile-program-local.py +# ^ won't work unless is resolved. +# (has many 'Use of uninitialized value $_ in pattern match (m//) at /home/owner/Downloads/git/felisPasseridae/Perl2Python/perl2python.pl line 179, <> line x.' where x is a line. +#if [ ! -d "$HOME/Downloads/git/Swati1910/Perl2Python-1" ]; then +# mkdir -p $HOME/Downloads/git/Swati1910 +# git clone https://github.com/Swati1910/Perl2Python-1 $HOME/Downloads/git/Swati1910/Perl2Python-1 +# cd $HOME/Downloads/git/Swati1910/Perl2Python-1 +# git checkout patch-1 +#fi +#$HOME/Downloads/git/Swati1910/Perl2Python-1/perl2python.pl $HOME/.config/EnlivenMinetest/linux-minetest-kit/mtcompile-program.pl > $HOME/git/locktopia/linux-minetest-kit-patched/mtcompile-program-local.py +#^ requires the CGI module for perl: +# See comments at . + +if [ ! -d "$HOME/Downloads/git/uhayat/perl2python" ]; then + mkdir -p $HOME/Downloads/git/uhayat + git clone https://github.com/uhayat/perl2python $HOME/Downloads/git/uhayat/perl2python + cd $HOME/Downloads/git/uhayat/perl2python + git checkout patch-1 +fi + +python $HOME/Downloads/git/uhayat/perl2python/perl2python.py -i $HOME/.config/EnlivenMinetest/linux-minetest-kit/mtcompile-program.pl -o $HOME/git/locktopia/linux-minetest-kit-patched/mtcompile-program-local.py +``` + +Then manually fix functions: +- [x] pushd +- [x] popd +- [x] RunCmd +- [x] add `customExit` to replace `die` + +Then manually fix uses of: +(errors caused by uhayat/perl2python) +- [x] `-f` perl feature +- [x] `-d` perl feature +- [ ] `segment` variable +- [x] Implement a `pushd` function +- [x] Implement a `popd` function +- [x] Implement a `GetOptions` function +- [x] use triple quotes for instances of `END` or other self-defined + stream end after `<<` +- [x] implement a `RunCmd` function +- [x] `die..if` (change to `if...customExit`) +- [x] `die..unless` (change to `if not...customExit`) +- [x] python2-style `print` without parenthesis +- [x] `TRUE` and `FALSE` (change to `True` and `False`) +- [ ] errant adding of spaces around equal signs within strings +- [x] errant use of `evalSed` without an input (`a =~ b` should become + `a = evalSed(a, b)` not `evalSed(b)`) +- [x] commented `exit` statements (they should not be commented) +- [x] use of `str` as a variable (should only be used as a builtin + Python function) (replace all with tmpStr) +- [ ] commented `open` commands diff --git a/mtcompile-program-local.py b/mtcompile-program-local.py new file mode 100644 index 0000000..185f5f1 --- /dev/null +++ b/mtcompile-program-local.py @@ -0,0 +1,1111 @@ +#!/usr/bin/env python3 +""" +--------------------------------------------------------------------- + file information +--------------------------------------------------------------------- + + Name: This program is based on mtcompile-program.pl + Purpose: Linux Minetest build script + License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0. + Attribution: OldCoder (Robert Kiraly) + and Poikilos (Jake Gustafson) + 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 +--------------------------------------------------------------------- +""" +import sys +import subprocess +import shutil +import re +import tarfile +import stat +from zipfile import ZipFile +import zipfile +import platform +import os + + +def error(msg): + sys.stderr.write(msg + "\n") + + +def customExit(msg): + error(msg) + exit(1) + + +def isExecutableFile(path): + return os.path.isfile(path) and os.access(path, os.X_OK) + + +def which(prog): + # for thisPath in os.environ["PATH"].split(os.pathsep): + for thisPath in sys.path: + # ^ sys.path includes BINDIR added before calling this! + sub_path = os.path.join(thisPath, prog) + return "" + + +def zipdir(path, ziph): + """ + Zip an entire directory. + See Mark Byers' Dec 6, 2009 answer edited by JosephH Feb 24, 2016 + on + """ + # ziph is zipfile handle + for root, dirs, files in os.walk(path): + for file in files: + ziph.write(os.path.join(root, file)) + + +def endsWithAny(haystack, needles): + for needle in needles: + if haystack.endswith(needle): + return True + return False + + +def containsAny(haystack, needles): + for needle in needles: + if haystack.contains(needle): + return True + return False + + +def startsWithAny(haystack, needles): + for needle in needles: + if haystack.startswith(needle): + return True + return False +# Label must be single-quoted here +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 "--portable" or "--makeprod" option swi- +tch os 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 deleted "build" files afterward. + + The "--git*" and "--debug" switches imply this swi- + tch. + Aliases: --notidy + +--server # Build server & not client unless --client also +--client # Build client & not server unless --server also + Default: If neither is set, both are implied + If just one is set, the other is off + +--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. + +--portable # Build a portable version. If this isn't specified, + the copy of Minetest built is tailored to your ma- + chine and may only run on an identical machine (same + hardware, distro, and distro release). At the same + time, non-portable versions may be slightly faster. + +--gitreset # Delete any existing source tree and try to do a + fresh "git clone". + +--gitpull # Try to update the current source tree using "git + pull". If there is no source tree or it's not a + "git" tree, this switch is the same as "--gitreset". + + The "git" switches require both the "git" software + package and Internet access. + +--safe # Don't delete existing source trees automatically. + +--edgy # Build EdgyTest instead of Final Minetest. Implies + "--fakemt4". + +--fakemt4 # Pretend to be MT 4. Implies "--oldproto". + +--oldproto # Limit network protocol used to level 32. For the mo- + ment, this is the default mode and there is no way + to disable it. + +--help # Display usage text and exit. + Aliases: --usage +For full documentation, see "linux-minetest-kit.txt". + +--minetest= # Set the minetest source path to a + # locally-modified copy, such as + # $HOME/git/minetest + +Before using this script, please +see doc/mtcompile-program-local.md in EnlivenMinetest +for changes and progress on implementing features from +mtcompile-program.pl. +""" + +#--------------------------------------------------------------------- +# module setup +#--------------------------------------------------------------------- + +# TODO: Trap warnings to mimic the Perl version? +#SIG["__WARN__"] = sub { die @_; } + +#--------------------------------------------------------------------- +# program parameters +#--------------------------------------------------------------------- + + +def _UNUSED_evalSed(line, sedStr): + """ + Mimic sed. + Example: + To mimic Perl `$str =~ s@\s+@ @gs;` do `evalSed(str, "s@\s+@ @gs")`. + For m/, use re.findall() instead. + """ + # - See + # - See + return os.popen('echo "{}" | sed "{}"'.format(line, sedStr)).read() + + +PURPOSE = 'Linux Minetest build script' +REVISION = '200522' # version of this script, not linux-minetest-kit +PROFILE_DIR = None +HOME_V = "HOME" +if platform.system() == "Windows": + HOME_V = "USERPROFILE" +PROFILE_DIR = os.environ.get(HOME_V) + +EXTRACTED_DIR = None +if os.path.isdir("mtsrc"): + EXTRACTED_DIR = os.getcwd() +elif PROFILE_DIR is not None: + EXTRACTED_DIR = os.path.join(PROFILE_DIR, ".config", + "EnlivenMinetest", + "linux-minetest-kit") + if not os.path.isdir(EXTRACTED_DIR): + print("You must run this from the directory of the extracted") + print("linux-minetest-kit or have {}".format(EXTRACTED_DIR)) + exit(1) +else: + if not os.path.isdir(EXTRACTED_DIR): + print("You must run this from the directory of the extracted" + "linux-minetest-kit or have a {} variable" + "".format(HOME_V)) + exit(1) + +GITURL = 'http://git.minetest.org/minetest/minetest.git' +IE = 'Internal error' +FlagMinetest = None + +#--------------------------------------------------------------------- +# global variables +#--------------------------------------------------------------------- + +PROGNAME = None # Program name without path +DirStack = [os.getcwd()] # Directory stack + +#--------------------------------------------------------------------- +# used by "--oldproto" +#--------------------------------------------------------------------- + +segment = """ +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: +""" + +#--------------------------------------------------------------------- +# low-level utility routines +#--------------------------------------------------------------------- + + + +def pushd(path): + if not os.path.isdir(path): + print("[pushd] ERROR: \"{}\" does not exist.".format(path)) + exit(1) + os.chdir(path) + DirStack.append(path) + + +def popd(): + if len(DirStack) < 2: + print("[popd] ERROR: only the original path is on the stack") + print(" (you popped more than you pushed).") + exit(1) + else: + del DirStack[-1] + os.chdir(DirStack[-1]) + + +def RunCmd(cmdParts, exitOnFail=True): + child = subprocess.Popen(openRTSP+opts.split(), + stdout=subprocess.PIPE) + streamdata = child.communicate()[0] + rc = child.returncode + if rc != 0: + if exitOnFail: + exit(rc) + else: + print("WARNING: {} failed".format(' '.join(cmdParts))) + + +def FixStr(s): + # TODO: make sure this does everything the original does + # (see mtcompile-program.pl) + if s is None: + return "" + return s.strip() + + +def GetProgDir(): + # TODO: finish converting this from Perl + # - [x] set PROGNAME + global PROGNAME + PROGNAME = os.path.basename(__file__) + return os.getcwd() + + +def GetOptions(nonBoolNames=[], TitleCaseAndFlag=False, bareArgs=[]): + """ + Convert command-line arguments to globals. + + Keyword Arguments: + nonBoolNames -- You should set all of these to None in the global + namespace before calling this so that you can check them against + None later without getting an undefined variable error. + TitleCaseAndFlag -- Change '--something' to 'FlagSomething' if + TitleCaseAndFlag, otherwise change it to 'something'. + bareArgs -- allowed arguments without "--" at the beginning. + + Returns: + false if arg has an equal sign and preceding part after "--" is not + in nonBoolNames. + """ + for i in range(1, len(sys.argv)): + arg = sys.argv[i] + if (arg in bareArgs) or arg.startswith("--"): + start = 0 + if arg.startswith("--"): + start = 2 + signI = arg.find("=") + name = arg[start:] + val = True + if signI > -1: + name = arg[start:signI] + if name not in nonBoolNames: + print("Only the following options can have values:" + " {}.".format(nonBoolNames)) + return False + val = arg[signI+1:] + if TitleCaseAndFlag: + name = "Flag" + name.title() + globals()[name] = val + else: + print("The option is unknown: {}".format(arg)) + return False + return True + + +USAGE_FMT = """ +#{PROGNAME} {REVISION} - {PURPOSE} + +#{USAGE_TEXT} +""" + + +def UsageText(): + """ + "UsageText" prints usage text for the current program, then termin- + ates the program with exit status one. + """ + # NOTE: PROGNAME is this script's name, NOT the engine name. + THIS_USAGE = USAGE_FMT.format(PROGNAME=PROGNAME, + REVISION=REVISION, + PURPOSE=PURPOSE, + USAGE_TEXT=USAGE_TEXT.format( + PROGNAME=PROGNAME + )) + # USAGE_TEXT = evalSed('s@\s*\z@\n@s') + print(THIS_USAGE) + exit(1) + + +def main(): + + #--------------------------------------------------------------------- + # Misc. variables. + + #my $cmd; # Shell command string + #my $tmpStr; # Scratch + + #--------------------------------------------------------------------- + # Mode flags. + + # These may be modified, indirectly, by command-line switches. + + MAKEDEBUG = False + PORTABLE = False + TIDYUP = True + MAKEPROD = False + + #--------------------------------------------------------------------- + # Command-line option flags. + + FlagBuild = False + FlagClient = False + FlagDebug = False + FlagEdgy = False + FlagGitPull = False + FlagGitReset = False + FlagHelp = False + FlagMakeProd = False + FlagFakeMT4 = False + FlagNoClean = False + FlagPortable = False + FlagPostgres = False + FlagRedis = False + FlagSafe = False + FlagServer = False + + FlagOldProto = True + + #--------------------------------------------------------------------- + # 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. + + THISDIR = GetProgDir() + + #--------------------------------------------------------------------- + # Parse command-line arguments. + + if not GetOptions(nonBoolNames=["minetest"], TitleCaseAndFlag=True, + bareArgs=["build"]): + UsageText() + + # Handle usage-text exit + if (not FlagBuild) or FlagHelp: + UsageText() + + #--------------------------------------------------------------------- + # Handle misc. flag issues. + if FlagEdgy: + FlagFakeMT4 = True + if FlagEdgy or FlagFakeMT4: + FlagOldProto = True + if FlagEdgy and FlagGitPull: + customExit("Error: Can't use both --edgy and --gitpull") + + #--------------------------------------------------------------------- + # Confirm that script is running in the right place. + + if not os.path.isdir('mtsrc'): + error(""" +Error: This script should be stored, and executed, in the directory +which contains the "mtsrc" directory. +""") + exit(1) + + #--------------------------------------------------------------------- + # Additional directory paths. + + BALLDIR = os.path.join(THISDIR, "mtsrc", "newline") + PRODDIR = os.path.join(THISDIR, "minetest") + TOOLS_PREFIX = os.path.join(THISDIR, "toolstree") + + BINDIR = os.path.join(TOOLS_PREFIX, "bin") + INCDIR = os.path.join(TOOLS_PREFIX, "include") + LIBDIR = os.path.join(TOOLS_PREFIX, "lib") + LIB64DIR = os.path.join(TOOLS_PREFIX, "lib64") + + #--------------------------------------------------------------------- + # Misc. setup. + sys.path.insert(0, BINDIR) + which("g++") + #--------------------------------------------------------------------- + # Handle some of the option flags. + if FlagDebug: + MAKEDEBUG = True + if FlagMakeProd: + MAKEPROD = True + if FlagNoClean: + TIDYUP = False + + if MAKEPROD: + MAKEDEBUG = False + PORTABLE = True + TIDYUP = True + + #--------------------------------------------------------------------- + # Handle "--gitreset". + + if FlagGitReset: + if FlagGitPull: + customExit("Error: Can't use both --gitreset and --gitpull\n") + + if FlagSafe and os.path.isdir('minetest'): + print(""" +Error: "minetest" directory exists and "--gitreset" needs to delete +it. But can't because "--safe" was specified. If you wish to proceed, +move or rename the directory. +""") + exit(1); + + TIDYUP = False + print(""" +* --gitreset specified and --safe not specified +* Removing any existing "minetest" directory +""") + shutil.rmtree("minetest") + print("* Attempting a git clone...") + cmdParts = ["git", "clone", GITURL, "minetest"] + print(" " + " ".join(cmdParts)) + RunCmd(cmdParts); + + #--------------------------------------------------------------------- + # Handle "--gitpull". + + if FlagGitPull: + if FlagGitReset: + customExit("Error: Can't use both --gitreset and --gitpull\n") + + TIDYUP = False + + if os.path.isdir('minetest'): + if not os.path.isdir('minetest/.git'): + print(""" +Error: "--gitpull" specified and I see a "minetest" directory but no +"minetest/.git" directory. +If you'd like to use "--gitpull", delete, rename, or move the "mine- +test" directory. + +Or you can use "--gitreset" instead. This will delete the directory +automatically. +""") + exit(1) + + if not os.path.isdir('minetest'): + print(""" +* "--gitpull" specified but I don't see a "minetest" directory +* Attempting a git clone +""") + cmdParts = ["git", "clone", GITURL, "minetest"] + print("cmd " + " ".join(cmdParts)) + RunCmd(cmdParts) + else: + if not os.path.isdir(os.path.join("minetest", ".git")): + customExit(IE + "#250458") + + print(""" +* --gitpull specified and I see "minetest/.git" +* Attempting a git pull +""") + pushd('minetest'); + cmdParts = ["git", "pull"] + RunCmd(cmdParts, exit_on_fail=false) + popd(); + + #--------------------------------------------------------------------- + # Handle "--client" and "--server". + + client_line = "-DBUILD_CLIENT=1" + server_line = "-DBUILD_SERVER=1" + + if FlagClient and not FlagServer: + client_line = "-DBUILD_CLIENT=1" + server_line = "-DBUILD_SERVER=0" + + if not FlagClient and FlagServer: + client_line = "-DBUILD_CLIENT=0" + server_line = "-DBUILD_SERVER=1" + + #--------------------------------------------------------------------- + # Status messages. + + NUBDF = "not used by default in this version" + + print(""" +* leveldb (by default) +* sqlite3 (by default) +""") + + #--------------------------------------------------------------------- + # Handle "--postgres". + + postgres_line = "-DENABLE_POSTGRESQL=0" + + if FlagPostgres: + print("* postgres (due to --postgresql)") + postgres_line = "-DENABLE_POSTGRESQL=1" + else: + print("(skipping postgresql --"+NUBDF) + + #--------------------------------------------------------------------- + # Handle "--redis". + + redis_line = "-DENABLE_REDIS=0" + + if FlagRedis: + print("* redis (due to --redis)") + redis_line = "-DENABLE_REDIS=1" + else: + print("(skipping redis --"+NUBDF) + + #--------------------------------------------------------------------- + # "--portable" requires the bootstrapped "gcc". + + if PORTABLE and not os.path.isfile(os.path.join(BINDIR, "gcc")): + print(""" +Error: For Linux portable mode (--portable), you need to build the in- +cluded "gcc" 8 compiler. To do so, run "mtcompile-libraries.sh" with +gcc-bootstrap mode enabled. +""") + exit(1) + + #--------------------------------------------------------------------- + # Identify "gcc" major release number. + + #my ($GCCVER) = $tmpStr =~ m@\ngcc.* (\d+)*\.\d+\.@ + tmpStr = subprocess.check_output(["gcc", "--version"]).decode() + tmpParts = re.findall("gcc.* (\d+)*\.\d+\.", tmpStr) + GCCVER = None + if len(tmpParts) > 0: + GCCVER = tmpParts[0] + else: + customExit("Error: Not able to identify gcc release") + + #--------------------------------------------------------------------- + # Replace existing "minetest" directory. + + RESETDIR = (not os.path.isdir(PRODDIR)) or TIDYUP + + if RESETDIR: + if FlagSafe and os.path.isdir('minetest'): + print(""" + +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. +""") + exit(1) + # PRODDIR is THISDIR/minetest + print("* cleaning " + os.getcwd()) + for sub in os.listdir(THISDIR): + sub_path = os.path.join(THISDIR, sub) + if sub.startswith("."): + continue + if os.path.isfile(sub_path): + continue + if sub_path == PRODDIR: + # ^ sub_path must be generated the same way as + # PRODDIR (from THISDIR) for this to work. + shutil.rmtree(sub_path) + elif sub.startswith("minetest-newline"): + shutil.rmtree(sub_path) + print("* extracting in " + os.getcwd()) + mtNewLine = "minetest-newline" + if FlagEdgy: + mtNewLine = "minetest-newline" + if FlagMinetest is not None: + if not os.path.isdir(FlagMinetest): + customExit("{} does not exist.".format(FlagMinetest)) + print("* using \"{}\"".format(FlagMinetest)) + shutil.copytree(FlagMinetest, PRODDIR, copy_function=copy2) + else: + tarPath = os.path.join(BALLDIR, mtNewLine + ".tar.bz2") + tar = tarfile.open(tarPath) + tar.extractall(path=THISDIR) + tar.close() + for sub in os.listdir(THISDIR): + sub_path = os.path.join(THISDIR, sub) + if sub.startswith(mtNewLine): + print("* using {} as minetest".format(sub_path)) + shutil.move(sub_path, PRODDIR) + break + + os.chdir(PRODDIR) + # or die "$IE #505850\n"; + + #--------------------------------------------------------------------- + # Sanity check. + + if not os.path.isfile('CMakeLists.txt'): + print(""" +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. +""") + exit(1) + + #--------------------------------------------------------------------- + # Delete leftover temporary files. + tmpFileNames = [ + "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" + ] + tmpFilePaths = [ + "textures/base/pack/menu_header_old.png" + ] + tmpExtensions = [ + ".a", + ".log", + ".o" + ] + androidSub = os.path.join("build", "android") + for root, dirs, files in os.walk(".", topdown=False): + for name in files: + subPath = os.path.join(root, name) + if name in tmpFileNames: + os.remove(subPath) + elif (name == "Makefile") and (androidSub in subPath): + os.remove(subPath) + elif endsWithAny(subPath, tmpFilePaths + tmpExtensions): + os.remove(subPath) + + #--------------------------------------------------------------------- + # Define paths for some ".a" library files. + + IRRLICHT_LIBRARY = os.path.join(LIBDIR, "libIrrlicht.a") + LEVELDB_LIBRARY = os.path.join(LIBDIR, "libleveldb.a") + LUA_LIBRARY = os.path.join(LIBDIR, "libluajit-5.1.a") + SQLITE3_LIBRARY = os.path.join(LIBDIR, "libsqlite3.a") + + #--------------------------------------------------------------------- + # Set "$XCFLAGS" (extra compiler flags). + + XCFLAGS = "-O2 -I" + INCDIR + "" + if MAKEDEBUG: + XCFLAGS = XCFLAGS + " -g" + if not PORTABLE: + XCFLAGS = "-march=native " + XCFLAGS + XCFLAGS = XCFLAGS + " -Wl,-L" + LIBDIR + " -Wl,-R" + LIBDIR + if os.path.isdir(LIB64DIR): + XCFLAGS = "$XCFLAGS -Wl,-L" + LIB64DIR + " -Wl,-R" + LIB64DIR + + print("XCFLAGS="+XCFLAGS) + + #--------------------------------------------------------------------- + # Get pathnames for "gcc" and "g++" compilers. + + WHICH_GCC = which("gcc") + WHICH_GPP = which("g++") + if not isExecutableFile(WHICH_GCC): + customExit("gcc is not present or not executable.") + if not isExecutableFile(WHICH_GPP): + customExit("g++ is not present or not executable.") + + #--------------------------------------------------------------------- + # Handle another "--edgy step". + + if FlagEdgy: + CM = 'src/defaultsettings.cpp' + # TODO: finish converting this from perl + print("FlagEdgy changing {} is not yet implemented." + "".format(CM)) + data = None + try: + with open(CM, 'r') as IFD: + pass + #SS = $/ + #undef $/; + #data = + #data = ""unless defined + data + #/ = SS + # - secure.enable_security to false by default + except FileNotFoundError: + customExit("Internal error 0766") + # try: + # with open(CM) as OFD: + # OFD.write(data) + # except FileNotFoundError: + # customExit("Internal error 0777") + #--------------------------------------------------------------------- + # Handle "--fakemt4". + + if FlagFakeMT4: + + CM = 'CMakeLists.txt' + print("FlagFakeMT4 changing {} is not yet implemented." + "".format(CM)) + # TODO: handle fakemt4 + # data = None + # with open(CM, 'r') as IFD: # or die "Internal error 0789\n"; + # SS = $/ + # undef $/; + # data = + # data = ""unless defined + data + # / = SS + + # pat = << 'END' + # set\(VERSION_MAJOR \d+\) + # .*? + # if \(CMAKE_BUILD_TYPE STREQUAL Debug\) + # END + # pat = evalSed('s@\s+\z@@s') + # pat = evalSed('s@\s*\n\s*@@gs') + # TODO: Use the segment variable here + # data = evalSed('s@\s*$pat\s*@\n$segment@is') + # with open(CM, 'w') as OFD: # or die "Internal error 0806\n"; + # OFD.write(data) + # OFD.close() # or die "Internal error 0808\n"; + + #--------------------------------------------------------------------- + # Handle "--oldproto". + + if FlagOldProto: + CM = 'src/network/networkprotocol.h' + print("FlagOldProto changing {} is not yet implemented." + "".format(CM)) + # TODO: change protocol in CM: + # data = None + # with open(CM, 'r') as IFD: #or die "Internal error 0714\n"; + # SS = $/ + # undef $/; + # data = + # data = ""unless defined + data + # / = SS + # data = evalSed('s@(#define\s+LATEST_PROTOCOL_VERSION)\s+3\d\b@$1 32@') + # with open("CM", 'w') as OFD: # or die "Internal error 0715\n"; + # OFD.write(data) + + #--------------------------------------------------------------------- + # Run "cmake". + cmdParts = ["cmake"] + cmdParts.append("-DCMAKE_BUILD_TYPE=release") + cmdParts.append("-DCMAKE_C_COMPILER="+WHICH_GCC) + cmdParts.append("-DCMAKE_CXX_COMPILER="+WHICH_GPP) + cmdParts.append("-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=1") + cmdParts.append("-DCMAKE_SKIP_INSTALL_RPATH=0") + cmdParts.append("-DCMAKE_SKIP_RPATH=0") + cmdParts.append(client_line) + cmdParts.append(server_line) + cmdParts.append("-DENABLE_LEVELDB=1") + cmdParts.append(postgres_line) + cmdParts.append(redis_line) + cmdParts.append("-DENABLE_SOUND=1") + cmdParts.append("-DENABLE_SPATIAL=0") + # ^ TODO: WHY 0 in linux-minetest-kit? + cmdParts.append("-DENABLE_SYSTEM_JSONCPP=0") + cmdParts.append("-DRUN_IN_PLACE=1") + cmdParts.append("-DIRRLICHT_INCLUDE_DIR={}/irrlicht".format(INCDIR)) + cmdParts.append("-DIRRLICHT_LIBRARY="+IRRLICHT_LIBRARY) + cmdParts.append("-DLEVELDB_INCLUDE_DIR={}/leveldb".format(INCDIR)) + cmdParts.append("-DLEVELDB_LIBRARY="+LEVELDB_LIBRARY) + cmdParts.append("-DLUA_INCLUDE_DIR={}/luajit-2.1".format(INCDIR)) + cmdParts.append("-DLUA_LIBRARY="+LUA_LIBRARY) + cmdParts.append("-DSQLITE3_INCLUDE_DIR="+INCDIR) + cmdParts.append("-DSQLITE3_LIBRARY="+SQLITE3_LIBRARY) + cmdParts.append("-DCMAKE_C_FLAGS=\"{}\"".format(XCFLAGS)) + cmdParts.append("-DCMAKE_CXX_FLAGS=\"{}\"".format(XCFLAGS)) + cmdParts.append("-DCMAKE_C_FLAGS_RELEASE=\"{}\"".format(XCFLAGS)) + cmdParts.append("-DCMAKE_CXX_FLAGS_RELEASE=\"{}\"".format(XCFLAGS)) + RunCmd(cmdParts); + + # TODO: use some absolute pathnames as the Perl version does + #--------------------------------------------------------------------- + # Replace some "-l..." switches with absolute pathnames. + + #cmd = << "END" + #sed -e "s:-lIrrlicht:$IRRLICHT_LIBRARY:g" + #-e "s:-lleveldb:$LEVELDB_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. + NUMJOBS = 2 + RunCmd(["make", "clean"]) + RunCmd("make", "-j{}".format(NUMJOBS)) + serverlistDir = os.path.join(PRODDIR, "client", "serverlist") + os.makedirs(serverlistDir, exist_ok=True) + os.makedirs("games", exist_ok=True) + os.makedirs("worlds", exist_ok=True) + dstAKPath = os.path.join(PRODDIR, "arrowkeys.txt") + shutil.copy(os.path.join(BALLDIR, "arrowkeys.txt"), dstAKPath) + + #--------------------------------------------------------------------- + # Add preloaded cache. + thisCache = os.path.join(PRODDIR, "cache") + if os.path.isdir(thisCache): + shutil.rmtree(thisCache) + tarPath = os.path.join(BALLDIR, "cachemedia.tar.bz2") + tar = tarfile.open(tarPath) + tar.extractall(path=PRODDIR) + tar.close() + + #--------------------------------------------------------------------- + # Add "_games". + + pushd('games'); + cmd = "" + gameNames = ["minimal", "amhi_game"] + if not FlagEdgy: + # TODO: What does FlagEdgy do here? Does it leave the old + # Bucket_Game and do nothing else differently? + # See mtcompile-program.pl + gameNames.append("Bucket_Game") + print("* purging gamepaths: {}".format(gamePaths)) + for gameName in gameNames: + gamePath = os.path.join(PRODDIR, gameName) + if os.path.isdir(gamePath): + shutil.rmtree(gamePath) + zipPath = os.path.Join(BALLDIR, gameName + ".zip") + if os.path.isfile(zipPath): + zf = ZipFile(zipPath) + zf.extractall(gamePath) # pwd means password in this case + popd(); + + #--------------------------------------------------------------------- + # Add worlds. + + #pushd('worlds'); + WORLDS_PATH = os.path.join(PRODDIR, "worlds") + for worldName in ["Bucket_City", "Wonder_World"]: + worldPath = os.path.join(WORLDS_PATH, worldName) + if os.path.isdir(worldPath): + shutil.rmtree(worldPath) + if FlagEdgy: + continue + tarPath = os.path.join(BALLDIR, worldName) + if os.path.isfile(tarPath): + tar = tarfile.open(tarPath) + tar.extractall(path=WORLDS_PATH) + tar.close() + else: + print("WARNING: \"{}\" is missing.".format(tarPath)) + #popd(); + + #--------------------------------------------------------------------- + # Strip the executable(s). + + if not MAKEDEBUG: + for thisBinName in ["minetest", "minetestserver"]: + thisBinPath = os.path.join(PRODDIR, "bin", thisBinName) + if not os.path.isfile(thisBinPath): + continue + RunCmd(["strip", thisBinPath]) + + #--------------------------------------------------------------------- + # Additional cleanup. + + if TIDYUP: + tmpNames = ["MakeFile", "build", "debug.txt", "lib", "src"] + tmpEndsWith = ["cmake"] + tmpStartsWith = ["CMake"] + for root, dirs, files in os.walk(".", topdown=False): + for name in files: + subPath = os.path.join(root, name) + if name in tmpNames: + if os.path.isfile(subPath): + os.remove(subPath) + else: + shutil.rmtree(subPath) + elif endsWithAny(subPath, tmpEndsWith): + if os.path.isfile(subPath): + os.remove(subPath) + else: + shutil.rmtree(subPath) + elif startsWithAny(subPath, tmpStartsWith): + if os.path.isfile(subPath): + os.remove(subPath) + else: + shutil.rmtree(subPath) + + keepWith = [" ", ".dummy"] + + for root, dirs, files in os.walk(".", topdown=False): + for name in files: + subPath = os.path.join(root, name) + if containsAny(name, keepWith): + continue + if not name.startswith("."): + continue + if name[1:2].upper() != name[1:2]: + # .[a-z]\* + os.remove(subPath) + + #--------------------------------------------------------------------- + # Finish required "--portable" operations. + + if PORTABLE: + M = os.uname().machine + BITS = 32 if (M == "i686") else 64 + solibPath = os.path.join(PRODDIR, "solib") + if os.path.isdir(solibPath): + shutil.rmtree(solibPath) + + tarPath = os.path.join(BALLDIR, "solib{}.tar.bz2".format(BITS)) + if os.path.isfile(tarPath): + tar = tarfile.open(tarPath) + tar.extractall(path=PRODDIR) + if not os.path.isdir(solibPath): + customExit("ERROR: extracting \"{}\" did not result in" + " \"{}\"".format(tarPath, solibPath)) + tar.close() + else: + customExit("ERROR: \"{}\" is missing.".format(tarPath)) + # pushd('bin'); + for prog in ["minetest", "minetestserver"]: + srcWrapPath = os.path.join(BALLDIR, prog+".wrapper") + progWrapPath = os.path.join(PRODDIR, "bin", prog) + progBinPath = os.path.join(PRODDIR, "bin", prog+".bin") + if os.path.isfile(progBinPath): + os.remove(progBinPath) + shutil.move(progWrapPath, progBinPath) + # copy2 mimics `cp -p` (preserve attributes) + shutil.copy2(srcWrapPath, progWrapPath) + os.chmod(progWrapPath, 0o755) + + # popd() +#--------------------------------------------------------------------- + + if MAKEPROD: + # os.chdir(THISDIR) # or die "$IE #505833\n"; + ZIPDIR = "minetest-linux" + BITS + ZIPDIR_PATH = os.path.join(THISDIR, ZIPDIR) + ZIPFILE = ZIPDIR + ".zip" + ZIPFILE_PATH = os.path.join(THISDIR, ZIPFILE) + if os.path.isdir(ZIPDIR_PATH): + shutil.rmtree(ZIPDIR_PATH) + if os.path.isfile(ZIPFILE_PATH): + os.remove(ZIPFILE_PATH) + shutil.move(PRODDIR_PATH, ZIPDIR_PATH) + zf = zipfile.ZipFile(ZIPFILE_PATH, 'w', + zipfile.ZIP_DEFLATED, compresslevel=9) + zipdir(ZIP_PATH, zf) + zf.close() + # originally zip -ro9q + # r: recurse into subdirectories (done by zipdir) + # o: make zipfile as old as latest entry (handled below) + # 9: compress better + # q: quiet + latestStamp = None + for root, dirs, files in os.walk(ZIPDIR_PATH): + for name in files: + subPath = os.path.join(root, name) + stamp = os.stat("ideas.md").st_mtime + if (latestStamp is None) or (stamp > latestStamp): + latestStamp = stamp + st = os.stat(ZIPFILE_PATH) + # See + atime = st[stat.ST_ATIME] + mtime = st[stat.ST_MTIME] + shutil.rmtree(ZIPDIR_PATH) + os.utime(ZIPFILE_PATH, (atime, latestStamp)) + + print("Done\n") + #end main + + +if __name__ == "__main__": + main()