diff --git a/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike b/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike
index f234d18b5ef5398d59403d2a7d50f3e365398d01..c5ef827c68b9b3cb17682b9621b18f9232bcb505 100644
--- a/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike
+++ b/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike
@@ -19,10 +19,13 @@ constant precompile_api_version = "3";
 constant want_args = 1;
 
 constant description = "Converts .pmod-files to .c files";
+
+mapping map_types = ([]), need_obj_defines = ([]);
+
 string usage = #"[options] <from> > <to>
 
 
- This script is used to process *.cmod files into *.c files, it 
+ This script is used to process *.cmod files into *.c files, it
  reads Pike style prototypes and converts them into C code.
 
  Supported options are:
@@ -827,8 +830,12 @@ class PikeType
 	case "longest":
 	  return "tInt";
 
-	case "object":  return "tObj";
+	case "object":
+          return "tObj";
 	default:
+          string define = "tObjImpl_"+replace(upper_case(ret), ".", "_");
+          if( !need_obj_defines[define] )
+            need_obj_defines[define] = ret;
 	  return sprintf("tName(%O, tObjImpl_%s)",
 			 ret, replace(upper_case(ret), ".", "_"));
       }
@@ -1682,6 +1689,8 @@ array generate_overload_func_for(array(FuncData) d,
   return out;
 }
 
+int gid;
+
 // Parses a block of cmod code, separating it into declarations,
 // functions to add, exit functions and other code.
 class ParseBlock
@@ -1690,6 +1699,7 @@ class ParseBlock
   array addfuncs=({});
   array exitfuncs=({});
   array declarations=({});
+  int local_id = ++gid;
 
   void create(array(array|PC.Token) x, string base, string class_name)
     {
@@ -1881,6 +1891,9 @@ sprintf("        } else {\n"
 	    ret+=subclass->declarations;
 	    ret+=subclass->code;
 
+            need_obj_defines["tObjImpl_"+upper_case(lname)] = 1;
+            map_types[subclass->local_id] = ({ define, "return "+program_var+"->id;" });
+
 	    addfuncs+=
 	      IFDEF(define,
 		    ({
@@ -1898,7 +1911,10 @@ sprintf("        } else {\n"
 			       proto[0]->line),
 		      IFDEF("tObjImpl_"+upper_case(lname),
 			    0,
-			    DEFINE("tObjImpl_"+upper_case(lname), "tObj")),
+			    DEFINE("tObjIs_"+upper_case(lname),
+                       sprintf("%O",sprintf("\3\1\x7f%3c", subclass->local_id)))+
+			    DEFINE("tObjImpl_"+upper_case(lname),
+                       sprintf("%O",sprintf("\3\0\x7f%3c", subclass->local_id)))),
 		    })+
 		    subclass->addfuncs+
 		    ({
@@ -2415,7 +2431,7 @@ static struct %s *%s_gdb_dummy_ptr;
 		  ret+=({
 		    PC.Token(sprintf("if (args > %d &&"
 				     "    (TYPEOF(Pike_sp[%d%s]) != PIKE_T_INT ||"
-				     "     Pike_sp[%d%s].u.integer)) {\n",
+			     "     Pike_sp[%d%s].u.integer)) {\n",
 				     argnum,
 				     argnum, check_argbase,
 				     argnum, check_argbase), arg->line()),
@@ -2711,7 +2727,8 @@ static struct %s *%s_gdb_dummy_ptr;
 	    }));
 	} else {
 	  addfuncs+=IFDEF(define, ({
-	    PC.Token(sprintf("  %s =\n", func_num)),
+               IFDEF(func_num+"_used",
+                    ({PC.Token(sprintf("  %s =", func_num))})),
 	    PC.Token(sprintf("    ADD_FUNCTION2(%O, %s, %s, %s, %s);\n",
 			     attributes->name || name,
 			     funcname,
@@ -2792,27 +2809,65 @@ class Handler {
 
     void create(mapping|void predefines) {
 	::create();
-	if (predefines) this::predefines = predefines;
+	if (predefines) this_program::predefines = predefines;
     }
 }
 
 int find_identifier( array in, string ident )
 {
-    foreach( in, mixed q )
+  foreach( in, mixed q )
+  {
+    if( objectp(q) )
     {
-        if( objectp(q) )
-        {
-            if( q == ident ) return 1;
-        }
-        else if( arrayp( q ) )
-        {
-            if( find_identifier( q, ident ) )
-                return 1;
-        }
-        else
-            /* generated by us, not useful currentrly. */
-          ;
+      if( q == ident ) {
+        return 1;
+      }
+    }
+    else if( arrayp( q ) )
+    {
+      if( find_identifier( q, ident ) )
+        return 1;
+    }
+  }
+}
+
+array resolve_obj_defines()
+{
+  array res = ({});
+
+  foreach( need_obj_defines; string key; int|string id )
+  {
+    if( intp( id ) )
+    {
+      m_delete( need_obj_defines, key );
+      continue; /* type in this file. Not external. */
     }
+  }
+  if( sizeof( need_obj_defines ) )
+  {
+    res += ({ "{ int i=0;\n"});
+    res += ({ "  ___cmod_ext_used=xalloc(sizeof(___cmod_ext_used[0]) * "+(sizeof(need_obj_defines)||1)+");\n" });
+    foreach( need_obj_defines; string key; string id )
+    {
+      int local_id = ++gid;
+      res += ({
+        sprintf("#ifndef %s\n"
+                "# define %[0]s %s\n"
+                "{\n"
+                "   struct program *tmp = resolve_program(" + allocate_string(sprintf("%O",id)) + ");\n"
+                "   if( tmp ) {\n"
+                "      ___cmod_ext_used[i].from = %d;\n"
+                "      ___cmod_ext_used[i].to = tmp->id;\n"
+                "      i++;\n"
+                "   }\n"
+                "}\n"
+                "#endif\n"
+                ,key,sprintf("%O",sprintf("\3\0\x7f%3c", local_id)),local_id)
+      });
+    }
+    res += ({ " ___cmod_ext_used[i].from = 0;\n}\n"});
+  }
+  return res;
 }
 
 int main(int argc, array(string) argv)
@@ -2979,7 +3034,10 @@ int main(int argc, array(string) argv)
 
   tmp->declarations += ({
     "\n\n"
+    "#define CMOD_MAP_PROGRAM_IDS_DEFINED 1\n"
+    "static int ___cmod_map_program_ids(int id);\n"
     "#ifndef TYPEOF\n"
+    "static void set_program_id_to_id(void*UNUSED(id)){}\n"
     "/* Compat with older Pikes. */\n"
     "#define TYPEOF(SVAL)\t((SVAL).type)\n"
     "#define SUBTYPEOF(SVAL)\t((SVAL).subtype)\n"
@@ -2992,15 +3050,26 @@ int main(int argc, array(string) argv)
     "    SET_SVAL_TYPE((SVAL), (TYPE));\t\t\t\\\n"
     "    SET_SVAL_SUBTYPE((SVAL), (SUBTYPE));\t\t\\\n"
     "  } while(0)\n"
+    "#else /* */\n"
+    "PMOD_EXPORT void set_program_id_to_id( int (*to)(int) );\n"
     "#endif /* !TYPEOF */\n"
     "\n\n",
-    // FIXME: Ought to default to static in 7.9.
+
     "#ifndef DEFAULT_CMOD_STORAGE\n"
     "#define CMOD_COND_USED\n"
     "#define DEFAULT_CMOD_STORAGE static\n"
     "#endif\n"
   });
 
+
+  tmp->addfuncs =
+    IFDEF("CMOD_MAP_PROGRAM_IDS_DEFINED",
+          ({"set_program_id_to_id( ___cmod_map_program_ids );"}))
+      + resolve_obj_defines()
+      +  tmp->addfuncs
+    + IFDEF("CMOD_MAP_PROGRAM_IDS_DEFINED",
+          ({"set_program_id_to_id( 0 );"}));
+
   if (last_str_id) {
     // Add code for allocation and deallocation of the strings.
     tmp->addfuncs =
@@ -3044,22 +3113,47 @@ int main(int argc, array(string) argv)
     }
   }
 
-  x=tmp->code;
+  x = tmp->code;
 
-  foreach( check_used; string key; )
+  x +=({
+    "\n"
+    "#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED\n"
+    "static int ___cmod_map_program_ids(int id)\n"
+    "{\n"
+    "  int i = 0;\n"
+    "  if( (id&0x7f000000) != 0x7f000000 ) return id;\n"
+    "  id = id&0x00ffffff;\n"
+  });
+
+  foreach( map_types; int i; string how )
   {
-      tmp->declarations += ({
-          "#ifndef CMOD_COND_USED\n"
-          "# define "+key+"_used 1\n"
-          "#else\n"
-      });
-      if( find_identifier( x, key ) )
-          tmp->declarations +=({ "#define "+key+"_used 1\n" });
-      else
-          tmp->declarations += ({ "#undef "+key+"_used\n" });
-      tmp->declarations += ({ "#endif\n" });
+    if( how[0] )
+      x += ({ "#ifdef "+how[0]+"\n" });
+    x += ({  "if(id=="+i+") "+how[1]+"\n" });
+    if( how[0] )
+      x += ({ "#endif\n" });
   }
 
+  if( sizeof( need_obj_defines ) )
+  {
+    tmp->declarations += ({
+      "static struct ext_used { INT32 from;INT32 to; } *___cmod_ext_used;\n"
+    });
+
+    x += ({
+      "  while(___cmod_ext_used[i].from ) {\n"
+      "   if( ___cmod_ext_used[i].from == id ) return ___cmod_ext_used[i].to;\n"
+      "   i++;\n"
+      "  }\n"
+    });
+  }
+  x += ({
+    "  return 0;\n"
+    "}\n"
+    "#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */\n"
+  });
+
+  tmp->code = x;
   x=recursive(replace,x,PC.Token("INIT",0),tmp->addfuncs);
   int need_init;
   if ((need_init = equal(x, tmp->code)))
@@ -3095,6 +3189,20 @@ int main(int argc, array(string) argv)
   // FIXME: This line is fishy; there is no optfuncs in ParseBlock.
   x=recursive(replace,x,PC.Token("OPTIMIZE",0),tmp->optfuncs);
 
+  foreach( check_used; string key; )
+  {
+      tmp->declarations += ({
+          "#ifndef CMOD_COND_USED\n"
+          "# define "+key+"_used 1\n"
+          "#else\n"
+      });
+      if( find_identifier( x, key ) )
+          tmp->declarations +=({ "#define "+key+"_used 1\n" });
+      else
+          tmp->declarations += ({ "#undef "+key+"_used\n" });
+      tmp->declarations += ({ "#endif\n" });
+  }
+  tmp->code = x;
   x=recursive(replace,x,PC.Token("DECLARATIONS",0),tmp->declarations);