From e12afb619f3845e64a4daeb8a5088b348ee3afc7 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 7 Jul 2023 11:25:49 -0500 Subject: [PATCH 01/23] Get milepost mac build working in Python --- .gitignore | 3 + scripts/build_runtime.py | 125 +++++++++++++++++++++++++++++++++++++++ scripts/orca.py | 13 ++++ scripts/utils.py | 32 ++++++++++ 4 files changed, 173 insertions(+) create mode 100644 scripts/build_runtime.py create mode 100755 scripts/orca.py create mode 100644 scripts/utils.py diff --git a/.gitignore b/.gitignore index 695d9d9..23ada4b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,7 @@ sdk/io_stubs.c sdk/orca_surface.c *bind_gen.c +.vscode/launch.json .vscode/settings.json + +__pycache__ diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py new file mode 100644 index 0000000..e9b48f4 --- /dev/null +++ b/scripts/build_runtime.py @@ -0,0 +1,125 @@ +import argparse +import os +import platform +import subprocess + +from utils import pushd, removeall, shellish + + +def attach_build_runtime(subparsers): + build = subparsers.add_parser("build-runtime", help="TODO") + build.add_argument("--release", action="store_true", help="compile Orca in release mode (default is debug)") + build.set_defaults(func=shellish(build_runtime)) + + +def build_runtime(args): + try: + subprocess.run(["clang", "-v"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + 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) + +def build_milepost(target, release): + print("Building milepost...") + with pushd("milepost"): + os.makedirs("bin", exist_ok=True) + os.makedirs("lib", exist_ok=True) + os.makedirs("resources", exist_ok=True) + + if target == "lib": + if platform.system() == "Darwin": + build_milepost_lib_mac(release) + else: + print(f"ERROR: can't build milepost for unknown platform '{platform.system()}'") + elif target == "test": + with pushd("examples/test_app"): + # TODO? + subprocess.run(["./build.sh"]) + elif target == "clean": + removeall("bin") + else: + print(f"ERROR: unrecognized milepost target '{target}'") + exit(1) + +def build_milepost_lib_mac(release): + sdk_dir = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" + + flags = ["-mmacos-version-min=10.15.4", "-maes"] + cflags = ["-std=c11"] + debug_flags = ["-O3"] if release else ["-g", "-DDEBUG", "-DLOG_COMPILE_DEBUG"] + ldflags = [f"-L{sdk_dir}/usr/lib", f"-F{sdk_dir}/System/Library/Frameworks/"] + includes = ["-Isrc", "-Isrc/util", "-Isrc/platform", "-Iext", "-Iext/angle_headers"] + + # compile metal shader + subprocess.run([ + "xcrun", "-sdk", "macosx", "metal", + # TODO: shaderFlagParam + "-fno-fast-math", "-c", + "-o", "lib/mtl_renderer.air", + "src/mtl_renderer.metal", + ], check=True) + subprocess.run([ + "xcrun", "-sdk", "macosx", "metallib", + "-o", "lib/mtl_renderer.metallib", + "lib/mtl_renderer.air", + ], check=True) + + # compile milepost. We use one compilation unit for all C code, and one + # compilation unit for all Objective-C code + subprocess.run([ + "clang", + *debug_flags, "-c", + "-o", "bin/milepost_c.o", + *cflags, *flags, *includes, + "src/milepost.c" + ], check=True) + subprocess.run([ + "clang", + *debug_flags, "-c", + "-o", "bin/milepost_objc.o", + *flags, *includes, + "src/milepost.m" + ], check=True) + + # build dynamic library + subprocess.run([ + "ld", + *ldflags, "-dylib", + "-o", "bin/libmilepost.dylib", + "bin/milepost_c.o", "bin/milepost_objc.o", + "-Llib", "-lc", + "-framework", "Carbon", "-framework", "Cocoa", "-framework", "Metal", "-framework", "QuartzCore", + "-weak-lEGL", "-weak-lGLESv2", + ], check=True) + + # change dependent libs path to @rpath + subprocess.run([ + "install_name_tool", + "-change", "./libEGL.dylib", "@rpath/libEGL.dylib", + "bin/libmilepost.dylib", + ], check=True) + subprocess.run([ + "install_name_tool", + "-change", "./libGLESv2.dylib", "@rpath/libGLESv2.dylib", + "bin/libmilepost.dylib", + ], check=True) + + # add executable path to rpath. Client executable can still add its own + # rpaths if needed, e.g. @executable_path/libs/ etc. + subprocess.run([ + "install_name_tool", + "-id", "@rpath/libmilepost.dylib", + "bin/libmilepost.dylib", + ], check=True) diff --git a/scripts/orca.py b/scripts/orca.py new file mode 100755 index 0000000..5b9c3b4 --- /dev/null +++ b/scripts/orca.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +import argparse + +from build_runtime import attach_build_runtime + +parser = argparse.ArgumentParser() + +subparsers = parser.add_subparsers(required=True, title='commands') +attach_build_runtime(subparsers) + +args = parser.parse_args() +args.func(args) diff --git a/scripts/utils.py b/scripts/utils.py new file mode 100644 index 0000000..d8ef8d8 --- /dev/null +++ b/scripts/utils.py @@ -0,0 +1,32 @@ +import glob +import os +import subprocess +import traceback + +from contextlib import contextmanager + +@contextmanager +def pushd(new_dir): + previous_dir = os.getcwd() + os.chdir(new_dir) + try: + yield + finally: + os.chdir(previous_dir) + + +def removeall(dir): + [os.remove(f) for f in glob.iglob("{}/*".format(dir), recursive=True)] + 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 -- 2.25.1 From 76e007ee72f174af364d51e80b3de21062a41872 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 7 Jul 2023 18:22:13 -0500 Subject: [PATCH 02/23] Add checksums for ANGLE and a logging system --- scripts/build_runtime.py | 87 +++++++++++++++++++++++++++++++--------- scripts/checksum.py | 30 ++++++++++++++ scripts/checksums.json | 6 +++ scripts/log.py | 80 ++++++++++++++++++++++++++++++++++++ scripts/utils.py | 12 ------ 5 files changed, 185 insertions(+), 30 deletions(-) create mode 100644 scripts/checksum.py create mode 100644 scripts/checksums.json create mode 100644 scripts/log.py diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index e9b48f4..64c6012 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -3,7 +3,12 @@ import os import platform 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): @@ -13,24 +18,12 @@ def attach_build_runtime(subparsers): def build_runtime(args): - try: - subprocess.run(["clang", "-v"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - 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 + ensure_programs() + ensure_angle() build_milepost("lib", args.release) + def build_milepost(target, release): print("Building milepost...") with pushd("milepost"): @@ -42,7 +35,8 @@ def build_milepost(target, release): if platform.system() == "Darwin": build_milepost_lib_mac(release) 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": with pushd("examples/test_app"): # TODO? @@ -50,9 +44,10 @@ def build_milepost(target, release): elif target == "clean": removeall("bin") else: - print(f"ERROR: unrecognized milepost target '{target}'") + log_error(f"unrecognized milepost target '{target}'") exit(1) + def build_milepost_lib_mac(release): sdk_dir = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" @@ -123,3 +118,59 @@ def build_milepost_lib_mac(release): "-id", "@rpath/libmilepost.dylib", "bin/libmilepost.dylib", ], 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 diff --git a/scripts/checksum.py b/scripts/checksum.py new file mode 100644 index 0000000..226fbc8 --- /dev/null +++ b/scripts/checksum.py @@ -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() diff --git a/scripts/checksums.json b/scripts/checksums.json new file mode 100644 index 0000000..1c2126f --- /dev/null +++ b/scripts/checksums.json @@ -0,0 +1,6 @@ +{ + "libEGL-win": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d", + "libGLESv2-win": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389", + "libEGL-mac-arm64": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", + "libGLESv2-mac-arm64": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" +} diff --git a/scripts/log.py b/scripts/log.py new file mode 100644 index 0000000..1c28dbd --- /dev/null +++ b/scripts/log.py @@ -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 diff --git a/scripts/utils.py b/scripts/utils.py index d8ef8d8..72483dc 100644 --- a/scripts/utils.py +++ b/scripts/utils.py @@ -18,15 +18,3 @@ def pushd(new_dir): def removeall(dir): [os.remove(f) for f in glob.iglob("{}/*".format(dir), recursive=True)] 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 -- 2.25.1 From fbba6330e9953158f04257da66234c4f5c547891 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 8 Jul 2023 09:22:29 -0500 Subject: [PATCH 03/23] Add automatic ANGLE downloads --- .gitignore | 1 + scripts/build_runtime.py | 42 +++++++++++++++++++++++++++++++++++++++- scripts/checksums.json | 6 ++++-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 23ada4b..25d7d9c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ sdk/orca_surface.c .vscode/settings.json __pycache__ +scripts/files diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 64c6012..f1fd1fb 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -1,7 +1,11 @@ import argparse +import glob import os import platform +import urllib.request +import shutil import subprocess +from zipfile import ZipFile import checksum from log import * @@ -173,4 +177,40 @@ def ensure_angle(): exit(1) if not angle_exists: - pass + download_angle() + + +def download_angle(): + print("Downloading ANGLE...") + if platform.system() == "Windows": + build = "win" + checksumkey = "angle.zip-win" + extension = "dll" + elif platform.system() == "Darwin": + extension = "dylib" + build = "macos-12" + checksumkey = "angle.zip-mac" + + # TODO(ben): make universal dylibs + if platform.machine() == "arm64": + log_error(f"automated ANGLE builds are not yet available for Apple silicon") + return + else: + log_error(f"could not automatically download ANGLE for unknown platform {platform.system()}") + return + + url = f"https://github.com/HandmadeNetwork/build-angle/releases/download/{ANGLE_VERSION}/angle-{build}-{ANGLE_VERSION}.zip" + with urllib.request.urlopen(url) as response: + os.makedirs("scripts/files", exist_ok=True) + with open("scripts/files/angle.zip", "wb") as out: + shutil.copyfileobj(response, out) + + if not checksum.checkfile(checksumkey, "scripts/files/angle.zip"): + log_error(f"ANGLE download did not match checksum") + exit(1) + + with ZipFile("scripts/files/angle.zip", "r") as anglezip: + anglezip.extractall(path="scripts/files") + + for filepath in glob.glob(f"scripts/files/angle/bin/*.{extension}"): + shutil.copy(filepath, "milepost/lib") diff --git a/scripts/checksums.json b/scripts/checksums.json index 1c2126f..d3289bf 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,6 +1,8 @@ { + "angle.zip-win": "pizza", + "angle.zip-mac-x64": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", "libEGL-win": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d", "libGLESv2-win": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389", - "libEGL-mac-arm64": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", - "libGLESv2-mac-arm64": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" + "libEGL-mac": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", + "libGLESv2-mac": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" } -- 2.25.1 From 92529ba7c1cc053e989602b6272ec7caa1e8a1ae Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 8 Jul 2023 17:21:01 -0500 Subject: [PATCH 04/23] Add Windows stuff (untested) --- scripts/build_runtime.py | 142 +++++++++++++++++++++++++++++++-------- scripts/checksum.py | 8 +-- scripts/checksums.json | 12 ++-- scripts/log.py | 13 ++-- 4 files changed, 131 insertions(+), 44 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index f1fd1fb..24d4b88 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -1,4 +1,5 @@ import argparse +from datetime import datetime import glob import os import platform @@ -36,7 +37,9 @@ def build_milepost(target, release): os.makedirs("resources", exist_ok=True) if target == "lib": - if platform.system() == "Darwin": + if platform.system() == "Windows": + build_milepost_lib_win(release) + elif platform.system() == "Darwin": build_milepost_lib_mac(release) else: log_error(f"can't build milepost for unknown platform '{platform.system()}'") @@ -52,6 +55,60 @@ def build_milepost(target, release): exit(1) +def build_milepost_lib_win(release): + # TODO(ben): delete embed_text.py + embed_text_glsl("src\\glsl_shaders.h", "glsl_", [ + "src\\glsl_shaders\\common.glsl", + "src\\glsl_shaders\\blit_vertex.glsl", + "src\\glsl_shaders\\blit_fragment.glsl", + "src\\glsl_shaders\\path_setup.glsl", + "src\\glsl_shaders\\segment_setup.glsl", + "src\\glsl_shaders\\backprop.glsl", + "src\\glsl_shaders\\merge.glsl", + "src\\glsl_shaders\\raster.glsl", + ]) + + includes = [ + "/I", "src", + "/I", "src/util", + "/I", "src/platform", + "/I", "ext", + "/I", "ext/angle_headers", + ] + libs = [ + "user32.lib", + "opengl32.lib", + "gdi32.lib", + "shcore.lib", + "delayimp.lib", + "dwmapi.lib", + "comctl32.lib", + "ole32.lib", + "shell32.lib", + "shlwapi.lib", + "/LIBPATH:./bin", + "libEGL.dll.lib", + "libGLESv2.dll.lib", + "/DELAYLOAD:libEGL.dll", + "/DELAYLOAD:libGLESv2.dll", + ] + + # TODO(ben): check for cl + subprocess.run([ + "cl", + "/we4013", "/Zi", "/Zc:preprocessor", + "/DMP_BUILD_DLL", + "/std:c11", + *includes, + "src/milepost.c", "/Fo:bin/milepost.o", + "/LD", "/link", + "/MANIFEST:EMBED", "/MANIFESTINPUT:src/win32_manifest.xml", + *libs, + "/OUT:bin/milepost.dll", + "/IMPLIB:bin/milepost.dll.lib", + ], check=True) + + def build_milepost_lib_mac(release): sdk_dir = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" @@ -145,21 +202,17 @@ def ensure_angle(): checkfiles = None if platform.system() == "Windows": checkfiles = [ - ["libEGL-win", "milepost/lib/libEGL.dll"], - ["libGLESv2-win", "milepost/lib/libGLESv2.dll"], + "milepost/lib/libEGL.dll", + "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"], - ] + log_warning(f"automated ANGLE builds are not yet available for Apple silicon") + return + checkfiles = [ + "milepost/lib/libEGL.dylib", + "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.") @@ -173,8 +226,9 @@ def ensure_angle(): angle_exists = False break if not checksum.checkfile(key, filepath): - log_error("wrong version of ANGLE libraries installed") - exit(1) + angle_exists = False + log_warning("wrong version of ANGLE libraries installed") + break if not angle_exists: download_angle() @@ -184,33 +238,65 @@ def download_angle(): print("Downloading ANGLE...") if platform.system() == "Windows": build = "win" - checksumkey = "angle.zip-win" extension = "dll" elif platform.system() == "Darwin": - extension = "dylib" - build = "macos-12" - checksumkey = "angle.zip-mac" - # TODO(ben): make universal dylibs - if platform.machine() == "arm64": - log_error(f"automated ANGLE builds are not yet available for Apple silicon") - return + build = "macos-12" + extension = "dylib" else: log_error(f"could not automatically download ANGLE for unknown platform {platform.system()}") return - url = f"https://github.com/HandmadeNetwork/build-angle/releases/download/{ANGLE_VERSION}/angle-{build}-{ANGLE_VERSION}.zip" + os.makedirs("scripts/files", exist_ok=True) + filename = f"angle-{build}-{ANGLE_VERSION}.zip" + filepath = f"scripts/files/{filename}" + url = f"https://github.com/HandmadeNetwork/build-angle/releases/download/{ANGLE_VERSION}/{filename}" with urllib.request.urlopen(url) as response: - os.makedirs("scripts/files", exist_ok=True) - with open("scripts/files/angle.zip", "wb") as out: + with open(filepath, "wb") as out: shutil.copyfileobj(response, out) - if not checksum.checkfile(checksumkey, "scripts/files/angle.zip"): + if not checksum.checkfile(filepath): log_error(f"ANGLE download did not match checksum") exit(1) - with ZipFile("scripts/files/angle.zip", "r") as anglezip: + with ZipFile(filepath, "r") as anglezip: anglezip.extractall(path="scripts/files") for filepath in glob.glob(f"scripts/files/angle/bin/*.{extension}"): shutil.copy(filepath, "milepost/lib") + + +def embed_text_glsl(outputpath, prefix, shaders): + output = open(outputpath, "w") + output.write("/*********************************************************************\n") + output.write("*\n") + output.write("*\tfile: %s\n" % os.path.basename(outputpath)) + output.write("*\tnote: string literals auto-generated by build_runtime.py\n") + output.write("*\tdate: %s\n" % datetime.now().strftime("%d/%m%Y")) + output.write("*\n") + output.write("**********************************************************************/\n") + + outSymbol = (os.path.splitext(os.path.basename(outputpath))[0]).upper() + + output.write("#ifndef __%s_H__\n" % outSymbol) + output.write("#define __%s_H__\n" % outSymbol) + output.write("\n\n") + + for fileName in shaders: + f = open(fileName, "r") + lines = f.read().splitlines() + + output.write("//NOTE: string imported from %s\n" % fileName) + + stringName = os.path.splitext(os.path.basename(fileName))[0] + output.write(f"const char* {prefix}{stringName} = ") + + for line in lines: + output.write("\n\"%s\\n\"" % line) + + output.write(";\n\n") + f.close() + + output.write("#endif // __%s_H__\n" % outSymbol) + + output.close() diff --git a/scripts/checksum.py b/scripts/checksum.py index 226fbc8..e404081 100644 --- a/scripts/checksum.py +++ b/scripts/checksum.py @@ -4,17 +4,17 @@ import json from log import * -def checkfile(key, filepath): +def checkfile(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}") + if filepath not in sums: + msg = log_warning(f"no checksum saved for file {filepath}") msg.more(f"file had checksum: {newsum}") return False - sum = sums[key] + sum = sums[filepath] if sum != newsum: msg = log_warning(f"checksums did not match for {filepath}:") diff --git a/scripts/checksums.json b/scripts/checksums.json index d3289bf..d68ec7b 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,8 +1,8 @@ { - "angle.zip-win": "pizza", - "angle.zip-mac-x64": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", - "libEGL-win": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d", - "libGLESv2-win": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389", - "libEGL-mac": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", - "libGLESv2-mac": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" + "scripts/files/angle-win-2023-07-05": "pizza", + "scripts/files/angle-mac-2023-07-05": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", + "milepost/lib/libEGL.dll": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d", + "milepost/lib/libGLESv2.dll": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389", + "milepost/lib/libEGL.dylib": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", + "milepost/lib/libGLESv2.dylib": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" } diff --git a/scripts/log.py b/scripts/log.py index 1c28dbd..3cb7911 100644 --- a/scripts/log.py +++ b/scripts/log.py @@ -34,28 +34,29 @@ def log_warning(msg): return entry -def log_finish(): - if len(errors) + len(warnings) == 0: +def log_finish(success): + if success and len(errors) + len(warnings) == 0: print("Task completed successfully.") return print() + result_str = "succeeded" if success else "failed" 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}:") + print(f"Task {result_str} 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}:") + print(f"Task {result_str} with {errors_str}:") for entry in errors: print("\n".join(entry.msgs)) elif len(warnings) > 0: - print(f"Task failed with {warnings_str}:") + print(f"Task {result_str} with {warnings_str}:") for entry in warnings: print("\n".join(entry.msgs)) @@ -75,6 +76,6 @@ def shellish(func): log_error(sys.exception()) exitcode = 1 finally: - log_finish() + log_finish(exitcode == 0) exit(exitcode) return shellfunc -- 2.25.1 From d97e69992bd33be49549ca50f0db2660c18fb959 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 8 Jul 2023 17:50:01 -0500 Subject: [PATCH 05/23] Preemptively fix a checksum problem I hope --- scripts/checksums.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/checksums.json b/scripts/checksums.json index d68ec7b..abdfe0e 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,6 +1,6 @@ { - "scripts/files/angle-win-2023-07-05": "pizza", - "scripts/files/angle-mac-2023-07-05": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", + "scripts/files/angle-win-2023-07-05.zip": "pizza", + "scripts/files/angle-mac-2023-07-05.zip": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", "milepost/lib/libEGL.dll": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d", "milepost/lib/libGLESv2.dll": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389", "milepost/lib/libEGL.dylib": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", -- 2.25.1 From 25782ccc7713d5ee0e63cd860980964e700df1c6 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 15 Jul 2023 16:23:05 -0500 Subject: [PATCH 06/23] Fix some build issues on Windows --- scripts/build_runtime.py | 25 +++++++++++++++++-------- scripts/checksums.json | 6 +++--- scripts/log.py | 8 ++++++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 24d4b88..8a676bd 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -13,7 +13,7 @@ from log import * from utils import pushd, removeall -ANGLE_VERSION = "2023-07-05" +ANGLE_VERSION = "2023-07-09" def attach_build_runtime(subparsers): @@ -93,7 +93,6 @@ def build_milepost_lib_win(release): "/DELAYLOAD:libGLESv2.dll", ] - # TODO(ben): check for cl subprocess.run([ "cl", "/we4013", "/Zi", "/Zc:preprocessor", @@ -182,13 +181,22 @@ def build_milepost_lib_mac(release): def ensure_programs(): + if platform.system() == "Windows": + try: + subprocess.run(["cl"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + except FileNotFoundError: + msg = log_error("MSVC was not found on your system.") + msg.more("If you have already installed Visual Studio, make sure you are running in a") + msg.more("Visual Studio command prompt or you have run vcvarsall.bat. Otherwise, download") + msg.more("and install Visual Studio: https://visualstudio.microsoft.com/") + exit(1) + 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() @@ -220,12 +228,11 @@ def ensure_angle(): angle_exists = True for file in checkfiles: - key = file[0] - filepath = file[1] - if not os.path.isfile(filepath): + if not os.path.isfile(file): + print(f"Required ANGLE file {file} not found.") angle_exists = False break - if not checksum.checkfile(key, filepath): + if not checksum.checkfile(file): angle_exists = False log_warning("wrong version of ANGLE libraries installed") break @@ -237,7 +244,7 @@ def ensure_angle(): def download_angle(): print("Downloading ANGLE...") if platform.system() == "Windows": - build = "win" + build = "windows-2019" extension = "dll" elif platform.system() == "Darwin": # TODO(ben): make universal dylibs @@ -259,10 +266,12 @@ def download_angle(): log_error(f"ANGLE download did not match checksum") exit(1) + print("Extracting ANGLE...") with ZipFile(filepath, "r") as anglezip: anglezip.extractall(path="scripts/files") for filepath in glob.glob(f"scripts/files/angle/bin/*.{extension}"): + os.makedirs("milepost/lib", exist_ok=True) shutil.copy(filepath, "milepost/lib") diff --git a/scripts/checksums.json b/scripts/checksums.json index abdfe0e..aa3ca26 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,8 +1,8 @@ { - "scripts/files/angle-win-2023-07-05.zip": "pizza", + "scripts/files/angle-windows-2019-2023-07-09.zip": "f58ee3ba5bbc4a6aec08c1c3ef3b9ac7b991676862c641a9bff27b6cdc5519e4", "scripts/files/angle-mac-2023-07-05.zip": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", - "milepost/lib/libEGL.dll": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d", - "milepost/lib/libGLESv2.dll": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389", + "milepost/lib/libEGL.dll": "5ed4d609ea11015473c89d3b5da91e831a0a8d9608608f840a77d49ccef6867a", + "milepost/lib/libGLESv2.dll": "f36811acdbc59f6cddd33f6a96b5d6e75559af76bdd73bcc56514455e9bffd16", "milepost/lib/libEGL.dylib": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", "milepost/lib/libGLESv2.dylib": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" } diff --git a/scripts/log.py b/scripts/log.py index 3cb7911..83d80e7 100644 --- a/scripts/log.py +++ b/scripts/log.py @@ -1,5 +1,5 @@ +import traceback import subprocess -import sys errors = [] @@ -72,8 +72,12 @@ def shellish(func): exitcode = err.returncode except SystemExit as err: exitcode = err.code + except Exception as err: + log_error(err) + print(traceback.format_exc()) + exitcode = 1 except: - log_error(sys.exception()) + print("something went REALLY wrong and also Ben does not know how to handle Python errors") exitcode = 1 finally: log_finish(exitcode == 0) -- 2.25.1 From 4337b9bffaa1869af20157a8a3dbeaef404ac432 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 15 Jul 2023 18:39:44 -0500 Subject: [PATCH 07/23] Copy .lib files on Windows --- scripts/build_runtime.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 8a676bd..754e03e 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -211,7 +211,9 @@ def ensure_angle(): if platform.system() == "Windows": checkfiles = [ "milepost/lib/libEGL.dll", + "milepost/lib/libEGL.dll.lib", "milepost/lib/libGLESv2.dll", + "milepost/lib/libGLESv2.dll.lib", ] elif platform.system() == "Darwin": if platform.machine() == "arm64": @@ -245,11 +247,11 @@ def download_angle(): print("Downloading ANGLE...") if platform.system() == "Windows": build = "windows-2019" - extension = "dll" + extensions = ["dll", "lib"] elif platform.system() == "Darwin": # TODO(ben): make universal dylibs build = "macos-12" - extension = "dylib" + extensions = ["dylib"] else: log_error(f"could not automatically download ANGLE for unknown platform {platform.system()}") return @@ -270,9 +272,11 @@ def download_angle(): with ZipFile(filepath, "r") as anglezip: anglezip.extractall(path="scripts/files") - for filepath in glob.glob(f"scripts/files/angle/bin/*.{extension}"): - os.makedirs("milepost/lib", exist_ok=True) - shutil.copy(filepath, "milepost/lib") + os.makedirs("milepost/lib", exist_ok=True) + for angleDir in ["bin", "lib"]: + for ext in extensions: + for filepath in glob.glob(f"scripts/files/angle/{angleDir}/*.{ext}"): + shutil.copy(filepath, "milepost/lib") def embed_text_glsl(outputpath, prefix, shaders): -- 2.25.1 From b398b74ac9fdaa61690df3383d7d0f6ab20bc5a1 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 15 Jul 2023 19:00:34 -0500 Subject: [PATCH 08/23] Go back to ANGLE 2023-07-05 and fix some checksum bugs --- scripts/build_runtime.py | 30 ++++++++++++++++++------------ scripts/checksums.json | 8 +++++--- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 754e03e..e832187 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -13,7 +13,7 @@ from log import * from utils import pushd, removeall -ANGLE_VERSION = "2023-07-09" +ANGLE_VERSION = "2023-07-05" def attach_build_runtime(subparsers): @@ -207,6 +207,15 @@ def ensure_programs(): def ensure_angle(): + if not verify_angle(): + download_angle() + print("Verifying ANGLE download...") + if not verify_angle(): + log_error("automatic ANGLE download failed") + exit(1) + + +def verify_angle(): checkfiles = None if platform.system() == "Windows": checkfiles = [ @@ -225,22 +234,19 @@ def ensure_angle(): ] if checkfiles is None: - log_warning("could not verify if the correct version of ANGLE is present; the build will probably fail.") - return + log_warning("could not verify if the correct version of ANGLE is present") + return False - angle_exists = True + ok = True for file in checkfiles: if not os.path.isfile(file): - print(f"Required ANGLE file {file} not found.") - angle_exists = False - break + ok = False + continue if not checksum.checkfile(file): - angle_exists = False - log_warning("wrong version of ANGLE libraries installed") - break + ok = False + continue - if not angle_exists: - download_angle() + return ok def download_angle(): diff --git a/scripts/checksums.json b/scripts/checksums.json index aa3ca26..6ce9243 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,8 +1,10 @@ { - "scripts/files/angle-windows-2019-2023-07-09.zip": "f58ee3ba5bbc4a6aec08c1c3ef3b9ac7b991676862c641a9bff27b6cdc5519e4", + "scripts/files/angle-windows-2019-2023-07-05.zip": "a333b5ccc8462151ee8df65c43cfacd70d9db2413f2e495da65670737b5b2d96", "scripts/files/angle-mac-2023-07-05.zip": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", - "milepost/lib/libEGL.dll": "5ed4d609ea11015473c89d3b5da91e831a0a8d9608608f840a77d49ccef6867a", - "milepost/lib/libGLESv2.dll": "f36811acdbc59f6cddd33f6a96b5d6e75559af76bdd73bcc56514455e9bffd16", + "milepost/lib/libEGL.dll": "b7bf51f83e88129ddc20c0c2cb904ec04c89059a30a2cd29b9b1ea11c80388fb", + "milepost/lib/libEGL.dll.lib": "4cec54c534136da413dea86bd271ccb9c5ae88e40aa91d1de7a01e701be8e1d7", + "milepost/lib/libGLESv2.dll": "193b53b0a16b702eaa28a73e84527acf7aecfd665e3e3f54a8d9db9ae73111e1", + "milepost/lib/libGLESv2.dll.lib": "ee87aac129efe8fe871825d181b85da1b1ea6626cb48be52c2e689f2804b953f", "milepost/lib/libEGL.dylib": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", "milepost/lib/libGLESv2.dylib": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" } -- 2.25.1 From 25f660227fba1ae095decbacd182dd189b5e4ace Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Wed, 19 Jul 2023 18:14:27 -0500 Subject: [PATCH 09/23] Add Windows wasm3 build --- scripts/build_runtime.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index e832187..eb642f9 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -27,6 +27,7 @@ def build_runtime(args): ensure_angle() build_milepost("lib", args.release) + build_wasm3(args.release) def build_milepost(target, release): @@ -180,6 +181,38 @@ def build_milepost_lib_mac(release): ], check=True) +def build_wasm3(release): + print("Building wasm3...") + + os.makedirs("bin", exist_ok=True) + os.makedirs("bin\\obj", exist_ok=True) + + if platform.system() == "Windows": + build_wasm3_lib_win(release) + elif platform.system() == "Darwin": + raise "can't yet build wasm3 on Mac" + else: + log_error(f"can't build wasm3 for unknown platform '{platform.system()}'") + exit(1) + + +def build_wasm3_lib_win(release): + for f in glob.iglob(".\\ext\\wasm3\\source\\*.c"): + name = os.path.splitext(os.path.basename(f))[0] + subprocess.run([ + "cl", "/nologo", + "/Zi", "/Zc:preprocessor", "/c", + *(["/O2"] if release else []), + f"/Fo:bin\\obj\\{name}.obj", + "/I", ".\\ext\\wasm3\\source", + f, + ], check=True) + subprocess.run([ + "lib", "/nologo", "/out:bin\\wasm3.lib", + "bin\\obj\\*.obj", + ], check=True) + + def ensure_programs(): if platform.system() == "Windows": try: -- 2.25.1 From 10351e45cd98973c5f086a531ac78864b276b851 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Wed, 19 Jul 2023 18:35:07 -0500 Subject: [PATCH 10/23] Get entire Orca build working on Windows --- scripts/bindgen.py | 220 ++++++++++++------------ scripts/bindgen2.py | 359 ++++++++++++++++++++------------------- scripts/build_runtime.py | 72 ++++++++ 3 files changed, 370 insertions(+), 281 deletions(-) diff --git a/scripts/bindgen.py b/scripts/bindgen.py index 0f81a54..2eda83d 100755 --- a/scripts/bindgen.py +++ b/scripts/bindgen.py @@ -1,131 +1,135 @@ #!/usr/bin/env python3 import sys -if len(sys.argv) < 2: - print("bindgen require an api name\n") - exit(-1); +def bindgen(apiName, cdir): + inPath = cdir + '/bindgen_' + apiName + '_api.txt' + outPath = cdir + '/bindgen_' + apiName + '_api.c' -apiName = sys.argv[1] -cdir = '' + inFile = open(inPath, 'r') + outFile = open(outPath, 'w') -if len(sys.argv) > 2: - cdir = sys.argv[2] + stubs = [] + links = [] -inPath = cdir + '/bindgen_' + apiName + '_api.txt' -outPath = cdir + '/bindgen_' + apiName + '_api.c' + def gen_stub(name, sig, native_name): + if native_name == None: + native_name = name -inFile = open(inPath, 'r') -outFile = open(outPath, 'w') + src = 'const void* ' + name + '_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t * _sp, void * _mem)\n' + src += '{\n' + spIndex = 0 -stubs = [] -links = [] + parsingRet = True + retCount = 0 + argCount = 0 + retString = '' + argString = '' -def gen_stub(name, sig, native_name): - if native_name == None: - native_name = name - - src = 'const void* ' + name + '_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t * _sp, void * _mem)\n' - src += '{\n' - spIndex = 0 - - parsingRet = True - retCount = 0 - argCount = 0 - retString = '' - argString = '' - - for index, c in enumerate(sig): - if parsingRet: - if retCount > 1: - print('unsupported multiple return types\n') - break - if c == '(': - parsingRet = False - continue - elif c == ')': - print('unexpected ) while parsing return type\n') - break; - elif c == 'v': - continue - elif c == 'i': - retString = '*((i32*)&_sp[0]) = ' - elif c == 'I': - retString = '*((i64*)&_sp[0]) = ' - elif c == 'f': - retString = '*((f32*)&_sp[0]) = ' - elif c == 'F': - retString = '*((f64*)&_sp[0]) = ' - elif c == 'p': - print('returning pointers is not supported yet\n') - break + for index, c in enumerate(sig): + if parsingRet: + if retCount > 1: + print('unsupported multiple return types\n') + break + if c == '(': + parsingRet = False + continue + elif c == ')': + print('unexpected ) while parsing return type\n') + break; + elif c == 'v': + continue + elif c == 'i': + retString = '*((i32*)&_sp[0]) = ' + elif c == 'I': + retString = '*((i64*)&_sp[0]) = ' + elif c == 'f': + retString = '*((f32*)&_sp[0]) = ' + elif c == 'F': + retString = '*((f64*)&_sp[0]) = ' + elif c == 'p': + print('returning pointers is not supported yet\n') + break + else: + print('unrecognized type ' + c + ' in procedure return\n') + break + retCount += 1 else: - print('unrecognized type ' + c + ' in procedure return\n') - break - retCount += 1 - else: - argIndex = argCount + retCount - if c == ')': - break - elif c == 'v': - break - elif c == 'i': - argString += '*(i32*)&_sp[' + str(argIndex) + ']' - elif c == 'I': - argString += '*(i64*)&_sp[' + str(argIndex) + ']' - elif c == 'f': - argString += '*(f32*)&_sp[' + str(argIndex) + ']' - elif c == 'F': - argString += '*(f64*)&_sp[' + str(argIndex) + ']' - elif c == 'p': - argString += '(void*)((char*)_mem + *(i32*)&_sp[' + str(argIndex) + '])' + argIndex = argCount + retCount + if c == ')': + break + elif c == 'v': + break + elif c == 'i': + argString += '*(i32*)&_sp[' + str(argIndex) + ']' + elif c == 'I': + argString += '*(i64*)&_sp[' + str(argIndex) + ']' + elif c == 'f': + argString += '*(f32*)&_sp[' + str(argIndex) + ']' + elif c == 'F': + argString += '*(f64*)&_sp[' + str(argIndex) + ']' + elif c == 'p': + argString += '(void*)((char*)_mem + *(i32*)&_sp[' + str(argIndex) + '])' + else: + print('unrecognized type ' + c + ' in procedure signature\n') + break + + if index+2 < len(sig): + argString += ', ' + argCount += 1 + + src += '\t' + retString + native_name + '(' + argString + ');\n' + src += '\treturn(0);\n' + src += '}\n' + stubs.append(src) + + def gen_link(name, sig): + m3_Sig = '' + for c in sig: + if c == 'p': + m3_Sig += 'i' else: - print('unrecognized type ' + c + ' in procedure signature\n') - break + m3_Sig += c - if index+2 < len(sig): - argString += ', ' - argCount += 1 + src = '\tres = m3_LinkRawFunction(module, "*", "' + name + '", "' + m3_Sig + '", ' + name + '_stub);\n' + src += '\tif(res != m3Err_none && res != m3Err_functionLookupFailed) { log_error("error: %s\\n", res); return(-1); }\n\n' + links.append(src) - src += '\t' + retString + native_name + '(' + argString + ');\n' - src += '\treturn(0);\n' - src += '}\n' - stubs.append(src) + for line in inFile: + if line.isspace(): + continue + desc = line.split() -def gen_link(name, sig): - m3_Sig = '' - for c in sig: - if c == 'p': - m3_Sig += 'i' - else: - m3_Sig += c + gen_stub(desc[0], desc[1], desc[2] if len(desc) > 2 else None) + gen_link(desc[0], desc[1]) - src = '\tres = m3_LinkRawFunction(module, "*", "' + name + '", "' + m3_Sig + '", ' + name + '_stub);\n' - src += '\tif(res != m3Err_none && res != m3Err_functionLookupFailed) { log_error("error: %s\\n", res); return(-1); }\n\n' - links.append(src) + linkProc = 'int bindgen_link_' + apiName + '_api(IM3Module module)\n' + linkProc += '{\n' + linkProc += '\tM3Result res;\n' -for line in inFile: - if line.isspace(): - continue - desc = line.split() + for link in links: + linkProc += link - gen_stub(desc[0], desc[1], desc[2] if len(desc) > 2 else None) - gen_link(desc[0], desc[1]) + linkProc += '\treturn(0);\n' + linkProc += '}\n' -linkProc = 'int bindgen_link_' + apiName + '_api(IM3Module module)\n' -linkProc += '{\n' -linkProc += '\tM3Result res;\n' + for stub in stubs: + outFile.write(stub) -for link in links: - linkProc += link + outFile.write('\n') + outFile.write(linkProc) -linkProc += '\treturn(0);\n' -linkProc += '}\n' + inFile.close() + outFile.close() -for stub in stubs: - outFile.write(stub) +if __name__ == "__main__": + if len(sys.argv) < 2: + print("bindgen require an api name\n") + exit(-1) -outFile.write('\n') -outFile.write(linkProc) + apiName = sys.argv[1] + cdir = '' -inFile.close() -outFile.close() + if len(sys.argv) > 2: + cdir = sys.argv[2] + + bindgen(apiName, cdir) diff --git a/scripts/bindgen2.py b/scripts/bindgen2.py index 48baa0e..3dde8b1 100644 --- a/scripts/bindgen2.py +++ b/scripts/bindgen2.py @@ -3,31 +3,6 @@ from argparse import ArgumentParser import json -parser = ArgumentParser(prog='bindgen.py') -parser.add_argument('api') -parser.add_argument('spec') -parser.add_argument('-g', '--guest-stubs') -parser.add_argument('--guest-include') -parser.add_argument('--wasm3-bindings') - -args = parser.parse_args() - -apiName = args.api -spec = args.spec -guest_stubs_path = args.guest_stubs -if guest_stubs_path == None: - guest_stubs_path = 'bindgen_' + apiName + '_guest_stubs.c' - -wasm3_bindings_path = args.wasm3_bindings -if wasm3_bindings_path == None: - wasm3_bindings_path = 'bindgen_' + apiName + '_wasm3_bindings.c' - -host_bindings = open(wasm3_bindings_path, 'w') -guest_bindings = None - -specFile = open(spec, 'r') -data = json.load(specFile) - def needs_arg_ptr_stub(decl): res = (decl['ret']['tag'] == 'S') for arg in decl['args']: @@ -35,167 +10,205 @@ def needs_arg_ptr_stub(decl): res = True return(res) -for decl in data: - if needs_arg_ptr_stub(decl): - guest_bindings = open(guest_stubs_path, 'w') - if args.guest_include != None: - s = '#include"' + args.guest_include + '"\n\n' - print(s, file=guest_bindings) - break +def bindgen2(apiName, spec, **kwargs): + guest_stubs_path = kwargs["guest_stubs"] + guest_include = kwargs.get("guest-include") + wasm3_bindings_path = kwargs["wasm3_bindings"] -for decl in data: + host_bindings = open(wasm3_bindings_path, 'w') + guest_bindings = None - name = decl['name'] - cname = decl.get('cname', name) + specFile = open(spec, 'r') + data = json.load(specFile) - if needs_arg_ptr_stub(decl): - argPtrStubName = name + '_argptr_stub' - # pointer arg stub declaration - s = '' - if decl['ret']['tag'] == 'S': - s += 'void' - else: - s += decl['ret']['name'] + for decl in data: + if needs_arg_ptr_stub(decl): + guest_bindings = open(guest_stubs_path, 'w') + if guest_include != None: + s = '#include"' + guest_include + '"\n\n' + print(s, file=guest_bindings) + break - s += ' ORCA_IMPORT(' + argPtrStubName + ') (' + for decl in data: - if decl['ret']['tag'] == 'S': - s += decl['ret']['name'] + '* __retArg' - if len(decl['args']) > 0: - s += ', ' + name = decl['name'] + cname = decl.get('cname', name) - for i, arg in enumerate(decl['args']): - s += arg['type']['name'] - if arg['type']['tag'] == 'S': - s += '*' - s += ' ' + arg['name'] - if i+1 < len(decl['args']): - s += ', ' - s += ');\n\n' - - # forward function to pointer arg stub declaration - s += decl['ret']['name'] + ' ' + name + '(' - for i, arg in enumerate(decl['args']): - s += arg['type']['name'] + ' ' + arg['name'] - if i+1 < len(decl['args']): - s += ', ' - s += ')\n' - s += '{\n' - s += '\t' - if decl['ret']['tag'] == 'S': - s += decl['ret']['name'] + ' __ret;\n\t' - elif decl['ret']['tag'] != 'v': - s += decl['ret']['name'] - s += ' __ret = ' - s += argPtrStubName + '(' - - if decl['ret']['tag'] == 'S': - s += '&__ret' - if len(decl['args']) > 0: - s += ', ' - - for i, arg in enumerate(decl['args']): - if arg['type']['tag'] == 'S': - s += '&' - - s += arg['name'] - if i+1 < len(decl['args']): - s += ', ' - s += ');\n' - if decl['ret']['tag'] != 'v': - s += '\treturn(__ret);\n' - s += '}\n\n' - - print(s, file=guest_bindings) - - # host-side stub - s = 'const void* ' + cname + '_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)' - - gen_stub = decl.get('gen_stub', True) - if gen_stub == False: - s += ';\n\n' - else: - s += '\n{\n\t' - retTag = decl['ret']['tag'] - - if retTag == 'i': - s += '*((i32*)&_sp[0]) = ' - elif retTag == 'I': - s += '*((i64*)&_sp[0]) = ' - elif retTag == 'f': - s += '*((f32*)&_sp[0]) = ' - elif retTag == 'F': - s += '*((f64*)&_sp[0]) = ' - elif retTag == 'S': - retTypeName = decl['ret']['name'] - retTypeCName = decl['ret'].get('cname', retTypeName) - s += '*(' + retTypeCName + '*)((char*)_mem + *(i32*)&_sp[0]) = ' - - s += cname + '(' - - firstArgIndex = 0 - if retTag != 'v': - firstArgIndex = 1 - - for i, arg in enumerate(decl['args']): - typeName = arg['type']['name'] - typeCName = arg['type'].get('cname', typeName) - argTag = arg['type']['tag'] - if argTag == 'i': - s += '*(i32*)&_sp[' + str(firstArgIndex + i) + ']' - elif argTag == 'I': - s += '*(i64*)&_sp[' + str(firstArgIndex + i) + ']' - elif argTag == 'f': - s += '*(f32*)&_sp[' + str(firstArgIndex + i) + ']' - elif argTag == 'F': - s += '*(f64*)&_sp[' + str(firstArgIndex + i) + ']' - elif argTag == 'p': - s += '(void*)((char*)_mem + *(i32*)&_sp[' + str(firstArgIndex + i) + '])' - elif argTag == 'S': - s += '*(' + typeCName + '*)((char*)_mem + *(i32*)&_sp[' + str(firstArgIndex + i) + '])' + if needs_arg_ptr_stub(decl): + argPtrStubName = name + '_argptr_stub' + # pointer arg stub declaration + s = '' + if decl['ret']['tag'] == 'S': + s += 'void' else: - print('unrecognized type ' + c + ' in procedure signature\n') - break + s += decl['ret']['name'] - if i+1 < len(decl['args']): - s += ', ' + s += ' ORCA_IMPORT(' + argPtrStubName + ') (' - s += ');\n\treturn(0);\n}\n\n' + if decl['ret']['tag'] == 'S': + s += decl['ret']['name'] + '* __retArg' + if len(decl['args']) > 0: + s += ', ' + + for i, arg in enumerate(decl['args']): + s += arg['type']['name'] + if arg['type']['tag'] == 'S': + s += '*' + s += ' ' + arg['name'] + if i+1 < len(decl['args']): + s += ', ' + s += ');\n\n' + + # forward function to pointer arg stub declaration + s += decl['ret']['name'] + ' ' + name + '(' + for i, arg in enumerate(decl['args']): + s += arg['type']['name'] + ' ' + arg['name'] + if i+1 < len(decl['args']): + s += ', ' + s += ')\n' + s += '{\n' + s += '\t' + if decl['ret']['tag'] == 'S': + s += decl['ret']['name'] + ' __ret;\n\t' + elif decl['ret']['tag'] != 'v': + s += decl['ret']['name'] + s += ' __ret = ' + s += argPtrStubName + '(' + + if decl['ret']['tag'] == 'S': + s += '&__ret' + if len(decl['args']) > 0: + s += ', ' + + for i, arg in enumerate(decl['args']): + if arg['type']['tag'] == 'S': + s += '&' + + s += arg['name'] + if i+1 < len(decl['args']): + s += ', ' + s += ');\n' + if decl['ret']['tag'] != 'v': + s += '\treturn(__ret);\n' + s += '}\n\n' + + print(s, file=guest_bindings) + + # host-side stub + s = 'const void* ' + cname + '_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)' + + gen_stub = decl.get('gen_stub', True) + if gen_stub == False: + s += ';\n\n' + else: + s += '\n{\n\t' + retTag = decl['ret']['tag'] + + if retTag == 'i': + s += '*((i32*)&_sp[0]) = ' + elif retTag == 'I': + s += '*((i64*)&_sp[0]) = ' + elif retTag == 'f': + s += '*((f32*)&_sp[0]) = ' + elif retTag == 'F': + s += '*((f64*)&_sp[0]) = ' + elif retTag == 'S': + retTypeName = decl['ret']['name'] + retTypeCName = decl['ret'].get('cname', retTypeName) + s += '*(' + retTypeCName + '*)((char*)_mem + *(i32*)&_sp[0]) = ' + + s += cname + '(' + + firstArgIndex = 0 + if retTag != 'v': + firstArgIndex = 1 + + for i, arg in enumerate(decl['args']): + typeName = arg['type']['name'] + typeCName = arg['type'].get('cname', typeName) + argTag = arg['type']['tag'] + if argTag == 'i': + s += '*(i32*)&_sp[' + str(firstArgIndex + i) + ']' + elif argTag == 'I': + s += '*(i64*)&_sp[' + str(firstArgIndex + i) + ']' + elif argTag == 'f': + s += '*(f32*)&_sp[' + str(firstArgIndex + i) + ']' + elif argTag == 'F': + s += '*(f64*)&_sp[' + str(firstArgIndex + i) + ']' + elif argTag == 'p': + s += '(void*)((char*)_mem + *(i32*)&_sp[' + str(firstArgIndex + i) + '])' + elif argTag == 'S': + s += '*(' + typeCName + '*)((char*)_mem + *(i32*)&_sp[' + str(firstArgIndex + i) + '])' + else: + print('unrecognized type ' + c + ' in procedure signature\n') + break + + if i+1 < len(decl['args']): + s += ', ' + + s += ');\n\treturn(0);\n}\n\n' + + print(s, file=host_bindings) + + # link function + s = 'int bindgen_link_' + apiName + '_api(IM3Module module)\n{\n\t' + s += 'M3Result res;\n' + + for decl in data: + name = decl['name'] + cname = decl.get('cname', name) + + if needs_arg_ptr_stub(decl): + name = name + '_argptr_stub' + + m3Sig = '' + if decl['ret']['tag'] == 'S': + m3Sig += 'v' + else: + m3Sig += decl['ret']['tag'] + + m3Sig += '(' + if decl['ret']['tag'] == 'S': + m3Sig += 'i' + for arg in decl['args']: + tag = arg['type']['tag'] + if tag == 'p' or tag == 'S': + tag = 'i' + m3Sig += tag + m3Sig += ')' + + + s += '\tres = m3_LinkRawFunction(module, "*", "' + name + '", "' + m3Sig + '", ' + cname + '_stub);\n' + s += '\tif(res != m3Err_none && res != m3Err_functionLookupFailed) { log_error("error: %s\\n", res); return(-1); }\n\n' + + + s += '\treturn(0);\n}\n' print(s, file=host_bindings) -# link function -s = 'int bindgen_link_' + apiName + '_api(IM3Module module)\n{\n\t' -s += 'M3Result res;\n' -for decl in data: - name = decl['name'] - cname = decl.get('cname', name) +if __name__ == "__main__": + parser = ArgumentParser(prog='bindgen.py') + parser.add_argument('api') + parser.add_argument('spec') + parser.add_argument('-g', '--guest-stubs') + parser.add_argument('--guest-include') + parser.add_argument('--wasm3-bindings') - if needs_arg_ptr_stub(decl): - name = name + '_argptr_stub' + args = parser.parse_args() - m3Sig = '' - if decl['ret']['tag'] == 'S': - m3Sig += 'v' - else: - m3Sig += decl['ret']['tag'] + apiName = args.api + spec = args.spec + guest_stubs_path = args.guest_stubs + if guest_stubs_path == None: + guest_stubs_path = 'bindgen_' + apiName + '_guest_stubs.c' - m3Sig += '(' - if decl['ret']['tag'] == 'S': - m3Sig += 'i' - for arg in decl['args']: - tag = arg['type']['tag'] - if tag == 'p' or tag == 'S': - tag = 'i' - m3Sig += tag - m3Sig += ')' - - - s += '\tres = m3_LinkRawFunction(module, "*", "' + name + '", "' + m3Sig + '", ' + cname + '_stub);\n' - s += '\tif(res != m3Err_none && res != m3Err_functionLookupFailed) { log_error("error: %s\\n", res); return(-1); }\n\n' - - -s += '\treturn(0);\n}\n' - -print(s, file=host_bindings) + wasm3_bindings_path = args.wasm3_bindings + if wasm3_bindings_path == None: + wasm3_bindings_path = 'bindgen_' + apiName + '_wasm3_bindings.c' + + bindgen2(apiName, spec, + guest_stubs_path=guest_stubs_path, + guest_include=args.guest_include, + wasm3_bindings_path=wasm3_bindings_path, + ) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index eb642f9..80d7a3b 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -9,6 +9,8 @@ import subprocess from zipfile import ZipFile import checksum +from bindgen import bindgen +from bindgen2 import bindgen2 from log import * from utils import pushd, removeall @@ -28,6 +30,7 @@ def build_runtime(args): build_milepost("lib", args.release) build_wasm3(args.release) + build_orca(args.release) def build_milepost(target, release): @@ -213,6 +216,75 @@ def build_wasm3_lib_win(release): ], check=True) +def build_orca(release): + print("Building Orca...") + + os.makedirs("bin", exist_ok=True) + + if platform.system() == "Windows": + build_orca_win(release) + elif platform.system() == "Darwin": + raise "can't yet build Orca on Mac" + else: + log_error(f"can't build Orca for unknown platform '{platform.system()}'") + exit(1) + + +def build_orca_win(release): + pthread_dir = "..\\vcpkg\\packages\\pthreads_x64-windows" + + # copy libraries + shutil.copy("milepost\\bin\\milepost.dll", "bin") + shutil.copy("milepost\\bin\\milepost.dll.lib", "bin") + shutil.copy(os.path.join(pthread_dir, "bin\\pthreadVC3.dll"), "bin") + + # generate wasm3 api bindings + bindgen("core", "src") + bindgen("gles", "src") + bindgen2("canvas", "src\\canvas_api.json", + guest_stubs="sdk\\orca_surface.c", + guest_include="graphics.h", + wasm3_bindings="src\\canvas_api_bind_gen.c", + ) + bindgen2("clock", "src\\clock_api.json", + guest_stubs="sdk\\orca_clock.c", + guest_include="platform_clock.h", + wasm3_bindings="src\\clock_api_bind_gen.c", + ) + bindgen2("io", "src\\io_api.json", + guest_stubs="sdk\\io_stubs.c", + wasm3_bindings="src\\io_api_bind_gen.c", + ) + + # compile orca + pthread_include = os.path.join(pthread_dir, "include") + includes = [ + "/I", "src", + "/I", "sdk", + "/I", "ext\wasm3\source", + "/I", "milepost\src", + "/I", "milepost\ext", + "/I", pthread_include, + ] + pthread_lib = os.path.join(pthread_dir, "lib") + libs = [ + "/LIBPATH:bin", + f"/LIBPATH:{pthread_lib}", + "milepost.dll.lib", + "wasm3.lib", + "pthreadVC3.lib", + ] + + subprocess.run([ + "cl", + "/Zi", "/Zc:preprocessor", "/std:c11", + *includes, + "src\\main.c", + "/link", *libs, + "/out:bin\\orca.exe", + ], check=True) + + def ensure_programs(): if platform.system() == "Windows": try: -- 2.25.1 From 6ca5b6f4f0536e222e64aeb4eac5adf5450c9c2b Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 22 Jul 2023 17:41:10 -0500 Subject: [PATCH 11/23] Change expected Mac filename --- scripts/build_runtime.py | 2 +- scripts/checksums.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 80d7a3b..1afea6c 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -332,7 +332,7 @@ def verify_angle(): elif platform.system() == "Darwin": if platform.machine() == "arm64": log_warning(f"automated ANGLE builds are not yet available for Apple silicon") - return + return False checkfiles = [ "milepost/lib/libEGL.dylib", "milepost/lib/libGLESv2.dylib", diff --git a/scripts/checksums.json b/scripts/checksums.json index 6ce9243..3b28389 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,6 +1,6 @@ { "scripts/files/angle-windows-2019-2023-07-05.zip": "a333b5ccc8462151ee8df65c43cfacd70d9db2413f2e495da65670737b5b2d96", - "scripts/files/angle-mac-2023-07-05.zip": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", + "scripts/files/angle-macos-12-2023-07-05.zip": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", "milepost/lib/libEGL.dll": "b7bf51f83e88129ddc20c0c2cb904ec04c89059a30a2cd29b9b1ea11c80388fb", "milepost/lib/libEGL.dll.lib": "4cec54c534136da413dea86bd271ccb9c5ae88e40aa91d1de7a01e701be8e1d7", "milepost/lib/libGLESv2.dll": "193b53b0a16b702eaa28a73e84527acf7aecfd665e3e3f54a8d9db9ae73111e1", -- 2.25.1 From 389b9607d6d6e5cefe0159b8e3187d3218529ab4 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 22 Jul 2023 18:16:31 -0500 Subject: [PATCH 12/23] Use frankensteined angle build for now --- scripts/build_runtime.py | 9 +++------ scripts/checksums.json | 6 +++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 1afea6c..1fc9935 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -193,7 +193,8 @@ def build_wasm3(release): if platform.system() == "Windows": build_wasm3_lib_win(release) elif platform.system() == "Darwin": - raise "can't yet build wasm3 on Mac" + log_error("can't yet build wasm3 on Mac") + exit(1) else: log_error(f"can't build wasm3 for unknown platform '{platform.system()}'") exit(1) @@ -330,9 +331,6 @@ def verify_angle(): "milepost/lib/libGLESv2.dll.lib", ] elif platform.system() == "Darwin": - if platform.machine() == "arm64": - log_warning(f"automated ANGLE builds are not yet available for Apple silicon") - return False checkfiles = [ "milepost/lib/libEGL.dylib", "milepost/lib/libGLESv2.dylib", @@ -360,8 +358,7 @@ def download_angle(): build = "windows-2019" extensions = ["dll", "lib"] elif platform.system() == "Darwin": - # TODO(ben): make universal dylibs - build = "macos-12" + build = "macos-jank" extensions = ["dylib"] else: log_error(f"could not automatically download ANGLE for unknown platform {platform.system()}") diff --git a/scripts/checksums.json b/scripts/checksums.json index 3b28389..f5ca541 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,10 +1,10 @@ { "scripts/files/angle-windows-2019-2023-07-05.zip": "a333b5ccc8462151ee8df65c43cfacd70d9db2413f2e495da65670737b5b2d96", - "scripts/files/angle-macos-12-2023-07-05.zip": "a3422c456278ff037ef89a7808e0ba256d972d4832d5272fc3d4aa4f7912c1e0", + "scripts/files/angle-macos-jank-2023-07-05.zip": "c234b8db179a24757ab9f46610a032123718dd9bed967d2bf8e27d0d17eb0aff", "milepost/lib/libEGL.dll": "b7bf51f83e88129ddc20c0c2cb904ec04c89059a30a2cd29b9b1ea11c80388fb", "milepost/lib/libEGL.dll.lib": "4cec54c534136da413dea86bd271ccb9c5ae88e40aa91d1de7a01e701be8e1d7", "milepost/lib/libGLESv2.dll": "193b53b0a16b702eaa28a73e84527acf7aecfd665e3e3f54a8d9db9ae73111e1", "milepost/lib/libGLESv2.dll.lib": "ee87aac129efe8fe871825d181b85da1b1ea6626cb48be52c2e689f2804b953f", - "milepost/lib/libEGL.dylib": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592", - "milepost/lib/libGLESv2.dylib": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe" + "milepost/lib/libEGL.dylib": "96baea4b1c8578d30738764784d07b509d1153df694c094faba2ee8ccbfde2a9", + "milepost/lib/libGLESv2.dylib": "98ce9f6248a6447ba9199e96b8f6d87df9548d43ce583a2615717aab168ecb71" } -- 2.25.1 From 062cd1e2de8245dcf192a7c8b0813447a5fbb022 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sun, 23 Jul 2023 10:18:25 -0500 Subject: [PATCH 13/23] Build wasm3 on Mac --- scripts/build_runtime.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 1fc9935..7dc98b0 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -188,13 +188,12 @@ def build_wasm3(release): print("Building wasm3...") os.makedirs("bin", exist_ok=True) - os.makedirs("bin\\obj", exist_ok=True) + os.makedirs("bin/obj", exist_ok=True) if platform.system() == "Windows": build_wasm3_lib_win(release) elif platform.system() == "Darwin": - log_error("can't yet build wasm3 on Mac") - exit(1) + build_wasm3_lib_mac(release) else: log_error(f"can't build wasm3 for unknown platform '{platform.system()}'") exit(1) @@ -217,6 +216,21 @@ def build_wasm3_lib_win(release): ], check=True) +def build_wasm3_lib_mac(release): + for f in glob.iglob("./ext/wasm3/source/*.c"): + name = os.path.splitext(os.path.basename(f))[0] + ".o" + subprocess.run([ + "clang", "-c", + "-g", *(["/O2"] if release else []), + "-foptimize-sibling-calls", "-Wno-extern-initializer", "-Dd_m3VerboseErrorMessages", + "-I./ext/wasm3/source", + "-o", f"./bin/obj/{name}", + f, + ], check=True) + subprocess.run(["ar", "-rcs", "./bin/libwasm3.a", *glob.glob("./bin/obj/*.o")], check=True) + subprocess.run(["rm", "-rf", "./bin/obj"], check=True) + + def build_orca(release): print("Building Orca...") @@ -225,7 +239,8 @@ def build_orca(release): if platform.system() == "Windows": build_orca_win(release) elif platform.system() == "Darwin": - raise "can't yet build Orca on Mac" + log_error("can't yet build Orca on Mac") + exit(1) else: log_error(f"can't build Orca for unknown platform '{platform.system()}'") exit(1) -- 2.25.1 From 731b5a6bba35f1af455cee8a03f06e007d73ac50 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sun, 23 Jul 2023 10:58:08 -0500 Subject: [PATCH 14/23] This commit will hard-lock your Mac --- scripts/build_runtime.py | 99 ++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 7dc98b0..3826b25 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -217,13 +217,19 @@ def build_wasm3_lib_win(release): def build_wasm3_lib_mac(release): + includes = ["-I./ext/wasm3/source"] + debug_flags = ["-O2"] if release else ["-g"] + flags = [ + *debug_flags, + "-foptimize-sibling-calls", + "-Wno-extern-initializer", + "-Dd_m3VerboseErrorMessages", + ] + for f in glob.iglob("./ext/wasm3/source/*.c"): name = os.path.splitext(os.path.basename(f))[0] + ".o" subprocess.run([ - "clang", "-c", - "-g", *(["/O2"] if release else []), - "-foptimize-sibling-calls", "-Wno-extern-initializer", "-Dd_m3VerboseErrorMessages", - "-I./ext/wasm3/source", + "clang", "-c", *flags, *includes, "-o", f"./bin/obj/{name}", f, ], check=True) @@ -239,8 +245,7 @@ def build_orca(release): if platform.system() == "Windows": build_orca_win(release) elif platform.system() == "Darwin": - log_error("can't yet build Orca on Mac") - exit(1) + build_orca_mac(release) else: log_error(f"can't build Orca for unknown platform '{platform.system()}'") exit(1) @@ -254,23 +259,7 @@ def build_orca_win(release): shutil.copy("milepost\\bin\\milepost.dll.lib", "bin") shutil.copy(os.path.join(pthread_dir, "bin\\pthreadVC3.dll"), "bin") - # generate wasm3 api bindings - bindgen("core", "src") - bindgen("gles", "src") - bindgen2("canvas", "src\\canvas_api.json", - guest_stubs="sdk\\orca_surface.c", - guest_include="graphics.h", - wasm3_bindings="src\\canvas_api_bind_gen.c", - ) - bindgen2("clock", "src\\clock_api.json", - guest_stubs="sdk\\orca_clock.c", - guest_include="platform_clock.h", - wasm3_bindings="src\\clock_api_bind_gen.c", - ) - bindgen2("io", "src\\io_api.json", - guest_stubs="sdk\\io_stubs.c", - wasm3_bindings="src\\io_api_bind_gen.c", - ) + gen_all_bindings() # compile orca pthread_include = os.path.join(pthread_dir, "include") @@ -301,6 +290,70 @@ def build_orca_win(release): ], check=True) +def build_orca_mac(release): + # copy libraries + shutil.copy("milepost/bin/mtl_renderer.metallib", "bin/") + shutil.copy("milepost/bin/libmilepost.dylib", "bin/") + shutil.copy("milepost/bin/libGLESv2.dylib", "bin/") + shutil.copy("milepost/bin/libEGL.dylib", "bin/") + + includes = [ + "-Isrc", + "-Isdk", + "-Imilepost/src", + "-Imilepost/src/util", + "-Imilepost/src/platform", + "-Iext/wasm3/source", + "-Imilepost/ext/", + ] + libs = ["-Lbin", "-lmilepost", "-lwasm3"] + debug_flags = ["-O2"] if release else ["-g", "-DLOG_COMPILE_DEBUG"] + flags = [ + *debug_flags, + "-mmacos-version-min=10.15.4", + "-maes", + ] + + gen_all_bindings() + + # compile orca + subprocess.run([ + "clang", *flags, *includes, *libs, + "-o", "bin/orca", + "src/main.c", + ], check=True) + + # fix libs imports + subprocess.run([ + "install_name_tool", "-change", + "./bin/libmilepost.dylib", "@rpath/libmilepost.dylib", "bin/orca", + ], check=True) + subprocess.run([ + "install_name_tool", "-add_rpath", + "@executable_path/", "bin/orca", + ], check=True) + + +def gen_all_bindings(): + bindgen("core", "src") + bindgen("gles", "src") + + bindgen2("canvas", "src/canvas_api.json", + guest_stubs="sdk/orca_surface.c", + guest_include="graphics.h", + wasm3_bindings="src/canvas_api_bind_gen.c", + ) + bindgen2("clock", "src/clock_api.json", + guest_stubs="sdk/orca_clock.c", + guest_include="platform_clock.h", + wasm3_bindings="src/clock_api_bind_gen.c", + ) + bindgen2("io", "src/io_api.json", + guest_stubs="sdk/io_stubs.c", + wasm3_bindings="src/io_api_bind_gen.c", + ) + + def ensure_programs(): if platform.system() == "Windows": try: -- 2.25.1 From 8bd12bdd1f1892d7f3d06ae51578cd8608a08208 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sun, 23 Jul 2023 12:01:06 -0500 Subject: [PATCH 15/23] This commit will not hard-lock your Mac --- .gitignore | 1 + build.sh | 2 +- scripts/build_runtime.py | 107 ++++++++++++++++++++++++--------------- scripts/checksums.json | 4 +- scripts/mkapp.py | 20 ++++---- 5 files changed, 79 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 25d7d9c..5df72cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store *.dSYM bin/* +build *.metallib *.pdb *.exe diff --git a/build.sh b/build.sh index 6b2f2b2..de9787d 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -set -eo pipefail +set -exo pipefail target="$1" diff --git a/scripts/build_runtime.py b/scripts/build_runtime.py index 3826b25..2a7339b 100644 --- a/scripts/build_runtime.py +++ b/scripts/build_runtime.py @@ -19,9 +19,12 @@ ANGLE_VERSION = "2023-07-05" def attach_build_runtime(subparsers): - build = subparsers.add_parser("build-runtime", help="TODO") - build.add_argument("--release", action="store_true", help="compile Orca in release mode (default is debug)") - build.set_defaults(func=shellish(build_runtime)) + build_cmd = subparsers.add_parser("build-runtime", help="TODO") + build_cmd.add_argument("--release", action="store_true", help="compile Orca in release mode (default is debug)") + build_cmd.set_defaults(func=shellish(build_runtime)) + + clean_cmd = subparsers.add_parser("clean", help="Delete all build artifacts and start fresh") + clean_cmd.set_defaults(func=shellish(clean)) def build_runtime(args): @@ -33,11 +36,21 @@ def build_runtime(args): build_orca(args.release) +def clean(args): + def yeet(path): + os.makedirs(path, exist_ok=True) + shutil.rmtree(path) + yeet("build") + yeet("milepost/build") + yeet("scripts/files") + yeet("scripts/__pycache__") + + def build_milepost(target, release): print("Building milepost...") with pushd("milepost"): - os.makedirs("bin", exist_ok=True) - os.makedirs("lib", exist_ok=True) + os.makedirs("build/bin", exist_ok=True) + os.makedirs("build/lib", exist_ok=True) os.makedirs("resources", exist_ok=True) if target == "lib": @@ -126,13 +139,13 @@ def build_milepost_lib_mac(release): "xcrun", "-sdk", "macosx", "metal", # TODO: shaderFlagParam "-fno-fast-math", "-c", - "-o", "lib/mtl_renderer.air", + "-o", "build/mtl_renderer.air", "src/mtl_renderer.metal", ], check=True) subprocess.run([ "xcrun", "-sdk", "macosx", "metallib", - "-o", "lib/mtl_renderer.metallib", - "lib/mtl_renderer.air", + "-o", "build/bin/mtl_renderer.metallib", + "build/mtl_renderer.air", ], check=True) # compile milepost. We use one compilation unit for all C code, and one @@ -140,14 +153,14 @@ def build_milepost_lib_mac(release): subprocess.run([ "clang", *debug_flags, "-c", - "-o", "bin/milepost_c.o", + "-o", "build/milepost_c.o", *cflags, *flags, *includes, "src/milepost.c" ], check=True) subprocess.run([ "clang", *debug_flags, "-c", - "-o", "bin/milepost_objc.o", + "-o", "build/milepost_objc.o", *flags, *includes, "src/milepost.m" ], check=True) @@ -156,9 +169,9 @@ def build_milepost_lib_mac(release): subprocess.run([ "ld", *ldflags, "-dylib", - "-o", "bin/libmilepost.dylib", - "bin/milepost_c.o", "bin/milepost_objc.o", - "-Llib", "-lc", + "-o", "build/bin/libmilepost.dylib", + "build/milepost_c.o", "build/milepost_objc.o", + "-Lbuild/bin", "-lc", "-framework", "Carbon", "-framework", "Cocoa", "-framework", "Metal", "-framework", "QuartzCore", "-weak-lEGL", "-weak-lGLESv2", ], check=True) @@ -167,12 +180,12 @@ def build_milepost_lib_mac(release): subprocess.run([ "install_name_tool", "-change", "./libEGL.dylib", "@rpath/libEGL.dylib", - "bin/libmilepost.dylib", + "build/bin/libmilepost.dylib", ], check=True) subprocess.run([ "install_name_tool", "-change", "./libGLESv2.dylib", "@rpath/libGLESv2.dylib", - "bin/libmilepost.dylib", + "build/bin/libmilepost.dylib", ], check=True) # add executable path to rpath. Client executable can still add its own @@ -180,15 +193,16 @@ def build_milepost_lib_mac(release): subprocess.run([ "install_name_tool", "-id", "@rpath/libmilepost.dylib", - "bin/libmilepost.dylib", + "build/bin/libmilepost.dylib", ], check=True) def build_wasm3(release): print("Building wasm3...") - os.makedirs("bin", exist_ok=True) - os.makedirs("bin/obj", exist_ok=True) + os.makedirs("build/bin", exist_ok=True) + os.makedirs("build/lib", exist_ok=True) + os.makedirs("build/obj", exist_ok=True) if platform.system() == "Windows": build_wasm3_lib_win(release) @@ -217,8 +231,8 @@ def build_wasm3_lib_win(release): def build_wasm3_lib_mac(release): - includes = ["-I./ext/wasm3/source"] - debug_flags = ["-O2"] if release else ["-g"] + includes = ["-Iext/wasm3/source"] + debug_flags = ["-g", "-O2"] flags = [ *debug_flags, "-foptimize-sibling-calls", @@ -226,21 +240,22 @@ def build_wasm3_lib_mac(release): "-Dd_m3VerboseErrorMessages", ] - for f in glob.iglob("./ext/wasm3/source/*.c"): + for f in glob.iglob("ext/wasm3/source/*.c"): name = os.path.splitext(os.path.basename(f))[0] + ".o" subprocess.run([ "clang", "-c", *flags, *includes, - "-o", f"./bin/obj/{name}", + "-o", f"build/obj/{name}", f, ], check=True) - subprocess.run(["ar", "-rcs", "./bin/libwasm3.a", *glob.glob("./bin/obj/*.o")], check=True) - subprocess.run(["rm", "-rf", "./bin/obj"], check=True) + subprocess.run(["ar", "-rcs", "build/lib/libwasm3.a", *glob.glob("build/obj/*.o")], check=True) + subprocess.run(["rm", "-rf", "build/obj"], check=True) def build_orca(release): print("Building Orca...") - os.makedirs("bin", exist_ok=True) + os.makedirs("build/bin", exist_ok=True) + os.makedirs("build/lib", exist_ok=True) if platform.system() == "Windows": build_orca_win(release) @@ -292,10 +307,10 @@ def build_orca_win(release): def build_orca_mac(release): # copy libraries - shutil.copy("milepost/bin/mtl_renderer.metallib", "bin/") - shutil.copy("milepost/bin/libmilepost.dylib", "bin/") - shutil.copy("milepost/bin/libGLESv2.dylib", "bin/") - shutil.copy("milepost/bin/libEGL.dylib", "bin/") + shutil.copy("milepost/build/bin/mtl_renderer.metallib", "build/bin/") + shutil.copy("milepost/build/bin/libmilepost.dylib", "build/bin/") + shutil.copy("milepost/build/bin/libGLESv2.dylib", "build/bin/") + shutil.copy("milepost/build/bin/libEGL.dylib", "build/bin/") includes = [ "-Isrc", @@ -306,7 +321,7 @@ def build_orca_mac(release): "-Iext/wasm3/source", "-Imilepost/ext/", ] - libs = ["-Lbin", "-lmilepost", "-lwasm3"] + libs = ["-Lbuild/bin", "-Lbuild/lib", "-lmilepost", "-lwasm3"] debug_flags = ["-O2"] if release else ["-g", "-DLOG_COMPILE_DEBUG"] flags = [ *debug_flags, @@ -319,18 +334,20 @@ def build_orca_mac(release): # compile orca subprocess.run([ "clang", *flags, *includes, *libs, - "-o", "bin/orca", + "-o", "build/bin/orca", "src/main.c", ], check=True) # fix libs imports subprocess.run([ - "install_name_tool", "-change", - "./bin/libmilepost.dylib", "@rpath/libmilepost.dylib", "bin/orca", + "install_name_tool", + "-change", "build/bin/libmilepost.dylib", "@rpath/libmilepost.dylib", + "build/bin/orca", ], check=True) subprocess.run([ - "install_name_tool", "-add_rpath", - "@executable_path/", "bin/orca", + "install_name_tool", + "-add_rpath", "@executable_path/", + "build/bin/orca", ], check=True) @@ -400,8 +417,8 @@ def verify_angle(): ] elif platform.system() == "Darwin": checkfiles = [ - "milepost/lib/libEGL.dylib", - "milepost/lib/libGLESv2.dylib", + "milepost/build/bin/libEGL.dylib", + "milepost/build/bin/libGLESv2.dylib", ] if checkfiles is None: @@ -424,10 +441,15 @@ def download_angle(): print("Downloading ANGLE...") if platform.system() == "Windows": build = "windows-2019" - extensions = ["dll", "lib"] + extensions = [ + ("dll", "milepost/build/bin/"), + ("lib", "milepost/build/lib/"), + ] elif platform.system() == "Darwin": build = "macos-jank" - extensions = ["dylib"] + extensions = [ + ("dylib", "milepost/build/bin/"), + ] else: log_error(f"could not automatically download ANGLE for unknown platform {platform.system()}") return @@ -448,11 +470,12 @@ def download_angle(): with ZipFile(filepath, "r") as anglezip: anglezip.extractall(path="scripts/files") - os.makedirs("milepost/lib", exist_ok=True) + os.makedirs("milepost/build/bin", exist_ok=True) + os.makedirs("milepost/build/lib", exist_ok=True) for angleDir in ["bin", "lib"]: - for ext in extensions: + for (ext, dest) in extensions: for filepath in glob.glob(f"scripts/files/angle/{angleDir}/*.{ext}"): - shutil.copy(filepath, "milepost/lib") + shutil.copy(filepath, dest) def embed_text_glsl(outputpath, prefix, shaders): diff --git a/scripts/checksums.json b/scripts/checksums.json index f5ca541..5570ef0 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -5,6 +5,6 @@ "milepost/lib/libEGL.dll.lib": "4cec54c534136da413dea86bd271ccb9c5ae88e40aa91d1de7a01e701be8e1d7", "milepost/lib/libGLESv2.dll": "193b53b0a16b702eaa28a73e84527acf7aecfd665e3e3f54a8d9db9ae73111e1", "milepost/lib/libGLESv2.dll.lib": "ee87aac129efe8fe871825d181b85da1b1ea6626cb48be52c2e689f2804b953f", - "milepost/lib/libEGL.dylib": "96baea4b1c8578d30738764784d07b509d1153df694c094faba2ee8ccbfde2a9", - "milepost/lib/libGLESv2.dylib": "98ce9f6248a6447ba9199e96b8f6d87df9548d43ce583a2615717aab168ecb71" + "milepost/build/bin/libEGL.dylib": "96baea4b1c8578d30738764784d07b509d1153df694c094faba2ee8ccbfde2a9", + "milepost/build/bin/libGLESv2.dylib": "98ce9f6248a6447ba9199e96b8f6d87df9548d43ce583a2615717aab168ecb71" } diff --git a/scripts/mkapp.py b/scripts/mkapp.py index af5aeaa..2a97a42 100644 --- a/scripts/mkapp.py +++ b/scripts/mkapp.py @@ -33,11 +33,11 @@ def macos_make_app(args): #----------------------------------------------------------- #NOTE: copy orca runtime executable and libraries #----------------------------------------------------------- - orca_exe = args.orca_dir + '/bin/orca' - milepost_lib = args.orca_dir + '/bin/libmilepost.dylib' - gles_lib = args.orca_dir + '/bin/libGLESv2.dylib' - egl_lib = args.orca_dir + '/bin/libEGL.dylib' - renderer_lib = args.orca_dir + '/bin/mtl_renderer.metallib' + orca_exe = args.orca_dir + '/build/bin/orca' + milepost_lib = args.orca_dir + '/build/bin/libmilepost.dylib' + gles_lib = args.orca_dir + '/build/bin/libGLESv2.dylib' + egl_lib = args.orca_dir + '/build/bin/libEGL.dylib' + renderer_lib = args.orca_dir + '/build/bin/mtl_renderer.metallib' shutil.copy(orca_exe, exe_dir) shutil.copy(milepost_lib, exe_dir) @@ -169,11 +169,11 @@ def windows_make_app(args): #----------------------------------------------------------- #NOTE: copy orca runtime executable and libraries #----------------------------------------------------------- - orca_exe = args.orca_dir + '/bin/orca.exe' - milepost_lib = args.orca_dir + '/bin/milepost.dll' - gles_lib = args.orca_dir + '/milepost/bin/libGLESv2.dll' - egl_lib = args.orca_dir + '/milepost/bin/libEGL.dll' - pthread_lib = args.orca_dir + '/bin/pthreadVC3.dll' + orca_exe = args.orca_dir + '/build/bin/orca.exe' + milepost_lib = args.orca_dir + '/build/bin/milepost.dll' + gles_lib = args.orca_dir + '/milepost/build/bin/libGLESv2.dll' + egl_lib = args.orca_dir + '/milepost/build/bin/libEGL.dll' + pthread_lib = args.orca_dir + '/build/bin/pthreadVC3.dll' shutil.copy(orca_exe, exe_dir) shutil.copy(milepost_lib, exe_dir) -- 2.25.1 From bbe34a3b5818205932992a5e97f3db9833ed8bd7 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Wed, 26 Jul 2023 21:28:39 -0500 Subject: [PATCH 16/23] Move mkapp.py into a bundle command --- samples/pong/build.sh | 2 +- scripts/{mkapp.py => bundle.py} | 119 ++++++++++++----------- scripts/orca.py | 6 +- scripts/{build_runtime.py => runtime.py} | 9 +- 4 files changed, 73 insertions(+), 63 deletions(-) rename scripts/{mkapp.py => bundle.py} (64%) rename scripts/{build_runtime.py => runtime.py} (97%) diff --git a/samples/pong/build.sh b/samples/pong/build.sh index c941ae0..ee234cf 100755 --- a/samples/pong/build.sh +++ b/samples/pong/build.sh @@ -30,4 +30,4 @@ wasmFlags="--target=wasm32 \ $CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c -python3 ../../scripts/mkapp.py --orca-dir ../.. --name Pong --icon icon.png --resource-dir data module.wasm +../../scripts/orca.py bundle --orca-dir ../.. --name Pong --icon icon.png --resource-dir data module.wasm diff --git a/scripts/mkapp.py b/scripts/bundle.py similarity index 64% rename from scripts/mkapp.py rename to scripts/bundle.py index 2a97a42..1e58b73 100644 --- a/scripts/mkapp.py +++ b/scripts/bundle.py @@ -6,19 +6,53 @@ import shutil import subprocess from argparse import ArgumentParser +from log import * + + +def attach_bundle_commands(subparsers): + mkapp_cmd = subparsers.add_parser("bundle", help="Package a WebAssembly module into a standalone Orca application.") + init_parser(mkapp_cmd) + + +def init_parser(parser): + parser.add_argument("-d", "--resource", action="append", dest="resource_files", help="copy a file to the app's resource directory") + parser.add_argument("-D", "--resource-dir", action="append", dest="resource_dirs", help="copy a directory to the app's resource directory") + parser.add_argument("-i", "--icon", help="an image file to use as the application's icon") + parser.add_argument("-C", "--out-dir", default=os.getcwd(), help="where to place the final application bundle (defaults to the current directory)") + parser.add_argument("-n", "--name", default="out", help="the app's name") + parser.add_argument("-O", "--orca-dir", default=".") + parser.add_argument("--version", default="0.0.0", help="a version number to embed in the application bundle") + parser.add_argument("module", help="a .wasm file containing the application's wasm module") + parser.set_defaults(func=shellish(make_app)) + + +def make_app(args): + #----------------------------------------------------------- + # Dispatch to platform-specific function + #----------------------------------------------------------- + platformName = platform.system() + if platformName == 'Darwin': + macos_make_app(args) + elif platformName == 'Windows': + windows_make_app(args) + else: + log_error("Platform '" + platformName + "' is not supported for now...") + exit(1) + + def macos_make_app(args): #----------------------------------------------------------- #NOTE: make bundle directory structure #----------------------------------------------------------- app_name = args.name bundle_name = app_name + '.app' - bundle_path = args.out_dir + '/' + bundle_name - contents_dir = bundle_path + '/Contents' - exe_dir = contents_dir + '/MacOS' - res_dir = contents_dir + '/resources' - guest_dir = contents_dir + '/app' - wasm_dir = guest_dir + '/wasm' - data_dir = guest_dir + '/data' + bundle_path = os.path.join(args.out_dir, bundle_name) + contents_dir = os.path.join(bundle_path, 'Contents') + exe_dir = os.path.join(contents_dir, 'MacOS') + res_dir = os.path.join(contents_dir, 'resources') + guest_dir = os.path.join(contents_dir, 'app') + wasm_dir = os.path.join(guest_dir, 'wasm') + data_dir = os.path.join(guest_dir, 'data') if os.path.exists(bundle_path): shutil.rmtree(bundle_path) @@ -33,11 +67,11 @@ def macos_make_app(args): #----------------------------------------------------------- #NOTE: copy orca runtime executable and libraries #----------------------------------------------------------- - orca_exe = args.orca_dir + '/build/bin/orca' - milepost_lib = args.orca_dir + '/build/bin/libmilepost.dylib' - gles_lib = args.orca_dir + '/build/bin/libGLESv2.dylib' - egl_lib = args.orca_dir + '/build/bin/libEGL.dylib' - renderer_lib = args.orca_dir + '/build/bin/mtl_renderer.metallib' + orca_exe = os.path.join(args.orca_dir, 'build/bin/orca') + milepost_lib = os.path.join(args.orca_dir, 'build/bin/libmilepost.dylib') + gles_lib = os.path.join(args.orca_dir, 'build/bin/libGLESv2.dylib') + egl_lib = os.path.join(args.orca_dir, 'build/bin/libEGL.dylib') + renderer_lib = os.path.join(args.orca_dir, 'build/bin/mtl_renderer.metallib') shutil.copy(orca_exe, exe_dir) shutil.copy(milepost_lib, exe_dir) @@ -48,18 +82,18 @@ def macos_make_app(args): #----------------------------------------------------------- #NOTE: copy wasm module and data #----------------------------------------------------------- - shutil.copy(args.module, wasm_dir + '/module.wasm') + shutil.copy(args.module, os.path.join(wasm_dir, 'module.wasm')) if args.resource_files != None: for resource in args.resource_files: - shutil.copytree(resource, data_dir + '/' + os.path.basename(resource), dirs_exist_ok=True) + shutil.copytree(resource, os.path.join(data_dir, os.path.basename(resource)), dirs_exist_ok=True) if args.resource_dirs != None: for resource_dir in args.resource_dirs: for resource in os.listdir(resource_dir): - src = resource_dir + '/' + resource + src = os.path.join(resource_dir, resource) if os.path.isdir(src): - shutil.copytree(src, data_dir + '/' + os.path.basename(resource), dirs_exist_ok=True) + shutil.copytree(src, os.path.join(data_dir, os.path.basename(resource)), dirs_exist_ok=True) else: shutil.copy(src, data_dir) @@ -67,15 +101,15 @@ def macos_make_app(args): #NOTE: copy runtime resources #----------------------------------------------------------- # default fonts - shutil.copy(args.orca_dir + '/resources/OpenSansLatinSubset.ttf', res_dir) - shutil.copy(args.orca_dir + '/resources/Menlo.ttf', res_dir) - shutil.copy(args.orca_dir + '/resources/Menlo Bold.ttf', res_dir) - shutil.copy(args.orca_dir + '/resources/Menlo Italics.ttf', res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/OpenSansLatinSubset.ttf'), res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/Menlo.ttf'), res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/Menlo Bold.ttf'), res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/Menlo Italics.ttf'), res_dir) #----------------------------------------------------------- #NOTE make icon #----------------------------------------------------------- - src_image=args.icon + src_image = args.icon #if src_image == None: # src_image = orca_dir + '/resources/default_app_icon.png' @@ -104,7 +138,7 @@ def macos_make_app(args): size = size*2 - subprocess.run(['iconutil', '-c', 'icns', '-o', res_dir + '/icon.icns', iconset]) + subprocess.run(['iconutil', '-c', 'icns', '-o', os.path.join(res_dir, 'icon.icns'), iconset]) shutil.rmtree(iconset) #----------------------------------------------------------- @@ -114,7 +148,7 @@ def macos_make_app(args): bundle_sig = "????" icon_file = '' - plist_contents = """ + plist_contents = f""" @@ -139,7 +173,7 @@ def macos_make_app(args): True - """.format(app_name=app_name, version=version, bundle_sig=bundle_sig, icon_file=icon_file) + """ plist_file = open(contents_dir + '/Info.plist', 'w') print(plist_contents, file=plist_file) @@ -214,37 +248,8 @@ def windows_make_app(args): #----------------------------------------------------------- #TODO -#--------------------------------------------------------------------------------------------- -# NOTE: get args -# -# mkapp.py [options] module -# -# -n, --name the name of the app -# -r, --res-file copies a file to the app bundle's resource directory -# -R, --res-dir copies the contents of a directory to the bundle's resource directory -# -i, --icon icon file -# -D, --out-dir output directory -#---------------------------------------------------------------------------------------------- +if __name__ == "__main__": + parser = ArgumentParser(prog='mkapp') + init_parser(parser) -parser = ArgumentParser(prog='mkapp') -parser.add_argument("-d", "--resource", action='append', dest='resource_files') -parser.add_argument("-D", "--resource-dir", action='append', dest='resource_dirs') -parser.add_argument("-i", "--icon") -parser.add_argument("-C", "--out-dir", default=os.getcwd()) -parser.add_argument("-n", "--name", default='out') -parser.add_argument("-O", "--orca-dir", default='.') -parser.add_argument("--version", default='0.0.0') -parser.add_argument("module") - -args = parser.parse_args() - -#---------------------------------------------------------------------------------------------- -# Dispatch to platform-specific function -#---------------------------------------------------------------------------------------------- -platformName = platform.system() -if platformName == 'Darwin': - macos_make_app(args) -elif platformName == 'Windows': - windows_make_app(args) -else: - print("Platform '" + platformName + "' is not supported for now...") + args = parser.parse_args() diff --git a/scripts/orca.py b/scripts/orca.py index 5b9c3b4..104f5f0 100755 --- a/scripts/orca.py +++ b/scripts/orca.py @@ -2,12 +2,14 @@ import argparse -from build_runtime import attach_build_runtime +from bundle import attach_bundle_commands +from runtime import attach_runtime_commands parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(required=True, title='commands') -attach_build_runtime(subparsers) +attach_bundle_commands(subparsers) +attach_runtime_commands(subparsers) args = parser.parse_args() args.func(args) diff --git a/scripts/build_runtime.py b/scripts/runtime.py similarity index 97% rename from scripts/build_runtime.py rename to scripts/runtime.py index 2a7339b..4cb62d7 100644 --- a/scripts/build_runtime.py +++ b/scripts/runtime.py @@ -18,12 +18,15 @@ from utils import pushd, removeall ANGLE_VERSION = "2023-07-05" -def attach_build_runtime(subparsers): - build_cmd = subparsers.add_parser("build-runtime", help="TODO") +def attach_runtime_commands(subparsers): + runtime_cmd = subparsers.add_parser("runtime", help="Commands for building the Orca runtime") + runtime_sub = runtime_cmd.add_subparsers(required=True, title='commands') + + build_cmd = runtime_sub.add_parser("build", help="Build the Orca runtime from source.") build_cmd.add_argument("--release", action="store_true", help="compile Orca in release mode (default is debug)") build_cmd.set_defaults(func=shellish(build_runtime)) - clean_cmd = subparsers.add_parser("clean", help="Delete all build artifacts and start fresh") + clean_cmd = runtime_sub.add_parser("clean", help="Delete all build artifacts and start fresh.") clean_cmd.set_defaults(func=shellish(clean)) -- 2.25.1 From 59f87436ce5eafc9418d131d7d10d14acc903ce3 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 29 Jul 2023 14:03:44 -0500 Subject: [PATCH 17/23] Isolate dev commands to only run in Orca source --- .orcaroot | 3 +++ scripts/{runtime.py => dev.py} | 25 ++++++++++++++++++++----- scripts/{orca.py => orca} | 4 ++-- 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 .orcaroot rename scripts/{runtime.py => dev.py} (94%) rename scripts/{orca.py => orca} (76%) diff --git a/.orcaroot b/.orcaroot new file mode 100644 index 0000000..394e764 --- /dev/null +++ b/.orcaroot @@ -0,0 +1,3 @@ +You are currently at the root of the Orca source. Welcome. + +This file exists to signal to the Orca CLI that you are in the Orca source and can do Orca source things. When the CLI detects this file, it will ignore the system Orca installation and use only the contents of this current source checkout. diff --git a/scripts/runtime.py b/scripts/dev.py similarity index 94% rename from scripts/runtime.py rename to scripts/dev.py index 4cb62d7..8b453b4 100644 --- a/scripts/runtime.py +++ b/scripts/dev.py @@ -18,18 +18,33 @@ from utils import pushd, removeall ANGLE_VERSION = "2023-07-05" -def attach_runtime_commands(subparsers): - runtime_cmd = subparsers.add_parser("runtime", help="Commands for building the Orca runtime") - runtime_sub = runtime_cmd.add_subparsers(required=True, title='commands') +def attach_dev_commands(subparsers): + dev_cmd = subparsers.add_parser("dev", help="Commands for building Orca itself. Must be run from the root of an Orca source checkout.") - build_cmd = runtime_sub.add_parser("build", help="Build the Orca runtime from source.") + try: + os.stat(".orcaroot") + except FileNotFoundError: + dev_cmd.set_defaults(func=orca_root_only) + return + + dev_sub = dev_cmd.add_subparsers(required=True, title='commands') + + build_cmd = dev_sub.add_parser("build-runtime", help="Build the Orca runtime from source.") build_cmd.add_argument("--release", action="store_true", help="compile Orca in release mode (default is debug)") build_cmd.set_defaults(func=shellish(build_runtime)) - clean_cmd = runtime_sub.add_parser("clean", help="Delete all build artifacts and start fresh.") + clean_cmd = dev_sub.add_parser("clean", help="Delete all build artifacts and start fresh.") clean_cmd.set_defaults(func=shellish(clean)) +def orca_root_only(args): + print("The Orca dev commands can only be run from an Orca source checkout.") + print() + print("If you want to build Orca yourself, download the source here:") + print("https://git.handmade.network/hmn/orca") + exit(1) + + def build_runtime(args): ensure_programs() ensure_angle() diff --git a/scripts/orca.py b/scripts/orca similarity index 76% rename from scripts/orca.py rename to scripts/orca index 104f5f0..f8b9750 100755 --- a/scripts/orca.py +++ b/scripts/orca @@ -3,13 +3,13 @@ import argparse from bundle import attach_bundle_commands -from runtime import attach_runtime_commands +from dev import attach_dev_commands parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(required=True, title='commands') attach_bundle_commands(subparsers) -attach_runtime_commands(subparsers) +attach_dev_commands(subparsers) args = parser.parse_args() args.func(args) -- 2.25.1 From 956ad51072bbc292a3a618b050bf44581faa2f61 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 29 Jul 2023 15:11:20 -0500 Subject: [PATCH 18/23] Add Orca install workflow --- orca | 31 ++++++++++++++++ scripts/bundle.py | 2 +- scripts/checksum.py | 2 +- scripts/dev.py | 77 ++++++++++++++++++++++++++++++--------- scripts/{orca => orca.py} | 4 +- 5 files changed, 95 insertions(+), 21 deletions(-) create mode 100755 orca rename scripts/{orca => orca.py} (76%) mode change 100755 => 100644 diff --git a/orca b/orca new file mode 100755 index 0000000..17ee216 --- /dev/null +++ b/orca @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +# This file is copied into the user's home directory on install, +# but also can be run from the root of an Orca source checkout. + +import os +import sys + + +root = True +try: + os.stat(".orcaroot") +except FileNotFoundError: + root = False + +if root: + # Running from Orca source checkout; use local source's scripts. + + scriptdir = os.path.dirname(os.path.abspath(__file__)) + if scriptdir != os.getcwd(): + # Only print this warning if running the system-installed Orca. + # It's annoying to see this if you run ./orca from the source. + print("The Orca tool is running from a local source checkout and will") + print("use that instead of the system Orca installation.") + print() + + sys.path.append(os.getcwd()) + import scripts.orca +else: + # Running from outside Orca source checkout; use system Orca install. + import sys_scripts.orca diff --git a/scripts/bundle.py b/scripts/bundle.py index 1e58b73..ca7a62c 100644 --- a/scripts/bundle.py +++ b/scripts/bundle.py @@ -6,7 +6,7 @@ import shutil import subprocess from argparse import ArgumentParser -from log import * +from .log import * def attach_bundle_commands(subparsers): diff --git a/scripts/checksum.py b/scripts/checksum.py index e404081..972ce9a 100644 --- a/scripts/checksum.py +++ b/scripts/checksum.py @@ -1,7 +1,7 @@ import hashlib import json -from log import * +from .log import * def checkfile(filepath): diff --git a/scripts/dev.py b/scripts/dev.py index 8b453b4..d9a4574 100644 --- a/scripts/dev.py +++ b/scripts/dev.py @@ -8,11 +8,11 @@ import shutil import subprocess from zipfile import ZipFile -import checksum -from bindgen import bindgen -from bindgen2 import bindgen2 -from log import * -from utils import pushd, removeall +from . import checksum +from .bindgen import bindgen +from .bindgen2 import bindgen2 +from .log import * +from .utils import pushd, removeall ANGLE_VERSION = "2023-07-05" @@ -20,21 +20,28 @@ ANGLE_VERSION = "2023-07-05" def attach_dev_commands(subparsers): dev_cmd = subparsers.add_parser("dev", help="Commands for building Orca itself. Must be run from the root of an Orca source checkout.") + dev_cmd.set_defaults(func=orca_root_only) - try: - os.stat(".orcaroot") - except FileNotFoundError: - dev_cmd.set_defaults(func=orca_root_only) - return - - dev_sub = dev_cmd.add_subparsers(required=True, title='commands') + dev_sub = dev_cmd.add_subparsers(required=is_orca_root(), title='commands') build_cmd = dev_sub.add_parser("build-runtime", help="Build the Orca runtime from source.") build_cmd.add_argument("--release", action="store_true", help="compile Orca in release mode (default is debug)") - build_cmd.set_defaults(func=shellish(build_runtime)) + build_cmd.set_defaults(func=dev_shellish(build_runtime)) clean_cmd = dev_sub.add_parser("clean", help="Delete all build artifacts and start fresh.") - clean_cmd.set_defaults(func=shellish(clean)) + clean_cmd.set_defaults(func=dev_shellish(clean)) + + install_cmd = dev_sub.add_parser("install", help="Install the Orca tools into a system folder.") + install_cmd.add_argument("--no-confirm", action="store_true", help="don't ask the user for confirmation before installing") + install_cmd.set_defaults(func=dev_shellish(install)) + + +def is_orca_root(): + try: + os.stat(".orcaroot") + return True + except FileNotFoundError: + return False def orca_root_only(args): @@ -45,6 +52,10 @@ def orca_root_only(args): exit(1) +def dev_shellish(func): + return shellish(func) if is_orca_root() else orca_root_only + + def build_runtime(args): ensure_programs() ensure_angle() @@ -55,9 +66,6 @@ def build_runtime(args): def clean(args): - def yeet(path): - os.makedirs(path, exist_ok=True) - shutil.rmtree(path) yeet("build") yeet("milepost/build") yeet("scripts/files") @@ -530,3 +538,38 @@ def embed_text_glsl(outputpath, prefix, shaders): output.write("#endif // __%s_H__\n" % outSymbol) output.close() + + +def yeet(path): + os.makedirs(path, exist_ok=True) + shutil.rmtree(path) + + +def install(args): + if not args.no_confirm: + dest = os.path.expanduser(os.path.join("~", ".orca")) + + print("The Orca command-line tools will be installed to your home directory in:") + print(dest) + print() + while True: + answer = input("Proceed with the installation? (y/n) >") + if answer.lower() in ["y", "yes"]: + break + elif answer.lower() in ["n", "no"]: + return + else: + print("Please enter \"yes\" or \"no\" and press return.") + + bin_dir = os.path.join(dest, "bin") + yeet(bin_dir) + shutil.copytree("scripts", os.path.join(bin_dir, "sys_scripts")) + shutil.copy("orca", bin_dir) + + # TODO: Customize these instructions for Windows + print() + print("Orca has been installed. Make sure the Orca tools are on your PATH by adding the") + print("following to your shell config:") + print() + print(f"export PATH=\"{bin_dir}:$PATH\"") + print() diff --git a/scripts/orca b/scripts/orca.py old mode 100755 new mode 100644 similarity index 76% rename from scripts/orca rename to scripts/orca.py index f8b9750..f161b05 --- a/scripts/orca +++ b/scripts/orca.py @@ -2,8 +2,8 @@ import argparse -from bundle import attach_bundle_commands -from dev import attach_dev_commands +from .bundle import attach_bundle_commands +from .dev import attach_dev_commands parser = argparse.ArgumentParser() -- 2.25.1 From 9a2c4d887603f5d950a0423670e5a0b985513e0e Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 29 Jul 2023 15:22:03 -0500 Subject: [PATCH 19/23] Fix bug with --no-confirm --- scripts/dev.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/dev.py b/scripts/dev.py index d9a4574..9ca30b7 100644 --- a/scripts/dev.py +++ b/scripts/dev.py @@ -546,9 +546,9 @@ def yeet(path): def install(args): - if not args.no_confirm: - dest = os.path.expanduser(os.path.join("~", ".orca")) + dest = os.path.expanduser(os.path.join("~", ".orca")) + if not args.no_confirm: print("The Orca command-line tools will be installed to your home directory in:") print(dest) print() @@ -561,15 +561,15 @@ def install(args): else: print("Please enter \"yes\" or \"no\" and press return.") - bin_dir = os.path.join(dest, "bin") - yeet(bin_dir) - shutil.copytree("scripts", os.path.join(bin_dir, "sys_scripts")) - shutil.copy("orca", bin_dir) + bin_dir = os.path.join(dest, "bin") + yeet(bin_dir) + shutil.copytree("scripts", os.path.join(bin_dir, "sys_scripts")) + shutil.copy("orca", bin_dir) - # TODO: Customize these instructions for Windows - print() - print("Orca has been installed. Make sure the Orca tools are on your PATH by adding the") - print("following to your shell config:") - print() - print(f"export PATH=\"{bin_dir}:$PATH\"") - print() + # TODO: Customize these instructions for Windows + print() + print("The Orca tools have been installed. Make sure the Orca tools are on your PATH by") + print("adding the following to your shell config:") + print() + print(f"export PATH=\"{bin_dir}:$PATH\"") + print() -- 2.25.1 From ed5dbc00539e5523f327c2d362de486ce1d88836 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 29 Jul 2023 15:23:10 -0500 Subject: [PATCH 20/23] Use system orca in pong example --- samples/pong/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/pong/build.sh b/samples/pong/build.sh index ee234cf..c53ab3b 100755 --- a/samples/pong/build.sh +++ b/samples/pong/build.sh @@ -30,4 +30,4 @@ wasmFlags="--target=wasm32 \ $CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c -../../scripts/orca.py bundle --orca-dir ../.. --name Pong --icon icon.png --resource-dir data module.wasm +orca bundle --orca-dir ../.. --name Pong --icon icon.png --resource-dir data module.wasm -- 2.25.1 From 4b1649f8bbcea6759489e820fe08834c4f4d4086 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sat, 29 Jul 2023 15:26:28 -0500 Subject: [PATCH 21/23] Use system orca for UI example too --- samples/ui/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 samples/ui/build.sh diff --git a/samples/ui/build.sh b/samples/ui/build.sh old mode 100644 new mode 100755 index 937eb18..8001b8d --- a/samples/ui/build.sh +++ b/samples/ui/build.sh @@ -24,4 +24,4 @@ wasmFlags="--target=wasm32 \ $CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c -python3 ../../scripts/mkapp.py --orca-dir ../.. --name UI --resource-dir data module.wasm +orca bundle --orca-dir ../.. --name UI --resource-dir data module.wasm -- 2.25.1 From 260872546b7200d89fd6b483162d7433c5d2d835 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Mon, 7 Aug 2023 22:10:32 -0500 Subject: [PATCH 22/23] Get it all working on Windows again for real --- orca.bat | 7 ++++ samples/pong/build.bat | 2 +- samples/ui/build.bat | 2 +- scripts/bundle.py | 28 ++++++++-------- scripts/checksums.json | 8 ++--- scripts/dev.py | 74 ++++++++++++++++++++++++------------------ 6 files changed, 70 insertions(+), 51 deletions(-) create mode 100644 orca.bat diff --git a/orca.bat b/orca.bat new file mode 100644 index 0000000..99adab7 --- /dev/null +++ b/orca.bat @@ -0,0 +1,7 @@ +@echo off + +rem Get the directory of this batch script +set "script_dir=%~dp0" + +python3 "%script_dir%orca" %* +exit /b %errorlevel% diff --git a/samples/pong/build.bat b/samples/pong/build.bat index 7ba6677..4cd29cb 100644 --- a/samples/pong/build.bat +++ b/samples/pong/build.bat @@ -14,4 +14,4 @@ set wasmFlags=--target=wasm32^ clang %wasmFlags% -o .\module.wasm ..\..\sdk\orca.c ..\..\cstdlib\src\*.c src\main.c -python3 ..\..\scripts\mkapp.py --orca-dir ..\.. --name Pong --icon icon.png --resource-dir data module.wasm +orca bundle --orca-dir ..\.. --name Pong --icon icon.png --resource-dir data module.wasm diff --git a/samples/ui/build.bat b/samples/ui/build.bat index 768432c..5717a40 100644 --- a/samples/ui/build.bat +++ b/samples/ui/build.bat @@ -14,4 +14,4 @@ set wasmFlags=--target=wasm32^ clang %wasmFlags% -o .\module.wasm ..\..\sdk\orca.c ..\..\cstdlib\src\*.c src\main.c -python3 ..\..\scripts\mkapp.py --orca-dir ..\.. --name UI --resource-dir data module.wasm +orca bundle --orca-dir ..\.. --name UI --resource-dir data module.wasm diff --git a/scripts/bundle.py b/scripts/bundle.py index 10f7ae7..1cd4791 100644 --- a/scripts/bundle.py +++ b/scripts/bundle.py @@ -184,12 +184,12 @@ def windows_make_app(args): #----------------------------------------------------------- app_name = args.name bundle_name = app_name - bundle_dir = args.out_dir + '/' + bundle_name - exe_dir = bundle_dir + '/bin' - res_dir = bundle_dir + '/resources' - guest_dir = bundle_dir + '/app' - wasm_dir = guest_dir + '/wasm' - data_dir = guest_dir + '/data' + bundle_dir = os.path.join(args.out_dir, bundle_name) + exe_dir = os.path.join(bundle_dir, 'bin') + res_dir = os.path.join(bundle_dir, 'resources') + guest_dir = os.path.join(bundle_dir, 'app') + wasm_dir = os.path.join(guest_dir, 'wasm') + data_dir = os.path.join(guest_dir, 'data') if os.path.exists(bundle_dir): shutil.rmtree(bundle_dir) @@ -203,10 +203,10 @@ def windows_make_app(args): #----------------------------------------------------------- #NOTE: copy orca runtime executable and libraries #----------------------------------------------------------- - orca_exe = args.orca_dir + '/build/bin/orca.exe' - milepost_lib = args.orca_dir + '/build/bin/milepost.dll' - gles_lib = args.orca_dir + '/milepost/build/bin/libGLESv2.dll' - egl_lib = args.orca_dir + '/milepost/build/bin/libEGL.dll' + orca_exe = os.path.join(args.orca_dir, 'build/bin/orca.exe') + milepost_lib = os.path.join(args.orca_dir, 'build/bin/milepost.dll') + gles_lib = os.path.join(args.orca_dir, 'milepost/build/bin/libGLESv2.dll') + egl_lib = os.path.join(args.orca_dir, 'milepost/build/bin/libEGL.dll') shutil.copy(orca_exe, exe_dir) shutil.copy(milepost_lib, exe_dir) @@ -236,10 +236,10 @@ def windows_make_app(args): #NOTE: copy runtime resources #----------------------------------------------------------- # default fonts - shutil.copy(args.orca_dir + '/resources/OpenSansLatinSubset.ttf', res_dir) - shutil.copy(args.orca_dir + '/resources/Menlo.ttf', res_dir) - shutil.copy(args.orca_dir + '/resources/Menlo Bold.ttf', res_dir) - shutil.copy(args.orca_dir + '/resources/Menlo Italics.ttf', res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/OpenSansLatinSubset.ttf'), res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/Menlo.ttf'), res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/Menlo Bold.ttf'), res_dir) + shutil.copy(os.path.join(args.orca_dir, 'resources/Menlo Italics.ttf'), res_dir) #----------------------------------------------------------- #NOTE make icon diff --git a/scripts/checksums.json b/scripts/checksums.json index 5570ef0..74cea47 100644 --- a/scripts/checksums.json +++ b/scripts/checksums.json @@ -1,10 +1,10 @@ { "scripts/files/angle-windows-2019-2023-07-05.zip": "a333b5ccc8462151ee8df65c43cfacd70d9db2413f2e495da65670737b5b2d96", "scripts/files/angle-macos-jank-2023-07-05.zip": "c234b8db179a24757ab9f46610a032123718dd9bed967d2bf8e27d0d17eb0aff", - "milepost/lib/libEGL.dll": "b7bf51f83e88129ddc20c0c2cb904ec04c89059a30a2cd29b9b1ea11c80388fb", - "milepost/lib/libEGL.dll.lib": "4cec54c534136da413dea86bd271ccb9c5ae88e40aa91d1de7a01e701be8e1d7", - "milepost/lib/libGLESv2.dll": "193b53b0a16b702eaa28a73e84527acf7aecfd665e3e3f54a8d9db9ae73111e1", - "milepost/lib/libGLESv2.dll.lib": "ee87aac129efe8fe871825d181b85da1b1ea6626cb48be52c2e689f2804b953f", + "milepost/build/bin/libEGL.dll": "b7bf51f83e88129ddc20c0c2cb904ec04c89059a30a2cd29b9b1ea11c80388fb", + "milepost/build/bin/libEGL.dll.lib": "4cec54c534136da413dea86bd271ccb9c5ae88e40aa91d1de7a01e701be8e1d7", + "milepost/build/bin/libGLESv2.dll": "193b53b0a16b702eaa28a73e84527acf7aecfd665e3e3f54a8d9db9ae73111e1", + "milepost/build/bin/libGLESv2.dll.lib": "ee87aac129efe8fe871825d181b85da1b1ea6626cb48be52c2e689f2804b953f", "milepost/build/bin/libEGL.dylib": "96baea4b1c8578d30738764784d07b509d1153df694c094faba2ee8ccbfde2a9", "milepost/build/bin/libGLESv2.dylib": "98ce9f6248a6447ba9199e96b8f6d87df9548d43ce583a2615717aab168ecb71" } diff --git a/scripts/dev.py b/scripts/dev.py index 9f3e33d..571b9d0 100644 --- a/scripts/dev.py +++ b/scripts/dev.py @@ -129,7 +129,7 @@ def build_milepost_lib_win(release): "ole32.lib", "shell32.lib", "shlwapi.lib", - "/LIBPATH:./bin", + "/LIBPATH:./build/bin", "libEGL.dll.lib", "libGLESv2.dll.lib", "/DELAYLOAD:libEGL.dll", @@ -137,17 +137,17 @@ def build_milepost_lib_win(release): ] subprocess.run([ - "cl", + "cl", "/nologo", "/we4013", "/Zi", "/Zc:preprocessor", "/DMP_BUILD_DLL", "/std:c11", "/experimental:c11atomics", *includes, - "src/milepost.c", "/Fo:bin/milepost.o", + "src/milepost.c", "/Fo:build/bin/milepost.o", "/LD", "/link", "/MANIFEST:EMBED", "/MANIFESTINPUT:src/win32_manifest.xml", *libs, - "/OUT:bin/milepost.dll", - "/IMPLIB:bin/milepost.dll.lib", + "/OUT:build/bin/milepost.dll", + "/IMPLIB:build/bin/milepost.dll.lib", ], check=True) @@ -240,19 +240,19 @@ def build_wasm3(release): def build_wasm3_lib_win(release): - for f in glob.iglob(".\\ext\\wasm3\\source\\*.c"): + for f in glob.iglob("./ext/wasm3/source/*.c"): name = os.path.splitext(os.path.basename(f))[0] subprocess.run([ "cl", "/nologo", "/Zi", "/Zc:preprocessor", "/c", - *(["/O2"] if release else []), - f"/Fo:bin\\obj\\{name}.obj", - "/I", ".\\ext\\wasm3\\source", + "/O2", + f"/Fo:build/obj/{name}.obj", + "/I", "./ext/wasm3/source", f, ], check=True) subprocess.run([ - "lib", "/nologo", "/out:bin\\wasm3.lib", - "bin\\obj\\*.obj", + "lib", "/nologo", "/out:build/bin/wasm3.lib", + "build/obj/*.obj", ], check=True) @@ -294,8 +294,8 @@ def build_orca(release): def build_orca_win(release): # copy libraries - shutil.copy("milepost\\bin\\milepost.dll", "bin") - shutil.copy("milepost\\bin\\milepost.dll.lib", "bin") + shutil.copy("milepost/build/bin/milepost.dll", "build/bin") + shutil.copy("milepost/build/bin/milepost.dll.lib", "build/bin") gen_all_bindings() @@ -303,12 +303,12 @@ def build_orca_win(release): includes = [ "/I", "src", "/I", "sdk", - "/I", "ext\wasm3\source", - "/I", "milepost\src", - "/I", "milepost\ext", + "/I", "ext/wasm3/source", + "/I", "milepost/src", + "/I", "milepost/ext", ] libs = [ - "/LIBPATH:bin", + "/LIBPATH:build/bin", "milepost.dll.lib", "wasm3.lib", ] @@ -318,9 +318,9 @@ def build_orca_win(release): "/Zi", "/Zc:preprocessor", "/std:c11", "/experimental:c11atomics", *includes, - "src\\main.c", + "src/main.c", "/link", *libs, - "/out:bin\\orca.exe", + "/out:build/bin/orca.exe", ], check=True) @@ -433,10 +433,10 @@ def verify_angle(): checkfiles = None if platform.system() == "Windows": checkfiles = [ - "milepost/lib/libEGL.dll", - "milepost/lib/libEGL.dll.lib", - "milepost/lib/libGLESv2.dll", - "milepost/lib/libGLESv2.dll.lib", + "milepost/build/bin/libEGL.dll", + "milepost/build/bin/libEGL.dll.lib", + "milepost/build/bin/libGLESv2.dll", + "milepost/build/bin/libGLESv2.dll.lib", ] elif platform.system() == "Darwin": checkfiles = [ @@ -466,7 +466,7 @@ def download_angle(): build = "windows-2019" extensions = [ ("dll", "milepost/build/bin/"), - ("lib", "milepost/build/lib/"), + ("lib", "milepost/build/bin/"), ] elif platform.system() == "Darwin": build = "macos-jank" @@ -494,7 +494,6 @@ def download_angle(): anglezip.extractall(path="scripts/files") os.makedirs("milepost/build/bin", exist_ok=True) - os.makedirs("milepost/build/lib", exist_ok=True) for angleDir in ["bin", "lib"]: for (ext, dest) in extensions: for filepath in glob.glob(f"scripts/files/angle/{angleDir}/*.{ext}"): @@ -543,10 +542,13 @@ def yeet(path): def install(args): - dest = os.path.expanduser(os.path.join("~", ".orca")) + if platform.system() == "Windows": + dest = os.path.join(os.getenv("LOCALAPPDATA"), "orca") + else: + dest = os.path.expanduser(os.path.join("~", ".orca")) if not args.no_confirm: - print("The Orca command-line tools will be installed to your home directory in:") + print("The Orca command-line tools will be installed to:") print(dest) print() while True: @@ -562,11 +564,21 @@ def install(args): yeet(bin_dir) shutil.copytree("scripts", os.path.join(bin_dir, "sys_scripts")) shutil.copy("orca", bin_dir) + if platform.system() == "Windows": + shutil.copy("orca.bat", bin_dir) # TODO: Customize these instructions for Windows print() - print("The Orca tools have been installed. Make sure the Orca tools are on your PATH by") - print("adding the following to your shell config:") - print() - print(f"export PATH=\"{bin_dir}:$PATH\"") + if platform.system() == "Windows": + print("The Orca tools have been installed. Make sure the Orca tools are on your PATH by") + print("adding the following path to your system PATH variable:") + print() + print(bin_dir) + print() + print("You can do this in the Windows settings by searching for \"environment variables\".") + else: + print("The Orca tools have been installed. Make sure the Orca tools are on your PATH by") + print("adding the following to your shell config:") + print() + print(f"export PATH=\"{bin_dir}:$PATH\"") print() -- 2.25.1 From 964dcf36982797b5f4f30b6b08e932d3c6e82723 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Tue, 8 Aug 2023 11:38:00 +0200 Subject: [PATCH 23/23] update milepost --- milepost | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/milepost b/milepost index 6221370..c103c00 160000 --- a/milepost +++ b/milepost @@ -1 +1 @@ -Subproject commit 6221370aa0e8c520ebde179a1e715a8ed2e28611 +Subproject commit c103c001f7c8e780602193f22360201810802438 -- 2.25.1