231 lines
7.5 KiB
Python
Executable File
231 lines
7.5 KiB
Python
Executable File
#!/usr/bin/python3
|
|
#
|
|
# This python script builds integration from scratch. That includes
|
|
# everything we need:
|
|
#
|
|
# - Generates BuildConfiguration.xml in integration repository
|
|
# - Generates BuildConfiguration.xml in UnrealEngine repository
|
|
# - Hardwires paths into Source/Integration/lpx-paths.hpp
|
|
# - Generates Integration.uproject
|
|
# - Generates Integration.code-workspace
|
|
# - Applies patch to Unreal Engine source.
|
|
# - Runs Setup.sh in the UnrealEngine repository
|
|
# - Builds luprex
|
|
# - Builds ShaderCompileWorker
|
|
# - Builds Unreal Engine and Unreal Editor
|
|
# - Builds integration
|
|
#
|
|
# Once this is all done, everything is ready to go. It is now possible
|
|
# to start up the IDE and run luprex in the debugger.
|
|
#
|
|
# If you edit the code, you can run this python script again to
|
|
# rebuild. It is always safe to use this script to rebuild after
|
|
# editing anything.
|
|
#
|
|
# However, if you only edited C++ code and Unreal Build.cs files, then
|
|
# it may be quicker and more convenient to rebuild from inside the
|
|
# VSCODE IDE. Bear in mind that doing so only works if you only edited
|
|
# the C++ code and the blueprint code. If you edited anything else, you
|
|
# should rerun this python script.
|
|
#
|
|
|
|
import sys, os, json, shutil, subprocess, re, time
|
|
from pathlib import Path
|
|
|
|
#
|
|
# Build the config table: a set of global constants that affect
|
|
# just about everything. These values become global variables
|
|
# in this script, they are also used as variables when expanding
|
|
# template files.
|
|
#
|
|
|
|
CONFIG = {}
|
|
|
|
if sys.platform == "windows":
|
|
CONFIG["OS"] = "Windows"
|
|
CONFIG["DLL"] = "dll"
|
|
CONFIG["BAT"] = "bat"
|
|
CONFIG["DOT_EXE"] = ".exe"
|
|
CONFIG["USER"] = "Unknown"
|
|
CONFIG["BUILD_BAT"] = "Build.bat"
|
|
else:
|
|
CONFIG["OS"] = "Linux"
|
|
CONFIG["DLL"] = "so"
|
|
CONFIG["BAT"] = "sh"
|
|
CONFIG["DOT_EXE"] = ""
|
|
CONFIG["USER"] = os.environ["USER"]
|
|
CONFIG["BUILD_BAT"] = "Linux/Build.sh"
|
|
|
|
CONFIG["INTEGRATION"] = os.path.dirname(os.path.abspath(sys.argv[0]))
|
|
CONFIG["UNREALENGINE"] = os.path.join(os.path.dirname(CONFIG["INTEGRATION"]), "UnrealEngine")
|
|
CONFIG["UE_BUILD_BAT"] = CONFIG["UNREALENGINE"] + "/Engine/Build/BatchFiles/" + CONFIG["BUILD_BAT"] + " -waitmutex"
|
|
|
|
globals().update(CONFIG)
|
|
|
|
#
|
|
# Sanity check the INTEGRATION and UNREALENGINE paths.
|
|
#
|
|
|
|
if not os.path.isdir(f"{INTEGRATION}/Source/Integration"):
|
|
sys.exit(f"Integration repository is not valid: {INTEGRATION}")
|
|
if not os.path.isdir(f"{UNREALENGINE}/Engine/Source/Editor"):
|
|
sys.exit(f"Integration repository is not valid: {UNREALENGINE}")
|
|
|
|
#
|
|
# This is the code for a simple json preprocessor that can
|
|
# expand "for-each" loops and substitute variables.
|
|
#
|
|
|
|
JSON_VAR_REGEX = re.compile(r'\[([A-Z0-9_]+)\]')
|
|
|
|
def expand_json(data, vars):
|
|
if isinstance(data, dict):
|
|
if "for-each" in data and "body" in data:
|
|
body = data["body"]
|
|
foreach = data["for-each"]
|
|
return [ expand_json(body, vars | lvars) for lvars in foreach ]
|
|
else:
|
|
return { key: expand_json(value, vars) for key, value in data.items() }
|
|
elif isinstance(data, list):
|
|
return [ expand_json(item, vars) for item in data ]
|
|
elif isinstance(data, str):
|
|
return JSON_VAR_REGEX.sub(lambda m: str(vars.get(m.group(1), m.group(0))), data)
|
|
else:
|
|
return data
|
|
|
|
#
|
|
# Apply the json expander to a file on disk: read the source file,
|
|
# apply the expander, write the result back out to disk.
|
|
#
|
|
|
|
def expand_json_file(sourcefile, outputfile):
|
|
Path(outputfile).unlink(missing_ok=True)
|
|
data = json.loads(Path(sourcefile).read_text())
|
|
expanded = expand_json(data, CONFIG)
|
|
Path(outputfile).write_text(json.dumps(expanded, indent=4))
|
|
|
|
#
|
|
# Because a single string is valid json, we can also use the json
|
|
# expander to substitute variables in plain old text files.
|
|
#
|
|
|
|
def expand_text_file(sourcefile, outputfile):
|
|
Path(outputfile).unlink(missing_ok=True)
|
|
data = Path(sourcefile).read_text()
|
|
expanded = expand_json(data, CONFIG)
|
|
Path(outputfile).write_text(expanded)
|
|
|
|
#
|
|
# A simplified interface to subprocess.run
|
|
#
|
|
|
|
def shell(dir, cmd):
|
|
start = time.time()
|
|
subprocess.run(cmd, shell=True, check=True, cwd=dir)
|
|
elapsed = time.time() - start
|
|
if elapsed > 0.2:
|
|
print("")
|
|
print("TIMING: ", elapsed, " CMD:", cmd)
|
|
print("")
|
|
|
|
#
|
|
# Change directory to an arbitrary subdirectory. Doing this enforces
|
|
# the rule that we specify absolute paths for everything.
|
|
#
|
|
|
|
os.chdir(f"{INTEGRATION}/EnginePatches")
|
|
|
|
#
|
|
# Write BuildConfiguration.xml
|
|
#
|
|
|
|
BUILDCONFIG=Path(f"{INTEGRATION}/EnginePatches/BuildConfiguration{OS}.xml").read_text()
|
|
|
|
Path(f"{INTEGRATION}/Saved/UnrealBuildTool").mkdir(parents=True, exist_ok=True)
|
|
Path(f"{UNREALENGINE}/Engine/Saved/UnrealBuildTool").mkdir(parents=True, exist_ok=True)
|
|
|
|
Path(f"{INTEGRATION}/Saved/UnrealBuildTool/BuildConfiguration.xml").unlink(missing_ok=True)
|
|
Path(f"{UNREALENGINE}/Engine/Saved/UnrealBuildTool/BuildConfiguration.xml").unlink(missing_ok=True)
|
|
|
|
Path(f"{INTEGRATION}/Saved/UnrealBuildTool/BuildConfiguration.xml").write_text(BUILDCONFIG)
|
|
Path(f"{UNREALENGINE}/Engine/Saved/UnrealBuildTool/BuildConfiguration.xml").write_text(BUILDCONFIG)
|
|
|
|
#
|
|
# Write lpx-paths.hpp.
|
|
#
|
|
|
|
Path(f"{INTEGRATION}/Source/Integration/lpx-paths.hpp").unlink(missing_ok=True)
|
|
Path(f"{INTEGRATION}/Source/Integration/lpx-paths.hpp").write_text(f"""
|
|
#define LUPREX_DLL_PATH "{INTEGRATION}/luprex/build/{OS}/luprexlib.{DLL}"
|
|
#define LUPREX_ROOT_PATH "{INTEGRATION}/luprex"
|
|
""")
|
|
|
|
#
|
|
# Apply patch to the unreal engine source. Check out HEAD version of
|
|
# affected sourcefiles before applying patch.
|
|
#
|
|
|
|
print("Applying patch to Unreal Engine...")
|
|
PATCH_LINES = Path(f"{INTEGRATION}/EnginePatches/EnginePatch").read_text().splitlines()
|
|
PATCHED_FILES = [line[6:] for line in PATCH_LINES if line.startswith("--- a/")]
|
|
for file in PATCHED_FILES:
|
|
shell(UNREALENGINE, f"git show HEAD:{file} > {file}")
|
|
shell(UNREALENGINE, f"git apply {INTEGRATION}/EnginePatches/EnginePatch")
|
|
|
|
#
|
|
# Write Integration.uproject.
|
|
#
|
|
|
|
expand_json_file(f"{INTEGRATION}/Integration.uproject.tpl.json",
|
|
f"{INTEGRATION}/Integration.uproject")
|
|
|
|
#
|
|
# Run Setup.sh in UNREALENGINE
|
|
#
|
|
|
|
shell(UNREALENGINE, f"{UNREALENGINE}/Setup.{BAT}")
|
|
|
|
#
|
|
# Use UnrealBuildTool to generate Integration.code-workspace.ubt
|
|
#
|
|
# We're not going to use it, but we keep it as a reference that you can
|
|
# use when editing Integration.code-workspace.tpl.json.
|
|
#
|
|
|
|
Path(f"{INTEGRATION}/Integration.code-workspace").unlink(missing_ok=True)
|
|
Path(f"{INTEGRATION}/Integration.code-workspace.ubt").unlink(missing_ok=True)
|
|
shell(INTEGRATION, f'{UNREALENGINE}/GenerateProjectFiles.{BAT} -projectfiles -project="{INTEGRATION}/Integration.uproject" -game')
|
|
Path(f"{INTEGRATION}/Integration.code-workspace").rename(f"{INTEGRATION}/Integration.code-workspace.ubt")
|
|
|
|
#
|
|
# Build Integration.code-workspace from Integration.code-workspace.tpl.json.
|
|
#
|
|
|
|
expand_json_file(f"{INTEGRATION}/Integration.code-workspace.tpl.json",
|
|
f"{INTEGRATION}/Integration.code-workspace")
|
|
|
|
#
|
|
# Create Makefile from Makefile.tpl.txt
|
|
#
|
|
|
|
expand_text_file(f"{INTEGRATION}/Makefile.tpl.txt",
|
|
f"{INTEGRATION}/Makefile")
|
|
|
|
#
|
|
# Build ShaderCompileWorker
|
|
#
|
|
|
|
print("Building ShaderCompileWorker...")
|
|
|
|
shell(UNREALENGINE, f"{UNREALENGINE}/Engine/Build/BatchFiles/{BUILD_BAT} -waitmutex ShaderCompileWorker {OS} Shipping")
|
|
|
|
Path(f"Engine/Binaries/{OS}/ShaderCompileWorker{DOT_EXE}").unlink(missing_ok=True)
|
|
shutil.copyfile(f"{UNREALENGINE}/Engine/Binaries/{OS}/ShaderCompileWorker-{OS}-Shipping{DOT_EXE}", f"{UNREALENGINE}/Engine/Binaries/{OS}/ShaderCompileWorker{DOT_EXE}")
|
|
|
|
#
|
|
# Run Make
|
|
#
|
|
|
|
shell(INTEGRATION, 'make intellisense')
|
|
|