views:

1539

answers:

6

I'm currently wring a Cocoa application which needs to execute some (console) applications which are optimized for 32 and 64 bit. Because of this I would like to detect what CPU architecture the application is running on so I can start the correct console application.

So in short: how do I detect if the application is running on a 64 bit OS?

Edit: I know about the Mach-O fat binaries, that was not my question. I need to know this so I can start another non bundled (console) application. One that is optimized for x86 and one for x64.

A: 

The standard way of checking the os version (and hence whether its snow leopard, a 64-bit os) is detailed here.

ennuikiller
This doesn't tell you what you need to know -- 64-bit capability depends on both the OS version and the CPU you're running on.
Gordon Davisson
Then you'd follow it up with either a host_processor_info or a host_info call as defined in the Mach headers.
Azeem.Butt
+4  A: 

There is a super-easy way. Compile two versions of the executable, one for 32-bit and one for 64-bit and combine them with lipo. That way, the right version will always get executed.

gcc -lobjc somefile.m -o somefile -m32 -march=i686
gcc -lobjc somefile.m -o somefile2 -m64 -march=x86_64
lipo -create -arch i686 somefile -arch x86_64 somefile2 -output somefileUniversal

Edit: or just compile a universal binary in the first place with gcc -arch i686 -arch x86_64

In response to OP's comment:

if(sizeof(int*) == 4)
    //system is 32-bit
else if(sizeof(int*) == 8)
    //system is 64-bit

EDIT: D'oh! I didn't realise you'd need runtime checking... Going through the output of sysctl -A, two variables look potentially useful. Try parsing the output of sysctl hw.optional.x86_64 and sysctl hw.cpu64bit_capable . I don't have a 32-bit Mac around to test this, but both these are set to 1 in Snow Leopard on a Core2Duo Mac.

Chinmay Kanchi
You can even do that in one line, `gcc -arch i386 -arch x86_64 somefile.m -o somefileUniversal` :)
Yuji
Haha, commented while I was editing...
Chinmay Kanchi
This seems like the best solution in my case. Thanks.Although I really would still like to know how to detect x64 or x86, just for future reference.
Ger Teunis
Excellent, it's that easy. Thanks for your reply.
Ger Teunis
Ger Teunis, you should note that the sizeof test proposed here is just as "compile time" as the \_\_LP64\_\_ suggestion below.
Logan Capaldo
That is correct, but they provided the lipo solution which works fine. I agree the original question isn't answered but lipo solved my problems.
Ger Teunis
Yep, lipo works, just wanted to make sure you were aware of the limitations of the "for future reference" response.
Logan Capaldo
+3  A: 

You don't have to detect it manually to achieve that effect. One Mach-O executable file can contain both binaries for 32 bit and 64 bit intel machines, and the kernel runs the most appropriate ones automatically. If you're using XCode, there's a setting in the project inspector where you can set the architectures (ppc, i386, x86_64) you want to have in a single universal binary.

Also, remember that on OS X, running a 64-bit kernel (with Snow Leopard) and being able to run a 64-bit user land app are two orthogonal concepts. If you have a machine with 64 bit cpu, you can run a user-land program in a 64-bit mode even when the kernel is running in the 32 bit mode (with Leopard or Snow Leopard), as long as all of the libraries you link with are available with 64 bit. So it's not that useful to check if the OS is 64-bit capable.

Yuji
I thought I was clear about this. I try to explain better. I want to call a NON FAT binary. One is optimized for x86 and one for x64. I did not create the binaries and do not have the source. To choose the best optimized non-fat binary I need to know what cpu I run on.
Ger Teunis
+1  A: 

If you are on Snow Leopard use NSRunningApplication's executableArchitecture.

Otherwise, I would do the following:

-(BOOL) is64Bit
{
#if __LP64__
  return YES;
#else
  return NO;
#endif
}
sbooth
Sadly that is compile time. Searched for the runtime check. Thanks for your reply anyways.
Ger Teunis
@Ger Teunis: The accepted answer is also compile time (the sizeof part) and it just doesn't matter. If someone runs your 32 bit binary despite the fact that you provide both a 64 and a 32 bit one, there is really little point in not considering the world to be 32-bit even if it happens to be a 64-bit machine.
Fredrik
That is correct, but they provided the lipo solution which works fine. I agree the original question isn't answered but lipo solved my problems.
Ger Teunis
+2  A: 

Usually, you shouldn't need to be able to check at runtime whether you're on 64 or 32 bits. If your host application (that's what I'd call the app that launches the 64 or 32 bit tools) is a fat binary, the compile-time check is enough. Since it will get compiled twice (once for the 32-bit part of the fat binary, once for the 64-bit part), and the right one will be launched by the system, you'll compile in the right launch code by just writing sth. like

#if __LP64__
    NSString    *vExecutablePath = [[NSBundle mainBundle] pathForResource: @"tool64" ofType: @""];
#else
    NSString    *vExecutablePath = [[NSBundle mainBundle] pathForResource: @"tool32" ofType: @""];
#endif
[NSTask launchedTaskWithLaunchPath: vExecutableName ...];

If the user somehow explicitly launches your app in 32 bits on a 64 bit Mac, trust them that they know what they're doing. It's an edge case anyway, and why break things for power users out of a wrong sense of perfection. You may even be happy yourself if you discover a 64-bit-only bug if you can tell users the workaround is launching as 32 bits.

You only need a real runtime check if your app itself is only 32 bits (e.g. Carbon GUI with command-line helper). In that case, host_processor_info or sysctl or similar are probably your only route if for some weird reason you can't just lipo the two executables together.

uliwitness
+1  A: 

Use [[NSRunningApplication currentApplication] executableArchitecture] which returns one of the following constants:

  • NSBundleExecutableArchitectureI386
  • NSBundleExecutableArchitectureX86_64
  • NSBundleExecutableArchitecturePPC
  • NSBundleExecutableArchitecturePPC64

For example:

switch ([[NSRunningApplication currentApplication] executableArchitecture]) {
  case NSBundleExecutableArchitectureI386:
    // TODO: i386
    break;

  case NSBundleExecutableArchitectureX86_64:
    // TODO: x86_64
    break;

  case NSBundleExecutableArchitecturePPC:
    // TODO: ppc
    break;

  case NSBundleExecutableArchitecturePPC64:
    // TODO: ppc64
    break;

  default:
    // TODO: unknown arch
    break;
}
Mirek Rusin