Commits

Dwayne Litzenberger  committed 1720c8a

Fix importing CoreFoundation on OSX 10.4 (Tiger) when using a newer SDK.

PyObjC binaries fail to load on 10.4 if they were built against the 10.5 SDK,
even if -mmacosx-version-min=10.4 was set, because they're still linked to
symbols from CFFileDescriptor[1], which was introduced in OS X v10.5.

The error happens when the CoreFoundation module is imported, and the backtrace
looks something like this:

File "CoreFoundation/_CoreFoundation.pyc", line 11, in __load
portError: dlopen([...]/lib-dynload/CoreFoundation/_CoreFoundation.so, 2): Symbol not found: _CFFileDescriptorCreate
Referenced from: [...]/lib-dynload/CoreFoundation/_CoreFoundation.so
Expected in: /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation

To fix this, we weakly link against the missing APIs using "#pragma weak" and
then remove the corresponding Python wrappers at runtime when we detect that
the underlying C functions aren't available. It's a bit gross, but it's
probably worse to try to mimic Py_InitModule*, which is "a bit of a hack"
according to its source code.

This way, users can write code like this:

try:
from CoreFouncation import CFFileDescriptorCreate
CFFileDescriptor_avail = True
except ImportError:
CFFileDescriptor_avail = False

or this:

import CoreFoundation
CFFileDescriptor_avail = hasattr(CoreFoundation, "CFFileDescriptorCreate")

In the above examples, CFFileDescriptor_avail will be True on OSX 10.5+ and
False otherwise.

[1] https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFFileDescriptorRef/Reference/reference.html

  • Participants
  • Parent commits adbb351

Comments (0)

Files changed (2)

File pyobjc-framework-Cocoa/Modules/_CoreFoundation.m

 		PyObjC_INITERROR();
 	}
 
+	/* Some C functions aren't available at runtime (e.g. when compiling on
+	 * OS X 10.5 but running on 10.4), so we use "#pragma weak" to weakly
+	 * link the functions, then we remove the corresponding Python wrappers
+	 * at runtime when we detect that the underlying C functions aren't
+	 * available.  It's a bit gross, but it's probably worse to try to
+	 * mimic Py_InitModule*, which is "a bit of a hack" according to its
+	 * source code.
+	 */
+	COREFOUNDATION_FILEDESCRIPTOR_AFTER_CREATE
+
 	if (PyObjC_ImportAPI(m) == -1) PyObjC_INITERROR();
 
 	PyObjC_INITDONE();

File pyobjc-framework-Cocoa/Modules/_CoreFoundation_CFFileDescriptor.m

 #if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED
 
+/* Needed when building against the OS X 10.5+ SDK but running on 10.4. */
+#pragma weak CFFileDescriptorCreate
+#pragma weak CFFileDescriptorGetContext
+
 static void* 
 mod_filedescr_retain(void* info) 
 {
 		METH_VARARGS,		\
 		NULL		\
 	},
+
+#define COREFOUNDATION_FILEDESCRIPTOR_AFTER_CREATE		\
+	if (&CFFileDescriptorCreate == NULL) {  /* weakly linked */		\
+		if (PyObject_DelAttrString(m, "CFFileDescriptorCreate") == -1) {		\
+			PyObjC_INITERROR();		\
+		}		\
+	}		\
+	if (&CFFileDescriptorGetContext == NULL) {  /* weakly linked */		\
+		if (PyObject_DelAttrString(m, "CFFileDescriptorGetContext") == -1) {		\
+			PyObjC_INITERROR();		\
+		}		\
+	}