在Objective C(Mac OS X)中检测CPU架构(32位/ 64位)运行时

时间:2010-01-01 16:36:20

标签: objective-c macos 32bit-64bit cpu-architecture

我正在拧一个需要执行一些(控制台)应用程序的Cocoa应用程序,这些应用程序针对32位和64位进行了优化。因此,我想检测运行应用程序的CPU架构,以便启动正确的控制台应用程序。

简而言之:如何检测应用程序是否在64位操作系统上运行?

编辑:我知道Mach-O胖二进制文件,这不是我的问题。我需要知道这一点,所以我可以启动另一个非捆绑(控制台)应用程序。一个针对x86进行了优化,一个针对x64进行了优化。

7 个答案:

答案 0 :(得分:10)

有一种超级简单的方法。编译可执行文件的两个版本,一个用于32位,一个用于64位,并将它们与lipo结合使用。这样,正确的版本将始终执行。

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

编辑:或者首先使用gcc -arch i686 -arch x86_64

编译通用二进制文件

回应OP的评论:

if(sizeof(int*) == 4)
    //system is 32-bit
else if(sizeof(int*) == 8)
    //system is 64-bit
编辑:D'哦!我没有意识到你需要运行时检查...通过sysctl -A的输出,两个变量看起来可能有用。尝试解析sysctl hw.optional.x86_64sysctl hw.cpu64bit_capable的输出。我没有32位Mac来测试这个,但是在Core2Duo Mac上的Snow Leopard中这两个都设置为1。

答案 1 :(得分:7)

使用[[NSRunningApplication currentApplication] executableArchitecture]返回以下常量之一:

  • NSBundleExecutableArchitectureI386
  • NSBundleExecutableArchitectureX86_64
  • NSBundleExecutableArchitecturePPC
  • NSBundleExecutableArchitecturePPC64

例如:

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

答案 2 :(得分:3)

您无需手动检测即可实现此效果。一个Mach-O可执行文件可以包含32位和64位英特尔机器的二进制文件,内核自动运行最合适的文件。如果您正在使用XCode,那么项目检查器中有一个设置,您可以在一个通用二进制文件中设置要包含的体系结构(ppc,i386,x86_64)。

另外,请记住,在OS X上,运行64位内核(使用Snow Leopard)并能够运行64位用户登陆应用程序是两个正交的概念。如果你有一台64位cpu的机器,即使内核以32位模式运行(使用Leopard或Snow Leopard),你也可以在64位模式下运行用户域程序,只要所有的库都可以。你链接的是64位。因此,检查操作系统是否具有64位功能并没有用。

答案 3 :(得分:3)

通常,您不需要能够在运行时检查您是64位还是32位。如果您的主机应用程序(我称之为启动64位或32位工具的应用程序)是胖二进制文件,则编译时检查就足够了。因为它将被编译两次(一次用于胖二进制文件的32位部分,一次用于64位部分),而正确的一次将由系统启动,您将在正确的启动代码中编译写......像

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

如果用户以某种方式在64位Mac上以32位显式启动您的应用程序,请相信他们知道他们正在做什么。无论如何,这是一个边缘案例,为什么要为权力​​用户打破错误的完美感。如果您发现只有64位的错误,如果您可以告诉用户解决方法是以32位方式启动,您甚至可能会感到高兴。

如果您的应用程序本身只有32位(例如带有命令行帮助程序的Carbon GUI),您只需要进行真正的运行时检查。在这种情况下,host_processor_info或sysctl或类似的可能是你唯一的路由,如果出于某些奇怪的原因你不能只是将两个可执行文件合并在一起。

答案 4 :(得分:2)

如果您使用的是Snow Leopard,请使用NSRunningApplication的executableArchitecture。

否则,我会做以下事情:

-(BOOL) is64Bit
{
#if __LP64__
  return YES;
#else
  return NO;
#endif
}

答案 5 :(得分:1)

以编程方式获取具有CPU体系结构名称的字符串:

#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);

在shell脚本中执行相同的操作:

set name=`sysctl -n hw.machine`

答案 6 :(得分:0)

检查操作系统版本的标准方法(以及它的雪豹,64位操作系统)是否详细here