#!/usr/bin/python3 -u from pathlib import Path import glob import json import os import subprocess import sys import time if len(sys.argv) < 2: raise ValueError('wrong number of arguments') home_path = str(Path.home()) + '/' project_path = sys.argv[1] + '/' project_name = project_path.rsplit('/')[-2] build_options_file = project_path + 'build_options.json' try: build_options = json.loads(open(build_options_file, "rb").read()) except: build_options = {} # Default settings default_settings = { 'isoc_file': project_path + 'build/isoc/NeinTerm.ISO.C', 'redsea_path': project_path + 'build/redsea', 'jakt_compiler_path': home_path + 'cloned/jakt/build/bin/jakt', 'jakt_runtime_path': home_path + 'cloned/jakt/runtime', 'jakt_lib_path': home_path + 'cloned/jakt/build/lib/x86_64-unknown-linux-unknown/', 'qemu_bin_path': 'qemu-system-x86_64', 'qemu_slipstream_iso_file': project_path + 'build/isoc/bootable.iso', 'templeos_iso_file': home_path + 'iso/TempleOS.ISO' } isoc_file = build_options['isoc_file'] if 'isoc_file' in build_options else default_settings['isoc_file'] redsea_path = build_options['redsea_path'] if 'redsea_path' in build_options else default_settings['redsea_path'] jakt_compiler_path = build_options['jakt_compiler_path'] if 'jakt_compiler_path' in build_options else default_settings['jakt_compiler_path'] jakt_runtime_path = build_options['jakt_runtime_path'] if 'jakt_runtime_path' in build_options else default_settings['jakt_runtime_path'] jakt_lib_path = build_options['jakt_lib_path'] if 'jakt_lib_path' in build_options else default_settings['jakt_lib_path'] qemu_bin_path = build_options['qemu_bin_path'] if 'qemu_bin_path' in build_options else default_settings['qemu_bin_path'] qemu_slipstream_iso_file = build_options['qemu_slipstream_iso_file'] if 'qemu_slipstream_iso_file' in build_options else default_settings['qemu_slipstream_iso_file'] templeos_iso_file = build_options['templeos_iso_file'] if 'templeos_iso_file' in build_options else default_settings['templeos_iso_file'] qemu_args = build_options['qemu_args'] if 'qemu_args' in build_options else [ '-display sdl,grab-mod=rctrl', '-enable-kvm', '-machine vmport=on', '-smp cores=4', '-m 4096', '-netdev tap,id=mynet0,ifname=tap0,script=no,downscript=no', '-device ac97', '-device virtio-net,netdev=mynet0', '-device vmware-svga', '-cdrom ' + qemu_slipstream_iso_file, '-debugcon stdio', '-boot d' ] qemu_run_cmd = ' '.join([qemu_bin_path] + qemu_args) def build_options_bool(key): if key not in build_options: return False return build_options[key] == True def clang_format_src_files(): print("build-all: clang-format-src-files") exclude_paths = ["stb_", "openlibm", "tlse", ".iso.c"] format_file_extensions = [".c", ".cpp", ".h", ".hc"] for src_file in glob.glob(project_path + "**", recursive=True): exclude_file = False for exclude_path in exclude_paths: if src_file.lower().find(exclude_path) > 0: exclude_file = True if exclude_file: continue for format_file_extension in format_file_extensions: if src_file.lower().endswith(format_file_extension): print(src_file) res = os.system('clang-format -i --style=file:' + project_path + '.clang-format ' + src_file) if res: raise ValueError("build-all: step 'clang-format-src-files' failed, error code " + str(res)) def refresh_build_path(): print("build-all: refresh-build-path") res = os.system('rm -rf ' + project_path + 'build && mkdir -p ' + project_path + 'build/bin && mkdir -p ' + project_path + 'build/isoc && mkdir -p ' + project_path + 'build/lib && mkdir -p ' + project_path + 'build/redsea') if res: raise ValueError("build-all: step 'refresh-build-path' failed, error code " + str(res)) def build_image(): print("build-all: build-image") build_specific_options = '-Wl,--section-start=.text=0x1004000 -Wl,--section-start=.plt=0x1002020 -no-pie' res = os.system('cd ' + project_path + '&& cd src/image && gcc -o ../../build/bin/image ' + build_specific_options + ' -O0 -mno-mmx -mno-red-zone image.c') if res: raise ValueError("build-all: step 'build-image' failed, error code " + str(res)) def build_libtemple(): print("build-all: build-libtemple") res = os.system('cd ' + project_path + 'src/libtemple && g++ -c -o ../../build/libtemple.o libtemple.cpp && gcc -shared -o ../../build/lib/libtemple.so ../../build/libtemple.o && rm ' + project_path + 'build/libtemple.o') if res: raise ValueError("build-all: step 'build-libtemple' failed, error code " + str(res)) def transpile_net_to_sepples(): print("build-all: transpile-net-to-sepples") res = os.system('cd ' + project_path + 'src/net && ' + jakt_compiler_path + ' -S -R ' + jakt_runtime_path + ' -B ' + project_path + 'build/net -O net.jakt') if res: raise ValueError("build-all: step 'transpile-net-to-sepples' failed, error code " + str(res)) def build_net(): print("build-all: build-net") build_specific_options = '-Wno-invalid-offsetof -Wl,--section-start=.text=0x1404000 -Wl,--section-start=.plt=0x1402020 -no-pie' res = os.system('cd ' + project_path + 'build/net && clang++-20 ' + build_specific_options + ' -O3 -I ' + jakt_runtime_path + ' -I ' + project_path + '/src/libtemple -fcolor-diagnostics -std=c++20 -fno-exceptions -Wno-user-defined-literals -Wno-deprecated-declarations -Wno-parentheses-equality -Wno-unqualified-std-cast-call -Wno-unknown-warning-option -Wno-int-to-pointer-cast -mno-red-zone -o ../bin/net *.cpp ../lib/libtemple.so ' + jakt_lib_path + 'libjakt_runtime_x86_64-unknown-linux-unknown.a ' + jakt_lib_path + 'libjakt_main_x86_64-unknown-linux-unknown.a && cd .. && rm -rf net') if res: raise ValueError("build-all: step 'build-net' failed, error code " + str(res)) def address_string_for_symbol(file, symbol): p = subprocess.Popen('readelf -s --wide "' + file + '" | grep \'' + symbol + '$\' | awk \'{sub("000000000", "0x", $2); print $2}\'', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) return str(p.communicate()[0][:-1].decode(encoding='utf-8')) def image_hc_fixup(macro, symbol, image_bin_path, image_hc_path): os.system('echo -e "#define ' + macro + ' ' + address_string_for_symbol(image_bin_path, symbol) + '\n" | cat - ' + image_hc_path + ' | sponge ' + image_hc_path) return def generate_iso_c_file(): print("build-all: generate-iso-c-file") step_error_message = "build-all: step 'generate-iso-c-file' failed, error code " try: os.remove(isoc_file) except: pass res = os.system('isoc-mount --rw ' + isoc_file + ' ' + redsea_path) if res: raise ValueError(step_error_message + str(res)) time.sleep(0.25) copy_files_cmd_line = 'rsync -av --inplace --progress ' + project_path + ' ' + redsea_path copy_files_cmd_line += ' --exclude .clang-format' copy_files_cmd_line += ' --exclude .git' copy_files_cmd_line += ' --exclude .gitignore' copy_files_cmd_line += ' --exclude .vscode' copy_files_cmd_line += ' --exclude build/isoc' copy_files_cmd_line += ' --exclude build/lib' copy_files_cmd_line += ' --exclude build/redsea' copy_files_cmd_line += ' --exclude scripts' copy_files_cmd_line += ' --exclude src' res = os.system(copy_files_cmd_line) if res: raise ValueError(step_error_message + str(res)) if 'custom_files_path' in build_options: copy_custom_files_cmd_line = 'rsync -av --inplace --progress ' + build_options['custom_files_path'] + ' ' + redsea_path res = os.system(copy_custom_files_cmd_line) if res: raise ValueError(step_error_message + str(res)) # Fixup addresses for Image.HC image_bin_path = redsea_path + '/build/bin/image' image_hc_path = redsea_path + '/System/Utilities/Image.HC' image_hc_fixup('IMAGE_LOAD_GIF_FROM_MEMORY', 'image_load_gif_from_memory', image_bin_path, image_hc_path) image_hc_fixup('STBI_WRITE_PNG_TO_MEM', 'stbi_write_png_to_mem', image_bin_path, image_hc_path) image_hc_fixup('STBI_LOAD_FROM_MEMORY', 'stbi_load_from_memory', image_bin_path, image_hc_path) image_hc_fixup('STBI_INFO_FROM_MEMORY', 'stbi_info_from_memory', image_bin_path, image_hc_path) image_hc_fixup('STBI_FAILURE_REASON', 'stbi_failure_reason', image_bin_path, image_hc_path) image_hc_fixup('RENDER_4BIT_FLOYDSTEIN', 'render_4bit_floydstein', image_bin_path, image_hc_path) time.sleep(0.25) res = os.system('sync && fusermount -u ' + redsea_path) if res: raise ValueError(step_error_message + str(res)) time.sleep(0.25) def generate_slipstream_iso_file(): print("build-all: generate-slipstream-iso-file") res = os.system('templeos-slipstream ' + templeos_iso_file + ' ' + isoc_file + ' ' + qemu_slipstream_iso_file) if res: raise ValueError("build-all: step 'generate-slipstream-iso-file' failed, error code " + str(res)) def run(): print("build-all: run") res = os.system(qemu_run_cmd) if res: raise ValueError("build-all: step 'run' failed, error code " + str(res)) def build_all(): if not build_options_bool('skip_clang_format'): clang_format_src_files() #if not build_options_bool('skip_rebuild'): if 2==3: refresh_build_path() build_image() build_libtemple() transpile_net_to_sepples() build_net() generate_iso_c_file() generate_slipstream_iso_file() run() build_all()