Question

I'm using py2app to bundle a Mac application and am trying to figure out how it works. Based on reading the Bundle Programming Guide it seems that CFBundleExecutable is a required key and that this is the key OSX uses to figure out which file in the MacOS subfolder to run. However, I stripped my Info.plist file to the following, and the app loads just fine:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>PyMainFileNames</key>
        <array>
                <string>__boot__</string>
        </array>
        <key>PyRuntimeLocations</key>
        <array>
                <string>@executable_path/../Frameworks/Python.framework/Versions/2.7/Python</string>
        </array>
</dict>
</plist>

How can this be so? Given that exact plist file, how can OSX load my application?

Was it helpful?

Solution

The CFBundleExecutable key is required in the sense that you really should have it, but CoreFoundation will do its best to deal with its absence. By looking at the source of CFBundle we can get an idea how it deals with this key:

static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) {
    CFStringRef executableName = NULL;

    // …

    if (infoDict) {
        // Figure out the name of the executable.
        // First try for the new key in the plist.
        executableName = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleExecutableKey);
        // Second try for the old key in the plist.
        if (!executableName) executableName = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey);
        if (executableName && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) {
            CFRetain(executableName);
        } else {
            executableName = NULL;
        }
    }
    if (!executableName && url) {
        // Third, take the name of the bundle itself (with path extension stripped)

So you can see that they look for the following in order:

  1. The CFBundleExecutable key.
  2. The NSExecutable key, a legacy name predating OS X public beta.
  3. If neither is present, fall back to using the name of the bundle with the path extension removed.

Having determined the executable name, the manner in which the directory that it lives in is found is equally full of quirks. I'll leave discovering those as an exercise for interested parties.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top