summaryrefslogtreecommitdiffstats
path: root/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozbuild/mozbuild/test/backend/test_recursivemake.py')
-rw-r--r--python/mozbuild/mozbuild/test/backend/test_recursivemake.py1307
1 files changed, 1307 insertions, 0 deletions
diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
new file mode 100644
index 0000000000..acbada060b
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -0,0 +1,1307 @@
+# 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/.
+
+import io
+import os
+import unittest
+
+import mozpack.path as mozpath
+import six
+import six.moves.cPickle as pickle
+from mozpack.manifests import InstallManifest
+from mozunit import main
+
+from mozbuild.backend.recursivemake import RecursiveMakeBackend, RecursiveMakeTraversal
+from mozbuild.backend.test_manifest import TestManifestBackend
+from mozbuild.frontend.emitter import TreeMetadataEmitter
+from mozbuild.frontend.reader import BuildReader
+from mozbuild.test.backend.common import BackendTester
+
+
+class TestRecursiveMakeTraversal(unittest.TestCase):
+ def test_traversal(self):
+ traversal = RecursiveMakeTraversal()
+ traversal.add("", dirs=["A", "B", "C"])
+ traversal.add("", dirs=["D"])
+ traversal.add("A")
+ traversal.add("B", dirs=["E", "F"])
+ traversal.add("C", dirs=["G", "H"])
+ traversal.add("D", dirs=["I", "K"])
+ traversal.add("D", dirs=["J", "L"])
+ traversal.add("E")
+ traversal.add("F")
+ traversal.add("G")
+ traversal.add("H")
+ traversal.add("I", dirs=["M", "N"])
+ traversal.add("J", dirs=["O", "P"])
+ traversal.add("K", dirs=["Q", "R"])
+ traversal.add("L", dirs=["S"])
+ traversal.add("M")
+ traversal.add("N", dirs=["T"])
+ traversal.add("O")
+ traversal.add("P", dirs=["U"])
+ traversal.add("Q")
+ traversal.add("R", dirs=["V"])
+ traversal.add("S", dirs=["W"])
+ traversal.add("T")
+ traversal.add("U")
+ traversal.add("V")
+ traversal.add("W", dirs=["X"])
+ traversal.add("X")
+
+ parallels = set(("G", "H", "I", "J", "O", "P", "Q", "R", "U"))
+
+ def filter(current, subdirs):
+ return (
+ current,
+ [d for d in subdirs.dirs if d in parallels],
+ [d for d in subdirs.dirs if d not in parallels],
+ )
+
+ start, deps = traversal.compute_dependencies(filter)
+ self.assertEqual(start, ("X",))
+ self.maxDiff = None
+ self.assertEqual(
+ deps,
+ {
+ "A": ("",),
+ "B": ("A",),
+ "C": ("F",),
+ "D": ("G", "H"),
+ "E": ("B",),
+ "F": ("E",),
+ "G": ("C",),
+ "H": ("C",),
+ "I": ("D",),
+ "J": ("D",),
+ "K": ("T", "O", "U"),
+ "L": ("Q", "V"),
+ "M": ("I",),
+ "N": ("M",),
+ "O": ("J",),
+ "P": ("J",),
+ "Q": ("K",),
+ "R": ("K",),
+ "S": ("L",),
+ "T": ("N",),
+ "U": ("P",),
+ "V": ("R",),
+ "W": ("S",),
+ "X": ("W",),
+ },
+ )
+
+ self.assertEqual(
+ list(traversal.traverse("", filter)),
+ [
+ "",
+ "A",
+ "B",
+ "E",
+ "F",
+ "C",
+ "G",
+ "H",
+ "D",
+ "I",
+ "M",
+ "N",
+ "T",
+ "J",
+ "O",
+ "P",
+ "U",
+ "K",
+ "Q",
+ "R",
+ "V",
+ "L",
+ "S",
+ "W",
+ "X",
+ ],
+ )
+
+ self.assertEqual(list(traversal.traverse("C", filter)), ["C", "G", "H"])
+
+ def test_traversal_2(self):
+ traversal = RecursiveMakeTraversal()
+ traversal.add("", dirs=["A", "B", "C"])
+ traversal.add("A")
+ traversal.add("B", dirs=["D", "E", "F"])
+ traversal.add("C", dirs=["G", "H", "I"])
+ traversal.add("D")
+ traversal.add("E")
+ traversal.add("F")
+ traversal.add("G")
+ traversal.add("H")
+ traversal.add("I")
+
+ start, deps = traversal.compute_dependencies()
+ self.assertEqual(start, ("I",))
+ self.assertEqual(
+ deps,
+ {
+ "A": ("",),
+ "B": ("A",),
+ "C": ("F",),
+ "D": ("B",),
+ "E": ("D",),
+ "F": ("E",),
+ "G": ("C",),
+ "H": ("G",),
+ "I": ("H",),
+ },
+ )
+
+ def test_traversal_filter(self):
+ traversal = RecursiveMakeTraversal()
+ traversal.add("", dirs=["A", "B", "C"])
+ traversal.add("A")
+ traversal.add("B", dirs=["D", "E", "F"])
+ traversal.add("C", dirs=["G", "H", "I"])
+ traversal.add("D")
+ traversal.add("E")
+ traversal.add("F")
+ traversal.add("G")
+ traversal.add("H")
+ traversal.add("I")
+
+ def filter(current, subdirs):
+ if current == "B":
+ current = None
+ return current, [], subdirs.dirs
+
+ start, deps = traversal.compute_dependencies(filter)
+ self.assertEqual(start, ("I",))
+ self.assertEqual(
+ deps,
+ {
+ "A": ("",),
+ "C": ("F",),
+ "D": ("A",),
+ "E": ("D",),
+ "F": ("E",),
+ "G": ("C",),
+ "H": ("G",),
+ "I": ("H",),
+ },
+ )
+
+ def test_traversal_parallel(self):
+ traversal = RecursiveMakeTraversal()
+ traversal.add("", dirs=["A", "B", "C"])
+ traversal.add("A")
+ traversal.add("B", dirs=["D", "E", "F"])
+ traversal.add("C", dirs=["G", "H", "I"])
+ traversal.add("D")
+ traversal.add("E")
+ traversal.add("F")
+ traversal.add("G")
+ traversal.add("H")
+ traversal.add("I")
+ traversal.add("J")
+
+ def filter(current, subdirs):
+ return current, subdirs.dirs, []
+
+ start, deps = traversal.compute_dependencies(filter)
+ self.assertEqual(start, ("A", "D", "E", "F", "G", "H", "I", "J"))
+ self.assertEqual(
+ deps,
+ {
+ "A": ("",),
+ "B": ("",),
+ "C": ("",),
+ "D": ("B",),
+ "E": ("B",),
+ "F": ("B",),
+ "G": ("C",),
+ "H": ("C",),
+ "I": ("C",),
+ "J": ("",),
+ },
+ )
+
+
+class TestRecursiveMakeBackend(BackendTester):
+ def test_basic(self):
+ """Ensure the RecursiveMakeBackend works without error."""
+ env = self._consume("stub0", RecursiveMakeBackend)
+ self.assertTrue(
+ os.path.exists(mozpath.join(env.topobjdir, "backend.RecursiveMakeBackend"))
+ )
+ self.assertTrue(
+ os.path.exists(
+ mozpath.join(env.topobjdir, "backend.RecursiveMakeBackend.in")
+ )
+ )
+
+ def test_output_files(self):
+ """Ensure proper files are generated."""
+ env = self._consume("stub0", RecursiveMakeBackend)
+
+ expected = ["", "dir1", "dir2"]
+
+ for d in expected:
+ out_makefile = mozpath.join(env.topobjdir, d, "Makefile")
+ out_backend = mozpath.join(env.topobjdir, d, "backend.mk")
+
+ self.assertTrue(os.path.exists(out_makefile))
+ self.assertTrue(os.path.exists(out_backend))
+
+ def test_makefile_conversion(self):
+ """Ensure Makefile.in is converted properly."""
+ env = self._consume("stub0", RecursiveMakeBackend)
+
+ p = mozpath.join(env.topobjdir, "Makefile")
+
+ lines = [
+ l.strip() for l in open(p, "rt").readlines()[1:] if not l.startswith("#")
+ ]
+ self.assertEqual(
+ lines,
+ [
+ "DEPTH := .",
+ "topobjdir := %s" % env.topobjdir,
+ "topsrcdir := %s" % env.topsrcdir,
+ "srcdir := %s" % env.topsrcdir,
+ "srcdir_rel := %s" % mozpath.relpath(env.topsrcdir, env.topobjdir),
+ "relativesrcdir := .",
+ "include $(DEPTH)/config/autoconf.mk",
+ "",
+ "FOO := foo",
+ "",
+ "include $(topsrcdir)/config/recurse.mk",
+ ],
+ )
+
+ def test_missing_makefile_in(self):
+ """Ensure missing Makefile.in results in Makefile creation."""
+ env = self._consume("stub0", RecursiveMakeBackend)
+
+ p = mozpath.join(env.topobjdir, "dir2", "Makefile")
+ self.assertTrue(os.path.exists(p))
+
+ lines = [l.strip() for l in open(p, "rt").readlines()]
+ self.assertEqual(len(lines), 10)
+
+ self.assertTrue(lines[0].startswith("# THIS FILE WAS AUTOMATICALLY"))
+
+ def test_backend_mk(self):
+ """Ensure backend.mk file is written out properly."""
+ env = self._consume("stub0", RecursiveMakeBackend)
+
+ p = mozpath.join(env.topobjdir, "backend.mk")
+
+ lines = [l.strip() for l in open(p, "rt").readlines()[2:]]
+ self.assertEqual(lines, ["DIRS := dir1 dir2"])
+
+ # Make env.substs writable to add ENABLE_TESTS
+ env.substs = dict(env.substs)
+ env.substs["ENABLE_TESTS"] = "1"
+ self._consume("stub0", RecursiveMakeBackend, env=env)
+ p = mozpath.join(env.topobjdir, "backend.mk")
+
+ lines = [l.strip() for l in open(p, "rt").readlines()[2:]]
+ self.assertEqual(lines, ["DIRS := dir1 dir2 dir3"])
+
+ def test_mtime_no_change(self):
+ """Ensure mtime is not updated if file content does not change."""
+
+ env = self._consume("stub0", RecursiveMakeBackend)
+
+ makefile_path = mozpath.join(env.topobjdir, "Makefile")
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ makefile_mtime = os.path.getmtime(makefile_path)
+ backend_mtime = os.path.getmtime(backend_path)
+
+ reader = BuildReader(env)
+ emitter = TreeMetadataEmitter(env)
+ backend = RecursiveMakeBackend(env)
+ backend.consume(emitter.emit(reader.read_topsrcdir()))
+
+ self.assertEqual(os.path.getmtime(makefile_path), makefile_mtime)
+ self.assertEqual(os.path.getmtime(backend_path), backend_mtime)
+
+ def test_substitute_config_files(self):
+ """Ensure substituted config files are produced."""
+ env = self._consume("substitute_config_files", RecursiveMakeBackend)
+
+ p = mozpath.join(env.topobjdir, "foo")
+ self.assertTrue(os.path.exists(p))
+ lines = [l.strip() for l in open(p, "rt").readlines()]
+ self.assertEqual(lines, ["TEST = foo"])
+
+ def test_install_substitute_config_files(self):
+ """Ensure we recurse into the dirs that install substituted config files."""
+ env = self._consume("install_substitute_config_files", RecursiveMakeBackend)
+
+ root_deps_path = mozpath.join(env.topobjdir, "root-deps.mk")
+ lines = [l.strip() for l in open(root_deps_path, "rt").readlines()]
+
+ # Make sure we actually recurse into the sub directory during export to
+ # install the subst file.
+ self.assertTrue(any(l == "recurse_export: sub/export" for l in lines))
+
+ def test_variable_passthru(self):
+ """Ensure variable passthru is written out correctly."""
+ env = self._consume("variable_passthru", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = {
+ "RCFILE": ["RCFILE := $(srcdir)/foo.rc"],
+ "RCINCLUDE": ["RCINCLUDE := $(srcdir)/bar.rc"],
+ "WIN32_EXE_LDFLAGS": ["WIN32_EXE_LDFLAGS += -subsystem:console"],
+ }
+
+ for var, val in expected.items():
+ # print("test_variable_passthru[%s]" % (var))
+ found = [str for str in lines if str.startswith(var)]
+ self.assertEqual(found, val)
+
+ def test_sources(self):
+ """Ensure SOURCES, HOST_SOURCES and WASM_SOURCES are handled properly."""
+ env = self._consume("sources", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = {
+ "ASFILES": ["ASFILES += $(srcdir)/bar.s", "ASFILES += $(srcdir)/foo.asm"],
+ "CMMSRCS": ["CMMSRCS += $(srcdir)/fuga.mm", "CMMSRCS += $(srcdir)/hoge.mm"],
+ "CSRCS": ["CSRCS += $(srcdir)/baz.c", "CSRCS += $(srcdir)/qux.c"],
+ "HOST_CPPSRCS": [
+ "HOST_CPPSRCS += $(srcdir)/bar.cpp",
+ "HOST_CPPSRCS += $(srcdir)/foo.cpp",
+ ],
+ "HOST_CSRCS": [
+ "HOST_CSRCS += $(srcdir)/baz.c",
+ "HOST_CSRCS += $(srcdir)/qux.c",
+ ],
+ "SSRCS": ["SSRCS += $(srcdir)/titi.S", "SSRCS += $(srcdir)/toto.S"],
+ "WASM_CSRCS": ["WASM_CSRCS += $(srcdir)/baz.c"],
+ "WASM_CPPSRCS": ["WASM_CPPSRCS += $(srcdir)/bar.cpp"],
+ }
+
+ for var, val in expected.items():
+ found = [str for str in lines if str.startswith(var)]
+ self.assertEqual(found, val)
+
+ def test_exports(self):
+ """Ensure EXPORTS is handled properly."""
+ env = self._consume("exports", RecursiveMakeBackend)
+
+ # EXPORTS files should appear in the dist_include install manifest.
+ m = InstallManifest(
+ path=mozpath.join(
+ env.topobjdir, "_build_manifests", "install", "dist_include"
+ )
+ )
+ self.assertEqual(len(m), 7)
+ self.assertIn("foo.h", m)
+ self.assertIn("mozilla/mozilla1.h", m)
+ self.assertIn("mozilla/dom/dom2.h", m)
+
+ def test_generated_files(self):
+ """Ensure GENERATED_FILES is handled properly."""
+ env = self._consume("generated-files", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "include $(topsrcdir)/config/AB_rCD.mk",
+ "PRE_COMPILE_TARGETS += $(MDDEPDIR)/bar.c.stub",
+ "bar.c: $(MDDEPDIR)/bar.c.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/bar.c.pp",
+ "$(MDDEPDIR)/bar.c.stub: %s/generate-bar.py" % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,%s/generate-bar.py baz bar.c $(MDDEPDIR)/bar.c.pp $(MDDEPDIR)/bar.c.stub)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ "EXPORT_TARGETS += $(MDDEPDIR)/foo.h.stub",
+ "foo.h: $(MDDEPDIR)/foo.h.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.h.pp",
+ "$(MDDEPDIR)/foo.h.stub: %s/generate-foo.py $(srcdir)/foo-data"
+ % (env.topsrcdir),
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,%s/generate-foo.py main foo.h $(MDDEPDIR)/foo.h.pp $(MDDEPDIR)/foo.h.stub $(srcdir)/foo-data)" # noqa
+ % (env.topsrcdir),
+ "@$(TOUCH) $@",
+ "",
+ ]
+
+ self.maxDiff = None
+ self.assertEqual(lines, expected)
+
+ def test_generated_files_force(self):
+ """Ensure GENERATED_FILES with .force is handled properly."""
+ env = self._consume("generated-files-force", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "include $(topsrcdir)/config/AB_rCD.mk",
+ "PRE_COMPILE_TARGETS += $(MDDEPDIR)/bar.c.stub",
+ "bar.c: $(MDDEPDIR)/bar.c.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/bar.c.pp",
+ "$(MDDEPDIR)/bar.c.stub: %s/generate-bar.py FORCE" % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,%s/generate-bar.py baz bar.c $(MDDEPDIR)/bar.c.pp $(MDDEPDIR)/bar.c.stub)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ "PRE_COMPILE_TARGETS += $(MDDEPDIR)/foo.c.stub",
+ "foo.c: $(MDDEPDIR)/foo.c.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.c.pp",
+ "$(MDDEPDIR)/foo.c.stub: %s/generate-foo.py $(srcdir)/foo-data"
+ % (env.topsrcdir),
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,%s/generate-foo.py main foo.c $(MDDEPDIR)/foo.c.pp $(MDDEPDIR)/foo.c.stub $(srcdir)/foo-data)" # noqa
+ % (env.topsrcdir),
+ "@$(TOUCH) $@",
+ "",
+ ]
+
+ self.maxDiff = None
+ self.assertEqual(lines, expected)
+
+ def test_localized_generated_files(self):
+ """Ensure LOCALIZED_GENERATED_FILES is handled properly."""
+ env = self._consume("localized-generated-files", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "include $(topsrcdir)/config/AB_rCD.mk",
+ "MISC_TARGETS += $(MDDEPDIR)/foo.xyz.stub",
+ "foo.xyz: $(MDDEPDIR)/foo.xyz.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.xyz.pp",
+ "$(MDDEPDIR)/foo.xyz.stub: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)" # noqa
+ % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,--locale=$(AB_CD) %s/generate-foo.py main foo.xyz $(MDDEPDIR)/foo.xyz.pp $(MDDEPDIR)/foo.xyz.stub $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ "LOCALIZED_FILES_0_FILES += foo.xyz",
+ "LOCALIZED_FILES_0_DEST = $(FINAL_TARGET)/",
+ "LOCALIZED_FILES_0_TARGET := misc",
+ "INSTALL_TARGETS += LOCALIZED_FILES_0",
+ ]
+
+ self.maxDiff = None
+ self.assertEqual(lines, expected)
+
+ def test_localized_generated_files_force(self):
+ """Ensure LOCALIZED_GENERATED_FILES with .force is handled properly."""
+ env = self._consume("localized-generated-files-force", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "include $(topsrcdir)/config/AB_rCD.mk",
+ "MISC_TARGETS += $(MDDEPDIR)/foo.xyz.stub",
+ "foo.xyz: $(MDDEPDIR)/foo.xyz.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.xyz.pp",
+ "$(MDDEPDIR)/foo.xyz.stub: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)" # noqa
+ % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,--locale=$(AB_CD) %s/generate-foo.py main foo.xyz $(MDDEPDIR)/foo.xyz.pp $(MDDEPDIR)/foo.xyz.stub $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ "MISC_TARGETS += $(MDDEPDIR)/abc.xyz.stub",
+ "abc.xyz: $(MDDEPDIR)/abc.xyz.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/abc.xyz.pp",
+ "$(MDDEPDIR)/abc.xyz.stub: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input FORCE" # noqa
+ % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,--locale=$(AB_CD) %s/generate-foo.py main abc.xyz $(MDDEPDIR)/abc.xyz.pp $(MDDEPDIR)/abc.xyz.stub $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ ]
+
+ self.maxDiff = None
+ self.assertEqual(lines, expected)
+
+ def test_localized_generated_files_AB_CD(self):
+ """Ensure LOCALIZED_GENERATED_FILES is handled properly
+ when {AB_CD} and {AB_rCD} are used."""
+ env = self._consume("localized-generated-files-AB_CD", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "include $(topsrcdir)/config/AB_rCD.mk",
+ "MISC_TARGETS += $(MDDEPDIR)/foo$(AB_CD).xyz.stub",
+ "foo$(AB_CD).xyz: $(MDDEPDIR)/foo$(AB_CD).xyz.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo$(AB_CD).xyz.pp",
+ "$(MDDEPDIR)/foo$(AB_CD).xyz.stub: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)" # noqa
+ % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,--locale=$(AB_CD) %s/generate-foo.py main foo$(AB_CD).xyz $(MDDEPDIR)/foo$(AB_CD).xyz.pp $(MDDEPDIR)/foo$(AB_CD).xyz.stub $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ "bar$(AB_rCD).xyz: $(MDDEPDIR)/bar$(AB_rCD).xyz.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/bar$(AB_rCD).xyz.pp",
+ "$(MDDEPDIR)/bar$(AB_rCD).xyz.stub: %s/generate-foo.py $(call MERGE_RELATIVE_FILE,localized-input,inner/locales) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)" # noqa
+ % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,--locale=$(AB_CD) %s/generate-foo.py main bar$(AB_rCD).xyz $(MDDEPDIR)/bar$(AB_rCD).xyz.pp $(MDDEPDIR)/bar$(AB_rCD).xyz.stub $(call MERGE_RELATIVE_FILE,localized-input,inner/locales) $(srcdir)/non-localized-input)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ "zot$(AB_rCD).xyz: $(MDDEPDIR)/zot$(AB_rCD).xyz.stub ;",
+ "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/zot$(AB_rCD).xyz.pp",
+ "$(MDDEPDIR)/zot$(AB_rCD).xyz.stub: %s/generate-foo.py $(call MERGE_RELATIVE_FILE,localized-input,locales) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)" # noqa
+ % env.topsrcdir,
+ "$(REPORT_BUILD)",
+ "$(call py_action,file_generate,--locale=$(AB_CD) %s/generate-foo.py main zot$(AB_rCD).xyz $(MDDEPDIR)/zot$(AB_rCD).xyz.pp $(MDDEPDIR)/zot$(AB_rCD).xyz.stub $(call MERGE_RELATIVE_FILE,localized-input,locales) $(srcdir)/non-localized-input)" # noqa
+ % env.topsrcdir,
+ "@$(TOUCH) $@",
+ "",
+ ]
+
+ self.maxDiff = None
+ self.assertEqual(lines, expected)
+
+ def test_exports_generated(self):
+ """Ensure EXPORTS that are listed in GENERATED_FILES
+ are handled properly."""
+ env = self._consume("exports-generated", RecursiveMakeBackend)
+
+ # EXPORTS files should appear in the dist_include install manifest.
+ m = InstallManifest(
+ path=mozpath.join(
+ env.topobjdir, "_build_manifests", "install", "dist_include"
+ )
+ )
+ self.assertEqual(len(m), 8)
+ self.assertIn("foo.h", m)
+ self.assertIn("mozilla/mozilla1.h", m)
+ self.assertIn("mozilla/dom/dom1.h", m)
+ self.assertIn("gfx/gfx.h", m)
+ self.assertIn("bar.h", m)
+ self.assertIn("mozilla/mozilla2.h", m)
+ self.assertIn("mozilla/dom/dom2.h", m)
+ self.assertIn("mozilla/dom/dom3.h", m)
+ # EXPORTS files that are also GENERATED_FILES should be handled as
+ # INSTALL_TARGETS.
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+ expected = [
+ "include $(topsrcdir)/config/AB_rCD.mk",
+ "dist_include_FILES += bar.h",
+ "dist_include_DEST := $(DEPTH)/dist/include/",
+ "dist_include_TARGET := export",
+ "INSTALL_TARGETS += dist_include",
+ "dist_include_mozilla_FILES += mozilla2.h",
+ "dist_include_mozilla_DEST := $(DEPTH)/dist/include/mozilla",
+ "dist_include_mozilla_TARGET := export",
+ "INSTALL_TARGETS += dist_include_mozilla",
+ "dist_include_mozilla_dom_FILES += dom2.h",
+ "dist_include_mozilla_dom_FILES += dom3.h",
+ "dist_include_mozilla_dom_DEST := $(DEPTH)/dist/include/mozilla/dom",
+ "dist_include_mozilla_dom_TARGET := export",
+ "INSTALL_TARGETS += dist_include_mozilla_dom",
+ ]
+ self.maxDiff = None
+ self.assertEqual(lines, expected)
+
+ def test_resources(self):
+ """Ensure RESOURCE_FILES is handled properly."""
+ env = self._consume("resources", RecursiveMakeBackend)
+
+ # RESOURCE_FILES should appear in the dist_bin install manifest.
+ m = InstallManifest(
+ path=os.path.join(env.topobjdir, "_build_manifests", "install", "dist_bin")
+ )
+ self.assertEqual(len(m), 10)
+ self.assertIn("res/foo.res", m)
+ self.assertIn("res/fonts/font1.ttf", m)
+ self.assertIn("res/fonts/desktop/desktop2.ttf", m)
+
+ self.assertIn("res/bar.res.in", m)
+ self.assertIn("res/tests/test.manifest", m)
+ self.assertIn("res/tests/extra.manifest", m)
+
+ def test_test_manifests_files_written(self):
+ """Ensure test manifests get turned into files."""
+ env = self._consume("test-manifests-written", RecursiveMakeBackend)
+
+ tests_dir = mozpath.join(env.topobjdir, "_tests")
+ m_master = mozpath.join(
+ tests_dir, "testing", "mochitest", "tests", "mochitest.ini"
+ )
+ x_master = mozpath.join(tests_dir, "xpcshell", "xpcshell.ini")
+ self.assertTrue(os.path.exists(m_master))
+ self.assertTrue(os.path.exists(x_master))
+
+ lines = [l.strip() for l in open(x_master, "rt").readlines()]
+ self.assertEqual(
+ lines,
+ [
+ "# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.",
+ "",
+ "[include:dir1/xpcshell.ini]",
+ "[include:xpcshell.ini]",
+ ],
+ )
+
+ def test_test_manifest_pattern_matches_recorded(self):
+ """Pattern matches in test manifests' support-files should be recorded."""
+ env = self._consume("test-manifests-written", RecursiveMakeBackend)
+ m = InstallManifest(
+ path=mozpath.join(
+ env.topobjdir, "_build_manifests", "install", "_test_files"
+ )
+ )
+
+ # This is not the most robust test in the world, but it gets the job
+ # done.
+ entries = [e for e in m._dests.keys() if "**" in e]
+ self.assertEqual(len(entries), 1)
+ self.assertIn("support/**", entries[0])
+
+ def test_test_manifest_deffered_installs_written(self):
+ """Shared support files are written to their own data file by the backend."""
+ env = self._consume("test-manifest-shared-support", RecursiveMakeBackend)
+
+ # First, read the generated for ini manifest contents.
+ test_files_manifest = mozpath.join(
+ env.topobjdir, "_build_manifests", "install", "_test_files"
+ )
+ m = InstallManifest(path=test_files_manifest)
+
+ # Then, synthesize one from the test-installs.pkl file. This should
+ # allow us to re-create a subset of the above.
+ env = self._consume("test-manifest-shared-support", TestManifestBackend)
+ test_installs_path = mozpath.join(env.topobjdir, "test-installs.pkl")
+
+ with open(test_installs_path, "rb") as fh:
+ test_installs = pickle.load(fh)
+
+ self.assertEqual(
+ set(test_installs.keys()),
+ set(["child/test_sub.js", "child/data/**", "child/another-file.sjs"]),
+ )
+ for key in test_installs.keys():
+ self.assertIn(key, test_installs)
+
+ synthesized_manifest = InstallManifest()
+ for item, installs in test_installs.items():
+ for install_info in installs:
+ if len(install_info) == 3:
+ synthesized_manifest.add_pattern_link(*install_info)
+ if len(install_info) == 2:
+ synthesized_manifest.add_link(*install_info)
+
+ self.assertEqual(len(synthesized_manifest), 3)
+ for item, info in synthesized_manifest._dests.items():
+ self.assertIn(item, m)
+ self.assertEqual(info, m._dests[item])
+
+ def test_xpidl_generation(self):
+ """Ensure xpidl files and directories are written out."""
+ env = self._consume("xpidl", RecursiveMakeBackend)
+
+ # Install manifests should contain entries.
+ install_dir = mozpath.join(env.topobjdir, "_build_manifests", "install")
+ self.assertTrue(os.path.isfile(mozpath.join(install_dir, "xpidl")))
+
+ m = InstallManifest(path=mozpath.join(install_dir, "xpidl"))
+ self.assertIn(".deps/my_module.pp", m)
+
+ m = InstallManifest(path=mozpath.join(install_dir, "xpidl"))
+ self.assertIn("my_module.xpt", m)
+
+ m = InstallManifest(path=mozpath.join(install_dir, "dist_include"))
+ self.assertIn("foo.h", m)
+
+ p = mozpath.join(env.topobjdir, "config/makefiles/xpidl")
+ self.assertTrue(os.path.isdir(p))
+
+ self.assertTrue(os.path.isfile(mozpath.join(p, "Makefile")))
+
+ def test_test_support_files_tracked(self):
+ env = self._consume("test-support-binaries-tracked", RecursiveMakeBackend)
+ m = InstallManifest(
+ path=mozpath.join(env.topobjdir, "_build_manifests", "install", "_tests")
+ )
+ self.assertEqual(len(m), 4)
+ self.assertIn("xpcshell/tests/mozbuildtest/test-library.dll", m)
+ self.assertIn("xpcshell/tests/mozbuildtest/test-one.exe", m)
+ self.assertIn("xpcshell/tests/mozbuildtest/test-two.exe", m)
+ self.assertIn("xpcshell/tests/mozbuildtest/host-test-library.dll", m)
+
+ def test_old_install_manifest_deleted(self):
+ # Simulate an install manifest from a previous backend version. Ensure
+ # it is deleted.
+ env = self._get_environment("stub0")
+ purge_dir = mozpath.join(env.topobjdir, "_build_manifests", "install")
+ manifest_path = mozpath.join(purge_dir, "old_manifest")
+ os.makedirs(purge_dir)
+ m = InstallManifest()
+ m.write(path=manifest_path)
+ with open(
+ mozpath.join(env.topobjdir, "backend.RecursiveMakeBackend"), "w"
+ ) as f:
+ f.write("%s\n" % manifest_path)
+
+ self.assertTrue(os.path.exists(manifest_path))
+ self._consume("stub0", RecursiveMakeBackend, env)
+ self.assertFalse(os.path.exists(manifest_path))
+
+ def test_install_manifests_written(self):
+ env, objs = self._emit("stub0")
+ backend = RecursiveMakeBackend(env)
+
+ m = InstallManifest()
+ backend._install_manifests["testing"] = m
+ m.add_link(__file__, "self")
+ backend.consume(objs)
+
+ man_dir = mozpath.join(env.topobjdir, "_build_manifests", "install")
+ self.assertTrue(os.path.isdir(man_dir))
+
+ expected = ["testing"]
+ for e in expected:
+ full = mozpath.join(man_dir, e)
+ self.assertTrue(os.path.exists(full))
+
+ m2 = InstallManifest(path=full)
+ self.assertEqual(m, m2)
+
+ def test_ipdl_sources(self):
+ """Test that PREPROCESSED_IPDL_SOURCES and IPDL_SOURCES are written to
+ ipdlsrcs.mk correctly."""
+ env = self._get_environment("ipdl_sources")
+
+ # Use the ipdl directory as the IPDL root for testing.
+ ipdl_root = mozpath.join(env.topobjdir, "ipdl")
+
+ # Make substs writable so we can set the value of IPDL_ROOT to reflect
+ # the correct objdir.
+ env.substs = dict(env.substs)
+ env.substs["IPDL_ROOT"] = ipdl_root
+
+ self._consume("ipdl_sources", RecursiveMakeBackend, env)
+
+ manifest_path = mozpath.join(ipdl_root, "ipdlsrcs.mk")
+ lines = [l.strip() for l in open(manifest_path, "rt").readlines()]
+
+ # Handle Windows paths correctly
+ topsrcdir = mozpath.normsep(env.topsrcdir)
+
+ expected = [
+ "ALL_IPDLSRCS := bar1.ipdl foo1.ipdl %s/bar/bar.ipdl %s/bar/bar2.ipdlh %s/foo/foo.ipdl %s/foo/foo2.ipdlh" # noqa
+ % tuple([topsrcdir] * 4),
+ "IPDLDIRS := %s %s/bar %s/foo" % (ipdl_root, topsrcdir, topsrcdir),
+ ]
+
+ found = [str for str in lines if str.startswith(("ALL_IPDLSRCS", "IPDLDIRS"))]
+ self.assertEqual(found, expected)
+
+ # Check that each directory declares the generated relevant .cpp files
+ # to be built in CPPSRCS.
+ # ENABLE_UNIFIED_BUILD defaults to False without mozilla-central's
+ # moz.configure so we don't see unified sources here.
+ for dir, expected in (
+ (".", []),
+ ("ipdl", []),
+ (
+ "bar",
+ [
+ "CPPSRCS += "
+ + " ".join(
+ f"{ipdl_root}/{f}"
+ for f in [
+ "bar.cpp",
+ "bar1.cpp",
+ "bar1Child.cpp",
+ "bar1Parent.cpp",
+ "bar2.cpp",
+ "barChild.cpp",
+ "barParent.cpp",
+ ]
+ )
+ ],
+ ),
+ (
+ "foo",
+ [
+ "CPPSRCS += "
+ + " ".join(
+ f"{ipdl_root}/{f}"
+ for f in [
+ "foo.cpp",
+ "foo1.cpp",
+ "foo1Child.cpp",
+ "foo1Parent.cpp",
+ "foo2.cpp",
+ "fooChild.cpp",
+ "fooParent.cpp",
+ ]
+ )
+ ],
+ ),
+ ):
+ backend_path = mozpath.join(env.topobjdir, dir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()]
+
+ found = [str for str in lines if str.startswith("CPPSRCS")]
+ self.assertEqual(found, expected)
+
+ def test_defines(self):
+ """Test that DEFINES are written to backend.mk correctly."""
+ env = self._consume("defines", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ var = "DEFINES"
+ defines = [val for val in lines if val.startswith(var)]
+
+ expected = ["DEFINES += -DFOO '-DBAZ=\"ab'\\''cd\"' -UQUX -DBAR=7 -DVALUE=xyz"]
+ self.assertEqual(defines, expected)
+
+ def test_local_includes(self):
+ """Test that LOCAL_INCLUDES are written to backend.mk correctly."""
+ env = self._consume("local_includes", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "LOCAL_INCLUDES += -I$(srcdir)/bar/baz",
+ "LOCAL_INCLUDES += -I$(srcdir)/foo",
+ ]
+
+ found = [str for str in lines if str.startswith("LOCAL_INCLUDES")]
+ self.assertEqual(found, expected)
+
+ def test_generated_includes(self):
+ """Test that GENERATED_INCLUDES are written to backend.mk correctly."""
+ env = self._consume("generated_includes", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "LOCAL_INCLUDES += -I$(CURDIR)/bar/baz",
+ "LOCAL_INCLUDES += -I$(CURDIR)/foo",
+ ]
+
+ found = [str for str in lines if str.startswith("LOCAL_INCLUDES")]
+ self.assertEqual(found, expected)
+
+ def test_rust_library(self):
+ """Test that a Rust library is written to backend.mk correctly."""
+ env = self._consume("rust-library", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [
+ l.strip()
+ for l in open(backend_path, "rt").readlines()[2:]
+ # Strip out computed flags, they're a PITA to test.
+ if not l.startswith("COMPUTED_")
+ ]
+
+ expected = [
+ "RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libtest_library.a"
+ % env.topobjdir, # noqa
+ "CARGO_FILE := $(srcdir)/Cargo.toml",
+ "CARGO_TARGET_DIR := %s" % env.topobjdir,
+ ]
+
+ self.assertEqual(lines, expected)
+
+ def test_host_rust_library(self):
+ """Test that a Rust library is written to backend.mk correctly."""
+ env = self._consume("host-rust-library", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [
+ l.strip()
+ for l in open(backend_path, "rt").readlines()[2:]
+ # Strip out computed flags, they're a PITA to test.
+ if not l.startswith("COMPUTED_")
+ ]
+
+ expected = [
+ "HOST_RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libhostrusttool.a"
+ % env.topobjdir, # noqa
+ "CARGO_FILE := $(srcdir)/Cargo.toml",
+ "CARGO_TARGET_DIR := %s" % env.topobjdir,
+ ]
+
+ self.assertEqual(lines, expected)
+
+ def test_host_rust_library_with_features(self):
+ """Test that a host Rust library with features is written to backend.mk correctly."""
+ env = self._consume("host-rust-library-features", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [
+ l.strip()
+ for l in open(backend_path, "rt").readlines()[2:]
+ # Strip out computed flags, they're a PITA to test.
+ if not l.startswith("COMPUTED_")
+ ]
+
+ expected = [
+ "HOST_RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libhostrusttool.a"
+ % env.topobjdir, # noqa
+ "CARGO_FILE := $(srcdir)/Cargo.toml",
+ "CARGO_TARGET_DIR := %s" % env.topobjdir,
+ "HOST_RUST_LIBRARY_FEATURES := musthave cantlivewithout",
+ ]
+
+ self.assertEqual(lines, expected)
+
+ def test_rust_library_with_features(self):
+ """Test that a Rust library with features is written to backend.mk correctly."""
+ env = self._consume("rust-library-features", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [
+ l.strip()
+ for l in open(backend_path, "rt").readlines()[2:]
+ # Strip out computed flags, they're a PITA to test.
+ if not l.startswith("COMPUTED_")
+ ]
+
+ expected = [
+ "RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libfeature_library.a"
+ % env.topobjdir, # noqa
+ "CARGO_FILE := $(srcdir)/Cargo.toml",
+ "CARGO_TARGET_DIR := %s" % env.topobjdir,
+ "RUST_LIBRARY_FEATURES := musthave cantlivewithout",
+ ]
+
+ self.assertEqual(lines, expected)
+
+ def test_rust_programs(self):
+ """Test that `{HOST_,}RUST_PROGRAMS` are written to backend.mk correctly."""
+ env = self._consume("rust-programs", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "code/backend.mk")
+ lines = [
+ l.strip()
+ for l in open(backend_path, "rt").readlines()[2:]
+ # Strip out computed flags, they're a PITA to test.
+ if not l.startswith("COMPUTED_")
+ ]
+
+ expected = [
+ "CARGO_FILE := %s/code/Cargo.toml" % env.topsrcdir,
+ "CARGO_TARGET_DIR := %s" % env.topobjdir,
+ "RUST_PROGRAMS += $(DEPTH)/i686-pc-windows-msvc/release/target.exe",
+ "RUST_CARGO_PROGRAMS += target",
+ "HOST_RUST_PROGRAMS += $(DEPTH)/i686-pc-windows-msvc/release/host.exe",
+ "HOST_RUST_CARGO_PROGRAMS += host",
+ ]
+
+ self.assertEqual(lines, expected)
+
+ root_deps_path = mozpath.join(env.topobjdir, "root-deps.mk")
+ lines = [l.strip() for l in open(root_deps_path, "rt").readlines()]
+
+ self.assertTrue(
+ any(l == "recurse_compile: code/host code/target" for l in lines)
+ )
+
+ def test_final_target(self):
+ """Test that FINAL_TARGET is written to backend.mk correctly."""
+ env = self._consume("final_target", RecursiveMakeBackend)
+
+ final_target_rule = "FINAL_TARGET = $(if $(XPI_NAME),$(DIST)/xpi-stage/$(XPI_NAME),$(DIST)/bin)$(DIST_SUBDIR:%=/%)" # noqa
+ expected = dict()
+ expected[env.topobjdir] = []
+ expected[mozpath.join(env.topobjdir, "both")] = [
+ "XPI_NAME = mycrazyxpi",
+ "DIST_SUBDIR = asubdir",
+ final_target_rule,
+ ]
+ expected[mozpath.join(env.topobjdir, "dist-subdir")] = [
+ "DIST_SUBDIR = asubdir",
+ final_target_rule,
+ ]
+ expected[mozpath.join(env.topobjdir, "xpi-name")] = [
+ "XPI_NAME = mycrazyxpi",
+ final_target_rule,
+ ]
+ expected[mozpath.join(env.topobjdir, "final-target")] = [
+ "FINAL_TARGET = $(DEPTH)/random-final-target"
+ ]
+ for key, expected_rules in six.iteritems(expected):
+ backend_path = mozpath.join(key, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+ found = [
+ str
+ for str in lines
+ if str.startswith("FINAL_TARGET")
+ or str.startswith("XPI_NAME")
+ or str.startswith("DIST_SUBDIR")
+ ]
+ self.assertEqual(found, expected_rules)
+
+ def test_final_target_pp_files(self):
+ """Test that FINAL_TARGET_PP_FILES is written to backend.mk correctly."""
+ env = self._consume("dist-files", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "DIST_FILES_0 += $(srcdir)/install.rdf",
+ "DIST_FILES_0 += $(srcdir)/main.js",
+ "DIST_FILES_0_PATH := $(DEPTH)/dist/bin/",
+ "DIST_FILES_0_TARGET := misc",
+ "PP_TARGETS += DIST_FILES_0",
+ ]
+
+ found = [str for str in lines if "DIST_FILES" in str]
+ self.assertEqual(found, expected)
+
+ def test_localized_files(self):
+ """Test that LOCALIZED_FILES is written to backend.mk correctly."""
+ env = self._consume("localized-files", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "LOCALIZED_FILES_0_FILES += $(wildcard $(LOCALE_SRCDIR)/abc/*.abc)",
+ "LOCALIZED_FILES_0_FILES += $(call MERGE_FILE,bar.ini)",
+ "LOCALIZED_FILES_0_FILES += $(call MERGE_FILE,foo.js)",
+ "LOCALIZED_FILES_0_DEST = $(FINAL_TARGET)/",
+ "LOCALIZED_FILES_0_TARGET := misc",
+ "INSTALL_TARGETS += LOCALIZED_FILES_0",
+ ]
+
+ found = [str for str in lines if "LOCALIZED_FILES" in str]
+ self.assertEqual(found, expected)
+
+ def test_localized_pp_files(self):
+ """Test that LOCALIZED_PP_FILES is written to backend.mk correctly."""
+ env = self._consume("localized-pp-files", RecursiveMakeBackend)
+
+ backend_path = mozpath.join(env.topobjdir, "backend.mk")
+ lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]]
+
+ expected = [
+ "LOCALIZED_PP_FILES_0 += $(call MERGE_FILE,bar.ini)",
+ "LOCALIZED_PP_FILES_0 += $(call MERGE_FILE,foo.js)",
+ "LOCALIZED_PP_FILES_0_PATH = $(FINAL_TARGET)/",
+ "LOCALIZED_PP_FILES_0_TARGET := misc",
+ "LOCALIZED_PP_FILES_0_FLAGS := --silence-missing-directive-warnings",
+ "PP_TARGETS += LOCALIZED_PP_FILES_0",
+ ]
+
+ found = [str for str in lines if "LOCALIZED_PP_FILES" in str]
+ self.assertEqual(found, expected)
+
+ def test_config(self):
+ """Test that CONFIGURE_SUBST_FILES are properly handled."""
+ env = self._consume("test_config", RecursiveMakeBackend)
+
+ self.assertEqual(
+ open(os.path.join(env.topobjdir, "file"), "r").readlines(),
+ ["#ifdef foo\n", "bar baz\n", "@bar@\n"],
+ )
+
+ def test_prog_lib_c_only(self):
+ """Test that C-only binary artifacts are marked as such."""
+ env = self._consume("prog-lib-c-only", RecursiveMakeBackend)
+
+ # PROGRAM C-onlyness.
+ with open(os.path.join(env.topobjdir, "c-program", "backend.mk"), "r") as fh:
+ lines = fh.readlines()
+ lines = [line.rstrip() for line in lines]
+
+ self.assertIn("PROG_IS_C_ONLY_c_test_program := 1", lines)
+
+ with open(os.path.join(env.topobjdir, "cxx-program", "backend.mk"), "r") as fh:
+ lines = fh.readlines()
+ lines = [line.rstrip() for line in lines]
+
+ # Test for only the absence of the variable, not the precise
+ # form of the variable assignment.
+ for line in lines:
+ self.assertNotIn("PROG_IS_C_ONLY_cxx_test_program", line)
+
+ # SIMPLE_PROGRAMS C-onlyness.
+ with open(
+ os.path.join(env.topobjdir, "c-simple-programs", "backend.mk"), "r"
+ ) as fh:
+ lines = fh.readlines()
+ lines = [line.rstrip() for line in lines]
+
+ self.assertIn("PROG_IS_C_ONLY_c_simple_program := 1", lines)
+
+ with open(
+ os.path.join(env.topobjdir, "cxx-simple-programs", "backend.mk"), "r"
+ ) as fh:
+ lines = fh.readlines()
+ lines = [line.rstrip() for line in lines]
+
+ for line in lines:
+ self.assertNotIn("PROG_IS_C_ONLY_cxx_simple_program", line)
+
+ # Libraries C-onlyness.
+ with open(os.path.join(env.topobjdir, "c-library", "backend.mk"), "r") as fh:
+ lines = fh.readlines()
+ lines = [line.rstrip() for line in lines]
+
+ self.assertIn("LIB_IS_C_ONLY := 1", lines)
+
+ with open(os.path.join(env.topobjdir, "cxx-library", "backend.mk"), "r") as fh:
+ lines = fh.readlines()
+ lines = [line.rstrip() for line in lines]
+
+ for line in lines:
+ self.assertNotIn("LIB_IS_C_ONLY", line)
+
+ def test_linkage(self):
+ env = self._consume("linkage", RecursiveMakeBackend)
+ expected_linkage = {
+ "prog": {
+ "SHARED_LIBS": ["qux/qux.so", "../shared/baz.so"],
+ "STATIC_LIBS": ["../real/foo.a"],
+ "OS_LIBS": ["-lfoo", "-lbaz", "-lbar"],
+ },
+ "shared": {
+ "OS_LIBS": ["-lfoo"],
+ "SHARED_LIBS": ["../prog/qux/qux.so"],
+ "STATIC_LIBS": [],
+ },
+ "static": {
+ "STATIC_LIBS": ["../real/foo.a"],
+ "OS_LIBS": ["-lbar"],
+ "SHARED_LIBS": ["../prog/qux/qux.so"],
+ },
+ "real": {
+ "STATIC_LIBS": [],
+ "SHARED_LIBS": ["../prog/qux/qux.so"],
+ "OS_LIBS": ["-lbaz"],
+ },
+ }
+ actual_linkage = {}
+ for name in expected_linkage.keys():
+ with open(os.path.join(env.topobjdir, name, "backend.mk"), "r") as fh:
+ actual_linkage[name] = [line.rstrip() for line in fh.readlines()]
+ for name in expected_linkage:
+ for var in expected_linkage[name]:
+ for val in expected_linkage[name][var]:
+ val = os.path.normpath(val)
+ line = "%s += %s" % (var, val)
+ self.assertIn(line, actual_linkage[name])
+ actual_linkage[name].remove(line)
+ for line in actual_linkage[name]:
+ self.assertNotIn("%s +=" % var, line)
+
+ def test_list_files(self):
+ env = self._consume("linkage", RecursiveMakeBackend)
+ expected_list_files = {
+ "prog/MyProgram_exe.list": [
+ "../static/bar/bar1.o",
+ "../static/bar/bar2.o",
+ "../static/bar/bar_helper/bar_helper1.o",
+ ],
+ "shared/baz_so.list": ["baz/baz1.o"],
+ }
+ actual_list_files = {}
+ for name in expected_list_files.keys():
+ with open(os.path.join(env.topobjdir, name), "r") as fh:
+ actual_list_files[name] = [line.rstrip() for line in fh.readlines()]
+ for name in expected_list_files:
+ self.assertEqual(
+ actual_list_files[name],
+ [os.path.normpath(f) for f in expected_list_files[name]],
+ )
+
+ # We don't produce a list file for a shared library composed only of
+ # object files in its directory, but instead list them in a variable.
+ with open(os.path.join(env.topobjdir, "prog", "qux", "backend.mk"), "r") as fh:
+ lines = [line.rstrip() for line in fh.readlines()]
+
+ self.assertIn("qux.so_OBJS := qux1.o", lines)
+
+ def test_jar_manifests(self):
+ env = self._consume("jar-manifests", RecursiveMakeBackend)
+
+ with open(os.path.join(env.topobjdir, "backend.mk"), "r") as fh:
+ lines = fh.readlines()
+
+ lines = [line.rstrip() for line in lines]
+
+ self.assertIn("JAR_MANIFEST := %s/jar.mn" % env.topsrcdir, lines)
+
+ def test_test_manifests_duplicate_support_files(self):
+ """Ensure duplicate support-files in test manifests work."""
+ env = self._consume(
+ "test-manifests-duplicate-support-files", RecursiveMakeBackend
+ )
+
+ p = os.path.join(env.topobjdir, "_build_manifests", "install", "_test_files")
+ m = InstallManifest(p)
+ self.assertIn("testing/mochitest/tests/support-file.txt", m)
+
+ def test_install_manifests_package_tests(self):
+ """Ensure test suites honor package_tests=False."""
+ env = self._consume("test-manifests-package-tests", RecursiveMakeBackend)
+
+ man_dir = mozpath.join(env.topobjdir, "_build_manifests", "install")
+ self.assertTrue(os.path.isdir(man_dir))
+
+ full = mozpath.join(man_dir, "_test_files")
+ self.assertTrue(os.path.exists(full))
+
+ m = InstallManifest(path=full)
+
+ # Only mochitest.js should be in the install manifest.
+ self.assertTrue("testing/mochitest/tests/mochitest.js" in m)
+
+ # The path is odd here because we do not normalize at test manifest
+ # processing time. This is a fragile test because there's currently no
+ # way to iterate the manifest.
+ self.assertFalse("instrumentation/./not_packaged.java" in m)
+
+ def test_program_paths(self):
+ """PROGRAMs with various moz.build settings that change the destination should produce
+ the expected paths in backend.mk."""
+ env = self._consume("program-paths", RecursiveMakeBackend)
+
+ expected = [
+ ("dist-bin", "$(DEPTH)/dist/bin/dist-bin.prog"),
+ ("dist-subdir", "$(DEPTH)/dist/bin/foo/dist-subdir.prog"),
+ ("final-target", "$(DEPTH)/final/target/final-target.prog"),
+ ("not-installed", "not-installed.prog"),
+ ]
+ prefix = "PROGRAM = "
+ for (subdir, expected_program) in expected:
+ with io.open(os.path.join(env.topobjdir, subdir, "backend.mk"), "r") as fh:
+ lines = fh.readlines()
+ program = [
+ line.rstrip().split(prefix, 1)[1]
+ for line in lines
+ if line.startswith(prefix)
+ ][0]
+ self.assertEqual(program, expected_program)
+
+
+if __name__ == "__main__":
+ main()