Initial Commit

This commit is contained in:
2025-07-07 14:12:53 +12:00
commit fc07e157c8
7 changed files with 640 additions and 0 deletions

122
util/builder/cpp_builder.py Normal file
View File

@@ -0,0 +1,122 @@
from util.generic.multithreader import MultiprocessWorker, WorkerProcess, WorkerReturn, Spinners
from util.generic.log import Log
from util.builder.info import Build, BuildType, Platform
from typing import List
import subprocess
import os
import json
class CppBuilder:
def __init__(self, builds: List[Build] = [], log: Log = None, build_dir: str = "build/", source_dir: str = ".", include_dir: str = "include/"):
if log is None: log = Log(self.__class__.__name__, Log.Level.DEBUG)
self.logger = log.create_logger()
self._builds:List[Build] = builds
self._build_dir: str = build_dir
self._source_dir: str = source_dir
self._include_dir: str = include_dir
self.multiprocesser = MultiprocessWorker(spinner_set=Spinners.SPIN_OPEN_CUBE)
def find_source_files(self, root_dir:str) -> List[str]:
cpp_files = []
for root, _, files in os.walk(root_dir):
for file in files:
if file.endswith('.c') or file.endswith('.cpp'):
relative_path = os.path.relpath(os.path.join(root, file), root_dir)
cpp_files.append(relative_path)
return cpp_files
def build(self):
if len(self._builds) > 1:
self.logger.log(Log.Level.INFO, "Starting builds...")
else:
self.logger.log(Log.Level.INFO, "Starting build...")
os.makedirs(self._build_dir, exist_ok=True)
for build in self._builds:
instruction = [
build.platform.value.compiler,
"-o", os.path.join(self._build_dir, f"{build.name}_{build.platform.value}"),
f"-march={build.platform.value.architecture}",
"-I", self._include_dir,
*self.find_source_files(self._source_dir)
]
instruction.append(build.platform.value.code_specification)
instruction.extend(build.type.value)
instruction.extend(build.additional_instructions)
self.multiprocesser.add_task(WorkerProcess(CppBuilder._build_worker, instruction))
results: List[WorkerReturn] = self.multiprocesser.run()
for res in results:
res.output_result(self.logger, r'-o (\S+)', "SUCCESS: Compiled '{output}'")
@staticmethod
def _build_worker(instruction):
try:
process = subprocess.run(instruction, capture_output=True, text=True, check=True)
return WorkerReturn(True, ' '.join(instruction), process.stdout, process.stderr, None)
except subprocess.CalledProcessError as e:
return WorkerReturn(False, ' '.join(instruction), e.stdout, e.stderr, str(e))
except Exception as e:
return WorkerReturn(False, ' '.join(instruction), "", "", str(e))
def load_config(self, file_path: str):
try:
with open(file_path, "r") as file:
config = json.load(file)
except FileNotFoundError:
self.logger.log(Log.Level.ERROR, f"File '{file_path}' not found.")
return False
except json.JSONDecodeError:
self.logger.log(Log.Level.ERROR, f"File '{file_path}' does not contain valid JSON data.")
return False
except Exception as e:
self.logger.log(Log.Level.ERROR, f"An unexpected error occurred: {e}")
return False
if config is None:
return False
configurations = config["configurations"]
global_build_args = config["global_build_args"]
for i in configurations:
build_name = i["name"]
build_type_str = i["build_type"]
platform_str = i["platform"]
if build_type_str not in BuildType.__members__:
self.logger.log(
Log.Level.ERROR,
f"Invalid build_type '{build_type_str}' for build '{build_name}'. Skipping..."
)
continue
if platform_str not in Platform.__members__:
self.logger.log(
Log.Level.ERROR,
f"Invalid platform '{platform_str}' for build '{build_name}'. Skipping..."
)
continue
build_type = BuildType[build_type_str]
platform = Platform[platform_str]
self._builds.append(Build(
build_name,
build_type,
platform,
i["args"] + global_build_args
))
self.logger.log(Log.Level.DEBUG, f"'{build_name}' config loaded from file.")
self.logger.log(Log.Level.INFO, f"Configurations successfully loaded from '{file_path}'.")