diff --git a/native/MacLauncher/.idea/.name b/native/MacLauncher/.idea/.name new file mode 100644 index 000000000000..dc9c257507df --- /dev/null +++ b/native/MacLauncher/.idea/.name @@ -0,0 +1 @@ +MacLauncher \ No newline at end of file diff --git a/native/MacLauncher/.idea/AppLauncher.iml b/native/MacLauncher/.idea/AppLauncher.iml new file mode 100644 index 000000000000..f9b36de1f5ad --- /dev/null +++ b/native/MacLauncher/.idea/AppLauncher.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/native/MacLauncher/.idea/dictionaries/max.xml b/native/MacLauncher/.idea/dictionaries/max.xml new file mode 100644 index 000000000000..81b3e8d28e3b --- /dev/null +++ b/native/MacLauncher/.idea/dictionaries/max.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/native/MacLauncher/.idea/encodings.xml b/native/MacLauncher/.idea/encodings.xml new file mode 100644 index 000000000000..e206d70d8595 --- /dev/null +++ b/native/MacLauncher/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/native/MacLauncher/.idea/find.xml b/native/MacLauncher/.idea/find.xml new file mode 100644 index 000000000000..689233077885 --- /dev/null +++ b/native/MacLauncher/.idea/find.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/native/MacLauncher/.idea/misc.xml b/native/MacLauncher/.idea/misc.xml new file mode 100644 index 000000000000..11e74ae401cf --- /dev/null +++ b/native/MacLauncher/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + http://www.w3.org/1999/xhtml + + + + diff --git a/native/MacLauncher/.idea/modules.xml b/native/MacLauncher/.idea/modules.xml new file mode 100644 index 000000000000..e77446284f14 --- /dev/null +++ b/native/MacLauncher/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/native/MacLauncher/.idea/scopes/scope_settings.xml b/native/MacLauncher/.idea/scopes/scope_settings.xml new file mode 100644 index 000000000000..922003b8433b --- /dev/null +++ b/native/MacLauncher/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/native/MacLauncher/.idea/vcs.xml b/native/MacLauncher/.idea/vcs.xml new file mode 100644 index 000000000000..9ab281ac88c7 --- /dev/null +++ b/native/MacLauncher/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/native/MacLauncher/.idea/xcode.xml b/native/MacLauncher/.idea/xcode.xml new file mode 100644 index 000000000000..28f4cb3a0788 --- /dev/null +++ b/native/MacLauncher/.idea/xcode.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/native/MacLauncher/Info.plist b/native/MacLauncher/Info.plist new file mode 100644 index 000000000000..a189b85581e3 --- /dev/null +++ b/native/MacLauncher/Info.plist @@ -0,0 +1,72 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + JetBrains.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + Java + + ClassPath + $APP_PACKAGE + MainClass + com.intellij.idea.Main + Properties + + CVS_PASSFILE + ~/.cvspass + apple.laf.useScreenMenuBar + true + com.apple.mrj.application.live-resize + false + idea.config.path + ~/Library/Preferences/IntelliJIdea10CE/ + idea.is.internal + true + idea.log.path + ~/Library/Logs/IntelliJIdea10CE/ + idea.platform.prefix + Idea + idea.plugins.path + ~/Library/Application Support/IntelliJIdea10CE/ + idea.system.path + ~/Library/Caches/IntelliJIdea10CE/ + idea.use.default.antialiasing.in.editor + true + + VMOptions + -ea + VMOptions.i386 + -Xms128m -Xmx512m -XX:MaxPermSize=250m + VMOptions.x86_64 + -Xms128m -Xmx800m -XX:MaxPermSize=350m -XX:+UseCompressedOops -XX:ReservedCodeCacheSize=256m + WorkingDirectory + $APP_PACKAGE/bin + + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSHumanReadableCopyright + Copyright © 2012 JetBrains inc. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/native/MacLauncher/Launcher.h b/native/MacLauncher/Launcher.h new file mode 100644 index 000000000000..82914da419be --- /dev/null +++ b/native/MacLauncher/Launcher.h @@ -0,0 +1,17 @@ +// +// Created by max on 5/4/12. +// +// To change the template use AppCode | Preferences | File Templates. +// + + +#import +#import + + +@interface Launcher : NSObject +- (id)initWithArgc:(int)anArgc argv:(char **)anArgv; + + +- (void) launch; +@end \ No newline at end of file diff --git a/native/MacLauncher/Launcher.m b/native/MacLauncher/Launcher.m new file mode 100644 index 000000000000..f351405089b4 --- /dev/null +++ b/native/MacLauncher/Launcher.m @@ -0,0 +1,374 @@ +// +// Created by max on 5/4/12. +// +// To change the template use AppCode | Preferences | File Templates. +// + + +#import "Launcher.h" +#import "VMOptionsReader.h" +#import "PropertyFileReader.h" +#import "utils.h" +#import + +typedef jint (JNICALL *fun_ptr_t_CreateJavaVM)(JavaVM **pvm, void **env, void *args); + + +@implementation NSString (CustomReplacements) +- (NSString *)replaceAll:(NSString *)pattern to:(NSString *)replacement { + if ([self rangeOfString:pattern].length == 0) return self; + + NSMutableString *answer = [self mutableCopy]; + [answer replaceOccurrencesOfString:pattern withString:replacement options:0 range:NSMakeRange(0, [self length])]; + return answer; +} +@end + +@implementation NSDictionary (TypedGetters) +- (NSDictionary *)dictionaryForKey:(id)key { + id answer = [self objectForKey:key]; + if ([answer isKindOfClass:[NSDictionary class]]) { + return answer; + } + return nil; +} + +- (id)valueForKey:(NSString *)key inDictionary:(NSString *)dictKey default: (NSString*) defaultValue { + NSDictionary *dict = [self dictionaryForKey:dictKey]; + if (dict == nil) return nil; + id answer = [dict valueForKey:key]; + return answer != nil ? answer : defaultValue; +} +@end + +@implementation Launcher { + int argc; + char **argv; +} + +- (id)initWithArgc:(int)anArgc argv:(char **)anArgv { + self = [super init]; + if (self) { + argc = anArgc; + argv = anArgv; + } + + return self; +} + + +void appendJvmBundlesAt(NSString *path, NSMutableArray *sink) { + NSError *error; + NSArray *names = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error]; + + if (!error) { + for (NSString *name in names) { + if ([name hasSuffix:@".jdk"] || [name hasSuffix:@".jre"]) { + NSBundle *bundle = [NSBundle bundleWithPath:[path stringByAppendingPathComponent:name]]; + if (bundle != nil) { + [sink addObject:bundle]; + } + } + } + } +} + +NSArray *allVms() { + NSMutableArray *jvmBundlePaths = [NSMutableArray array]; + + NSString *explicit = [[[NSProcessInfo processInfo] environment] objectForKey:@"IDEA_JDK"]; + + if (explicit != nil) { + appendJvmBundlesAt(explicit, jvmBundlePaths); + } + else { + NSBundle *bundle = [NSBundle mainBundle]; + NSString *appDir = bundle.bundlePath; + + appendJvmBundlesAt([appDir stringByAppendingPathComponent:@"jre"], jvmBundlePaths); + if (jvmBundlePaths.count > 0) return jvmBundlePaths; + + appendJvmBundlesAt([NSHomeDirectory() stringByAppendingPathComponent:@"Library/Java/JavaVirtualMachines"], jvmBundlePaths); + appendJvmBundlesAt(@"/Library/Java/JavaVirtualMachines", jvmBundlePaths); + appendJvmBundlesAt(@"/System/Library/Java/JavaVirtualMachines", jvmBundlePaths); + } + + return jvmBundlePaths; +} + +NSString *jvmVersion(NSBundle *bundle) { + return [bundle.infoDictionary valueForKey:@"JVMVersion" inDictionary:@"JavaVM" default: @"0"]; +} + +NSString *requiredJvmVersion() { + return [[NSBundle mainBundle].infoDictionary valueForKey:@"JVMVersion" inDictionary:@"Java" default: @"1.7*"]; +} + +BOOL satisfies(NSString *vmVersion, NSString *requiredVersion) { + if ([requiredVersion hasSuffix:@"+"]) { + requiredVersion = [requiredVersion substringToIndex:[requiredVersion length] - 1]; + return [requiredVersion compare:vmVersion options:NSNumericSearch] <= 0; + } + + if ([requiredVersion hasSuffix:@"*"]) { + requiredVersion = [requiredVersion substringToIndex:[requiredVersion length] - 1]; + } + + return [vmVersion hasPrefix:requiredVersion]; +} + +NSBundle *findMatchingVm() { + NSArray *vmBundles = [allVms() sortedArrayUsingComparator:^NSComparisonResult(id b1, id b2) { + return [jvmVersion(b2) compare:jvmVersion(b1) options:NSNumericSearch]; + }]; + + if (isDebugEnabled()) { + debugLog(@"Found Java Virtual Machines:"); + for (NSBundle *vm in vmBundles) { + debugLog([vm bundlePath]); + } + } + + NSString *required = requiredJvmVersion(); + debugLog([NSString stringWithFormat:@"Required VM: %@", required]); + + for (NSBundle *vm in vmBundles) { + if (satisfies(jvmVersion(vm), required)) { + debugLog(@"Chosen VM:"); + debugLog([vm bundlePath]); + return vm; + } + } + + debugLog(@"No matching VM found"); + + return nil; +} + +CFBundleRef NSBundle2CFBundle(NSBundle *bundle) { + CFURLRef bundleURL = (__bridge CFURLRef) bundle.bundleURL; + return CFBundleCreate(kCFAllocatorDefault, bundleURL); +} + +- (NSString *)expandMacros:(NSString *)str { + return [[str + replaceAll:@"$APP_PACKAGE" to:[[NSBundle mainBundle] bundlePath]] + replaceAll:@"$USER_HOME" to:NSHomeDirectory()]; +} + +- (NSMutableString *)buildClasspath:(NSBundle *)jvm { + NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"]; + NSMutableString *classpathOption = [NSMutableString stringWithString:@"-Djava.class.path="]; + [classpathOption appendString:[jvmInfo objectForKey:@"ClassPath"]]; + + NSString *toolsJar = [[jvm bundlePath] stringByAppendingString:@"/Contents/Home/lib/tools.jar"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:toolsJar]) { + [classpathOption appendString:@":"]; + [classpathOption appendString:toolsJar]; + } + return classpathOption; +} + + +NSString *getSelector() { + NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"]; + NSDictionary *properties = [jvmInfo dictionaryForKey:@"Properties"]; + if (properties != nil) { + return [properties objectForKey:@"idea.paths.selector"]; + } + return nil; +} + +NSString *getPreferencesFolderPath() { + return [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), getSelector()]; +} + +NSString *getPropertiesFilePath() { + return [getPreferencesFolderPath() stringByAppendingString:@"/idea.properites"]; +} + +NSString *getDefaultPropertiesFilePath() { + return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/bin/idea.properties"]; +} + +NSString *getDefaultVMOptionsFilePath() { + return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/bin/idea.vmoptions"]; +} + +NSString *getVMOptionsFilePath() { + return [getPreferencesFolderPath() stringByAppendingString:@"/idea.vmoptions"]; +} + +NSArray *parseVMOptions() { + NSArray *inConfig=[VMOptionsReader readFile:getVMOptionsFilePath()]; + if (inConfig) return inConfig; + return [VMOptionsReader readFile:getDefaultVMOptionsFilePath()]; +} + +NSDictionary *parseProperties() { + NSDictionary *inConfig = [PropertyFileReader readFile:getPropertiesFilePath()]; + if (inConfig) return inConfig; + return [PropertyFileReader readFile:getDefaultPropertiesFilePath()]; +} + +- (JavaVMInitArgs)buildArgsFor:(NSBundle *)jvm { + NSMutableString *classpathOption = [self buildClasspath:jvm]; + + NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"]; + NSMutableArray *args_array = [NSMutableArray array]; + + [args_array addObject:classpathOption]; + + [args_array addObjectsFromArray:[[jvmInfo objectForKey:@"VMOptions"] componentsSeparatedByString:@" "]]; + [args_array addObjectsFromArray:parseVMOptions()]; + + void (^propertySink)(id,id,BOOL *)=^(id key, id obj, BOOL *stop) { + [args_array addObject:[NSString stringWithFormat:@"-D%@=%@", key, obj]]; + }; + + NSDictionary *properties = [jvmInfo dictionaryForKey:@"Properties"]; + if (properties != nil) { + [properties enumerateKeysAndObjectsUsingBlock:propertySink]; + } + + [parseProperties() enumerateKeysAndObjectsUsingBlock:propertySink]; + + JavaVMInitArgs args; + args.version = JNI_VERSION_1_6; + args.ignoreUnrecognized = JNI_TRUE; + + args.nOptions = [args_array count]; + args.options = calloc((size_t) args.nOptions, sizeof(JavaVMOption)); + [args_array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + args.options[idx].optionString = strdup([[self expandMacros:[obj description]] UTF8String]); + }]; + return args; +} + +- (const char *)mainClassName { + NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"]; + char *answer = strdup([[jvmInfo objectForKey:@"MainClass"] UTF8String]); + + char *cur = answer; + while (*cur) { + if (*cur == '.') { + *cur = '/'; + } + cur++; + } + + return answer; +} + +- (void)process_cwd { + NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"Java"]; + NSString *cwd = [jvmInfo objectForKey:@"WorkingDirectory"]; + if (cwd != nil) { + cwd = [self expandMacros:cwd]; + if (chdir([cwd UTF8String]) != 0) { + NSLog(@"Cannot chdir to working directory at %@", cwd); + } + } +} + +- (void)launch { + NSBundle *vm = findMatchingVm(); + if (vm == nil) { + NSString *old_launcher = [self expandMacros:@"$APP_PACKAGE/Contents/MacOS/idea_appLauncher"]; + execv([old_launcher fileSystemRepresentation], self->argv); + + NSLog(@"Cannot find matching VM, aborting"); + exit(-1); + } + + NSError *error; + BOOL ok = [vm loadAndReturnError:&error]; + if (!ok || error != nil) { + NSLog(@"Cannot load JVM bundle: %@", error); + exit(-1); + } + + CFBundleRef cfvm = NSBundle2CFBundle(vm); + + fun_ptr_t_CreateJavaVM create_vm = CFBundleGetFunctionPointerForName(cfvm, CFSTR("JNI_CreateJavaVM")); + + if (create_vm == NULL) { + // We have Apple VM chosen here... +/* + [self execCommandLineJava:vm]; + return; +*/ + + NSString *serverLibUrl = [vm.bundlePath stringByAppendingPathComponent:@"Contents/Libraries/libserver.dylib"]; + + void *libHandle = dlopen(serverLibUrl.UTF8String, RTLD_NOW + RTLD_GLOBAL); + if (libHandle) { + create_vm = dlsym(libHandle, "JNI_CreateJavaVM_Impl"); + } + } + + if (create_vm == NULL) { + NSLog(@"Cannot find JNI_CreateJavaVM in chosen JVM bundle at %@", vm.bundlePath); + exit(-1); + } + + [self process_cwd]; + + JNIEnv *env; + JavaVM *jvm; + + JavaVMInitArgs args = [self buildArgsFor:vm]; + + jint create_vm_rc = create_vm(&jvm, &env, &args); + if (create_vm_rc != JNI_OK || jvm == NULL) { + NSLog(@"JNI_CreateJavaVM (%@) failed: %d", vm.bundlePath, create_vm_rc); + exit(-1); + } + + jclass string_class = (*env)->FindClass(env, "java/lang/String"); + if (string_class == NULL) { + NSLog(@"No java.lang.String in classpath!"); + exit(-1); + } + + const char *mainClassName = [self mainClassName]; + jclass mainClass = (*env)->FindClass(env, mainClassName); + if (mainClass == NULL || (*env)->ExceptionOccurred(env)) { + NSLog(@"Main class %s not found", mainClassName); + (*env)->ExceptionDescribe(env); + exit(-1); + } + + jmethodID mainMethod = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); + if (mainMethod == NULL || (*env)->ExceptionOccurred(env)) { + NSLog(@"Cant't find main() method"); + (*env)->ExceptionDescribe(env); + exit(-1); + } + + // See http://stackoverflow.com/questions/10242115/os-x-strange-psn-command-line-parameter-when-launched-from-finder + // about psn_ stuff + int arg_count = 0; + for (int i = 1; i < argc; i++) { + if (memcmp(argv[i], "-psn_", 4) != 0) arg_count++; + } + + jobject jni_args = (*env)->NewObjectArray(env, arg_count, string_class, NULL); + + arg_count = 0; + for (int i = 1; i < argc; i++) { + if (memcmp(argv[i], "-psn_", 4) != 0) { + jstring jni_arg = (*env)->NewStringUTF(env, argv[i]); + (*env)->SetObjectArrayElement(env, jni_args, arg_count, jni_arg); + arg_count++; + } + } + + (*env)->CallStaticVoidMethod(env, mainClass, mainMethod, jni_args); + + (*jvm)->DetachCurrentThread(jvm); + (*jvm)->DestroyJavaVM(jvm); +} + + +@end \ No newline at end of file diff --git a/native/MacLauncher/Launcher.pch b/native/MacLauncher/Launcher.pch new file mode 100644 index 000000000000..7504e2dc804d --- /dev/null +++ b/native/MacLauncher/Launcher.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'Launcher' target in the 'Launcher' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/native/MacLauncher/MacLauncher.xcodeproj/project.pbxproj b/native/MacLauncher/MacLauncher.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..c84184267714 --- /dev/null +++ b/native/MacLauncher/MacLauncher.xcodeproj/project.pbxproj @@ -0,0 +1,257 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1A5645DB6F789D018FF4A4AF /* PropertyFileReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A5645FEAD4A0FF166644D97 /* PropertyFileReader.m */; }; + 1A564BCFE66693BF0B2DD4A9 /* VMOptionsReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EDDE28564EF1AEBCD13 /* VMOptionsReader.m */; }; + 1A564C27F0BA05F900F34907 /* utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A564EEF77B93DBD7FD23161 /* utils.m */; }; + 50E17738155444B900E97451 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50E17737155444B900E97451 /* Cocoa.framework */; }; + 50E1775715552D2900E97451 /* JavaVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0B58A123544A15DA59B13E3 /* JavaVM.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + C0B58A123544A15DA59B13E4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0B58A123544A15DA59B13DC /* main.m */; }; + C0B58A123544A15DA59B13E5 /* Launcher.m in Sources */ = {isa = PBXBuildFile; fileRef = C0B58A123544A15DA59B13E0 /* Launcher.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1A5645FEAD4A0FF166644D97 /* PropertyFileReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PropertyFileReader.m; sourceTree = ""; }; + 1A564A1031F4C91C464C1B75 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = ""; }; + 1A564D7CEEAA02F14A6D4F20 /* VMOptionsReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMOptionsReader.h; sourceTree = ""; }; + 1A564EDDE28564EF1AEBCD13 /* VMOptionsReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VMOptionsReader.m; sourceTree = ""; }; + 1A564EEF77B93DBD7FD23161 /* utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = utils.m; sourceTree = ""; }; + 1A564F6D5833A0B9CE6E2839 /* PropertyFileReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyFileReader.h; sourceTree = ""; }; + 50E17735155444B900E97451 /* Launcher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Launcher.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 50E17737155444B900E97451 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 50E1773F155444B900E97451 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 50E17745155444B900E97451 /* Launcher.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Launcher.pch; sourceTree = ""; }; + C0B58A123544A15DA59B13DC /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + C0B58A123544A15DA59B13DE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + C0B58A123544A15DA59B13E0 /* Launcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Launcher.m; sourceTree = ""; }; + C0B58A123544A15DA59B13E2 /* Launcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Launcher.h; sourceTree = ""; }; + C0B58A123544A15DA59B13E3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = System/Library/Frameworks/JavaVM.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 50E17732155444B900E97451 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 50E1775715552D2900E97451 /* JavaVM.framework in Frameworks */, + 50E17738155444B900E97451 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C0B58A123544A15DA59B13CA = { + isa = PBXGroup; + children = ( + C0B58A123544A15DA59B13DC /* main.m */, + C0B58A123544A15DA59B13E0 /* Launcher.m */, + C0B58A123544A15DA59B13E2 /* Launcher.h */, + 50E17745155444B900E97451 /* Launcher.pch */, + 50E1773F155444B900E97451 /* Info.plist */, + C0B58A123544A15DA59B13CB /* Products */, + C0B58A123544A15DA59B13D6 /* Frameworks */, + 1A5645FEAD4A0FF166644D97 /* PropertyFileReader.m */, + 1A564F6D5833A0B9CE6E2839 /* PropertyFileReader.h */, + 1A564EDDE28564EF1AEBCD13 /* VMOptionsReader.m */, + 1A564D7CEEAA02F14A6D4F20 /* VMOptionsReader.h */, + 1A564A1031F4C91C464C1B75 /* utils.h */, + 1A564EEF77B93DBD7FD23161 /* utils.m */, + ); + sourceTree = ""; + }; + C0B58A123544A15DA59B13CB /* Products */ = { + isa = PBXGroup; + children = ( + 50E17735155444B900E97451 /* Launcher.app */, + ); + name = Products; + sourceTree = ""; + }; + C0B58A123544A15DA59B13D6 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C0B58A123544A15DA59B13E3 /* JavaVM.framework */, + C0B58A123544A15DA59B13DE /* Foundation.framework */, + 50E17737155444B900E97451 /* Cocoa.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 50E17734155444B900E97451 /* Launcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50E17751155444BA00E97451 /* Build configuration list for PBXNativeTarget "Launcher" */; + buildPhases = ( + 50E17731155444B900E97451 /* Sources */, + 50E17732155444B900E97451 /* Frameworks */, + 50E17733155444B900E97451 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Launcher; + productName = Launcher; + productReference = 50E17735155444B900E97451 /* Launcher.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C0B58A123544A15DA59B13C8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0450; + }; + buildConfigurationList = C0B58A123544A15DA59B13C9 /* Build configuration list for PBXProject "MacLauncher" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C0B58A123544A15DA59B13CA; + productRefGroup = C0B58A123544A15DA59B13CB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 50E17734155444B900E97451 /* Launcher */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 50E17733155444B900E97451 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 50E17731155444B900E97451 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C0B58A123544A15DA59B13E4 /* main.m in Sources */, + C0B58A123544A15DA59B13E5 /* Launcher.m in Sources */, + 1A5645DB6F789D018FF4A4AF /* PropertyFileReader.m in Sources */, + 1A564BCFE66693BF0B2DD4A9 /* VMOptionsReader.m in Sources */, + 1A564C27F0BA05F900F34907 /* utils.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 50E1774F155444BA00E97451 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Launcher.pch; + INFOPLIST_FILE = Info.plist; + MACOSX_DEPLOYMENT_TARGET = 10.6; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx10.7; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + 50E17750155444BA00E97451 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Launcher.pch; + INFOPLIST_FILE = Info.plist; + MACOSX_DEPLOYMENT_TARGET = 10.6; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx10.7; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + C0B58A123544A15DA59B13CC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_ARC = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = ""; + SDKROOT = macosx; + }; + name = Release; + }; + C0B58A123544A15DA59B13CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_ARC = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = ""; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 50E17751155444BA00E97451 /* Build configuration list for PBXNativeTarget "Launcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50E1774F155444BA00E97451 /* Release */, + 50E17750155444BA00E97451 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C0B58A123544A15DA59B13C9 /* Build configuration list for PBXProject "MacLauncher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C0B58A123544A15DA59B13CC /* Release */, + C0B58A123544A15DA59B13CD /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C0B58A123544A15DA59B13C8 /* Project object */; +} diff --git a/native/MacLauncher/PropertyFileReader.h b/native/MacLauncher/PropertyFileReader.h new file mode 100644 index 000000000000..44e46a93ee61 --- /dev/null +++ b/native/MacLauncher/PropertyFileReader.h @@ -0,0 +1,13 @@ +// +// Created by max on 11/6/12. +// +// To change the template use AppCode | Preferences | File Templates. +// + + +#import + + +@interface PropertyFileReader : NSObject ++ (NSDictionary *)readFile:(NSString *)path; +@end \ No newline at end of file diff --git a/native/MacLauncher/PropertyFileReader.m b/native/MacLauncher/PropertyFileReader.m new file mode 100644 index 000000000000..050b6b978dcb --- /dev/null +++ b/native/MacLauncher/PropertyFileReader.m @@ -0,0 +1,45 @@ +// +// Created by max on 11/6/12. +// +// To change the template use AppCode | Preferences | File Templates. +// + + +#import "PropertyFileReader.h" +#import "utils.h" + + +@implementation PropertyFileReader { +} + ++ (NSDictionary *)readFile:(NSString *)path { + NSMutableDictionary *answer = [NSMutableDictionary dictionary]; + + NSString *contents = readFile(path); + + if (contents) { + [contents enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { + NSString *trimmedLine = trim(line); + if ([trimmedLine length] > 0) { + if ([trimmedLine characterAtIndex:0] != '#') { + [self parseProperty:trimmedLine to:answer]; + } + } + }]; + + return answer; + } + + return nil; +} + ++ (void)parseProperty:(NSString *)string to:(NSMutableDictionary *)to { + NSRange delimiter = [string rangeOfString:@"="]; + if (delimiter.length > 0 && delimiter.location + 1 <= string.length) { + NSString *key = [string substringToIndex:delimiter.location]; + NSString *value=[string substringFromIndex:delimiter.location + 1]; + [to setObject:value forKey:key]; + } +} + +@end \ No newline at end of file diff --git a/native/MacLauncher/VMOptionsReader.h b/native/MacLauncher/VMOptionsReader.h new file mode 100644 index 000000000000..bb4dbeaa6a16 --- /dev/null +++ b/native/MacLauncher/VMOptionsReader.h @@ -0,0 +1,13 @@ +// +// Created by max on 11/6/12. +// +// To change the template use AppCode | Preferences | File Templates. +// + + +#import + + +@interface VMOptionsReader : NSObject ++ (NSArray *) readFile: (NSString *)path; +@end \ No newline at end of file diff --git a/native/MacLauncher/VMOptionsReader.m b/native/MacLauncher/VMOptionsReader.m new file mode 100644 index 000000000000..440e2662859a --- /dev/null +++ b/native/MacLauncher/VMOptionsReader.m @@ -0,0 +1,34 @@ +// +// Created by max on 11/6/12. +// +// To change the template use AppCode | Preferences | File Templates. +// + + +#import "VMOptionsReader.h" +#import "utils.h" + + +@implementation VMOptionsReader { + +} ++ (NSArray *)readFile:(NSString *)path { + NSMutableArray *answer = [NSMutableArray array]; + + NSString *contents = readFile(path); + if (contents) { + [contents enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { + NSString *trimmedLine = trim(line); + if ([trimmedLine length] > 0) { + if ([trimmedLine characterAtIndex:0] != '#') { + [answer addObject:trimmedLine]; + } + } + }]; + return answer; + } + + return nil; +} + +@end \ No newline at end of file diff --git a/native/MacLauncher/main.m b/native/MacLauncher/main.m new file mode 100644 index 000000000000..0c0af43bb98a --- /dev/null +++ b/native/MacLauncher/main.m @@ -0,0 +1,40 @@ +#import "Launcher.h" + +#define FOREVER ((CFTimeInterval) 1e20) + +static void timer_empty(CFRunLoopTimerRef timer, void *info) { +} + +static void parkRunLoop() { + CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, FOREVER, (CFTimeInterval)0.0, 0, 0, timer_empty, NULL); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode); + CFRelease(t); + + SInt32 result; + do { + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, FOREVER, false); + } while (result != kCFRunLoopRunFinished); +} + +static void makeSameStackSize(NSThread *thread) { + struct rlimit l; + int err = getrlimit(RLIMIT_STACK, &l); + if (err == ERR_SUCCESS && l.rlim_cur > 0) { + thread.stackSize = (NSUInteger) l.rlim_cur; + } +} + +static void launchInNewThread(Launcher *launcher) { + NSThread *thread = [[NSThread alloc] initWithTarget:launcher selector:@selector(launch) object:nil]; + makeSameStackSize(thread); + [thread start]; +} + +int main(int argc, char *argv[]) { + @autoreleasepool { + launchInNewThread([[Launcher alloc] initWithArgc:argc argv:argv]); + parkRunLoop(); + } + + return 0; +} diff --git a/native/MacLauncher/utils.h b/native/MacLauncher/utils.h new file mode 100644 index 000000000000..4c28b3506929 --- /dev/null +++ b/native/MacLauncher/utils.h @@ -0,0 +1,5 @@ +NSString *readFile(NSString *path); +NSString *trim(NSString *line); + +void debugLog(NSString *message); +BOOL isDebugEnabled(); diff --git a/native/MacLauncher/utils.m b/native/MacLauncher/utils.m new file mode 100644 index 000000000000..63c392282044 --- /dev/null +++ b/native/MacLauncher/utils.m @@ -0,0 +1,30 @@ +#include "utils.h" + +NSString *readFile(NSString *path) { + NSError *err = nil; + NSString *contents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&err]; + if (contents == nil) { + debugLog([NSString stringWithFormat:@"Reading at %@ failed, Error is: %@", path, err.localizedDescription]); + return nil; + } + + debugLog([NSString stringWithFormat: @"Reading at %@ OK", path]); + + return contents; +} + +NSString *trim(NSString *line) { + return [line stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" \t"]]; +} + +BOOL isDebugEnabled() { + return getenv("IDEA_LAUNCHER_DEBUG") != NULL; +} + +void debugLog(NSString *message) { + if (isDebugEnabled()) { + NSLog(@"%@", message); + } +} + +