Merge pull request #81 from hughbe/used-llvm

Use LLVM_ATTRIBUTE_USED instead of compiler specific code
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f009fd..66e3088 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -73,6 +73,7 @@
 
 find_package(Lit REQUIRED)
 find_package(FileCheck REQUIRED)
+find_package(PythonInterp)
 
 # Check if we should build the Swift bindings.
 if (";${LLBUILD_SUPPORT_BINDINGS};" MATCHES ";Swift;")
diff --git a/include/llbuild/Core/BuildEngine.h b/include/llbuild/Core/BuildEngine.h
index 959ea5a..b42ce59 100644
--- a/include/llbuild/Core/BuildEngine.h
+++ b/include/llbuild/Core/BuildEngine.h
@@ -20,6 +20,8 @@
 #include <utility>
 #include <vector>
 
+#include "llvm/ADT/Twine.h"
+
 namespace llbuild {
 namespace core {
 
@@ -204,6 +206,11 @@
   /// the cycle (i.e., the node participating in the cycle will appear twice).
   virtual void cycleDetected(const std::vector<Rule*>& items) = 0;
 
+  /// Called when a fatal error is encountered by the build engine.
+  ///
+  /// \param message The diagnostic message.
+  virtual void error(const llvm::Twine& message) = 0;
+
 };
 
 /// A build engine supports fast, incremental, persistent, and parallel
diff --git a/lib/BuildSystem/BuildSystem.cpp b/lib/BuildSystem/BuildSystem.cpp
index 8c3feb3..ea7aeaa 100644
--- a/lib/BuildSystem/BuildSystem.cpp
+++ b/lib/BuildSystem/BuildSystem.cpp
@@ -117,6 +117,7 @@
 
   virtual Rule lookupRule(const KeyType& keyData) override;
   virtual void cycleDetected(const std::vector<Rule*>& items) override;
+  virtual void error(const Twine& message) override;
 
 public:
   BuildSystemEngineDelegate(BuildSystemImpl& system) : system(system) {}
@@ -826,6 +827,10 @@
   system.error(system.getMainFilename(), os.str());
 }
 
+void BuildSystemEngineDelegate::error(const Twine& message) {
+  system.error(system.getMainFilename(), message);
+}
+
 #pragma mark - BuildSystemImpl implementation
 
 std::unique_ptr<BuildNode>
diff --git a/lib/Commands/BuildEngineCommand.cpp b/lib/Commands/BuildEngineCommand.cpp
index 602bf83..8f50c2b 100644
--- a/lib/Commands/BuildEngineCommand.cpp
+++ b/lib/Commands/BuildEngineCommand.cpp
@@ -214,6 +214,11 @@
     virtual void cycleDetected(const std::vector<core::Rule*>& items) override {
       assert(0 && "unexpected cycle!");
     }
+
+    /// Called when a fatal error is encountered by the build engine.
+    virtual void error(const Twine &message) override {
+      assert(0 && ("error:" + message.str()).c_str());
+    }
   };
   AckermannDelegate delegate;
   core::BuildEngine engine(delegate);
diff --git a/lib/Commands/NinjaBuildCommand.cpp b/lib/Commands/NinjaBuildCommand.cpp
index 3eb0b78..efef371 100644
--- a/lib/Commands/NinjaBuildCommand.cpp
+++ b/lib/Commands/NinjaBuildCommand.cpp
@@ -400,6 +400,8 @@
   virtual core::Rule lookupRule(const core::KeyType& key) override;
 
   virtual void cycleDetected(const std::vector<core::Rule*>& items) override;
+
+  virtual void error(const Twine& message) override;
 };
 
 /// Wrapper for information used during a single build.
@@ -1682,6 +1684,14 @@
   context->isCancelled = true;
 }
 
+void NinjaBuildEngineDelegate::error(const Twine& message) {
+  // Report the error.
+  context->emitError("error: " + message.str());
+
+  // Cancel the build.
+  context->isCancelled = true;
+}
+
 }
 
 int commands::executeNinjaBuildCommand(std::vector<std::string> args) {
diff --git a/lib/Core/BuildEngine.cpp b/lib/Core/BuildEngine.cpp
index d4b5c1d..1d93b08 100644
--- a/lib/Core/BuildEngine.cpp
+++ b/lib/Core/BuildEngine.cpp
@@ -816,9 +816,9 @@
           std::string error;
           bool result = db->setRuleResult(ruleInfo->rule, ruleInfo->result, &error);
           if (!result) {
-            // FIXME: Error handling.
-            std::cerr << error << std::endl;
-            exit(1);
+            delegate.error(error);
+            completeRemainingTasks();
+            return false;
           }
         }
 
@@ -1013,10 +1013,13 @@
     assert(!cycleList.empty());
 
     delegate.cycleDetected(cycleList);
+    completeRemainingTasks();
+  }
 
-    // Complete all of the remaining tasks.
-    //
-    // FIXME: Should we have a task abort callback?
+  // Complete all of the remaining tasks.
+  //
+  // FIXME: Should we have a task abort callback?
+  void completeRemainingTasks() {
     for (auto& it: taskInfos) {
       // Complete the task, even though it did not update the value.
       //
@@ -1091,9 +1094,8 @@
       std::string error;
       db->lookupRuleResult(ruleInfo.rule, &ruleInfo.result, &error);
       if (!error.empty()) {
-        // FIXME: Error handling.
-        std::cerr << error << std::endl;
-        exit(1);
+        delegate.error(error);
+        completeRemainingTasks();
       }
     }
 
@@ -1132,9 +1134,9 @@
       std::string error;
       bool result = db->setCurrentIteration(currentTimestamp, &error);
       if (!result) {
-        // FIXME: Error handling.
-        std::cerr << error << std::endl;
-        exit(1);
+        delegate.error(error);
+        static ValueType emptyValue{};
+        return emptyValue;
       }
       db->buildComplete();
     }
@@ -1189,10 +1191,8 @@
   void dumpGraphToFile(const std::string& path) {
     FILE* fp = ::fopen(path.c_str(), "w");
     if (!fp) {
-      // FIXME: Error handling.
-      std::cerr << "error: unable to open graph output path \""
-                << path << "\"\n";
-      exit(1);
+      delegate.error("error: unable to open graph output path \"" + path + "\"");
+      return;
     }
 
     // Write the graph header.
@@ -1260,9 +1260,9 @@
   void taskNeedsInput(Task* task, const KeyType& key, uintptr_t inputID) {
     // Validate the InputID.
     if (inputID > BuildEngine::kMaximumInputID) {
-      // FIXME: Error handling.
-      std::cerr << "error: attempt to use reserved input ID\n";
-      exit(1);
+      delegate.error("error: attempt to use reserved input ID");
+      completeRemainingTasks();
+      return;
     }
 
     addTaskInputRequest(task, key, inputID);
@@ -1278,9 +1278,9 @@
     assert(taskInfo && "cannot request inputs for an unknown task");
 
     if (!taskInfo->forRuleInfo->isInProgressComputing()) {
-      // FIXME: Error handling.
-      std::cerr << "error: invalid state for adding discovered dependency\n";
-      exit(1);
+      delegate.error("error: invalid state for adding discovered dependency");
+      completeRemainingTasks();
+      return;
     }
 
     taskInfo->discoveredDependencies.push_back(key);
@@ -1294,9 +1294,9 @@
     assert(taskInfo && "cannot request inputs for an unknown task");
 
     if (!taskInfo->forRuleInfo->isInProgressComputing()) {
-      // FIXME: Error handling.
-      std::cerr << "error: invalid state for marking task complete\n";
-      exit(1);
+      delegate.error("error: invalid state for marking task complete");
+      completeRemainingTasks();
+      return;
     }
 
     RuleInfo* ruleInfo = taskInfo->forRuleInfo;
diff --git a/perftests/Xcode/PerfTests/CorePerfTests.mm b/perftests/Xcode/PerfTests/CorePerfTests.mm
index f51cfd6..78216bf 100644
--- a/perftests/Xcode/PerfTests/CorePerfTests.mm
+++ b/perftests/Xcode/PerfTests/CorePerfTests.mm
@@ -141,6 +141,11 @@
       fprintf(stderr, "error: unexpected cycle\n");
       abort();
     }
+
+    virtual void error(const Twine& message) override {
+      fprintf(stderr, "error: %s\n", message.str().c_str());
+      abort();
+    }
   } Delegate;
   __block core::BuildEngine Engine(Delegate);
   int LastInputValue = 0;
@@ -216,6 +221,11 @@
       fprintf(stderr, "error: unexpected cycle\n");
       abort();
     }
+
+    virtual void error(const Twine& message) override {
+      fprintf(stderr, "error: %s\n", message.str().c_str());
+      abort();
+    }
   } Delegate;
   __block core::BuildEngine Engine(Delegate);
   int LastInputValue = 0;
@@ -295,6 +305,11 @@
       fprintf(stderr, "error: unexpected cycle\n");
       abort();
     }
+
+    virtual void error(const Twine& message) override {
+      fprintf(stderr, "error: %s\n", message.str().c_str());
+      abort();
+    }
   } Delegate;
   __block core::BuildEngine Engine(Delegate);
   int LastInputValue = 0;
diff --git a/products/libllbuild/Core-C-API.cpp b/products/libllbuild/Core-C-API.cpp
index 4a5a4da..3c8f904 100644
--- a/products/libllbuild/Core-C-API.cpp
+++ b/products/libllbuild/Core-C-API.cpp
@@ -86,6 +86,10 @@
     assert(0 && "unexpected cycle!");
   }
 
+  virtual void error(const Twine& message) override {
+    cAPIDelegate.error(cAPIDelegate.context, message.str().c_str());
+  }
+
 public:
   CAPIBuildEngineDelegate(llb_buildengine_delegate_t delegate)
     : cAPIDelegate(delegate)
diff --git a/products/libllbuild/public-api/llbuild/core.h b/products/libllbuild/public-api/llbuild/core.h
index f2eb3cf..82f5899 100644
--- a/products/libllbuild/public-api/llbuild/core.h
+++ b/products/libllbuild/public-api/llbuild/core.h
@@ -104,6 +104,12 @@
     void (*lookup_rule)(void* context,
                         const llb_data_t* key,
                         llb_rule_t* rule_out);
+
+    /// Callback for fatal errors the build engine encounters.
+    ///
+    /// Xparam context The user context pointer.
+    /// Xparam message Error message.
+    void (*error)(void* context, const char* message);
 } llb_buildengine_delegate_t;
 
 /// Create a new build engine object.
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b847e66..3441e2d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -28,6 +28,7 @@
   endif()
 
   set(lit_command
+    ${PYTHON_EXECUTABLE}
     ${LIT_EXECUTABLE}
     ${LIT_ARGS}
     --param build_mode=${build_mode})
diff --git a/unittests/Core/BuildEngineTest.cpp b/unittests/Core/BuildEngineTest.cpp
index fb70e54..a10f771 100644
--- a/unittests/Core/BuildEngineTest.cpp
+++ b/unittests/Core/BuildEngineTest.cpp
@@ -45,6 +45,11 @@
     std::transform(items.begin(), items.end(), std::back_inserter(cycle),
                    [](auto rule) { return std::string(rule->key); });
   }
+
+  virtual void error(const Twine& message) override {
+    fprintf(stderr, "error: %s\n", message.str().c_str());
+    abort();
+  }
 };
 
 static int32_t intFromValue(const core::ValueType& value) {
diff --git a/unittests/Core/DependencyInfoParserTest.cpp b/unittests/Core/DependencyInfoParserTest.cpp
index b44f370..a629be1 100644
--- a/unittests/Core/DependencyInfoParserTest.cpp
+++ b/unittests/Core/DependencyInfoParserTest.cpp
@@ -50,8 +50,9 @@
     }
   };
 
-#define INPUT(str) ({ \
-      assert(sizeof(str) != 0); StringRef(str, sizeof(str) - 1); })
+#define INPUT(str)                                                             \
+  StringRef(str, sizeof(str) - 1);                                             \
+  assert(sizeof(str) != 0);
 
   // Check missing terminator diagnose (on empty file).
   {
diff --git a/unittests/Core/DepsBuildEngineTest.cpp b/unittests/Core/DepsBuildEngineTest.cpp
index 77b40a1..2d10445 100644
--- a/unittests/Core/DepsBuildEngineTest.cpp
+++ b/unittests/Core/DepsBuildEngineTest.cpp
@@ -43,6 +43,11 @@
     fprintf(stderr, "error: cycle\n");
     abort();
   }
+
+  virtual void error(const Twine& message) override {
+    fprintf(stderr, "error: %s\n", message.str().c_str());
+    abort();
+  }
 };
 
 static int32_t intFromValue(const core::ValueType& value) {