Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compile Swift from command line for distribution

I have a single file Swift command line script (it dumps the contents of the menu bar given a process id).

To give an idea of the APIs I am using, here's a few relevant lines:

import Foundation
import Cocoa

// ...
func getAttribute(element: AXUIElement, name: String) -> CFTypeRef? {
    var value: CFTypeRef? = nil
    AXUIElementCopyAttributeValue(element, name as CFString, &value)
    return value
}

// ...
var app: NSRunningApplication? = nil
if pid == -1 {
    app = NSWorkspace.shared().menuBarOwningApplication
}
else {
    app = NSRunningApplication(processIdentifier: pid)
}

// ...
let axApp = AXUIElementCreateApplication(app.processIdentifier)

The whole file is available here.

When I compile this using swiftc menu.swift, I can run it just fine in my system which has Swift installed.

When I share the menu executable to somebody who does not have Swift, they get the following error when running it via Terminal:

Code 6: dyld: Library not loaded: @rpath/libswiftAppKit.dylib
  Referenced from: ./menu
  Reason: image not found

I figure I need to statically link something, but I am not sure. I cannot test this easily since I do not have access to a macOS build without Swift.

How would I use swiftc so that I can compile my script such that it can be run on any macOS system?

like image 701
Benzi Avatar asked Apr 18 '17 17:04

Benzi


Video Answer


1 Answers

You can solve this for the cases where you only use the standard library using -static-stdlib.

When you compile a script with no options, the final executable contains rpaths to the various Swift standard libs, which you can verify using otool.

> swiftc menu.swift 
> otool -L menu
menu:
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1348.28.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1504.75.0)
    /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 48.0.0)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1349.25.0)
    @rpath/libswiftAppKit.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftCore.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftCoreData.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftCoreGraphics.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftCoreImage.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftDarwin.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftDispatch.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftFoundation.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftIOKit.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftObjectiveC.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftQuartzCore.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftSwiftOnoneSupport.dylib (compatibility version 1.0.0, current version 800.0.63)
    @rpath/libswiftXPC.dylib (compatibility version 1.0.0, current version 800.0.63)    

Using -static-stdlib ensures that the standard libraries are linked to as required.

> swiftc -static-stdlib menu.swift 
> otool -L menu
menu:
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1348.28.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 307.4.0)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1349.25.0)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1504.75.0)
    /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 48.0.0)
    /System/Library/Frameworks/CoreData.framework/Versions/A/CoreData (compatibility version 1.0.0, current version 752.8.0)
    /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics (compatibility version 64.0.0, current version 1070.13.0)
> 

I still do not know how to link 3rd party frameworks - but the above steps solves my original problem.

Related Linux Question - Compile Swift script with static Swift core library

like image 190
Benzi Avatar answered Oct 03 '22 10:10

Benzi