Convert build scripts to Python #31

Merged
MartinFouilleul merged 24 commits from build-python into main 2023-08-08 09:38:44 +00:00
5 changed files with 185 additions and 30 deletions
Showing only changes of commit 76e007ee72 - Show all commits

View File

@ -3,7 +3,12 @@ import os
import platform import platform
import subprocess import subprocess
from utils import pushd, removeall, shellish import checksum
from log import *
from utils import pushd, removeall
ANGLE_VERSION = "2023-07-05"
def attach_build_runtime(subparsers): def attach_build_runtime(subparsers):
@ -13,24 +18,12 @@ def attach_build_runtime(subparsers):
def build_runtime(args): def build_runtime(args):
try: ensure_programs()
subprocess.run(["clang", "-v"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) ensure_angle()
except FileNotFoundError:
print("ERROR: clang was not found on your system.")
if platform.system() == "Windows":
print("We recommend installing clang via the Visual Studio installer.")
# TODO(ben): Link to the Visual Studio download page (I have no internet right now)
elif platform.system() == "Darwin":
print("Run the following to install it:")
print()
print(" brew install llvm")
print()
exit(1)
# TODO(ben): Check for xcode command line tools
build_milepost("lib", args.release) build_milepost("lib", args.release)
def build_milepost(target, release): def build_milepost(target, release):
print("Building milepost...") print("Building milepost...")
with pushd("milepost"): with pushd("milepost"):
@ -42,7 +35,8 @@ def build_milepost(target, release):
if platform.system() == "Darwin": if platform.system() == "Darwin":
build_milepost_lib_mac(release) build_milepost_lib_mac(release)
else: else:
print(f"ERROR: can't build milepost for unknown platform '{platform.system()}'") log_error(f"can't build milepost for unknown platform '{platform.system()}'")
exit(1)
elif target == "test": elif target == "test":
with pushd("examples/test_app"): with pushd("examples/test_app"):
# TODO? # TODO?
@ -50,9 +44,10 @@ def build_milepost(target, release):
elif target == "clean": elif target == "clean":
removeall("bin") removeall("bin")
else: else:
print(f"ERROR: unrecognized milepost target '{target}'") log_error(f"unrecognized milepost target '{target}'")
exit(1) exit(1)
def build_milepost_lib_mac(release): def build_milepost_lib_mac(release):
sdk_dir = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" sdk_dir = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
@ -123,3 +118,59 @@ def build_milepost_lib_mac(release):
"-id", "@rpath/libmilepost.dylib", "-id", "@rpath/libmilepost.dylib",
"bin/libmilepost.dylib", "bin/libmilepost.dylib",
], check=True) ], check=True)
def ensure_programs():
try:
subprocess.run(["clang", "-v"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except FileNotFoundError:
msg = log_error("clang was not found on your system.")
if platform.system() == "Windows":
msg.more("We recommend installing clang via the Visual Studio installer.")
# TODO(ben): Link to the Visual Studio download page (I have no internet right now)
elif platform.system() == "Darwin":
msg.more("Run the following to install it:")
msg.more()
msg.more(" brew install llvm")
msg.more()
exit(1)
# TODO(ben): Check for xcode command line tools
def ensure_angle():
checkfiles = None
if platform.system() == "Windows":
checkfiles = [
["libEGL-win", "milepost/lib/libEGL.dll"],
["libGLESv2-win", "milepost/lib/libGLESv2.dll"],
]
elif platform.system() == "Darwin":
# TODO(ben): Do we need specific builds of ANGLE for each macOS version?
if platform.machine() == "arm64":
checkfiles = [
["libEGL-mac-arm64", "milepost/lib/libEGL.dylib"],
["libGLESv2-mac-arm64", "milepost/lib/libGLESv2.dylib"],
]
else:
checkfiles = [
["libEGL-mac-x64", "milepost/lib/libEGL.dylib"],
["libGLESv2-mac-x64", "milepost/lib/libGLESv2.dylib"],
]
if checkfiles is None:
log_warning("could not verify if the correct version of ANGLE is present; the build will probably fail.")
return
angle_exists = True
for file in checkfiles:
key = file[0]
filepath = file[1]
if not os.path.isfile(filepath):
angle_exists = False
break
if not checksum.checkfile(key, filepath):
log_error("wrong version of ANGLE libraries installed")
exit(1)
if not angle_exists:
pass

30
scripts/checksum.py Normal file
View File

@ -0,0 +1,30 @@
import hashlib
import json
from log import *
def checkfile(key, filepath):
newsum = filesum(filepath)
sums = {}
with open("scripts/checksums.json", "r") as sumsfile:
sums = json.loads(sumsfile.read())
if key not in sums:
msg = log_warning(f"no checksum saved for {key}")
msg.more(f"file had checksum: {newsum}")
return False
sum = sums[key]
if sum != newsum:
msg = log_warning(f"checksums did not match for {filepath}:")
msg.more(f"expected: {sum}")
msg.more(f" got: {newsum}")
return False
return True
def filesum(filepath):
with open(filepath, "rb") as file:
return hashlib.sha256(file.read()).hexdigest()

6
scripts/checksums.json Normal file
View File

@ -0,0 +1,6 @@
{
"libEGL-win": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d",
"libGLESv2-win": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389",
"libEGL-mac-arm64": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592",
"libGLESv2-mac-arm64": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe"
}

80
scripts/log.py Normal file
View File

@ -0,0 +1,80 @@
import subprocess
import sys
errors = []
warnings = []
class Entry:
def __init__(self, msg):
self.msgs = [msg]
def more(self, *msgs):
if len(msgs) == 0:
msgs = [""]
for msg in msgs:
print(msg)
self.msgs.append(msg)
def log_error(msg):
msg = f"ERROR: {msg}"
print(msg)
entry = Entry(msg)
errors.append(entry)
return entry
def log_warning(msg):
msg = f"WARNING: {msg}"
print(msg)
entry = Entry(msg)
warnings.append(entry)
return entry
def log_finish():
if len(errors) + len(warnings) == 0:
print("Task completed successfully.")
return
print()
errors_str = "1 error" if len(errors) == 1 else f"{len(errors)} errors"
warnings_str = "1 warning" if len(warnings) == 1 else f"{len(warnings)} warnings"
if len(errors) > 0 and len(warnings) > 0:
print(f"Task failed with {errors_str} and {warnings_str}:")
for entry in warnings:
print("\n".join(entry.msgs))
for entry in errors:
print("\n".join(entry.msgs))
elif len(errors) > 0:
print(f"Task failed with {errors_str}:")
for entry in errors:
print("\n".join(entry.msgs))
elif len(warnings) > 0:
print(f"Task failed with {warnings_str}:")
for entry in warnings:
print("\n".join(entry.msgs))
def shellish(func):
def shellfunc(*args, **kwargs):
exitcode = 0
try:
func(*args, **kwargs)
except subprocess.CalledProcessError as err:
msg = log_error(f"The following command failed with code {err.returncode}:")
msg.more(" ".join(err.cmd))
exitcode = err.returncode
except SystemExit as err:
exitcode = err.code
except:
log_error(sys.exception())
exitcode = 1
finally:
log_finish()
exit(exitcode)
return shellfunc

View File

@ -18,15 +18,3 @@ def pushd(new_dir):
def removeall(dir): def removeall(dir):
[os.remove(f) for f in glob.iglob("{}/*".format(dir), recursive=True)] [os.remove(f) for f in glob.iglob("{}/*".format(dir), recursive=True)]
os.removedirs(dir) os.removedirs(dir)
def shellish(func):
def shellfunc(*args, **kwargs):
try:
func(*args, **kwargs)
except subprocess.CalledProcessError as err:
print()
print(f"ERROR (code {err.returncode}): The following command failed:")
print(" ".join(err.cmd))
exit(err.returncode)
return shellfunc