diff --git a/python/mozbuild/mozbuild/makeutil.py b/python/mozbuild/mozbuild/makeutil.py index 20b494daa613..280b80c7613e 100644 --- a/python/mozbuild/mozbuild/makeutil.py +++ b/python/mozbuild/mozbuild/makeutil.py @@ -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) diff --git a/python/mozbuild/mozbuild/test/test_makeutil.py b/python/mozbuild/mozbuild/test/test_makeutil.py index 5c11d172c49e..38ecdb34243f 100644 --- a/python/mozbuild/mozbuild/test/test_makeutil.py +++ b/python/mozbuild/mozbuild/test/test_makeutil.py @@ -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()