chromium,chromedriver: 129.0.6668.91 -> 129.0.6668.100
[NixPkgs.git] / pkgs / os-specific / darwin / gen-frameworks.py
blobec2a6c7c16ecd1d82f6bdbf7c53b8f989a99d4c3
1 #!/usr/bin/env nix-shell
2 #!nix-shell -i python -p python3 swiftPackages.swift-unwrapped
4 """
5 Generate a frameworks.nix for a macOS SDK.
7 You may point this tool at an Xcode bundled SDK, but more ideal is using the
8 SDK from Nixpkgs. For example:
10 SDK_PATH="$(nix-build --no-link -A darwin.apple_sdk_11_0.MacOSX-SDK)"
11 ./gen-frameworks.py "$SDK_PATH" > ./new-frameworks.nix
12 """
14 import json
15 import os
16 import subprocess
17 import sys
19 ALLOWED_LIBS = ["simd"]
21 HEADER = """\
22 # This file is generated by gen-frameworks.nix.
23 # Do not edit, put overrides in apple_sdk.nix instead.
24 { libs, frameworks }: with libs; with frameworks;
26 """
28 FOOTER = """\
30 """
33 def eprint(*args):
34 print(*args, file=sys.stderr)
37 def name_from_ident(ident):
38 return ident.get("swift", ident.get("clang"))
41 def scan_sdk(sdk):
42 # Find frameworks by scanning the SDK frameworks directory.
43 frameworks = [
44 framework.removesuffix(".framework")
45 for framework in os.listdir(f"{sdk}/System/Library/Frameworks")
46 if not framework.startswith("_")
48 frameworks.sort()
50 # Determine the longest name for padding output.
51 width = len(max(frameworks, key=len))
53 output = HEADER
55 for framework in frameworks:
56 deps = []
58 # Use Swift to scan dependencies, because a module may have both Clang
59 # and Swift parts. Using Clang only imports the Clang module, whereas
60 # using Swift will usually import both Clang + Swift overlay.
62 # TODO: The above is an assumption. Not sure if it's possible a Swift
63 # module completely shadows a Clang module. (Seems unlikely)
65 # TODO: Handle "module 'Foobar' is incompatible with feature 'swift'"
67 # If there were a similar Clang invocation for scanning, we could fix
68 # the above todos, but that doesn't appear to exist.
69 eprint(f"# scanning {framework}")
70 result = subprocess.run(
72 "swiftc",
73 "-scan-dependencies",
74 # We provide a source snippet via stdin.
75 "-",
76 # Use the provided SDK.
77 "-sdk",
78 sdk,
79 # This search path is normally added automatically by the
80 # compiler based on the SDK, but we have a patch in place that
81 # removes that for SDKs in /nix/store, because our xcbuild stub
82 # SDK doesn't have the directory.
83 # (swift-prevent-sdk-dirs-warning.patch)
84 "-I",
85 f"{sdk}/usr/lib/swift",
86 # For some reason, 'lib/swift/shims' from both the SDK and
87 # Swift compiler are picked up, causing redefinition errors.
88 # This eliminates the latter.
89 "-resource-dir",
90 f"{sdk}/usr/lib/swift",
92 input=f"import {framework}".encode(),
93 stdout=subprocess.PIPE,
95 if result.returncode != 0:
96 eprint(f"# Scanning {framework} failed (exit code {result.returncode})")
97 result.stdout = b""
99 # Parse JSON output.
100 if len(result.stdout) != 0:
101 data = json.loads(result.stdout)
103 # Entries in the modules list come in pairs. The first is an
104 # identifier (`{ swift: "foobar" }` or `{ clang: "foobar" }`), and
105 # the second metadata for that module. Here we look for the pair
106 # that matches the framework we're scanning (and ignore the rest).
107 modules = data["modules"]
108 for i in range(0, len(modules), 2):
109 ident, meta = modules[i : i + 2]
111 # NOTE: We may match twice, for a Swift module _and_ for a
112 # Clang module. So matching here doesn't break from the loop,
113 # and deps is appended to.
114 if name_from_ident(ident) == framework:
115 dep_idents = meta["directDependencies"]
116 deps += [name_from_ident(ident) for ident in dep_idents]
117 # List unfiltered deps in progress output.
118 eprint(ident, "->", dep_idents)
120 # Filter out modules that are not separate derivations.
121 # Also filter out duplicates (when a Swift overlay imports the Clang module)
122 allowed = frameworks + ALLOWED_LIBS
123 deps = set([dep for dep in deps if dep in allowed])
125 # Filter out self-references. (Swift overlay importing Clang module.)
126 if framework in deps:
127 deps.remove(framework)
129 # Generate a Nix attribute line.
130 if len(deps) != 0:
131 deps = list(deps)
132 deps.sort()
133 deps = " ".join(deps)
134 output += f" {framework.ljust(width)} = {{ inherit {deps}; }};\n"
135 else:
136 output += f" {framework.ljust(width)} = {{}};\n"
138 output += FOOTER
139 sys.stdout.write(output)
142 if __name__ == "__main__":
143 if len(sys.argv) != 2:
144 eprint(f"Usage: {sys.argv[0]} <path to MacOSX.sdk>")
145 sys.exit(64)
147 scan_sdk(sys.argv[1])