|
8 | 8 | # SDK modules (WeatherKit), SwiftPM packages and the app's own module. They are |
9 | 9 | # generated as one unit. The script writes the object file and the extra |
10 | 10 | # linker arguments, one per line, to |
11 | | -# $CONFIGURATION_BUILD_DIR/NSSwiftInterop-<arch>/link-arguments.txt. |
| 11 | +# $CONFIGURATION_BUILD_DIR/NSSwiftInterop-<arch>/link-arguments.txt. When the |
| 12 | +# extracted symbol graphs, the generator and the settings are unchanged, the |
| 13 | +# previous object is reused. |
12 | 14 | # |
13 | 15 | # Optional settings: |
14 | 16 | # NS_SWIFT_UNIT unit name (default: <product module>Swift) |
15 | 17 | # NS_SWIFT_VERIFY NO skips compiler verification of the surface |
16 | 18 | # NS_TYPESCRIPT_DECLARATIONS_PATH also writes swift!<Module>.d.ts there |
17 | 19 |
|
| 20 | +import hashlib |
| 21 | +import json |
18 | 22 | import os |
19 | 23 | import shlex |
20 | 24 | import shutil |
@@ -42,8 +46,10 @@ def main(arch): |
42 | 46 | modules = env("NS_SWIFT_MODULES").split() |
43 | 47 | work = os.path.join(env("CONFIGURATION_BUILD_DIR"), "NSSwiftInterop-" + arch) |
44 | 48 | arguments_file = os.path.join(work, "link-arguments.txt") |
45 | | - shutil.rmtree(work, ignore_errors=True) |
46 | | - os.makedirs(work) |
| 49 | + key_file = os.path.join(work, "cache-key.txt") |
| 50 | + for stale in ("graphs", "verify"): |
| 51 | + shutil.rmtree(os.path.join(work, stale), ignore_errors=True) |
| 52 | + os.makedirs(work, exist_ok=True) |
47 | 53 | if not modules: |
48 | 54 | open(arguments_file, "w").close() |
49 | 55 | return |
@@ -100,15 +106,33 @@ def resolve(paths): |
100 | 106 | declarations = env("NS_TYPESCRIPT_DECLARATIONS_PATH") |
101 | 107 | if declarations: |
102 | 108 | generator += ["-output-typescript", os.path.join(declarations, "swift")] |
103 | | - run(generator + ["Xclang"], os.path.join(work, "generator.log")) |
104 | | - |
105 | 109 | thunks = os.path.join(work, unit + "+NativeScript.swift") |
106 | 110 | obj = os.path.join(work, unit + "+NativeScript.o") |
107 | 111 | optimization = "-Onone" if env("CONFIGURATION") == "Debug" else "-O" |
108 | | - run(["xcrun", "swiftc", "-parse-as-library", "-c", thunks, "-o", obj, |
109 | | - "-module-name", "NSSwiftInterop" + unit, "-target", target, "-sdk", sdk, |
110 | | - "-swift-version", "5", optimization] + search_flags, |
111 | | - os.path.join(work, "swiftc.log")) |
| 112 | + compile = ["xcrun", "swiftc", "-parse-as-library", "-c", thunks, "-o", obj, |
| 113 | + "-module-name", "NSSwiftInterop" + unit, "-target", target, "-sdk", sdk, |
| 114 | + "-swift-version", "5", optimization] + search_flags |
| 115 | + |
| 116 | + # Everything the object depends on. |
| 117 | + digest = hashlib.sha256() |
| 118 | + for directory in graph_dirs: |
| 119 | + for name in sorted(os.listdir(directory)): |
| 120 | + with open(os.path.join(directory, name), "rb") as graph: |
| 121 | + digest.update(name.encode() + graph.read()) |
| 122 | + tool = os.stat("./objc-metadata-generator") |
| 123 | + digest.update(json.dumps([generator, compile, tool.st_size, tool.st_mtime, |
| 124 | + os.stat(__file__).st_mtime]).encode()) |
| 125 | + key = digest.hexdigest() |
| 126 | + previous = open(key_file).read() if os.path.exists(key_file) else "" |
| 127 | + if previous == key and os.path.exists(obj): |
| 128 | + print("Swift interop: {} is up to date".format(obj)) |
| 129 | + else: |
| 130 | + if os.path.exists(key_file): |
| 131 | + os.remove(key_file) |
| 132 | + run(generator + ["Xclang"], os.path.join(work, "generator.log")) |
| 133 | + run(compile, os.path.join(work, "swiftc.log")) |
| 134 | + with open(key_file, "w") as output: |
| 135 | + output.write(key) |
112 | 136 |
|
113 | 137 | with open(arguments_file, "w") as output: |
114 | 138 | output.write(obj + "\n") |
|
0 commit comments