diff --git a/Makefile.in b/Makefile.in index 95395677181d..682af0080ef1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -34,6 +34,7 @@ else configure_dir = $(topsrcdir) endif +ifndef TEST_MOZBUILD ifndef MOZ_PROFILE_USE # We need to explicitly put backend.RecursiveMakeBackend here # otherwise the rule in rules.mk doesn't run early enough. @@ -44,6 +45,7 @@ $(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status endif endif endif +endif ifdef JS_STANDALONE .PHONY: CLOBBER @@ -81,6 +83,7 @@ config.status js/src/config.status: # The mach build driver will ensure the backend is up to date for partial tree # builds. This cleanly avoids most of the pain. +ifndef TEST_MOZBUILD backend.RecursiveMakeBackend: @echo 'Build configuration changed. Regenerating backend.' $(PYTHON) config.status @@ -91,6 +94,7 @@ Makefile: backend.RecursiveMakeBackend include backend.RecursiveMakeBackend.pp default:: backend.RecursiveMakeBackend +endif install_manifests := \ $(addprefix dist/,bin branding idl include public private sdk xpi-stage) \ diff --git a/config/faster/rules.mk b/config/faster/rules.mk index 3b1f910875e4..28ca22ea3d2a 100644 --- a/config/faster/rules.mk +++ b/config/faster/rules.mk @@ -43,7 +43,9 @@ default: $(addprefix install-,$(INSTALL_MANIFESTS)) # Explicit files to be built for a default build default: $(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS)) +ifndef TEST_MOZBUILD default: $(TOPOBJDIR)/dist/bin/platform.ini +endif ifndef NO_XPIDL # Targets from the recursive make backend to be built for a default build @@ -52,6 +54,9 @@ endif ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) # Mac builds require to copy things in dist/bin/*.app +# TODO: remove the MOZ_WIDGET_TOOLKIT and MOZ_BUILD_APP variables from +# faster/Makefile and python/mozbuild/mozbuild/test/backend/test_build.py +# when this is not required anymore. default: $(MAKE) -C $(TOPOBJDIR)/$(MOZ_BUILD_APP)/app repackage endif diff --git a/python/moz.build b/python/moz.build index d9f2064c2143..66c474c787fb 100644 --- a/python/moz.build +++ b/python/moz.build @@ -35,6 +35,7 @@ PYTHON_UNIT_TESTS += [ 'mozbuild/mozbuild/test/backend/__init__.py', 'mozbuild/mozbuild/test/backend/common.py', 'mozbuild/mozbuild/test/backend/test_android_eclipse.py', + 'mozbuild/mozbuild/test/backend/test_build.py', 'mozbuild/mozbuild/test/backend/test_configenvironment.py', 'mozbuild/mozbuild/test/backend/test_recursivemake.py', 'mozbuild/mozbuild/test/backend/test_visualstudio.py', diff --git a/python/mozbuild/mozbuild/test/backend/data/build/app/moz.build b/python/mozbuild/mozbuild/test/backend/data/build/app/moz.build new file mode 100644 index 000000000000..afc4b90b0dcc --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/app/moz.build @@ -0,0 +1,49 @@ +DIST_SUBDIR = 'app' + +EXTRA_JS_MODULES += [ + '../foo.jsm', +] + +EXTRA_JS_MODULES.child += [ + '../bar.jsm', +] + +EXTRA_PP_JS_MODULES += [ + '../baz.jsm', +] + +EXTRA_PP_JS_MODULES.child2 += [ + '../qux.jsm', +] + +FINAL_TARGET_FILES += [ + '../foo.ini', +] + +FINAL_TARGET_FILES.child += [ + '../bar.ini', +] + +FINAL_TARGET_PP_FILES += [ + '../baz.ini', +] + +FINAL_TARGET_PP_FILES.child2 += [ + '../qux.ini', +] + +EXTRA_COMPONENTS += [ + '../components.manifest', + '../foo.js', +] + +EXTRA_PP_COMPONENTS += [ + '../bar.js', +] + +JS_PREFERENCE_FILES += [ + '../prefs.js', +] + +DEFINES['FOO'] = 'bar' +DEFINES['BAR'] = True diff --git a/python/mozbuild/mozbuild/test/backend/data/build/bar.ini b/python/mozbuild/mozbuild/test/backend/data/build/bar.ini new file mode 100644 index 000000000000..91dcbe15361a --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/bar.ini @@ -0,0 +1 @@ +bar.ini diff --git a/python/mozbuild/mozbuild/test/backend/data/build/bar.js b/python/mozbuild/mozbuild/test/backend/data/build/bar.js new file mode 100644 index 000000000000..1a608e8a5616 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/bar.js @@ -0,0 +1,2 @@ +#filter substitution +bar.js: FOO is @FOO@ diff --git a/python/mozbuild/mozbuild/test/backend/data/build/bar.jsm b/python/mozbuild/mozbuild/test/backend/data/build/bar.jsm new file mode 100644 index 000000000000..05db2e2f6aa8 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/bar.jsm @@ -0,0 +1 @@ +bar.jsm diff --git a/python/mozbuild/mozbuild/test/backend/data/build/baz.ini b/python/mozbuild/mozbuild/test/backend/data/build/baz.ini new file mode 100644 index 000000000000..975a1e437d9e --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/baz.ini @@ -0,0 +1,2 @@ +#filter substitution +baz.ini: FOO is @FOO@ diff --git a/python/mozbuild/mozbuild/test/backend/data/build/baz.jsm b/python/mozbuild/mozbuild/test/backend/data/build/baz.jsm new file mode 100644 index 000000000000..f39ed0208211 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/baz.jsm @@ -0,0 +1,2 @@ +#filter substitution +baz.jsm: FOO is @FOO@ diff --git a/python/mozbuild/mozbuild/test/backend/data/build/components.manifest b/python/mozbuild/mozbuild/test/backend/data/build/components.manifest new file mode 100644 index 000000000000..b5bb87254c9c --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/components.manifest @@ -0,0 +1,2 @@ +component {foo} foo.js +component {bar} bar.js diff --git a/python/mozbuild/mozbuild/test/backend/data/build/foo.ini b/python/mozbuild/mozbuild/test/backend/data/build/foo.ini new file mode 100644 index 000000000000..c93c9d7658ef --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/foo.ini @@ -0,0 +1 @@ +foo.ini diff --git a/python/mozbuild/mozbuild/test/backend/data/build/foo.js b/python/mozbuild/mozbuild/test/backend/data/build/foo.js new file mode 100644 index 000000000000..4fa71e2d27dc --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/foo.js @@ -0,0 +1 @@ +foo.js diff --git a/python/mozbuild/mozbuild/test/backend/data/build/foo.jsm b/python/mozbuild/mozbuild/test/backend/data/build/foo.jsm new file mode 100644 index 000000000000..d58fd61c16e8 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/foo.jsm @@ -0,0 +1 @@ +foo.jsm diff --git a/python/mozbuild/mozbuild/test/backend/data/build/moz.build b/python/mozbuild/mozbuild/test/backend/data/build/moz.build new file mode 100644 index 000000000000..c69219b91165 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/moz.build @@ -0,0 +1,63 @@ +CONFIGURE_SUBST_FILES += [ + '/config/autoconf.mk', + '/config/emptyvars.mk', +] + +EXTRA_JS_MODULES += [ + 'foo.jsm', +] + +EXTRA_JS_MODULES.child += [ + 'bar.jsm', +] + +EXTRA_PP_JS_MODULES += [ + 'baz.jsm', +] + +EXTRA_PP_JS_MODULES.child2 += [ + 'qux.jsm', +] + +FINAL_TARGET_FILES += [ + 'foo.ini', +] + +FINAL_TARGET_FILES.child += [ + 'bar.ini', +] + +FINAL_TARGET_PP_FILES += [ + 'baz.ini', +] + +FINAL_TARGET_PP_FILES.child2 += [ + 'qux.ini', +] + +EXTRA_COMPONENTS += [ + 'components.manifest', + 'foo.js', +] + +EXTRA_PP_COMPONENTS += [ + 'bar.js', +] + +JS_PREFERENCE_FILES += [ + 'prefs.js', +] + +RESOURCE_FILES += [ + 'resource', +] + +RESOURCE_FILES.child += [ + 'resource2', +] + +DEFINES['FOO'] = 'foo' + +DIRS += [ + 'app', +] diff --git a/python/mozbuild/mozbuild/test/backend/data/build/prefs.js b/python/mozbuild/mozbuild/test/backend/data/build/prefs.js new file mode 100644 index 000000000000..a030da9fd77b --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/prefs.js @@ -0,0 +1 @@ +prefs.js diff --git a/python/mozbuild/mozbuild/test/backend/data/build/qux.ini b/python/mozbuild/mozbuild/test/backend/data/build/qux.ini new file mode 100644 index 000000000000..3ce157eb6dbe --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/qux.ini @@ -0,0 +1,5 @@ +#ifdef BAR +qux.ini: BAR is defined +#else +qux.ini: BAR is not defined +#endif diff --git a/python/mozbuild/mozbuild/test/backend/data/build/qux.jsm b/python/mozbuild/mozbuild/test/backend/data/build/qux.jsm new file mode 100644 index 000000000000..9c5fe28d584e --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/qux.jsm @@ -0,0 +1,5 @@ +#ifdef BAR +qux.jsm: BAR is defined +#else +qux.jsm: BAR is not defined +#endif diff --git a/python/mozbuild/mozbuild/test/backend/data/build/resource b/python/mozbuild/mozbuild/test/backend/data/build/resource new file mode 100644 index 000000000000..91e75c679ee4 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/resource @@ -0,0 +1 @@ +resource diff --git a/python/mozbuild/mozbuild/test/backend/data/build/resource2 b/python/mozbuild/mozbuild/test/backend/data/build/resource2 new file mode 100644 index 000000000000..b7c270096491 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/data/build/resource2 @@ -0,0 +1 @@ +resource2 diff --git a/python/mozbuild/mozbuild/test/backend/test_build.py b/python/mozbuild/mozbuild/test/backend/test_build.py new file mode 100644 index 000000000000..09ad35b439f7 --- /dev/null +++ b/python/mozbuild/mozbuild/test/backend/test_build.py @@ -0,0 +1,166 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from __future__ import unicode_literals, print_function + +import buildconfig +import os +import shutil +import sys +import unittest +import mozpack.path as mozpath +from contextlib import contextmanager +from mozunit import main +from mozbuild.backend.configenvironment import ConfigEnvironment +from mozbuild.backend.recursivemake import RecursiveMakeBackend +from mozbuild.backend.fastermake import FasterMakeBackend +from mozbuild.base import MozbuildObject +from mozbuild.frontend.emitter import TreeMetadataEmitter +from mozbuild.frontend.reader import BuildReader +from mozbuild.util import ensureParentDir +from mozpack.files import FileFinder +from tempfile import mkdtemp + + +BASE_SUBSTS = [ + ('PYTHON', sys.executable), +] + + +class TestBuild(unittest.TestCase): + @contextmanager + def do_test_backend(self, *backends, **kwargs): + topobjdir = mkdtemp() + try: + config = ConfigEnvironment(buildconfig.topsrcdir, topobjdir, + **kwargs) + reader = BuildReader(config) + emitter = TreeMetadataEmitter(config) + moz_build = mozpath.join(config.topsrcdir, 'test.mozbuild') + definitions = list(emitter.emit( + reader.read_mozbuild(moz_build, config))) + for backend in backends: + backend(config).consume(definitions) + + yield config + except: + raise + finally: + if not os.environ.get('MOZ_NO_CLEANUP'): + shutil.rmtree(topobjdir) + + @contextmanager + def line_handler(self): + lines = [] + + def handle_make_line(line): + lines.append(line) + + try: + yield handle_make_line + except: + print('\n'.join(lines)) + raise + + if os.environ.get('MOZ_VERBOSE_MAKE'): + print('\n'.join(lines)) + + def test_recursive_make(self): + substs = list(BASE_SUBSTS) + with self.do_test_backend(RecursiveMakeBackend, + substs=substs) as config: + build = MozbuildObject(config.topsrcdir, None, None, + config.topobjdir) + overrides = [ + 'install_manifest_depends=', + 'TEST_MOZBUILD=1', + ] + with self.line_handler() as handle_make_line: + build._run_make(directory=config.topobjdir, target=overrides, + silent=False, line_handler=handle_make_line) + + self.validate(config) + + def test_faster_make(self): + substs = list(BASE_SUBSTS) + [ + ('MOZ_BUILD_APP', 'dummy_app'), + ('MOZ_WIDGET_TOOLKIT', 'dummy_widget'), + ] + with self.do_test_backend(RecursiveMakeBackend, FasterMakeBackend, + substs=substs) as config: + buildid = mozpath.join(config.topobjdir, 'config', 'buildid') + ensureParentDir(buildid) + with open(buildid, 'w') as fh: + fh.write('20100101012345\n') + + build = MozbuildObject(config.topsrcdir, None, None, + config.topobjdir) + overrides = [ + 'TEST_MOZBUILD=1', + ] + with self.line_handler() as handle_make_line: + build._run_make(directory=mozpath.join(config.topobjdir, + 'faster'), + target=overrides, silent=False, + line_handler=handle_make_line) + + self.validate(config) + + def validate(self, config): + self.maxDiff = None + test_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'data', 'build') + os.sep + + # We want unicode instances out of the files, because having plain str + # makes assertEqual diff output in case of error extra verbose because + # of the difference in type. + result = { + p: f.open().read().decode('utf-8') + for p, f in FileFinder(mozpath.join(config.topobjdir, 'dist')) + } + self.assertTrue(len(result)) + self.assertEqual(result, { + 'bin/baz.ini': 'baz.ini: FOO is foo\n', + 'bin/child/bar.ini': 'bar.ini\n', + 'bin/child2/qux.ini': 'qux.ini: BAR is not defined\n', + 'bin/chrome.manifest': 'manifest components/components.manifest\n', + 'bin/components/bar.js': + '//@line 2 "%sbar.js"\nbar.js: FOO is foo\n' % (test_path), + 'bin/components/components.manifest': + 'component {foo} foo.js\ncomponent {bar} bar.js\n', + 'bin/components/foo.js': 'foo.js\n', + 'bin/defaults/pref/prefs.js': 'prefs.js\n', + 'bin/foo.ini': 'foo.ini\n', + 'bin/modules/baz.jsm': + '//@line 2 "%sbaz.jsm"\nbaz.jsm: FOO is foo\n' % (test_path), + 'bin/modules/child/bar.jsm': 'bar.jsm\n', + 'bin/modules/child2/qux.jsm': + '//@line 4 "%squx.jsm"\nqux.jsm: BAR is not defined\n' + % (test_path), + 'bin/modules/foo.jsm': 'foo.jsm\n', + 'bin/res/resource': 'resource\n', + 'bin/res/child/resource2': 'resource2\n', + + 'bin/app/baz.ini': 'baz.ini: FOO is bar\n', + 'bin/app/child/bar.ini': 'bar.ini\n', + 'bin/app/child2/qux.ini': 'qux.ini: BAR is defined\n', + 'bin/app/chrome.manifest': 'manifest components/components.manifest\n', + 'bin/app/components/bar.js': + '//@line 2 "%sbar.js"\nbar.js: FOO is bar\n' % (test_path), + 'bin/app/components/components.manifest': + 'component {foo} foo.js\ncomponent {bar} bar.js\n', + 'bin/app/components/foo.js': 'foo.js\n', + 'bin/app/defaults/preferences/prefs.js': 'prefs.js\n', + 'bin/app/foo.ini': 'foo.ini\n', + 'bin/app/modules/baz.jsm': + '//@line 2 "%sbaz.jsm"\nbaz.jsm: FOO is bar\n' % (test_path), + 'bin/app/modules/child/bar.jsm': 'bar.jsm\n', + 'bin/app/modules/child2/qux.jsm': + '//@line 2 "%squx.jsm"\nqux.jsm: BAR is defined\n' + % (test_path), + 'bin/app/modules/foo.jsm': 'foo.jsm\n', + }) + +if __name__ == '__main__': + main() diff --git a/test.mozbuild b/test.mozbuild new file mode 100644 index 000000000000..9db5f980d69a --- /dev/null +++ b/test.mozbuild @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This file is necessary to "bootstrap" the test case for the test_build +# test, because of the requirement of the top-level directory containing +# config/*.mk. +DIRS += [ + 'python/mozbuild/mozbuild/test/backend/data/build', +]