@@ -16,6 +16,8 @@ import LanguageServerProtocol
1616import SourceKitLSP
1717import TSCBasic
1818
19+ private struct SwiftSyntaxCShimsModulemapNotFoundError : Error { }
20+
1921public class SwiftPMTestProject : MultiFileTestProject {
2022 enum Error : Swift . Error {
2123 /// The `swift` executable could not be found.
@@ -33,6 +35,114 @@ public class SwiftPMTestProject: MultiFileTestProject {
3335 )
3436 """
3537
38+ /// A manifest that defines two targets:
39+ /// - A macro target named `MyMacro`
40+ /// - And executable target named `MyMacroClient`
41+ ///
42+ /// It builds the macro using the swift-syntax that was already built as part of the SourceKit-LSP build.
43+ /// Re-using the SwiftSyntax modules that are already built is significantly faster than building swift-syntax in
44+ /// each test case run and does not require internet access.
45+ public static var macroPackageManifest : String {
46+ get async throws {
47+ // Directories that we should search for the swift-syntax package.
48+ // We prefer a checkout in the build folder. If that doesn't exist, we are probably using local dependencies
49+ // (SWIFTCI_USE_LOCAL_DEPS), so search next to the sourcekit-lsp source repo
50+ let swiftSyntaxSearchPaths = [
51+ productsDirectory
52+ . deletingLastPathComponent ( ) // arm64-apple-macosx
53+ . deletingLastPathComponent ( ) // debug
54+ . appendingPathComponent ( " checkouts " ) ,
55+ URL ( fileURLWithPath: #filePath)
56+ . deletingLastPathComponent ( ) // SwiftPMTestProject.swift
57+ . deletingLastPathComponent ( ) // SKTestSupport
58+ . deletingLastPathComponent ( ) // Sources
59+ . deletingLastPathComponent ( ) , // sourcekit-lsp
60+ ]
61+
62+ let swiftSyntaxCShimsModulemap =
63+ swiftSyntaxSearchPaths. map { swiftSyntaxSearchPath in
64+ swiftSyntaxSearchPath
65+ . appendingPathComponent ( " swift-syntax " )
66+ . appendingPathComponent ( " Sources " )
67+ . appendingPathComponent ( " _SwiftSyntaxCShims " )
68+ . appendingPathComponent ( " include " )
69+ . appendingPathComponent ( " module.modulemap " )
70+ }
71+ . first { FileManager . default. fileExists ( atPath: $0. path) }
72+
73+ guard let swiftSyntaxCShimsModulemap else {
74+ throw SwiftSyntaxCShimsModulemapNotFoundError ( )
75+ }
76+
77+ let swiftSyntaxModulesToLink = [
78+ " SwiftBasicFormat " ,
79+ " SwiftCompilerPlugin " ,
80+ " SwiftCompilerPluginMessageHandling " ,
81+ " SwiftDiagnostics " ,
82+ " SwiftOperators " ,
83+ " SwiftParser " ,
84+ " SwiftParserDiagnostics " ,
85+ " SwiftSyntax " ,
86+ " SwiftSyntaxBuilder " ,
87+ " SwiftSyntaxMacroExpansion " ,
88+ " SwiftSyntaxMacros " ,
89+ ]
90+
91+ var objectFiles : [ String ] = [ ]
92+ for moduleName in swiftSyntaxModulesToLink {
93+ let dir = productsDirectory. appendingPathComponent ( " \( moduleName) .build " )
94+ let enumerator = FileManager . default. enumerator ( at: dir, includingPropertiesForKeys: nil )
95+ while let file = enumerator? . nextObject ( ) as? URL {
96+ if file. pathExtension == " o " {
97+ objectFiles. append ( file. path)
98+ }
99+ }
100+ }
101+
102+ let linkerFlags = objectFiles. map {
103+ """
104+ " -l " , " \( $0) " ,
105+ """
106+ } . joined ( separator: " \n " )
107+
108+ let moduleSearchPath : String
109+ if let toolchainVersion = try await ToolchainRegistry . forTesting. default? . swiftVersion,
110+ toolchainVersion < SwiftVersion ( 6 , 0 )
111+ {
112+ moduleSearchPath = productsDirectory. path
113+ } else {
114+ moduleSearchPath = " \( productsDirectory. path) /Modules "
115+ }
116+
117+ return """
118+ // swift-tools-version: 5.10
119+
120+ import PackageDescription
121+ import CompilerPluginSupport
122+
123+ let package = Package(
124+ name: " MyMacro " ,
125+ platforms: [.macOS(.v10_15)],
126+ targets: [
127+ .macro(
128+ name: " MyMacros " ,
129+ swiftSettings: [.unsafeFlags([
130+ " -I " , " \( moduleSearchPath) " ,
131+ " -Xcc " , " -fmodule-map-file= \( swiftSyntaxCShimsModulemap. path) "
132+ ])],
133+ linkerSettings: [
134+ .unsafeFlags([
135+ \( linkerFlags)
136+ ])
137+ ]
138+ ),
139+ .executableTarget(name: " MyMacroClient " , dependencies: [ " MyMacros " ]),
140+ ]
141+ )
142+ """
143+ }
144+ }
145+
36146 /// Create a new SwiftPM package with the given files.
37147 ///
38148 /// If `index` is `true`, then the package will be built, indexing all modules within the package.
0 commit comments