【问题标题】:Detect CPU Architecture (32-bit / 64-bit) runtime in Objective C (Mac OS X)在 Objective C (Mac OS X) 中检测 CPU 架构(32 位/64 位)运行时
【发布时间】:2010-12-31 15:11:27
【问题描述】:

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

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

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

【问题讨论】:

  • 即使您没有源代码,您也可以合并已有的两个二进制文件。请记住,胖二进制文件适用于非捆绑控制台二进制文件!照 cgkanchi 的建议去做,lipo -create -arch i386 bin32 -arch x86_64 bin64 -output bin_universal
  • 我已经这样做了。像魅力一样工作。

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


【解决方案1】:

有一个超级简单的方法。编译两个版本的可执行文件,一个用于 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

编辑:哦!我没有意识到您需要运行时检查......通过sysctl -A 的输出,两个变量看起来可能有用。尝试解析 sysctl hw.optional.x86_64sysctl hw.cpu64bit_capable 的输出。我没有 32 位 Mac 来测试这个,但在 Core2Duo Mac 上的 Snow Leopard 中,这两个都设置为 1。

【讨论】:

  • 你甚至可以在一行中做到这一点,gcc -arch i386 -arch x86_64 somefile.m -o somefileUniversal :)
  • 这似乎是我的最佳解决方案。谢谢。虽然我还是很想知道如何检测 x64 或 x86,仅供参考。
  • 太好了,就这么简单。感谢您的回复。
  • Ger Teunis,您应该注意这里提出的 sizeof 测试与下面的 __LP64__ 建议一样是“编译时间”。
  • 没错,但他们提供的 lipo 解决方案效果很好。我同意原始问题没有得到回答,但 lipo 解决了我的问题。
【解决方案2】:

使用[[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;
}

【讨论】:

  • 那个不行。如果您的可执行文件是用 32 位编译的,则无论操作系统是什么,它都会提供 NSBundleExecutableArchitectureI386。
  • 当然,它就是这样工作的。它告诉您您的应用程序在哪个架构上运行。 x86_64 CPU 可以在 i386 中模拟和运行应用程序。如果您的二进制文件仅在 i386 中编译,它将在 i386 中运行。如果它是通用的,它通常会在 x86_64 CPU 上的 x86_64 中运行,除非您将内核选项更改为在 i386 中运行,或者如果您通过 arch -32 ... 运行您的应用程序。如果您想了解 CPU 架构而不考虑正在运行的应用程序的架构,请通过 sysctl 阅读 hw.machine,例如 bleater 的回答。
【解决方案3】:

您不必手动检测它来实现该效果。一个 Mach-O 可执行文件可以包含 32 位和 64 位英特尔机器的二进制文件,内核会自动运行最合适的二进制文件。如果您使用 XCode,项目检查器中有一个设置,您可以在其中设置您想要在单个通用二进制文件中拥有的架构(ppc、i386、x86_64)。

另外,请记住,在 OS X 上,运行 64 位内核(使用 Snow Leopard)和能够运行 64 位用户空间应用程序是两个相互正交的概念。如果你有一台 64 位 cpu 的机器,你可以在 64 位模式下运行用户级程序,即使内核在 32 位模式下运行(使用 Leopard 或 Snow Leopard),只要所有库您链接的可用于 64 位。所以检查操作系统是否支持 64 位并没有多大用处。

【讨论】:

  • 我以为我很清楚这一点。我试图更好地解释。我想调用一个非 FAT 二进制文件。一种针对 x86 进行了优化,另一种针对 x64 进行了优化。我没有创建二进制文件,也没有源代码。要选择最佳优化的非胖二进制文件,我需要知道我在什么 CPU 上运行。
【解决方案4】:

通常,您不需要在运行时检查您使用的是 64 位还是 32 位。如果您的主机应用程序(我称之为启动 64 位或 32 位工具的应用程序)是一个胖二进制文件,那么编译时检查就足够了。由于它将被编译两次(一次用于 fat 二进制文件的 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 位启动您的应用,请相信他们知道自己在做什么。无论如何,这是一个边缘案例,为什么要出于错误的完美感而为高级用户破坏事物。如果您能告诉用户解决方法是以 32 位启动的,那么您甚至可能会为自己发现一个仅限 64 位的错误感到高兴。

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

【讨论】:

    【解决方案5】:

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

    否则,我会执行以下操作:

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

    【讨论】:

    • 可悲的是编译时间。搜索运行时检查。无论如何感谢您的回复。
    • @Ger Teunis:接受的答案也是编译时间(sizeof 部分),这并不重要。如果有人运行您的 32 位二进制文​​件,尽管您提供了 64 位和 32 位二进制文​​件,那么即使它恰好是 64 位机器,也不认为世界是 32 位的。
    • 没错,但他们提供的 lipo 解决方案效果很好。我同意原始问题没有得到回答,但 lipo 解决了我的问题。
    【解决方案6】:

    以编程方式获取带有 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`
    

    【讨论】:

      【解决方案7】:

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

      【讨论】:

      • 这并没有告诉您您需要知道什么——64 位功能取决于操作系统版本和您运行的 CPU。
      猜你喜欢
      • 1970-01-01
      • 2011-03-13
      • 2016-01-12
      • 2012-03-12
      • 1970-01-01
      • 1970-01-01
      • 2013-04-07
      • 1970-01-01
      • 2012-10-03
      相关资源
      最近更新 更多