@@ -24,21 +24,24 @@ struct CMakeSmokeTest: CommandPlugin {
24
24
}
25
25
26
26
guard let cmakePath = args. extractOption ( named: " cmake-path " ) . last else { throw Errors . missingRequiredOption ( " --cmake-path " ) }
27
- print ( " using cmake at \( cmakePath) " )
27
+ Diagnostics . progress ( " using cmake at \( cmakePath) " )
28
28
let cmakeURL = URL ( filePath: cmakePath)
29
29
guard let ninjaPath = args. extractOption ( named: " ninja-path " ) . last else { throw Errors . missingRequiredOption ( " --ninja-path " ) }
30
- print ( " using ninja at \( ninjaPath) " )
30
+ Diagnostics . progress ( " using ninja at \( ninjaPath) " )
31
31
let ninjaURL = URL ( filePath: ninjaPath)
32
32
let sysrootPath = args. extractOption ( named: " sysroot-path " ) . last
33
33
if let sysrootPath {
34
- print ( " using sysroot at \( sysrootPath) " )
34
+ Diagnostics . progress ( " using sysroot at \( sysrootPath) " )
35
35
}
36
36
37
+ let extraCMakeArgs = args. extractOption ( named: " extra-cmake-arg " )
38
+ Diagnostics . progress ( " Extra cmake args: \( extraCMakeArgs. joined ( separator: " " ) ) " )
39
+
37
40
let moduleCachePath = context. pluginWorkDirectoryURL. appending ( component: " module-cache " ) . path ( )
38
41
39
42
let swiftBuildURL = context. package . directoryURL
40
43
let swiftBuildBuildURL = context. pluginWorkDirectoryURL. appending ( component: " swift-build " )
41
- print ( " swift-build: \( swiftBuildURL. path ( ) ) " )
44
+ Diagnostics . progress ( " swift-build: \( swiftBuildURL. path ( ) ) " )
42
45
43
46
let swiftToolsSupportCoreURL = try findDependency ( " swift-tools-support-core " , pluginContext: context)
44
47
let swiftToolsSupportCoreBuildURL = context. pluginWorkDirectoryURL. appending ( component: " swift-tools-support-core " )
@@ -80,39 +83,39 @@ struct CMakeSmokeTest: CommandPlugin {
80
83
" -DCMAKE_MAKE_PROGRAM= \( ninjaPath) " ,
81
84
" -DCMAKE_BUILD_TYPE:=Debug " ,
82
85
" -DCMAKE_Swift_FLAGS=' \( sharedSwiftFlags. joined ( separator: " " ) ) ' "
83
- ] + cMakeProjectArgs
86
+ ] + cMakeProjectArgs + extraCMakeArgs
84
87
85
- print ( " Building swift-tools-support-core " )
88
+ Diagnostics . progress ( " Building swift-tools-support-core " )
86
89
try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftToolsSupportCoreURL. path ( ) ] , workingDirectory: swiftToolsSupportCoreBuildURL)
87
90
try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftToolsSupportCoreBuildURL)
88
- print ( " Built swift-tools-support-core " )
91
+ Diagnostics . progress ( " Built swift-tools-support-core " )
89
92
90
93
if hostOS != . macOS {
91
- print ( " Building swift-system " )
94
+ Diagnostics . progress ( " Building swift-system " )
92
95
try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftSystemURL. path ( ) ] , workingDirectory: swiftSystemBuildURL)
93
96
try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftSystemBuildURL)
94
- print ( " Built swift-system " )
97
+ Diagnostics . progress ( " Built swift-system " )
95
98
}
96
99
97
- print ( " Building llbuild " )
100
+ Diagnostics . progress ( " Building llbuild " )
98
101
try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ " -DLLBUILD_SUPPORT_BINDINGS:=Swift " , llbuildURL. path ( ) ] , workingDirectory: llbuildBuildURL)
99
102
try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: llbuildBuildURL)
100
- print ( " Built llbuild " )
103
+ Diagnostics . progress ( " Built llbuild " )
101
104
102
- print ( " Building swift-argument-parser " )
105
+ Diagnostics . progress ( " Building swift-argument-parser " )
103
106
try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ " -DBUILD_TESTING=NO " , " -DBUILD_EXAMPLES=NO " , swiftArgumentParserURL. path ( ) ] , workingDirectory: swiftArgumentParserBuildURL)
104
107
try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftArgumentParserBuildURL)
105
- print ( " Built swift-argument-parser " )
108
+ Diagnostics . progress ( " Built swift-argument-parser " )
106
109
107
- print ( " Building swift-driver " )
110
+ Diagnostics . progress ( " Building swift-driver " )
108
111
try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftDriverURL. path ( ) ] , workingDirectory: swiftDriverBuildURL)
109
112
try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftDriverBuildURL)
110
- print ( " Built swift-driver " )
113
+ Diagnostics . progress ( " Built swift-driver " )
111
114
112
- print ( " Building swift-build in \( swiftBuildBuildURL) " )
115
+ Diagnostics . progress ( " Building swift-build in \( swiftBuildBuildURL) " )
113
116
try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftBuildURL. path ( ) ] , workingDirectory: swiftBuildBuildURL)
114
117
try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftBuildBuildURL)
115
- print ( " Built swift-build " )
118
+ Diagnostics . progress ( " Built swift-build " )
116
119
}
117
120
118
121
func findDependency( _ name: String , pluginContext: PluginContext ) throws -> URL {
@@ -132,7 +135,7 @@ struct CMakeSmokeTest: CommandPlugin {
132
135
throw Errors . missingRepository ( name)
133
136
}
134
137
let dependencyURL = dependency. directoryURL
135
- print ( " \( name) : \( dependencyURL. path ( ) ) " )
138
+ Diagnostics . progress ( " \( name) : \( dependencyURL. path ( ) ) " )
136
139
guard FileManager . default. fileExists ( atPath: dependencyURL. path ( ) ) else {
137
140
throw Errors . missingRepository ( dependencyURL. path ( ) )
138
141
}
@@ -145,6 +148,7 @@ enum Errors: Error {
145
148
case missingRequiredOption( String )
146
149
case missingRepository( String )
147
150
case unimplementedForHostOS
151
+ case miscError( String )
148
152
}
149
153
150
154
enum OS {
@@ -182,7 +186,52 @@ extension Process {
182
186
}
183
187
184
188
static func checkNonZeroExit( url: URL , arguments: [ String ] , workingDirectory: URL , environment: [ String : String ] ? = nil ) async throws {
185
- print ( " \( url. path ( ) ) \( arguments. joined ( separator: " " ) ) " )
189
+ Diagnostics . progress ( " \( url. path ( ) ) \( arguments. joined ( separator: " " ) ) " )
190
+ #if os(Linux)
191
+ // Linux workaround for https://github.com/swiftlang/swift-corelibs-foundation/issues/4772
192
+ // Foundation.Process on Linux seems to inherit the Process.run()-calling thread's signal mask, creating processes that even have SIGTERM blocked
193
+ // This manifests as CMake hanging when invoking 'uname' with incorrectly configured signal handlers.
194
+ var fileActions = posix_spawn_file_actions_t ( )
195
+ defer { posix_spawn_file_actions_destroy ( & fileActions) }
196
+ var attrs : posix_spawnattr_t = posix_spawnattr_t ( )
197
+ defer { posix_spawnattr_destroy ( & attrs) }
198
+ posix_spawn_file_actions_init ( & fileActions)
199
+ posix_spawn_file_actions_addchdir_np ( & fileActions, workingDirectory. path ( ) )
200
+
201
+ posix_spawnattr_init ( & attrs)
202
+ posix_spawnattr_setpgroup ( & attrs, 0 )
203
+ var noSignals = sigset_t ( )
204
+ sigemptyset ( & noSignals)
205
+ posix_spawnattr_setsigmask ( & attrs, & noSignals)
206
+
207
+ var mostSignals = sigset_t ( )
208
+ sigemptyset ( & mostSignals)
209
+ for i in 1 ..< SIGSYS {
210
+ if i == SIGKILL || i == SIGSTOP {
211
+ continue
212
+ }
213
+ sigaddset ( & mostSignals, i)
214
+ }
215
+ posix_spawnattr_setsigdefault ( & attrs, & mostSignals)
216
+ posix_spawnattr_setflags ( & attrs, numericCast ( POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK) )
217
+ var pid : pid_t = - 1
218
+ try withArrayOfCStrings ( [ url. path ( ) ] + arguments) { arguments in
219
+ try withArrayOfCStrings ( ( environment ?? [ : ] ) . map { key, value in " \( key) = \( value) " } ) { environment in
220
+ let spawnResult = posix_spawn ( & pid, url. path ( ) , /*file_actions=*/& fileActions, /*attrp=*/& attrs, arguments, nil ) ;
221
+ var exitCode : Int32 = - 1
222
+ var result = wait4 ( pid, & exitCode, 0 , nil ) ;
223
+ while ( result == - 1 && errno == EINTR) {
224
+ result = wait4 ( pid, & exitCode, 0 , nil )
225
+ }
226
+ guard result != - 1 else {
227
+ throw Errors . miscError ( " wait failed " )
228
+ }
229
+ guard exitCode == 0 else {
230
+ throw Errors . miscError ( " exit code nonzero " )
231
+ }
232
+ }
233
+ }
234
+ #else
186
235
let process = Process ( )
187
236
process. executableURL = url
188
237
process. arguments = arguments
@@ -192,5 +241,44 @@ extension Process {
192
241
if process. terminationStatus != 0 {
193
242
throw Errors . processError ( terminationReason: process. terminationReason, terminationStatus: process. terminationStatus)
194
243
}
244
+ #endif
245
+ }
246
+ }
247
+
248
+ func scan< S: Sequence , U> ( _ seq: S , _ initial: U , _ combine: ( U , S . Element ) -> U ) -> [ U ] {
249
+ var result : [ U ] = [ ]
250
+ result. reserveCapacity ( seq. underestimatedCount)
251
+ var runningResult = initial
252
+ for element in seq {
253
+ runningResult = combine ( runningResult, element)
254
+ result. append ( runningResult)
255
+ }
256
+ return result
257
+ }
258
+
259
+ func withArrayOfCStrings< T> (
260
+ _ args: [ String ] ,
261
+ _ body: ( UnsafePointer < UnsafeMutablePointer < Int8 > ? > ) throws -> T
262
+ ) throws -> T {
263
+ let argsCounts = Array ( args. map { $0. utf8. count + 1 } )
264
+ let argsOffsets = [ 0 ] + scan( argsCounts, 0 , + )
265
+ let argsBufferSize = argsOffsets. last!
266
+ var argsBuffer : [ UInt8 ] = [ ]
267
+ argsBuffer. reserveCapacity ( argsBufferSize)
268
+ for arg in args {
269
+ argsBuffer. append ( contentsOf: arg. utf8)
270
+ argsBuffer. append ( 0 )
271
+ }
272
+ return try argsBuffer. withUnsafeMutableBufferPointer {
273
+ ( argsBuffer) in
274
+ let ptr = UnsafeRawPointer ( argsBuffer. baseAddress!) . bindMemory (
275
+ to: Int8 . self, capacity: argsBuffer. count)
276
+ var cStrings : [ UnsafePointer < Int8 > ? ] = argsOffsets. map { ptr + $0 }
277
+ cStrings [ cStrings. count - 1 ] = nil
278
+ return try cStrings. withUnsafeMutableBufferPointer {
279
+ let unsafeString = UnsafeMutableRawPointer ( $0. baseAddress!) . bindMemory (
280
+ to: UnsafeMutablePointer< Int8>? . self , capacity: $0. count)
281
+ return try body ( unsafeString)
195
282
}
283
+ }
196
284
}
0 commit comments