[Bf-committers] 2nd Try OS X Plugins Fix

Douglas Bischoff bf-committers@blender.org
Tue, 2 Dec 2003 12:54:21 -0500


Hello all:

Okay, second try at fixing OS X plugins involves rewriting the dlopen() 
series of functions in native OS X operations using the code from the 
dlcompat library as a starting point.

I have contacted the author of dlcompat to ensure that his rights with 
regards to his code are respected.

Here are 2 diff files that enable the revised method to work.

-Bischofftep

Index: bmake
===================================================================
RCS file: /cvsroot/bf-blender/blender/release/plugins/bmake,v
retrieving revision 1.5
diff -u -u -r1.5 bmake
--- bmake	25 Nov 2003 20:10:06 -0000	1.5
+++ bmake	2 Dec 2003 17:53:05 -0000
@@ -74,7 +74,7 @@
          CC="cc";
          CFLAGS="-fPIC -funsigned-char -O2 -fno-common";
          LD="cc";
-        LDFLAGS="-flat_namespace -bundle -bundle_loader 
../../blender.app/Contents/MacOS/blender -ldl -lm";
+        LDFLAGS="-flat_namespace -bundle -bundle_loader 
../../blender.app/Contents/MacOS/blender -lm";
          EXT="so";
  fi

Index: dynlib.c
===================================================================
RCS file: 
/cvsroot/bf-blender/blender/source/blender/blenlib/intern/dynlib.c,v
retrieving revision 1.7
diff -u -u -r1.7 dynlib.c
--- dynlib.c	25 Nov 2003 20:10:06 -0000	1.7
+++ dynlib.c	2 Dec 2003 17:49:21 -0000
@@ -102,7 +102,203 @@
  	free(lib);
  }

-#else	/* Unix & MacOS X */
+#else
+#ifdef __APPLE__	/* MacOS X */
+
+#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+
+#define ERR_STR_LEN 256
+
+struct PILdynlib {
+	void *handle;
+};
+
+char *osxerror(int setget, const char *str, ...)
+{
+	static char errstr[ERR_STR_LEN];
+	static int err_filled = 0;
+	char *retval;
+	NSLinkEditErrors ler;
+	int lerno;
+	const char *dylderrstr;
+	const char *file;
+	va_list arg;
+	if (setget <= 0)
+	{
+		va_start(arg, str);
+		strncpy(errstr, "dlsimple: ", ERR_STR_LEN);
+		vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg);
+		va_end(arg);
+	/* We prefer to use the dyld error string if setget is 0 */
+		if (setget == 0) {
+			NSLinkEditError(&ler, &lerno, &file, &dylderrstr);
+			printf("dyld: %s\n",dylderrstr);
+			if (dylderrstr && strlen(dylderrstr))
+				strncpy(errstr,dylderrstr,ERR_STR_LEN);
+		}		
+		err_filled = 1;
+		retval = NULL;
+	}
+	else
+	{
+		if (!err_filled)
+			retval = NULL;
+		else
+			retval = errstr;
+		err_filled = 0;
+	}
+	return retval;
+}
+
+void *osxdlopen(const char *path, int mode)
+{
+	void *module = 0;
+	NSObjectFileImage ofi = 0;
+	NSObjectFileImageReturnCode ofirc;
+	static int (*make_private_module_public) (NSModule module) = 0;
+	unsigned int flags =  NSLINKMODULE_OPTION_RETURN_ON_ERROR | 
NSLINKMODULE_OPTION_PRIVATE;
+
+	/* If we got no path, the app wants the global namespace, use -1 as 
the marker
+	   in this case */
+	if (!path)
+		return (void *)-1;
+
+	/* Create the object file image, works for things linked with the 
-bundle arg to ld */
+	ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
+	switch (ofirc)
+	{
+		case NSObjectFileImageSuccess:
+			/* It was okay, so use NSLinkModule to link in the image */
+			if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW;
+			module = NSLinkModule(ofi, path,flags);
+			/* Don't forget to destroy the object file image, unless you like 
leaks */
+			NSDestroyObjectFileImage(ofi);
+			/* If the mode was global, then change the module, this avoids
+			   multiply defined symbol errors to first load private then make
+			   global. Silly, isn't it. */
+			if ((mode & RTLD_GLOBAL))
+			{
+			  if (!make_private_module_public)
+			  {
+			    _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
+				(unsigned long *)&make_private_module_public);
+			  }
+			  make_private_module_public(module);
+			}
+			break;
+		case NSObjectFileImageInappropriateFile:
+			/* It may have been a dynamic library rather than a bundle, try to 
load it */
+			module = (void *)NSAddImage(path, 
NSADDIMAGE_OPTION_RETURN_ON_ERROR);
+			break;
+		case NSObjectFileImageFailure:
+			osxerror(0,"Object file setup failure :  \"%s\"", path);
+			return 0;
+		case NSObjectFileImageArch:
+			osxerror(0,"No object for this architecture :  \"%s\"", path);
+			return 0;
+		case NSObjectFileImageFormat:
+			osxerror(0,"Bad object file format :  \"%s\"", path);
+			return 0;
+		case NSObjectFileImageAccess:
+			osxerror(0,"Can't read object file :  \"%s\"", path);
+			return 0;		
+	}
+	if (!module)
+		osxerror(0, "Can not open \"%s\"", path);
+	return module;
+}
+
+PILdynlib *PIL_dynlib_open(char *name) {
+	void *handle= osxdlopen(name, RTLD_LAZY);
+
+	if (handle) {	
+		PILdynlib *lib= malloc(sizeof(*lib));
+		lib->handle= handle;
+		
+		return lib;
+	} else {
+		return NULL;
+	}
+}
+
+void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname)
+{
+	int sym_len = strlen(symname);
+	void *value = NULL;
+	char *malloc_sym = NULL;
+	NSSymbol *nssym = 0;
+	malloc_sym = malloc(sym_len + 2);
+	if (malloc_sym)
+	{
+		sprintf(malloc_sym, "_%s", symname);
+		/* If the lib->handle is -1, if is the app global context */
+		if (lib->handle == (void *)-1)
+		{
+			/* Global context, use NSLookupAndBindSymbol */
+			if (NSIsSymbolNameDefined(malloc_sym))
+			{
+				nssym = NSLookupAndBindSymbol(malloc_sym);
+			}
+		}
+		/* Now see if the lib->handle is a struch mach_header* or not, use 
NSLookupSymbol in image
+		   for libraries, and NSLookupSymbolInModule for bundles */
+		else
+		{
+			/* Check for both possible magic numbers depending on x86/ppc byte 
order */
+			if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
+				(((struct mach_header *)lib->handle)->magic == MH_CIGAM))
+			{
+				if (NSIsSymbolNameDefinedInImage((struct mach_header 
*)lib->handle, malloc_sym))
+				{
+					nssym = NSLookupSymbolInImage((struct mach_header *)lib->handle,
+												  malloc_sym,
+												  NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
+												  | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+				}
+	
+			}
+			else
+			{
+				nssym = NSLookupSymbolInModule(lib->handle, malloc_sym);
+			}
+		}
+		if (!nssym)
+		{
+			osxerror(0, "symname \"%s\" Not found", symname);
+		}
+		value = NSAddressOfSymbol(nssym);
+		free(malloc_sym);
+	}
+	else
+	{
+		osxerror(-1, "Unable to allocate memory");
+	}
+	return value;
+}
+
+char *PIL_dynlib_get_error_as_string(PILdynlib* lib)
+{
+	return osxerror(1, (char *)NULL);
+}
+	
+void PIL_dynlib_close(PILdynlib *lib)
+{
+	if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
+		(((struct mach_header *)lib->handle)->magic == MH_CIGAM))
+	{
+		osxerror(-1, "Can't remove dynamic libraries on darwin");
+	}
+	if (!NSUnLinkModule(lib->handle, 0))
+	{
+		osxerror(0, "unable to unlink module %s", 
NSNameOfModule(lib->handle));
+	}
+	
+	free(lib);
+}
+
+#else	/* Unix */

  #include <dlfcn.h>

@@ -137,4 +333,5 @@
  	free(lib);
  }

+#endif
  #endif