Files
drippu/.github/scripts/test_package_macos.py
Dallin Bland 9e51197c36 Fix automated release failures on macOS, FreeBSD, and Android libretro
The macOS packager treated each library install name as a load command, so
@executable_path self-ids failed the portability check. FreeBSD configure
requires Qt6 Charts and Svg. Android libretro could not link the prebuilt
OpenSSL archive until Poly1305 SVE2 binds locally, matching yuzu-android.
2026-09-21 13:54:02 -05:00

92 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""Regression tests for macOS release packaging path checks."""
from __future__ import annotations
import importlib.util
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
SCRIPT = Path(__file__).with_name("package_macos.py")
spec = importlib.util.spec_from_file_location("package_macos", SCRIPT)
assert spec and spec.loader
package = importlib.util.module_from_spec(spec)
spec.loader.exec_module(package)
class PackageMacOSTest(unittest.TestCase):
def test_otool_listing_drops_install_id(self) -> None:
install_name = "@executable_path/../Frameworks/libSDL3.0.dylib"
entries = [
install_name,
"@executable_path/../Frameworks/libfoo.dylib",
"/usr/lib/libSystem.B.dylib",
]
self.assertEqual(
package.dependent_libraries(entries, install_name),
[
"@executable_path/../Frameworks/libfoo.dylib",
"/usr/lib/libSystem.B.dylib",
],
)
def test_executables_keep_every_load_command(self) -> None:
entries = ["/usr/lib/libSystem.B.dylib", "@rpath/QtCore.framework/Versions/A/QtCore"]
self.assertEqual(package.dependent_libraries(entries, None), entries)
def test_framework_executable_path_id_is_not_a_cli_dependency(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
app = root / "drippu.app"
frameworks = app / "Contents" / "Frameworks"
binary = frameworks / "libSDL3.0.dylib"
binary.parent.mkdir(parents=True)
binary.write_bytes(b"")
cli = root / "drippu-cmd"
cli.write_bytes(b"")
app_executable = app / "Contents" / "MacOS" / "suyu"
app_executable.parent.mkdir(parents=True)
app_executable.write_bytes(b"")
install_name = "@executable_path/../Frameworks/libSDL3.0.dylib"
# Resolves for the .app executable. The same string on a Frameworks
# dylib is its install name, not a load command the CLI must satisfy.
self.assertTrue(package.reference_exists(install_name, app_executable, app, cli))
self.assertFalse(package.reference_exists(install_name, binary, app, cli))
self.assertTrue(
package.reference_exists("@loader_path/libSDL3.0.dylib", binary, app, cli)
)
@unittest.skipUnless(sys.platform == "darwin", "needs otool")
def test_real_dylib_install_id_is_excluded(self) -> None:
clang = "clang"
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
source = root / "dep.c"
source.write_text("void dep(void) {}\n", encoding="utf-8")
binary = root / "libdep.dylib"
install_name = "@executable_path/../Frameworks/libdep.dylib"
subprocess.run(
[
clang,
"-dynamiclib",
"-o",
str(binary),
"-install_name",
install_name,
str(source),
],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
self.assertEqual(package.install_id(binary), install_name)
self.assertNotIn(install_name, package.dependencies(binary))
if __name__ == "__main__":
unittest.main()