Skip to content

Commit 22afbc2

Browse files
committed
Update ab.
1 parent c005003 commit 22afbc2

6 files changed

Lines changed: 408 additions & 115 deletions

File tree

build/_sandbox.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def main():
2626
print("link", sf)
2727
os.makedirs(dirname(sf), exist_ok=True)
2828
try:
29-
os.link(abspath(f), sf)
29+
os.symlink(abspath(f), sf)
3030
except PermissionError:
3131
shutil.copy(f, sf)
3232

@@ -38,6 +38,11 @@ def main():
3838
df = dirname(f)
3939
if df:
4040
os.makedirs(df, exist_ok=True)
41+
42+
try:
43+
os.remove(f)
44+
except FileNotFoundError:
45+
pass
4146
os.rename(sf, f)
4247

4348

build/ab.mk

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
MAKENOT4 := $(if $(findstring 3.9999, $(lastword $(sort 3.9999 $(MAKE_VERSION)))),yes,no)
2-
MAKE4.3 := $(if $(findstring 4.3, $(firstword $(sort 4.3 $(MAKE_VERSION)))),yes,no)
3-
MAKE4.1 := $(if $(findstring no_no,$(MAKENOT4)_$(MAKE4.3)),yes,no)
42

5-
ifeq ($(MAKENOT3),yes)
3+
ifeq ($(MAKENOT4),yes)
64
$(error You need GNU Make 4.x for this (if you're on OSX, use gmake).)
75
endif
86

97
OBJ ?= .obj
108
PYTHON ?= python3
11-
CC ?= gcc
12-
CXX ?= g++
13-
AR ?= ar
14-
CFLAGS ?= -g -Og
15-
LDFLAGS ?= -g
169
PKG_CONFIG ?= pkg-config
1710
HOST_PKG_CONFIG ?= $(PKG_CONFIG)
1811
ECHO ?= echo
1912
CP ?= cp
2013

14+
HOSTCC ?= gcc
15+
HOSTCXX ?= g++
16+
HOSTAR ?= ar
17+
HOSTCFLAGS ?= -g -Og
18+
HOSTLDFLAGS ?= -g
19+
20+
CC ?= $(HOSTCC)
21+
CXX ?= $(HOSTCXX)
22+
AR ?= $(HOSTAR)
23+
CFLAGS ?= $(HOSTCFLAGS)
24+
LDFLAGS ?= $(HOSTLDFLAGS)
25+
2126
export PKG_CONFIG
2227
export HOST_PKG_CONFIG
2328

@@ -31,6 +36,11 @@ else
3136
endif
3237
endif
3338

39+
# If enabled, shows a nice display of how far through the build you are. This
40+
# doubles Make startup time. Also, on Make 4.3 and above, rebuilds don't show
41+
# correct progress information.
42+
AB_ENABLE_PROGRESS_INFO ?= true
43+
3444
WINDOWS := no
3545
OSX := no
3646
LINUX := no
@@ -53,13 +63,17 @@ EXT ?=
5363

5464
CWD=$(shell pwd)
5565

56-
ifeq ($(PROGRESSINFO),)
57-
# The first make invocation here has to have its output discarded or else it
58-
# produces spurious 'Leaving directory' messages... don't know why.
59-
rulecount := $(strip $(shell $(MAKE) --no-print-directory -q $(OBJ)/build.mk PROGRESSINFO=1 > /dev/null \
60-
&& $(MAKE) --no-print-directory -n $(MAKECMDGOALS) PROGRESSINFO=XXXPROGRESSINFOXXX | grep XXXPROGRESSINFOXXX | wc -l))
61-
ruleindex := 1
62-
PROGRESSINFO = "[$(ruleindex)/$(rulecount)]$(eval ruleindex := $(shell expr $(ruleindex) + 1))"
66+
ifeq ($(AB_ENABLE_PROGRESS_INFO),true)
67+
ifeq ($(PROGRESSINFO),)
68+
# The first make invocation here has to have its output discarded or else it
69+
# produces spurious 'Leaving directory' messages... don't know why.
70+
rulecount := $(strip $(shell $(MAKE) --no-print-directory -q $(OBJ)/build.mk PROGRESSINFO=1 > /dev/null \
71+
&& $(MAKE) --no-print-directory -n $(MAKECMDGOALS) PROGRESSINFO=XXXPROGRESSINFOXXX | grep XXXPROGRESSINFOXXX | wc -l))
72+
ruleindex := 1
73+
PROGRESSINFO = "[$(ruleindex)/$(rulecount)]$(eval ruleindex := $(shell expr $(ruleindex) + 1)) "
74+
endif
75+
else
76+
PROGRESSINFO = ""
6377
endif
6478

6579
PKG_CONFIG_HASHES = $(OBJ)/.pkg-config-hashes/target-$(word 1, $(shell $(PKG_CONFIG) --list-all | md5sum))

build/ab.py

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from copy import copy
77
import functools
88
import importlib
9-
import importlib.abc
109
import importlib.util
1110
from importlib.machinery import (
1211
SourceFileLoader,
@@ -21,13 +20,17 @@
2120
import ast
2221
from collections import namedtuple
2322

23+
VERBOSE_MK_FILE = False
24+
2425
verbose = False
2526
quiet = False
2627
cwdStack = [""]
2728
targets = {}
2829
unmaterialisedTargets = {} # dict, not set, to get consistent ordering
2930
materialisingStack = []
3031
defaultGlobals = {}
32+
globalId = 1
33+
wordCache = {}
3134

3235
RE_FORMAT_SPEC = re.compile(
3336
r"(?:(?P<fill>[\s\S])?(?P<align>[<>=^]))?"
@@ -157,7 +160,8 @@ def wrapper(*, name=None, replaces=None, **kwargs):
157160
t.callback = func
158161
t.traits.add(func.__name__)
159162
if "args" in kwargs:
160-
t.args.update(kwargs["args"])
163+
t.explicit_args = kwargs["args"]
164+
t.args.update(t.explicit_args)
161165
del kwargs["args"]
162166
if "traits" in kwargs:
163167
t.traits |= kwargs["traits"]
@@ -406,8 +410,17 @@ def _removesuffix(self, suffix):
406410

407411

408412
def loadbuildfile(filename):
409-
filename = _removesuffix(filename.replace("/", "."), ".py")
410-
builtins.__import__(filename)
413+
modulename = _removesuffix(filename.replace("/", "."), ".py")
414+
if modulename not in sys.modules:
415+
spec = importlib.util.spec_from_file_location(
416+
name=modulename,
417+
location=filename,
418+
loader=BuildFileLoaderImpl(fullname=modulename, path=filename),
419+
submodule_search_locations=[],
420+
)
421+
module = importlib.util.module_from_spec(spec)
422+
sys.modules[modulename] = module
423+
spec.loader.exec_module(module)
411424

412425

413426
def flatten(items):
@@ -433,6 +446,7 @@ def filenamesof(items):
433446
def generate(xs):
434447
for x in xs:
435448
if isinstance(x, Target):
449+
x.materialise()
436450
yield from generate(x.outs)
437451
else:
438452
yield x
@@ -458,63 +472,67 @@ def emit(*args, into=None):
458472

459473
def emit_rule(self, ins, outs, cmds=[], label=None):
460474
name = self.name
461-
fins = set(filenamesof(ins))
475+
fins_list = filenamesof(ins)
476+
fins = set(fins_list)
462477
fouts = filenamesof(outs)
463478
nonobjs = [f for f in fouts if not f.startswith("$(OBJ)")]
464479

465480
emit("")
481+
if VERBOSE_MK_FILE:
482+
for k, v in self.args.items():
483+
emit(f"# {k} = {v}")
466484

467485
lines = []
468486
if nonobjs:
469487
emit("clean::", into=lines)
470488
emit("\t$(hide) rm -f", *nonobjs, into=lines)
471489

490+
hashable = cmds + fins_list + fouts
491+
hash = hashlib.sha1(bytes("\n".join(hashable), "utf-8")).hexdigest()
492+
hashfile = join(self.dir, f"hash_{hash}")
493+
494+
global globalId
472495
emit(".PHONY:", name, into=lines)
473496
if outs:
474-
emit(name, ":", *fouts, into=lines)
475-
if len(fouts) == 1:
476-
emit(*fouts, ":", *fins, "\x01", into=lines)
477-
else:
478-
emit("ifeq ($(MAKE4.3),yes)", into=lines)
479-
emit(*fouts, "&:", *fins, "\x01", into=lines)
480-
emit("else", into=lines)
481-
emit(*(fouts[1:]), ":", fouts[0], into=lines)
482-
emit(fouts[0], ":", *fins, "\x01", into=lines)
483-
emit("endif", into=lines)
497+
outsn = globalId
498+
globalId = globalId + 1
499+
insn = globalId
500+
globalId = globalId + 1
501+
502+
emit(f"OUTS_{outsn}", "=", *fouts, into=lines)
503+
emit(f"INS_{insn}", "=", *fins, into=lines)
504+
emit(name, ":", f"$(OUTS_{outsn})")
505+
emit(hashfile, ":")
506+
emit(f"\t@mkdir -p {self.dir}")
507+
emit(f"\t@touch {hashfile}")
508+
emit(f"$(OUTS_{outsn})", "&:",f"$(INS_{insn})", hashfile, into=lines)
484509

485510
if label:
486-
emit("\t$(hide)", "$(ECHO) $(PROGRESSINFO)", label, into=lines)
511+
emit("\t$(hide)", "$(ECHO) $(PROGRESSINFO)" + label, into=lines)
487512

488513
sandbox = join(self.dir, "sandbox")
489514
emit("\t$(hide)", f"rm -rf {sandbox}", into=lines)
490515
emit(
491516
"\t$(hide)",
492-
f"$(PYTHON) build/_sandbox.py --link -s {sandbox}",
493-
*fins,
517+
"$(PYTHON) build/_sandbox.py --link -s",
518+
sandbox,
519+
f"$(INS_{insn})",
494520
into=lines,
495521
)
496522
for c in cmds:
497523
emit(f"\t$(hide) cd {sandbox} && (", c, ")", into=lines)
498524
emit(
499525
"\t$(hide)",
500-
f"$(PYTHON) build/_sandbox.py --export -s {sandbox}",
501-
*fouts,
526+
"$(PYTHON) build/_sandbox.py --export -s",
527+
sandbox,
528+
f"$(OUTS_{outsn})",
502529
into=lines,
503530
)
504531
else:
505532
assert len(cmds) == 0, "rules with no outputs cannot have commands"
506533
emit(name, ":", *fins, into=lines)
507534

508-
cmd = "".join(lines)
509-
hash = hashlib.sha1(bytes(cmd, "utf-8")).hexdigest()
510-
511-
outputFp.write(cmd.replace("\x01", f"$(OBJ)/.hashes/{hash}"))
512-
513-
if outs:
514-
emit(f"$(OBJ)/.hashes/{hash}:")
515-
emit(
516-
f"\t$(hide) mkdir -p $(OBJ)/.hashes && touch $(OBJ)/.hashes/{hash}"
517-
)
535+
outputFp.write("".join(lines))
518536
emit("")
519537

520538

@@ -578,13 +596,12 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []):
578596
)
579597
subrule.materialise()
580598

581-
simplerule(
582-
replaces=self,
583-
ins=outs + deps,
584-
outs=["=sentinel"],
585-
commands=["touch $[outs[0]]"],
586-
label="EXPORT",
587-
)
599+
self.ins = []
600+
self.outs = deps + outs
601+
602+
emit("")
603+
emit(".PHONY:", name)
604+
emit(name, ":", *filenamesof(outs + deps))
588605

589606

590607
def main():

0 commit comments

Comments
 (0)