diff --git a/contrib/mac/newapp/Julia.dist b/contrib/mac/newapp/Julia.dist
new file mode 100644
index 0000000000000..30526883962a8
--- /dev/null
+++ b/contrib/mac/newapp/Julia.dist
@@ -0,0 +1,26 @@
+
+
+ FRAMEWORK_NAME
+
+
+
+
+
+
+
+
+
+
+ FRAMEWORK_NAME-framework.pkg
+ launcher.pkg
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.pbxproj b/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000000..62124f9f54839
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.pbxproj
@@ -0,0 +1,335 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 50;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ DCECD36721B6461B0099A8C3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCECD36621B6461B0099A8C3 /* AppDelegate.m */; };
+ DCECD36921B6461C0099A8C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DCECD36821B6461C0099A8C3 /* Assets.xcassets */; };
+ DCECD36C21B6461C0099A8C3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCECD36A21B6461C0099A8C3 /* MainMenu.xib */; };
+ DCECD36F21B6461C0099A8C3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DCECD36E21B6461C0099A8C3 /* main.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ DCECD36221B6461B0099A8C3 /* Julia.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Julia.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ DCECD36521B6461B0099A8C3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
+ DCECD36621B6461B0099A8C3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
+ DCECD36821B6461C0099A8C3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ DCECD36B21B6461C0099A8C3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
+ DCECD36D21B6461C0099A8C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ DCECD36E21B6461C0099A8C3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
+ DCECD37021B6461C0099A8C3 /* JuliaLauncher.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = JuliaLauncher.entitlements; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ DCECD35F21B6461B0099A8C3 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ DCECD35921B6461B0099A8C3 = {
+ isa = PBXGroup;
+ children = (
+ DCECD36421B6461B0099A8C3 /* JuliaLauncher */,
+ DCECD36321B6461B0099A8C3 /* Products */,
+ );
+ sourceTree = "";
+ };
+ DCECD36321B6461B0099A8C3 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ DCECD36221B6461B0099A8C3 /* Julia.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ DCECD36421B6461B0099A8C3 /* JuliaLauncher */ = {
+ isa = PBXGroup;
+ children = (
+ DCECD36E21B6461C0099A8C3 /* main.m */,
+ DCECD36521B6461B0099A8C3 /* AppDelegate.h */,
+ DCECD36621B6461B0099A8C3 /* AppDelegate.m */,
+ DCECD36821B6461C0099A8C3 /* Assets.xcassets */,
+ DCECD36A21B6461C0099A8C3 /* MainMenu.xib */,
+ DCECD36D21B6461C0099A8C3 /* Info.plist */,
+ DCECD37021B6461C0099A8C3 /* JuliaLauncher.entitlements */,
+ );
+ path = JuliaLauncher;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ DCECD36121B6461B0099A8C3 /* JuliaLauncher */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DCECD37321B6461C0099A8C3 /* Build configuration list for PBXNativeTarget "JuliaLauncher" */;
+ buildPhases = (
+ DCECD35E21B6461B0099A8C3 /* Sources */,
+ DCECD35F21B6461B0099A8C3 /* Frameworks */,
+ DCECD36021B6461B0099A8C3 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = JuliaLauncher;
+ productName = JuliaLauncher;
+ productReference = DCECD36221B6461B0099A8C3 /* Julia.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ DCECD35A21B6461B0099A8C3 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1010;
+ ORGANIZATIONNAME = JuliaLang;
+ TargetAttributes = {
+ DCECD36121B6461B0099A8C3 = {
+ CreatedOnToolsVersion = 10.1;
+ SystemCapabilities = {
+ com.apple.HardenedRuntime = {
+ enabled = 1;
+ };
+ com.apple.Sandbox = {
+ enabled = 0;
+ };
+ };
+ };
+ };
+ };
+ buildConfigurationList = DCECD35D21B6461B0099A8C3 /* Build configuration list for PBXProject "JuliaLauncher" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = DCECD35921B6461B0099A8C3;
+ productRefGroup = DCECD36321B6461B0099A8C3 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ DCECD36121B6461B0099A8C3 /* JuliaLauncher */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ DCECD36021B6461B0099A8C3 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DCECD36921B6461C0099A8C3 /* Assets.xcassets in Resources */,
+ DCECD36C21B6461C0099A8C3 /* MainMenu.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ DCECD35E21B6461B0099A8C3 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DCECD36F21B6461C0099A8C3 /* main.m in Sources */,
+ DCECD36721B6461B0099A8C3 /* AppDelegate.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ DCECD36A21B6461C0099A8C3 /* MainMenu.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ DCECD36B21B6461C0099A8C3 /* Base */,
+ );
+ name = MainMenu.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ DCECD37121B6461C0099A8C3 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ DCECD37221B6461C0099A8C3 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ DCECD37421B6461C0099A8C3 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_ENTITLEMENTS = JuliaLauncher/JuliaLauncher.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ ENABLE_HARDENED_RUNTIME = YES;
+ INFOPLIST_FILE = JuliaLauncher/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = org.julialang.JuliaLauncher;
+ PRODUCT_NAME = Julia;
+ };
+ name = Debug;
+ };
+ DCECD37521B6461C0099A8C3 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_ENTITLEMENTS = JuliaLauncher/JuliaLauncher.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ ENABLE_HARDENED_RUNTIME = YES;
+ INFOPLIST_FILE = JuliaLauncher/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = org.julialang.JuliaLauncher;
+ PRODUCT_NAME = Julia;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ DCECD35D21B6461B0099A8C3 /* Build configuration list for PBXProject "JuliaLauncher" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DCECD37121B6461C0099A8C3 /* Debug */,
+ DCECD37221B6461C0099A8C3 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ DCECD37321B6461C0099A8C3 /* Build configuration list for PBXNativeTarget "JuliaLauncher" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DCECD37421B6461C0099A8C3 /* Debug */,
+ DCECD37521B6461C0099A8C3 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = DCECD35A21B6461B0099A8C3 /* Project object */;
+}
diff --git a/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000000..05896b2ee55dd
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000000000..18d981003d68d
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/contrib/mac/newapp/JuliaLauncher.xcodeproj/xcshareddata/xcschemes/JuliaLauncher.xcscheme b/contrib/mac/newapp/JuliaLauncher.xcodeproj/xcshareddata/xcschemes/JuliaLauncher.xcscheme
new file mode 100644
index 0000000000000..dbb4b36f469cf
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher.xcodeproj/xcshareddata/xcschemes/JuliaLauncher.xcscheme
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/mac/newapp/JuliaLauncher/AppDelegate.h b/contrib/mac/newapp/JuliaLauncher/AppDelegate.h
new file mode 100644
index 0000000000000..4441cd97cfd7f
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/AppDelegate.h
@@ -0,0 +1,7 @@
+// This file is a part of Julia. License is MIT: https://julialang.org/license
+
+@import AppKit;
+
+@interface AppDelegate : NSObject
+
+@end
diff --git a/contrib/mac/newapp/JuliaLauncher/AppDelegate.m b/contrib/mac/newapp/JuliaLauncher/AppDelegate.m
new file mode 100644
index 0000000000000..11f9bb202d36c
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/AppDelegate.m
@@ -0,0 +1,317 @@
+// This file is a part of Julia. License is MIT: https://julialang.org/license
+
+#import "AppDelegate.h"
+
+/// Terminal's bundle ID.
+NSString static const *const terminalBundleID = @"com.apple.Terminal";
+
+static bool launchTerminalApp(void);
+static void execJuliaInTerminal(NSURL *julia);
+
+@interface AppDelegate ()
+@property NSMetadataQuery *mdq;
+@end
+
+@implementation AppDelegate
+
+- (void)dealloc {
+ [self stopFindJuliaWithSpotlight];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ NSURL *juliaexe = [self findJuliaInLinkedFramework];
+ if (juliaexe != nil) {
+ execJuliaInTerminal(juliaexe);
+ } else {
+ [self findJuliaWithSpotlight];
+ }
+}
+
+- (NSURL *_Nullable)findJuliaInLinkedFramework {
+ // Try NSBundle's search by bundle ID for the Julia framework.
+ NSBundle *b = [NSBundle bundleWithIdentifier:@"org.julialang.julia.lib"];
+ if (b != nil) {
+ return [b URLForAuxiliaryExecutable:@"julia"];
+ }
+ return nil;
+}
+
+- (void)findJuliaQueryDidUpdate:(NSNotification *)sender {
+ // Disable updates while enumerating results.
+ [self.mdq disableUpdates];
+
+ for (NSUInteger i = 0; i < self.mdq.resultCount; ++i) {
+ // Grab the path attribute from the item.
+ NSMetadataItem *item = [self.mdq resultAtIndex:i];
+ NSURL *frameworkPath = [[NSURL alloc]
+ initFileURLWithPath:[item valueForAttribute:NSMetadataItemPathKey]
+ isDirectory:true];
+ NSLog(@"Found Julia framework %@", frameworkPath);
+
+ NSURL *frameworkVersions =
+ [frameworkPath URLByAppendingPathComponent:@"Versions"];
+
+ NSFileManager *fm = NSFileManager.defaultManager;
+ NSArray *versions =
+ [fm contentsOfDirectoryAtURL:frameworkVersions
+ includingPropertiesForKeys:@[ NSURLIsDirectoryKey ]
+ options:0
+ error:nil];
+
+ for (NSURL *frameworkVersion in versions) {
+ NSNumber *isDir;
+ if (![frameworkVersion getResourceValue:&isDir
+ forKey:NSURLIsDirectoryKey
+ error:nil] ||
+ !isDir.boolValue) {
+ continue;
+ }
+
+ NSBundle *bundle = [NSBundle bundleWithURL:frameworkVersion];
+
+ NSString *frameworkVersion =
+ bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
+ NSString *frameworkShortVersion =
+ bundle.infoDictionary[@"CFBundleShortVersionString"];
+
+ // Form the path to julia in the framework's Helpers directory.
+ NSURL *juliaexe = [[[[bundle.executableURL URLByResolvingSymlinksInPath]
+ URLByDeletingLastPathComponent] URLByAppendingPathComponent:@"Helpers"
+ isDirectory:true]
+ URLByAppendingPathComponent:@"julia"
+ isDirectory:false];
+
+ if (juliaexe != nil) {
+ NSLog(@"Found Julia %@ (%@) at %@", frameworkShortVersion,
+ frameworkVersion, juliaexe.path);
+ execJuliaInTerminal(juliaexe);
+ }
+ }
+ }
+
+ // Safe to enable updates now.
+ [self.mdq enableUpdates];
+}
+
+/// Start a Spotlight query for Julia frameworks.
+- (void)findJuliaWithSpotlight {
+ if (self.mdq != nil) {
+ // Query exists so return.
+ return;
+ }
+
+ self.mdq = [[NSMetadataQuery alloc] init];
+
+ // Search for the framework bundle identifier.
+ NSPredicate *searchPredicate = [NSPredicate
+ predicateWithFormat:
+ @"kMDItemCFBundleIdentifier == 'org.julialang.julia.lib'"];
+ self.mdq.predicate = searchPredicate;
+
+ // Include the framework's path as metadata.
+ self.mdq.valueListAttributes = @[ NSMetadataItemPathKey ];
+
+ // Observe the query's notifications.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(findJuliaQueryDidUpdate:)
+ name:NSMetadataQueryDidUpdateNotification
+ object:self.mdq];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(findJuliaQueryDidUpdate:)
+ name:NSMetadataQueryDidFinishGatheringNotification
+ object:self.mdq];
+
+ if (![self.mdq startQuery]) {
+ NSAlert *a = [[NSAlert alloc] init];
+ a.alertStyle = NSAlertStyleCritical;
+ a.messageText = NSLocalizedString(@"Cannot find the Julia framework.", );
+ a.informativeText =
+ NSLocalizedString(@"The Julia framework cannot be found. The Spotlight "
+ @"query for the Julia framework failed to start.", );
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [a runModal];
+ });
+ NSLog(@"Failed starting Julia spotlight search.");
+ [self stopFindJuliaWithSpotlight];
+ }
+}
+
+- (void)stopFindJuliaWithSpotlight {
+ if (self.mdq == nil) {
+ return;
+ }
+
+ [self.mdq stopQuery];
+
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:NSMetadataQueryDidUpdateNotification
+ object:self.mdq];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:NSMetadataQueryDidFinishGatheringNotification
+ object:self.mdq];
+
+ self.mdq = nil;
+}
+
+@end
+
+void execJuliaInTerminal(NSURL *julia) {
+ OSStatus s;
+ NSAlert *a = [[NSAlert alloc] init];
+ a.alertStyle = NSAlertStyleCritical;
+ a.messageText = NSLocalizedString(@"Cannot run the Julia REPL.", );
+
+ // Create the AE descriptor for the bundle ID of Terminal.
+ NSData *terminalBundleIDData =
+ [terminalBundleID dataUsingEncoding:NSUTF8StringEncoding];
+ NSAppleEventDescriptor *aedTarget = [NSAppleEventDescriptor
+ descriptorWithDescriptorType:typeApplicationBundleID
+ data:terminalBundleIDData];
+
+ // Command: activate
+ NSAppleEventDescriptor *aevActivate =
+ [NSAppleEventDescriptor appleEventWithEventClass:kAEMiscStandards
+ eventID:kAEActivate
+ targetDescriptor:aedTarget
+ returnID:kAutoGenerateReturnID
+ transactionID:kAnyTransactionID];
+
+ // Command: do shell script
+ NSAppleEventDescriptor *aevShellCmd =
+ [NSAppleEventDescriptor appleEventWithEventClass:kAECoreSuite
+ eventID:kAEDoScript
+ targetDescriptor:aedTarget
+ returnID:kAutoGenerateReturnID
+ transactionID:kAnyTransactionID];
+
+ // Set shell script as direct parameter.
+ char const *juliaFSRepCstr;
+ if (@available(macOS 10.9, *)) {
+ juliaFSRepCstr = julia.fileSystemRepresentation;
+ } else {
+ juliaFSRepCstr = julia.path.fileSystemRepresentation;
+ }
+ // Add ';' at start of command to mitigate a race condition.
+ // Between the time the shell opens and the "exec ..." command is inserted,
+ // it's possible for stray key events to insert leading to the command being
+ // "asdf;exec ..." (for example). The semicolon mitigates the stray key
+ // presses.
+ NSString *execJuliaCmd =
+ [NSString stringWithFormat:@";exec '%s'", juliaFSRepCstr];
+ NSAppleEventDescriptor *shellScript =
+ [NSAppleEventDescriptor descriptorWithString:execJuliaCmd];
+ [aevShellCmd setParamDescriptor:shellScript forKeyword:keyDirectObject];
+
+ if (@available(macOS 10.14, *)) {
+ bool retry = false;
+
+ do {
+ s = AEDeterminePermissionToAutomateTarget(
+ aedTarget.aeDesc, aevShellCmd.eventClass, aevShellCmd.eventID, true);
+ retry = s == procNotFound && !retry && launchTerminalApp();
+ } while (retry);
+
+ if (s == errAEEventNotPermitted) {
+ a.informativeText = NSLocalizedString(
+ @"The system prevented running the Julia REPL in the Terminal.", );
+ } else if (s == errAETargetAddressNotPermitted) {
+ a.informativeText = NSLocalizedString(
+ @"The system prevented sending AppleEvents to Terminal.", );
+ } else if (s == procNotFound) {
+ a.informativeText = NSLocalizedString(
+ @"Terminal is not running and could not be launched.", );
+ }
+
+ if (s != noErr) {
+ [[NSRunLoop mainRunLoop] performBlock:^{
+ [a runModal];
+ }];
+ NSLog(@"AEDeterminePermissionToAutomateTarget failed: %@",
+ [[NSError errorWithDomain:NSOSStatusErrorDomain code:s
+ userInfo:nil] localizedDescription]);
+ return;
+ }
+ }
+
+ s = AESendMessage(aevShellCmd.aeDesc, NULL, kAENoReply | kAECanInteract,
+ kAEDefaultTimeout);
+
+ if (s != noErr) {
+ a.informativeText = NSLocalizedString(@"\"do script\" command failed.", );
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [a runModal];
+ });
+ NSLog(@"\"do script\" failed: %@",
+ [[NSError errorWithDomain:NSOSStatusErrorDomain code:s
+ userInfo:nil] localizedDescription]);
+ return;
+ }
+
+ s = AESendMessage(aevActivate.aeDesc, NULL, kAENoReply | kAECanInteract,
+ kAEDefaultTimeout);
+
+ if (s != noErr) {
+ a.informativeText = NSLocalizedString(@"\"activate\" command failed.", );
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [a runModal];
+ });
+ NSLog(@"\"activate\" failed: %@",
+ [[NSError errorWithDomain:NSOSStatusErrorDomain code:s
+ userInfo:nil] localizedDescription]);
+ return;
+ }
+}
+
+bool launchTerminalApp(void) {
+ // Launch Terminal.app. Use newer or older API depending on OS version.
+
+ // Send hint to Terminal to not open a new window when opened.
+ NSAppleEventDescriptor *aedLaunchedAsServiceItem = [NSAppleEventDescriptor
+ descriptorWithEnumCode:keyAELaunchedAsServiceItem];
+
+ // Common launch URL spec for either old or new API.
+ LSLaunchURLSpec lspec = {.launchFlags = kLSLaunchDontSwitch,
+ .passThruParams = aedLaunchedAsServiceItem.aeDesc};
+
+ if (@available(macOS 10.10, *)) {
+ NSArray *terminalURLs =
+ (__bridge NSArray *)LSCopyApplicationURLsForBundleIdentifier(
+ (__bridge CFStringRef)terminalBundleID, NULL);
+ for (NSURL *terminalURL in terminalURLs) {
+ lspec.appURL = (__bridge CFURLRef)terminalURL;
+ OSStatus s = LSOpenFromURLSpec(&lspec, NULL);
+ if (s == noErr) {
+ return true;
+ } else {
+ NSLog(@"LSOpenFromURLSpec failed for %@\n%@", terminalURL,
+ [[NSError errorWithDomain:NSOSStatusErrorDomain
+ code:s
+ userInfo:nil] localizedDescription]);
+ }
+ }
+ } else {
+ CFURLRef terminalURL = NULL;
+ LSFindApplicationForInfo(kLSUnknownCreator,
+ (__bridge CFStringRef)terminalBundleID, NULL, NULL,
+ &terminalURL);
+ if (terminalURL != NULL) {
+ lspec.appURL = terminalURL;
+ OSStatus s = LSOpenFromURLSpec(&lspec, NULL);
+ CFRelease(terminalURL);
+ if (s == noErr) {
+ return true;
+ } else {
+ NSLog(@"LSOpenFromURLSpec failed for %@\n%@", terminalURL,
+ [[NSError errorWithDomain:NSOSStatusErrorDomain
+ code:s
+ userInfo:nil] localizedDescription]);
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/128.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/128.png
new file mode 100644
index 0000000000000..a3ea0c6f98767
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/128.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/128@2x.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/128@2x.png
new file mode 100644
index 0000000000000..eb5a0737fb439
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/128@2x.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/16.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/16.png
new file mode 100644
index 0000000000000..50f46aa80179f
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/16.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/16@2x.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/16@2x.png
new file mode 100644
index 0000000000000..f658786b9bf54
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/16@2x.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/256.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/256.png
new file mode 100644
index 0000000000000..c13e5c36cf6a2
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/256.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/256@2x.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/256@2x.png
new file mode 100644
index 0000000000000..4781fbbf401d9
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/256@2x.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/32.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/32.png
new file mode 100644
index 0000000000000..1822e86d61526
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/32.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/32@2x.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/32@2x.png
new file mode 100644
index 0000000000000..8fe905555b25c
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/32@2x.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/512.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/512.png
new file mode 100644
index 0000000000000..0bb203c1e01c7
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/512.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/512@2x.png b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/512@2x.png
new file mode 100644
index 0000000000000..01eee2eb4ab04
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/512@2x.png differ
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000000..2fe2dbc16b987
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,68 @@
+{
+ "images" : [
+ {
+ "size" : "16x16",
+ "idiom" : "mac",
+ "filename" : "16.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "16x16",
+ "idiom" : "mac",
+ "filename" : "16@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "32x32",
+ "idiom" : "mac",
+ "filename" : "32.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "32x32",
+ "idiom" : "mac",
+ "filename" : "32@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "128x128",
+ "idiom" : "mac",
+ "filename" : "128.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "128x128",
+ "idiom" : "mac",
+ "filename" : "128@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "256x256",
+ "idiom" : "mac",
+ "filename" : "256.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "256x256",
+ "idiom" : "mac",
+ "filename" : "256@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "512x512",
+ "idiom" : "mac",
+ "filename" : "512.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "512x512",
+ "idiom" : "mac",
+ "filename" : "512@2x.png",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/Contents.json b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/Contents.json
new file mode 100644
index 0000000000000..da4a164c91865
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/contrib/mac/newapp/JuliaLauncher/Base.lproj/MainMenu.xib b/contrib/mac/newapp/JuliaLauncher/Base.lproj/MainMenu.xib
new file mode 100644
index 0000000000000..aec55baf7b505
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/Base.lproj/MainMenu.xib
@@ -0,0 +1,679 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/mac/newapp/JuliaLauncher/Info.plist b/contrib/mac/newapp/JuliaLauncher/Info.plist
new file mode 100644
index 0000000000000..1bd50dd21b15b
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/Info.plist
@@ -0,0 +1,34 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIconFile
+
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(APP_SHORT_VERSION_STRING)
+ CFBundleVersion
+ $(APP_VERSION)
+ LSMinimumSystemVersion
+ $(MACOSX_DEPLOYMENT_TARGET)
+ NSHumanReadableCopyright
+ Copyright © 2009-2019 Julia project contributors (https://github.com/JuliaLang/julia/contributors). See LICENSE.md.
+ NSAppleEventsUsageDescription
+ Apple events are sent to the Terminal to execute the Julia REPL.
+ NSMainNibFile
+ MainMenu
+ NSPrincipalClass
+ NSApplication
+
+
diff --git a/contrib/mac/newapp/JuliaLauncher/JuliaLauncher.entitlements b/contrib/mac/newapp/JuliaLauncher/JuliaLauncher.entitlements
new file mode 100644
index 0000000000000..e48ecf963c8fe
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/JuliaLauncher.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.automation.apple-events
+
+ com.apple.security.temporary-exception.apple-events
+ com.apple.Terminal
+
+
diff --git a/contrib/mac/newapp/JuliaLauncher/julia.idraw b/contrib/mac/newapp/JuliaLauncher/julia.idraw
new file mode 100644
index 0000000000000..d3ffc06d61343
Binary files /dev/null and b/contrib/mac/newapp/JuliaLauncher/julia.idraw differ
diff --git a/contrib/mac/newapp/JuliaLauncher/main.m b/contrib/mac/newapp/JuliaLauncher/main.m
new file mode 100644
index 0000000000000..04aedef2e05fd
--- /dev/null
+++ b/contrib/mac/newapp/JuliaLauncher/main.m
@@ -0,0 +1,7 @@
+// This file is a part of Julia. License is MIT: https://julialang.org/license
+
+@import AppKit;
+
+int main(int argc, const char *argv[]) {
+ return NSApplicationMain(argc, argv);
+}
diff --git a/contrib/mac/newapp/Makefile b/contrib/mac/newapp/Makefile
new file mode 100644
index 0000000000000..0dc6c3472573a
--- /dev/null
+++ b/contrib/mac/newapp/Makefile
@@ -0,0 +1,120 @@
+JULIAHOME := $(abspath ../../..)
+include $(JULIAHOME)/Make.inc
+
+default: productarchive
+
+# The following variables default to development environment values.
+# For a build intended for distribution, they must be overridden.
+# Set APPLE_DISTRIBUTE_DEVID=1 to use automatic (It Just Works) distribution
+# signing.
+ifneq ($(APPLE_DISTRIBUTE_DEVID),1)
+# Identity to use for signing products.
+DARWIN_CODESIGN_KEYCHAIN_IDENTITY ?= Mac Developer
+# Identifier of Apple Developer team.
+APPLE_DEVELOPMENT_TEAM ?= unidentified
+# method value in -exportOptionsPlist flag to xcodebuild.
+XCEXPORT_METHOD ?= development
+# Identity for the product archive (the .pkg installer).
+DARWIN_CODESIGN_PRODUCT_ARCHIVE_KEYCHAIN_IDENTITY ?= -
+else
+DARWIN_CODESIGN_KEYCHAIN_IDENTITY ?= Developer ID Application
+APPLE_DEVELOPMENT_TEAM ?= unidentified
+XCEXPORT_METHOD ?= developer-id
+DARWIN_CODESIGN_PRODUCT_ARCHIVE_KEYCHAIN_IDENTITY ?= Developer ID Installer
+endif
+
+# X.Y.Z
+JULIA_VERSION_MAJOR_MINOR_PATCH := $(JULIA_MAJOR_VERSION).$(JULIA_MINOR_VERSION).$(JULIA_PATCH_VERSION)
+
+FRAMEWORK_DESTDIR := $(BUILDROOT)/julia-$(JULIA_COMMIT)-framework
+JULIA_FRAMEWORK_PATH := $(FRAMEWORK_DESTDIR)/$(framework_directory)
+JULIA_FRAMEWORK_LIB := $(FRAMEWORK_DESTDIR)/$(framework_dylib)
+
+# Xcode configurations:
+XCCONFIGURATION ?= Debug
+XCARCHIVE_SUFFIX := -$(JULIA_COMMIT)-$(XCCONFIGURATION).xcarchive
+XCARCHIVE := $(BUILDROOT)/Xcode/Archives/JuliaLauncher$(XCARCHIVE_SUFFIX)
+XCDERIVEDDATA := $(BUILDROOT)/Xcode/DerivedData/JuliaLauncher$(XCARCHIVE_SUFFIX)
+XCEXPORT := $(BUILDROOT)/Xcode/Exports/JuliaLauncher$(XCARCHIVE_SUFFIX)
+
+PRODUCTARCHIVE := $(BUILDROOT)/$(FRAMEWORK_NAME)-$(JULIA_VERSION).pkg
+
+$(JULIA_FRAMEWORK_LIB):
+ $(MAKE) -C $(JULIAHOME) DARWIN_FRAMEWORK=1 prefix=$(FRAMEWORK_DESTDIR) darwinframework
+
+$(XCARCHIVE)/Info.plist: $(JULIA_FRAMEWORK_LIB)
+ xcodebuild \
+ -project JuliaLauncher.xcodeproj \
+ -scheme JuliaLauncher \
+ -configuration $(XCCONFIGURATION) \
+ -archivePath $(XCARCHIVE) \
+ -derivedDataPath $(XCDERIVEDDATA) \
+ archive \
+ MACOSX_DEPLOYMENT_TARGET=$(MACOSX_DEPLOYMENT_TARGET) \
+ CODE_SIGN_STYLE=Manual \
+ DEVELOPMENT_TEAM="$(APPLE_DEVELOPMENT_TEAM)" \
+ CODE_SIGN_IDENTITY="$(DARWIN_CODESIGN_KEYCHAIN_IDENTITY)" \
+ JULIA_FRAMEWORK_PATH="$(JULIA_FRAMEWORK_PATH)" \
+ APP_SHORT_VERSION_STRING="$(JULIA_VERSION_MAJOR_MINOR_PATCH)" \
+ APP_VERSION="$(JULIA_COMMIT)"
+
+$(BUILDROOT)/xcodebuild-export.plist:
+ /usr/libexec/PlistBuddy -x -c "Clear dict" $@
+ /usr/libexec/PlistBuddy -x -c "Add :method string $(XCEXPORT_METHOD)" $@
+ /usr/libexec/PlistBuddy -x -c "Add :teamID string $(APPLE_DEVELOPMENT_TEAM)" $@
+
+
+$(XCEXPORT)/Julia.app/Contents/MacOS/Julia: $(XCARCHIVE)/Info.plist $(BUILDROOT)/xcodebuild-export.plist
+ xcodebuild -exportArchive -archivePath $(XCARCHIVE) -exportPath $(XCEXPORT) -exportOptionsPlist $(BUILDROOT)/xcodebuild-export.plist
+
+appexport: $(XCEXPORT)/Julia.app/Contents/MacOS/Julia
+
+$(BUILDROOT)/framework-component.plist: $(JULIAHOME)/contrib/mac/newapp/framework-component.plist
+ sed -e 's/FRAMEWORK_VERSION/$(FRAMEWORK_VERSION)/g' -e 's/FRAMEWORK_NAME/$(FRAMEWORK_NAME)/g' $< > $@
+
+# This target makes a component package for the framework. It has some
+# important and properties. The properties allow one "Julia.framework" to
+# exist at a location with multiple versions of Julia within.
+#
+# tree Julia.frameo
+#
+# 1. The component's identifer is versioned to match the bundled framework.
+$(BUILDROOT)/$(FRAMEWORK_NAME)-framework.pkg: $(JULIA_FRAMEWORK_LIB) $(BUILDROOT)/framework-component.plist
+ pkgbuild \
+ --install-location /Library/Frameworks \
+ --version $(JULIA_VERSION_MAJOR_MINOR_PATCH) \
+ --root $(FRAMEWORK_DESTDIR) \
+ --component-plist $(BUILDROOT)/framework-component.plist \
+ --identifier org.julialang.julia.lib.v$(FRAMEWORK_VERSION) \
+ $@
+
+$(BUILDROOT)/launcher.pkg: $(XCEXPORT)/Julia.app/Contents/MacOS/Julia
+ pkgbuild \
+ --install-location /Applications \
+ --version $(JULIA_VERSION_MAJOR_MINOR_PATCH) \
+ --component $(XCEXPORT)/Julia.app \
+ $@
+
+$(BUILDROOT)/$(FRAMEWORK_NAME).dist: $(JULIAHOME)/contrib/mac/newapp/Julia.dist
+ sed -e 's/MINVERSION/$(MACOSX_VERSION_MIN)/g' -e 's/FRAMEWORK_NAME/$(FRAMEWORK_NAME)/g' $< > $@
+
+$(PRODUCTARCHIVE): $(BUILDROOT)/launcher.pkg $(BUILDROOT)/$(FRAMEWORK_NAME)-framework.pkg $(BUILDROOT)/$(FRAMEWORK_NAME).dist $(JULIAHOME)/contrib/mac/newapp/installresources
+ productbuild \
+ --package-path $(BUILDROOT) \
+ --resources $(JULIAHOME)/contrib/mac/newapp/installresources \
+ --distribution $(BUILDROOT)/$(FRAMEWORK_NAME).dist \
+ $@
+
+productarchive: $(PRODUCTARCHIVE)
+
+signedproductarchive: $(PRODUCTARCHIVE)
+ productsign --sign $(DARWIN_CODESIGN_PRODUCT_ARCHIVE_KEYCHAIN_IDENTITY) $< $<.signed
+ mv $<.signed $<
+
+clean:
+ -rm -rf $(XCARCHIVE) $(XCDERIVEDDATA) $(XCEXPORT)
+ -rm -rf $(FRAMEWORK_DESTDIR)
+ -rm -f $(PRODUCTARCHIVE)
+
+.PHONY: appexport clean productarchive signedproductarchive
+.INTERMEDIATE: $(BUILDROOT)/xcodebuild-export.plist $(BUILDROOT)/framework-component.plist $(BUILDROOT)/$(FRAMEWORK_NAME)-framework.pkg $(BUILDROOT)/launcher.pkg $(BUILDROOT)/$(FRAMEWORK_NAME).dist
diff --git a/contrib/mac/newapp/README.md b/contrib/mac/newapp/README.md
new file mode 100644
index 0000000000000..43cee0ee3716a
--- /dev/null
+++ b/contrib/mac/newapp/README.md
@@ -0,0 +1,26 @@
+New Julia Launcher App
+======================
+
+This builds the Julia framework and a launcher app and packages them in a
+product archive for the macOS Installer.
+
+Run `make APPLE_DEVELOPMENT_TEAM=xxxxxxxxxx` to build the product archive. The
+resulting archive may be installed to the home directory with
+`installer -pkg~/Documents/pkgs/Julia-1.1.0.pkg -target CurrentUserHomeDirectory`.
+To just build the app, build the `appexport` make target. Read the comments at
+the top of the `Makefile` to set appropriate code signing parameters.
+
+The framework is installed in `/Library/Frameworks` and the app in
+`/Applications`. Installation may be system-wide (i.e., relative to `/`) or
+local to the user's home directory (i.e., `$Home/Appliations/Julia.app`).
+
+The `julia` binary is embedded in the framework at
+`Julia.framework/Helpers/julia`.
+
+Multiple versions of Julia may be installed at once. Each version is placed in
+the `Julia.framework/Versions` directory. By default, the version is
+identified by the Major.Minor version number but may be customized by setting
+the `FRAMEWORK_VERSION` make variable. The resulting product archive will not
+overwrite other versions but will upgrade a version if it exists. Thus, the
+`1.1` framework version that is actually the 3rd patch (1.1.3) will overwrite
+any existing `1.1` framework version.
diff --git a/contrib/mac/newapp/framework-component.plist b/contrib/mac/newapp/framework-component.plist
new file mode 100644
index 0000000000000..43f71a18dc0f6
--- /dev/null
+++ b/contrib/mac/newapp/framework-component.plist
@@ -0,0 +1,18 @@
+
+
+
+
+
+ BundleIsVersionChecked
+
+ BundleHasStrictIdentifier
+
+ BundleIsRelocatable
+
+ BundleOverwriteAction
+ upgrade
+ RootRelativeBundlePath
+ FRAMEWORK_NAME.framework/Versions/FRAMEWORK_VERSION
+
+
+
diff --git a/contrib/mac/newapp/installresources/conclusion.rtf b/contrib/mac/newapp/installresources/conclusion.rtf
new file mode 100644
index 0000000000000..8d794ae31c04b
--- /dev/null
+++ b/contrib/mac/newapp/installresources/conclusion.rtf
@@ -0,0 +1,80 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf200
+{\fonttbl\f0\fswiss\fcharset0 Helvetica-Bold;\f1\fswiss\fcharset0 Helvetica;\f2\fnil\fcharset0 Menlo-Regular;
+}
+{\colortbl;\red255\green255\blue255;\red249\green249\blue249;}
+{\*\expandedcolortbl;;\cssrgb\c98039\c98039\c98039;}
+{\info
+{\author Stephen Larew}}\margl1440\margr1440\vieww14400\viewh9600\viewkind0
+\deftab720
+\pard\pardeftab720\sb120\sa200\partightenfactor0
+
+\f0\b\fs40 \cf0 \expnd0\expndtw0\kerning0
+Conclusion\
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+
+\f1\b0\fs28 \cf0 Julia is now installed. Running Julia.app will open a REPL for Julia in Terminal.\
+\pard\pardeftab720\sb120\sa200\partightenfactor0
+
+\f0\b\fs40 \cf0 Command Line
+\f1\b0\fs28 \
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+\cf0 The
+\f2 \cb2 julia
+\f1 \cb1 executable is located at
+\f2 \cb2 Julia.framework/Helpers/julia
+\f1 \cb1 inside the Julia framework. In a shell, run\
+\pard\pardeftab720\partightenfactor0
+
+\f2 \cf0 \cb2 mdfind "kMDItemCFBundleIdentifier == 'org.julialang.julia.lib' && kMDItemContentType == 'com.apple.framework'"\
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+
+\f1 \cf0 \cb1 to find the Julia frameworks on your system. Alternatively, run\
+\pard\pardeftab720\partightenfactor0
+
+\f2 \cf0 \cb2 mdfind "kMDItemFSName == 'julia' && kMDItemContentType == 'public.unix-executable'"\
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+
+\f1 \cf0 \cb1 to find julia executables on your system. (The commands assume the files are indexed and searchable by Spotlight.)\
+\pard\pardeftab720\sb120\sa200\partightenfactor0
+
+\f0\b\fs40 \cf0 Uninstall\
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+
+\f1\b0\fs28 \cf0 To uninstall, simply remove
+\f2 \cb2 [/Applications/]Julia.app
+\f1 \cb1 and
+\f2 \cb2 [/Library/Frameworks/]Julia.framework
+\f1 \cb1 (e.g. move it to the Trash in Finder or use the
+\f2 \cb2 rm
+\f1 \cb1 program from a shell).\
+\pard\pardeftab720\sb120\sa200\partightenfactor0
+
+\f0\b\fs40 \cf0 Path Modification\
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+
+\f1\b0\fs28 \cf0 In order for the shell to find and run the
+\f2 \cb2 julia
+\f1 \cb1 command, the
+\f2 \cb2 PATH
+\f1 \cb1 environment variable must contain the path to the
+\f2 \cb2 julia
+\f1 \cb1 binary. Either add
+\f2 \cb2 INSTALL_LOCATION/Julia.framework/Helpers
+\f1 \cb1 to
+\f2 \cb2 PATH
+\f1 \cb1 , for example in Bash shell\
+\pard\pardeftab720\partightenfactor0
+
+\f2 \cf0 \cb2 export PATH=INSTALL_LOCATION/Julia.framework/Helpers:$PATH\
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+
+\f1 \cf0 \cb1 or link a file in
+\f2 \cb2 PATH
+\f1 \cb1 to
+\f2 \cb2 INSTALL_LOCATION/Julia.framework/Helpers/julia
+\f1 \cb1 , for example by creating a symlink with
+\f2 \cb2 ln
+\f1 \cb1 \
+\pard\pardeftab720\partightenfactor0
+
+\f2 \cf0 \cb2 ln -s INSTALL_LOCATION/Julia.framework/Helpers/julia DIR_IN_PATH/julia}
\ No newline at end of file
diff --git a/contrib/mac/newapp/installresources/logo_hires.png b/contrib/mac/newapp/installresources/logo_hires.png
new file mode 100644
index 0000000000000..052549b42c627
Binary files /dev/null and b/contrib/mac/newapp/installresources/logo_hires.png differ
diff --git a/contrib/mac/newapp/installresources/readme.rtf b/contrib/mac/newapp/installresources/readme.rtf
new file mode 100644
index 0000000000000..d555047dd5c1c
--- /dev/null
+++ b/contrib/mac/newapp/installresources/readme.rtf
@@ -0,0 +1,31 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf200
+{\fonttbl\f0\fswiss\fcharset0 Helvetica-Bold;\f1\fswiss\fcharset0 Helvetica;\f2\fnil\fcharset0 Menlo-Regular;
+}
+{\colortbl;\red255\green255\blue255;\red249\green249\blue249;}
+{\*\expandedcolortbl;;\cssrgb\c98039\c98039\c98039;}
+{\info
+{\author Stephen Larew}}\margl1440\margr1440\vieww14400\viewh9600\viewkind0
+\deftab720
+\pard\pardeftab720\sb120\sa200\partightenfactor0
+
+\f0\b\fs40 \cf0 \expnd0\expndtw0\kerning0
+Readme\
+\pard\pardeftab720\sb80\sa120\partightenfactor0
+
+\f1\b0\fs28 \cf0 This package contains the Julia language distribution.\
+
+\f0\b\fs40 Install Location\
+
+\f1\b0\fs28 The default install locations of
+\f2 \cb2 /Applications/Julia.app
+\f1 \cb1 and
+\f2 \cb2 /Library/Frameworks/Julia.framework
+\f1 \cb1 are accessible to all users on the system and require admin privileges to proceed. If admin privileges are not obtainable or system-wide accessibility is not desired, choose \'93Change Install Location\'85\'94 in the next step and choose \'93Install for me only\'94 to change the default location to
+\f2 \cb2 $HOME/Applications/Julia.app
+\f1 \cb1 and
+\f2 \cb2 $HOME/Library/Frameworks/Julia.framework
+\f1 \cb1 (
+\f2 \cb2 $HOME
+\f1 \cb1 usually expands to
+\f2 \cb2 /Users/username
+\f1 \cb1 ).}
\ No newline at end of file