Bug 912914 - Preserve targets and dependencies order when creating Makefiles with makeutil.py. r=gps

Also allow to add random statements (like variable assignment)
This commit is contained in:
Mike Hommey 2013-09-11 08:21:39 +09:00
parent ab53a10348
commit 6889ad2ada
2 changed files with 43 additions and 22 deletions

View File

@ -15,7 +15,7 @@ class Makefile(object):
'''
def __init__(self):
self._rules = []
self._statements = []
def create_rule(self, targets=[]):
'''
@ -23,9 +23,16 @@ class Makefile(object):
Returns the corresponding Rule instance.
'''
rule = Rule(targets)
self._rules.append(rule)
self._statements.append(rule)
return rule
def add_statement(self, statement):
'''
Add a raw statement in the makefile. Meant to be used for
simple variable assignments.
'''
self._statements.append(statement)
def dump(self, fh, removal_guard=True):
'''
Dump all the rules to the given file handle. Optionally (and by
@ -34,12 +41,15 @@ class Makefile(object):
'''
all_deps = set()
all_targets = set()
for rule in self._rules:
rule.dump(fh)
all_deps.update(rule.dependencies())
all_targets.update(rule.targets())
for statement in self._statements:
if isinstance(statement, Rule):
statement.dump(fh)
all_deps.update(statement.dependencies())
all_targets.update(statement.targets())
else:
fh.write('%s\n' % statement)
if removal_guard:
guard = Rule(all_deps - all_targets)
guard = Rule(sorted(all_deps - all_targets))
guard.dump(fh)
@ -51,21 +61,23 @@ class Rule(object):
...
'''
def __init__(self, targets=[]):
self._targets = set()
self._dependencies = set()
self._targets = []
self._dependencies = []
self._commands = []
self.add_targets(targets)
def add_targets(self, targets):
'''Add additional targets to the rule.'''
assert isinstance(targets, Iterable) and not isinstance(targets, StringTypes)
self._targets.update(t.replace(os.sep, '/') for t in targets)
self._targets.extend(t.replace(os.sep, '/') for t in targets
if not t in self._targets)
return self
def add_dependencies(self, deps):
'''Add dependencies to the rule.'''
assert isinstance(deps, Iterable) and not isinstance(deps, StringTypes)
self._dependencies.update(d.replace(os.sep, '/') for d in deps)
self._dependencies.extend(d.replace(os.sep, '/') for d in deps
if not d in self._dependencies)
return self
def add_commands(self, commands):
@ -94,9 +106,9 @@ class Rule(object):
'''
if not self._targets:
return
fh.write('%s:' % ' '.join(sorted(self._targets)))
fh.write('%s:' % ' '.join(self._targets))
if self._dependencies:
fh.write(' %s' % ' '.join(sorted(self._dependencies)))
fh.write(' %s' % ' '.join(self._dependencies))
fh.write('\n')
for cmd in self._commands:
fh.write('\t%s\n' % cmd)

View File

@ -22,19 +22,13 @@ class TestMakefile(unittest.TestCase):
rule.add_targets(['foo', 'bar'])
rule.dump(out)
self.assertEqual(out.getvalue(), 'bar foo:\n')
self.assertEqual(out.getvalue(), 'foo bar:\n')
out.truncate(0)
rule.add_targets(['baz'])
rule.add_dependencies(['qux', 'hoge', 'piyo'])
rule.dump(out)
self.assertEqual(out.getvalue(), 'bar baz foo: hoge piyo qux\n')
out.truncate(0)
rule.add_targets(['baz'])
rule.add_dependencies(['qux', 'hoge', 'piyo'])
rule.dump(out)
self.assertEqual(out.getvalue(), 'bar baz foo: hoge piyo qux\n')
self.assertEqual(out.getvalue(), 'foo bar baz: qux hoge piyo\n')
out.truncate(0)
rule = Rule(['foo', 'bar'])
@ -43,7 +37,7 @@ class TestMakefile(unittest.TestCase):
rule.add_commands(['$(BAZ) -o $@ $<', '$(TOUCH) $@'])
rule.dump(out)
self.assertEqual(out.getvalue(),
'bar foo: baz\n' +
'foo bar: baz\n' +
'\techo $@\n' +
'\t$(BAZ) -o $@ $<\n' +
'\t$(TOUCH) $@\n')
@ -73,6 +67,21 @@ class TestMakefile(unittest.TestCase):
'\techo $@\n' +
'hoge qux:\n')
def test_statement(self):
out = StringIO()
mk = Makefile()
mk.create_rule(['foo']).add_dependencies(['bar']) \
.add_commands(['echo foo'])
mk.add_statement('BAR = bar')
mk.create_rule(['$(BAR)']).add_commands(['echo $@'])
mk.dump(out, removal_guard=False)
self.assertEqual(out.getvalue(),
'foo: bar\n' +
'\techo foo\n' +
'BAR = bar\n' +
'$(BAR):\n' +
'\techo $@\n')
@unittest.skipIf(os.name != 'nt', 'Test only applicable on Windows.')
def test_path_normalization(self):
out = StringIO()