diff --git a/lib/master.pike.in b/lib/master.pike.in
index c80370510d16938f152440a4fd1ebfa6c279babb..4ee05dafd8676ae1813bb8defe7789e572a33774 100644
--- a/lib/master.pike.in
+++ b/lib/master.pike.in
@@ -1169,16 +1169,19 @@ program compile_string(string source, void|string filename,
   werror ("%*s>>> compile_string %O\n", GET_MSG_DEPTH, "", filename);
   INC_MSG_DEPTH();
 #endif
-  program ret = compile(cpp(source, filename||"-", 1, handler,
-		     compat_major, compat_minor,
-		     (zero_type(_show_if_constant_errors)?
-		      show_if_constant_errors:
-		      _show_if_constant_errors)),
-		 handler,
-		 compat_major,
-		 compat_minor,
-		 p,
-		 o);
+  string code = cpp(source, filename||"-", 1, handler,
+                    compat_major, compat_minor,
+                    (zero_type(_show_if_constant_errors)?
+                     show_if_constant_errors:
+                     _show_if_constant_errors));
+  program ret;
+  if(code)
+    ret = compile(code,
+                  handler,
+                  compat_major,
+                  compat_minor,
+                  p,
+                  o);
   if (source_cache)
     source_cache[ret] = source;
 #ifdef RECUR_COMPILE_DEBUG
@@ -1970,7 +1973,10 @@ protected program low_findprog(string pname,
       return programs[fname] = 0;
     }
     else {
-      resolv_debug("low_findprog %s: returning %O\n", fname, ret);
+      if(!ret)
+        resolv_debug("low_findprog %s: dependencies failed.\n");
+      else
+        resolv_debug("low_findprog %s: returning %O\n", fname, ret);
       return programs[fname]=ret;
     }
   }
diff --git a/src/cpp.c b/src/cpp.c
index b91ec48391f009cac1eded409ad7dc5b609e3c24..0b2f32c910ea6d8a96ccb724115ba00b9216fddc 100644
--- a/src/cpp.c
+++ b/src/cpp.c
@@ -131,7 +131,7 @@ struct cpp
   INT_TYPE compat_minor;
   struct pike_string *data;
   struct pike_string *prefix;
-  INT_TYPE picky_cpp, keep_comments;
+  INT_TYPE picky_cpp, keep_comments, dependencies_fail;
 };
 
 struct define *defined_macro =0;
@@ -588,6 +588,17 @@ void cpp_change_compat(struct cpp *this, int major, int minor)
  *!   @[#if], @[#ifdef], @[defined]
  */
 
+/*! @directive #require
+ *!
+ *!   If the directive evaluates to false, the source file will be
+ *!   considered to have failed dependencies, and will not be found by
+ *!   the resolver. In practical terms the @[cpp()] call will return
+ *!   zero.
+ *!
+ *! @seealso
+ *!   @[#if]
+ */
+
 /*! @directive #endif
  *!
  *!   End a block opened with @[#if], @[#ifdef], @[#ifndef],
@@ -2471,6 +2482,7 @@ void f_cpp(INT32 args)
   this.compile_errors=0;
   this.defines=0;
   this.keep_comments = 0;
+  this.dependencies_fail = 0;
 
 #define TTS(type)	(((type) == PIKE_T_STRING && "string")	\
 		      || ((type) == PIKE_T_MAPPING && "mapping")\
@@ -2752,7 +2764,14 @@ void f_cpp(INT32 args)
     free_string_builder(&this.buf);
     throw_error_object(fast_clone_object(cpp_error_program), 0, 0, 0,
 		       "Cpp() failed\n");
-  }else{
+  }
+  else if(this.dependencies_fail)
+  {
+    free_string_builder(&this.buf);
+    push_int(0);
+  }
+  else
+  {
     pop_n_elems(sp - save_sp);
     push_string(finish_string_builder(&this.buf));
   }
diff --git a/src/preprocessor.h b/src/preprocessor.h
index 4219e33d406f30535a46cc119bdfc26a5c62d6ed..666358fd7dd1dbea34c78c79d6700f98504b67da 100644
--- a/src/preprocessor.h
+++ b/src/preprocessor.h
@@ -1074,7 +1074,7 @@ static ptrdiff_t lower_cpp(struct cpp *this,
   int include_mode;
   INT_TYPE first_line = this->current_line;
   /* FIXME: What about this->current_file? */
-  
+
   for(pos=0; pos<len;)
   {
     ptrdiff_t old_pos = pos;
@@ -2531,6 +2531,46 @@ concat_identifier:
 	  break;
 	}
       }
+    case 'r': /* require */
+      {
+        static const WCHAR require_[] = { 'r', 'e', 'q', 'u', 'i', 'r', 'e' };
+        if(WGOBBLE2(require_))
+        {
+          struct string_builder save, tmp;
+          save = this->buf;
+          init_string_builder(&this->buf, SHIFT);
+          pos += lower_cpp(this, data+pos, len-pos,
+                           CPP_END_AT_NEWLINE | CPP_DO_IF,
+                           auto_convert, charset);
+          tmp = this->buf;
+          this->buf = save;
+          string_builder_putchar(&tmp, 0);
+          tmp.s->len--;
+
+          switch(tmp.s->size_shift) {
+	  case 0:
+	    calc_0(this, (p_wchar0 *)tmp.s->str, tmp.s->len, 0, 0);
+	    break;
+	  case 1:
+	    calc_1(this, (p_wchar1 *)tmp.s->str, tmp.s->len, 0, 0);
+	    break;
+	  case 2:
+	    calc_2(this, (p_wchar2 *)tmp.s->str, tmp.s->len, 0, 0);
+	    break;
+#ifdef PIKE_DEBUG
+	  default:
+	    Pike_fatal("cpp(): Bad shift: %d\n", tmp.s->size_shift);
+	    break;
+#endif
+	  }
+          if(SAFE_IS_ZERO(Pike_sp-1)) this->dependencies_fail=1;
+          pop_stack();
+          free_string_builder(&tmp);
+          if(this->dependencies_fail) return pos;
+          break;
+        }
+	goto unknown_preprocessor_directive;
+      }
     case 'w': /* warning */
       {
 	static const WCHAR warning_[] = { 'w', 'a', 'r', 'n', 'i', 'n', 'g' };