Skip to content

Commit e07ecaa

Browse files
authored
generator: Cache the lld binary after extracting it from the LLVM archive (#149)
Extracting `lld` from the `llvm` archive takes about 40s on my machine, and after the binary has been extracted a 5.5GB directory is left behind in the `Artifacts` directory. This change uses `tar` filters to reduce the number of files unpacked from the archive and caches the resulting `lld` binary. Excluding the time to download the archives, building an SDK from Debian packages before `lld` has been cached takes about 57s on an M3 MacBook Air. A subsequent build with `lld` cached takes about 17s. The SDKs generated by the old and new methods are identical. This PR adds `CacheKey` conformance to `Array`, as suggested by @yingguqing in #106. Adding this conformance to `Range` was not necessary in this case. -- * generator: Adopt CacheKey conformance for [FilePath.Component] This is needed to cache arrays of [FilePath.Component], so a subsequent commit can cache the slow extraction of the `ld.lld` binary from the `llvm` tar archive. This problem was also reported by @yingguqing in #106, although Range conformance does not seem to be required to cache lld. Suggested-by: @yingguqing * generator: Cache the lld binary after extracting it from the LLVM archive Extracting `lld` from the `llvm` archive takes about 40s on my machine, and after the binary has been extracted a 5.5GB directory is left in the `Artifacts` directory. This change uses `tar` filters to reduce the number of files unpacked from the archive and caches the resulting `lld` binary. Excluding the time to download the archives, building an SDK from Debian packages before `lld` has been cached takes about 57s on an M3 MacBook Air. A subsequent build with `lld` cached takes about 17s. The SDKs generated by the old and new methods are identical.
1 parent 397105e commit e07ecaa

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

Sources/Helpers/Vendor/QueryEngine/CacheKey.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,11 @@ extension URL: LeafCacheKey {
175175
self.description.hash(with: &hashFunction)
176176
}
177177
}
178+
179+
extension Array: CacheKey where Element == FilePath.Component {
180+
func hash(with hashFunction: inout some HashFunction) {
181+
String(reflecting: Self.self).hash(with: &hashFunction)
182+
map(\.string).joined(separator: "\n").hash(with: &hashFunction)
183+
}
184+
}
185+

Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Unpack.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import Helpers
14+
1415
import struct SystemPackage.FilePath
1516

1617
let unusedDarwinPlatforms = [
@@ -99,16 +100,21 @@ extension SwiftSDKGenerator {
99100
FilePath.Component(llvmArtifact.localPath.stem!)!.stem
100101
)
101102
try self.createDirectoryIfNeeded(at: untarDestination)
102-
try await self.untar(
103-
file: llvmArtifact.localPath,
104-
into: untarDestination,
105-
stripComponents: 1
106-
)
107103

108104
let unpackedLLDPath: FilePath
109105
if llvmArtifact.isPrebuilt {
110-
unpackedLLDPath = untarDestination.appending("bin/lld")
106+
unpackedLLDPath = try await engine[TarExtractQuery(
107+
file: llvmArtifact.localPath,
108+
into: untarDestination,
109+
outputBinarySubpath: ["bin", "lld"],
110+
stripComponents: 1
111+
)].path
111112
} else {
113+
try await self.untar(
114+
file: llvmArtifact.localPath,
115+
into: untarDestination,
116+
stripComponents: 1
117+
)
112118
unpackedLLDPath = try await engine[CMakeBuildQuery(
113119
sourcesDirectory: untarDestination,
114120
outputBinarySubpath: ["bin", "lld"],
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2022-202Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Helpers
14+
15+
import struct SystemPackage.FilePath
16+
17+
struct TarExtractQuery: CachingQuery {
18+
var file: FilePath // Archive to extract
19+
var into: FilePath // Destination for unpacked archive
20+
var outputBinarySubpath: [FilePath.Component]
21+
var stripComponents: Int? = nil
22+
23+
func run(engine: QueryEngine) async throws -> FilePath {
24+
let stripComponentsOption = stripComponents.map { " --strip-components \($0)" } ?? ""
25+
let archivePath = self.file
26+
let destinationPath = self.into
27+
28+
try await Shell.run(
29+
#"tar -C "\#(destinationPath)" -x -f "\#(archivePath)" \#(stripComponentsOption) \#(FilePath("*").appending(outputBinarySubpath))"#,
30+
logStdout: true
31+
)
32+
33+
// We must return a path to a single file which the cache will track
34+
return destinationPath.appending(outputBinarySubpath)
35+
}
36+
}

0 commit comments

Comments
 (0)