Skip to content

Commit

Permalink
Merge pull request #172 from davidgiven/ab
Browse files Browse the repository at this point in the history
Update ab.
  • Loading branch information
davidgiven authored Sep 12, 2024
2 parents 215aa53 + 5ca7641 commit bf813e6
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 154 deletions.
2 changes: 1 addition & 1 deletion build/ab.mk
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ EXT ?=

include $(OBJ)/build.mk

MAKEFLAGS += -r
MAKEFLAGS += -r -j$(shell nproc)
.DELETE_ON_ERROR:

.PHONY: update-ab
Expand Down
163 changes: 97 additions & 66 deletions build/ab.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ def wrapper(*, name=None, replaces=None, **kwargs):
t.types = func.__annotations__
t.callback = func
t.traits.add(func.__name__)
if "args" in kwargs:
t.args |= kwargs["args"]
del kwargs["args"]
if "traits" in kwargs:
t.traits |= kwargs["traits"]
del kwargs["traits"]

t.binding = sig.bind(name=name, self=t, **kwargs)
t.binding.apply_defaults()
Expand All @@ -125,6 +131,12 @@ def wrapper(*, name=None, replaces=None, **kwargs):
return wrapper


def _isiterable(xs):
return isinstance(xs, Iterable) and not isinstance(
xs, (str, bytes, bytearray)
)


class Target:
def __init__(self, cwd, name):
if verbose:
Expand All @@ -145,7 +157,7 @@ def __hash__(self):
return id(self)

def __repr__(self):
return f"Target('{self.name}', {id(self)})"
return f"Target('{self.name}')"

def templateexpand(selfi, s):
class Formatter(string.Formatter):
Expand All @@ -160,7 +172,7 @@ def format_field(self, value, format_spec):
return ""
if type(value) == str:
return value
if isinstance(value, (set, tuple)):
if _isiterable(value):
value = list(value)
if type(value) != list:
value = [value]
Expand All @@ -185,7 +197,6 @@ def materialise(self, replacing=False):
# Perform type conversion to the declared rule parameter types.

try:
self.args = {}
for k, v in self.binding.arguments.items():
if k != "kwargs":
t = self.types.get(k, None)
Expand All @@ -205,9 +216,23 @@ def materialise(self, replacing=False):
# Actually call the callback.

cwdStack.append(self.cwd)
self.callback(
**{k: v for k, v in self.args.items() if k not in {"dir"}}
)
if "kwargs" in self.binding.arguments.keys():
# If the caller wants kwargs, return all arguments except the standard ones.
cbargs = {
k: v for k, v in self.args.items() if k not in {"dir"}
}
else:
# Otherwise, just call the callback with the ones it asks for.
cbargs = {}
for k in self.binding.arguments.keys():
if k != "kwargs":
try:
cbargs[k] = self.args[k]
except KeyError:
error(
f"invocation of {self} failed because {k} isn't an argument"
)
self.callback(**cbargs)
cwdStack.pop()
except BaseException as e:
print(f"Error materialising {self}: {self.callback}")
Expand All @@ -228,73 +253,82 @@ def convert(value, target):
return target.targetof(value)

def targetof(self, value):
if isinstance(value, Path):
value = value.as_posix()
if isinstance(value, Target):
t = value
else:
if value[0] == "=":
value = join(self.dir, value[1:])

if value.startswith("."):
# Check for local rule.
if value.startswith(".+"):
value = normpath(join(self.cwd, value[1:]))
# Check for local path.
elif value.startswith("./"):
value = normpath(join(self.cwd, value))
# Explicit directories are always raw files.
elif value.endswith("/"):
return self._filetarget(value)
# Anything starting with a variable expansion is always a raw file.
elif value.startswith("$"):
return self._filetarget(value)

# If this is not a rule lookup...
if "+" not in value:
# ...and if the value is pointing at a directory without a trailing /,
# it's a shorthand rule lookup.
if isdir(value):
value = value + "+" + basename(value)
# Otherwise it's an absolute file.
else:
return self._filetarget(value)
if isinstance(value, str) and (value[0] == "="):
value = join(self.dir, value[1:])

# At this point we have the fully qualified name of a rule.
return targetof(value, self.cwd)

(path, target) = value.rsplit("+", 1)
value = join(path, "+" + target)
if value not in targets:
# Load the new build file.

path = join(path, "build.py")
loadbuildfile(path)
assert (
value in targets
), f"build file at '{path}' doesn't contain '+{target}' when trying to resolve '{value}'"
def _filetarget(value, cwd):
if value in targets:
return targets[value]

t = targets[value]
t = Target(cwd, value)
t.outs = [value]
targets[value] = t
return t

t.materialise()
return t

def _filetarget(self, value):
if value in targets:
return targets[value]
def targetof(value, cwd=None):
if not cwd:
cwd = cwdStack[-1]
if isinstance(value, Path):
value = value.as_posix()
if isinstance(value, Target):
t = value
else:
assert (
value[0] != "="
), "can only use = for targets associated with another target"

if value.startswith("."):
# Check for local rule.
if value.startswith(".+"):
value = normpath(join(cwd, value[1:]))
# Check for local path.
elif value.startswith("./"):
value = normpath(join(cwd, value))
# Explicit directories are always raw files.
elif value.endswith("/"):
return _filetarget(value, cwd)
# Anything starting with a variable expansion is always a raw file.
elif value.startswith("$"):
return _filetarget(value, cwd)

# If this is not a rule lookup...
if "+" not in value:
# ...and if the value is pointing at a directory without a trailing /,
# it's a shorthand rule lookup.
if isdir(value):
value = value + "+" + basename(value)
# Otherwise it's an absolute file.
else:
return _filetarget(value, cwd)

t = Target(self.cwd, value)
t.outs = [value]
targets[value] = t
return t
# At this point we have the fully qualified name of a rule.

(path, target) = value.rsplit("+", 1)
value = join(path, "+" + target)
if value not in targets:
# Load the new build file.

path = join(path, "build.py")
loadbuildfile(path)
assert (
value in targets
), f"build file at '{path}' doesn't contain '+{target}' when trying to resolve '{value}'"

t = targets[value]

t.materialise()
return t


class Targets:
def convert(value, target):
if not value:
return []
assert isinstance(
value, (list, tuple)
), "cannot convert non-list to Targets"
assert _isiterable(value), "cannot convert non-list to Targets"
return [target.targetof(x) for x in flatten(value)]


Expand All @@ -318,7 +352,7 @@ def loadbuildfile(filename):
def flatten(items):
def generate(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
if _isiterable(x):
yield from generate(x)
else:
yield x
Expand All @@ -327,15 +361,13 @@ def generate(xs):


def targetnamesof(items):
if not isinstance(items, (list, tuple, set)):
error("argument of filenamesof is not a list/tuple/set")
assert _isiterable(items), "argument of filenamesof is not a collection"

return [t.name for t in items]


def filenamesof(items):
if not isinstance(items, (list, tuple, set)):
error("argument of filenamesof is not a list/tuple/set")
assert _isiterable(items), "argument of filenamesof is not a collection"

def generate(xs):
for x in xs:
Expand Down Expand Up @@ -398,7 +430,6 @@ def simplerule(
deps: Targets = [],
commands=[],
label="RULE",
**kwargs,
):
self.ins = ins
self.outs = outs
Expand Down
25 changes: 16 additions & 9 deletions build/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def cfileimpl(self, name, srcs, deps, suffix, commands, label, kind, cflags):
outs=[outleaf],
label=label,
commands=commands,
cflags=cflags,
args={"cflags": cflags},
)


Expand Down Expand Up @@ -150,7 +150,7 @@ def cheaders(
commands=cs,
deps=deps,
label="CHEADERS",
caller_cflags=caller_cflags + ["-I" + self.dir],
args={"caller_cflags": caller_cflags + ["-I" + self.dir]},
)


Expand Down Expand Up @@ -204,13 +204,18 @@ def libraryimpl(
outs=[f"={self.localname}.a"],
label=label,
commands=commands,
caller_cflags=(hr.args["caller_cflags"] if hr else []),
caller_ldflags=caller_ldflags,
args={
"caller_cflags": collectattrs(
targets=deps + ([hr] if hr else []), name="caller_cflags"
),
"caller_ldflags": collectattrs(
targets=deps, name="caller_ldflags", initial=caller_ldflags
),
},
traits={"cheaders"},
)
self.outs = self.outs + (hr.outs if hr else [])

self.traits.add("cheaders")


@Rule
def clibrary(
Expand Down Expand Up @@ -310,9 +315,11 @@ def programimpl(
deps=deps,
label=toolchain.label + label,
commands=commands,
ldflags=collectattrs(
targets=deps, name="caller_ldflags", initial=ldflags
),
args={
"ldflags": collectattrs(
targets=deps, name="caller_ldflags", initial=ldflags
)
},
)


Expand Down
Loading

0 comments on commit bf813e6

Please sign in to comment.