Provide API in xpcom macutils for determining universal binary type. b=572125 r=benwa

This commit is contained in:
Josh Aas 2010-07-15 22:32:00 -04:00
Родитель 5d2b2437ae
Коммит fdcf53b706
3 изменённых файлов: 101 добавлений и 70 удалений

Просмотреть файл

@ -41,7 +41,7 @@
* nsIMacUtils: Generic globally-available Mac-specific utilities.
*/
[scriptable, uuid(F6FC107C-5CBA-4C5C-A35E-B69D580D1DB6)]
[scriptable, uuid(5E9072D7-FF95-455E-9466-8AF9841A72EC)]
interface nsIMacUtils : nsISupports
{
/**
@ -50,6 +50,13 @@ interface nsIMacUtils : nsISupports
*/
readonly attribute boolean isUniversalBinary;
/**
* Returns a string containing a list of architectures delimited
* by "-". Architecture sets are always in the same order:
* ppc > i386 > ppc64 > x86_64 > (future additions)
*/
readonly attribute AString architecturesInBinary;
/**
* True when running under binary translation (Rosetta).
*/

Просмотреть файл

@ -38,93 +38,110 @@
#include "nsMacUtilsImpl.h"
#include <CoreFoundation/CoreFoundation.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <mach-o/fat.h>
NS_IMPL_ISUPPORTS1(nsMacUtilsImpl, nsIMacUtils)
/* readonly attribute boolean isUniversalBinary; */
// True when the main executable is a fat file supporting at least
// ppc and x86 (universal binary).
NS_IMETHODIMP nsMacUtilsImpl::GetIsUniversalBinary(PRBool *aIsUniversalBinary)
nsresult nsMacUtilsImpl::GetArchString(nsAString& archString)
{
static PRBool sInitialized = PR_FALSE,
sIsUniversalBinary = PR_FALSE;
if (sInitialized) {
*aIsUniversalBinary = sIsUniversalBinary;
if (!mBinaryArchs.IsEmpty()) {
archString.Assign(mBinaryArchs);
return NS_OK;
}
archString.Truncate();
PRBool foundPPC = PR_FALSE,
foundX86 = PR_FALSE;
CFURLRef executableURL = nsnull;
int fd = -1;
foundX86 = PR_FALSE,
foundPPC64 = PR_FALSE,
foundX86_64 = PR_FALSE;
CFBundleRef mainBundle;
if (!(mainBundle = ::CFBundleGetMainBundle()))
goto done;
if (!(executableURL = ::CFBundleCopyExecutableURL(mainBundle)))
goto done;
char executablePath[PATH_MAX];
if (!::CFURLGetFileSystemRepresentation(executableURL, PR_TRUE,
(UInt8*) executablePath,
sizeof(executablePath)))
goto done;
if ((fd = open(executablePath, O_RDONLY)) == -1)
goto done;
struct fat_header fatHeader;
if (read(fd, &fatHeader, sizeof(fatHeader)) != sizeof(fatHeader))
goto done;
// The fat header is always stored on disk as big-endian.
fatHeader.magic = CFSwapInt32BigToHost(fatHeader.magic);
fatHeader.nfat_arch = CFSwapInt32BigToHost(fatHeader.nfat_arch);
// Main executable is thin.
if (fatHeader.magic != FAT_MAGIC)
goto done;
// Loop over each architecture in the file. We're presently only
// interested in 32-bit PPC and x86.
for (PRUint32 i = 0 ; i < fatHeader.nfat_arch ; i++) {
struct fat_arch fatArch;
if (read(fd, &fatArch, sizeof(fatArch)) != sizeof(fatArch))
goto done;
// This is still part of the fat header, so byte-swap as needed.
fatArch.cputype = CFSwapInt32BigToHost(fatArch.cputype);
// Don't mask out the ABI bits. This allows identification of ppc64
// as distinct from ppc. CPU_TYPE_X86 is preferred to CPU_TYPE_I386
// but does not exist prior to the 10.4 headers.
if (fatArch.cputype == CPU_TYPE_POWERPC)
foundPPC = PR_TRUE;
else if (fatArch.cputype == CPU_TYPE_I386)
foundX86 = PR_TRUE;
CFBundleRef mainBundle = ::CFBundleGetMainBundle();
if (!mainBundle) {
return NS_ERROR_FAILURE;
}
if (foundPPC && foundX86)
sIsUniversalBinary = PR_TRUE;
CFArrayRef archList = ::CFBundleCopyExecutableArchitectures(mainBundle);
if (!archList) {
return NS_ERROR_FAILURE;
}
done:
if (fd != -1)
close(fd);
if (executableURL)
::CFRelease(executableURL);
CFIndex archCount = ::CFArrayGetCount(archList);
for (CFIndex i = 0; i < archCount; i++) {
CFNumberRef arch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archList, i));
*aIsUniversalBinary = sIsUniversalBinary;
sInitialized = PR_TRUE;
int archInt = 0;
if (!::CFNumberGetValue(arch, kCFNumberIntType, &archInt)) {
::CFRelease(archList);
return NS_ERROR_FAILURE;
}
if (archInt == kCFBundleExecutableArchitecturePPC)
foundPPC = PR_TRUE;
else if (archInt == kCFBundleExecutableArchitectureI386)
foundX86 = PR_TRUE;
else if (archInt == kCFBundleExecutableArchitecturePPC64)
foundPPC64 = PR_TRUE;
else if (archInt == kCFBundleExecutableArchitectureX86_64)
foundX86_64 = PR_TRUE;
}
::CFRelease(archList);
// The order in the string must always be the same so
// don't do this in the loop.
if (foundPPC) {
mBinaryArchs.Append(NS_LITERAL_STRING("ppc"));
}
if (foundX86) {
if (!mBinaryArchs.IsEmpty()) {
mBinaryArchs.Append(NS_LITERAL_STRING("-"));
}
mBinaryArchs.Append(NS_LITERAL_STRING("i386"));
}
if (foundPPC64) {
if (!mBinaryArchs.IsEmpty()) {
mBinaryArchs.Append(NS_LITERAL_STRING("-"));
}
mBinaryArchs.Append(NS_LITERAL_STRING("ppc64"));
}
if (foundX86_64) {
if (!mBinaryArchs.IsEmpty()) {
mBinaryArchs.Append(NS_LITERAL_STRING("-"));
}
mBinaryArchs.Append(NS_LITERAL_STRING("x86_64"));
}
archString.Assign(mBinaryArchs);
return (archString.IsEmpty() ? NS_ERROR_FAILURE : NS_OK);
}
NS_IMETHODIMP nsMacUtilsImpl::GetIsUniversalBinary(PRBool *aIsUniversalBinary)
{
NS_ENSURE_ARG_POINTER(aIsUniversalBinary);
*aIsUniversalBinary = PR_FALSE;
nsAutoString archString;
nsresult rv = GetArchString(archString);
if (NS_FAILED(rv))
return rv;
// The delimiter char in the arch string is '-', so if that character
// is in the string we know we have multiple architectures.
*aIsUniversalBinary = (archString.Find("-") > -1);
return NS_OK;
}
NS_IMETHODIMP nsMacUtilsImpl::GetArchitecturesInBinary(nsAString& archString)
{
return GetArchString(archString);
}
/* readonly attribute boolean isTranslated; */
// True when running under binary translation (Rosetta).
NS_IMETHODIMP nsMacUtilsImpl::GetIsTranslated(PRBool *aIsTranslated)

Просмотреть файл

@ -39,6 +39,7 @@
#define nsMacUtilsImpl_h___
#include "nsIMacUtils.h"
#include "nsString.h"
class nsMacUtilsImpl : public nsIMacUtils
{
@ -50,6 +51,12 @@ public:
private:
~nsMacUtilsImpl() {}
nsresult GetArchString(nsAString& archString);
// A string containing a "-" delimited list of architectures
// in our binary.
nsString mBinaryArchs;
};
// Global singleton service