1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5from __future__ import absolute_import, print_function, unicode_literals 6 7import io 8import os 9import six.moves.cPickle as pickle 10import six 11import unittest 12 13from mozpack.manifests import InstallManifest 14from mozunit import main 15 16from mozbuild.backend.recursivemake import RecursiveMakeBackend, RecursiveMakeTraversal 17from mozbuild.backend.test_manifest import TestManifestBackend 18from mozbuild.frontend.emitter import TreeMetadataEmitter 19from mozbuild.frontend.reader import BuildReader 20 21from mozbuild.test.backend.common import BackendTester 22 23import mozpack.path as mozpath 24 25 26class TestRecursiveMakeTraversal(unittest.TestCase): 27 def test_traversal(self): 28 traversal = RecursiveMakeTraversal() 29 traversal.add("", dirs=["A", "B", "C"]) 30 traversal.add("", dirs=["D"]) 31 traversal.add("A") 32 traversal.add("B", dirs=["E", "F"]) 33 traversal.add("C", dirs=["G", "H"]) 34 traversal.add("D", dirs=["I", "K"]) 35 traversal.add("D", dirs=["J", "L"]) 36 traversal.add("E") 37 traversal.add("F") 38 traversal.add("G") 39 traversal.add("H") 40 traversal.add("I", dirs=["M", "N"]) 41 traversal.add("J", dirs=["O", "P"]) 42 traversal.add("K", dirs=["Q", "R"]) 43 traversal.add("L", dirs=["S"]) 44 traversal.add("M") 45 traversal.add("N", dirs=["T"]) 46 traversal.add("O") 47 traversal.add("P", dirs=["U"]) 48 traversal.add("Q") 49 traversal.add("R", dirs=["V"]) 50 traversal.add("S", dirs=["W"]) 51 traversal.add("T") 52 traversal.add("U") 53 traversal.add("V") 54 traversal.add("W", dirs=["X"]) 55 traversal.add("X") 56 57 parallels = set(("G", "H", "I", "J", "O", "P", "Q", "R", "U")) 58 59 def filter(current, subdirs): 60 return ( 61 current, 62 [d for d in subdirs.dirs if d in parallels], 63 [d for d in subdirs.dirs if d not in parallels], 64 ) 65 66 start, deps = traversal.compute_dependencies(filter) 67 self.assertEqual(start, ("X",)) 68 self.maxDiff = None 69 self.assertEqual( 70 deps, 71 { 72 "A": ("",), 73 "B": ("A",), 74 "C": ("F",), 75 "D": ("G", "H"), 76 "E": ("B",), 77 "F": ("E",), 78 "G": ("C",), 79 "H": ("C",), 80 "I": ("D",), 81 "J": ("D",), 82 "K": ("T", "O", "U"), 83 "L": ("Q", "V"), 84 "M": ("I",), 85 "N": ("M",), 86 "O": ("J",), 87 "P": ("J",), 88 "Q": ("K",), 89 "R": ("K",), 90 "S": ("L",), 91 "T": ("N",), 92 "U": ("P",), 93 "V": ("R",), 94 "W": ("S",), 95 "X": ("W",), 96 }, 97 ) 98 99 self.assertEqual( 100 list(traversal.traverse("", filter)), 101 [ 102 "", 103 "A", 104 "B", 105 "E", 106 "F", 107 "C", 108 "G", 109 "H", 110 "D", 111 "I", 112 "M", 113 "N", 114 "T", 115 "J", 116 "O", 117 "P", 118 "U", 119 "K", 120 "Q", 121 "R", 122 "V", 123 "L", 124 "S", 125 "W", 126 "X", 127 ], 128 ) 129 130 self.assertEqual(list(traversal.traverse("C", filter)), ["C", "G", "H"]) 131 132 def test_traversal_2(self): 133 traversal = RecursiveMakeTraversal() 134 traversal.add("", dirs=["A", "B", "C"]) 135 traversal.add("A") 136 traversal.add("B", dirs=["D", "E", "F"]) 137 traversal.add("C", dirs=["G", "H", "I"]) 138 traversal.add("D") 139 traversal.add("E") 140 traversal.add("F") 141 traversal.add("G") 142 traversal.add("H") 143 traversal.add("I") 144 145 start, deps = traversal.compute_dependencies() 146 self.assertEqual(start, ("I",)) 147 self.assertEqual( 148 deps, 149 { 150 "A": ("",), 151 "B": ("A",), 152 "C": ("F",), 153 "D": ("B",), 154 "E": ("D",), 155 "F": ("E",), 156 "G": ("C",), 157 "H": ("G",), 158 "I": ("H",), 159 }, 160 ) 161 162 def test_traversal_filter(self): 163 traversal = RecursiveMakeTraversal() 164 traversal.add("", dirs=["A", "B", "C"]) 165 traversal.add("A") 166 traversal.add("B", dirs=["D", "E", "F"]) 167 traversal.add("C", dirs=["G", "H", "I"]) 168 traversal.add("D") 169 traversal.add("E") 170 traversal.add("F") 171 traversal.add("G") 172 traversal.add("H") 173 traversal.add("I") 174 175 def filter(current, subdirs): 176 if current == "B": 177 current = None 178 return current, [], subdirs.dirs 179 180 start, deps = traversal.compute_dependencies(filter) 181 self.assertEqual(start, ("I",)) 182 self.assertEqual( 183 deps, 184 { 185 "A": ("",), 186 "C": ("F",), 187 "D": ("A",), 188 "E": ("D",), 189 "F": ("E",), 190 "G": ("C",), 191 "H": ("G",), 192 "I": ("H",), 193 }, 194 ) 195 196 def test_traversal_parallel(self): 197 traversal = RecursiveMakeTraversal() 198 traversal.add("", dirs=["A", "B", "C"]) 199 traversal.add("A") 200 traversal.add("B", dirs=["D", "E", "F"]) 201 traversal.add("C", dirs=["G", "H", "I"]) 202 traversal.add("D") 203 traversal.add("E") 204 traversal.add("F") 205 traversal.add("G") 206 traversal.add("H") 207 traversal.add("I") 208 traversal.add("J") 209 210 def filter(current, subdirs): 211 return current, subdirs.dirs, [] 212 213 start, deps = traversal.compute_dependencies(filter) 214 self.assertEqual(start, ("A", "D", "E", "F", "G", "H", "I", "J")) 215 self.assertEqual( 216 deps, 217 { 218 "A": ("",), 219 "B": ("",), 220 "C": ("",), 221 "D": ("B",), 222 "E": ("B",), 223 "F": ("B",), 224 "G": ("C",), 225 "H": ("C",), 226 "I": ("C",), 227 "J": ("",), 228 }, 229 ) 230 231 232class TestRecursiveMakeBackend(BackendTester): 233 def test_basic(self): 234 """Ensure the RecursiveMakeBackend works without error.""" 235 env = self._consume("stub0", RecursiveMakeBackend) 236 self.assertTrue( 237 os.path.exists(mozpath.join(env.topobjdir, "backend.RecursiveMakeBackend")) 238 ) 239 self.assertTrue( 240 os.path.exists( 241 mozpath.join(env.topobjdir, "backend.RecursiveMakeBackend.in") 242 ) 243 ) 244 245 def test_output_files(self): 246 """Ensure proper files are generated.""" 247 env = self._consume("stub0", RecursiveMakeBackend) 248 249 expected = ["", "dir1", "dir2"] 250 251 for d in expected: 252 out_makefile = mozpath.join(env.topobjdir, d, "Makefile") 253 out_backend = mozpath.join(env.topobjdir, d, "backend.mk") 254 255 self.assertTrue(os.path.exists(out_makefile)) 256 self.assertTrue(os.path.exists(out_backend)) 257 258 def test_makefile_conversion(self): 259 """Ensure Makefile.in is converted properly.""" 260 env = self._consume("stub0", RecursiveMakeBackend) 261 262 p = mozpath.join(env.topobjdir, "Makefile") 263 264 lines = [ 265 l.strip() for l in open(p, "rt").readlines()[1:] if not l.startswith("#") 266 ] 267 self.assertEqual( 268 lines, 269 [ 270 "DEPTH := .", 271 "topobjdir := %s" % env.topobjdir, 272 "topsrcdir := %s" % env.topsrcdir, 273 "srcdir := %s" % env.topsrcdir, 274 "srcdir_rel := %s" % mozpath.relpath(env.topsrcdir, env.topobjdir), 275 "relativesrcdir := .", 276 "include $(DEPTH)/config/autoconf.mk", 277 "", 278 "FOO := foo", 279 "", 280 "include $(topsrcdir)/config/recurse.mk", 281 ], 282 ) 283 284 def test_missing_makefile_in(self): 285 """Ensure missing Makefile.in results in Makefile creation.""" 286 env = self._consume("stub0", RecursiveMakeBackend) 287 288 p = mozpath.join(env.topobjdir, "dir2", "Makefile") 289 self.assertTrue(os.path.exists(p)) 290 291 lines = [l.strip() for l in open(p, "rt").readlines()] 292 self.assertEqual(len(lines), 10) 293 294 self.assertTrue(lines[0].startswith("# THIS FILE WAS AUTOMATICALLY")) 295 296 def test_backend_mk(self): 297 """Ensure backend.mk file is written out properly.""" 298 env = self._consume("stub0", RecursiveMakeBackend) 299 300 p = mozpath.join(env.topobjdir, "backend.mk") 301 302 lines = [l.strip() for l in open(p, "rt").readlines()[2:]] 303 self.assertEqual(lines, ["DIRS := dir1 dir2"]) 304 305 # Make env.substs writable to add ENABLE_TESTS 306 env.substs = dict(env.substs) 307 env.substs["ENABLE_TESTS"] = "1" 308 self._consume("stub0", RecursiveMakeBackend, env=env) 309 p = mozpath.join(env.topobjdir, "backend.mk") 310 311 lines = [l.strip() for l in open(p, "rt").readlines()[2:]] 312 self.assertEqual(lines, ["DIRS := dir1 dir2 dir3"]) 313 314 def test_mtime_no_change(self): 315 """Ensure mtime is not updated if file content does not change.""" 316 317 env = self._consume("stub0", RecursiveMakeBackend) 318 319 makefile_path = mozpath.join(env.topobjdir, "Makefile") 320 backend_path = mozpath.join(env.topobjdir, "backend.mk") 321 makefile_mtime = os.path.getmtime(makefile_path) 322 backend_mtime = os.path.getmtime(backend_path) 323 324 reader = BuildReader(env) 325 emitter = TreeMetadataEmitter(env) 326 backend = RecursiveMakeBackend(env) 327 backend.consume(emitter.emit(reader.read_topsrcdir())) 328 329 self.assertEqual(os.path.getmtime(makefile_path), makefile_mtime) 330 self.assertEqual(os.path.getmtime(backend_path), backend_mtime) 331 332 def test_substitute_config_files(self): 333 """Ensure substituted config files are produced.""" 334 env = self._consume("substitute_config_files", RecursiveMakeBackend) 335 336 p = mozpath.join(env.topobjdir, "foo") 337 self.assertTrue(os.path.exists(p)) 338 lines = [l.strip() for l in open(p, "rt").readlines()] 339 self.assertEqual(lines, ["TEST = foo"]) 340 341 def test_install_substitute_config_files(self): 342 """Ensure we recurse into the dirs that install substituted config files.""" 343 env = self._consume("install_substitute_config_files", RecursiveMakeBackend) 344 345 root_deps_path = mozpath.join(env.topobjdir, "root-deps.mk") 346 lines = [l.strip() for l in open(root_deps_path, "rt").readlines()] 347 348 # Make sure we actually recurse into the sub directory during export to 349 # install the subst file. 350 self.assertTrue(any(l == "recurse_export: sub/export" for l in lines)) 351 352 def test_variable_passthru(self): 353 """Ensure variable passthru is written out correctly.""" 354 env = self._consume("variable_passthru", RecursiveMakeBackend) 355 356 backend_path = mozpath.join(env.topobjdir, "backend.mk") 357 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 358 359 expected = { 360 "RCFILE": ["RCFILE := $(srcdir)/foo.rc"], 361 "RCINCLUDE": ["RCINCLUDE := $(srcdir)/bar.rc"], 362 "WIN32_EXE_LDFLAGS": ["WIN32_EXE_LDFLAGS += -subsystem:console"], 363 } 364 365 for var, val in expected.items(): 366 # print("test_variable_passthru[%s]" % (var)) 367 found = [str for str in lines if str.startswith(var)] 368 self.assertEqual(found, val) 369 370 def test_sources(self): 371 """Ensure SOURCES, HOST_SOURCES and WASM_SOURCES are handled properly.""" 372 env = self._consume("sources", RecursiveMakeBackend) 373 374 backend_path = mozpath.join(env.topobjdir, "backend.mk") 375 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 376 377 expected = { 378 "ASFILES": ["ASFILES += $(srcdir)/bar.s", "ASFILES += $(srcdir)/foo.asm"], 379 "CMMSRCS": ["CMMSRCS += $(srcdir)/bar.mm", "CMMSRCS += $(srcdir)/foo.mm"], 380 "CSRCS": ["CSRCS += $(srcdir)/bar.c", "CSRCS += $(srcdir)/foo.c"], 381 "HOST_CPPSRCS": [ 382 "HOST_CPPSRCS += $(srcdir)/bar.cpp", 383 "HOST_CPPSRCS += $(srcdir)/foo.cpp", 384 ], 385 "HOST_CSRCS": [ 386 "HOST_CSRCS += $(srcdir)/bar.c", 387 "HOST_CSRCS += $(srcdir)/foo.c", 388 ], 389 "SSRCS": ["SSRCS += $(srcdir)/baz.S", "SSRCS += $(srcdir)/foo.S"], 390 "WASM_CSRCS": ["WASM_CSRCS += $(srcdir)/bar.c"], 391 "WASM_CPPSRCS": ["WASM_CPPSRCS += $(srcdir)/bar.cpp"], 392 } 393 394 for var, val in expected.items(): 395 found = [str for str in lines if str.startswith(var)] 396 self.assertEqual(found, val) 397 398 def test_exports(self): 399 """Ensure EXPORTS is handled properly.""" 400 env = self._consume("exports", RecursiveMakeBackend) 401 402 # EXPORTS files should appear in the dist_include install manifest. 403 m = InstallManifest( 404 path=mozpath.join( 405 env.topobjdir, "_build_manifests", "install", "dist_include" 406 ) 407 ) 408 self.assertEqual(len(m), 7) 409 self.assertIn("foo.h", m) 410 self.assertIn("mozilla/mozilla1.h", m) 411 self.assertIn("mozilla/dom/dom2.h", m) 412 413 def test_generated_files(self): 414 """Ensure GENERATED_FILES is handled properly.""" 415 env = self._consume("generated-files", RecursiveMakeBackend) 416 417 backend_path = mozpath.join(env.topobjdir, "backend.mk") 418 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 419 420 expected = [ 421 "include $(topsrcdir)/config/AB_rCD.mk", 422 "PRE_COMPILE_TARGETS += $(MDDEPDIR)/bar.c.stub", 423 "bar.c: $(MDDEPDIR)/bar.c.stub ;", 424 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/bar.c.pp", 425 "$(MDDEPDIR)/bar.c.stub: %s/generate-bar.py" % env.topsrcdir, 426 "$(REPORT_BUILD)", 427 "$(call py_action,file_generate,%s/generate-bar.py baz bar.c $(MDDEPDIR)/bar.c.pp $(MDDEPDIR)/bar.c.stub)" # noqa 428 % env.topsrcdir, 429 "@$(TOUCH) $@", 430 "", 431 "EXPORT_TARGETS += $(MDDEPDIR)/foo.h.stub", 432 "foo.h: $(MDDEPDIR)/foo.h.stub ;", 433 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.h.pp", 434 "$(MDDEPDIR)/foo.h.stub: %s/generate-foo.py $(srcdir)/foo-data" 435 % (env.topsrcdir), 436 "$(REPORT_BUILD)", 437 "$(call py_action,file_generate,%s/generate-foo.py main foo.h $(MDDEPDIR)/foo.h.pp $(MDDEPDIR)/foo.h.stub $(srcdir)/foo-data)" # noqa 438 % (env.topsrcdir), 439 "@$(TOUCH) $@", 440 "", 441 ] 442 443 self.maxDiff = None 444 self.assertEqual(lines, expected) 445 446 def test_generated_files_force(self): 447 """Ensure GENERATED_FILES with .force is handled properly.""" 448 env = self._consume("generated-files-force", RecursiveMakeBackend) 449 450 backend_path = mozpath.join(env.topobjdir, "backend.mk") 451 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 452 453 expected = [ 454 "include $(topsrcdir)/config/AB_rCD.mk", 455 "PRE_COMPILE_TARGETS += $(MDDEPDIR)/bar.c.stub", 456 "bar.c: $(MDDEPDIR)/bar.c.stub ;", 457 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/bar.c.pp", 458 "$(MDDEPDIR)/bar.c.stub: %s/generate-bar.py FORCE" % env.topsrcdir, 459 "$(REPORT_BUILD)", 460 "$(call py_action,file_generate,%s/generate-bar.py baz bar.c $(MDDEPDIR)/bar.c.pp $(MDDEPDIR)/bar.c.stub)" # noqa 461 % env.topsrcdir, 462 "@$(TOUCH) $@", 463 "", 464 "PRE_COMPILE_TARGETS += $(MDDEPDIR)/foo.c.stub", 465 "foo.c: $(MDDEPDIR)/foo.c.stub ;", 466 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.c.pp", 467 "$(MDDEPDIR)/foo.c.stub: %s/generate-foo.py $(srcdir)/foo-data" 468 % (env.topsrcdir), 469 "$(REPORT_BUILD)", 470 "$(call py_action,file_generate,%s/generate-foo.py main foo.c $(MDDEPDIR)/foo.c.pp $(MDDEPDIR)/foo.c.stub $(srcdir)/foo-data)" # noqa 471 % (env.topsrcdir), 472 "@$(TOUCH) $@", 473 "", 474 ] 475 476 self.maxDiff = None 477 self.assertEqual(lines, expected) 478 479 def test_localized_generated_files(self): 480 """Ensure LOCALIZED_GENERATED_FILES is handled properly.""" 481 env = self._consume("localized-generated-files", RecursiveMakeBackend) 482 483 backend_path = mozpath.join(env.topobjdir, "backend.mk") 484 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 485 486 expected = [ 487 "include $(topsrcdir)/config/AB_rCD.mk", 488 "MISC_TARGETS += $(MDDEPDIR)/foo.xyz.stub", 489 "foo.xyz: $(MDDEPDIR)/foo.xyz.stub ;", 490 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.xyz.pp", 491 "$(MDDEPDIR)/foo.xyz.stub: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)" # noqa 492 % env.topsrcdir, 493 "$(REPORT_BUILD)", 494 "$(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 495 % env.topsrcdir, 496 "@$(TOUCH) $@", 497 "", 498 "LOCALIZED_FILES_0_FILES += foo.xyz", 499 "LOCALIZED_FILES_0_DEST = $(FINAL_TARGET)/", 500 "LOCALIZED_FILES_0_TARGET := misc", 501 "INSTALL_TARGETS += LOCALIZED_FILES_0", 502 ] 503 504 self.maxDiff = None 505 self.assertEqual(lines, expected) 506 507 def test_localized_generated_files_force(self): 508 """Ensure LOCALIZED_GENERATED_FILES with .force is handled properly.""" 509 env = self._consume("localized-generated-files-force", RecursiveMakeBackend) 510 511 backend_path = mozpath.join(env.topobjdir, "backend.mk") 512 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 513 514 expected = [ 515 "include $(topsrcdir)/config/AB_rCD.mk", 516 "MISC_TARGETS += $(MDDEPDIR)/foo.xyz.stub", 517 "foo.xyz: $(MDDEPDIR)/foo.xyz.stub ;", 518 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo.xyz.pp", 519 "$(MDDEPDIR)/foo.xyz.stub: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input $(if $(IS_LANGUAGE_REPACK),FORCE)" # noqa 520 % env.topsrcdir, 521 "$(REPORT_BUILD)", 522 "$(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 523 % env.topsrcdir, 524 "@$(TOUCH) $@", 525 "", 526 "MISC_TARGETS += $(MDDEPDIR)/abc.xyz.stub", 527 "abc.xyz: $(MDDEPDIR)/abc.xyz.stub ;", 528 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/abc.xyz.pp", 529 "$(MDDEPDIR)/abc.xyz.stub: %s/generate-foo.py $(call MERGE_FILE,localized-input) $(srcdir)/non-localized-input FORCE" # noqa 530 % env.topsrcdir, 531 "$(REPORT_BUILD)", 532 "$(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 533 % env.topsrcdir, 534 "@$(TOUCH) $@", 535 "", 536 ] 537 538 self.maxDiff = None 539 self.assertEqual(lines, expected) 540 541 def test_localized_generated_files_AB_CD(self): 542 """Ensure LOCALIZED_GENERATED_FILES is handled properly 543 when {AB_CD} and {AB_rCD} are used.""" 544 env = self._consume("localized-generated-files-AB_CD", RecursiveMakeBackend) 545 546 backend_path = mozpath.join(env.topobjdir, "backend.mk") 547 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 548 549 expected = [ 550 "include $(topsrcdir)/config/AB_rCD.mk", 551 "MISC_TARGETS += $(MDDEPDIR)/foo$(AB_CD).xyz.stub", 552 "foo$(AB_CD).xyz: $(MDDEPDIR)/foo$(AB_CD).xyz.stub ;", 553 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/foo$(AB_CD).xyz.pp", 554 "$(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 555 % env.topsrcdir, 556 "$(REPORT_BUILD)", 557 "$(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 558 % env.topsrcdir, 559 "@$(TOUCH) $@", 560 "", 561 "bar$(AB_rCD).xyz: $(MDDEPDIR)/bar$(AB_rCD).xyz.stub ;", 562 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/bar$(AB_rCD).xyz.pp", 563 "$(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 564 % env.topsrcdir, 565 "$(REPORT_BUILD)", 566 "$(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 567 % env.topsrcdir, 568 "@$(TOUCH) $@", 569 "", 570 "zot$(AB_rCD).xyz: $(MDDEPDIR)/zot$(AB_rCD).xyz.stub ;", 571 "EXTRA_MDDEPEND_FILES += $(MDDEPDIR)/zot$(AB_rCD).xyz.pp", 572 "$(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 573 % env.topsrcdir, 574 "$(REPORT_BUILD)", 575 "$(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 576 % env.topsrcdir, 577 "@$(TOUCH) $@", 578 "", 579 ] 580 581 self.maxDiff = None 582 self.assertEqual(lines, expected) 583 584 def test_exports_generated(self): 585 """Ensure EXPORTS that are listed in GENERATED_FILES 586 are handled properly.""" 587 env = self._consume("exports-generated", RecursiveMakeBackend) 588 589 # EXPORTS files should appear in the dist_include install manifest. 590 m = InstallManifest( 591 path=mozpath.join( 592 env.topobjdir, "_build_manifests", "install", "dist_include" 593 ) 594 ) 595 self.assertEqual(len(m), 8) 596 self.assertIn("foo.h", m) 597 self.assertIn("mozilla/mozilla1.h", m) 598 self.assertIn("mozilla/dom/dom1.h", m) 599 self.assertIn("gfx/gfx.h", m) 600 self.assertIn("bar.h", m) 601 self.assertIn("mozilla/mozilla2.h", m) 602 self.assertIn("mozilla/dom/dom2.h", m) 603 self.assertIn("mozilla/dom/dom3.h", m) 604 # EXPORTS files that are also GENERATED_FILES should be handled as 605 # INSTALL_TARGETS. 606 backend_path = mozpath.join(env.topobjdir, "backend.mk") 607 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 608 expected = [ 609 "include $(topsrcdir)/config/AB_rCD.mk", 610 "dist_include_FILES += bar.h", 611 "dist_include_DEST := $(DEPTH)/dist/include/", 612 "dist_include_TARGET := export", 613 "INSTALL_TARGETS += dist_include", 614 "dist_include_mozilla_FILES += mozilla2.h", 615 "dist_include_mozilla_DEST := $(DEPTH)/dist/include/mozilla", 616 "dist_include_mozilla_TARGET := export", 617 "INSTALL_TARGETS += dist_include_mozilla", 618 "dist_include_mozilla_dom_FILES += dom2.h", 619 "dist_include_mozilla_dom_FILES += dom3.h", 620 "dist_include_mozilla_dom_DEST := $(DEPTH)/dist/include/mozilla/dom", 621 "dist_include_mozilla_dom_TARGET := export", 622 "INSTALL_TARGETS += dist_include_mozilla_dom", 623 ] 624 self.maxDiff = None 625 self.assertEqual(lines, expected) 626 627 def test_resources(self): 628 """Ensure RESOURCE_FILES is handled properly.""" 629 env = self._consume("resources", RecursiveMakeBackend) 630 631 # RESOURCE_FILES should appear in the dist_bin install manifest. 632 m = InstallManifest( 633 path=os.path.join(env.topobjdir, "_build_manifests", "install", "dist_bin") 634 ) 635 self.assertEqual(len(m), 10) 636 self.assertIn("res/foo.res", m) 637 self.assertIn("res/fonts/font1.ttf", m) 638 self.assertIn("res/fonts/desktop/desktop2.ttf", m) 639 640 self.assertIn("res/bar.res.in", m) 641 self.assertIn("res/tests/test.manifest", m) 642 self.assertIn("res/tests/extra.manifest", m) 643 644 def test_test_manifests_files_written(self): 645 """Ensure test manifests get turned into files.""" 646 env = self._consume("test-manifests-written", RecursiveMakeBackend) 647 648 tests_dir = mozpath.join(env.topobjdir, "_tests") 649 m_master = mozpath.join( 650 tests_dir, "testing", "mochitest", "tests", "mochitest.ini" 651 ) 652 x_master = mozpath.join(tests_dir, "xpcshell", "xpcshell.ini") 653 self.assertTrue(os.path.exists(m_master)) 654 self.assertTrue(os.path.exists(x_master)) 655 656 lines = [l.strip() for l in open(x_master, "rt").readlines()] 657 self.assertEqual( 658 lines, 659 [ 660 "# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.", 661 "", 662 "[include:dir1/xpcshell.ini]", 663 "[include:xpcshell.ini]", 664 ], 665 ) 666 667 def test_test_manifest_pattern_matches_recorded(self): 668 """Pattern matches in test manifests' support-files should be recorded.""" 669 env = self._consume("test-manifests-written", RecursiveMakeBackend) 670 m = InstallManifest( 671 path=mozpath.join( 672 env.topobjdir, "_build_manifests", "install", "_test_files" 673 ) 674 ) 675 676 # This is not the most robust test in the world, but it gets the job 677 # done. 678 entries = [e for e in m._dests.keys() if "**" in e] 679 self.assertEqual(len(entries), 1) 680 self.assertIn("support/**", entries[0]) 681 682 def test_test_manifest_deffered_installs_written(self): 683 """Shared support files are written to their own data file by the backend.""" 684 env = self._consume("test-manifest-shared-support", RecursiveMakeBackend) 685 686 # First, read the generated for ini manifest contents. 687 test_files_manifest = mozpath.join( 688 env.topobjdir, "_build_manifests", "install", "_test_files" 689 ) 690 m = InstallManifest(path=test_files_manifest) 691 692 # Then, synthesize one from the test-installs.pkl file. This should 693 # allow us to re-create a subset of the above. 694 env = self._consume("test-manifest-shared-support", TestManifestBackend) 695 test_installs_path = mozpath.join(env.topobjdir, "test-installs.pkl") 696 697 with open(test_installs_path, "rb") as fh: 698 test_installs = pickle.load(fh) 699 700 self.assertEqual( 701 set(test_installs.keys()), 702 set(["child/test_sub.js", "child/data/**", "child/another-file.sjs"]), 703 ) 704 for key in test_installs.keys(): 705 self.assertIn(key, test_installs) 706 707 synthesized_manifest = InstallManifest() 708 for item, installs in test_installs.items(): 709 for install_info in installs: 710 if len(install_info) == 3: 711 synthesized_manifest.add_pattern_link(*install_info) 712 if len(install_info) == 2: 713 synthesized_manifest.add_link(*install_info) 714 715 self.assertEqual(len(synthesized_manifest), 3) 716 for item, info in synthesized_manifest._dests.items(): 717 self.assertIn(item, m) 718 self.assertEqual(info, m._dests[item]) 719 720 def test_xpidl_generation(self): 721 """Ensure xpidl files and directories are written out.""" 722 env = self._consume("xpidl", RecursiveMakeBackend) 723 724 # Install manifests should contain entries. 725 install_dir = mozpath.join(env.topobjdir, "_build_manifests", "install") 726 self.assertTrue(os.path.isfile(mozpath.join(install_dir, "xpidl"))) 727 728 m = InstallManifest(path=mozpath.join(install_dir, "xpidl")) 729 self.assertIn(".deps/my_module.pp", m) 730 731 m = InstallManifest(path=mozpath.join(install_dir, "xpidl")) 732 self.assertIn("my_module.xpt", m) 733 734 m = InstallManifest(path=mozpath.join(install_dir, "dist_include")) 735 self.assertIn("foo.h", m) 736 737 p = mozpath.join(env.topobjdir, "config/makefiles/xpidl") 738 self.assertTrue(os.path.isdir(p)) 739 740 self.assertTrue(os.path.isfile(mozpath.join(p, "Makefile"))) 741 742 def test_test_support_files_tracked(self): 743 env = self._consume("test-support-binaries-tracked", RecursiveMakeBackend) 744 m = InstallManifest( 745 path=mozpath.join(env.topobjdir, "_build_manifests", "install", "_tests") 746 ) 747 self.assertEqual(len(m), 4) 748 self.assertIn("xpcshell/tests/mozbuildtest/test-library.dll", m) 749 self.assertIn("xpcshell/tests/mozbuildtest/test-one.exe", m) 750 self.assertIn("xpcshell/tests/mozbuildtest/test-two.exe", m) 751 self.assertIn("xpcshell/tests/mozbuildtest/host-test-library.dll", m) 752 753 def test_old_install_manifest_deleted(self): 754 # Simulate an install manifest from a previous backend version. Ensure 755 # it is deleted. 756 env = self._get_environment("stub0") 757 purge_dir = mozpath.join(env.topobjdir, "_build_manifests", "install") 758 manifest_path = mozpath.join(purge_dir, "old_manifest") 759 os.makedirs(purge_dir) 760 m = InstallManifest() 761 m.write(path=manifest_path) 762 with open( 763 mozpath.join(env.topobjdir, "backend.RecursiveMakeBackend"), "w" 764 ) as f: 765 f.write("%s\n" % manifest_path) 766 767 self.assertTrue(os.path.exists(manifest_path)) 768 self._consume("stub0", RecursiveMakeBackend, env) 769 self.assertFalse(os.path.exists(manifest_path)) 770 771 def test_install_manifests_written(self): 772 env, objs = self._emit("stub0") 773 backend = RecursiveMakeBackend(env) 774 775 m = InstallManifest() 776 backend._install_manifests["testing"] = m 777 m.add_link(__file__, "self") 778 backend.consume(objs) 779 780 man_dir = mozpath.join(env.topobjdir, "_build_manifests", "install") 781 self.assertTrue(os.path.isdir(man_dir)) 782 783 expected = ["testing"] 784 for e in expected: 785 full = mozpath.join(man_dir, e) 786 self.assertTrue(os.path.exists(full)) 787 788 m2 = InstallManifest(path=full) 789 self.assertEqual(m, m2) 790 791 def test_ipdl_sources(self): 792 """Test that PREPROCESSED_IPDL_SOURCES and IPDL_SOURCES are written to 793 ipdlsrcs.mk correctly.""" 794 env = self._get_environment("ipdl_sources") 795 796 # Make substs writable so we can set the value of IPDL_ROOT to reflect 797 # the correct objdir. 798 env.substs = dict(env.substs) 799 env.substs["IPDL_ROOT"] = env.topobjdir 800 801 self._consume("ipdl_sources", RecursiveMakeBackend, env) 802 803 manifest_path = mozpath.join(env.topobjdir, "ipdlsrcs.mk") 804 lines = [l.strip() for l in open(manifest_path, "rt").readlines()] 805 806 # Handle Windows paths correctly 807 topsrcdir = env.topsrcdir.replace(os.sep, "/") 808 809 expected = [ 810 "ALL_IPDLSRCS := bar1.ipdl foo1.ipdl %s/bar/bar.ipdl %s/bar/bar2.ipdlh %s/foo/foo.ipdl %s/foo/foo2.ipdlh" # noqa 811 % tuple([topsrcdir] * 4), 812 "CPPSRCS := UnifiedProtocols0.cpp", 813 "IPDLDIRS := %s %s/bar %s/foo" % (env.topobjdir, topsrcdir, topsrcdir), 814 ] 815 816 found = [ 817 str 818 for str in lines 819 if str.startswith(("ALL_IPDLSRCS", "CPPSRCS", "IPDLDIRS")) 820 ] 821 self.assertEqual(found, expected) 822 823 def test_defines(self): 824 """Test that DEFINES are written to backend.mk correctly.""" 825 env = self._consume("defines", RecursiveMakeBackend) 826 827 backend_path = mozpath.join(env.topobjdir, "backend.mk") 828 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 829 830 var = "DEFINES" 831 defines = [val for val in lines if val.startswith(var)] 832 833 expected = ["DEFINES += -DFOO '-DBAZ=\"ab'\\''cd\"' -UQUX -DBAR=7 -DVALUE=xyz"] 834 self.assertEqual(defines, expected) 835 836 def test_local_includes(self): 837 """Test that LOCAL_INCLUDES are written to backend.mk correctly.""" 838 env = self._consume("local_includes", RecursiveMakeBackend) 839 840 backend_path = mozpath.join(env.topobjdir, "backend.mk") 841 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 842 843 expected = [ 844 "LOCAL_INCLUDES += -I$(srcdir)/bar/baz", 845 "LOCAL_INCLUDES += -I$(srcdir)/foo", 846 ] 847 848 found = [str for str in lines if str.startswith("LOCAL_INCLUDES")] 849 self.assertEqual(found, expected) 850 851 def test_generated_includes(self): 852 """Test that GENERATED_INCLUDES are written to backend.mk correctly.""" 853 env = self._consume("generated_includes", RecursiveMakeBackend) 854 855 backend_path = mozpath.join(env.topobjdir, "backend.mk") 856 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 857 858 expected = [ 859 "LOCAL_INCLUDES += -I$(CURDIR)/bar/baz", 860 "LOCAL_INCLUDES += -I$(CURDIR)/foo", 861 ] 862 863 found = [str for str in lines if str.startswith("LOCAL_INCLUDES")] 864 self.assertEqual(found, expected) 865 866 def test_rust_library(self): 867 """Test that a Rust library is written to backend.mk correctly.""" 868 env = self._consume("rust-library", RecursiveMakeBackend) 869 870 backend_path = mozpath.join(env.topobjdir, "backend.mk") 871 lines = [ 872 l.strip() 873 for l in open(backend_path, "rt").readlines()[2:] 874 # Strip out computed flags, they're a PITA to test. 875 if not l.startswith("COMPUTED_") 876 ] 877 878 expected = [ 879 "RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libtest_library.a" 880 % env.topobjdir, # noqa 881 "CARGO_FILE := $(srcdir)/Cargo.toml", 882 "CARGO_TARGET_DIR := %s" % env.topobjdir, 883 ] 884 885 self.assertEqual(lines, expected) 886 887 def test_host_rust_library(self): 888 """Test that a Rust library is written to backend.mk correctly.""" 889 env = self._consume("host-rust-library", RecursiveMakeBackend) 890 891 backend_path = mozpath.join(env.topobjdir, "backend.mk") 892 lines = [ 893 l.strip() 894 for l in open(backend_path, "rt").readlines()[2:] 895 # Strip out computed flags, they're a PITA to test. 896 if not l.startswith("COMPUTED_") 897 ] 898 899 expected = [ 900 "HOST_RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libhostrusttool.a" 901 % env.topobjdir, # noqa 902 "CARGO_FILE := $(srcdir)/Cargo.toml", 903 "CARGO_TARGET_DIR := %s" % env.topobjdir, 904 ] 905 906 self.assertEqual(lines, expected) 907 908 def test_host_rust_library_with_features(self): 909 """Test that a host Rust library with features is written to backend.mk correctly.""" 910 env = self._consume("host-rust-library-features", RecursiveMakeBackend) 911 912 backend_path = mozpath.join(env.topobjdir, "backend.mk") 913 lines = [ 914 l.strip() 915 for l in open(backend_path, "rt").readlines()[2:] 916 # Strip out computed flags, they're a PITA to test. 917 if not l.startswith("COMPUTED_") 918 ] 919 920 expected = [ 921 "HOST_RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libhostrusttool.a" 922 % env.topobjdir, # noqa 923 "CARGO_FILE := $(srcdir)/Cargo.toml", 924 "CARGO_TARGET_DIR := %s" % env.topobjdir, 925 "HOST_RUST_LIBRARY_FEATURES := musthave cantlivewithout", 926 ] 927 928 self.assertEqual(lines, expected) 929 930 def test_rust_library_with_features(self): 931 """Test that a Rust library with features is written to backend.mk correctly.""" 932 env = self._consume("rust-library-features", RecursiveMakeBackend) 933 934 backend_path = mozpath.join(env.topobjdir, "backend.mk") 935 lines = [ 936 l.strip() 937 for l in open(backend_path, "rt").readlines()[2:] 938 # Strip out computed flags, they're a PITA to test. 939 if not l.startswith("COMPUTED_") 940 ] 941 942 expected = [ 943 "RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libfeature_library.a" 944 % env.topobjdir, # noqa 945 "CARGO_FILE := $(srcdir)/Cargo.toml", 946 "CARGO_TARGET_DIR := %s" % env.topobjdir, 947 "RUST_LIBRARY_FEATURES := musthave cantlivewithout", 948 ] 949 950 self.assertEqual(lines, expected) 951 952 def test_rust_programs(self): 953 """Test that {HOST_,}RUST_PROGRAMS are written to backend.mk correctly.""" 954 env = self._consume("rust-programs", RecursiveMakeBackend) 955 956 backend_path = mozpath.join(env.topobjdir, "code/backend.mk") 957 lines = [ 958 l.strip() 959 for l in open(backend_path, "rt").readlines()[2:] 960 # Strip out computed flags, they're a PITA to test. 961 if not l.startswith("COMPUTED_") 962 ] 963 964 expected = [ 965 "CARGO_FILE := %s/code/Cargo.toml" % env.topsrcdir, 966 "CARGO_TARGET_DIR := .", 967 "RUST_PROGRAMS += i686-pc-windows-msvc/release/target.exe", 968 "RUST_CARGO_PROGRAMS += target", 969 "HOST_RUST_PROGRAMS += i686-pc-windows-msvc/release/host.exe", 970 "HOST_RUST_CARGO_PROGRAMS += host", 971 ] 972 973 self.assertEqual(lines, expected) 974 975 root_deps_path = mozpath.join(env.topobjdir, "root-deps.mk") 976 lines = [l.strip() for l in open(root_deps_path, "rt").readlines()] 977 978 self.assertTrue( 979 any(l == "recurse_compile: code/host code/target" for l in lines) 980 ) 981 982 def test_final_target(self): 983 """Test that FINAL_TARGET is written to backend.mk correctly.""" 984 env = self._consume("final_target", RecursiveMakeBackend) 985 986 final_target_rule = "FINAL_TARGET = $(if $(XPI_NAME),$(DIST)/xpi-stage/$(XPI_NAME),$(DIST)/bin)$(DIST_SUBDIR:%=/%)" # noqa 987 expected = dict() 988 expected[env.topobjdir] = [] 989 expected[mozpath.join(env.topobjdir, "both")] = [ 990 "XPI_NAME = mycrazyxpi", 991 "DIST_SUBDIR = asubdir", 992 final_target_rule, 993 ] 994 expected[mozpath.join(env.topobjdir, "dist-subdir")] = [ 995 "DIST_SUBDIR = asubdir", 996 final_target_rule, 997 ] 998 expected[mozpath.join(env.topobjdir, "xpi-name")] = [ 999 "XPI_NAME = mycrazyxpi", 1000 final_target_rule, 1001 ] 1002 expected[mozpath.join(env.topobjdir, "final-target")] = [ 1003 "FINAL_TARGET = $(DEPTH)/random-final-target" 1004 ] 1005 for key, expected_rules in six.iteritems(expected): 1006 backend_path = mozpath.join(key, "backend.mk") 1007 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 1008 found = [ 1009 str 1010 for str in lines 1011 if str.startswith("FINAL_TARGET") 1012 or str.startswith("XPI_NAME") 1013 or str.startswith("DIST_SUBDIR") 1014 ] 1015 self.assertEqual(found, expected_rules) 1016 1017 def test_final_target_pp_files(self): 1018 """Test that FINAL_TARGET_PP_FILES is written to backend.mk correctly.""" 1019 env = self._consume("dist-files", RecursiveMakeBackend) 1020 1021 backend_path = mozpath.join(env.topobjdir, "backend.mk") 1022 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 1023 1024 expected = [ 1025 "DIST_FILES_0 += $(srcdir)/install.rdf", 1026 "DIST_FILES_0 += $(srcdir)/main.js", 1027 "DIST_FILES_0_PATH := $(DEPTH)/dist/bin/", 1028 "DIST_FILES_0_TARGET := misc", 1029 "PP_TARGETS += DIST_FILES_0", 1030 ] 1031 1032 found = [str for str in lines if "DIST_FILES" in str] 1033 self.assertEqual(found, expected) 1034 1035 def test_localized_files(self): 1036 """Test that LOCALIZED_FILES is written to backend.mk correctly.""" 1037 env = self._consume("localized-files", RecursiveMakeBackend) 1038 1039 backend_path = mozpath.join(env.topobjdir, "backend.mk") 1040 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 1041 1042 expected = [ 1043 "LOCALIZED_FILES_0_FILES += $(wildcard $(LOCALE_SRCDIR)/abc/*.abc)", 1044 "LOCALIZED_FILES_0_FILES += $(call MERGE_FILE,bar.ini)", 1045 "LOCALIZED_FILES_0_FILES += $(call MERGE_FILE,foo.js)", 1046 "LOCALIZED_FILES_0_DEST = $(FINAL_TARGET)/", 1047 "LOCALIZED_FILES_0_TARGET := misc", 1048 "INSTALL_TARGETS += LOCALIZED_FILES_0", 1049 ] 1050 1051 found = [str for str in lines if "LOCALIZED_FILES" in str] 1052 self.assertEqual(found, expected) 1053 1054 def test_localized_pp_files(self): 1055 """Test that LOCALIZED_PP_FILES is written to backend.mk correctly.""" 1056 env = self._consume("localized-pp-files", RecursiveMakeBackend) 1057 1058 backend_path = mozpath.join(env.topobjdir, "backend.mk") 1059 lines = [l.strip() for l in open(backend_path, "rt").readlines()[2:]] 1060 1061 expected = [ 1062 "LOCALIZED_PP_FILES_0 += $(call MERGE_FILE,bar.ini)", 1063 "LOCALIZED_PP_FILES_0 += $(call MERGE_FILE,foo.js)", 1064 "LOCALIZED_PP_FILES_0_PATH = $(FINAL_TARGET)/", 1065 "LOCALIZED_PP_FILES_0_TARGET := misc", 1066 "LOCALIZED_PP_FILES_0_FLAGS := --silence-missing-directive-warnings", 1067 "PP_TARGETS += LOCALIZED_PP_FILES_0", 1068 ] 1069 1070 found = [str for str in lines if "LOCALIZED_PP_FILES" in str] 1071 self.assertEqual(found, expected) 1072 1073 def test_config(self): 1074 """Test that CONFIGURE_SUBST_FILES are properly handled.""" 1075 env = self._consume("test_config", RecursiveMakeBackend) 1076 1077 self.assertEqual( 1078 open(os.path.join(env.topobjdir, "file"), "r").readlines(), 1079 ["#ifdef foo\n", "bar baz\n", "@bar@\n"], 1080 ) 1081 1082 def test_prog_lib_c_only(self): 1083 """Test that C-only binary artifacts are marked as such.""" 1084 env = self._consume("prog-lib-c-only", RecursiveMakeBackend) 1085 1086 # PROGRAM C-onlyness. 1087 with open(os.path.join(env.topobjdir, "c-program", "backend.mk"), "r") as fh: 1088 lines = fh.readlines() 1089 lines = [line.rstrip() for line in lines] 1090 1091 self.assertIn("PROG_IS_C_ONLY_c_test_program := 1", lines) 1092 1093 with open(os.path.join(env.topobjdir, "cxx-program", "backend.mk"), "r") as fh: 1094 lines = fh.readlines() 1095 lines = [line.rstrip() for line in lines] 1096 1097 # Test for only the absence of the variable, not the precise 1098 # form of the variable assignment. 1099 for line in lines: 1100 self.assertNotIn("PROG_IS_C_ONLY_cxx_test_program", line) 1101 1102 # SIMPLE_PROGRAMS C-onlyness. 1103 with open( 1104 os.path.join(env.topobjdir, "c-simple-programs", "backend.mk"), "r" 1105 ) as fh: 1106 lines = fh.readlines() 1107 lines = [line.rstrip() for line in lines] 1108 1109 self.assertIn("PROG_IS_C_ONLY_c_simple_program := 1", lines) 1110 1111 with open( 1112 os.path.join(env.topobjdir, "cxx-simple-programs", "backend.mk"), "r" 1113 ) as fh: 1114 lines = fh.readlines() 1115 lines = [line.rstrip() for line in lines] 1116 1117 for line in lines: 1118 self.assertNotIn("PROG_IS_C_ONLY_cxx_simple_program", line) 1119 1120 # Libraries C-onlyness. 1121 with open(os.path.join(env.topobjdir, "c-library", "backend.mk"), "r") as fh: 1122 lines = fh.readlines() 1123 lines = [line.rstrip() for line in lines] 1124 1125 self.assertIn("LIB_IS_C_ONLY := 1", lines) 1126 1127 with open(os.path.join(env.topobjdir, "cxx-library", "backend.mk"), "r") as fh: 1128 lines = fh.readlines() 1129 lines = [line.rstrip() for line in lines] 1130 1131 for line in lines: 1132 self.assertNotIn("LIB_IS_C_ONLY", line) 1133 1134 def test_linkage(self): 1135 env = self._consume("linkage", RecursiveMakeBackend) 1136 expected_linkage = { 1137 "prog": { 1138 "SHARED_LIBS": ["qux/qux.so", "../shared/baz.so"], 1139 "STATIC_LIBS": ["../real/foo.a"], 1140 "OS_LIBS": ["-lfoo", "-lbaz", "-lbar"], 1141 }, 1142 "shared": { 1143 "OS_LIBS": ["-lfoo"], 1144 "SHARED_LIBS": ["../prog/qux/qux.so"], 1145 "STATIC_LIBS": [], 1146 }, 1147 "static": { 1148 "STATIC_LIBS": ["../real/foo.a"], 1149 "OS_LIBS": ["-lbar"], 1150 "SHARED_LIBS": ["../prog/qux/qux.so"], 1151 }, 1152 "real": { 1153 "STATIC_LIBS": [], 1154 "SHARED_LIBS": ["../prog/qux/qux.so"], 1155 "OS_LIBS": ["-lbaz"], 1156 }, 1157 } 1158 actual_linkage = {} 1159 for name in expected_linkage.keys(): 1160 with open(os.path.join(env.topobjdir, name, "backend.mk"), "r") as fh: 1161 actual_linkage[name] = [line.rstrip() for line in fh.readlines()] 1162 for name in expected_linkage: 1163 for var in expected_linkage[name]: 1164 for val in expected_linkage[name][var]: 1165 val = os.path.normpath(val) 1166 line = "%s += %s" % (var, val) 1167 self.assertIn(line, actual_linkage[name]) 1168 actual_linkage[name].remove(line) 1169 for line in actual_linkage[name]: 1170 self.assertNotIn("%s +=" % var, line) 1171 1172 def test_list_files(self): 1173 env = self._consume("linkage", RecursiveMakeBackend) 1174 expected_list_files = { 1175 "prog/MyProgram_exe.list": [ 1176 "../static/bar/bar1.o", 1177 "../static/bar/bar2.o", 1178 "../static/bar/bar_helper/bar_helper1.o", 1179 ], 1180 "shared/baz_so.list": ["baz/baz1.o"], 1181 } 1182 actual_list_files = {} 1183 for name in expected_list_files.keys(): 1184 with open(os.path.join(env.topobjdir, name), "r") as fh: 1185 actual_list_files[name] = [line.rstrip() for line in fh.readlines()] 1186 for name in expected_list_files: 1187 self.assertEqual( 1188 actual_list_files[name], 1189 [os.path.normpath(f) for f in expected_list_files[name]], 1190 ) 1191 1192 # We don't produce a list file for a shared library composed only of 1193 # object files in its directory, but instead list them in a variable. 1194 with open(os.path.join(env.topobjdir, "prog", "qux", "backend.mk"), "r") as fh: 1195 lines = [line.rstrip() for line in fh.readlines()] 1196 1197 self.assertIn("qux.so_OBJS := qux1.o", lines) 1198 1199 def test_jar_manifests(self): 1200 env = self._consume("jar-manifests", RecursiveMakeBackend) 1201 1202 with open(os.path.join(env.topobjdir, "backend.mk"), "r") as fh: 1203 lines = fh.readlines() 1204 1205 lines = [line.rstrip() for line in lines] 1206 1207 self.assertIn("JAR_MANIFEST := %s/jar.mn" % env.topsrcdir, lines) 1208 1209 def test_test_manifests_duplicate_support_files(self): 1210 """Ensure duplicate support-files in test manifests work.""" 1211 env = self._consume( 1212 "test-manifests-duplicate-support-files", RecursiveMakeBackend 1213 ) 1214 1215 p = os.path.join(env.topobjdir, "_build_manifests", "install", "_test_files") 1216 m = InstallManifest(p) 1217 self.assertIn("testing/mochitest/tests/support-file.txt", m) 1218 1219 def test_install_manifests_package_tests(self): 1220 """Ensure test suites honor package_tests=False.""" 1221 env = self._consume("test-manifests-package-tests", RecursiveMakeBackend) 1222 1223 man_dir = mozpath.join(env.topobjdir, "_build_manifests", "install") 1224 self.assertTrue(os.path.isdir(man_dir)) 1225 1226 full = mozpath.join(man_dir, "_test_files") 1227 self.assertTrue(os.path.exists(full)) 1228 1229 m = InstallManifest(path=full) 1230 1231 # Only mochitest.js should be in the install manifest. 1232 self.assertTrue("testing/mochitest/tests/mochitest.js" in m) 1233 1234 # The path is odd here because we do not normalize at test manifest 1235 # processing time. This is a fragile test because there's currently no 1236 # way to iterate the manifest. 1237 self.assertFalse("instrumentation/./not_packaged.java" in m) 1238 1239 def test_program_paths(self): 1240 """PROGRAMs with various moz.build settings that change the destination should produce 1241 the expected paths in backend.mk.""" 1242 env = self._consume("program-paths", RecursiveMakeBackend) 1243 1244 expected = [ 1245 ("dist-bin", "$(DEPTH)/dist/bin/dist-bin.prog"), 1246 ("dist-subdir", "$(DEPTH)/dist/bin/foo/dist-subdir.prog"), 1247 ("final-target", "$(DEPTH)/final/target/final-target.prog"), 1248 ("not-installed", "not-installed.prog"), 1249 ] 1250 prefix = "PROGRAM = " 1251 for (subdir, expected_program) in expected: 1252 with io.open(os.path.join(env.topobjdir, subdir, "backend.mk"), "r") as fh: 1253 lines = fh.readlines() 1254 program = [ 1255 line.rstrip().split(prefix, 1)[1] 1256 for line in lines 1257 if line.startswith(prefix) 1258 ][0] 1259 self.assertEqual(program, expected_program) 1260 1261 1262if __name__ == "__main__": 1263 main() 1264