How to run an external program in Swift?

How to run an external program in Swift?
I'm trying to run a calculator in Swift and I can't!
Note: I'm using Windows:

import Foundation
    let p = Process()
    p.executableURL = URL(fileURLWithPath: "calc")
    try p.run()

Would you be able to provide the exact error message that you're seeing?

The calculator is not running!

C:\teste.app>swift run teste.app
Building for debugging...
[1/1] Write auxiliary file C:\teste.app.build\x86_64-unknown-windows-msvc\debug\swift-version-7C931827B4E7650F.txt
Build of product 'teste.app' complete! (22.45s)
warning: unable to create symbolic link at C:\teste.app.build\debug: Error Domain=NSCocoaErrorDomain Code=512 "(null)"
error: exec error: No such file or directory (2): C:\teste.app.build\x86_64-unknown-windows-msvc\debug\teste.app .build\x86_64-unknown-windows-msvc\debug\teste.app

Which version of Swift are you using? Could you paste the output of swift --version command here?

swift --version
Swift version 6.0.3 (swift-6.0.3-RELEASE)
Target: x86_64-unknown-windows-msvc

I don't get the same error as you, but you appear to be passing the name of the program that you want to run, instead of its path.

Try this instead:

p.executableURL = URL(fileURLWithPath: "/Windows/System32/calc.exe")

That works for me (on a virtualised copy of Windows.)

It's still giving an error! I'll see if reinstalling Swift on Windows will make the error go away! I'll reinstall it on Windows tomorrow!

Any installation tips?

import Foundation

    let p = Process()
    p.executableURL = URL(fileURLWithPath: "/Windows/System32/calc.exe")
    try p.run()

Error:

C:\teste.app>swift run teste.app
Building for debugging...
[5/5] Compiling teste_app main.swift
Build of product 'teste.app' complete! (34.45s)
warning: unable to create symbolic link at C:\teste.app.build\debug: Error Domain=NSCocoaErrorDomain Code=512 "(null)"
error: exec error: No such file or directory (2): C:\teste.app.build\x86_64-unknown-windows-msvc\debug\teste.app .build\x86_64-unknown-windows-msvc\debug\teste.app

I think that it maybe because your project has a full-stop (period) in the name: teste.app - why did you give it an .app suffix, out of curiosity?

I tried making a swift executable package on Windows with a matching name and then moving into the package directory and running swift run and it wasn't happy, although the executable was built.

Building for debugging...
[8/8] Linking C:\Users\diggory\test.app\.build\aarch64-unknown-windows-msvc\debug\test.app.exe
Build of product 'test.app' complete! (4.27s)
error: exec error: No such file or directory (2): C:\Users\diggory\test.app\.build\aarch64-unknown-windows-msvc\debug\test.app .build\aarch64-unknown-windows-msvc\debug\test.app

It seems like URL(fileURLWithPath:) will give you the URL relative to the current directory. I don't think this is what you want though. Try this:

import Foundation
let calc = URL(string: "file:///c:/Windows/System32/calc.exe")!
_ = try calc.checkResourceIsReachable()

Also I'd take a look at RFC 8089 - The "file" URI Scheme.

I was able to open the calculator!
But when I insert these parameters of the Java code, I can't open the program!
The parameters are:

c:/java/jdk-23/bin/java.exe -jar /java-exec/WindowJAR.jar

How can I run the program with the addition of these parameters?

import Foundation

let p = Process()
p.executableURL = URL(string: "file:///c:/java/jdk-23/bin/java.exe -jar /java-exec/WindowJAR.jar")
try p.run()

Error

C:\teste>swift run teste
Building for debugging...
[8/8] Linking C:\teste\.build\x86_64-unknown-windows-msvc\debug\teste.exe
Build of product 'teste' complete! (52.91s)
warning: unable to create symbolic link at C:\teste\.build\debug: Error Domain=NSCocoaErrorDomain Code=512 "(null)"
Swift/ErrorType.swift:253: Fatal error: Error raised at top level: Error Domain=NSCocoaErrorDomain Code=260 "The file doesn’t exist."
Current stack trace:
0    swiftCore.dll                      0x00007ff855c50e70 swift_stdlib_reportFatalErrorInFile + 132
1    swiftCore.dll                      0x00007ff85588ad80 StaticString.withUTF8Buffer<A>(_:) + 1172
2    swiftCore.dll                      0x00007ff85588ad80 StaticString.withUTF8Buffer<A>(_:) + 626
3    swiftCore.dll                      0x00007ff855889d50 _assertionFailure(_:_:file:line:flags:) + 372
4    swiftCore.dll                      0x00007ff8558ffcd0 swift_errorInMain + 960
5    teste.exe                          0x00007ff6825f12b0 main + 190
6    teste.exe                          0x00007ff6825f12b0 main + 832
7    KERNEL32.DLL                       0x00007ff8dc59e8c0 BaseThreadInitThunk + 23
8    ntdll.dll                          0x00007ff8dde7bf40 RtlUserThreadStart + 44

You get this error because it's going to look for a file with the path c:/java/jdk-23/bin/java.exe -jar /java-exec/WindowJAR.jar which doesn't exist. Your executableUrl is just URL(string: "file:///c:/java/jdk-23/bin/java.exe), the rest are arguments e.g.,

let p = Process()
p.executableURL = URL(string: "file:///c:/myExecutable.exe")
p.arguments = ["-s", "path/to/some/file"]

However for /java-exec/... make sure you pass the absolute path.

Also, if you want avoid throwing an error at the top level you can wrap your p.run() in a do-catch:

import Foundation
let p = Process()
p.executableURL = URL(string: "file:///foo")!
do {
  try p.run()
} catch {
  print("Error:", error.localizedDescription)
}

EDIT: Added note about error handling.

Solved!
Thanks everyone for helping me!

import Foundation

let p = Process()
p.executableURL = URL(string: "file:///c:/java/jdk-23/bin/java.exe")
p.arguments = ["-jar", "/java-exec/WindowJAR.jar"]

do {
try p.run()
} catch {
print("Error:", error.localizedDescription)
}
2 Likes