Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 26 additions & 81 deletions Sources/Testing/Support/Additions/CommandLineAdditions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,27 @@ enum CommandLine {
}
#endif

#if !SWT_NO_EXIT_TESTS
extension CommandLine {
#if !hasFeature(Embedded) && !os(WASI) && !SWT_TARGET_OS_APPLE
#if os(Windows)
private typealias FPEncoding = UTF16
#else
private typealias FPEncoding = UTF8
#endif

private static var executablePathCString: ContiguousArray<FPEncoding.CodeUnit>? {
@_silgen_name("_swift_stdlib_executablePathCString") get
}
#endif

/// The path to the current process' executable.
static var executablePath: String {
get throws {
#if SWT_TARGET_OS_APPLE
#if hasFeature(Embedded) || os(WASI)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be its own configuration?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really a quirk of the stdlib rather than ours. 🤷‍♂️

// Embedded Swift and WASI do not currently support getting the executable
// path via the standard library.
throw SystemError(description: "The current executable path is not available on this platform.")
#elseif SWT_TARGET_OS_APPLE
var result: String?
#if DEBUG
var bufferCount = UInt32(1) // force looping
Expand All @@ -49,91 +64,21 @@ extension CommandLine {
}
}
return result!
#elseif os(Linux) || os(Android)
var result: String?
#if DEBUG
var bufferCount = Int(1) // force looping
#else
var bufferCount = Int(PATH_MAX)
#endif
while result == nil {
try withUnsafeTemporaryAllocation(of: CChar.self, capacity: bufferCount) { buffer in
let readCount = readlink("/proc/self/exe", buffer.baseAddress!, buffer.count)
guard readCount >= 0 else {
throw CError(rawValue: swt_errno())
}
if readCount < buffer.count {
buffer[readCount] = 0 // NUL-terminate the string.
result = String(cString: buffer.baseAddress!)
} else {
bufferCount += Int(PATH_MAX) // add more space and try again
}
}
}
return result!
#elseif os(FreeBSD)
var mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1]
return try mib.withUnsafeMutableBufferPointer { mib in
var bufferCount = 0
guard 0 == sysctl(mib.baseAddress!, .init(mib.count), nil, &bufferCount, nil, 0) else {
throw CError(rawValue: swt_errno())
}
return try withUnsafeTemporaryAllocation(of: CChar.self, capacity: bufferCount) { buffer in
guard 0 == sysctl(mib.baseAddress!, .init(mib.count), buffer.baseAddress!, &bufferCount, nil, 0) else {
throw CError(rawValue: swt_errno())
}
return String(cString: buffer.baseAddress!)
}
}
#elseif os(OpenBSD)
// OpenBSD does not have API to get a path to the running executable. Use
// arguments[0]. We do a basic sniff test for a path-like string, and
// prepend the early CWD if it looks like a relative path, but otherwise
// return argv[0] verbatim.
guard var argv0 = arguments.first, argv0.contains("/") else {
throw CError(rawValue: ENOEXEC)
}
if argv0.first != "/",
let earlyCWD = swt_getEarlyCWD().flatMap(String.init(validatingCString:)),
!earlyCWD.isEmpty {
argv0 = "\(earlyCWD)/\(argv0)"
}
return argv0
#elseif os(Windows)
var result: String?
#if DEBUG
var bufferCount = Int(1) // force looping
guard let executablePathCString else {
#if os(Windows)
throw Win32Error(rawValue: GetLastError())
#else
var bufferCount = Int(MAX_PATH)
throw CError(rawValue: swt_errno())
#endif
while result == nil {
try withUnsafeTemporaryAllocation(of: CWideChar.self, capacity: bufferCount) { buffer in
SetLastError(DWORD(ERROR_SUCCESS))
_ = GetModuleFileNameW(nil, buffer.baseAddress!, DWORD(buffer.count))
switch GetLastError() {
case DWORD(ERROR_SUCCESS):
result = String.decodeCString(buffer.baseAddress!, as: UTF16.self)?.result
if result == nil {
throw Win32Error(rawValue: DWORD(ERROR_ILLEGAL_CHARACTER))
}
case DWORD(ERROR_INSUFFICIENT_BUFFER):
bufferCount += Int(MAX_PATH)
case let errorCode:
throw Win32Error(rawValue: errorCode)
}
}
return try executablePathCString.withUnsafeBufferPointer { executablePathCString in
guard let result = String.decodeCString(executablePathCString.baseAddress!, as: FPEncoding.self)?.result else {
throw SystemError(description: "Could not decode the current executable's path as \(FPEncoding.self).")
}
return result
}
return result!
#elseif os(WASI)
// WASI does not really have the concept of a file system path to the main
// executable, so simply return the first argument--presumably the program
// name, but as you know this is not guaranteed by the C standard!
return arguments[0]
#else
#warning("Platform-specific implementation missing: executable path unavailable")
throw SystemError(description: "The executable path of the current process could not be determined.")
#endif
}
}
}
#endif
1 change: 0 additions & 1 deletion Sources/_TestingInternals/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ set(CMAKE_CXX_SCAN_FOR_MODULES 0)
include(GitCommit)
include(TargetTriple)
add_library(_TestingInternals STATIC
ExecutablePath.cpp
Versions.cpp
WillThrow.cpp)
target_include_directories(_TestingInternals PUBLIC
Expand Down
39 changes: 0 additions & 39 deletions Sources/_TestingInternals/ExecutablePath.cpp

This file was deleted.

31 changes: 0 additions & 31 deletions Sources/_TestingInternals/include/ExecutablePath.h

This file was deleted.

Loading