Skip to content

Commit b941bbe

Browse files
charles-zablitjakepetroules
authored andcommitted
gate Process extension behind preprocessor check
1 parent 7eae6e7 commit b941bbe

File tree

1 file changed

+95
-93
lines changed

1 file changed

+95
-93
lines changed

Sources/SwiftDriver/Utilities/PythonArchitecture.swift

Lines changed: 95 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -99,110 +99,112 @@ public enum ExecutableArchitecture: String {
9999
#endif
100100
}
101101

102+
#if os(Windows)
102103
extension Process {
103-
#if os(Windows)
104-
/// Resolves the filename from the `Path` environment variable and read its COFF header to determine the architecture
105-
/// of the binary.
106-
///
107-
/// - Parameters:
108-
/// - cwd: The current working directory.
109-
/// - env: A dictionary of the environment variables and their values. Usually of the parent shell.
110-
/// - filename: The name of the file we are resolving the architecture of.
111-
/// - Returns: The architecture of the file which was found in the `Path`.
112-
static func readWindowsExecutableArchitecture(
113-
cwd: AbsolutePath?, envBlock: ProcessEnvironmentBlock, filename: String
114-
) -> ExecutableArchitecture {
115-
let searchPaths = getEnvSearchPaths(
116-
pathString: envBlock["Path"], currentWorkingDirectory: cwd)
117-
guard
118-
let filePath = lookupExecutablePath(
119-
filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
120-
else {
121-
return .unknown
122-
}
123-
guard let fileHandle = FileHandle(forReadingAtPath: filePath.pathString) else {
124-
return .unknown
125-
}
126-
127-
defer { fileHandle.closeFile() }
128-
129-
// Infering the architecture of a Windows executable from its COFF header involves the following:
130-
// 1. Get the COFF header offset from the pointer located at the 0x3C offset (4 bytes long).
131-
// 2. Jump to that offset and read the next 6 bytes.
132-
// 3. The first 4 are the signature which should be equal to 0x50450000.
133-
// 4. The last 2 are the machine architecture which can be infered from the value we get.
134-
//
135-
// The link below provides a visualization of the COFF header and the process to get to it.
136-
// https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg
137-
guard (try? fileHandle.seek(toOffset: 0x3C)) != nil else {
138-
return .unknown
139-
}
140-
guard let offsetPointer = try? fileHandle.read(upToCount: 4),
141-
offsetPointer.count == 4
142-
else {
143-
return .unknown
144-
}
104+
/// Resolves the filename from the `Path` environment variable and read its COFF header to determine the architecture
105+
/// of the binary.
106+
///
107+
/// - Parameters:
108+
/// - cwd: The current working directory.
109+
/// - env: A dictionary of the environment variables and their values. Usually of the parent shell.
110+
/// - filename: The name of the file we are resolving the architecture of.
111+
/// - Returns: The architecture of the file which was found in the `Path`.
112+
static func readWindowsExecutableArchitecture(
113+
cwd: AbsolutePath?, envBlock: ProcessEnvironmentBlock, filename: String
114+
) -> ExecutableArchitecture {
115+
let searchPaths = getEnvSearchPaths(
116+
pathString: envBlock["Path"], currentWorkingDirectory: cwd)
117+
guard
118+
let filePath = lookupExecutablePath(
119+
filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
120+
else {
121+
return .unknown
122+
}
123+
guard let fileHandle = FileHandle(forReadingAtPath: filePath.pathString) else {
124+
return .unknown
125+
}
145126

146-
let peHeaderOffset = offsetPointer.withUnsafeBytes { $0.load(as: UInt32.self) }
127+
defer { fileHandle.closeFile() }
128+
129+
// Infering the architecture of a Windows executable from its COFF header involves the following:
130+
// 1. Get the COFF header offset from the pointer located at the 0x3C offset (4 bytes long).
131+
// 2. Jump to that offset and read the next 6 bytes.
132+
// 3. The first 4 are the signature which should be equal to 0x50450000.
133+
// 4. The last 2 are the machine architecture which can be infered from the value we get.
134+
//
135+
// The link below provides a visualization of the COFF header and the process to get to it.
136+
// https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg
137+
guard (try? fileHandle.seek(toOffset: 0x3C)) != nil else {
138+
return .unknown
139+
}
140+
guard let offsetPointer = try? fileHandle.read(upToCount: 4),
141+
offsetPointer.count == 4
142+
else {
143+
return .unknown
144+
}
147145

148-
guard (try? fileHandle.seek(toOffset: UInt64(peHeaderOffset))) != nil else {
149-
return .unknown
150-
}
151-
guard let coffHeader = try? fileHandle.read(upToCount: 6), coffHeader.count == 6 else {
152-
return .unknown
153-
}
146+
let peHeaderOffset = offsetPointer.withUnsafeBytes { $0.load(as: UInt32.self) }
154147

155-
let signature = coffHeader.prefix(4)
156-
let machineBytes = coffHeader.suffix(2)
148+
guard (try? fileHandle.seek(toOffset: UInt64(peHeaderOffset))) != nil else {
149+
return .unknown
150+
}
151+
guard let coffHeader = try? fileHandle.read(upToCount: 6), coffHeader.count == 6 else {
152+
return .unknown
153+
}
157154

158-
guard signature == Data([0x50, 0x45, 0x00, 0x00]) else {
159-
return .unknown
160-
}
155+
let signature = coffHeader.prefix(4)
156+
let machineBytes = coffHeader.suffix(2)
161157

162-
let machine = machineBytes.withUnsafeBytes { $0.load(as: UInt16.self) }
163-
return .fromPEMachineByte(machine: Int32(machine))
158+
guard signature == Data([0x50, 0x45, 0x00, 0x00]) else {
159+
return .unknown
164160
}
165-
#endif
166161

167-
#if os(macOS)
168-
static func readDarwinExecutableArchitecture(
169-
cwd: AbsolutePath?, envBlock: ProcessEnvironmentBlock, filename: String
170-
) -> ExecutableArchitecture {
171-
let magicNumber: UInt32 = 0xcafe_babe
172-
173-
let searchPaths = getEnvSearchPaths(
174-
pathString: envBlock["PATH"], currentWorkingDirectory: cwd)
175-
guard
176-
let filePath = lookupExecutablePath(
177-
filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
178-
else {
179-
return .unknown
180-
}
181-
guard let fileHandle = FileHandle(forReadingAtPath: filePath.pathString) else {
182-
return .unknown
183-
}
162+
let machine = machineBytes.withUnsafeBytes { $0.load(as: UInt16.self) }
163+
return .fromPEMachineByte(machine: Int32(machine))
164+
}
165+
}
166+
#endif
184167

185-
defer {
186-
try? fileHandle.close()
187-
}
168+
#if os(macOS)
169+
extension Process {
170+
static func readDarwinExecutableArchitecture(
171+
cwd: AbsolutePath?, envBlock: ProcessEnvironmentBlock, filename: String
172+
) -> ExecutableArchitecture {
173+
let magicNumber: UInt32 = 0xcafe_babe
174+
175+
let searchPaths = getEnvSearchPaths(
176+
pathString: envBlock["PATH"], currentWorkingDirectory: cwd)
177+
guard
178+
let filePath = lookupExecutablePath(
179+
filename: filename, currentWorkingDirectory: cwd, searchPaths: searchPaths)
180+
else {
181+
return .unknown
182+
}
183+
guard let fileHandle = FileHandle(forReadingAtPath: filePath.pathString) else {
184+
return .unknown
185+
}
188186

189-
// The first 4 bytes of a Mach-O header contain the magic number. We use it to determine if the binary is
190-
// universal.
191-
// https://github.com/apple/darwin-xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h
192-
let magicData = fileHandle.readData(ofLength: 4)
193-
let magic = magicData.withUnsafeBytes { $0.load(as: UInt32.self).bigEndian }
187+
defer {
188+
try? fileHandle.close()
189+
}
194190

195-
if magic == magicNumber {
196-
return .universal
197-
}
191+
// The first 4 bytes of a Mach-O header contain the magic number. We use it to determine if the binary is
192+
// universal.
193+
// https://github.com/apple/darwin-xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h
194+
let magicData = fileHandle.readData(ofLength: 4)
195+
let magic = magicData.withUnsafeBytes { $0.load(as: UInt32.self).bigEndian }
198196

199-
// If the binary is not universal, the next 4 bytes contain the CPU type.
200-
guard (try? fileHandle.seek(toOffset: 4)) != nil else {
201-
return .unknown
202-
}
203-
let cpuTypeData = fileHandle.readData(ofLength: 4)
204-
let cpuType = cpuTypeData.withUnsafeBytes { $0.load(as: Int32.self) }
205-
return .fromMachoCPUType(cpuType: cpuType)
197+
if magic == magicNumber {
198+
return .universal
206199
}
207-
#endif
200+
201+
// If the binary is not universal, the next 4 bytes contain the CPU type.
202+
guard (try? fileHandle.seek(toOffset: 4)) != nil else {
203+
return .unknown
204+
}
205+
let cpuTypeData = fileHandle.readData(ofLength: 4)
206+
let cpuType = cpuTypeData.withUnsafeBytes { $0.load(as: Int32.self) }
207+
return .fromMachoCPUType(cpuType: cpuType)
208+
}
208209
}
210+
#endif

0 commit comments

Comments
 (0)