macosrustterminal

Running Rust app without showing the terminal - for MacOS


I have the same situation as in this post...

https://users.rust-lang.org/t/running-rust-app-without-showing-the-terminal/41859

... where the poster in the link above can run the Rust binary in Windows, but along with the binary, a Terminal window also opens. In that post, someone mentioned a workaround, which did help.

On my Mac M1 I compile the Rust binary with...

cargo build --target aarch64-apple-darwin --release

... and the binary GUI opens just fine, but the Terminal is also displayed.

How do I prevent the Terminal from opening?


Solution

  • On macOS, if you open a bare executable file, it is assumed to be a command-line program which should get a terminal. To make a proper GUI application with no terminal, you need to create an .app bundle.

    The minimum viable structure for an .app is actually quite simple and does not require any special tool to create. Create this directory structure:

    Your Application Name.app/
        Contents/
            Info.plist
            MacOS/
                your-executable-goes-here
    

    For development purposes, the executable can be a symlink or shell script that refers to the executable in your Rust target/ directory (but an application you are distributing should be self-contained instead).

    In the Info.plist file, you should put:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>CFBundleExecutable</key>
      <string>your-executable-goes-here</string>
      <key>CFBundleIdentifier</key>
      <string>com.example.your-app-name</string>
    </dict>
    </plist>
    

    A plist <dict> is made up of key-value pairs, so there are two entries in the dict here; if hypothetically they were written in JSON instead (you cannot actually do this) they would look like:

    {
        "CFBundleExecutable": "your-executable-goes-here",
        "CFBundleIdentifier": "com.example.your-app-name",
    }
    

    The <string> value for CFBundleExecutable (replacing "your-executable-goes-here" in the above example) must be the file name of the executable that you put in Contents/MacOS/.

    The <string> value for CFBundleIdentifier (replacing "com.example.your-app-name" in the above example) should be a unique identifier for your application in the form of a reversed DNS name — that is, if you own the domain name example.com then you can use identifiers starting with com.example.. It is important that the CFBundleIdentifier is unique (except for different versions of the same application).

    If you wish your application to have an icon, or be able to used to open documents, then you will need to put more things in the Info.plist file. (On macOS, opened documents are not passed as command line arguments, but as events delivered to the event loop.)