From 01fd35818c7fd36bbafa2deb16869f06d3659698 Mon Sep 17 00:00:00 2001 From: NanoTech Date: Wed, 15 Feb 2017 22:08:20 -0600 Subject: [PATCH] Fix linking with -whole-module-optimization enabled --- README.md | 58 +++++++++++++------------- SwiftAppLibrary/AppDelegate.swift | 9 ---- SwiftAppLibrary/SwiftAppLibrary.m | 13 ++++++ SwiftHaskell.xcodeproj/project.pbxproj | 4 ++ 4 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 SwiftAppLibrary/SwiftAppLibrary.m diff --git a/README.md b/README.md index c6de983..d724bfc 100644 --- a/README.md +++ b/README.md @@ -229,32 +229,39 @@ executable SwiftHaskell ## Starting the GUI Because Haskell has control over the program's entry point -(`main`), we'll need to have it call out to Swift to -start Cocoa's main thread. Add this top level function to -`AppDelegate.swift`: - -```swift -@_cdecl("runNSApplication") -func runNSApplication() { - let app = NSApplication.shared() - var topObjects: NSArray = [] - NSNib.init(nibNamed: "MainMenu", bundle: Bundle(for: AppDelegate.self))! - .instantiate(withOwner: app, topLevelObjects: &topObjects) - app.run() -} -``` - -`@_cdecl` sets the symbol name of the Swift function, overriding -normal symbol mangling. - -In `SwiftAppLibrary.h`, add a `FOUNDATION_EXPORT` C prototype -for the function, so that its symbol gets marked as public and -is exported from the framework: +(`main`), we'll need to have it call out to Cocoa to start its +main thread. In `SwiftAppLibrary.h`, declare a new function +named `runNSApplication` and mark it as `FOUNDATION_EXPORT` to +indicate that it should be exported from the framework: ```c FOUNDATION_EXPORT void runNSApplication(void); ``` +Implement the function by adding a new Objective-C `.m` file to +the framework target containing + +```objective-c +#import "SwiftAppLibrary.h" + +@interface AClassInThisFramework : NSObject @end +@implementation AClassInThisFramework @end + +void runNSApplication(void) { + NSApplication *app = [NSApplication sharedApplication]; + NSBundle *bundle = [NSBundle bundleForClass:[AClassInThisFramework class]]; + NSArray *topObjects; + [[[NSNib alloc] initWithNibNamed:@"MainMenu" bundle:bundle] + instantiateWithOwner:app topLevelObjects:&topObjects]; + [app run]; +} +``` + +This *is* possible to write in Swift, however as of Swift 3.0.2, +the annotation to export unmangled C symbols (`@_cdecl`) is not +documented as stable. Additionally, whole module optimization +will assume that `@_cdecl` symbols are unused and remove them. + In `Main.hs`, import the foreign function and call it from the end of `main`: @@ -401,15 +408,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationWillTerminate(_ aNotification: Notification) { } } - -@_cdecl("swiftAppMain") -func swiftAppMain() { - let app = NSApplication.shared() - var topObjects: NSArray = [] - NSNib.init(nibNamed: "MainMenu", bundle: Bundle(for: AppDelegate.self))! - .instantiate(withOwner: app, topLevelObjects: &topObjects) - app.run() -} ``` Running the app, diff --git a/SwiftAppLibrary/AppDelegate.swift b/SwiftAppLibrary/AppDelegate.swift index 3fc14ed..6998fa5 100644 --- a/SwiftAppLibrary/AppDelegate.swift +++ b/SwiftAppLibrary/AppDelegate.swift @@ -37,15 +37,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { } } -@_cdecl("runNSApplication") -func runNSApplication() { - let app = NSApplication.shared() - var topObjects: NSArray = [] - NSNib.init(nibNamed: "MainMenu", bundle: Bundle(for: AppDelegate.self))! - .instantiate(withOwner: app, topLevelObjects: &topObjects) - app.run() -} - // Swift to Haskell ByteString Example diff --git a/SwiftAppLibrary/SwiftAppLibrary.m b/SwiftAppLibrary/SwiftAppLibrary.m new file mode 100644 index 0000000..242e605 --- /dev/null +++ b/SwiftAppLibrary/SwiftAppLibrary.m @@ -0,0 +1,13 @@ +#import "SwiftAppLibrary.h" + +@interface AClassInThisFramework : NSObject @end +@implementation AClassInThisFramework @end + +void runNSApplication(void) { + NSApplication *app = [NSApplication sharedApplication]; + NSBundle *bundle = [NSBundle bundleForClass:[AClassInThisFramework class]]; + NSArray *topObjects; + [[[NSNib alloc] initWithNibNamed:@"MainMenu" bundle:bundle] + instantiateWithOwner:app topLevelObjects:&topObjects]; + [app run]; +} diff --git a/SwiftHaskell.xcodeproj/project.pbxproj b/SwiftHaskell.xcodeproj/project.pbxproj index 4eade78..6766037 100644 --- a/SwiftHaskell.xcodeproj/project.pbxproj +++ b/SwiftHaskell.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ BFABC4E01E4D781D006036C6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BFABC4DF1E4D781D006036C6 /* Assets.xcassets */; }; BFABC4ED1E4D78E5006036C6 /* SwiftHaskell in Copy Files */ = {isa = PBXBuildFile; fileRef = BFABC4EA1E4D78D9006036C6 /* SwiftHaskell */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; BFABC4F01E4D7951006036C6 /* SwiftAppLibrary.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFABC45B1E4C1DD1006036C6 /* SwiftAppLibrary.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + BFE4CC421E55553000F232D6 /* SwiftAppLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = BFE4CC411E55553000F232D6 /* SwiftAppLibrary.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,6 +61,7 @@ BFABC4DF1E4D781D006036C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; BFABC4E41E4D781D006036C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BFABC4EA1E4D78D9006036C6 /* SwiftHaskell */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = SwiftHaskell; path = build/SwiftHaskell; sourceTree = SOURCE_ROOT; }; + BFE4CC411E55553000F232D6 /* SwiftAppLibrary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SwiftAppLibrary.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,6 +97,7 @@ isa = PBXGroup; children = ( BFABC45E1E4C1DD1006036C6 /* SwiftAppLibrary.h */, + BFE4CC411E55553000F232D6 /* SwiftAppLibrary.m */, BFABC4CC1E4D627E006036C6 /* AppDelegate.swift */, BFABC4D01E4D664D006036C6 /* MainMenu.xib */, BFABC45F1E4C1DD1006036C6 /* Info.plist */, @@ -266,6 +269,7 @@ buildActionMask = 2147483647; files = ( BFABC4CD1E4D627E006036C6 /* AppDelegate.swift in Sources */, + BFE4CC421E55553000F232D6 /* SwiftAppLibrary.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };