我目前正在编写一个Cocoa应用程序,它需要执行一些针对 32 位和 64 位优化的(控制台)应用程序。因此,我想检测应用程序正在运行的 CPU 架构,以便我可以启动正确的控制台应用程序。
简而言之:我如何检测应用程序是否在 64 位操作系统上运行?
编辑:我知道Mach-O fat 二进制文件,这不是我的问题。我需要知道这一点,这样我才能启动另一个非捆绑(控制台)应用程序。一种针对x86进行了优化,另一种针对x64进行了优化。
有一个超级简单的方法。编译两个版本的可执行文件,一个用于 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_64
and的输出sysctl hw.cpu64bit_capable
。我没有 32 位 Mac 来测试这个,但在 Core2Duo Mac 上的 Snow Leopard 中,这两个都设置为 1。
使用[[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;
}
您不必手动检测它即可达到该效果。一个 Mach-O 可执行文件可以包含 32 位和 64 位英特尔机器的二进制文件,内核会自动运行最合适的二进制文件。如果您使用的是 XCode,项目检查器中有一个设置,您可以在其中设置您想要在单个通用二进制文件中拥有的架构(ppc、i386、x86_64)。
另外,请记住,在 OS X 上,运行 64 位内核(使用 Snow Leopard)和能够运行 64 位用户空间应用程序是两个正交的概念。如果你有一台 64 位 cpu 的机器,你可以在 64 位模式下运行用户级程序,即使内核在 32 位模式下运行(使用 Leopard 或 Snow Leopard),只要所有库您链接的可用于 64 位。因此,检查操作系统是否支持 64 位并不是那么有用。
通常,您不需要能够在运行时检查您是使用 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 。
如果您使用的是 Snow Leopard,请使用 NSRunningApplication 的 executableArchitecture。
否则,我会执行以下操作:
-(BOOL) is64Bit
{
#if __LP64__
return YES;
#else
return NO;
#endif
}
以编程方式获取带有 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`
检查操作系统版本的标准方法(以及是否它的雪豹,一个 64 位操作系统)在此处详细说明。