Initial Commit
This commit is contained in:
122
util/builder/cpp_builder.py
Normal file
122
util/builder/cpp_builder.py
Normal 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}'.")
|
||||
Reference in New Issue
Block a user