Commits

Ronald Oussoren committed 1cd4e03

Use explicit weak linking

Comments (0)

Files changed (8)

pyobjc-core/Modules/objc/pyobjc-api.h

  * * Use 'WEAK_LINKED_NAME(CFArrayCreate)' at the start of a wrapper module
  * * Use 'USE(CFArrayCreate)' to actually call the function, don't use the
  *   actual function.
- * * Use 'CHECK_WEAK_LINK(module_dict, CFArrayCreate)' in the module init function, 
+ * * Use 'CHECK_WEAK_LINK(module, CFArrayCreate)' in the module init function, 
  *   this will remove "CFArrayCreate" from the module dictionary when the function
  *   cannot by found by dlsym.
  * * All access to function should be done through weak-refs like this.
  */
 #include <dlfcn.h>
 
-#define WEAK_LINKED_NAME(NAME)	static __typeof__(&NAME) ptr_ ## NAME
+#define WEAK_LINKED_NAME(NAME)	static __typeof__(&NAME) ptr_ ## NAME;
 #define USE(NAME)		ptr_ ## NAME
-#define CHECK_WEAK_LINK(module_dict, NAME) \
+#define CHECK_WEAK_LINK(module, NAME) \
 	do {											\
 		void* dl = dlopen(NULL, RTLD_GLOBAL);						\
 		ptr_ ## NAME = dlsym(dl, PyObjC_STR(NAME));					\
 		dlclose(dl);									\
 		if (ptr_ ## NAME == NULL) {							\
-			if (PyDict_DelItemString((module_dict), PyObjC_STR(NAME)) < 0) {	\
+			if (PyDict_DelItemString(PyModule_GetDict(module), PyObjC_STR(NAME)) < 0) {	\
 				PyObjC_INITERROR();						\
 			}									\
 		}										\
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
 #define WEAK_LINKED_NAME_10_5(NAME)	
 #define USE_10_5(NAME)				NAME
-#define CHECK_WEAK_LINK_10_5(module_dict, NAME) do {} while(0)
+#define CHECK_WEAK_LINK_10_5(module, NAME) do {} while(0)
 #else
 #define WEAK_LINKED_NAME_10_5(NAME)	 	WEAK_LINKED_NAME(NAME)
 #define USE_10_5(NAME)				USE(NAME)
-#define CHECK_WEAK_LINK_10_5(module_dict, NAME) CHECK_WEAK_LINK(module_dict, NAME)
+#define CHECK_WEAK_LINK_10_5(module, NAME) CHECK_WEAK_LINK(module, NAME)
 #endif
 
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
 #define WEAK_LINKED_NAME_10_6(NAME)	
 #define USE_10_6(NAME)				NAME
-#define CHECK_WEAK_LINK_10_6(module_dict, NAME) do {} while(0)
+#define CHECK_WEAK_LINK_10_6(module, NAME) do {} while(0)
 #else
 #define WEAK_LINKED_NAME_10_6(NAME)	 	WEAK_LINKED_NAME(NAME)
 #define USE_10_6(NAME)				USE(NAME)
-#define CHECK_WEAK_LINK_10_6(module_dict, NAME) CHECK_WEAK_LINK(module_dict, NAME)
+#define CHECK_WEAK_LINK_10_6(module, NAME) CHECK_WEAK_LINK(module, NAME)
 #endif
 
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
 #define WEAK_LINKED_NAME_10_7(NAME)	
 #define USE_10_7(NAME)				NAME
-#define CHECK_WEAK_LINK_10_7(module_dict, NAME) do {} while(0)
+#define CHECK_WEAK_LINK_10_7(module, NAME) do {} while(0)
 #else
 #define WEAK_LINKED_NAME_10_7(NAME)	 	WEAK_LINKED_NAME(NAME)
 #define USE_10_7(NAME)				USE(NAME)
-#define CHECK_WEAK_LINK_10_7(module_dict, NAME) CHECK_WEAK_LINK(module_dict, NAME)
+#define CHECK_WEAK_LINK_10_7(module, NAME) CHECK_WEAK_LINK(module, NAME)
 #endif
 
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
 #define WEAK_LINKED_NAME_10_8(NAME)	
 #define USE_10_8(NAME)				NAME
-#define CHECK_WEAK_LINK_10_8(module_dict, NAME) do {} while(0)
+#define CHECK_WEAK_LINK_10_8(module, NAME) do {} while(0)
 #else
 #define WEAK_LINKED_NAME_10_8(NAME)	 	WEAK_LINKED_NAME(NAME)
 #define USE_10_8(NAME)				USE(NAME)
-#define CHECK_WEAK_LINK_10_8(module_dict, NAME) CHECK_WEAK_LINK(module_dict, NAME)
+#define CHECK_WEAK_LINK_10_8(module, NAME) CHECK_WEAK_LINK(module, NAME)
 #endif
 
 #endif /*  PyObjC_API_H */

pyobjc-core/TODO.txt

 Medium term
 -----------
 
-* All symbols that are available on 10.5 or later should be weak linked using the new
-  macros in pyobjc-api.h. See <https://bitbucket.org/ronaldoussoren/pyobjc/issue/46/deployment-issue-in-coregraphics>
-  for the reason for this.
-
-  This shouldn't result in a lot more code, and could even make manual wrappers slightly
-  shorter.
-
 * Loading a framework takes too much time, why?
 
 * Look for a more efficient encoding of _metadata.py, possibly using a C exension

pyobjc-framework-CFNetwork/Modules/_manual.m

 
 #if PyObjC_BUILD_RELEASE >= 1005
   /* This function is available on 10.5 or later, but the prototype isn't in the headers on 10.5 */
+WEAK_LINKED_NAME_10_5(CFNetworkExecuteProxyAutoConfigurationScript)
+
 static PyObject*
 m_CFNetworkExecuteProxyAutoConfigurationScript(PyObject* mod __attribute__((__unused__)),
 		PyObject* args)
 	CFRunLoopSourceRef ref = NULL;
 
 	PyObjC_DURING
-		ref = CFNetworkExecuteProxyAutoConfigurationScript(
+		ref = USE_10_5(CFNetworkExecuteProxyAutoConfigurationScript)(
 				script, url, 
 				m_CFProxyAutoConfigurationResultCallback,
 				&context);
 #endif
 
 #if PyObjC_BUILD_RELEASE >= 1005
+WEAK_LINKED_NAME_10_5(CFNetworkExecuteProxyAutoConfigurationURL)
+
 static PyObject*
 m_CFNetworkExecuteProxyAutoConfigurationURL(PyObject* mod __attribute__((__unused__)),
 		PyObject* args)
 	CFRunLoopSourceRef ref = NULL;
 
 	PyObjC_DURING
-		ref = CFNetworkExecuteProxyAutoConfigurationURL(
+		ref = USE_10_5(CFNetworkExecuteProxyAutoConfigurationURL)(
 				script, url, 
 				m_CFProxyAutoConfigurationResultCallback,
 				&context);
 		PyObjC_INITERROR();
 	}
 
-#if PyObjC_BUILD_RELEASE >= 1006
-	if (CFNetworkExecuteProxyAutoConfigurationScript == NULL) {
-		if (PyDict_DelItemString(m, "CFNetworkExecuteProxyAutoConfigurationScript") < 0) {
-			PyObjC_INITERROR();
-		}
-	}
-#endif
-#if PyObjC_BUILD_RELEASE >= 1005
-	if (CFNetworkExecuteProxyAutoConfigurationURL == NULL) {
-		if (PyDict_DelItemString(m, "CFNetworkExecuteProxyAutoConfigurationURL") < 0) {
-			PyObjC_INITERROR();
-		}
-	}
-#endif
+	CHECK_WEAK_LINK_10_5(m, CFNetworkExecuteProxyAutoConfigurationScript);
+	CHECK_WEAK_LINK_10_5(m, CFNetworkExecuteProxyAutoConfigurationURL);
 
 	PyObjC_INITDONE();
 }

pyobjc-framework-CFNetwork/PyObjCTest/test_cfhost.py

 
         self.assertResultIsCFRetained(CFHostCreateCopy)
         w = CFHostCreateCopy(None, v)
-        self.assertIsInstance(w, (type(None), CFHostRef))
+        self.assertIsInstance(w, type(v))
 
 
         self.assertArgHasType(CFHostGetReachability, 1, b'o^' + objc._C_NSBOOL)

pyobjc-framework-Cocoa/Modules/_CoreFoundation_CFFileDescriptor.m

 #pragma weak CFFileDescriptorCreate
 #pragma weak CFFileDescriptorGetContext
 
+WEAK_LINKED_NAME_10_5(CFFileDescriptorCreate)
+WEAK_LINKED_NAME_10_5(CFFileDescriptorGetContext)
+
 static void* 
 mod_filedescr_retain(void* info) 
 {
 
 	CFFileDescriptorRef rv = NULL;
 	PyObjC_DURING
-		rv = CFFileDescriptorCreate(
+		rv = USE_10_5(CFFileDescriptorCreate)(
 			allocator, descriptor, closeOnInvalidate,
 			mod_CFFileDescriptorCallBack, &context);
 		
 	context.version = 0;
 
 	PyObjC_DURING
-		CFFileDescriptorGetContext(f, &context);
+		USE_10_5(CFFileDescriptorGetContext)(f, &context);
 
 	PyObjC_HANDLER
 		PyObjCErr_FromObjC(localException);
 	},
 
 #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();		\
-		}		\
-	}
+	CHECK_WEAK_LINK_10_5(m, CFFileDescriptorCreate); \
+	CHECK_WEAK_LINK_10_5(m, CFFileDescriptorGetContext);

pyobjc-framework-Quartz/Modules/_CVPixelBuffer.m

 	PyGILState_Release(state);
 }
 
+WEAK_LINKED_NAME_10_5(CVPixelBufferCreateWithBytes)
+
 static PyObject*
 mod_CVPixelBufferCreateWithBytes(
 	PyObject* self __attribute__((__unused__)),
 	CVReturn rv;
 
 	PyObjC_DURING
-		rv = CVPixelBufferCreateWithBytes(
+		rv = USE_10_5(CVPixelBufferCreateWithBytes)(
 			allocator,
 			width,
 			height,
 
 	if (PyObjC_ImportAPI(m) < 0) PyObjC_INITERROR();
 
+#if PyObjC_BUILD_RELEASE >= 1005
+	CHECK_WEAK_LINK_10_5(m, CVPixelBufferCreateWithBytes);
+#endif
+
 	PyObjC_INITDONE();
 }

pyobjc-framework-Quartz/Modules/_callbacks.m

 }
 
 #if PyObjC_BUILD_RELEASE < 1008
+/* XXX: compile this in on 10.8 as well */
 
 static void 
 m_CGDataProviderSkipBytesCallback(void* _info, size_t count)
 }
 
 #if PyObjC_BUILD_RELEASE < 1008
+/* XXX: compile this in on 10.8 as well */
 static CGDataProviderCallbacks m_CGDataProviderCallbacks = {
 	m_CGDataProviderGetBytesCallback, 	/*  getBytes */
 	m_CGDataProviderSkipBytesCallback,	/*  skipBytes */
 #endif /* PyObjC_BUILD_RELEASE < 1008 */
 
 #if PyObjC_BUILD_RELEASE < 1008
+/* XXX: compile this in on 10.8 as well, using manual weaklinking support */
 static const void*
 m_CGDataProviderGetBytePointerCallback(void* _info)
 {
 
 };
 
+WEAK_LINKED_NAME_10_5(CGDataProviderCreateSequential)
+
 PyDoc_STRVAR(doc_CGDataProviderCreateSequential,
 	"CGDataConsumerCreateSequential(info, (getBytes, skipForward, rewind, releaseProvider)) -> object\n"
 	"\n"
 
 	CGDataProviderRef result;
 	PyObjC_DURING
-		result = CGDataProviderCreateSequential(real_info, 
+		result = USE_10_5(CGDataProviderCreateSequential)(real_info, 
 				&m_CGDataProviderSequentialCallbacks);
 
 	PyObjC_HANDLER
 
 
 #if PyObjC_BUILD_RELEASE < 1008
+/* XXX: compile in on 10.8 as well, unless min deploymet > 10.8 */
 PyDoc_STRVAR(doc_CGDataProviderCreate,
 	"CGDataConsumerCreate(info, (getBytes, skipBytes, rewind, releaseProvider)) -> object\n"
 	"\n"
         if (PyObjC_ImportAPI(m) < 0) PyObjC_INITERROR();
 
 #if PyObjC_BUILD_RELEASE >= 1005
-	if (CGDataProviderCreateSequential == NULL) {
-		if (PyDict_DelItemString(md, "CGDataProviderCreateSequential") < 0) {
-			PyObjC_INITERROR();
-		}
-	}
+	CHECK_WEAK_LINK_10_5(m, CGDataProviderCreateSequential);
 #endif
 	
 	PyObjC_INITDONE();

pyobjc-framework-Quartz/Modules/_coregraphics.m

 
 #import <ApplicationServices/ApplicationServices.h>
 
-#if PyObjC_BUILD_RELEASE >= 1006
-#  if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
-
-/* 
- * Implementation of poor-mans weak linking for a 10.6+ symbol, needed
- * to be able to use a binary created on OSX 10.8 on a 10.5 system.
- *
- * XXX: The same mechanism should be used for the other functions wrapped
- *      in this file.
- */
-#include <dlfcn.h>
-static CGContextRef (*ptr_CGBitmapContextCreateWithData)(
-		   void *data, size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow,
-		  CGColorSpaceRef space, CGBitmapInfo bitmapInfo, CGBitmapContextReleaseDataCallback releaseCallback,
-		   void *releaseInfo);
-#  else
-#    define ptr_CGBitmapContextCreateWithData CGBitmapContextCreateWithData
-#  endif
-#endif
- 
 
 
 #if PyObjC_BUILD_RELEASE >= 1005
 
 }
 
+WEAK_LINKED_NAME_10_6(CGBitmapContextCreateWithData)
 static PyObject*
 m_CGBitmapContextCreateWithData(PyObject* self __attribute__((__unused__)), 
 		PyObject* args)
 
 	CGContextRef ctx = NULL;
 	PyObjC_DURING
-		ctx = ptr_CGBitmapContextCreateWithData(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo, m_releasecallback, releaseInfo);
+		ctx = USE_10_6(CGBitmapContextCreateWithData)(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo, m_releasecallback, releaseInfo);
 
 	PyObjC_HANDLER
 		ctx = NULL;
 
 
 #if (PyObjC_BUILD_RELEASE >= 1006) && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6)
-	{
-		void* dl = dlopen(NULL, RTLD_GLOBAL);
-		ptr_CGBitmapContextCreateWithData = dlsym(dl, "CGBitmapContextCreateWithData");
-		if (ptr_CGBitmapContextCreateWithData == NULL) {
-			if (PyDict_DelItemString(d, "CGBitmapContextCreateWithData") < 0) {
-				PyObjC_INITERROR();
-			}
-		}
-		/* Don't call dlclose */
-	}
+	CHECK_WEAK_LINK_10_6(m, CGBitmapContextCreateWithData);
 #endif
 
 	PyObjC_INITDONE();