diff --git a/Package.resolved b/Package.resolved index 5fd667d0f..39195a5e5 100644 --- a/Package.resolved +++ b/Package.resolved @@ -11,7 +11,7 @@ } }, { - "package": "swift-llbuild", + "package": "llbuild", "repositoryURL": "https://github.com/apple/swift-llbuild.git", "state": { "branch": "main", diff --git a/Sources/SwiftDriver/CMakeLists.txt b/Sources/SwiftDriver/CMakeLists.txt index 72cf9f2d1..2888f3b14 100644 --- a/Sources/SwiftDriver/CMakeLists.txt +++ b/Sources/SwiftDriver/CMakeLists.txt @@ -1,6 +1,6 @@ # This source file is part of the Swift.org open source project # -# Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +# Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors # Licensed under Apache License v2.0 with Runtime Library Exception # # See http://swift.org/LICENSE.txt for license information @@ -57,6 +57,7 @@ add_library(SwiftDriver Jobs/APIDigesterJobs.swift Jobs/AutolinkExtractJob.swift Jobs/BackendJob.swift + Jobs/CheckScriptJob.swift Jobs/CommandLineArguments.swift Jobs/CompileJob.swift Jobs/DarwinToolchain+LinkerSupport.swift @@ -75,6 +76,7 @@ add_library(SwiftDriver Jobs/Planning.swift Jobs/PrintTargetInfoJob.swift Jobs/ReplJob.swift + Jobs/RunScriptJob.swift Jobs/Toolchain+InterpreterSupport.swift Jobs/Toolchain+LinkerSupport.swift Jobs/VerifyDebugInfoJob.swift diff --git a/Sources/SwiftDriver/Jobs/CheckScriptJob.swift b/Sources/SwiftDriver/Jobs/CheckScriptJob.swift new file mode 100644 index 000000000..5189499eb --- /dev/null +++ b/Sources/SwiftDriver/Jobs/CheckScriptJob.swift @@ -0,0 +1,55 @@ +//===-------- CheckScriptJob.swift - Swift Script Prechecking Job --------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021 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 TSCBasic + +public enum ScriptingError: Error, DiagnosticData { + case tooManyInputFiles + case noSwiftScript + + public var description: String { + switch self { + case .tooManyInputFiles: + return "Scripting mode expect exactly 1 input file" + + case .noSwiftScript: + return "'swift-script' tool not found" + } + } +} + +extension Driver { + /// Check if the script requires scripting mode. + func checkScriptJob(inputs: [TypedVirtualPath]) throws -> Job { + var commandLine: [Job.ArgTemplate] = [] + commandLine.appendFlags("-frontend", "-print-package-declarations") + + // Check and add the input file. + guard inputs.count == 1 else { + throw ScriptingError.tooManyInputFiles + } + for input in inputs { + commandLine.append(.path(input.file)) + } + + return Job( + moduleName: moduleOutputInfo.name, + kind: .checkScript, + tool: .absolute(try toolchain.getToolPath(.swiftCompiler)), + commandLine: commandLine, + inputs: inputs, + primaryInputs: [], + outputs: [], + requiresInPlaceExecution: false, + supportsResponseFiles: true + ) + } +} diff --git a/Sources/SwiftDriver/Jobs/Job.swift b/Sources/SwiftDriver/Jobs/Job.swift index c180041ef..69d37c1ba 100644 --- a/Sources/SwiftDriver/Jobs/Job.swift +++ b/Sources/SwiftDriver/Jobs/Job.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2021 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 @@ -41,6 +41,9 @@ public struct Job: Codable, Equatable, Hashable { case generateABIBaseline = "generate-abi-baseline" case compareAPIBaseline = "compare-api-baseline" case compareABIBaseline = "compare-abi-baseline" + + case checkScript = "check-script" + case runScript = "run-script" } public enum ArgTemplate: Equatable, Hashable { @@ -166,52 +169,52 @@ extension Job : CustomStringConvertible { public var description: String { switch kind { case .compile: - return "Compiling \(moduleName) \(displayInputs.first?.file.basename ?? "")" + return "Compiling \(moduleName) \(displayInputs.first?.file.basename ?? "")" case .mergeModule: - return "Merging module \(moduleName)" + return "Merging module \(moduleName)" case .link: - return "Linking \(moduleName)" + return "Linking \(moduleName)" case .generateDSYM: - return "Generating dSYM for module \(moduleName)" + return "Generating dSYM for module \(moduleName)" case .autolinkExtract: - return "Extracting autolink information for module \(moduleName)" + return "Extracting autolink information for module \(moduleName)" case .emitModule: - return "Emitting module for \(moduleName)" + return "Emitting module for \(moduleName)" case .generatePCH: - return "Compiling bridging header \(displayInputs.first?.file.basename ?? "")" + return "Compiling bridging header \(displayInputs.first?.file.basename ?? "")" case .moduleWrap: return "Wrapping Swift module \(moduleName)" case .generatePCM: - return "Compiling Clang module \(moduleName)" + return "Compiling Clang module \(moduleName)" case .dumpPCM: - return "Dump information about Clang module \(displayInputs.first?.file.name ?? "")" + return "Dump information about Clang module \(displayInputs.first?.file.name ?? "")" case .interpret: - return "Interpreting \(displayInputs.first?.file.name ?? "")" + return "Interpreting \(displayInputs.first?.file.name ?? "")" case .repl: - return "Executing Swift REPL" + return "Executing Swift REPL" case .verifyDebugInfo: - return "Verifying debug information for module \(moduleName)" + return "Verifying debug information for module \(moduleName)" case .printTargetInfo: - return "Gathering target information for module \(moduleName)" + return "Gathering target information for module \(moduleName)" case .versionRequest: - return "Getting Swift version information" + return "Getting Swift version information" case .help: - return "Swift help" + return "Swift help" case .backend: return "Embedding bitcode for \(moduleName) \(displayInputs.first?.file.basename ?? "")" @@ -236,6 +239,12 @@ extension Job : CustomStringConvertible { case .compareABIBaseline: return "Comparing ABI of \(moduleName) to baseline" + + case .checkScript: + return "Checking if \(displayInputs.first?.file.basename ?? "") requires scripting mode" + + case .runScript: + return "Running a script with SwiftPM" } } @@ -254,13 +263,14 @@ extension Job.Kind { public var isSwiftFrontend: Bool { switch self { case .backend, .compile, .mergeModule, .emitModule, .generatePCH, - .generatePCM, .dumpPCM, .interpret, .repl, .printTargetInfo, - .versionRequest, .emitSupportedFeatures, .scanDependencies, .verifyModuleInterface: - return true + .generatePCM, .dumpPCM, .interpret, .repl, .printTargetInfo, .checkScript, + .versionRequest, .emitSupportedFeatures, .scanDependencies, .verifyModuleInterface: + return true case .autolinkExtract, .generateDSYM, .help, .link, .verifyDebugInfo, .moduleWrap, - .generateAPIBaseline, .generateABIBaseline, .compareAPIBaseline, .compareABIBaseline: - return false + .generateAPIBaseline, .generateABIBaseline, .compareAPIBaseline, .compareABIBaseline, + .runScript: + return false } } @@ -275,7 +285,7 @@ extension Job.Kind { .help, .link, .verifyDebugInfo, .scanDependencies, .emitSupportedFeatures, .moduleWrap, .verifyModuleInterface, .generateAPIBaseline, .generateABIBaseline, .compareAPIBaseline, - .compareABIBaseline: + .compareABIBaseline, .checkScript, .runScript: return false } } diff --git a/Sources/SwiftDriver/Jobs/Planning.swift b/Sources/SwiftDriver/Jobs/Planning.swift index a2499e72f..f9adf939a 100644 --- a/Sources/SwiftDriver/Jobs/Planning.swift +++ b/Sources/SwiftDriver/Jobs/Planning.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2021 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 @@ -687,7 +687,17 @@ extension Driver { case .immediate: var jobs: [Job] = [] try addPrecompileModuleDependenciesJobs(addJob: { jobs.append($0) }) - jobs.append(try interpretJob(inputs: inputFiles)) + // Check if the script requires scripting mode. + let result = try executor.execute(job: checkScriptJob(inputs: inputFiles), + forceResponseFiles: true, + recordedInputModificationDates: recordedInputModificationDates) + // Only use scripting mode when package dependencies are known. + if result.exitStatus == .terminated(code: 0), + try !result.utf8Output().hasPrefix("[]") { + jobs.append(try runScriptJob(inputs: inputFiles)) + } else { + jobs.append(try interpretJob(inputs: inputFiles)) + } return (jobs, nil) case .standardCompile, .batchCompile, .singleCompile: diff --git a/Sources/SwiftDriver/Jobs/RunScriptJob.swift b/Sources/SwiftDriver/Jobs/RunScriptJob.swift new file mode 100644 index 000000000..d1eac5f8b --- /dev/null +++ b/Sources/SwiftDriver/Jobs/RunScriptJob.swift @@ -0,0 +1,68 @@ +//===--------------- RunScriptJob.swift - Swift Scripting Mode ------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021 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 TSCBasic + +extension Driver { + /// Run a script with the `swift-script` tool. + mutating func runScriptJob(inputs allInputs: [TypedVirtualPath]) throws -> Job { + // Find and use `swift-script run`. + let swiftScriptTool = try toolchain.getToolPath(.swiftCompiler).parentDirectory.appending(component: "swift-script") + guard fileSystem.isExecutableFile(swiftScriptTool) else { + throw ScriptingError.noSwiftScript + } + var commandLine: [Job.ArgTemplate] = [.flag("run")] + + // Add the inputs. + var inputs: [TypedVirtualPath] = [] + for input in allInputs { + commandLine.append(.path(input.file)) + inputs.append(input) + } + + // Add frontend arguments. + var frontendArgs: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) } + try frontendArgs.appendAll(.l, .framework, from: &parsedOptions) + frontendArgs.forEach { + commandLine.appendFlag("-Xfrontend") + commandLine.append($0) + } + + // Appending extra arguments + // FIXME: Is there a more elegant solution? + try commandLine.appendLast(.DASHDASH, from: &parsedOptions) + if let idx = commandLine.firstIndex(of: .flag("--")) { + commandLine.remove(at: idx) + } + + // Explicitly handle -v flag + // FIXME: Is there a more elegant solution? + if let idx = commandLine.firstIndex(of: .flag("-v")) { + commandLine.remove(at: idx) + stderrStream <<< "\(swiftScriptTool.pathString) \(commandLine.joinedUnresolvedArguments)\n" + stderrStream.flush() + } else { + commandLine.insert(.flag("--quiet"), at: 1) + } + + return Job( + moduleName: moduleOutputInfo.name, + kind: .runScript, + tool: .absolute(swiftScriptTool), + commandLine: commandLine, + inputs: inputs, + primaryInputs: [], + outputs: [], + requiresInPlaceExecution: true, + supportsResponseFiles: true + ) + } +}