Provide API in xpcom macutils for determining universal binary type. b=572125 r=benwa
authorJosh Aas <joshmoz@gmail.com>
Thu, 15 Jul 2010 22:32:00 -0400
changeset 47782 b141a304ad08a26961e81d29d9d7b4a20d71ce19
parent 47781 764bb4ae886c5058c5c7634d6ffb02ddfe431354
child 47784 aba8cc27fcef3ceafc61f10e0090150e1b1c0849
push id14417
push userjosh@mozilla.com
push dateFri, 16 Jul 2010 02:32:15 +0000
treeherderautoland@b141a304ad08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbenwa
bugs572125
milestone2.0b2pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Provide API in xpcom macutils for determining universal binary type. b=572125 r=benwa
xpcom/base/nsIMacUtils.idl
xpcom/base/nsMacUtilsImpl.cpp
xpcom/base/nsMacUtilsImpl.h
--- a/xpcom/base/nsIMacUtils.idl
+++ b/xpcom/base/nsIMacUtils.idl
@@ -36,22 +36,29 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 /**
  * nsIMacUtils: Generic globally-available Mac-specific utilities.
  */
 
-[scriptable, uuid(F6FC107C-5CBA-4C5C-A35E-B69D580D1DB6)]
+[scriptable, uuid(5E9072D7-FF95-455E-9466-8AF9841A72EC)]
 interface nsIMacUtils : nsISupports
 {
   /**
    * True when the main executable is a fat file supporting at least
    * ppc and x86 (universal binary).
    */
   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).
    */
   readonly attribute boolean isTranslated;
 };
--- a/xpcom/base/nsMacUtilsImpl.cpp
+++ b/xpcom/base/nsMacUtilsImpl.cpp
@@ -33,103 +33,120 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #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;
   }
 
-  PRBool foundPPC = PR_FALSE,
-         foundX86 = PR_FALSE;
-  CFURLRef executableURL = nsnull;
-  int fd = -1;
+  archString.Truncate();
 
-  CFBundleRef mainBundle;
-  if (!(mainBundle = ::CFBundleGetMainBundle()))
-    goto done;
-
-  if (!(executableURL = ::CFBundleCopyExecutableURL(mainBundle)))
-    goto done;
+  PRBool foundPPC = PR_FALSE,
+         foundX86 = PR_FALSE,
+         foundPPC64 = PR_FALSE,
+         foundX86_64 = PR_FALSE;
 
-  char executablePath[PATH_MAX];
-  if (!::CFURLGetFileSystemRepresentation(executableURL, PR_TRUE,
-                                          (UInt8*) executablePath,
-                                          sizeof(executablePath)))
-    goto done;
+  CFBundleRef mainBundle = ::CFBundleGetMainBundle();
+  if (!mainBundle) {
+    return NS_ERROR_FAILURE;
+  }
 
-  if ((fd = open(executablePath, O_RDONLY)) == -1)
-    goto done;
+  CFArrayRef archList = ::CFBundleCopyExecutableArchitectures(mainBundle);
+  if (!archList) {
+    return NS_ERROR_FAILURE;
+  }
 
-  struct fat_header fatHeader;
-  if (read(fd, &fatHeader, sizeof(fatHeader)) != sizeof(fatHeader))
-    goto done;
+  CFIndex archCount = ::CFArrayGetCount(archList);
+  for (CFIndex i = 0; i < archCount; i++) {
+    CFNumberRef arch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archList, i));
 
-  // 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;
+    int archInt = 0;
+    if (!::CFNumberGetValue(arch, kCFNumberIntType, &archInt)) {
+      ::CFRelease(archList);
+      return NS_ERROR_FAILURE;
+    }
 
-  // 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;
+    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;
+  }
 
-    // This is still part of the fat header, so byte-swap as needed.
-    fatArch.cputype = CFSwapInt32BigToHost(fatArch.cputype);
+  ::CFRelease(archList);
 
-    // 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;
+  // 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 (foundPPC && foundX86)
-    sIsUniversalBinary = PR_TRUE;
+  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"));
+  }
 
-done:
-  if (fd != -1)
-    close(fd);
-  if (executableURL)
-    ::CFRelease(executableURL);
+  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);
+}
 
-  *aIsUniversalBinary = sIsUniversalBinary;
-  sInitialized = PR_TRUE;
+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)
 {
 #ifdef __ppc__
   static PRBool  sInitialized = PR_FALSE;
 
   // Initialize sIsNative to 1.  If the sysctl fails because it doesn't
--- a/xpcom/base/nsMacUtilsImpl.h
+++ b/xpcom/base/nsMacUtilsImpl.h
@@ -34,27 +34,34 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsMacUtilsImpl_h___
 #define nsMacUtilsImpl_h___
 
 #include "nsIMacUtils.h"
+#include "nsString.h"
 
 class nsMacUtilsImpl : public nsIMacUtils
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMACUTILS
 
   nsMacUtilsImpl() {}
 
 private:
   ~nsMacUtilsImpl() {}
+
+  nsresult GetArchString(nsAString& archString);
+
+  // A string containing a "-" delimited list of architectures
+  // in our binary.
+  nsString mBinaryArchs;
 };
 
 // Global singleton service
 // 697BD3FD-43E5-41CE-AD5E-C339175C0818
 #define NS_MACUTILSIMPL_CLASSNAME "Mac OS X Utilities"
 #define NS_MACUTILSIMPL_CID \
  {0x697BD3FD, 0x43E5, 0x41CE, {0xAD, 0x5E, 0xC3, 0x39, 0x17, 0x5C, 0x08, 0x18}}
 #define NS_MACUTILSIMPL_CONTRACTID "@mozilla.org/xpcom/mac-utils;1"