@@ -294,13 +294,15 @@ def _is_recipe_comment(tok):
294294 # corner case to handle a line with leading <tab> and a comment
295295 # which will be a Recipe if we're inside a Rule but is ignored
296296 # before we've seen a Rule
297+ tok = tok .token_list [0 ]
297298 try :
298- tok = tok .token_list [0 ]
299299 lit = tok .literal
300300 except AttributeError :
301301 # not a literal therefore definitely can't be a comment
302302 return False
303- return tokenizer .seek_comment (iter (tok .string ))
303+ s = tok .makefile ().lstrip ()
304+ return s [0 ] == '#'
305+ # return tokenizer.seek_comment(iter(tok.string))
304306
305307 for statement in stmt_list :
306308 # sanity check; everything has to have a successful get_pos()
@@ -314,18 +316,46 @@ def _is_recipe_comment(tok):
314316 # If this is just a comment line, ignore it
315317 # But if we haven't seen a rule, throw the infamous error.
316318
317- if not curr_rules and not _is_recipe_comment (statement ):
319+ # use a better name
320+ recipe = statement
321+
322+ if not curr_rules and not _is_recipe_comment (recipe ):
318323 # So We're confused.
319324 raise RecipeCommencesBeforeFirstTarget (pos = statement .get_pos ())
320325
321- [rule .add_recipe (statement ) for rule in curr_rules ]
326+ # The RuleDB contains a Rule instance for each target. The RuleDB
327+ # is key'd by the target string. Given a rule with multiple targets
328+ # such as
329+ # a b c d: ; @echo $@
330+ # there will be four separate Rule instances in the RuleDB.
331+ #
332+ # Each Rule instance has a RecipeList instance (which is basically
333+ # just a wrapper around a python list to automatically support the
334+ # .makefile() method). The Rule's RecipeList is created from the
335+ # RuleExpression.
336+ #
337+ # Here's the punchline:
338+ # The Symbol class hierarchy creates one RuleExpression and one
339+ # RecipeList even if there are multiple targets. But the RuleDB
340+ # uses a separate Rule instance for each target. The RecipeList
341+ # instance is therefore shared between each Rule (basically, all
342+ # Rule instances point to the exact same RecipeList instance)
343+ #
344+ if curr_rules :
345+ if len (curr_rules ) > 1 :
346+ # sanity clause
347+ id_ = id (curr_rules [0 ].recipe_list )
348+ assert all ( id_ == id (r .recipe_list ) for r in curr_rules )
349+ curr_rules [0 ].add_recipe (recipe )
350+ # [rule.add_recipe(recipe) for rule in curr_rules]
322351
323352 elif isinstance (statement ,RuleExpression ):
324353 # restart the rules list but maintain the same ref!
325354 # (need the same ref because this array is passed by the caller and
326355 # we need to track the values across calls to this function)
327356 curr_rules .clear ()
328357
358+ # use a better name
329359 rule_expr = statement
330360 m = rule_expr .makefile ()
331361
@@ -602,7 +632,7 @@ def execute(makefile, args):
602632 # target" error.
603633 #
604634 # Basically, we have context sensitive evaluation.
605- curr_rules = []
635+ curr_rules = [] # array of Rule instances
606636
607637 # For handling $(eval) This is not my proudest moment. I originally
608638 # designed my make function implementations to be truly functional (no side
0 commit comments