diff --git a/.gitignore b/.gitignore index 49744f46..27981aad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ ISLE.EXE LEGO1.DLL build/ original/ -compiler/ +tools/msvc42/ +tools/ninja/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 46ee6707..72333a3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,6 @@ cmake_minimum_required(VERSION 2.8...3.5 FATAL_ERROR) project(isle CXX) -link_directories("$ENV{LIB}") -include_directories("$ENV{INCLUDE}") - option(ISLE_BUILD_APP "Build ISLE.EXE application" ON) add_library(lego1 SHARED diff --git a/build.py b/build.py old mode 100644 new mode 100755 index 6538bb8a..99228de1 --- a/build.py +++ b/build.py @@ -1,10 +1,12 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 -import pathlib -import subprocess import argparse +import pathlib import re import requests +import subprocess + +ISLE_PATH = pathlib.Path(__file__).parents[0] parser = argparse.ArgumentParser() parser.add_argument("-i", "--inspect", metavar='', @@ -16,6 +18,7 @@ parser.add_argument("--inspect-shim", nargs=2, metavar=('', ''), help="Inspect the assembly diff of the function spanning in . " "Intended to be invoked by IDE commands.") +parser.add_argument("-B", dest="builddir", default=ISLE_PATH / "build", type=pathlib.Path, help="build directory") args = parser.parse_args() # Figure out what offset to pass to the reccmp tool if any @@ -44,17 +47,18 @@ def get_inspect_offset(): return None # If the build directory doesn't exist yet, run configure.py -if not pathlib.Path("build").exists(): +if not args.builddir.exists(): print("Not configured yet, please run configure.py first.") exit(1) # Run cmake, with no parallel build because that does not play nice the # MSVC420 compiler the original game was built with thanks to the different # threads contending over the pdb file. -result = subprocess.run(["cmake", "--build", ".", "-j", "1"], cwd="build") +result = subprocess.run(["cmake", "--build", ".", "-j", "1"], cwd=str(args.builddir)) def require_original(): - if not pathlib.Path("original/LEGO1.DLL").exists(): + if not (ISLE_PATH / "original/LEGO1.DLL").exists(): + (ISLE_PATH / "original").mkdir(parents=True, exist_ok=True) print("Couldn't find original/LEGO1.DLL. Downloading a copy...") url1 = "https://legoisland.org/download/ISLE.EXE" r1 = requests.get(url1, stream=True) diff --git a/configure.py b/configure.py old mode 100644 new mode 100755 index 8c5444ba..73d1af0d --- a/configure.py +++ b/configure.py @@ -1,72 +1,122 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 -import pathlib -import subprocess import argparse -import shutil -import platform -import requests -import zipfile import io import os +import pathlib +import platform +import requests +import shutil +import subprocess +import textwrap +import zipfile -parser = argparse.ArgumentParser() +ISLE_PATH = pathlib.Path(__file__).parents[0] + +parser = argparse.ArgumentParser(allow_abbrev=False) parser.add_argument("-m", "--modern-compiler", action="store_true", help="Use a contemporary compiler instead of Microsoft Visual C++ 4.2 even though this will result in non-matching code") +parser.add_argument("-B", dest="builddir", default=ISLE_PATH / "build", type=pathlib.Path, help="build directory") args = parser.parse_args() -# Do we have a builtin ninja? -specific_ninja = None -if shutil.which("ninja") is None: - sys = platform.system() - # Use the bundled ninja - if sys == "Windows": - specific_ninja = "./tools/ninja/ninja-win.exe" - elif sys == "Linux": - specific_ninja = "./tools/ninja/ninja-linux" - elif sys == "Darwin": - specific_ninja = "./tools/ninja/ninja-mac" - else: - print("No bundled ninja for this platform, please install ninja and add it to your path.") - exit(1) - specific_ninja = str(pathlib.Path(specific_ninja).absolute()) +builddir = args.builddir.resolve() + +compilerdir = ISLE_PATH / "tools/msvc42" # Create a build folder in the current directory if it does not exist -pathlib.Path("build").mkdir(parents=True, exist_ok=True) - -# Create a folder for the compiler -pathlib.Path("compiler").mkdir(parents=True, exist_ok=True) +builddir.mkdir(parents=True, exist_ok=True) # Check if MSVC420 is in the INCLUDE environment variable -set_compiler_paths = False -if not args.modern_compiler: - if not pathlib.Path("compiler/MSVC420-master").exists(): - print("MSVC420 not found in compiler/...") - url = "https://github.com/itsmattkc/MSVC420/archive/refs/heads/master.zip" - print("Downloading MSVC420...") - r = requests.get(url, stream=True) - print("Unzipping to compiler/...") - z = zipfile.ZipFile(io.BytesIO(r.content)) - z.extractall(path="compiler") - set_compiler_paths = True +set_compiler_paths = not args.modern_compiler +if not args.modern_compiler and not compilerdir.exists(): + # Create a folder for the compiler + compilerdir.mkdir(parents=True, exist_ok=True) + + print(f"MSVC420 not found in {compilerdir}/...") + url = "https://github.com/itsmattkc/MSVC420/archive/refs/heads/master.zip" + print("Downloading MSVC420...") + r = requests.get(url, stream=True) + z = zipfile.ZipFile(io.BytesIO(r.content)) + print(f"Unzipping MSVC420 to {compilerdir}/...") + for name in z.namelist(): + info = z.getinfo(name) + # Remove the MSVC420-master prefix + extract_name = name.split("/", 1)[1] + if not extract_name: + continue + fullpath = compilerdir / extract_name + if info.is_dir(): + fullpath.mkdir(parents=True, exist_ok=True) + else: + with fullpath.open("wb") as f: + f.write(z.read(name)) # Run cmake in the build folder -cmake_args = [] -cmake_args += ["-G", "Ninja"] -cmake_args += ["-DCMAKE_BUILD_TYPE=RelWithDebInfo"] -if specific_ninja: - cmake_args += ["-DCMAKE_MAKE_PROGRAM="+specific_ninja] +cmake_cmd = [ + "cmake", + str(ISLE_PATH), + "-G", "Ninja", + "-DCMAKE_BUILD_TYPE=RelWithDebInfo" +] + +# Do we have a builtin ninja? +if shutil.which("ninja") is None: + sys = platform.system() + ninjadir = ISLE_PATH / "tools/ninja" / sys + ninja_urls = { + "Windows": "https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-win.zip", + "Linux": "https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-linux.zip", + "Darwin": "https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-mac.zip", + } + if sys not in ninja_urls: + print("Ninja is not available for this platform, please install ninja and add it to your PATH.") + exit(1) + if not ninjadir.exists(): + print("Downloading Ninja...") + r = requests.get(ninja_urls[sys], stream=True) + z = zipfile.ZipFile(io.BytesIO(r.content)) + print(f"Unzipping Ninja to {ninjadir}/...") + z.extractall(path=str(ninjadir)) + + specific_ninja = ninjadir / ("ninja" + ".exe" if sys == "Windows" else "") + print("Using specific ninja:", specific_ninja) + cmake_cmd += [f"-DCMAKE_MAKE_PROGRAM={specific_ninja.as_posix()}"] + +extra_include_dirs = [] +extra_library_dirs = [] + if set_compiler_paths: - full_compiler_path = pathlib.Path.cwd() / "compiler" / "MSVC420-master/" - cmake_args += ["-DCMAKE_CXX_COMPILER=" + (full_compiler_path / "bin" / "CL.EXE").as_posix()] - cmake_args += ["-DCMAKE_C_COMPILER=" + (full_compiler_path / "bin" / "CL.EXE").as_posix()] - cmake_args += ["-DCMAKE_LINKER=" + (full_compiler_path / "bin" / "LINK.EXE").as_posix()] - cmake_args += ["-DCMAKE_RC_COMPILER=" + (full_compiler_path / "bin" / "RC.EXE").as_posix()] - os.environ["INCLUDE"] = (full_compiler_path / "include").as_posix() - os.environ["LIB"] = (full_compiler_path / "lib").as_posix() -cmake_args += [".."] -subprocess.run(["cmake"] + cmake_args, cwd="build") + full_compiler_path = compilerdir + cl_path = (full_compiler_path / "bin" / "CL.EXE").as_posix() + link_path = (full_compiler_path / "bin" / "LINK.EXE").as_posix() + rc_path = (full_compiler_path / "bin" / "RC.EXE").as_posix() + + extra_include_dirs += [ + (full_compiler_path / "include").as_posix(), + ] + extra_library_dirs += [ + (full_compiler_path / "lib").as_posix(), + ] + + cmake_toolchain_file = builddir / "msvc42.cmake" + cmake_cmd += [f"-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file}"] + with cmake_toolchain_file.open("w") as f: + print(textwrap.dedent(f"""\ + set(CMAKE_SYSTEM_NAME "Windows") + + set(CMAKE_C_COMPILER "{cl_path}") + set(CMAKE_CXX_COMPILER "{cl_path}") + set(CMAKE_RC_COMPILER "{rc_path}") + set(CMAKE_LINKER "{link_path}") + """), file=f) + for incdir in extra_include_dirs: + print(f"""include_directories("{incdir}")""", file=f) + for libdir in extra_library_dirs: + print(f"""link_directories("{libdir}")""", file=f) + +print("cmake command:", " ".join(cmake_cmd)) +subprocess.run(cmake_cmd, cwd=builddir) # Create a folder for the original binaries if not pathlib.Path("original/LEGO1.DLL").exists(): diff --git a/tools/ninja/ninja-linux b/tools/ninja/ninja-linux deleted file mode 100644 index 3aaf2a9d..00000000 Binary files a/tools/ninja/ninja-linux and /dev/null differ diff --git a/tools/ninja/ninja-mac b/tools/ninja/ninja-mac deleted file mode 100644 index 07dee2f5..00000000 Binary files a/tools/ninja/ninja-mac and /dev/null differ diff --git a/tools/ninja/ninja-win.exe b/tools/ninja/ninja-win.exe deleted file mode 100644 index e4fafa04..00000000 Binary files a/tools/ninja/ninja-win.exe and /dev/null differ