Skip to content

Commit 30d4f77

Browse files
Create Mac app bundle for GUI apps on macOS when --app:gui is used (#25042)
Fixes #25041 Basically it creates a "real" console-less app when --app:gui is used. Otherwise a console window opens, see the bug. --------- Co-authored-by: Andreas Rumpf <araq4k@proton.me>
1 parent 6ab532f commit 30d4f77

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

compiler/extccomp.nim

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,59 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
810810
(ose.msg & " " & $ose.errorCode))
811811
raise
812812

813+
proc createMacAppBundle(conf: ConfigRef; exefile: AbsoluteFile) =
814+
let (dir, name, _) = splitFile(exefile.string)
815+
let appBundleName = name & ".app"
816+
let appBundlePath = dir / appBundleName
817+
let contentsPath = appBundlePath / "Contents"
818+
let macosPath = contentsPath / "MacOS"
819+
820+
createDir(macosPath)
821+
822+
let bundleExePath = macosPath / name
823+
copyFileWithPermissions(exefile.string, bundleExePath)
824+
825+
let infoPlistPath = contentsPath / "Info.plist"
826+
827+
proc xmlEscape(s: string): string =
828+
result = newStringOfCap(s.len)
829+
for c in items(s):
830+
case c:
831+
of '<': result.add("&lt;")
832+
of '>': result.add("&gt;")
833+
of '&': result.add("&amp;")
834+
of '"': result.add("&quot;")
835+
of '\'': result.add("&apos;")
836+
else:
837+
if ord(c) < 32:
838+
result.add("&#" & $ord(c) & ';')
839+
else:
840+
result.add(c)
841+
842+
let escapedName = xmlEscape(name)
843+
let infoPlistContent = """<?xml version="1.0" encoding="UTF-8"?>
844+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
845+
<plist version="1.0">
846+
<dict>
847+
<key>CFBundleExecutable</key>
848+
<string>$1</string>
849+
<key>CFBundleIdentifier</key>
850+
<string>com.nim.$1</string>
851+
<key>CFBundleName</key>
852+
<string>$1</string>
853+
<key>CFBundlePackageType</key>
854+
<string>APPL</string>
855+
<key>LSUIElement</key>
856+
<string>1</string>
857+
</dict>
858+
</plist>""" % [escapedName]
859+
860+
writeFile(infoPlistPath, infoPlistContent)
861+
862+
removeFile(exefile.string)
863+
864+
rawMessage(conf, hintUserRaw, "Created Mac app bundle: " & appBundlePath)
865+
813866
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
814867
result = @[]
815868
when defined(macosx):
@@ -994,6 +1047,10 @@ proc callCCompiler*(conf: ConfigRef) =
9941047
preventLinkCmdMaxCmdLen(conf, linkCmd)
9951048
for cmd in extraCmds:
9961049
execExternalProgram(conf, cmd, hintExecuting)
1050+
# create Mac app bundle for GUI apps on macOS
1051+
when defined(macosx):
1052+
if conf.globalOptions * {optGenGuiApp, optGenDynLib, optGenStaticLib} == {optGenGuiApp}:
1053+
createMacAppBundle(conf, mainOutput)
9971054
else:
9981055
linkCmd = ""
9991056
if optGenScript in conf.globalOptions:

0 commit comments

Comments
 (0)