@@ -24,21 +24,24 @@ struct CMakeSmokeTest: CommandPlugin {
2424 }
2525
2626 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) " )
2828 let cmakeURL = URL ( filePath: cmakePath)
2929 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) " )
3131 let ninjaURL = URL ( filePath: ninjaPath)
3232 let sysrootPath = args. extractOption ( named: " sysroot-path " ) . last
3333 if let sysrootPath {
34- print ( " using sysroot at \( sysrootPath) " )
34+ Diagnostics . progress ( " using sysroot at \( sysrootPath) " )
3535 }
3636
37+ let extraCMakeArgs = args. extractOption ( named: " extra-cmake-arg " )
38+ Diagnostics . progress ( " Extra cmake args: \( extraCMakeArgs. joined ( separator: " " ) ) " )
39+
3740 let moduleCachePath = context. pluginWorkDirectoryURL. appending ( component: " module-cache " ) . path ( )
3841
3942 let swiftBuildURL = context. package . directoryURL
4043 let swiftBuildBuildURL = context. pluginWorkDirectoryURL. appending ( component: " swift-build " )
41- print ( " swift-build: \( swiftBuildURL. path ( ) ) " )
44+ Diagnostics . progress ( " swift-build: \( swiftBuildURL. path ( ) ) " )
4245
4346 let swiftToolsSupportCoreURL = try findDependency ( " swift-tools-support-core " , pluginContext: context)
4447 let swiftToolsSupportCoreBuildURL = context. pluginWorkDirectoryURL. appending ( component: " swift-tools-support-core " )
@@ -80,39 +83,39 @@ struct CMakeSmokeTest: CommandPlugin {
8083 " -DCMAKE_MAKE_PROGRAM= \( ninjaPath) " ,
8184 " -DCMAKE_BUILD_TYPE:=Debug " ,
8285 " -DCMAKE_Swift_FLAGS=' \( sharedSwiftFlags. joined ( separator: " " ) ) ' "
83- ] + cMakeProjectArgs
86+ ] + cMakeProjectArgs + extraCMakeArgs
8487
85- print ( " Building swift-tools-support-core " )
88+ Diagnostics . progress ( " Building swift-tools-support-core " )
8689 try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftToolsSupportCoreURL. path ( ) ] , workingDirectory: swiftToolsSupportCoreBuildURL)
8790 try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftToolsSupportCoreBuildURL)
88- print ( " Built swift-tools-support-core " )
91+ Diagnostics . progress ( " Built swift-tools-support-core " )
8992
9093 if hostOS != . macOS {
91- print ( " Building swift-system " )
94+ Diagnostics . progress ( " Building swift-system " )
9295 try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftSystemURL. path ( ) ] , workingDirectory: swiftSystemBuildURL)
9396 try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftSystemBuildURL)
94- print ( " Built swift-system " )
97+ Diagnostics . progress ( " Built swift-system " )
9598 }
9699
97- print ( " Building llbuild " )
100+ Diagnostics . progress ( " Building llbuild " )
98101 try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ " -DLLBUILD_SUPPORT_BINDINGS:=Swift " , llbuildURL. path ( ) ] , workingDirectory: llbuildBuildURL)
99102 try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: llbuildBuildURL)
100- print ( " Built llbuild " )
103+ Diagnostics . progress ( " Built llbuild " )
101104
102- print ( " Building swift-argument-parser " )
105+ Diagnostics . progress ( " Building swift-argument-parser " )
103106 try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ " -DBUILD_TESTING=NO " , " -DBUILD_EXAMPLES=NO " , swiftArgumentParserURL. path ( ) ] , workingDirectory: swiftArgumentParserBuildURL)
104107 try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftArgumentParserBuildURL)
105- print ( " Built swift-argument-parser " )
108+ Diagnostics . progress ( " Built swift-argument-parser " )
106109
107- print ( " Building swift-driver " )
110+ Diagnostics . progress ( " Building swift-driver " )
108111 try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftDriverURL. path ( ) ] , workingDirectory: swiftDriverBuildURL)
109112 try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftDriverBuildURL)
110- print ( " Built swift-driver " )
113+ Diagnostics . progress ( " Built swift-driver " )
111114
112- print ( " Building swift-build in \( swiftBuildBuildURL) " )
115+ Diagnostics . progress ( " Building swift-build in \( swiftBuildBuildURL) " )
113116 try await Process . checkNonZeroExit ( url: cmakeURL, arguments: sharedCMakeArgs + [ swiftBuildURL. path ( ) ] , workingDirectory: swiftBuildBuildURL)
114117 try await Process . checkNonZeroExit ( url: ninjaURL, arguments: [ ] , workingDirectory: swiftBuildBuildURL)
115- print ( " Built swift-build " )
118+ Diagnostics . progress ( " Built swift-build " )
116119 }
117120
118121 func findDependency( _ name: String , pluginContext: PluginContext ) throws -> URL {
@@ -132,7 +135,7 @@ struct CMakeSmokeTest: CommandPlugin {
132135 throw Errors . missingRepository ( name)
133136 }
134137 let dependencyURL = dependency. directoryURL
135- print ( " \( name) : \( dependencyURL. path ( ) ) " )
138+ Diagnostics . progress ( " \( name) : \( dependencyURL. path ( ) ) " )
136139 guard FileManager . default. fileExists ( atPath: dependencyURL. path ( ) ) else {
137140 throw Errors . missingRepository ( dependencyURL. path ( ) )
138141 }
@@ -145,6 +148,7 @@ enum Errors: Error {
145148 case missingRequiredOption( String )
146149 case missingRepository( String )
147150 case unimplementedForHostOS
151+ case miscError( String )
148152}
149153
150154enum OS {
@@ -182,7 +186,53 @@ extension Process {
182186 }
183187
184188 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 USE_PROCESS_SPAWNING_WORKAROUND
191+ Diagnostics . progress ( " Using process spawning workaround " )
192+ // Linux workaround for https://github.com/swiftlang/swift-corelibs-foundation/issues/4772
193+ // Foundation.Process on Linux seems to inherit the Process.run()-calling thread's signal mask, creating processes that even have SIGTERM blocked
194+ // This manifests as CMake hanging when invoking 'uname' with incorrectly configured signal handlers.
195+ var fileActions = posix_spawn_file_actions_t ( )
196+ defer { posix_spawn_file_actions_destroy ( & fileActions) }
197+ var attrs : posix_spawnattr_t = posix_spawnattr_t ( )
198+ defer { posix_spawnattr_destroy ( & attrs) }
199+ posix_spawn_file_actions_init ( & fileActions)
200+ posix_spawn_file_actions_addchdir_np ( & fileActions, workingDirectory. path ( ) )
201+
202+ posix_spawnattr_init ( & attrs)
203+ posix_spawnattr_setpgroup ( & attrs, 0 )
204+ var noSignals = sigset_t ( )
205+ sigemptyset ( & noSignals)
206+ posix_spawnattr_setsigmask ( & attrs, & noSignals)
207+
208+ var mostSignals = sigset_t ( )
209+ sigemptyset ( & mostSignals)
210+ for i in 1 ..< SIGSYS {
211+ if i == SIGKILL || i == SIGSTOP {
212+ continue
213+ }
214+ sigaddset ( & mostSignals, i)
215+ }
216+ posix_spawnattr_setsigdefault ( & attrs, & mostSignals)
217+ posix_spawnattr_setflags ( & attrs, numericCast ( POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK) )
218+ var pid : pid_t = - 1
219+ try withArrayOfCStrings ( [ url. path ( ) ] + arguments) { arguments in
220+ try withArrayOfCStrings ( ( environment ?? [ : ] ) . map { key, value in " \( key) = \( value) " } ) { environment in
221+ let spawnResult = posix_spawn ( & pid, url. path ( ) , /*file_actions=*/& fileActions, /*attrp=*/& attrs, arguments, nil ) ;
222+ var exitCode : Int32 = - 1
223+ var result = wait4 ( pid, & exitCode, 0 , nil ) ;
224+ while ( result == - 1 && errno == EINTR) {
225+ result = wait4 ( pid, & exitCode, 0 , nil )
226+ }
227+ guard result != - 1 else {
228+ throw Errors . miscError ( " wait failed " )
229+ }
230+ guard exitCode == 0 else {
231+ throw Errors . miscError ( " exit code nonzero " )
232+ }
233+ }
234+ }
235+ #else
186236 let process = Process ( )
187237 process. executableURL = url
188238 process. arguments = arguments
@@ -192,5 +242,44 @@ extension Process {
192242 if process. terminationStatus != 0 {
193243 throw Errors . processError ( terminationReason: process. terminationReason, terminationStatus: process. terminationStatus)
194244 }
245+ #endif
246+ }
247+ }
248+
249+ func scan< S: Sequence , U> ( _ seq: S , _ initial: U , _ combine: ( U , S . Element ) -> U ) -> [ U ] {
250+ var result : [ U ] = [ ]
251+ result. reserveCapacity ( seq. underestimatedCount)
252+ var runningResult = initial
253+ for element in seq {
254+ runningResult = combine ( runningResult, element)
255+ result. append ( runningResult)
256+ }
257+ return result
258+ }
259+
260+ func withArrayOfCStrings< T> (
261+ _ args: [ String ] ,
262+ _ body: ( UnsafePointer < UnsafeMutablePointer < Int8 > ? > ) throws -> T
263+ ) throws -> T {
264+ let argsCounts = Array ( args. map { $0. utf8. count + 1 } )
265+ let argsOffsets = [ 0 ] + scan( argsCounts, 0 , + )
266+ let argsBufferSize = argsOffsets. last!
267+ var argsBuffer : [ UInt8 ] = [ ]
268+ argsBuffer. reserveCapacity ( argsBufferSize)
269+ for arg in args {
270+ argsBuffer. append ( contentsOf: arg. utf8)
271+ argsBuffer. append ( 0 )
272+ }
273+ return try argsBuffer. withUnsafeMutableBufferPointer {
274+ ( argsBuffer) in
275+ let ptr = UnsafeRawPointer ( argsBuffer. baseAddress!) . bindMemory (
276+ to: Int8 . self, capacity: argsBuffer. count)
277+ var cStrings : [ UnsafePointer < Int8 > ? ] = argsOffsets. map { ptr + $0 }
278+ cStrings [ cStrings. count - 1 ] = nil
279+ return try cStrings. withUnsafeMutableBufferPointer {
280+ let unsafeString = UnsafeMutableRawPointer ( $0. baseAddress!) . bindMemory (
281+ to: UnsafeMutablePointer< Int8>? . self , capacity: $0. count)
282+ return try body ( unsafeString)
195283 }
284+ }
196285}
0 commit comments