# -*- python -*- from pathlib import Path from dataclasses import dataclass # # File lists # PROGRAM_SOURCES = ["src/main.c"] LIB_SRCS = [ "src/arena.c", "src/builtins.c", "src/evaluate.c", "src/memory.c", "src/special.c", "src/scope.c", "src/utility.c", "src/parse.c", ] LIB_INCLUDES = ["src/"] TEST_SRCS = [ "test/test_arena.c", "test/test_e2e.c", "test/test_parse.c", "test/test_scope.c", "test/test_utility.c", ] TEST_LIB_SRCS = ["third-party/unity/src/unity.c"] TEST_LIB_INCLUDES = ["third-party/unity/src/"] def with_suffix(path, suffix): return str(Path(path).with_suffix(suffix)) @dataclass class BuildVariant: variant_name: str cc: str ccflags: list[str] libs: list[str] linkflags: list[str] enable_compile_commands_db: bool = False def built(self, path): return self.variant_dir + path def enable_compile_commands(self): self.env.Tool("compilation_db") self.env.CompilationDatabase() def configure_lib(self): self.lib_objs = [ self.env.Object(target=self.built(with_suffix(p, ".o")), source=p) for p in LIB_SRCS ] self.static_lib = self.env.StaticLibrary(self.built("uclisp"), self.lib_objs) def configure_repl(self): pgm_objs = [ self.env.Object(target=self.built(with_suffix(p, ".o")), source=p) for p in PROGRAM_SOURCES ] repl_env = self.env.Clone() repl_env.Append(LIBS=[self.static_lib]) self.repl_program = repl_env.Program( self.built("uclisp"), pgm_objs, ) def configure_tests(self): test_lib_objs = [ self.test_env.Object(target=self.built(with_suffix(p, ".o")), source=p) for p in TEST_LIB_SRCS ] self.test_env.Append(LIBS=[self.static_lib]) test_deps = test_lib_objs test_objs = [ self.test_env.Object(target=self.built(with_suffix(p, ".o")), source=p) for p in TEST_SRCS ] self.tests = [ self.test_env.Program( self.built(with_suffix(p, "")), test_deps + [self.built(with_suffix(p, ".o"))], ) for p in TEST_SRCS ] def configure(self): self.variant_dir = f"build/{self.variant_name}/" # # Construct Environments # self.env = Environment( CC=self.cc, CPPPATH=LIB_INCLUDES, COMPILATIONDB_USE_ABSPATH=True, CCFLAGS=self.ccflags, LINKFLAGS=self.linkflags, LIBS=self.libs, ) if self.enable_compile_commands_db: self.enable_compile_commands() self.test_env = self.env.Clone() self.test_env.Append(CPPPATH=TEST_LIB_INCLUDES) self.configure_lib() self.configure_repl() self.configure_tests() self.env.Substfile( target=self.built("run_tests.sh"), source="run_tests.sh.in", SUBST_DICT={ "@tests@": " ".join( str(Path(str(test[0])).resolve()) for test in self.tests ) }, ) self.env.Command( self.built("run_tests"), self.built("run_tests.sh"), Chmod(self.built("run_tests.sh"), 0o755), ) # Copy default build compile commands to root, which is where tools seem to want # it. if self.enable_compile_commands_db: Copy("compile_commands.json", self.built("compile_commands.json")) self.env.Alias(self.variant_name, self.variant_dir) base_ccflags = ["-Werror", "-Wall", "-Wextra", "-Wno-unused-parameter"] debug_ccflags = ["-ggdb", "-O0"] release_ccflags = [ "-Oz", "-flto", "-ffunction-sections", "-fdata-sections", "-Wl,--gc-sections", ] variants = [ BuildVariant( variant_name="debug", cc="gcc", ccflags=debug_ccflags + base_ccflags, libs=["readline"], linkflags=[], enable_compile_commands_db=True, ), BuildVariant( variant_name="release", cc="gcc", ccflags=release_ccflags + base_ccflags, linkflags=[], libs=["readline"], ), BuildVariant( variant_name="arm-debug", cc="arm-none-eabi-gcc", ccflags=["-DNO_READLINE"] + debug_ccflags + base_ccflags, libs=[], linkflags=["--specs=nosys.specs"], ), ] for variant in variants: variant.configure()