Trouble loading bundles at runtime

  • Hi all,

    On tiger I used to be able to load bundles at runtime using the code
    below, this doesn't seem to work on Leopard anymore however:

    - (BOOL)addMyPluginBundle: (NSString *)path{
        Class pluginClass;
        NSBundle *pluginBundle;

        id aPlugin = nil;
        BOOL nibLoaded = NO;

        pluginBundle = [NSBundle bundleWithPath: path];
        if (pluginClass = [pluginBundle principalClass]) {
            if ([pluginClass
    conformsToProtocol:@protocol(myPluginProtocol)] ) {
      aPlugin = [[pluginClass alloc] init];
      nibLoaded = [NSBundle loadNibNamed:  [[pluginBundle infoDictionary]
    objectForKey: @"NSMainNibFile"] owner: aPlugin];
            }
        }

        if ( aPlugin && nibLoaded) {
    //do some stuff
        }

        return YES;
    }

    The weird thing is that this only happens if I just before have
    download the bundle and wrote it to disk. If I restart my main app and
    use the exact same code to load the bundle it works fine. What happens
    is that instead of the bundle's nib file the main app's nib is loaded
    again!?! Diving a bit further into it shows that this is because the
    [pluginBundle infoDictionary] doesn't contain the complete plist of
    the bundle (although it definitely is there!) and lacks the
    NSMainNibFile entry.

    If I run this code at startup the plist looks like:

    dict: {
        CFBundleDevelopmentRegion = English;
        CFBundleExecutable = WOSSearchEngine;
        CFBundleExecutablePath = "/Users/griek/Library/Application
    Support/Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine/
    Contents/MacOS/WOSSearchEngine";
        CFBundleIconFile = searchengine;
        CFBundleIdentifier = "com.mekentosj.papers.WOSSearchEngine";
        CFBundleInfoDictionaryVersion = "6.0";
        CFBundleInfoPlistURL = Contents/Info.plist -- file://localhost/Users/griek/Library/Application%20Support/Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine/
    ;
        CFBundleNumericVersion = 18907136;
        CFBundlePackageType = BNDL;
        CFBundleSignature = MTPX;
        CFBundleVersion = "1.2";
        NSBundleInitialPath = "/Users/griek/Library/Application Support/
    Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine";
        NSBundleResolvedPath = "/Users/griek/Library/Application Support/
    Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine";
        NSMainNibFile = Panel;
        NSPrincipalClass = mtWOSSearchEngine;
    }

    while at runtime and just after downloading the bundle it looks like:

    dict: {
        CFBundleExecutablePath = "/Users/griek/Library/Application
    Support/Papers/PlugIns/SearchEngines/CiteseerSearchEngine.searchengine/
    Contents/MacOS/CiteseerSearchEngine";
        NSBundleInitialPath = "/Users/griek/Library/Application Support/
    Papers/PlugIns/SearchEngines/CiteseerSearchEngine.searchengine";
        NSBundleResolvedPath = "/Users/griek/Library/Application Support/
    Papers/PlugIns/SearchEngines/CiteseerSearchEngine.searchengine";
        NSPrincipalClass = mtCiteseerSearchEngine;
    }

    I'm quite running out of ideas what is going on. The more because in
    addition the gcc debugger seems to have problems with this on its own:

    BFD: BFD 2.16.91 20050815 internal error, aborting at /SourceCache/gdb/
    gdb-768/src/bfd/cache.c line 517 in bfd_cache_lookup_worker
    BFD: Please report this bug.
    The Debugger has exited with status 1.The Debugger has exited with
    status 1.

    Anyone a clue of what's going on? Any help is appreciated!
    Alex
  • On Feb 6, 2008, at 9:36 AM, Alexander Griekspoor wrote:

    > Hi all,
    >
    > On tiger I used to be able to load bundles at runtime using the code
    > below, this doesn't seem to work on Leopard anymore however:
    >
    > - (BOOL)addMyPluginBundle: (NSString *)path{
    > Class pluginClass;
    > NSBundle *pluginBundle;
    >
    > id aPlugin = nil;
    > BOOL nibLoaded = NO;
    >
    > pluginBundle = [NSBundle bundleWithPath: path];
    > if (pluginClass = [pluginBundle principalClass]) {
    > if ([pluginClass
    > conformsToProtocol:@protocol(myPluginProtocol)] ) {
    > aPlugin = [[pluginClass alloc] init];
    > nibLoaded = [NSBundle loadNibNamed:  [[pluginBundle
    > infoDictionary] objectForKey: @"NSMainNibFile"] owner: aPlugin];
    > }
    > }
    >
    > if ( aPlugin && nibLoaded) {
    > //do some stuff
    > }
    >
    > return YES;
    > }

    Hey Alexander -

    I'm not sure that this is your problem, but I would expect to see a
    call to [pluginBundle load] right after pluginBundle is set to
    [NSBundle bundleWithPath: path]. Having an instance of NSBundle
    doesn't imply that the code for the bundle has been loaded into your
    address space.

    Jon Hess

    >
    >
    > The weird thing is that this only happens if I just before have
    > download the bundle and wrote it to disk. If I restart my main app
    > and use the exact same code to load the bundle it works fine. What
    > happens is that instead of the bundle's nib file the main app's nib
    > is loaded again!?! Diving a bit further into it shows that this is
    > because the [pluginBundle infoDictionary] doesn't contain the
    > complete plist of the bundle (although it definitely is there!) and
    > lacks the NSMainNibFile entry.
    >
    > If I run this code at startup the plist looks like:
    >
    > dict: {
    > CFBundleDevelopmentRegion = English;
    > CFBundleExecutable = WOSSearchEngine;
    > CFBundleExecutablePath = "/Users/griek/Library/Application
    > Support/Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine/
    > Contents/MacOS/WOSSearchEngine";
    > CFBundleIconFile = searchengine;
    > CFBundleIdentifier = "com.mekentosj.papers.WOSSearchEngine";
    > CFBundleInfoDictionaryVersion = "6.0";
    > CFBundleInfoPlistURL = Contents/Info.plist -- file://localhost/Users/griek/Library/Application%20Support/Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine/
    > ;
    > CFBundleNumericVersion = 18907136;
    > CFBundlePackageType = BNDL;
    > CFBundleSignature = MTPX;
    > CFBundleVersion = "1.2";
    > NSBundleInitialPath = "/Users/griek/Library/Application Support/
    > Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine";
    > NSBundleResolvedPath = "/Users/griek/Library/Application Support/
    > Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine";
    > NSMainNibFile = Panel;
    > NSPrincipalClass = mtWOSSearchEngine;
    > }
    >
    > while at runtime and just after downloading the bundle it looks like:
    >
    > dict: {
    > CFBundleExecutablePath = "/Users/griek/Library/Application
    > Support/Papers/PlugIns/SearchEngines/
    > CiteseerSearchEngine.searchengine/Contents/MacOS/
    > CiteseerSearchEngine";
    > NSBundleInitialPath = "/Users/griek/Library/Application Support/
    > Papers/PlugIns/SearchEngines/CiteseerSearchEngine.searchengine";
    > NSBundleResolvedPath = "/Users/griek/Library/Application Support/
    > Papers/PlugIns/SearchEngines/CiteseerSearchEngine.searchengine";
    > NSPrincipalClass = mtCiteseerSearchEngine;
    > }
    >
    > I'm quite running out of ideas what is going on. The more because in
    > addition the gcc debugger seems to have problems with this on its own:
    >
    > BFD: BFD 2.16.91 20050815 internal error, aborting at /SourceCache/
    > gdb/gdb-768/src/bfd/cache.c line 517 in bfd_cache_lookup_worker
    > BFD: Please report this bug.
    > The Debugger has exited with status 1.The Debugger has exited with
    > status 1.
    >
    > Anyone a clue of what's going on? Any help is appreciated!
    > Alex
  • Hi Jon,

    I tried that but that doesn't make a different, I also believe that
    the call [pluginBundle principalClass] loads the bundle according to
    the docs.
    The problem seems in the cached plist which somehow is incomplete. But
    even if I load the plist using the filemanager like suggested
    previously on the list I can't get the nib to load, neither using
    loadNibNamed, nor even using NSNib initWithContentsOfURL. It seems the
    bundle is somehow crippled/cached and needs to be refreshed to bring
    it in the state it is when I would quit my app and relaunch it..
    Alex

    > Hey Alexander -
    >
    > I'm not sure that this is your problem, but I would expect to see a
    > call to [pluginBundle load] right after pluginBundle is set to
    > [NSBundle bundleWithPath: path]. Having an instance of NSBundle
    > doesn't imply that the code for the bundle has been loaded into your
    > address space.
    >
    > Jon Hess
    >
    >>
    >>
    >> The weird thing is that this only happens if I just before have
    >> download the bundle and wrote it to disk. If I restart my main app
    >> and use the exact same code to load the bundle it works fine. What
    >> happens is that instead of the bundle's nib file the main app's nib
    >> is loaded again!?! Diving a bit further into it shows that this is
    >> because the [pluginBundle infoDictionary] doesn't contain the
    >> complete plist of the bundle (although it definitely is there!) and
    >> lacks the NSMainNibFile entry.
    >>
    >> If I run this code at startup the plist looks like:
    >>
    >> dict: {
    >> CFBundleDevelopmentRegion = English;
    >> CFBundleExecutable = WOSSearchEngine;
    >> CFBundleExecutablePath = "/Users/griek/Library/Application
    >> Support/Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine/
    >> Contents/MacOS/WOSSearchEngine";
    >> CFBundleIconFile = searchengine;
    >> CFBundleIdentifier = "com.mekentosj.papers.WOSSearchEngine";
    >> CFBundleInfoDictionaryVersion = "6.0";
    >> CFBundleInfoPlistURL = Contents/Info.plist -- file://localhost/Users/griek/Library/Application%20Support/Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine/
    >> ;
    >> CFBundleNumericVersion = 18907136;
    >> CFBundlePackageType = BNDL;
    >> CFBundleSignature = MTPX;
    >> CFBundleVersion = "1.2";
    >> NSBundleInitialPath = "/Users/griek/Library/Application Support/
    >> Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine";
    >> NSBundleResolvedPath = "/Users/griek/Library/Application Support/
    >> Papers/PlugIns/SearchEngines/WOSSearchEngine.searchengine";
    >> NSMainNibFile = Panel;
    >> NSPrincipalClass = mtWOSSearchEngine;
    >> }
    >>
    >> while at runtime and just after downloading the bundle it looks like:
    >>
    >> dict: {
    >> CFBundleExecutablePath = "/Users/griek/Library/Application
    >> Support/Papers/PlugIns/SearchEngines/
    >> CiteseerSearchEngine.searchengine/Contents/MacOS/
    >> CiteseerSearchEngine";
    >> NSBundleInitialPath = "/Users/griek/Library/Application Support/
    >> Papers/PlugIns/SearchEngines/CiteseerSearchEngine.searchengine";
    >> NSBundleResolvedPath = "/Users/griek/Library/Application Support/
    >> Papers/PlugIns/SearchEngines/CiteseerSearchEngine.searchengine";
    >> NSPrincipalClass = mtCiteseerSearchEngine;
    >> }
    >>
    >> I'm quite running out of ideas what is going on. The more because
    >> in addition the gcc debugger seems to have problems with this on
    >> its own:
    >>
    >> BFD: BFD 2.16.91 20050815 internal error, aborting at /SourceCache/
    >> gdb/gdb-768/src/bfd/cache.c line 517 in bfd_cache_lookup_worker
    >> BFD: Please report this bug.
    >> The Debugger has exited with status 1.The Debugger has exited with
    >> status 1.
    >>
    >> Anyone a clue of what's going on? Any help is appreciated!
    >> Alex
    >

    **********************************************
              ** Alexander Griekspoor  PhD **
    **********************************************
              mekentosj.com

              4Peaks - For Peaks, Four Peaks
      2004 Winner of the Apple Design Awards
              Best Mac OS X Student Product
              http://www.mekentosj.com/4peaks
    **********************************************
  • On Feb 6, 2008, at 2:12 PM, Jonathan Hess wrote:
    > I'm not sure that this is your problem, but I would expect to see a
    > call to [pluginBundle load] right after pluginBundle is set to
    > [NSBundle bundleWithPath: path]. Having an instance of NSBundle
    > doesn't imply that the code for the bundle has been loaded into your
    > address space.

    -principalClass should load the bundle and this check....

    > if (pluginClass = [pluginBundle principalClass]) {

    .... would barf it didn't.

    I would suggest that OP put in some logging or debugging only code
    that prints something indicative of which if() fell through on failure.

    >> I'm quite running out of ideas what is going on. The more because
    >> in addition the gcc debugger seems to have problems with this on
    >> its own:

    Some suggestions:

    - Check the bundle's path;  is it different in the failure case vs.
    the success case?

    - does the download process do some kind of a "all done, move into
    place" operation?

    - could there be a race condition where your loading code is
    activated before the cleanup-after-download is done?

    >> BFD: BFD 2.16.91 20050815 internal error, aborting at /SourceCache/
    >> gdb/gdb-768/src/bfd/cache.c line 517 in bfd_cache_lookup_worker
    >> BFD: Please report this bug.
    >> The Debugger has exited with status 1.The Debugger has exited with
    >> status 1.

    Please file a bug on that...

    b.bum
  • On Feb 6, 2008, at 2:21 PM, Bill Bumgarner wrote:
    > Some suggestions:
    >
    > - Check the bundle's path;  is it different in the failure case vs.
    > the success case?
    >
    > - does the download process do some kind of a "all done, move into
    > place" operation?
    >
    > - could there be a race condition where your loading code is
    > activated before the cleanup-after-download is done?

    And another:

    - Use fs_usage or Instruments File Activity template to monitor the
    filesystem interaction on a broken run vs. a normal run.  Comparing
    the sequence of FS API calls should give indication as to exactly
    where things have gone horribly wrong.

    b.bum
  • Hi Bill,

    > Some suggestions:
    >
    > - Check the bundle's path;  is it different in the failure case vs.
    > the success case?
    No, identical, except as said the infoDictionary of the bundle is
    markedly different (lacking the key for the main nib, hence in Leopard
    loadNibNamed seems to fall back to your main nib of the application).
    If I then load the plist using NSFileManager to get the complete one
    and fill in the proper nib name in loadNibNamed it still fails.
    >
    > - does the download process do some kind of a "all done, move into
    > place" operation?
    Yes, it downloads the zipped bundle, and does an unzip.
    >
    > - could there be a race condition where your loading code is
    > activated before the cleanup-after-download is done?
    That's what I thought as well for a moment, but even if I do a
    performSelector:object:withDelay: of 3 sec it's still doesn't work.

    >>> BFD: BFD 2.16.91 20050815 internal error, aborting at /SourceCache/
    >>> gdb/gdb-768/src/bfd/cache.c line 517 in bfd_cache_lookup_worker
    >>> BFD: Please report this bug.
    >>> The Debugger has exited with status 1.The Debugger has exited with
    >>> status 1.
    > Please file a bug on that...
    Ok, will do. It's difficult to know what happens though..
    Thanks,
    Alex
    >
    >

    **********************************************
              ** Alexander Griekspoor  PhD **
    **********************************************
              mekentosj.com

                EnzymeX - To cut or not to cut
      2006 Winner of the Apple Design Awards
              Best Mac OS X Scientific Solution
            http://www.mekentosj.com/enzymex
    **********************************************