9

I have a Cocoa application that usually runs in full 64-bit mode on any Mac that supports this architecture.

Now I have an external API that is only available as a 32-bit plug-in to be loaded into the main program. This API is for a third-party input device that only a small percentage of my users will ever purchase, but that is important for that small percentage.

My problem is that the program can only use this API if executed in 32-bit mode. The easiest thing to do is of course to:

Scenario 1: ask the user to start the program in 32-bit mode by changing its information via the Finder's Get Info dialog.

This is easily done, but hardly elegant..

Scenario 2: always run in 32-bit mode thus avoiding the problem

Hardly what I want to do either.. penalizing 98% of users for the sake of an exotic feature.

Scenario 3: automatically change the application's launch attributes so that it starts in 32-bit mode next time it is launched and every time afterwards

or

Scenario 4: at launch time, establish which architecture is being used, then re-launch in 32-bit mode if necessary

Scenarios 3 & 4 have the problem that very little is documented on how to do this and it might get me into trouble with the Mac App Store guidelines.

So far, I've established:

  • that using the "arch" command line tool will allow me to restart my executable in 32-bit mode
  • Finder scripting won't let me change the "Launch in 32-bit mode" flag
  • the flag is managed by the Launch Services API (http://blog.timac.org/?p=490)
  • BUT I haven't found any interface to programmatically change the flag in the Launch Services API

So far I can see only these options, none of which seem particularly great:

  1. relaunch the application using NSTask and the "arch" command line tool
  2. write directly into the com.apple.LaunchServices.plist
  3. isolate the 32-bit plug-in into its own 32-bit only process and use IPC

Solution 1 could get me into trouble with the MAS submission. Solution 2 would almost certainly do so at some stage.. only solution 3 would be perfect from a user's perspective but add a huge amount of complexity for minimal pay-off.

Any advice on how to do this "cleanly" and with reasonable effort would be highly appreciated!

Cœur
  • 37,241
  • 25
  • 195
  • 267
Frank
  • 91
  • 2
  • 5
    Why would it matter if your app is 32-bit only - does it need large amounts of memory (> 2 GB) ? – Paul R Aug 15 '11 at 11:37
  • 1
    Is running always in 32-bit mode that much of a penalty? – hamstergene Aug 15 '11 at 13:01
  • possible duplicate of [How can I programmatically start a program in the 32 bits or 64 bits environment?](http://stackoverflow.com/questions/5268957/how-can-i-programmatically-start-a-program-in-the-32-bits-or-64-bits-environment) – ughoavgfhw Aug 15 '11 at 18:21
  • The application uses garbage collection which works much better in 64-bit mode, so yes it's a big penalty to be paid by ALL users. It's similar to the other linked question, but that doesn't have a satisfactory answer either. – Frank R. Aug 16 '11 at 07:55

4 Answers4

4

Option 5: Create another executable that always runs as 32 bit and its sole purpose is to drive the 32 bit component in question. Launch that executable from your primary application and use some type of processor independent io to communicate with each other, probably sockets.

NSGod
  • 22,699
  • 3
  • 58
  • 66
justin.m.chase
  • 13,061
  • 8
  • 52
  • 100
2

I figured out the way to set the key using defaults...

Given a bash shell variable:

alias="<0000 .... 1234>"  #(there is a lot more hex data than that...)

And the bundle identifier:

bundle="com.mycompany.myprogram"

You can set the key thusly:

defaults write com.apple.LaunchServices LSArchitecturesForX86_64 -dict-add $bundle "($alias, i386)"

Good luck generating the binary alias. I just steal the _CFURLAliasData from com.plist.dock since the program I am trying to set to launch 32bit has an icon installed into the dock. The other way to generate the alias, if you can get your hands on it, might be to use the program dockit.c. I haven't been able to find that program.

EdChum
  • 376,765
  • 198
  • 813
  • 562
John Wolf
  • 21
  • 1
  • Would the alias variable be the 0 key under the bundle identifier if I look in plisteditor pro? I think it might be. Anyhow I think there's some kind of cache involved here. If I use the above Bash approach the info dialog tick box state does not show that it's changed UNLESS I force quit Finder. It must trigger something that rebuilds it's internal caching. Looking here it seems to suggest that http://www.thexlab.com/faqs/resetlaunchservices.html – Keegan 82 Feb 25 '14 at 14:19
  • Even with force quiting I'm finding the app in particular only responds to manual info dialog ticks. In otherwords even if I run the bash script to say 32bit, and see it changed in the UI tick box, my app still launches in 64bit. I'm gonna try just creating 2 copies of the .app package now. – Keegan 82 Feb 25 '14 at 14:21
1

You can programmatically change what mode your application will launch in by changing the plist file located here:

~/Library/Preferences/com.apple.LaunchServices.plist

You need to change the key located at /LSArchitecturesForX86_64/[your.app.idenitfier]/Item 1/

  • setting it to x86_64 will run in 64 bit
  • setting it to i386 will run in 32 bit

You can edit this with either the built in defaults command or the built in plistbuddy command. I have never had much luck getting a key that may levels down to change with defaults, if I figure out the plistbuddy syntax I will post it.

Once you have all that, you can create a simple script to run at log in that tests for the presence of your input device (or a another attribute, department etc) and sets the launch mode accordingly.

Don
  • 11
  • 1
0

My scenario is very similar. I use Ableton Live and Reason as a rewire slave. If I launch Ableton in 32bit I need Reason to be in 32bit mode. Here's what I did.

  1. Make a copy of the app you want to be able to change modes quickly with.
  2. Call the copy 32.app (in my case Reason32.app)
  3. Show package contents of this new app and delete the Contents folder (Yes the one that contains everything)
  4. Now go into the original, make a symlink of Contents
  5. Copy symlink into the appname32.app package (where old deleted one used to reside)
  6. Use the finder properties and tick 32bit mode for your new copy.

You now have 2 apps you can easily launch/script.

Keegan 82
  • 394
  • 2
  • 11