From c115de9d40607a4ad50fe5c6d563b4c311d0c72c Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 29 Mar 2024 23:53:05 +0100 Subject: [PATCH] Update to build with ab. --- Makefile | 2 +- build/ab.mk | 19 ++- build/ab.py | 250 ++++++++++++++++++++++------------- build/c.py | 254 +++++++++++++++++++++--------------- build/pkg.py | 17 ++- build/protobuf.py | 51 ++++---- build/utils.py | 4 +- lib/build.py | 2 +- scripts/build.py | 5 +- src/gui/build.py | 2 +- src/gui/drivetypes/build.py | 2 +- tests/build.py | 16 ++- tools/build.py | 15 ++- 13 files changed, 395 insertions(+), 244 deletions(-) diff --git a/Makefile b/Makefile index db6d782c..a83a38d6 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ all: +all README.md binaries: all tests: all -README.md: $(OBJ)/scripts+mkdocindex/scripts+mkdocindex$(EXT) +README.md: $(OBJ)/scripts/+mkdocindex/+mkdocindex$(EXT) @echo MKDOC $@ @csplit -s -f$(OBJ)/README. README.md '//' '%%' @(cat $(OBJ)/README.00 && $< && cat $(OBJ)/README.01) > README.md diff --git a/build/ab.mk b/build/ab.mk index 7614259f..61da4fb0 100644 --- a/build/ab.mk +++ b/build/ab.mk @@ -9,9 +9,19 @@ CXX ?= g++ AR ?= ar CFLAGS ?= -g -Og LDFLAGS ?= -g -hide = @ PKG_CONFIG ?= pkg-config ECHO ?= echo +TARGETS ?= +all + +ifdef VERBOSE + hide = +else + ifdef V + hide = + else + hide = @ + endif +endif ifeq ($(OS), Windows_NT) EXT ?= .exe @@ -20,6 +30,9 @@ EXT ?= include $(OBJ)/build.mk +MAKEFLAGS += -r +.DELETE_ON_ERROR: + .PHONY: update-ab update-ab: @echo "Press RETURN to update ab from the repository, or CTRL+C to cancel." \ @@ -33,10 +46,10 @@ clean:: $(hide) rm -rf $(OBJ) bin export PYTHONHASHSEED = 1 -build-files = $(shell find . -name 'build.py') build/*.py config.py +build-files = $(shell find . -name 'build.py') $(wildcard build/*.py) $(wildcard config.py) $(OBJ)/build.mk: Makefile $(build-files) @echo "AB" @mkdir -p $(OBJ) - $(hide) $(PYTHON) -X pycache_prefix=$(OBJ) build/ab.py -t +all -o $@ \ + $(hide) $(PYTHON) -X pycache_prefix=$(OBJ) build/ab.py $(patsubst %,-t %,$(TARGETS)) -o $@ \ build.py || rm -f $@ diff --git a/build/ab.py b/build/ab.py index d5393867..4b485745 100644 --- a/build/ab.py +++ b/build/ab.py @@ -2,7 +2,6 @@ from collections.abc import Iterable, Sequence from os.path import * from types import SimpleNamespace import argparse -import copy import functools import importlib import importlib.abc @@ -10,10 +9,10 @@ import importlib.util import inspect import re import sys -import types -import pathlib import builtins -import os +import string +import fnmatch +import traceback defaultGlobals = {} targets = {} @@ -52,27 +51,6 @@ class ABException(BaseException): pass -class ParameterList(Sequence): - def __init__(self, parent=[]): - self.data = parent - - def __getitem__(self, i): - return self.data[i] - - def __len__(self): - return len(self.data) - - def __str__(self): - return " ".join(self.data) - - def __add__(self, other): - newdata = self.data.copy() + other - return ParameterList(newdata) - - def __repr__(self): - return f"" - - class Invocation: name = None callback = None @@ -80,6 +58,20 @@ class Invocation: ins = None outs = None binding = None + traits = None + attr = None + attrdeps = None + + def __init__(self): + self.attr = SimpleNamespace() + self.attrdeps = SimpleNamespace() + self.traits = set() + + def __eq__(self, other): + return self.name is other.name + + def __hash__(self): + return id(self.name) def materialise(self, replacing=False): if self in unmaterialisedTargets: @@ -115,9 +107,7 @@ class Invocation: self.callback(**self.args) cwdStack.pop() except BaseException as e: - print( - f"Error materialising {self} ({id(self)}): {self.callback}" - ) + print(f"Error materialising {self}: {self.callback}") print(f"Arguments: {self.args}") raise e @@ -129,8 +119,18 @@ class Invocation: materialisingStack.pop() + def bubbleattr(self, attr, xs): + xs = targetsof(xs, cwd=self.cwd) + a = set() + if hasattr(self.attrdeps, attr): + a = getattr(self.attrdeps, attr) + + for x in xs: + a.add(x) + setattr(self.attrdeps, attr, a) + def __repr__(self): - return "" % self.name + return "'%s'" % self.name def Rule(func): @@ -150,7 +150,7 @@ def Rule(func): if name.startswith("./"): name = join(cwd, name) elif "+" not in name: - name = cwd + "+" + name + name = join(cwd, "+" + name) i.name = name i.localname = name.split("+")[-1] @@ -162,12 +162,13 @@ def Rule(func): i = replaces name = i.name else: - raise ABException("you must supply either name or replaces") + raise ABException("you must supply either 'name' or 'replaces'") i.cwd = cwd + i.sentinel = "$(OBJ)/.sentinels/" + name + ".mark" i.types = func.__annotations__ i.callback = func - setattr(i, func.__name__, SimpleNamespace()) + i.traits.add(func.__name__) i.binding = sig.bind(name=name, self=i, **kwargs) i.binding.apply_defaults() @@ -186,9 +187,21 @@ class Type: self.value = value +class List(Type): + def convert(self, invocation): + value = self.value + if not value: + return [] + if type(value) is str: + return [value] + return list(value) + + class Targets(Type): def convert(self, invocation): value = self.value + if not value: + return [] if type(value) is str: value = [value] if type(value) is list: @@ -207,6 +220,8 @@ class Target(Type): class TargetsMap(Type): def convert(self, invocation): value = self.value + if not value: + return {} if type(value) is dict: return { k: targetof(v, cwd=invocation.cwd) for k, v in value.items() @@ -233,20 +248,29 @@ def fileinvocation(s): return i -def targetof(s, cwd): +def targetof(s, cwd=None): if isinstance(s, Invocation): s.materialise() return s + if type(s) != str: + raise ABException("parameter of targetof is not a single target") + if s in targets: t = targets[s] t.materialise() return t - if s.startswith(".+"): - s = cwd + s[1:] - elif s.startswith("./"): - s = normpath(join(cwd, s)) + if s.startswith("."): + if cwd == None: + raise ABException( + "relative target names can't be used in targetof without supplying cwd" + ) + if s.startswith(".+"): + s = cwd + s[1:] + elif s.startswith("./"): + s = normpath(join(cwd, s)) + elif s.endswith("/"): return fileinvocation(s) elif s.startswith("$"): @@ -259,15 +283,18 @@ def targetof(s, cwd): return fileinvocation(s) (path, target) = s.split("+", 2) + s = join(path, "+" + target) loadbuildfile(join(path, "build.py")) if not s in targets: - raise ABException(f"build file at {path} doesn't contain +{target}") + raise ABException( + f"build file at {path} doesn't contain +{target} when trying to resolve {s}" + ) i = targets[s] i.materialise() return i -def targetsof(*xs, cwd): +def targetsof(*xs, cwd=None): return flatten([targetof(x, cwd) for x in flatten(xs)]) @@ -282,6 +309,14 @@ def filenamesof(*xs): return s +def filenamesmatchingof(xs, pattern): + return fnmatch.filter(filenamesof(xs), pattern) + + +def targetswithtraitsof(xs, trait): + return [target for target in targetsof(xs) if trait in target.traits] + + def targetnamesof(*xs): s = [] for x in flatten(xs): @@ -302,6 +337,24 @@ def filenameof(x): return xs[0] +def bubbledattrsof(x, attr): + x = targetsof(x) + alltargets = set() + pending = set(x) if isinstance(x, Iterable) else {x} + while pending: + t = pending.pop() + if t not in alltargets: + alltargets.add(t) + if hasattr(t.attrdeps, attr): + pending.update(getattr(t.attrdeps, attr)) + + values = [] + for t in alltargets: + if hasattr(t.attr, attr): + values += getattr(t.attr, attr) + return values + + def stripext(path): return splitext(path)[0] @@ -312,30 +365,43 @@ def emit(*args): def templateexpand(s, invocation): - class Converter: - def __getitem__(self, key): - if key == "self": - return invocation - f = filenamesof(invocation.args[key]) - if isinstance(f, Sequence): - f = ParameterList(f) - return f + class Formatter(string.Formatter): + def get_field(self, name, a1, a2): + return ( + eval(name, invocation.callback.__globals__, invocation.args), + False, + ) - return eval("f%r" % s, invocation.callback.__globals__, Converter()) + def format_field(self, value, format_spec): + if type(self) == str: + return value + return " ".join( + [templateexpand(f, invocation) for f in filenamesof(value)] + ) + + return Formatter().format(s) -def emitter_rule(name, ins, outs, deps=[]): +def emitter_rule(rule, ins, outs, deps=[]): emit("") - emit(".PHONY:", name) - if outs: - emit(name, ":", filenamesof(outs), ";") - emit(filenamesof(outs), "&:", filenamesof(ins), filenamesof(deps)) - else: - emit(name, "&:", filenamesof(ins), filenamesof(deps)) + emit(".PHONY:", rule.name) + emit(rule.name, ":", rule.sentinel) + + emit( + rule.sentinel, + # filenamesof(outs) if outs else [], + ":", + filenamesof(ins), + filenamesof(deps), + ) -def emitter_endrule(name): - pass +def emitter_endrule(rule, outs): + emit("\t$(hide) mkdir -p", dirname(rule.sentinel)) + emit("\t$(hide) touch", rule.sentinel) + + for f in filenamesof(outs): + emit(f, ":", rule.sentinel, ";") def emitter_label(s): @@ -357,47 +423,50 @@ def unmake(*ss): def simplerule( self, name, - ins: Targets = [], - outs=[], - deps: Targets = [], - commands=[], + ins: Targets = None, + outs: List = [], + deps: Targets = None, + commands: List = [], label="RULE", **kwargs, ): self.ins = ins self.outs = outs self.deps = deps - emitter_rule(self.name, ins + deps, outs) + emitter_rule(self, ins + deps, outs) emitter_label(templateexpand("{label} {name}", self)) dirs = [] + cs = [] for out in filenamesof(outs): dir = dirname(out) if dir and dir not in dirs: dirs += [dir] cs = [("mkdir -p %s" % dir) for dir in dirs] + for c in commands: cs += [templateexpand(c, self)] + emitter_exec(cs) - emitter_endrule(self.name) + emitter_endrule(self, outs) @Rule def normalrule( self, name=None, - ins: Targets = [], - deps: Targets = [], - outs=[], + ins: Targets = None, + deps: Targets = None, + outs: List = [], label="RULE", objdir=None, - commands=[], + commands: List = [], **kwargs, ): objdir = objdir or join("$(OBJ)", name) - self.normalrule.objdir = objdir + self.attr.objdir = objdir simplerule( replaces=self, ins=ins, @@ -410,9 +479,9 @@ def normalrule( @Rule -def export(self, name=None, items: TargetsMap = {}, deps: Targets = []): +def export(self, name=None, items: TargetsMap = {}, deps: Targets = None): cs = [] - self.ins = items.values() + self.ins = [] self.outs = [] for dest, src in items.items(): destf = filenameof(dest) @@ -424,23 +493,26 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []): "a dependency of an export must have exactly one output file" ) - emitter_rule(self.name + "+" + destf, srcs, [destf]) - emitter_label(f"CP {destf}") - if dir: - emitter_exec(["mkdir -p " + dir]) - - emitter_exec(["cp %s %s" % (srcs[0], destf)]) - self.outs += [destf] - - emitter_rule(self.name, self.outs, [], deps) - emit("\t@") - - if self.outs: + subrule = simplerule( + name=self.name + "/+" + destf, + ins=[srcs[0]], + outs=[destf], + commands=["cp %s %s" % (srcs[0], destf)], + label="CP", + ) + subrule.materialise() emit("clean::") - emit("\t$(hide) rm -f " + (" ".join(filenamesof(self.outs)))) - self.outs += deps + emit("\t$(hide) rm -f", destf) - emitter_endrule(self.name) + self.ins += [subrule] + + emitter_rule( + self, + self.ins, + self.outs, + [(d.outs if d.outs else d.sentinel) for d in deps], + ) + emitter_endrule(self, self.outs) def loadbuildfile(filename): @@ -478,9 +550,11 @@ def main(): loadbuildfile(f) for t in flatten([a.split(",") for a in args.targets]): - if t not in targets: - raise ABException("target %s is not defined" % t) - targets[t].materialise() + (path, target) = t.split("+", 2) + s = join(path, "+" + target) + if s not in targets: + raise ABException("target %s is not defined" % s) + targets[s].materialise() emit("AB_LOADED = 1\n") diff --git a/build/c.py b/build/c.py index eef55ed1..3cb32be0 100644 --- a/build/c.py +++ b/build/c.py @@ -1,14 +1,18 @@ from os.path import basename, join from build.ab import ( ABException, + List, Rule, Targets, TargetsMap, filenameof, - flatten, + filenamesmatchingof, filenamesof, + flatten, normalrule, + bubbledattrsof, stripext, + targetswithtraitsof, ) from os.path import * from types import SimpleNamespace @@ -24,7 +28,7 @@ def cfileimpl(self, name, srcs, deps, suffix, commands, label, kind, cflags): outs=[outleaf], label=label, commands=commands, - cflags=cflags, + cflags=cflags + bubbledattrsof(deps, "caller_cflags"), ) @@ -32,9 +36,9 @@ def cfileimpl(self, name, srcs, deps, suffix, commands, label, kind, cflags): def cfile( self, name, - srcs: Targets = [], - deps: Targets = [], - cflags=[], + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], suffix=".o", commands=["$(CC) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"], label="CC", @@ -46,9 +50,9 @@ def cfile( def cxxfile( self, name, - srcs: Targets = [], - deps: Targets = [], - cflags=[], + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], suffix=".o", commands=["$(CXX) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"], label="CXX", @@ -69,7 +73,11 @@ def findsources(name, srcs, deps, cflags, filerule): cflags=cflags, ) for f in filenamesof(s) - if f.endswith(".c") or f.endswith(".cc") or f.endswith(".cpp") + if f.endswith(".c") + or f.endswith(".cc") + or f.endswith(".cpp") + or f.endswith(".S") + or f.endswith(".s") ] if any(f.endswith(".o") for f in filenamesof(s)): objs += [s] @@ -77,100 +85,126 @@ def findsources(name, srcs, deps, cflags, filerule): return objs -def libraryimpl( - self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, kind +@Rule +def cheaders( + self, + name, + hdrs: TargetsMap = None, + caller_cflags: List = None, + deps: Targets = None, ): - if not srcs and not hdrs: - raise ABException( - "clibrary contains no sources and no exported headers" - ) - - libraries = [d for d in deps if hasattr(d, "clibrary")] - for library in libraries: - if library.clibrary.cflags: - cflags += library.clibrary.cflags - if library.clibrary.ldflags: - ldflags += library.clibrary.ldflags - - for f in filenamesof(srcs): - if f.endswith(".h"): - deps += [f] - - hdrcs = [] - hdrins = list(hdrs.values()) - hdrouts = [] + cs = [] + ins = list(hdrs.values()) + outs = [] i = 0 for dest, src in hdrs.items(): s = filenamesof(src) if len(s) != 1: raise ABException( - "a dependency of an export must have exactly one output file" + "the target of a header must return exactly one file" ) - hdrcs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"] - hdrouts += [dest] + cs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"] + outs += [dest] i = i + 1 - if not hasattr(self, "clibrary"): - self.clibrary = SimpleNamespace() - if srcs: - hr = None - if hdrcs: - hr = normalrule( - name=f"{name}_hdrs", - ins=hdrins, - outs=hdrouts, - label="HEADERS", - commands=hdrcs, - ) - hr.materialise() + r = normalrule( + replaces=self, + ins=ins, + outs=outs, + commands=cs, + deps=deps, + label="CHEADERS", + ) + r.materialise() + self.attr.caller_cflags = caller_cflags + ["-I" + r.attr.objdir] + self.bubbleattr("caller_cflags", deps) - actualsrcs = findsources( - name, - srcs, - deps + ([f"{name}_hdrs"] if hr else []), - cflags + ([f"-I{hr.normalrule.objdir}"] if hr else []), - kind, - ) - normalrule( +def libraryimpl( + self, + name, + srcs, + deps, + hdrs, + caller_cflags, + caller_ldflags, + cflags, + ldflags, + commands, + label, + kind, +): + hr = None + if hdrs and not srcs: + cheaders( replaces=self, - ins=actualsrcs, - outs=[basename(name) + ".a"], - label=label, - commands=commands if actualsrcs else [], + hdrs=hdrs, + deps=targetswithtraitsof(deps, "cheaders"), + caller_cflags=caller_cflags, ) - - self.clibrary.ldflags = ldflags - self.clibrary.cflags = ["-I" + hr.normalrule.objdir] if hr else [] - else: - r = normalrule( - replaces=self, - ins=hdrins, - outs=hdrouts, - label="HEADERS", - commands=hdrcs, + return + if hdrs: + hr = cheaders( + name=self.localname + "_hdrs", + hdrs=hdrs, + deps=targetswithtraitsof(deps, "cheaders"), + caller_cflags=caller_cflags, ) - r.materialise() + hr.materialise() + deps = deps + [hr] - self.clibrary.ldflags = ldflags - self.clibrary.cflags = ["-I" + r.normalrule.objdir] + objs = findsources( + name, + srcs, + targetswithtraitsof(deps, "cheaders"), + cflags + bubbledattrsof(deps, "caller_cflags"), + kind, + ) + + normalrule( + replaces=self, + ins=objs, + outs=[basename(name) + ".a"], + label=label, + commands=commands, + ) + self.outs = self.outs + (hr.outs if hr else []) + + self.traits.add("cheaders") + self.attr.caller_ldflags = caller_ldflags + self.bubbleattr("caller_ldflags", deps) + self.bubbleattr("caller_cflags", deps) @Rule def clibrary( self, name, - srcs: Targets = [], - deps: Targets = [], - hdrs: TargetsMap = {}, - cflags=[], - ldflags=[], + srcs: Targets = None, + deps: Targets = None, + hdrs: TargetsMap = None, + caller_cflags: List = [], + caller_ldflags: List = [], + cflags: List = [], + ldflags: List = [], commands=["$(AR) cqs {outs[0]} {ins}"], label="LIB", + cfilerule=cfile, ): - return libraryimpl( - self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, cfile + libraryimpl( + self, + name, + srcs, + deps, + hdrs, + caller_cflags, + caller_ldflags, + cflags, + ldflags, + commands, + label, + cfilerule, ) @@ -178,35 +212,43 @@ def clibrary( def cxxlibrary( self, name, - srcs: Targets = [], - deps: Targets = [], - hdrs: TargetsMap = {}, - cflags=[], - ldflags=[], + srcs: Targets = None, + deps: Targets = None, + hdrs: TargetsMap = None, + caller_cflags: List = [], + caller_ldflags: List = [], + cflags: List = [], + ldflags: List = [], commands=["$(AR) cqs {outs[0]} {ins}"], label="LIB", ): - return libraryimpl( - self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, cxxfile + libraryimpl( + self, + name, + srcs, + deps, + hdrs, + caller_cflags, + caller_ldflags, + cflags, + ldflags, + commands, + label, + cxxfile, ) def programimpl( self, name, srcs, deps, cflags, ldflags, commands, label, filerule, kind ): - libraries = [d for d in deps if hasattr(d, "clibrary")] - for library in libraries: - if library.clibrary.cflags: - cflags += library.clibrary.cflags - if library.clibrary.ldflags: - ldflags += library.clibrary.ldflags + ars = filenamesmatchingof(deps, "*.a") + deps = deps + filenamesmatchingof(srcs, "*.h") + ldflags = ldflags + bubbledattrsof(deps, "caller_ldflags") - deps += [f for f in filenamesof(srcs) if f.endswith(".h")] - - ars = [f for f in filenamesof(libraries) if f.endswith(".a")] + cfiles = findsources(name, srcs, deps, cflags, filerule) normalrule( replaces=self, - ins=(findsources(name, srcs, deps, cflags, filerule) + ars + ars), + ins=cfiles + ars + ars, outs=[basename(name) + "$(EXT)"], deps=deps, label=label, @@ -219,12 +261,14 @@ def programimpl( def cprogram( self, name, - srcs: Targets = [], - deps: Targets = [], - cflags=[], - ldflags=[], + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], + ldflags: List = [], commands=["$(CC) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"], label="CLINK", + cfilerule=cfile, + cfilekind="cprogram", ): programimpl( self, @@ -235,8 +279,8 @@ def cprogram( ldflags, commands, label, - cfile, - "cprogram", + cfilerule, + cfilekind, ) @@ -244,10 +288,10 @@ def cprogram( def cxxprogram( self, name, - srcs: Targets = [], - deps: Targets = [], - cflags=[], - ldflags=[], + srcs: Targets = None, + deps: Targets = None, + cflags: List = [], + ldflags: List = [], commands=["$(CXX) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"], label="CXXLINK", ): diff --git a/build/pkg.py b/build/pkg.py index 769cc15f..a4200ad3 100644 --- a/build/pkg.py +++ b/build/pkg.py @@ -1,4 +1,4 @@ -from build.ab import Rule, emit, Target +from build.ab import Rule, emit, Target, bubbledattrsof from types import SimpleNamespace import os import subprocess @@ -15,8 +15,14 @@ PACKAGES := $(shell $(PKG_CONFIG) --list-all | cut -d' ' -f1 | sort) def package(self, name, package=None, fallback: Target = None): emit("ifeq ($(filter %s, $(PACKAGES)),)" % package) if fallback: - emit(f"PACKAGE_CFLAGS_{package} :=", fallback.clibrary.cflags) - emit(f"PACKAGE_LDFLAGS_{package} := ", fallback.clibrary.ldflags) + emit( + f"PACKAGE_CFLAGS_{package} :=", + bubbledattrsof(fallback, "caller_cflags"), + ) + emit( + f"PACKAGE_LDFLAGS_{package} := ", + bubbledattrsof(fallback, "caller_ldflags"), + ) emit(f"PACKAGE_DEP_{package} := ", fallback.name) else: emit(f"$(error Required package '{package}' not installed.)") @@ -30,9 +36,8 @@ def package(self, name, package=None, fallback: Target = None): emit(f"PACKAGE_DEP_{package} := ") emit("endif") - self.clibrary = SimpleNamespace() - self.clibrary.cflags = [f"$(PACKAGE_CFLAGS_{package})"] - self.clibrary.ldflags = [f"$(PACKAGE_LDFLAGS_{package})"] + self.attr.caller_cflags = [f"$(PACKAGE_CFLAGS_{package})"] + self.attr.caller_ldflags = [f"$(PACKAGE_LDFLAGS_{package})"] self.ins = [] self.outs = [f"$(PACKAGE_DEP_{package})"] diff --git a/build/protobuf.py b/build/protobuf.py index 8dc7337b..b499fc43 100644 --- a/build/protobuf.py +++ b/build/protobuf.py @@ -1,8 +1,17 @@ from os.path import join -from build.ab import Rule, Targets, emit, normalrule, filenamesof, flatten +from build.ab import ( + Rule, + Targets, + emit, + normalrule, + filenamesof, + filenamesmatchingof, + bubbledattrsof, + targetswithtraitsof, +) from build.c import cxxlibrary -import build.pkg from types import SimpleNamespace +import build.pkg emit( """ @@ -15,7 +24,7 @@ endif @Rule -def proto(self, name, srcs: Targets = [], deps: Targets = []): +def proto(self, name, srcs: Targets = None, deps: Targets = None): normalrule( replaces=self, ins=srcs, @@ -26,40 +35,38 @@ def proto(self, name, srcs: Targets = [], deps: Targets = []): ], label="PROTO", ) - self.proto.srcs = filenamesof(srcs) + flatten( - [s.proto.srcs for s in flatten(deps)] - ) + self.attr.protosrcs = filenamesof(srcs) + self.bubbleattr("protosrcs", deps) @Rule -def protocc(self, name, srcs: Targets = [], deps: Targets = []): +def protocc(self, name, srcs: Targets = None, deps: Targets = None): outs = [] protos = [] - for f in flatten([s.proto.srcs for s in flatten(srcs + deps)]): - if f.endswith(".proto"): - cc = f.replace(".proto", ".pb.cc") - h = f.replace(".proto", ".pb.h") - protos += [f] - srcs += [f] - outs += [cc, h] + for f in filenamesmatchingof(bubbledattrsof(srcs, "protosrcs"), "*.proto"): + cc = f.replace(".proto", ".pb.cc") + h = f.replace(".proto", ".pb.h") + protos += [f] + srcs += [f] + outs += [cc, h] + + srcname = f"{name}_srcs" + objdir = join("$(OBJ)", srcname) r = normalrule( - name=f"{name}_srcs", + name=srcname, ins=protos, outs=outs, deps=deps, - commands=["$(PROTOC) --cpp_out={self.normalrule.objdir} {ins}"], + commands=["$(PROTOC) --cpp_out={self.attr.objdir} {ins}"], label="PROTOCC", ) - r.materialise() - headers = { - f: join(r.normalrule.objdir, f) for f in outs if f.endswith(".pb.h") - } + headers = {f: join(objdir, f) for f in outs if f.endswith(".pb.h")} cxxlibrary( replaces=self, - srcs=[f"{name}_srcs"], + srcs=[r], + deps=targetswithtraitsof(deps, "cheaders"), hdrs=headers, - cflags=[f"-I{r.normalrule.objdir}"], ) diff --git a/build/utils.py b/build/utils.py index e1a227aa..0ce1cbc6 100644 --- a/build/utils.py +++ b/build/utils.py @@ -19,8 +19,8 @@ def test( name, command: Target = None, commands=None, - ins: Targets = [], - deps: Targets = [], + ins: Targets = None, + deps: Targets = None, label="TEST", ): if command: diff --git a/lib/build.py b/lib/build.py index 7602d214..1fbed16e 100644 --- a/lib/build.py +++ b/lib/build.py @@ -22,4 +22,4 @@ proto( deps=[".+common_proto", "+fl2_proto"], ) -protocc(name="config_proto_lib", srcs=[".+config_proto", "arch+arch_proto"]) +protocc(name="config_proto_lib", srcs=[".+common_proto", ".+config_proto", "arch+arch_proto"]) diff --git a/scripts/build.py b/scripts/build.py index ec053834..021b829e 100644 --- a/scripts/build.py +++ b/scripts/build.py @@ -16,6 +16,7 @@ def protoencode(self, name, srcs: Targets, proto, symbol): "tests+test_proto_lib", "+protobuf_lib", "+fmt_lib", + "+lib", ], ) encoders[proto] = r @@ -36,11 +37,11 @@ def protoencode(self, name, srcs: Targets, proto, symbol): cxxprogram( name="mkdoc", srcs=["./mkdoc.cc"], - deps=["src/formats", "lib+config_proto_lib", "+lib"], + deps=["src/formats", "lib+config_proto_lib", "+lib", "+fmt_lib", "+protobuf_lib"], ) cxxprogram( name="mkdocindex", srcs=["./mkdocindex.cc"], - deps=["src/formats", "lib+config_proto_lib", "+lib"], + deps=["src/formats", "lib+config_proto_lib", "+lib", "+fmt_lib", "+protobuf_lib"], ) diff --git a/src/gui/build.py b/src/gui/build.py index 82fd7608..c2dadc74 100644 --- a/src/gui/build.py +++ b/src/gui/build.py @@ -24,7 +24,7 @@ if config.windows: outs=["rc.o"], deps=["./manifest.xml", "extras+fluxengine_ico"], commands=["$(WINDRES) {ins[0]} {outs[0]}"], - label="WINDRES" + label="WINDRES", ) ] diff --git a/src/gui/drivetypes/build.py b/src/gui/drivetypes/build.py index 0e950c9a..5e82721d 100644 --- a/src/gui/drivetypes/build.py +++ b/src/gui/drivetypes/build.py @@ -31,4 +31,4 @@ encoded = [ for name in drivetypes ] -cxxlibrary(name="drivetypes", srcs=[".+drivetypes_cc"] + encoded) +cxxlibrary(name="drivetypes", srcs=[".+drivetypes_cc"] + encoded, deps=["+lib"]) diff --git a/tests/build.py b/tests/build.py index ef3f9625..1daea37e 100644 --- a/tests/build.py +++ b/tests/build.py @@ -13,9 +13,7 @@ proto( ) protocc( - name="test_proto_lib", - srcs=[".+test_proto"], - deps=["lib+config_proto", "arch+arch_proto"], + name="test_proto_lib", srcs=[".+test_proto"], deps=["lib+config_proto_lib"] ) tests = [ @@ -60,6 +58,9 @@ export( ], deps=[ "+fl2_proto_lib", + "+fmt_lib", + "+lib", + "+protobuf_lib", "+protocol", "+z_lib", ".+test_proto_lib", @@ -70,7 +71,6 @@ export( "dep/libusbp", "dep/snowhouse", "dep/stb", - "+lib", "lib+config_proto_lib", "src/formats", ], @@ -85,7 +85,11 @@ export( srcs=[f"./{n}.cc"], deps=[ "+fl2_proto_lib", + "+fmt_lib", + "+lib", + "+protobuf_lib", "+protocol", + "+z_lib", "dep/adflib", "dep/agg", "dep/fatfs", @@ -93,10 +97,10 @@ export( "dep/libusbp", "dep/snowhouse", "dep/stb", - "+lib", "lib+config_proto_lib", "src/formats", - ], + ] + + ([".+test_proto_lib"] if n == "options" else []), ), ) for n in tests diff --git a/tools/build.py b/tools/build.py index 5d2895f5..3ac8d4d8 100644 --- a/tools/build.py +++ b/tools/build.py @@ -8,25 +8,28 @@ if config.windows: cxxprogram( name="brother120tool", srcs=["./brother120tool.cc"], - deps=["+lib", "lib+config_proto_lib"] + emu, + deps=["+lib", "lib+config_proto_lib", "+fmt_lib", "+z_lib"] + emu, ) cxxprogram( name="brother240tool", srcs=["./brother240tool.cc"], - deps=["+lib", "lib+config_proto_lib"] + emu, + deps=["+lib", "lib+config_proto_lib", "+fmt_lib", "+z_lib"] + emu, ) cxxprogram( name="upgrade-flux-file", srcs=["./upgrade-flux-file.cc"], deps=[ - "+lib", - "src/formats", - "lib+config_proto_lib", - "+protocol", "+fl2_proto_lib", + "+fmt_lib", + "+lib", + "+protobuf_lib", + "+protocol", "+sqlite3_lib", + "+z_lib", "dep/libusbp", + "lib+config_proto_lib", + "src/formats", ], )