import os import shutil import subprocess as sp from sane import _Help as Sane from glob import glob from sane import * COMPILER = "gcc" COMPILE_FLAGS = [ "-std=c11", "-g3", "-O0", "-Wall", "-Wextra", "-Werror", "-Wpedantic", "-pedantic-errors", "-fopenmp", ] LINK_FLAGS = ["-fopenmp"] LIBRARIES = ["-lm"] OBJ_DIR = os.path.join("obj", "release" if ("RELEASE" in os.environ) else "debug") SRC_DIR = "src" EXE_NAME = "main." + ("release" if ("RELEASE" in os.environ) else "debug") + ".exe" ROOT = os.path.dirname(os.path.realpath(__file__)) if "RELEASE" in os.environ: COMPILE_FLAGS[COMPILE_FLAGS.index("-O0")] = "-O2" COMPILE_FLAGS[COMPILE_FLAGS.index("-g3")] = "-g" COMPILE_FLAGS.append("-DRELEASE") LINK_FLAGS.append("-DRELEASE") if "COMPILE_FLAGS" in os.environ: COMPILE_FLAGS.extend(os.environ["COMPILE_FLAGS"].split(";")) if "LINK_FLAGS" in os.environ: LINK_FLAGS.extend(os.environ["LINK_FLAGS"].split(";")) def as_object(source_path): """Takes a source path and returns the path to the corresponding compiled object.""" source_path = os.path.relpath(source_path, ROOT) object_name = source_path + ".obj" object_path = os.path.join(OBJ_DIR, object_name) return object_path def make_object_recipe(source_path): object_path = os.path.realpath(as_object(source_path)) object_dir = os.path.dirname(object_path) if not os.path.exists(object_dir): os.makedirs(object_dir) condition = Sane.file_condition(sources=[source_path], targets=[object_path]) @recipe( name=f"compile_{source_path}", conditions=[condition], hooks=["obj_compile"] ) def compile_obj(): sp.run([COMPILER, "-c", *COMPILE_FLAGS, "-o", object_path, source_path]) source_files = [os.path.realpath(path) for path in glob("**/*.c", recursive=True)] for source_file in source_files: make_object_recipe(source_file) def exe_not_exists(): return not os.path.exists(EXE_NAME) def old_exe(): object_files = [os.path.realpath(path) for path in glob("**/*.obj", recursive=True)] return Sane.file_condition(object_files, [EXE_NAME])() @recipe(hook_deps=["obj_compile"], info="Compile the source files.") def compile(): pass @recipe( recipe_deps=[compile], conditions=[exe_not_exists, old_exe], info="Links the main executable.", ) def link(): obj_files = glob( os.path.join(OBJ_DIR, "**", "*.obj").replace("\\", "/"), recursive=True ) sp.run([COMPILER, *LINK_FLAGS, "-o", EXE_NAME, *obj_files, *LIBRARIES]) @recipe(info="Removes all compiled objects.") def clean(): shutil.rmtree(OBJ_DIR) @recipe(recipe_deps=[link], conditions=[lambda: True]) def run(): with open(os.path.join(ROOT, "data/2222_inq.txt"), "r") as input: exe = os.path.join(ROOT, EXE_NAME) sp.run( [exe, "2", "2", "2", "2"], stdin=input, ) sane_run(link)