4

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

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

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

4

7 回答 7

11

有一个超级简单的方法。编译两个版本的可执行文件,一个用于 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_64and的输出sysctl hw.cpu64bit_capable。我没有 32 位 Mac 来测试这个,但在 Core2Duo Mac 上的 Snow Leopard 中,这两个都设置为 1。

于 2010-01-01T16:56:13.107 回答
8

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

  • 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;
}
于 2010-10-01T10:05:47.227 回答
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 位并不是那么有用。

于 2010-01-01T16:56:34.810 回答
3

通常,您不需要能够在运行时检查您是使用 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 。

于 2010-01-02T16:41:41.293 回答
2

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

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

-(BOOL) is64Bit
{
#if __LP64__
  return YES;
#else
  return NO;
#endif
}
于 2010-01-01T16:57:57.097 回答
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`
于 2014-04-03T00:34:34.633 回答
0

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

于 2010-01-01T16:48:57.163 回答