Skip to content

Commit 5789a5c

Browse files
committed
Migrate build script to Swift
1 parent cecb034 commit 5789a5c

File tree

73 files changed

+615
-33
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+615
-33
lines changed

CodeGeneration/Package.swift renamed to SwiftSyntaxCLI/Package.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
// swift-tools-version:5.7
1+
// swift-tools-version:5.8
22

33
import PackageDescription
44
import Foundation
55

66
let package = Package(
7-
name: "CodeGeneration",
7+
name: "SwiftSyntaxCLI",
88
platforms: [
99
.macOS(.v10_15)
1010
],
1111
products: [
12-
.executable(name: "generate-swiftsyntax", targets: ["generate-swiftsyntax"])
12+
.executable(name: "swift-syntax-cli", targets: ["swift-syntax-cli"])
1313
],
1414
dependencies: [
15-
.package(url: "..", revision: "HEAD")
15+
.package(path: "..")
1616
],
1717
targets: [
1818
.executableTarget(
19-
name: "generate-swiftsyntax",
19+
name: "swift-syntax-cli",
2020
dependencies: [
2121
.product(name: "SwiftSyntax", package: "swift-syntax"),
2222
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
@@ -45,7 +45,7 @@ let package = Package(
4545
if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
4646
// Building standalone.
4747
package.dependencies += [
48-
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.2")
48+
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.2"))
4949
]
5050
} else {
5151
package.dependencies += [
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
# Code-Generation for SwiftSyntax
1+
# SwiftSyntaxCLI
2+
3+
## Code-Generation for SwiftSyntax
24

35
This directory contains file to generate source code that is part of the SwiftSyntax package. If you are looking to generate Swift code yourself, you might be interested in [SwiftSyntaxBuilder](../Sources/SwiftSyntaxBuilder).
46

57
Some source code inside SwiftSyntax is generated using [SwiftSyntaxBuilder](../Sources/SwiftSyntaxBuilder), a Swift library whose purpose is to generate Swift code using Swift itself. This kind of code generation is performed by the Swift package defined in this directory.
68

7-
This directory is a standalone package that uses HEAD of the current branch. This guarantees that when `generate-swiftsyntax` is run, it can't break its own build when run multiple times without committing.
8-
This means that `CodeGeneration` will build against your latest local commit of SwiftSyntax. If you are making changes to `SwiftSyntax` that affect how code is being generated, commit your SwiftSyntax changes (pushing is not necessary) and re-generate files afterwards.
9+
This directory is a standalone package that uses HEAD of the current branch. This guarantees that when `generate-source-code` is run, it can't break its own build when run multiple times without committing.
10+
This means that `SwiftSyntaxCLI` will build against your latest local commit of SwiftSyntax. If you are making changes to `SwiftSyntax` that affect how code is being generated, commit your SwiftSyntax changes (pushing is not necessary) and re-generate files afterwards.
911

10-
To re-generate the files after changing `CodeGeneration` run the `generate-swiftsyntax`
11-
target of `CodeGeneration` and pass `path/to/swift-syntax/Sources` as the argument.
12+
To re-generate the files after changing `SwiftSyntaxCLI` run the `generate-source-code`
13+
target of `SwiftSyntaxCLI` and pass `path/to/swift-syntax/Sources` as the argument.
1214

1315
On the command line, this would be
1416
```bash
15-
swift run --package-path CodeGeneration generate-swiftsyntax Sources
17+
swift run --package-path SwiftSyntaxCLI generate-source-code Sources
1618
```
1719

18-
Or if you open the `CodeGeneration` package in Xcode, you can add the
19-
`generate-swift syntax ../Sources` arguments using Product -> Scheme -> Edit Scheme…
20-
20+
Or if you open the `SwiftSyntaxCLI` package in Xcode, you can add the
21+
`generate-source-code ../Sources` arguments using Product -> Scheme -> Edit Scheme…
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple 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 ArgumentParser
14+
15+
@main
16+
struct SwiftSyntaxCLI: ParsableCommand {
17+
18+
static var configuration: CommandConfiguration = CommandConfiguration(
19+
abstract: """
20+
Build and test script for SwiftSyntax.
21+
22+
The build script can also drive the test suite included in the SwiftSyntax
23+
repo. This requires a custom build of the compiler project since it accesses
24+
test utilities that are not shipped as part of the toolchains. See the Testing
25+
section for arguments that need to be specified for this.
26+
""",
27+
subcommands: [
28+
Build.self,
29+
GenerateSourceCode.self,
30+
Test.self,
31+
VerifySourceCode.self,
32+
]
33+
)
34+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple 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 ArgumentParser
14+
import Foundation
15+
16+
struct Build: ParsableCommand, Builder {
17+
@OptionGroup
18+
var arguments: BuilderArguments
19+
20+
func run() throws {
21+
// Until rdar://53881101 is implemented, we cannot request a build of multiple
22+
// targets simultaneously. For now, just build one product after the other.
23+
try buildProduct(productName: "SwiftSyntax")
24+
try buildProduct(productName: "SwiftSyntaxBuilder")
25+
26+
// Build examples
27+
try buildExample(exampleName: "AddOneToIntegerLiterals")
28+
try buildExample(exampleName: "CodeGenerationUsingSwiftSyntaxBuilder")
29+
}
30+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple 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 ArgumentParser
14+
import Foundation
15+
16+
struct GenerateSourceCode: ParsableCommand, Generator {
17+
@OptionGroup
18+
var arguments: GeneratorArguments
19+
20+
func run() throws {
21+
try self.runCodeGeneration(sourceDir: Paths.sourcesDir)
22+
}
23+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple 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 ArgumentParser
14+
import Foundation
15+
16+
struct Test: ParsableCommand, Builder {
17+
@OptionGroup
18+
var arguments: BuilderArguments
19+
20+
@Flag(help: "Don't run lit-based tests")
21+
var skipLitTests: Bool = false
22+
23+
@Argument(
24+
help: """
25+
Path to the FileCheck executable that was built as part of the LLVM repository.
26+
If not specified, it will be looked up from PATH.
27+
"""
28+
)
29+
var filecheckExec: String?
30+
31+
func run() throws {
32+
try buildProduct(productName: "lit-test-helper")
33+
try buildExample(exampleName: "ExamplePlugin")
34+
35+
try runTests()
36+
37+
print("** All tests passed **")
38+
}
39+
40+
private func runTests() throws {
41+
print("** Running SwiftSyntax Tests **")
42+
43+
if !skipLitTests {
44+
try runLitTests()
45+
}
46+
47+
try runXctests()
48+
}
49+
50+
private func runLitTests() throws {
51+
print("** Running lit-based tests **")
52+
53+
guard FileManager.default.fileExists(atPath: Paths.litExec.relativePath) else {
54+
fatalError(
55+
"""
56+
Error: Could not find lit.py.
57+
Looking at '\(Paths.litExec.relativePath)'.
58+
59+
Make sure you have the llvm repo checked out next to the swift-syntax repo.
60+
Refer to README.md for more information.
61+
"""
62+
)
63+
}
64+
65+
guard FileManager.default.fileExists(atPath: Paths.incrTransferRoundtripExec.relativePath) else {
66+
fatalError(
67+
"""
68+
Error: Could not find incr_transfer_round_trip.py.
69+
70+
Make sure you have the main swift repo checked out next to the swift-syntax
71+
repo.
72+
Refer to README.md for more information.
73+
"""
74+
)
75+
}
76+
77+
let productBinPath = try findProductBinPath()
78+
let examplesBinPath = try findExamplesBinPath()
79+
80+
let litTestHelperExec = productBinPath + "/lit-test-helper"
81+
var litCall = [
82+
Paths.litExec.relativePath,
83+
Paths.packageDir.relativePath,
84+
"lit_tests",
85+
]
86+
87+
if let filecheckExec {
88+
litCall += ["--param", "FILECHECK=" + filecheckExec]
89+
}
90+
91+
litCall += ["--param", "LIT_TEST_HELPER=" + litTestHelperExec]
92+
litCall += ["--param", "INCR_TRANSFER_ROUND_TRIP.PY=" + Paths.incrTransferRoundtripExec.relativePath]
93+
94+
litCall += ["--param", "EXAMPLES_BIN_PATH=" + examplesBinPath]
95+
litCall += ["--param", "TOOLCHAIN=" + arguments.toolchain]
96+
97+
// Print all failures
98+
litCall += ["--verbose"]
99+
// Don't show all commands if verbose is not enabled
100+
if !arguments.verbose {
101+
litCall += ["--succinct"]
102+
}
103+
104+
try runPython(arguments: litCall)
105+
}
106+
107+
private func runXctests() throws {
108+
print("** Running XCTests **")
109+
var swiftpmCallArguments: [String] = []
110+
111+
if arguments.verbose {
112+
swiftpmCallArguments += ["--verbose"]
113+
}
114+
115+
swiftpmCallArguments += ["--test-product", "SwiftSyntaxPackageTests"]
116+
117+
var env = ProcessInfo.processInfo.environment
118+
env["SWIFT_BUILD_SCRIPT_ENVIRONMENT"] = "1"
119+
120+
if arguments.enableRawsyntaxValidation {
121+
env["SWIFTSYNTAX_ENABLE_RAWSYNTAX_VALIDATION"] = "1"
122+
}
123+
124+
if arguments.enableTestFuzzing {
125+
env["SWIFTPARSER_ENABLE_ALTERNATE_TOKEN_INTROSPECTION"] = "1"
126+
}
127+
128+
// Tell other projects in the unified build to use local dependencies
129+
env["SWIFTCI_USE_LOCAL_DEPS"] = "1"
130+
env["SWIFT_SYNTAX_PARSER_LIB_SEARCH_PATH"] =
131+
URL(fileURLWithPath: arguments.toolchain)
132+
.appendingPathComponent("lib")
133+
.appendingPathComponent("swift")
134+
.appendingPathComponent("macosx")
135+
.relativePath
136+
137+
try swiftpmInvocation(
138+
action: "test",
139+
packageDir: Paths.packageDir,
140+
additionalArguments: swiftpmCallArguments,
141+
env: env
142+
)
143+
}
144+
145+
private func findSwiftpmBinPath(packageDir: URL) throws -> String {
146+
return try swiftpmInvocation(
147+
action: "build",
148+
packageDir: packageDir,
149+
additionalArguments: ["--show-bin-path"],
150+
env: [:]
151+
)
152+
}
153+
154+
private func findProductBinPath() throws -> String {
155+
return try findSwiftpmBinPath(packageDir: Paths.packageDir)
156+
}
157+
158+
private func findExamplesBinPath() throws -> String {
159+
return try findSwiftpmBinPath(packageDir: Paths.examplesDir)
160+
}
161+
162+
private func runPython(arguments: [String]) throws {
163+
let process = Process()
164+
process.executableURL = URL(fileURLWithPath: "/usr/bin/python3")
165+
process.arguments = arguments
166+
try process.run()
167+
process.waitUntilExit()
168+
}
169+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple 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 ArgumentParser
14+
import Foundation
15+
16+
struct VerifySourceCode: ParsableCommand, Generator {
17+
@OptionGroup
18+
var arguments: GeneratorArguments
19+
20+
func run() throws {
21+
let tempDir = FileManager.default.temporaryDirectory
22+
23+
try self.runCodeGeneration(sourceDir: tempDir)
24+
25+
print("** Verifing code generated files **")
26+
27+
for module in Paths.modules {
28+
let selfGeneratedDir = tempDir.appendingPathComponent(module).appendingPathComponent("generated")
29+
let userGeneratedDir = Paths.sourcesDir.appendingPathComponent(module).appendingPathComponent("generated")
30+
try checkGeneratedFilesMatch(selfGeneratedDir: selfGeneratedDir, userGeneratedDir: userGeneratedDir)
31+
}
32+
}
33+
34+
private func checkGeneratedFilesMatch(
35+
selfGeneratedDir: URL,
36+
userGeneratedDir: URL
37+
) throws {
38+
39+
let selfGeneratedFiles = try FileManager.default.contentsOfDirectory(at: selfGeneratedDir, includingPropertiesForKeys: nil)
40+
let userGeneratedFiles = try FileManager.default.contentsOfDirectory(at: userGeneratedDir, includingPropertiesForKeys: nil)
41+
42+
zip(selfGeneratedFiles, userGeneratedFiles)
43+
.forEach {
44+
if arguments.verbose {
45+
print("Comparing \($0.relativePath) with \($1.relativePath) ...")
46+
}
47+
48+
if !FileManager.default.contentsEqual(atPath: $0.relativePath, andPath: $1.relativePath) {
49+
fatalError(
50+
"""
51+
FAIL: code-generated files committed to repository do
52+
not match generated ones. Please re-generate the
53+
code-generated-files using the following command, open a PR to the
54+
SwiftSyntax project and merge it alongside the main PR.
55+
$ swift-syntax/build-script.py generate-source-code
56+
--toolchain /path/to/toolchain.xctoolchain/usr
57+
"""
58+
)
59+
}
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)