Skip to content

Commit 6d73371

Browse files
committed
Update ab.
1 parent 4d60ff8 commit 6d73371

File tree

6 files changed

+408
-114
lines changed

6 files changed

+408
-114
lines changed

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: 59 additions & 35 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,74 @@ 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(
505+
name,
506+
":",
507+
hashfile,
508+
f"$(OUTS_{outsn})",
509+
into=lines,
510+
)
511+
emit(f"$(OUTS_{outsn})", ":", hashfile, into=lines)
512+
emit(hashfile, ":", f"$(INS_{insn})", into=lines)
484513

485514
if label:
486-
emit("\t$(hide)", "$(ECHO) $(PROGRESSINFO)", label, into=lines)
515+
emit("\t$(hide)", "$(ECHO) $(PROGRESSINFO)" + label, into=lines)
487516

488517
sandbox = join(self.dir, "sandbox")
489518
emit("\t$(hide)", f"rm -rf {sandbox}", into=lines)
490519
emit(
491520
"\t$(hide)",
492-
f"$(PYTHON) build/_sandbox.py --link -s {sandbox}",
493-
*fins,
521+
"$(PYTHON) build/_sandbox.py --link -s",
522+
sandbox,
523+
f"$(INS_{insn})",
494524
into=lines,
495525
)
496526
for c in cmds:
497527
emit(f"\t$(hide) cd {sandbox} && (", c, ")", into=lines)
498528
emit(
499529
"\t$(hide)",
500-
f"$(PYTHON) build/_sandbox.py --export -s {sandbox}",
501-
*fouts,
530+
"$(PYTHON) build/_sandbox.py --export -s",
531+
sandbox,
532+
f"$(OUTS_{outsn})",
502533
into=lines,
503534
)
504535
else:
505536
assert len(cmds) == 0, "rules with no outputs cannot have commands"
506537
emit(name, ":", *fins, into=lines)
507538

508-
cmd = "".join(lines)
509-
hash = hashlib.sha1(bytes(cmd, "utf-8")).hexdigest()
510-
511-
outputFp.write(cmd.replace("\x01", f"$(OBJ)/.hashes/{hash}"))
539+
outputFp.write("".join(lines))
512540

513541
if outs:
514-
emit(f"$(OBJ)/.hashes/{hash}:")
515-
emit(
516-
f"\t$(hide) mkdir -p $(OBJ)/.hashes && touch $(OBJ)/.hashes/{hash}"
517-
)
542+
emit(f"\t$(hide) touch {hashfile}")
518543
emit("")
519544

520545

@@ -578,13 +603,12 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []):
578603
)
579604
subrule.materialise()
580605

581-
simplerule(
582-
replaces=self,
583-
ins=outs + deps,
584-
outs=["=sentinel"],
585-
commands=["touch $[outs[0]]"],
586-
label="EXPORT",
587-
)
606+
self.ins = []
607+
self.outs = deps + outs
608+
609+
emit("")
610+
emit(".PHONY:", name)
611+
emit(name, ":", *filenamesof(outs + deps))
588612

589613

590614
def main():

0 commit comments

Comments
 (0)