diff --git a/core/relinker/domain/include/domain/Types.hpp b/core/relinker/domain/include/domain/Types.hpp index 31405091c5..e488940a5f 100644 --- a/core/relinker/domain/include/domain/Types.hpp +++ b/core/relinker/domain/include/domain/Types.hpp @@ -112,6 +112,7 @@ struct CallRegistryEntry { FileByteOffset TargetOffset; std::vector CallSites; bool CallSitesResolved; + bool Weak = false; }; } diff --git a/core/relinker/relinker/src/output/CallRegistryWriter.cpp b/core/relinker/relinker/src/output/CallRegistryWriter.cpp index e598056d6e..7c8c909e63 100644 --- a/core/relinker/relinker/src/output/CallRegistryWriter.cpp +++ b/core/relinker/relinker/src/output/CallRegistryWriter.cpp @@ -52,7 +52,8 @@ std::string CallRegistryWriter::WriteCallRegistry(const std::vector 2: + record["weak"] = entry[2] + records.append(record) + path.write_text(json.dumps(records), encoding=encoding) class Workspace: @@ -485,6 +491,17 @@ class ImportAuditTests(unittest.TestCase): self.assertEqual(data["stops"], [{"registry": str(registry), "nid": None, "library": None, "name": None}]) self.assertIn(f" {registry}: none", out) + def test_a_weak_unresolved_import_is_not_a_stop(self): + work = self.work + (work.libs / "libSceA.prx").write_bytes(exporting("AAAAAAAAAAA")) + registry = work.root / "game.json" + write_registry(registry, [("BBBBBBBBBBB", "libSceA.prx", True), ("CCCCCCCCCCC", "libSceA.prx")]) + result = work.root / "audit.json" + code, out, err = work.run(registry, "--json", str(result)) + self.assertEqual((code, err), (1, "")) + data = json.loads(result.read_text()) + self.assertEqual(data["stops"], [{"registry": str(registry), "nid": "CCCCCCCCCCC", "library": "libSceA.prx", "name": None}]) + def test_removing_an_export_flips_the_class(self): work = self.work registry = work.root / "game.json" @@ -517,11 +534,11 @@ class ImportAuditTests(unittest.TestCase): nid = nid_names.compute_nid("sceTwinCall") stubs = import_audit.source_stubs(source) exports = {nid: ["libA.prx", "libB.prx"]} - records, _ = import_audit.audit([(nid, "libB.prx")], {nid: ["libB.prx"]}, stubs, {"libB.prx"}, set()) + records, _ = import_audit.audit([(nid, "libB.prx", False)], {nid: ["libB.prx"]}, stubs, {"libB.prx"}, set()) self.assertEqual((records[0]["class"], records[0]["name"]), ("stub", "sceTwinCall")) - records, _ = import_audit.audit([(nid, "libA.prx")], {nid: ["libA.prx"]}, stubs, {"libA.prx"}, set()) + records, _ = import_audit.audit([(nid, "libA.prx", False)], {nid: ["libA.prx"]}, stubs, {"libA.prx"}, set()) self.assertEqual((records[0]["class"], records[0]["name"]), ("implemented", None)) - records, _ = import_audit.audit([(nid, "libB.prx")], exports, stubs, {"libA.prx", "libB.prx"}, set()) + records, _ = import_audit.audit([(nid, "libB.prx", False)], exports, stubs, {"libA.prx", "libB.prx"}, set()) self.assertEqual(records[0]["class"], "implemented") def test_cmake_shared_library_preserves_stub_names_and_implemented_exports(self): @@ -889,7 +906,7 @@ class ImportAuditTests(unittest.TestCase): with self.assertRaisesRegex(import_audit.AuditError, r"entry 1 has an invalid NID 'bad\\x01nid'"): import_audit.read_registry(path) write_registry(path, [("AAAAAAAAAAA#A#B", "libSceA.prx")], encoding="utf-8-sig") - self.assertEqual(import_audit.read_registry(path), [("AAAAAAAAAAA", "libSceA.prx")]) + self.assertEqual(import_audit.read_registry(path), [("AAAAAAAAAAA", "libSceA.prx", False)]) def test_names_never_download(self): work = self.work