Detect CPU Architecture (32-bit / 64-bit) runtime

2019-04-11 20:04发布

问题:

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.

回答1:

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.



回答2:

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;
}


回答3:

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.



回答4:

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.



回答5:

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
}


回答6:

To programmatically get a string with the CPU architecture name:

#include <sys/types.h>
#include <sys/sysctl.h>

// Determine the machine name, e.g. "x86_64".
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0); // Get size of data to be returned.
char *name = malloc(size);
sysctlbyname("hw.machine", name, &size, NULL, 0);

// Do stuff...

free(name);

To do the same thing in a shell script:

set name=`sysctl -n hw.machine`


回答7:

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