I was stuck in a funk yesterday, trying to get XULRunner application bundles working properly on Mac OS X. The basic problem is that I’m trying to run the xulrunner-bin executable from the XUL.framework, but have the launch manager think that it is running as the application bundle (using the application bundle dock icon/application name/etc). The basic strategy is to have a little stub binary inside the application bundle which will execv to the xulrunner-bin binary. However, this wasn’t working… Launch Services was convinced that the xulrunner-bin was running on its own, and because it is part of a framework instead of an application bundle, it was running as a background application (no access to the dock or menus).
In my frustration I visited my infrequent hangout freenode #opendarwin, who were quick to inform me that launch services was not their domain, but that I should visit #macdev.
<bsmedberg> Is this a decent place to ask questions about application bundles and launch services?
<mikeash> I wouldn’t call it decent, “wretched hive of scum and villainy” is more appropriate
<bsmedberg> Is there some way to run /foo/bar-executable but tell launch services to pretend that it’s running as part of /bar/MyApp.app ?
<mikeash> “as part of”?
<bsmedberg> Basically, I want to stick a “runtime executable” in /Library/XUL.framework/Versions/<foo>/xulrunner-bin
<bsmedberg> sorry, /Library/Frameworks/…
<arwyn> so you want to have your normal app bundle in /bar/MyApp, but you want the actual executable file to be from /Library/XUL.framework,e tc?
<bsmedberg> And when a user runs /bar/XULApplication.app it will have a little stub binary at Contents/MacOS/xulrunner-stub
* arwyn suggests a symlink
<mikeash> that sure sounds like odd design
<mikeash> I *think* that if your app’s main executable just execs the other one, it’ll work, but I’ve never tried it and I’m nowhere near sure
<bsmedberg> it doesn’t work to execv the other one :-(
<arwyn> what doesn’t work?
<bsmedberg> the xulrunner-bin doesn’t get menus/dock icon (can’t activate the window)
<arwyn> and to be clear, we are talking about exec() the system call… not relaunching via LS
<mikeash> does xulrunner-bin work properly when it’s actually the main executable of your app?
<arwyn> in your exec(), did you preserve the original argv parameters so that the OS will think the bundle is still located in the right place?
<bsmedberg> as long as all the rest of the XUL framework is along with it
<bsmedberg> arwyn: no, I didn’t… does the OS use the argv to determine the bundle?
* bsmedberg gets excited
<arwyn> yes, there is no other way
<bsmedberg> cool, I’ll try that, thanks
<mikeash> arwyn, aren’t there undocumented ways, like env(“_”) or something?
<arwyn> I know this type of re-exec() trick can work, people on this channel have done it
<arwyn> it might just need some tweaking
<mikeash> I think that Firefox does it
<bsmedberg> well, no
<bsmedberg> Firefox execs itself, but it’s the same binary
* bsmedberg wrote that code
<mikeash> I don’t think that being the same binary is going to magically make it work, and being a different binary is going to magically make it break
<arwyn> mike, maybe… I’m not entirely sure
<arwyn> binary doesn’t matter at all, its all paths & args
<mikeash> arwyn, anyway, irrelevant since Apple does apparently use argv
<arwyn> argv is accessible via the NSGetArgv() stuff in Libc, which is what CF/NS uses to get it later to do main bundling
<mikeash> I can’t even think of a way that LS could even detect that you’ve re-exec’d, much less figure out whether you re-exec’d the same binary or a different one
[snip a long discussion that I didn’t understand about how the Mac OS could do this differently if it really wanted to]
Thank you Mike Ash and arwyn (whose real name I don’t know) for your invaluable help! I would probably be rearchitechting how mac bundles launched the XULRunner if it weren’t for you.