1717import string
1818import sys
1919import hashlib
20+ import re
21+ import ast
22+ from collections import namedtuple
2023
2124verbose = False
2225quiet = False
2629materialisingStack = []
2730defaultGlobals = {}
2831
32+ RE_FORMAT_SPEC = re .compile (
33+ r"(?:(?P<fill>[\s\S])?(?P<align>[<>=^]))?"
34+ r"(?P<sign>[- +])?"
35+ r"(?P<pos_zero>z)?"
36+ r"(?P<alt>#)?"
37+ r"(?P<zero_padding>0)?"
38+ r"(?P<width_str>\d+)?"
39+ r"(?P<grouping>[_,])?"
40+ r"(?:(?P<decimal>\.)(?P<precision_str>\d+))?"
41+ r"(?P<type>[bcdeEfFgGnosxX%])?"
42+ )
43+
44+ CommandFormatSpec = namedtuple (
45+ "CommandFormatSpec" , RE_FORMAT_SPEC .groupindex .keys ()
46+ )
47+
2948sys .path += ["." ]
3049old_import = builtins .__import__
3150
@@ -80,6 +99,29 @@ def error(message):
8099 raise ABException (message )
81100
82101
102+ class BracketedFormatter (string .Formatter ):
103+ def parse (self , format_string ):
104+ while format_string :
105+ left , * right = format_string .split ("$[" , 1 )
106+ if not right :
107+ yield (left , None , None , None )
108+ break
109+ right = right [0 ]
110+
111+ offset = len (right ) + 1
112+ try :
113+ ast .parse (right )
114+ except SyntaxError as e :
115+ if not str (e ).startswith ("unmatched ']'" ):
116+ raise e
117+ offset = e .offset
118+
119+ expr = right [0 : offset - 1 ]
120+ format_string = right [offset :]
121+
122+ yield (left if left else None , expr , None , None )
123+
124+
83125def Rule (func ):
84126 sig = inspect .signature (func )
85127
@@ -166,7 +208,7 @@ def __repr__(self):
166208 return f"Target('{ self .name } ')"
167209
168210 def templateexpand (selfi , s ):
169- class Formatter (string . Formatter ):
211+ class Formatter (BracketedFormatter ):
170212 def get_field (self , name , a1 , a2 ):
171213 return (
172214 eval (name , selfi .callback .__globals__ , selfi .args ),
@@ -358,10 +400,11 @@ def convert(value, target):
358400def _removesuffix (self , suffix ):
359401 # suffix='' should not call self[:-0].
360402 if suffix and self .endswith (suffix ):
361- return self [:- len (suffix )]
403+ return self [: - len (suffix )]
362404 else :
363405 return self [:]
364406
407+
365408def loadbuildfile (filename ):
366409 filename = _removesuffix (filename .replace ("/" , "." ), ".py" )
367410 builtins .__import__ (filename )
@@ -413,8 +456,9 @@ def emit(*args, into=None):
413456 outputFp .write (s )
414457
415458
416- def emit_rule (name , ins , outs , cmds = [], label = None ):
417- fins = filenamesof (ins )
459+ def emit_rule (self , ins , outs , cmds = [], label = None ):
460+ name = self .name
461+ fins = set (filenamesof (ins ))
418462 fouts = filenamesof (outs )
419463 nonobjs = [f for f in fouts if not f .startswith ("$(OBJ)" )]
420464
@@ -440,8 +484,23 @@ def emit_rule(name, ins, outs, cmds=[], label=None):
440484
441485 if label :
442486 emit ("\t $(hide)" , "$(ECHO) $(PROGRESSINFO)" , label , into = lines )
487+
488+ sandbox = join (self .dir , "sandbox" )
489+ emit ("\t $(hide)" , f"rm -rf { sandbox } " , into = lines )
490+ emit (
491+ "\t $(hide)" ,
492+ f"$(PYTHON) build/_sandbox.py --link -s { sandbox } " ,
493+ * fins ,
494+ into = lines ,
495+ )
443496 for c in cmds :
444- emit ("\t $(hide)" , c , into = lines )
497+ emit (f"\t $(hide) cd { sandbox } && (" , c , ")" , into = lines )
498+ emit (
499+ "\t $(hide)" ,
500+ f"$(PYTHON) build/_sandbox.py --export -s { sandbox } " ,
501+ * fouts ,
502+ into = lines ,
503+ )
445504 else :
446505 assert len (cmds ) == 0 , "rules with no outputs cannot have commands"
447506 emit (name , ":" , * fins , into = lines )
@@ -486,10 +545,10 @@ def simplerule(
486545 cs += [self .templateexpand (c )]
487546
488547 emit_rule (
489- name = self . name ,
548+ self = self ,
490549 ins = ins + deps ,
491550 outs = outs ,
492- label = self .templateexpand ("{ label} { name} " ) if label else None ,
551+ label = self .templateexpand ("$[ label] $[ name] " ) if label else None ,
493552 cmds = cs ,
494553 )
495554
@@ -514,7 +573,7 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []):
514573 cwd = self .cwd ,
515574 ins = [srcs [0 ]],
516575 outs = [destf ],
517- commands = ["$(CP) %s %s" % (srcs [0 ], destf )],
576+ commands = ["$(CP) -H %s %s" % (srcs [0 ], destf )],
518577 label = "" ,
519578 )
520579 subrule .materialise ()
@@ -523,7 +582,7 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []):
523582 replaces = self ,
524583 ins = outs + deps ,
525584 outs = ["=sentinel" ],
526- commands = ["touch { outs[0]} " ],
585+ commands = ["touch $[ outs[0]] " ],
527586 label = "EXPORT" ,
528587 )
529588
0 commit comments