diff --git a/pd/src/m_class.c b/pd/src/m_class.c
index 3db693bbb80cc29615b8cb4cc54dc2b9774c337d..85ca523491fa773cf446c07667331079063f4c08 100644
--- a/pd/src/m_class.c
+++ b/pd/src/m_class.c
@@ -613,9 +613,6 @@ int pd_setloadingabstraction(t_symbol *sym);
     doesn't know.  Pd tries to load it as an extern, then as an abstraction. */
 void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv)
 {
-    t_pd *current;
-    int fd;
-    char dirbuf[FILENAME_MAX], *nameptr;
     if (tryingalready) return;
     newest = 0;
     class_loadsym = s;
@@ -627,25 +624,6 @@ void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv)
         return;
     }
     class_loadsym = 0;
-    current = s__X.s_thing;
-    if ((fd = canvas_open(canvas_getcurrent(), s->s_name, ".pd",
-        dirbuf, &nameptr, FILENAME_MAX, 0)) >= 0 ||
-            (fd = canvas_open(canvas_getcurrent(), s->s_name, ".pat",
-                dirbuf, &nameptr, FILENAME_MAX, 0)) >= 0)
-    {
-        close (fd);
-        if (!pd_setloadingabstraction(s))
-        {
-            canvas_setargs(argc, argv);
-            binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
-            canvas_initbang((t_canvas *)(s__X.s_thing));/* JMZ*/
-            if (s__X.s_thing != current)
-                canvas_popabstraction((t_canvas *)(s__X.s_thing));
-            canvas_setargs(0, 0);
-        }
-        else error("%s: can't load abstraction within itself\n", s->s_name);
-    }
-    else newest = 0;
 }
 
 t_symbol  s_pointer =   {"pointer", 0, 0};
diff --git a/pd/src/s_loader.c b/pd/src/s_loader.c
index 23140ccd94a80c13b4bbfe66c1fb1fe5a3fb890f..fe1304c63155578b5f1be4f2ee34de2b454be482 100644
--- a/pd/src/s_loader.c
+++ b/pd/src/s_loader.c
@@ -2,20 +2,20 @@
 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
 * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
-#ifdef HAVE_LIBDL
+#if defined(HAVE_LIBDL) || defined(__FreeBSD__)
 #include <dlfcn.h>
 #endif
-#ifdef UNISTD
+#ifdef HAVE_UNISTD_H
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #endif
-#ifdef MSW
+#ifdef _WIN32
 #include <io.h>
 #include <windows.h>
 #endif
 #ifdef __APPLE__
-#include <mach-o/dyld.h> 
+#include <mach-o/dyld.h>
 #endif
 #include <string.h>
 #include "m_pd.h"
@@ -24,6 +24,7 @@
 #include <sys/stat.h>
 #ifdef _MSC_VER  /* This is only for Microsoft's compiler, not cygwin, e.g. */
 #define snprintf sprintf_s
+#define stat _stat
 #endif
 
 typedef void (*t_xxx)(void);
@@ -36,9 +37,7 @@ objects.  The specific name is the letter b, l, d, or m for  BSD, linux,
 darwin, or microsoft, followed by a more specific string, either "fat" for
 a fat binary or an indication of the instruction set. */
 
-#ifdef __FreeBSD__
-static char sys_dllextent[] = ".b_i386", sys_dllextent2[] = ".pd_freebsd";
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__) || defined(__FreeBSD__)
 static char sys_dllextent2[] = ".pd_linux";
 # ifdef __x86_64__
 static char sys_dllextent[] = ".l_ia64"; // this should be .l_x86_64 or .l_amd64
@@ -69,7 +68,7 @@ typedef struct _loadedlist
 } t_loadlist;
 
 static t_loadlist *sys_loaded;
-int sys_onloadlist(char *classname) /* return true if already loaded */
+int sys_onloadlist(const char *classname) /* return true if already loaded */
 {
     t_symbol *s = gensym(classname);
     t_loadlist *ll;
@@ -79,7 +78,8 @@ int sys_onloadlist(char *classname) /* return true if already loaded */
     return (0);
 }
 
-void sys_putonloadlist(char *classname) /* add to list of loaded modules */
+     /* add to list of loaded modules */
+void sys_putonloadlist(const char *classname)
 {
     t_loadlist *ll = (t_loadlist *)getbytes(sizeof(*ll));
     ll->ll_name = gensym(classname);
@@ -90,27 +90,31 @@ void sys_putonloadlist(char *classname) /* add to list of loaded modules */
 
 void class_set_extern_dir(t_symbol *s);
 
-static int sys_do_load_lib(t_canvas *canvas, char *objectname)
+static int sys_do_load_abs(t_canvas *canvas, const char *objectname,
+    const char *path);
+static int sys_do_load_lib(t_canvas *canvas, const char *objectname,
+    const char *path)
 {
-    char symname[MAXPDSTRING], filename[FILENAME_MAX], dirbuf[FILENAME_MAX],
-        *classname, *nameptr;
+    char symname[MAXPDSTRING], filename[MAXPDSTRING], dirbuf[MAXPDSTRING],
+        *nameptr, altsymname[MAXPDSTRING];
+    const char *classname, *cnameptr;
     void *dlobj;
     t_xxx makeout = NULL;
     int i, hexmunge = 0, fd;
-#ifdef MSW
+#ifdef _WIN32
     HINSTANCE ntdll;
 #endif
-    if (classname = strrchr(objectname, '/'))
+        /* NULL-path is only used as a last resort,
+           but we have already tried all paths */
+    if(!path)return (0);
+
+    if ((classname = strrchr(objectname, '/')))
         classname++;
     else classname = objectname;
-    if (sys_onloadlist(objectname))
+    for (i = 0, cnameptr = classname; i < MAXPDSTRING-7 && *cnameptr;
+        cnameptr++)
     {
-        post("%s: already loaded", objectname);
-        return (1);
-    }
-    for (i = 0, nameptr = classname; i < MAXPDSTRING-7 && *nameptr; nameptr++)
-    {
-        char c = *nameptr;
+        char c = *cnameptr;
         if ((c>='0' && c<='9') || (c>='A' && c<='Z')||
            (c>='a' && c<='z' )|| c == '_')
         {
@@ -118,7 +122,7 @@ static int sys_do_load_lib(t_canvas *canvas, char *objectname)
             i++;
         }
             /* trailing tilde becomes "_tilde" */
-        else if (c == '~' && nameptr[1] == 0)
+        else if (c == '~' && cnameptr[1] == 0)
         {
             strcpy(symname+i, "_tilde");
             i += strlen(symname+i);
@@ -137,76 +141,112 @@ static int sys_do_load_lib(t_canvas *canvas, char *objectname)
         strncpy(symname, "setup_", 6);
     }
     else strcat(symname, "_setup");
-    
+
 #if 0
-    fprintf(stderr, "lib: %s %s\n", classname, symname);
+    fprintf(stderr, "lib: %s\n", classname);
 #endif
         /* try looking in the path for (objectname).(sys_dllextent) ... */
-    if ((fd = canvas_open(canvas, objectname, sys_dllextent,
-        dirbuf, &nameptr, FILENAME_MAX, 1)) >= 0)
+    if ((fd = sys_trytoopenone(path, objectname, sys_dllextent,
+        dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0)
             goto gotone;
         /* same, with the more generic sys_dllextent2 */
-    if ((fd = canvas_open(canvas, objectname, sys_dllextent2,
-        dirbuf, &nameptr, FILENAME_MAX, 1)) >= 0)
+    if ((fd = sys_trytoopenone(path, objectname, sys_dllextent2,
+        dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0)
             goto gotone;
         /* next try (objectname)/(classname).(sys_dllextent) ... */
-    strncpy(filename, objectname, FILENAME_MAX);
+    strncpy(filename, objectname, MAXPDSTRING);
     filename[MAXPDSTRING-2] = 0;
     strcat(filename, "/");
-    strncat(filename, classname, FILENAME_MAX-strlen(filename));
-    filename[FILENAME_MAX-1] = 0;
-    if ((fd = canvas_open(canvas, filename, sys_dllextent,
-        dirbuf, &nameptr, FILENAME_MAX, 1)) >= 0)
+    strncat(filename, classname, MAXPDSTRING-strlen(filename));
+    filename[MAXPDSTRING-1] = 0;
+    if ((fd = sys_trytoopenone(path, filename, sys_dllextent,
+        dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0)
             goto gotone;
-    if ((fd = canvas_open(canvas, filename, sys_dllextent2,
-        dirbuf, &nameptr, FILENAME_MAX, 1)) >= 0)
+    if ((fd = sys_trytoopenone(path, filename, sys_dllextent2,
+        dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0)
             goto gotone;
+#ifdef ANDROID
+    /* Android libs have a 'lib' prefix, '.so' suffix and don't allow ~ */
+    char libname[MAXPDSTRING] = "lib";
+    strncat(libname, objectname, MAXPDSTRING - 4);
+    int len = strlen(libname);
+    if (libname[len-1] == '~' && len < MAXPDSTRING - 6) {
+        strcpy(libname+len-1, "_tilde");
+    }
+    if ((fd = sys_trytoopenone(path, libname, ".so",
+        dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0)
+            goto gotone;
+#endif
     return (0);
 gotone:
     close(fd);
     class_set_extern_dir(gensym(dirbuf));
 
         /* rebuild the absolute pathname */
-    strncpy(filename, dirbuf, FILENAME_MAX);
-    filename[FILENAME_MAX-2] = 0;
+    strncpy(filename, dirbuf, MAXPDSTRING);
+    filename[MAXPDSTRING-2] = 0;
     strcat(filename, "/");
-    strncat(filename, nameptr, FILENAME_MAX-strlen(filename));
-    filename[FILENAME_MAX-1] = 0;
+    strncat(filename, nameptr, MAXPDSTRING-strlen(filename));
+    filename[MAXPDSTRING-1] = 0;
 
-#ifdef HAVE_LIBDL
+#ifdef _WIN32
+    {
+        char dirname[MAXPDSTRING], *s, *basename;
+        sys_bashfilename(filename, filename);
+        /* set the dirname as DllDirectory, meaning in the path for
+           loading other DLLs so that dependent libraries can be included
+           in the same folder as the external. SetDllDirectory() needs a
+           minimum supported version of Windows XP SP1 for
+           SetDllDirectory, so WINVER must be 0x0502 */
+        strncpy(dirname, filename, MAXPDSTRING);
+        s = strrchr(dirname, '\\');
+        basename = s;
+        if (s && *s)
+          *s = '\0';
+        if (!SetDllDirectory(dirname))
+           error("Could not set '%s' as DllDirectory(), '%s' might not load.",
+                 dirname, basename);
+        /* now load the DLL for the external */
+        ntdll = LoadLibrary(filename);
+        if (!ntdll)
+        {
+            verbose(1, "%s: couldn't load", filename);
+            class_set_extern_dir(&s_);
+            return (0);
+        }
+        makeout = (t_xxx)GetProcAddress(ntdll, symname);
+        if (!makeout)
+             makeout = (t_xxx)GetProcAddress(ntdll, "setup");
+        SetDllDirectory(NULL); /* reset DLL dir to nothing */
+    }
+#elif defined(HAVE_LIBDL) || defined(__FreeBSD__)
     dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
     if (!dlobj)
     {
-        post("%s: %s", filename, dlerror());
+        verbose(1, "%s: %s", filename, dlerror());
         class_set_extern_dir(&s_);
         return (0);
     }
     makeout = (t_xxx)dlsym(dlobj,  symname);
-#endif
-#ifdef MSW
-    sys_bashfilename(filename, filename);
-    ntdll = LoadLibrary(filename);
-    if (!ntdll)
-    {
-        post("%s: couldn't load", filename);
-        class_set_extern_dir(&s_);
-        return (0);
-    }
-    makeout = (t_xxx)GetProcAddress(ntdll, symname);  
+    if(!makeout)
+        makeout = (t_xxx)dlsym(dlobj,  "setup");
+#else
+#warning "No dynamic loading mechanism specified, \
+    libdl or WIN32 required for loading externals!"
 #endif
 
     if (!makeout)
     {
-        post("load_object: Symbol \"%s\" not found", symname);
+        verbose(1, "load_object: Symbol \"%s\" not found", symname);
         class_set_extern_dir(&s_);
         return 0;
     }
     (*makeout)();
     class_set_extern_dir(&s_);
-    sys_putonloadlist(objectname);
     return (1);
 }
 
+
 /* linked list of loaders */
 typedef struct loader_queue {
     loader_t loader;
@@ -221,7 +261,9 @@ void sys_register_loader(loader_t loader)
     loader_queue_t *q = &loaders;
     while (1)
     {
-        if (q->next) 
+        if (q->loader == loader)    /* already loaded - nothing to do */
+            return;
+        else if (q->next)
             q = q->next;
         else
         {
@@ -230,18 +272,78 @@ void sys_register_loader(loader_t loader)
             q->next->next = NULL;
             break;
         }
-    }   
+    }
 }
 
-int sys_load_lib(t_canvas *canvas, char *classname)
+#include "g_canvas.h"
+
+/* the data passed to the iter-function */
+struct _loadlib_data
+{
+    t_canvas *canvas;
+    const char *classname;
+    int ok;
+};
+
+int sys_loadlib_iter(const char *path, struct _loadlib_data *data)
 {
-    int dspstate = canvas_suspend_dsp();
     int ok = 0;
     loader_queue_t *q;
     for(q = &loaders; q; q = q->next)
-        if (ok = q->loader(canvas, classname)) break;
+        if ((ok = q->loader(data->canvas, data->classname, path)))
+            break;
+    /* if all loaders failed, try to load as abstraction */
+    if (!ok)
+        ok = sys_do_load_abs(data->canvas, data->classname, path);
+    data->ok = ok;
+    return (ok == 0);
+}
+
+int sys_load_lib(t_canvas *canvas, const char *classname)
+{
+    int dspstate = canvas_suspend_dsp();
+    struct _loadlib_data data;
+    data.canvas = canvas;
+    data.ok = 0;
+
+    if (sys_onloadlist(classname))
+    {
+        verbose(1, "%s: already loaded", classname);
+        return (1);
+    }
+        /* if classname is absolute, try this first */
+    if (sys_isabsolutepath(classname))
+    {
+            /* this is just copied from sys_open_absolute()
+               LATER avoid code duplication */
+        char dirbuf[MAXPDSTRING], *z = strrchr(classname, '/');
+        int dirlen;
+        if (!z)
+            return (0);
+        dirlen = z - classname;
+        if (dirlen > MAXPDSTRING-1)
+            dirlen = MAXPDSTRING-1;
+        strncpy(dirbuf, classname, dirlen);
+        dirbuf[dirlen] = 0;
+        data.classname=classname+(dirlen+1);
+        sys_loadlib_iter(dirbuf, &data);
+    }
+    data.classname = classname;
+    if(!data.ok)
+        canvas_path_iterate(canvas, (t_canvas_path_iterator)sys_loadlib_iter,
+            &data);
+
+    /* if loaders failed so far, we try a last time without a PATH
+     * let the loaders search wherever they want */
+    if (!data.ok)
+        sys_loadlib_iter(0, &data);
+
+    if(data.ok)
+      sys_putonloadlist(classname);
+
+
     canvas_resume_dsp(dspstate);
-    return ok;
+    return data.ok;
 }
 
 int sys_run_scheduler(const char *externalschedlibname,
@@ -250,41 +352,142 @@ int sys_run_scheduler(const char *externalschedlibname,
     typedef int (*t_externalschedlibmain)(const char *);
     t_externalschedlibmain externalmainfunc;
     char filename[MAXPDSTRING];
+    struct stat statbuf;
     snprintf(filename, sizeof(filename), "%s%s", externalschedlibname,
         sys_dllextent);
     sys_bashfilename(filename, filename);
-#ifdef MSW
+        /* if first-choice file extent can't 'stat', go for second */
+    if (stat(filename, &statbuf) < 0)
+    {
+        snprintf(filename, sizeof(filename), "%s%s", externalschedlibname,
+            sys_dllextent2);
+        sys_bashfilename(filename, filename);
+    }
+#ifdef _WIN32
     {
         HINSTANCE ntdll = LoadLibrary(filename);
         if (!ntdll)
         {
-            post("%s: couldn't load external scheduler lib ", filename);
+            fprintf(stderr, "%s: couldn't load external scheduler\n", filename);
+            error("%s: couldn't load external scheduler", filename);
             return (1);
         }
         externalmainfunc =
-            (t_externalschedlibmain)GetProcAddress(ntdll, "main");
+            (t_externalschedlibmain)GetProcAddress(ntdll, "pd_extern_sched");
+        if (!externalmainfunc)
+            externalmainfunc =
+                (t_externalschedlibmain)GetProcAddress(ntdll, "main");
     }
-#else
+#elif defined HAVE_LIBDL
     {
         void *dlobj;
-        struct stat statbuf;
-            /* if first-choice file extent can't 'stat', go for second */
-        if (stat(filename, &statbuf) < 0)
-        {
-            snprintf(filename, sizeof(filename), "%s%s", externalschedlibname,
-                sys_dllextent2);
-            sys_bashfilename(filename, filename);
-        }       
         dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
         if (!dlobj)
         {
-            post("%s: %s", filename, dlerror());
+            error("%s: %s", filename, dlerror());
             fprintf(stderr, "dlopen failed for %s: %s\n", filename, dlerror());
             return (1);
         }
         externalmainfunc = (t_externalschedlibmain)dlsym(dlobj,
             "pd_extern_sched");
     }
+#else
+    return (0);
 #endif
-    return((*externalmainfunc)(sys_extraflagsstring));
+    if (externalmainfunc)
+        return((*externalmainfunc)(sys_extraflagsstring));
+    else
+    {
+        fprintf(stderr, "%s: couldn't find pd_extern_sched() or main()\n",
+            filename);
+        return (0);
+    }
+}
+
+
+/* abstraction loading */
+void canvas_popabstraction(t_canvas *x);
+int pd_setloadingabstraction(t_symbol *sym);
+extern t_pd *newest;
+
+static t_pd *do_create_abstraction(t_symbol*s, int argc, t_atom *argv)
+{
+    /*
+     * TODO: check if the there is a binbuf cached for <canvas::symbol>
+        and use that instead.  We'll have to invalidate the cache once we
+        are done (either with a clock_delay(0) or something else)
+     */
+    if (!pd_setloadingabstraction(s))
+    {
+        const char *objectname = s->s_name;
+        char dirbuf[MAXPDSTRING], classslashclass[MAXPDSTRING], *nameptr;
+        t_glist *glist = (t_glist *)canvas_getcurrent();
+        t_canvas *canvas = (t_canvas*)glist_getcanvas(glist);
+        int fd = -1;
+
+        t_pd *was = s__X.s_thing;
+        snprintf(classslashclass, MAXPDSTRING, "%s/%s", objectname, objectname);
+        if ((fd = canvas_open(canvas, objectname, ".pd",
+                  dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 ||
+            (fd = canvas_open(canvas, objectname, ".pat",
+                  dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 ||
+            (fd = canvas_open(canvas, classslashclass, ".pd",
+                  dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0)
+        {
+            close(fd);
+            canvas_setargs(argc, argv);
+
+            binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
+            if (s__X.s_thing && was != s__X.s_thing)
+                canvas_popabstraction((t_canvas *)(s__X.s_thing));
+            else s__X.s_thing = was;
+            canvas_setargs(0, 0);
+            return (newest);
+        }
+            /* otherwise we couldn't do it; just return 0 */
+    }
+    else error("%s: can't load abstraction within itself\n", s->s_name);
+    newest = 0;
+    return (0);
+}
+
+/* search for abstraction; register a creator if found */
+static int sys_do_load_abs(t_canvas *canvas, const char *objectname,
+    const char *path)
+{
+    int fd;
+    static t_gobj*abstraction_classes = 0;
+    char dirbuf[MAXPDSTRING], classslashclass[MAXPDSTRING], *nameptr;
+        /* NULL-path is only used as a last resort,
+           but we have already tried all paths */
+    if (!path) return (0);
+
+    snprintf(classslashclass, MAXPDSTRING, "%s/%s", objectname, objectname);
+    if ((fd = sys_trytoopenone(path, objectname, ".pd",
+              dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0 ||
+        (fd = sys_trytoopenone(path, objectname, ".pat",
+              dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0 ||
+        (fd = sys_trytoopenone(path, classslashclass, ".pd",
+              dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0)
+    {
+        t_class*c=0;
+        close(fd);
+            /* found an abstraction, now register it as a new pseudo-class */
+        class_set_extern_dir(gensym(dirbuf));
+        if((c=class_new(gensym(objectname),
+                        (t_newmethod)do_create_abstraction, 0,
+                        0, 0, A_GIMME, 0)))
+        {
+                /* store away the newly created class, maybe we will need it one day */
+            t_gobj*absclass=0;
+            absclass=t_getbytes(sizeof(*absclass));
+            absclass->g_pd=c;
+            absclass->g_next=abstraction_classes;
+            abstraction_classes=absclass;
+        }
+        class_set_extern_dir(&s_);
+
+        return (1);
+    }
+    return (0);
 }
diff --git a/pd/src/s_stuff.h.in b/pd/src/s_stuff.h.in
index a5b72e89aaa8b8ac2ff2cbdb43df9dc0655d9a0b..0fb85a58a9024504c115fb3d5655f23cad1b2890 100644
--- a/pd/src/s_stuff.h.in
+++ b/pd/src/s_stuff.h.in
@@ -71,8 +71,8 @@ extern t_symbol *sys_libdir;    /* library directory for auxilliary files */
 extern t_symbol *sys_guidir;    /* directory holding pd_gui, u_pdsend, etc */
 
 /* s_loader.c */
-typedef int (*loader_t)(t_canvas *canvas, char *classname); /* callback type */
-EXTERN int sys_load_lib(t_canvas *canvas, char *filename);
+typedef int (*loader_t)(t_canvas *canvas, const char *classname, const char *path); /* callback type */
+EXTERN int sys_load_lib(t_canvas *canvas, const char *classname);
 EXTERN void sys_register_loader(loader_t loader);
 
 /* s_audio.c */