File: BuildSystem.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (213 lines) | stat: -rw-r--r-- 9,353 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import BuildServerProtocol
import LSPLogging
import LanguageServerProtocol

import struct TSCBasic.AbsolutePath

/// Defines how well a `BuildSystem` can handle a file with a given URI.
public enum FileHandlingCapability: Comparable, Sendable {
  /// The build system can't handle the file at all
  case unhandled

  /// The build system has fallback build settings for the file
  case fallback

  /// The build system knows how to handle the file
  case handled
}

public struct SourceFileInfo: Sendable {
  /// The URI of the source file.
  public let uri: DocumentURI

  /// `true` if this file belongs to the root project that the user is working on. It is false, if the file belongs
  /// to a dependency of the project.
  public let isPartOfRootProject: Bool

  /// Whether the file might contain test cases. This property is an over-approximation. It might be true for files
  /// from non-test targets or files that don't actually contain any tests. Keeping this list of files with
  /// `mayContainTets` minimal as possible helps reduce the amount of work that the syntactic test indexer needs to
  /// perform.
  public let mayContainTests: Bool

  public init(uri: DocumentURI, isPartOfRootProject: Bool, mayContainTests: Bool) {
    self.uri = uri
    self.isPartOfRootProject = isPartOfRootProject
    self.mayContainTests = mayContainTests
  }
}

/// A target / run destination combination. For example, a configured target can represent building the target
/// `MyLibrary` for iOS.
public struct ConfiguredTarget: Hashable, Sendable, CustomLogStringConvertible {
  /// An opaque string that represents the target.
  ///
  /// The target's ID should be generated by the build system that handles the target and only interpreted by that
  /// build system.
  public let targetID: String

  /// An opaque string that represents the run destination.
  ///
  /// The run destination's ID should be generated by the build system that handles the target and only interpreted by
  /// that build system.
  public let runDestinationID: String

  public init(targetID: String, runDestinationID: String) {
    self.targetID = targetID
    self.runDestinationID = runDestinationID
  }

  public var description: String {
    "\(targetID)-\(runDestinationID)"
  }

  public var redactedDescription: String {
    "\(targetID.hashForLogging)-\(runDestinationID.hashForLogging)"
  }
}

/// An error build systems can throw from `prepare` if they don't support preparation of targets.
public struct PrepareNotSupportedError: Error, CustomStringConvertible {
  public init() {}

  public var description: String { "Preparation not supported" }
}

/// Provider of FileBuildSettings and other build-related information.
///
/// The primary role of the build system is to answer queries for
/// FileBuildSettings and to notify its delegate when they change. The
/// BuildSystem is also the source of related information, such as where the
/// index datastore is located.
///
/// For example, a SwiftPMWorkspace provides compiler arguments for the files
/// contained in a SwiftPM package root directory.
public protocol BuildSystem: AnyObject, Sendable {
  /// The root of the project that this build system manages. For example, for SwiftPM packages, this is the folder
  /// containing Package.swift. For compilation databases it is the root folder based on which the compilation database
  /// was found.
  var projectRoot: AbsolutePath { get async }

  /// The path to the raw index store data, if any.
  var indexStorePath: AbsolutePath? { get async }

  /// The path to put the index database, if any.
  var indexDatabasePath: AbsolutePath? { get async }

  /// Path remappings for remapping index data for local use.
  var indexPrefixMappings: [PathPrefixMapping] { get async }

  /// Delegate to handle any build system events such as file build settings initial reports as well as changes.
  ///
  /// The build system must not retain the delegate because the delegate can be the `BuildSystemManager`, which could
  /// result in a retain cycle `BuildSystemManager` -> `BuildSystem` -> `BuildSystemManager`.
  var delegate: BuildSystemDelegate? { get async }

  /// Set the build system's delegate.
  ///
  /// - Note: Needed so we can set the delegate from a different actor isolation
  ///   context.
  func setDelegate(_ delegate: BuildSystemDelegate?) async

  /// Whether the build system is capable of preparing a target for indexing, ie. if the `prepare` methods has been
  /// implemented.
  var supportsPreparation: Bool { get }

  /// Retrieve build settings for the given document with the given source
  /// language.
  ///
  /// Returns `nil` if the build system can't provide build settings for this
  /// file or if it hasn't computed build settings for the file yet.
  func buildSettings(
    for document: DocumentURI,
    in target: ConfiguredTarget,
    language: Language
  ) async throws -> FileBuildSettings?

  /// Return the list of targets and run destinations that the given document can be built for.
  func configuredTargets(for document: DocumentURI) async -> [ConfiguredTarget]

  /// Re-generate the build graph.
  ///
  /// If `allowFileSystemWrites` is `true`, this should include all the tasks that are necessary for building the entire
  /// build graph, like resolving package versions.
  ///
  /// If `allowFileSystemWrites` is `false`, no files must be written to disk. This mode is used to determine whether
  /// the build system can handle a source file, and decide whether a workspace should be opened with this build system
  func generateBuildGraph(allowFileSystemWrites: Bool) async throws

  /// Sort the targets so that low-level targets occur before high-level targets.
  ///
  /// This sorting is best effort but allows the indexer to prepare and index low-level targets first, which allows
  /// index data to be available earlier.
  ///
  /// `nil` if the build system doesn't support topological sorting of targets.
  func topologicalSort(of targets: [ConfiguredTarget]) async -> [ConfiguredTarget]?

  /// Returns the list of targets that might depend on the given target and that need to be re-prepared when a file in
  /// `target` is modified.
  ///
  /// The returned list can be an over-approximation, in which case the indexer will perform more work than strictly
  /// necessary by scheduling re-preparation of a target where it isn't necessary.
  ///
  /// Returning `nil` indicates that all targets should be considered depending on the given target.
  func targets(dependingOn targets: [ConfiguredTarget]) async -> [ConfiguredTarget]?

  /// Prepare the given targets for indexing and semantic functionality. This should build all swift modules of target
  /// dependencies.
  func prepare(
    targets: [ConfiguredTarget],
    logMessageToIndexLog: @escaping @Sendable (_ taskID: IndexTaskID, _ message: String) -> Void
  ) async throws

  /// If the build system has knowledge about the language that this document should be compiled in, return it.
  ///
  /// This is used to determine the language in which a source file should be background indexed.
  ///
  /// If `nil` is returned, the language based on the file's extension.
  func defaultLanguage(for document: DocumentURI) async -> Language?

  /// The toolchain that should be used to open the given document.
  ///
  /// If `nil` is returned, then the default toolchain for the given language is used.
  func toolchain(for uri: DocumentURI, _ language: Language) async -> Toolchain?

  /// Register the given file for build-system level change notifications, such
  /// as command line flag changes, dependency changes, etc.
  ///
  /// IMPORTANT: When first receiving a register request, the `BuildSystem` MUST asynchronously
  /// inform its delegate of any initial settings for the given file via the
  /// `fileBuildSettingsChanged` method, even if unavailable.
  func registerForChangeNotifications(for: DocumentURI) async

  /// Unregister the given file for build-system level change notifications,
  /// such as command line flag changes, dependency changes, etc.
  func unregisterForChangeNotifications(for: DocumentURI) async

  /// Called when files in the project change.
  func filesDidChange(_ events: [FileEvent]) async

  func fileHandlingCapability(for uri: DocumentURI) async -> FileHandlingCapability

  /// Returns the list of source files in the project.
  ///
  /// Header files should not be considered as source files because they cannot be compiled.
  func sourceFiles() async -> [SourceFileInfo]

  /// Adds a callback that should be called when the value returned by `sourceFiles()` changes.
  ///
  /// The callback might also be called without an actual change to `sourceFiles`.
  func addSourceFilesDidChangeCallback(_ callback: @Sendable @escaping () async -> Void) async
}