1 //===-- BuildSystem.cpp ---------------------------------------------------===//
2 //
3 // This source file is part of the Swift.org open source project
4 //
5 // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6 // Licensed under Apache License v2.0 with Runtime Library Exception
7 //
8 // See http://swift.org/LICENSE.txt for license information
9 // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llbuild/BuildSystem/BuildSystem.h"
14 #include "llbuild/BuildSystem/BuildSystemCommandInterface.h"
15 #include "llbuild/BuildSystem/BuildSystemFrontend.h"
16 #include "llbuild/BuildSystem/CommandResult.h"
17 
18 #include "llbuild/Basic/FileInfo.h"
19 #include "llbuild/Basic/FileSystem.h"
20 #include "llbuild/Basic/Hashing.h"
21 #include "llbuild/Basic/LLVM.h"
22 #include "llbuild/Basic/PlatformUtility.h"
23 #include "llbuild/Basic/ShellUtility.h"
24 #include "llbuild/Core/BuildDB.h"
25 #include "llbuild/Core/BuildEngine.h"
26 #include "llbuild/Core/DependencyInfoParser.h"
27 #include "llbuild/Core/MakefileDepsParser.h"
28 #include "llbuild/BuildSystem/BuildExecutionQueue.h"
29 #include "llbuild/BuildSystem/BuildFile.h"
30 #include "llbuild/BuildSystem/BuildKey.h"
31 #include "llbuild/BuildSystem/BuildNode.h"
32 #include "llbuild/BuildSystem/BuildValue.h"
33 #include "llbuild/BuildSystem/ExternalCommand.h"
34 
35 #include "llvm/ADT/ArrayRef.h"
36 #include "llvm/ADT/Hashing.h"
37 #include "llvm/ADT/STLExtras.h"
38 #include "llvm/ADT/SmallString.h"
39 #include "llvm/ADT/StringMap.h"
40 #include "llvm/ADT/StringRef.h"
41 #include "llvm/Support/ErrorHandling.h"
42 #include "llvm/Support/FileSystem.h"
43 #include "llvm/Support/MemoryBuffer.h"
44 #include "llvm/Support/Path.h"
45 #include "llvm/Support/raw_ostream.h"
46 
47 #include <memory>
48 #include <mutex>
49 #include <set>
50 
51 #include <unistd.h>
52 
53 using namespace llbuild;
54 using namespace llbuild::basic;
55 using namespace llbuild::core;
56 using namespace llbuild::buildsystem;
57 
~BuildSystemDelegate()58 BuildSystemDelegate::~BuildSystemDelegate() {}
59 
~BuildSystemCommandInterface()60 BuildSystemCommandInterface::~BuildSystemCommandInterface() {}
61 
62 #pragma mark - BuildSystem implementation
63 
64 namespace {
65 
66 class BuildSystemImpl;
67 
68 /// The delegate used to load the build file for use by a build system.
69 class BuildSystemFileDelegate : public BuildFileDelegate {
70   BuildSystemImpl& system;
71 
72   /// FIXME: It would be nice to have a StringSet.
73   llvm::StringMap<bool> internedStrings;
74 
75 public:
BuildSystemFileDelegate(BuildSystemImpl & system)76   BuildSystemFileDelegate(BuildSystemImpl& system)
77       : BuildFileDelegate(), system(system) {}
78 
79   BuildSystemDelegate& getSystemDelegate();
80 
81   /// @name Delegate Implementation
82   /// @{
83 
getInternedString(StringRef value)84   virtual StringRef getInternedString(StringRef value) override {
85     auto entry = internedStrings.insert(std::make_pair(value, true));
86     return entry.first->getKey();
87   }
88 
getFileSystem()89   virtual FileSystem& getFileSystem() override {
90     return getSystemDelegate().getFileSystem();
91   }
92 
93   virtual void setFileContentsBeingParsed(StringRef buffer) override;
94 
95   virtual void error(StringRef filename,
96                      const BuildFileToken& at,
97                      const Twine& message) override;
98 
99   virtual bool configureClient(const ConfigureContext&, StringRef name,
100                                uint32_t version,
101                                const property_list_type& properties) override;
102 
103   virtual std::unique_ptr<Tool> lookupTool(StringRef name) override;
104 
105   virtual void loadedTarget(StringRef name,
106                             const Target& target) override;
107 
108   virtual void loadedDefaultTarget(StringRef target) override;
109 
110   virtual void loadedCommand(StringRef name,
111                              const Command& target) override;
112 
113   virtual std::unique_ptr<Node> lookupNode(StringRef name,
114                                            bool isImplicit=false) override;
115 
116   /// @}
117 };
118 
119 /// The delegate used to build a loaded build file.
120 class BuildSystemEngineDelegate : public BuildEngineDelegate {
121   BuildSystemImpl& system;
122 
123   // FIXME: This is an inefficent map, the string is duplicated.
124   std::unordered_map<std::string, std::unique_ptr<BuildNode>> dynamicNodes;
125 
126   /// The custom tasks which are owned by the build system.
127   std::vector<std::unique_ptr<Command>> customTasks;
128 
129   const BuildDescription& getBuildDescription() const;
130 
131   virtual Rule lookupRule(const KeyType& keyData) override;
132   virtual void cycleDetected(const std::vector<Rule*>& items) override;
133   virtual void error(const Twine& message) override;
134 
135 public:
BuildSystemEngineDelegate(BuildSystemImpl & system)136   BuildSystemEngineDelegate(BuildSystemImpl& system) : system(system) {}
137 
getBuildSystem()138   BuildSystemImpl& getBuildSystem() {
139     return system;
140   }
141 };
142 
143 class BuildSystemImpl : public BuildSystemCommandInterface {
144   /// The internal schema version.
145   ///
146   /// Version History:
147   /// * 7: Added StaleFileRemoval to BuildValue
148   /// * 6: Added DirectoryContents to BuildKey
149   /// * 5: Switch BuildValue to be BinaryCoding based
150   /// * 4: Pre-history
151   static const uint32_t internalSchemaVersion = 7;
152 
153   BuildSystem& buildSystem;
154 
155   /// The delegate the BuildSystem was configured with.
156   BuildSystemDelegate& delegate;
157 
158   /// The name of the main input file.
159   std::string mainFilename;
160 
161   /// The delegate used for the loading the build file.
162   BuildSystemFileDelegate fileDelegate;
163 
164   /// The build description, once loaded.
165   std::unique_ptr<BuildDescription> buildDescription;
166 
167   /// The delegate used for building the file contents.
168   BuildSystemEngineDelegate engineDelegate;
169 
170   /// The build engine.
171   BuildEngine buildEngine;
172 
173   /// Mutex for access to execution queue.
174   std::mutex executionQueueMutex;
175 
176   /// The execution queue reference; this is only valid while a build is
177   /// actually in progress.
178   std::unique_ptr<BuildExecutionQueue> executionQueue;
179 
180   /// Flag indicating if the build has been aborted.
181   bool buildWasAborted = false;
182 
183   /// Flag indicating if the build has been cancelled.
184   std::atomic<bool> isCancelled_{ false };
185 
186   /// @name BuildSystemCommandInterface Implementation
187   /// @{
188 
getBuildEngine()189   virtual BuildEngine& getBuildEngine() override {
190     return buildEngine;
191   }
192 
getExecutionQueue()193   virtual BuildExecutionQueue& getExecutionQueue() override {
194     assert(executionQueue.get());
195     return *executionQueue;
196   }
197 
taskNeedsInput(core::Task * task,const BuildKey & key,uintptr_t inputID)198   virtual void taskNeedsInput(core::Task* task, const BuildKey& key,
199                               uintptr_t inputID) override {
200     return buildEngine.taskNeedsInput(task, key.toData(), inputID);
201   }
202 
taskMustFollow(core::Task * task,const BuildKey & key)203   virtual void taskMustFollow(core::Task* task, const BuildKey& key) override {
204     return buildEngine.taskMustFollow(task, key.toData());
205   }
206 
taskDiscoveredDependency(core::Task * task,const BuildKey & key)207   virtual void taskDiscoveredDependency(core::Task* task,
208                                         const BuildKey& key) override {
209     return buildEngine.taskDiscoveredDependency(task, key.toData());
210   }
211 
taskIsComplete(core::Task * task,const BuildValue & value,bool forceChange)212   virtual void taskIsComplete(core::Task* task, const BuildValue& value,
213                               bool forceChange) override {
214     return buildEngine.taskIsComplete(task, value.toData(), forceChange);
215   }
216 
addJob(QueueJob && job)217   virtual void addJob(QueueJob&& job) override {
218     executionQueue->addJob(std::move(job));
219   }
220 
221   /// @}
222 
223 public:
BuildSystemImpl(class BuildSystem & buildSystem,BuildSystemDelegate & delegate)224   BuildSystemImpl(class BuildSystem& buildSystem,
225                   BuildSystemDelegate& delegate)
226       : buildSystem(buildSystem), delegate(delegate),
227         fileDelegate(*this), engineDelegate(*this), buildEngine(engineDelegate),
228         executionQueue() {}
229 
getBuildSystem()230   BuildSystem& getBuildSystem() {
231     return buildSystem;
232   }
233 
getDelegate()234   BuildSystemDelegate& getDelegate() override {
235     return delegate;
236   }
237 
238   // FIXME: We should eliminate this, it isn't well formed when loading
239   // descriptions not from a file. We currently only use that for unit testing,
240   // though.
getMainFilename()241   StringRef getMainFilename() {
242     return mainFilename;
243   }
244 
getCommandInterface()245   BuildSystemCommandInterface& getCommandInterface() {
246     return *this;
247   }
248 
getBuildDescription() const249   const BuildDescription& getBuildDescription() const {
250     assert(buildDescription);
251     return *buildDescription;
252   }
253 
error(StringRef filename,const Twine & message)254   void error(StringRef filename, const Twine& message) {
255     getDelegate().error(filename, {}, message);
256   }
257 
error(StringRef filename,const BuildSystemDelegate::Token & at,const Twine & message)258   void error(StringRef filename, const BuildSystemDelegate::Token& at,
259              const Twine& message) {
260     getDelegate().error(filename, at, message);
261   }
262 
263   std::unique_ptr<BuildNode> lookupNode(StringRef name,
264                                         bool isImplicit);
265 
getMergedSchemaVersion()266   uint32_t getMergedSchemaVersion() {
267     // FIXME: Find a cleaner strategy for merging the internal schema version
268     // with that from the client.
269     auto clientVersion = delegate.getVersion();
270     assert(clientVersion <= (1 << 16) && "unsupported client verison");
271     return internalSchemaVersion + (clientVersion << 16);
272   }
273 
274   /// @name Client API
275   /// @{
276 
loadDescription(StringRef filename)277   bool loadDescription(StringRef filename) {
278     this->mainFilename = filename;
279 
280     auto description = BuildFile(filename, fileDelegate).load();
281     if (!description) {
282       error(getMainFilename(), "unable to load build file");
283       return false;
284     }
285 
286     buildDescription = std::move(description);
287     return true;
288   }
289 
loadDescription(std::unique_ptr<BuildDescription> description)290   void loadDescription(std::unique_ptr<BuildDescription> description) {
291     buildDescription = std::move(description);
292   }
293 
attachDB(StringRef filename,std::string * error_out)294   bool attachDB(StringRef filename, std::string* error_out) {
295     // FIXME: How do we pass the client schema version here, if we haven't
296     // loaded the file yet.
297     std::unique_ptr<core::BuildDB> db(
298         core::createSQLiteBuildDB(filename, getMergedSchemaVersion(),
299                                   error_out));
300     if (!db)
301       return false;
302 
303     return buildEngine.attachDB(std::move(db), error_out);
304   }
305 
enableTracing(StringRef filename,std::string * error_out)306   bool enableTracing(StringRef filename, std::string* error_out) {
307     return buildEngine.enableTracing(filename, error_out);
308   }
309 
310   /// Build the given key, and return the result and an indication of success.
311   llvm::Optional<BuildValue> build(BuildKey key);
312 
313   bool build(StringRef target);
314 
setBuildWasAborted(bool value)315   void setBuildWasAborted(bool value) {
316     buildWasAborted = value;
317   }
318 
resetForBuild()319   void resetForBuild() {
320     std::lock_guard<std::mutex> guard(executionQueueMutex);
321     isCancelled_ = false;
322   }
323 
324   /// Cancel the running build.
cancel()325   void cancel() {
326     std::lock_guard<std::mutex> guard(executionQueueMutex);
327 
328     isCancelled_ = true;
329     // Cancel jobs if we actually have a queue.
330     if (executionQueue.get() != nullptr)
331       getExecutionQueue().cancelAllJobs();
332   }
333 
334   /// Check if the build has been cancelled.
isCancelled()335   bool isCancelled() {
336     return isCancelled_;
337   }
338 
339   /// @}
340 };
341 
342 #pragma mark - BuildSystem engine integration
343 
344 #pragma mark - Task implementations
345 
getBuildSystem(BuildEngine & engine)346 static BuildSystemImpl& getBuildSystem(BuildEngine& engine) {
347   return static_cast<BuildSystemEngineDelegate*>(
348       engine.getDelegate())->getBuildSystem();
349 }
350 
351 /// This is the task used to "build" a target, it translates between the request
352 /// for building a target key and the requests for all of its nodes.
353 class TargetTask : public Task {
354   Target& target;
355 
356   // Build specific data.
357   //
358   // FIXME: We should probably factor this out somewhere else, so we can enforce
359   // it is never used when initialized incorrectly.
360 
361   /// If true, the command had a missing input (this implies ShouldSkip is
362   /// true).
363   bool hasMissingInput = false;
364 
start(BuildEngine & engine)365   virtual void start(BuildEngine& engine) override {
366     // Request all of the necessary system tasks.
367     unsigned id = 0;
368     for (auto it = target.getNodes().begin(),
369            ie = target.getNodes().end(); it != ie; ++it, ++id) {
370       engine.taskNeedsInput(this, BuildKey::makeNode(*it).toData(), id);
371     }
372   }
373 
providePriorValue(BuildEngine &,const ValueType & value)374   virtual void providePriorValue(BuildEngine&,
375                                  const ValueType& value) override {
376     // Do nothing.
377   }
378 
provideValue(BuildEngine & engine,uintptr_t inputID,const ValueType & valueData)379   virtual void provideValue(BuildEngine& engine, uintptr_t inputID,
380                             const ValueType& valueData) override {
381     // Do nothing.
382     auto value = BuildValue::fromData(valueData);
383 
384     if (value.isMissingInput()) {
385       hasMissingInput = true;
386 
387       // FIXME: Design the logging and status output APIs.
388       auto& system = getBuildSystem(engine);
389       system.error(system.getMainFilename(),
390                    (Twine("missing input '") +
391                     target.getNodes()[inputID]->getName() +
392                     "' and no rule to build it"));
393     }
394   }
395 
inputsAvailable(BuildEngine & engine)396   virtual void inputsAvailable(BuildEngine& engine) override {
397     // If the build should cancel, do nothing.
398     if (getBuildSystem(engine).isCancelled()) {
399       engine.taskIsComplete(this, BuildValue::makeSkippedCommand().toData());
400       return;
401     }
402 
403     if (hasMissingInput) {
404       // FIXME: Design the logging and status output APIs.
405       auto& system = getBuildSystem(engine);
406       system.error(system.getMainFilename(),
407                    (Twine("cannot build target '") + target.getName() +
408                     "' due to missing input"));
409 
410       // Report the command failure.
411       system.getDelegate().hadCommandFailure();
412     }
413 
414     // Complete the task immediately.
415     engine.taskIsComplete(this, BuildValue::makeTarget().toData());
416   }
417 
418 public:
TargetTask(Target & target)419   TargetTask(Target& target) : target(target) {}
420 
isResultValid(BuildEngine & engine,Target & node,const BuildValue & value)421   static bool isResultValid(BuildEngine& engine, Target& node,
422                             const BuildValue& value) {
423     // Always treat target tasks as invalid.
424     return false;
425   }
426 };
427 
428 
429 /// This is the task to "build" a file node which represents pure raw input to
430 /// the system.
431 class FileInputNodeTask : public Task {
432   BuildNode& node;
433 
start(BuildEngine & engine)434   virtual void start(BuildEngine& engine) override {
435     assert(node.getProducers().empty());
436   }
437 
providePriorValue(BuildEngine &,const ValueType & value)438   virtual void providePriorValue(BuildEngine&,
439                                  const ValueType& value) override {
440   }
441 
provideValue(BuildEngine &,uintptr_t inputID,const ValueType & value)442   virtual void provideValue(BuildEngine&, uintptr_t inputID,
443                             const ValueType& value) override {
444   }
445 
inputsAvailable(BuildEngine & engine)446   virtual void inputsAvailable(BuildEngine& engine) override {
447     // FIXME: We should do this work in the background.
448 
449     // Get the information on the file.
450     //
451     // FIXME: This needs to delegate, since we want to have a notion of
452     // different node types.
453     assert(!node.isVirtual());
454     auto info = node.getFileInfo(
455         getBuildSystem(engine).getDelegate().getFileSystem());
456     if (info.isMissing()) {
457       engine.taskIsComplete(this, BuildValue::makeMissingInput().toData());
458       return;
459     }
460 
461     engine.taskIsComplete(
462         this, BuildValue::makeExistingInput(info).toData());
463   }
464 
465 public:
FileInputNodeTask(BuildNode & node)466   FileInputNodeTask(BuildNode& node) : node(node) {
467     assert(!node.isVirtual());
468   }
469 
isResultValid(BuildEngine & engine,const BuildNode & node,const BuildValue & value)470   static bool isResultValid(BuildEngine& engine, const BuildNode& node,
471                             const BuildValue& value) {
472     // The result is valid if the existence matches the value type and the file
473     // information remains the same.
474     //
475     // FIXME: This is inefficient, we will end up doing the stat twice, once
476     // when we check the value for up to dateness, and once when we "build" the
477     // output.
478     //
479     // We can solve this by caching ourselves but I wonder if it is something
480     // the engine should support more naturally. In practice, this is unlikely
481     // to be very performance critical in practice because this is only
482     // redundant in the case where we have never built the node before (or need
483     // to rebuild it), and thus the additional stat is only one small part of
484     // the work we need to perform.
485     auto info = node.getFileInfo(
486         getBuildSystem(engine).getDelegate().getFileSystem());
487     if (info.isMissing()) {
488       return value.isMissingInput();
489     } else {
490       return value.isExistingInput() && value.getOutputInfo() == info;
491     }
492   }
493 };
494 
495 
496 /// This is the task to "build" a directory node.
497 ///
498 /// This node effectively just adapts a directory tree signature to a node. The
499 /// reason why we need it (versus simply making the directory tree signature
500 /// *be* this, is that we want the directory signature to be able to interface
501 /// with other build nodes produced by commands).
502 class DirectoryInputNodeTask : public Task {
503   BuildNode& node;
504 
505   core::ValueType directorySignature;
506 
start(BuildEngine & engine)507   virtual void start(BuildEngine& engine) override {
508     // Remove any trailing slash from the node name.
509     StringRef path =  node.getName();
510     if (path.endswith("/") && path != "/") {
511       path = path.substr(0, path.size() - 1);
512     }
513     engine.taskNeedsInput(
514         this, BuildKey::makeDirectoryTreeSignature(path).toData(),
515         /*inputID=*/0);
516   }
517 
providePriorValue(BuildEngine &,const ValueType & value)518   virtual void providePriorValue(BuildEngine&,
519                                  const ValueType& value) override {
520   }
521 
provideValue(BuildEngine &,uintptr_t inputID,const ValueType & value)522   virtual void provideValue(BuildEngine&, uintptr_t inputID,
523                             const ValueType& value) override {
524     directorySignature = value;
525   }
526 
inputsAvailable(BuildEngine & engine)527   virtual void inputsAvailable(BuildEngine& engine) override {
528     // Simply propagate the value.
529     engine.taskIsComplete(this, ValueType(directorySignature));
530   }
531 
532 public:
DirectoryInputNodeTask(BuildNode & node)533   DirectoryInputNodeTask(BuildNode& node) : node(node) {
534     assert(!node.isVirtual());
535   }
536 };
537 
538 
539 /// This is the task to build a virtual node which isn't connected to any
540 /// output.
541 class VirtualInputNodeTask : public Task {
start(BuildEngine & engine)542   virtual void start(BuildEngine& engine) override {
543   }
544 
providePriorValue(BuildEngine &,const ValueType & value)545   virtual void providePriorValue(BuildEngine&,
546                                  const ValueType& value) override {
547   }
548 
provideValue(BuildEngine &,uintptr_t inputID,const ValueType & value)549   virtual void provideValue(BuildEngine&, uintptr_t inputID,
550                             const ValueType& value) override {
551   }
552 
inputsAvailable(BuildEngine & engine)553   virtual void inputsAvailable(BuildEngine& engine) override {
554     engine.taskIsComplete(
555         this, BuildValue::makeVirtualInput().toData());
556   }
557 
558 public:
VirtualInputNodeTask()559   VirtualInputNodeTask() {}
560 
isResultValid(BuildEngine & engine,const BuildNode & node,const BuildValue & value)561   static bool isResultValid(BuildEngine& engine, const BuildNode& node,
562                             const BuildValue& value) {
563     // Virtual input nodes are always valid unless the value type is wrong.
564     return value.isVirtualInput();
565   }
566 };
567 
568 
569 /// This is the task to "build" a node which is the product of some command.
570 ///
571 /// It is responsible for selecting the appropriate producer command to run to
572 /// produce the node, and for synchronizing any external state the node depends
573 /// on.
574 class ProducedNodeTask : public Task {
575   Node& node;
576   BuildValue nodeResult;
577   Command* producingCommand = nullptr;
578 
579   // Build specific data.
580   //
581   // FIXME: We should probably factor this out somewhere else, so we can enforce
582   // it is never used when initialized incorrectly.
583 
584   // Whether this is a node we are unable to produce.
585   bool isInvalid = false;
586 
start(BuildEngine & engine)587   virtual void start(BuildEngine& engine) override {
588     // Request the producer command.
589     if (node.getProducers().size() == 1) {
590       producingCommand = node.getProducers()[0];
591       engine.taskNeedsInput(this, BuildKey::makeCommand(
592                                 producingCommand->getName()).toData(),
593                             /*InputID=*/0);
594       return;
595     }
596 
597     // We currently do not support building nodes which have multiple producers.
598     auto producerA = node.getProducers()[0];
599     auto producerB = node.getProducers()[1];
600     getBuildSystem(engine).error(
601         "", "unable to build node: '" + node.getName() + "' (node is produced "
602         "by multiple commands; e.g., '" + producerA->getName() + "' and '" +
603         producerB->getName() + "')");
604     isInvalid = true;
605   }
606 
providePriorValue(BuildEngine &,const ValueType & value)607   virtual void providePriorValue(BuildEngine&,
608                                  const ValueType& value) override {
609   }
610 
provideValue(BuildEngine &,uintptr_t inputID,const ValueType & valueData)611   virtual void provideValue(BuildEngine&, uintptr_t inputID,
612                             const ValueType& valueData) override {
613     auto value = BuildValue::fromData(valueData);
614 
615     // Extract the node result from the command.
616     assert(producingCommand);
617     nodeResult = producingCommand->getResultForOutput(&node, value);
618   }
619 
inputsAvailable(BuildEngine & engine)620   virtual void inputsAvailable(BuildEngine& engine) override {
621     if (isInvalid) {
622       getBuildSystem(engine).getDelegate().hadCommandFailure();
623       engine.taskIsComplete(this, BuildValue::makeFailedInput().toData());
624       return;
625     }
626 
627     assert(!nodeResult.isInvalid());
628 
629     // Complete the task immediately.
630     engine.taskIsComplete(this, nodeResult.toData());
631   }
632 
633 public:
ProducedNodeTask(Node & node)634   ProducedNodeTask(Node& node)
635       : node(node), nodeResult(BuildValue::makeInvalid()) {}
636 
isResultValid(BuildEngine &,Node & node,const BuildValue & value)637   static bool isResultValid(BuildEngine&, Node& node,
638                             const BuildValue& value) {
639     // If the result was failure, we always need to rebuild (it may produce an
640     // error).
641     if (value.isFailedInput())
642       return false;
643 
644     // The produced node result itself doesn't need any synchronization.
645     return true;
646   }
647 };
648 
649 
650 /// This task is responsible for computing the lists of files in directories.
651 class DirectoryContentsTask : public Task {
652   std::string path;
653 
654   /// The value for the input directory.
655   ValueType directoryValue;
656 
start(BuildEngine & engine)657   virtual void start(BuildEngine& engine) override {
658     // Request the base directory node -- this task doesn't actually use the
659     // value, but this connects the task to its producer if present.
660     engine.taskNeedsInput(
661         this, BuildKey::makeNode(path).toData(), /*inputID=*/0);
662   }
663 
providePriorValue(BuildEngine &,const ValueType & value)664   virtual void providePriorValue(BuildEngine&,
665                                  const ValueType& value) override {
666   }
667 
provideValue(BuildEngine &,uintptr_t inputID,const ValueType & value)668   virtual void provideValue(BuildEngine&, uintptr_t inputID,
669                             const ValueType& value) override {
670     if (inputID == 0) {
671       directoryValue = value;
672       return;
673     }
674   }
675 
inputsAvailable(BuildEngine & engine)676   virtual void inputsAvailable(BuildEngine& engine) override {
677     // FIXME: We should do this work in the background.
678 
679     // Get the stat information on the directory.
680     //
681     // FIXME: We should probably be using the directory value here, but that
682     // requires reworking some of the value encoding for the directory.
683     auto info = getBuildSystem(engine).getDelegate().getFileSystem().getFileInfo(
684         path);
685     if (info.isMissing()) {
686       engine.taskIsComplete(
687           this, BuildValue::makeMissingInput().toData());
688       return;
689     }
690 
691     // Get the list of files in the directory.
692     std::error_code ec;
693     std::vector<std::string> filenames;
694     for (auto it = llvm::sys::fs::directory_iterator(path, ec),
695            end = llvm::sys::fs::directory_iterator(); it != end;
696          it = it.increment(ec)) {
697       filenames.push_back(llvm::sys::path::filename(it->path()));
698     }
699 
700     // Order the filenames.
701     std::sort(filenames.begin(), filenames.end(),
702               [](const std::string& a, const std::string& b) {
703                 return a < b;
704               });
705 
706     // Create the result.
707     engine.taskIsComplete(
708         this, BuildValue::makeDirectoryContents(info, filenames).toData());
709   }
710 
711 public:
DirectoryContentsTask(StringRef path)712   DirectoryContentsTask(StringRef path) : path(path) {}
713 
isResultValid(BuildEngine & engine,StringRef path,const BuildValue & value)714   static bool isResultValid(BuildEngine& engine, StringRef path,
715                             const BuildValue& value) {
716     // The result is valid if the existence matches the existing value type, and
717     // the file information remains the same.
718     auto info = getBuildSystem(engine).getDelegate().getFileSystem().getFileInfo(
719         path);
720     if (info.isMissing()) {
721       return value.isMissingInput();
722     } else {
723       return value.isDirectoryContents() && value.getOutputInfo() == info;
724     }
725   }
726 };
727 
728 
729 
730 /// This is the task to "build" a directory node which will encapsulate (via a
731 /// signature) all of the contents of the directory, recursively.
732 class DirectoryTreeSignatureTask : public Task {
733   // The basic algorithm we need to follow:
734   //
735   // 1. Get the directory contents.
736   // 2. Get the subpath directory info.
737   // 3. For each node input, if it is a directory, get the input node for it.
738   //
739   // FIXME: This algorithm currently does a redundant stat for each directory,
740   // because we stat it once to find out it is a directory, then again when we
741   // gather its contents (to use for validating the directory contents).
742   //
743   // FIXME: We need to fix the directory list to not get contents for symbolic
744   // links.
745 
746   /// This structure encapsulates the information we need on each child.
747   struct SubpathInfo {
748     /// The filename;
749     std::string filename;
750 
751     /// The result of requesting the node at this subpath, once available.
752     ValueType value;
753 
754     /// The directory signature, if needed.
755     llvm::Optional<ValueType> directorySignatureValue;
756   };
757 
758   /// The path we are taking the signature of.
759   std::string path;
760 
761   /// The value for the directory itself.
762   ValueType directoryValue;
763 
764   /// The accumulated list of child input info.
765   ///
766   /// Once we have the input directory information, we resize this to match the
767   /// number of children to avoid dynamically resizing it.
768   std::vector<SubpathInfo> childResults;
769 
start(BuildEngine & engine)770   virtual void start(BuildEngine& engine) override {
771     // Ask for the base directory directory contents.
772     engine.taskNeedsInput(
773         this, BuildKey::makeDirectoryContents(path).toData(),
774         /*inputID=*/0);
775   }
776 
providePriorValue(BuildEngine &,const ValueType & value)777   virtual void providePriorValue(BuildEngine&,
778                                  const ValueType& value) override {
779   }
780 
provideValue(BuildEngine & engine,uintptr_t inputID,const ValueType & valueData)781   virtual void provideValue(BuildEngine& engine, uintptr_t inputID,
782                             const ValueType& valueData) override {
783     // The first input is the directory contents.
784     if (inputID == 0) {
785       // Record the value for the directory.
786       directoryValue = valueData;
787 
788       // Request the inputs for each subpath.
789       auto value = BuildValue::fromData(valueData);
790       if (value.isMissingInput())
791         return;
792 
793       assert(value.isDirectoryContents());
794       auto filenames = value.getDirectoryContents();
795       for (size_t i = 0; i != filenames.size(); ++i) {
796         SmallString<256> childPath{ path };
797         llvm::sys::path::append(childPath, filenames[i]);
798         childResults.emplace_back(SubpathInfo{ filenames[i], {}, None });
799         engine.taskNeedsInput(this, BuildKey::makeNode(childPath).toData(),
800                               /*inputID=*/1 + i);
801       }
802       return;
803     }
804 
805     // If the input is a child, add it to the collection and dispatch a
806     // directory request if needed.
807     if (inputID >= 1 && inputID < 1 + childResults.size()) {
808       auto index = inputID - 1;
809       auto& childResult = childResults[index];
810       childResult.value = valueData;
811 
812       // If this node is a directory, request its signature recursively.
813       auto value = BuildValue::fromData(valueData);
814       if (value.isExistingInput()) {
815         if (value.getOutputInfo().isDirectory()) {
816           SmallString<256> childPath{ path };
817           llvm::sys::path::append(childPath, childResult.filename);
818 
819           engine.taskNeedsInput(
820               this, BuildKey::makeDirectoryTreeSignature(childPath).toData(),
821               /*inputID=*/1 + childResults.size() + index);
822         }
823       }
824       return;
825     }
826 
827     // Otherwise, the input should be a directory signature.
828     auto index = inputID - 1 - childResults.size();
829     assert(index < childResults.size());
830     childResults[index].directorySignatureValue = valueData;
831   }
832 
inputsAvailable(BuildEngine & engine)833   virtual void inputsAvailable(BuildEngine& engine) override {
834     // Compute the signature across all of the inputs.
835     using llvm::hash_combine;
836     llvm::hash_code code = hash_value(path);
837 
838     // Add the signature for the actual input path.
839     code = hash_combine(
840         code, hash_combine_range(directoryValue.begin(), directoryValue.end()));
841 
842     // For now, we represent this task as the aggregation of all the inputs.
843     for (const auto& info: childResults) {
844       // We merge the children by simply combining their encoded representation.
845       code = hash_combine(
846           code, hash_combine_range(info.value.begin(), info.value.end()));
847       if (info.directorySignatureValue.hasValue()) {
848         auto& data = info.directorySignatureValue.getValue();
849         code = hash_combine(
850             code, hash_combine_range(data.begin(), data.end()));
851       } else {
852         // Combine a random number to represent nil.
853         code = hash_combine(code, 0XC183979C3E98722E);
854       }
855     }
856 
857     // Compute the signature.
858     engine.taskIsComplete(this, BuildValue::makeDirectoryTreeSignature(
859                               uint64_t(code)).toData());
860   }
861 
862 public:
DirectoryTreeSignatureTask(StringRef path)863   DirectoryTreeSignatureTask(StringRef path) : path(path) {}
864 };
865 
866 
867 /// This is the task to actually execute a command.
868 class CommandTask : public Task {
869   Command& command;
870 
start(BuildEngine & engine)871   virtual void start(BuildEngine& engine) override {
872     // Notify the client the command is preparing to run.
873     getBuildSystem(engine).getDelegate().commandPreparing(&command);
874 
875     command.start(getBuildSystem(engine).getCommandInterface(), this);
876   }
877 
providePriorValue(BuildEngine & engine,const ValueType & valueData)878   virtual void providePriorValue(BuildEngine& engine,
879                                  const ValueType& valueData) override {
880     BuildValue value = BuildValue::fromData(valueData);
881     command.providePriorValue(
882         getBuildSystem(engine).getCommandInterface(), this, value);
883   }
884 
provideValue(BuildEngine & engine,uintptr_t inputID,const ValueType & valueData)885   virtual void provideValue(BuildEngine& engine, uintptr_t inputID,
886                             const ValueType& valueData) override {
887     command.provideValue(
888         getBuildSystem(engine).getCommandInterface(), this, inputID,
889         BuildValue::fromData(valueData));
890   }
891 
inputsAvailable(BuildEngine & engine)892   virtual void inputsAvailable(BuildEngine& engine) override {
893     auto& bsci = getBuildSystem(engine).getCommandInterface();
894     auto fn = [this, &bsci=bsci](QueueJobContext* context) {
895       // If the build should cancel, do nothing.
896       if (getBuildSystem(bsci.getBuildEngine()).isCancelled()) {
897         bsci.taskIsComplete(this, BuildValue::makeCancelledCommand());
898         return;
899       }
900 
901       // Check if the command should be skipped.
902       if (!bsci.getDelegate().shouldCommandStart(&command)) {
903         // We need to call commandFinished here because commandPreparing and
904         // shouldCommandStart guarantee that they're followed by
905         // commandFinished.
906         bsci.getDelegate().commandFinished(&command, CommandResult::Skipped);
907         bsci.taskIsComplete(this, BuildValue::makeSkippedCommand());
908         return;
909       }
910 
911       // Execute the command, with notifications to the delegate.
912       auto result = command.execute(bsci, this, context);
913 
914       // Inform the engine of the result.
915       if (result.isFailedCommand()) {
916         bsci.getDelegate().hadCommandFailure();
917       }
918       bsci.taskIsComplete(this, std::move(result));
919     };
920     bsci.addJob({ &command, std::move(fn) });
921   }
922 
923 public:
CommandTask(Command & command)924   CommandTask(Command& command) : command(command) {}
925 
isResultValid(BuildEngine & engine,Command & command,const BuildValue & value)926   static bool isResultValid(BuildEngine& engine, Command& command,
927                             const BuildValue& value) {
928     // Delegate to the command for further checking.
929     return command.isResultValid(
930         getBuildSystem(engine).getBuildSystem(), value);
931   }
932 };
933 
934 #pragma mark - BuildSystemEngineDelegate implementation
935 
936 /// This is a synthesized task used to represent a missing command.
937 ///
938 /// This command is used in cases where a command has been removed from the
939 /// manifest, but can still be found during an incremental rebuild. This command
940 /// is used to inject an invalid value thus forcing downstream clients to
941 /// rebuild.
942 class MissingCommandTask : public Task {
943 private:
start(BuildEngine & engine)944   virtual void start(BuildEngine& engine) override { }
providePriorValue(BuildEngine & engine,const ValueType & valueData)945   virtual void providePriorValue(BuildEngine& engine,
946                                  const ValueType& valueData) override { }
947 
provideValue(BuildEngine & engine,uintptr_t inputID,const ValueType & valueData)948   virtual void provideValue(BuildEngine& engine, uintptr_t inputID,
949                             const ValueType& valueData) override { }
950 
inputsAvailable(BuildEngine & engine)951   virtual void inputsAvailable(BuildEngine& engine) override {
952     // A missing command always builds to an invalid value, and forces
953     // downstream clients to be rebuilt (at which point they will presumably see
954     // the command is no longer used).
955     return engine.taskIsComplete(this, BuildValue::makeInvalid().toData(),
956                                  /*forceChange=*/true);
957   }
958 
959 public:
960   using Task::Task;
961 };
962 
getBuildDescription() const963 const BuildDescription& BuildSystemEngineDelegate::getBuildDescription() const {
964   return system.getBuildDescription();
965 }
966 
967 static BuildSystemDelegate::CommandStatusKind
convertStatusKind(core::Rule::StatusKind kind)968 convertStatusKind(core::Rule::StatusKind kind) {
969   switch (kind) {
970   case core::Rule::StatusKind::IsScanning:
971     return BuildSystemDelegate::CommandStatusKind::IsScanning;
972   case core::Rule::StatusKind::IsUpToDate:
973     return BuildSystemDelegate::CommandStatusKind::IsUpToDate;
974   case core::Rule::StatusKind::IsComplete:
975     return BuildSystemDelegate::CommandStatusKind::IsComplete;
976   }
977   assert(0 && "unknown status kind");
978   return BuildSystemDelegate::CommandStatusKind::IsScanning;
979 }
980 
lookupRule(const KeyType & keyData)981 Rule BuildSystemEngineDelegate::lookupRule(const KeyType& keyData) {
982   // Decode the key.
983   auto key = BuildKey::fromData(keyData);
984 
985   switch (key.getKind()) {
986   case BuildKey::Kind::Unknown:
987     break;
988 
989   case BuildKey::Kind::Command: {
990     // Find the comand.
991     auto it = getBuildDescription().getCommands().find(key.getCommandName());
992     if (it == getBuildDescription().getCommands().end()) {
993       // If there is no such command, produce an error task.
994       return Rule{
995         keyData,
996         /*Action=*/ [](BuildEngine& engine) -> Task* {
997           return engine.registerTask(new MissingCommandTask());
998         },
999         /*IsValid=*/ [](BuildEngine&, const Rule& rule,
1000                         const ValueType& value) -> bool {
1001           // The cached result for a missing command is never valid.
1002           return false;
1003         }
1004       };
1005     }
1006 
1007     // Create the rule for the command.
1008     Command* command = it->second.get();
1009     return Rule{
1010       keyData,
1011       /*Action=*/ [command](BuildEngine& engine) -> Task* {
1012         return engine.registerTask(new CommandTask(*command));
1013       },
1014       /*IsValid=*/ [command](BuildEngine& engine, const Rule& rule,
1015                              const ValueType& value) -> bool {
1016         return CommandTask::isResultValid(
1017             engine, *command, BuildValue::fromData(value));
1018       },
1019       /*UpdateStatus=*/ [command](BuildEngine& engine,
1020                                   core::Rule::StatusKind status) {
1021         return ::getBuildSystem(engine).getDelegate().commandStatusChanged(
1022             command, convertStatusKind(status));
1023       }
1024     };
1025   }
1026 
1027   case BuildKey::Kind::CustomTask: {
1028     // Search for a tool which knows how to create the given custom task.
1029     //
1030     // FIXME: We should most likely have some kind of registration process so we
1031     // can do an efficient query here, but exactly how this should look isn't
1032     // clear yet.
1033     for (const auto& it: getBuildDescription().getTools()) {
1034       auto result = it.second->createCustomCommand(key);
1035       if (!result) continue;
1036 
1037       // Save the custom command.
1038       customTasks.emplace_back(std::move(result));
1039       Command *command = customTasks.back().get();
1040 
1041       return Rule{
1042         keyData,
1043         /*Action=*/ [command](BuildEngine& engine) -> Task* {
1044           return engine.registerTask(new CommandTask(*command));
1045         },
1046         /*IsValid=*/ [command](BuildEngine& engine, const Rule& rule,
1047                                const ValueType& value) -> bool {
1048           return CommandTask::isResultValid(
1049               engine, *command, BuildValue::fromData(value));
1050         }
1051       };
1052     }
1053 
1054     // We were unable to create an appropriate custom command, produce an error
1055     // task.
1056     return Rule{
1057       keyData,
1058       /*Action=*/ [](BuildEngine& engine) -> Task* {
1059         return engine.registerTask(new MissingCommandTask());
1060       },
1061       /*IsValid=*/ [](BuildEngine&, const Rule& rule,
1062                       const ValueType& value) -> bool {
1063         // The cached result for a missing command is never valid.
1064         return false;
1065       }
1066     };
1067   }
1068 
1069   case BuildKey::Kind::DirectoryContents: {
1070     std::string path = key.getDirectoryContentsPath();
1071     return Rule{
1072       keyData,
1073       /*Action=*/ [path](BuildEngine& engine) -> Task* {
1074         return engine.registerTask(new DirectoryContentsTask(path));
1075       },
1076       /*IsValid=*/ [path](BuildEngine& engine, const Rule& rule,
1077                           const ValueType& value) -> bool {
1078         return DirectoryContentsTask::isResultValid(
1079             engine, path, BuildValue::fromData(value));
1080       }
1081     };
1082   }
1083 
1084   case BuildKey::Kind::DirectoryTreeSignature: {
1085     std::string path = key.getDirectoryTreeSignaturePath();
1086     return Rule{
1087       keyData,
1088       /*Action=*/ [path](BuildEngine& engine) -> Task* {
1089         return engine.registerTask(new DirectoryTreeSignatureTask(path));
1090       },
1091         // Directory signatures don't require any validation outside of their
1092         // concrete dependencies.
1093       /*IsValid=*/ nullptr
1094     };
1095   }
1096 
1097   case BuildKey::Kind::Node: {
1098     // Find the node.
1099     auto it = getBuildDescription().getNodes().find(key.getNodeName());
1100     BuildNode* node;
1101     if (it != getBuildDescription().getNodes().end()) {
1102       node = static_cast<BuildNode*>(it->second.get());
1103     } else {
1104       auto it = dynamicNodes.find(key.getNodeName());
1105       if (it != dynamicNodes.end()) {
1106         node = it->second.get();
1107       } else {
1108         // Create nodes on the fly for any unknown ones.
1109         auto nodeOwner = system.lookupNode(
1110             key.getNodeName(), /*isImplicit=*/true);
1111         node = nodeOwner.get();
1112         dynamicNodes[key.getNodeName()] = std::move(nodeOwner);
1113       }
1114     }
1115 
1116     // Create the rule used to construct this node.
1117     //
1118     // We could bypass this level and directly return the rule to run the
1119     // command, which would reduce the number of tasks in the system. For now we
1120     // do the uniform thing, but do differentiate between input and command
1121     // nodes.
1122 
1123     // Create an input node if there are no producers.
1124     if (node->getProducers().empty()) {
1125       if (node->isVirtual()) {
1126         return Rule{
1127           keyData,
1128           /*Action=*/ [](BuildEngine& engine) -> Task* {
1129             return engine.registerTask(new VirtualInputNodeTask());
1130           },
1131           /*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
1132                                 const ValueType& value) -> bool {
1133             return VirtualInputNodeTask::isResultValid(
1134                 engine, *node, BuildValue::fromData(value));
1135           }
1136         };
1137       }
1138 
1139       if (node->isDirectory()) {
1140         return Rule{
1141           keyData,
1142             /*Action=*/ [node](BuildEngine& engine) -> Task* {
1143             return engine.registerTask(new DirectoryInputNodeTask(*node));
1144           },
1145             // Directory nodes don't require any validation outside of their
1146             // concrete dependencies.
1147           /*IsValid=*/ nullptr
1148         };
1149       }
1150 
1151       return Rule{
1152         keyData,
1153         /*Action=*/ [node](BuildEngine& engine) -> Task* {
1154           return engine.registerTask(new FileInputNodeTask(*node));
1155         },
1156         /*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
1157                             const ValueType& value) -> bool {
1158           return FileInputNodeTask::isResultValid(
1159               engine, *node, BuildValue::fromData(value));
1160         }
1161       };
1162     }
1163 
1164     // Otherwise, create a task for a produced node.
1165     return Rule{
1166       keyData,
1167       /*Action=*/ [node](BuildEngine& engine) -> Task* {
1168         return engine.registerTask(new ProducedNodeTask(*node));
1169       },
1170       /*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
1171                           const ValueType& value) -> bool {
1172         return ProducedNodeTask::isResultValid(
1173             engine, *node, BuildValue::fromData(value));
1174       }
1175     };
1176   }
1177 
1178   case BuildKey::Kind::Target: {
1179     // Find the target.
1180     auto it = getBuildDescription().getTargets().find(key.getTargetName());
1181     if (it == getBuildDescription().getTargets().end()) {
1182       // FIXME: Invalid target name, produce an error.
1183       assert(0 && "FIXME: invalid target");
1184       abort();
1185     }
1186 
1187     // Create the rule to construct this target.
1188     Target* target = it->second.get();
1189     return Rule{
1190       keyData,
1191         /*Action=*/ [target](BuildEngine& engine) -> Task* {
1192         return engine.registerTask(new TargetTask(*target));
1193       },
1194       /*IsValid=*/ [target](BuildEngine& engine, const Rule& rule,
1195                             const ValueType& value) -> bool {
1196         return TargetTask::isResultValid(
1197             engine, *target, BuildValue::fromData(value));
1198       }
1199     };
1200   }
1201   }
1202 
1203   assert(0 && "invalid key type");
1204   abort();
1205 }
1206 
cycleDetected(const std::vector<Rule * > & cycle)1207 void BuildSystemEngineDelegate::cycleDetected(const std::vector<Rule*>& cycle) {
1208   // Track that the build has been aborted.
1209   getBuildSystem().setBuildWasAborted(true);
1210   static_cast<BuildSystemFrontendDelegate*>(&getBuildSystem().getDelegate())->cycleDetected(cycle);
1211 }
1212 
error(const Twine & message)1213 void BuildSystemEngineDelegate::error(const Twine& message) {
1214   system.error(system.getMainFilename(), message);
1215 }
1216 
1217 #pragma mark - BuildSystemImpl implementation
1218 
1219 std::unique_ptr<BuildNode>
lookupNode(StringRef name,bool isImplicit)1220 BuildSystemImpl::lookupNode(StringRef name, bool isImplicit) {
1221   bool isDirectory = name.endswith("/");
1222   bool isVirtual = !name.empty() && name[0] == '<' && name.back() == '>';
1223   return llvm::make_unique<BuildNode>(name, isDirectory, isVirtual,
1224                                       /*isCommandTimestamp=*/false,
1225                                       /*isMutable=*/false);
1226 }
1227 
build(BuildKey key)1228 llvm::Optional<BuildValue> BuildSystemImpl::build(BuildKey key) {
1229 
1230   // Aquire lock and create execution queue.
1231   {
1232     std::lock_guard<std::mutex> guard(executionQueueMutex);
1233 
1234     // If we were cancelled, return.
1235     if (isCancelled()) {
1236       return None;
1237     }
1238 
1239     executionQueue = delegate.createExecutionQueue();
1240   }
1241 
1242   // Build the target.
1243   buildWasAborted = false;
1244   auto result = getBuildEngine().build(key.toData());
1245 
1246   // Release the execution queue, impicitly waiting for it to complete. The
1247   // asynchronous nature of the engine callbacks means it is possible for the
1248   // queue to have notified the engine of the last task completion, but still
1249   // have other work to perform (e.g., informing the client of command
1250   // completion).
1251   executionQueue.reset();
1252 
1253   if (buildWasAborted)
1254     return None;
1255   return BuildValue::fromData(result);
1256 }
1257 
build(StringRef target)1258 bool BuildSystemImpl::build(StringRef target) {
1259   // The build description must have been loaded.
1260   if (!buildDescription) {
1261     error(getMainFilename(), "no build description loaded");
1262     return false;
1263   }
1264 
1265   // If target name is not passed then we try to load the default target name
1266   // from manifest file
1267   if (target.empty()) {
1268     target = getBuildDescription().getDefaultTarget();
1269   }
1270 
1271   return build(BuildKey::makeTarget(target)).hasValue();
1272 }
1273 
1274 #pragma mark - PhonyTool implementation
1275 
1276 class PhonyCommand : public ExternalCommand {
1277 public:
1278   using ExternalCommand::ExternalCommand;
1279 
shouldShowStatus()1280   virtual bool shouldShowStatus() override { return false; }
1281 
getShortDescription(SmallVectorImpl<char> & result)1282   virtual void getShortDescription(SmallVectorImpl<char> &result) override {
1283     llvm::raw_svector_ostream(result) << getName();
1284   }
1285 
getVerboseDescription(SmallVectorImpl<char> & result)1286   virtual void getVerboseDescription(SmallVectorImpl<char> &result) override {
1287     llvm::raw_svector_ostream(result) << getName();
1288   }
1289 
executeExternalCommand(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context)1290   virtual CommandResult executeExternalCommand(BuildSystemCommandInterface& bsci,
1291                                                Task* task,
1292                                                QueueJobContext* context) override {
1293     // Nothing needs to be done for phony commands.
1294     return CommandResult::Succeeded;
1295   }
1296 
getResultForOutput(Node * node,const BuildValue & value)1297   virtual BuildValue getResultForOutput(Node* node, const BuildValue& value) override {
1298     // If the node is virtual, the output is always a virtual input value,
1299     // regardless of the actual build value.
1300     //
1301     // This is a special case for phony commands, to avoid them incorrectly
1302     // propagating failed/cancelled states onwards to downstream commands when
1303     // they are being used only for ordering purposes.
1304     auto buildNode = static_cast<BuildNode*>(node);
1305     if (buildNode->isVirtual() && !buildNode->isCommandTimestamp()) {
1306       return BuildValue::makeVirtualInput();
1307     }
1308 
1309     // Otherwise, delegate to the inherited implementation.
1310     return ExternalCommand::getResultForOutput(node, value);
1311   }
1312 };
1313 
1314 class PhonyTool : public Tool {
1315 public:
1316   using Tool::Tool;
1317 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)1318   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1319                                   StringRef value) override {
1320     // No supported configuration attributes.
1321     ctx.error("unexpected attribute: '" + name + "'");
1322     return false;
1323   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)1324   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1325                                   ArrayRef<StringRef> values) override {
1326     // No supported configuration attributes.
1327     ctx.error("unexpected attribute: '" + name + "'");
1328     return false;
1329   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)1330   virtual bool configureAttribute(
1331       const ConfigureContext& ctx, StringRef name,
1332       ArrayRef<std::pair<StringRef, StringRef>> values) override {
1333     // No supported attributes.
1334     ctx.error("unexpected attribute: '" + name + "'");
1335     return false;
1336   }
1337 
createCommand(StringRef name)1338   virtual std::unique_ptr<Command> createCommand(StringRef name) override {
1339     return llvm::make_unique<PhonyCommand>(name);
1340   }
1341 };
1342 
1343 #pragma mark - ShellTool implementation
1344 
1345 class ShellCommand : public ExternalCommand {
1346   /// The dependencies style to expect (in the `depsPath`).
1347   enum class DepsStyle {
1348     /// No discovered dependencies are in use.
1349     Unused = 0,
1350 
1351     /// "Makefile" style dependencies in the form typically generated by C
1352     /// compilers, wherein the dependencies of the first target are treated as
1353     /// dependencies of the command.
1354     Makefile,
1355 
1356     /// Darwin's DependencyInfo format.
1357     DependencyInfo,
1358   };
1359 
1360   /// The command line arguments.
1361   std::vector<StringRef> args;
1362 
1363   /// The environment to use. If empty, the environment will be inherited.
1364   SmallVector<std::pair<StringRef, StringRef>, 1> env;
1365 
1366   /// The path to the dependency output file, if used.
1367   SmallVector<std::string, 1> depsPaths{};
1368 
1369   /// The style of dependencies used.
1370   DepsStyle depsStyle = DepsStyle::Unused;
1371 
1372   /// Whether to inherit the base environment.
1373   bool inheritEnv = true;
1374 
1375   /// The cached signature, once computed -- 0 is used as a sentinel value.
1376   std::atomic<uint64_t> cachedSignature{ 0 };
1377 
getSignature()1378   virtual uint64_t getSignature() override {
1379     uint64_t signature = cachedSignature;
1380     if (signature != 0)
1381       return signature;
1382 
1383     // FIXME: Use a more appropriate hashing infrastructure.
1384     using llvm::hash_combine;
1385     llvm::hash_code code = ExternalCommand::getSignature();
1386     for (const auto& arg: args) {
1387       code = hash_combine(code, arg);
1388     }
1389     for (const auto& entry: env) {
1390       code = hash_combine(code, entry.first);
1391       code = hash_combine(code, entry.second);
1392     }
1393     for (const auto& path: depsPaths) {
1394       code = hash_combine(code, path);
1395     }
1396     code = hash_combine(code, int(depsStyle));
1397     code = hash_combine(code, int(inheritEnv));
1398     signature = size_t(code);
1399     if (signature == 0) {
1400       signature = 1;
1401     }
1402     cachedSignature = signature;
1403     return signature;
1404   }
1405 
processDiscoveredDependencies(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context)1406   bool processDiscoveredDependencies(BuildSystemCommandInterface& bsci,
1407                                      Task* task,
1408                                      QueueJobContext* context) {
1409     // It is an error if the dependencies style is not specified.
1410     //
1411     // FIXME: Diagnose this sooner.
1412     if (depsStyle == DepsStyle::Unused) {
1413       getBuildSystem(bsci.getBuildEngine()).error(
1414           "", "missing required 'deps-style' specifier");
1415       return false;
1416     }
1417 
1418     for (const auto& depsPath: depsPaths) {
1419       // Read the dependencies file.
1420       auto input = bsci.getDelegate().getFileSystem().getFileContents(depsPath);
1421       if (!input) {
1422         getBuildSystem(bsci.getBuildEngine()).error(
1423             depsPath, "unable to open dependencies file (" + depsPath + ")");
1424         return false;
1425       }
1426 
1427       switch (depsStyle) {
1428       case DepsStyle::Unused:
1429         assert(0 && "unreachable");
1430         break;
1431 
1432       case DepsStyle::Makefile:
1433         if (!processMakefileDiscoveredDependencies(
1434                 bsci, task, context, depsPath, input.get()))
1435           return false;
1436         continue;
1437 
1438       case DepsStyle::DependencyInfo:
1439         if (!processDependencyInfoDiscoveredDependencies(
1440                 bsci, task, context, depsPath, input.get()))
1441           return false;
1442         continue;
1443       }
1444 
1445       llvm::report_fatal_error("unknown dependencies style");
1446     }
1447 
1448     return true;
1449   }
1450 
processMakefileDiscoveredDependencies(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context,StringRef depsPath,llvm::MemoryBuffer * input)1451   bool processMakefileDiscoveredDependencies(BuildSystemCommandInterface& bsci,
1452                                              Task* task,
1453                                              QueueJobContext* context,
1454                                              StringRef depsPath,
1455                                              llvm::MemoryBuffer* input) {
1456     // Parse the output.
1457     //
1458     // We just ignore the rule, and add any dependency that we encounter in the
1459     // file.
1460     struct DepsActions : public core::MakefileDepsParser::ParseActions {
1461       BuildSystemCommandInterface& bsci;
1462       Task* task;
1463       ShellCommand* command;
1464       StringRef depsPath;
1465       unsigned numErrors{0};
1466 
1467       DepsActions(BuildSystemCommandInterface& bsci, Task* task,
1468                   ShellCommand* command, StringRef depsPath)
1469           : bsci(bsci), task(task), command(command), depsPath(depsPath) {}
1470 
1471       virtual void error(const char* message, uint64_t position) override {
1472         getBuildSystem(bsci.getBuildEngine()).error(
1473             depsPath, "error reading dependency file: " + std::string(message));
1474         ++numErrors;
1475       }
1476 
1477       virtual void actOnRuleDependency(const char* dependency,
1478                                        uint64_t length,
1479                                        const StringRef unescapedWord) override {
1480         bsci.taskDiscoveredDependency(task, BuildKey::makeNode(unescapedWord));
1481       }
1482 
1483       virtual void actOnRuleStart(const char* name, uint64_t length,
1484                                   const StringRef unescapedWord) override {}
1485 
1486       virtual void actOnRuleEnd() override {}
1487     };
1488 
1489     DepsActions actions(bsci, task, this, depsPath);
1490     core::MakefileDepsParser(input->getBufferStart(), input->getBufferSize(),
1491                              actions).parse();
1492     return actions.numErrors == 0;
1493   }
1494 
1495   bool
processDependencyInfoDiscoveredDependencies(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context,StringRef depsPath,llvm::MemoryBuffer * input)1496   processDependencyInfoDiscoveredDependencies(BuildSystemCommandInterface& bsci,
1497                                               Task* task,
1498                                               QueueJobContext* context,
1499                                               StringRef depsPath,
1500                                               llvm::MemoryBuffer* input) {
1501     // Parse the output.
1502     //
1503     // We just ignore the rule, and add any dependency that we encounter in the
1504     // file.
1505     struct DepsActions : public core::DependencyInfoParser::ParseActions {
1506       BuildSystemCommandInterface& bsci;
1507       Task* task;
1508       ShellCommand* command;
1509       StringRef depsPath;
1510       unsigned numErrors{0};
1511 
1512       DepsActions(BuildSystemCommandInterface& bsci, Task* task,
1513                   ShellCommand* command, StringRef depsPath)
1514           : bsci(bsci), task(task), command(command), depsPath(depsPath) {}
1515 
1516       virtual void error(const char* message, uint64_t position) override {
1517         getBuildSystem(bsci.getBuildEngine()).error(
1518             depsPath, "error reading dependency file: " + std::string(message));
1519         ++numErrors;
1520       }
1521 
1522       // Ignore everything but actual inputs.
1523       virtual void actOnVersion(StringRef) override { }
1524       virtual void actOnMissing(StringRef) override { }
1525       virtual void actOnOutput(StringRef) override { }
1526 
1527       virtual void actOnInput(StringRef name) override {
1528         bsci.taskDiscoveredDependency(task, BuildKey::makeNode(name));
1529       }
1530     };
1531 
1532     DepsActions actions(bsci, task, this, depsPath);
1533     core::DependencyInfoParser(input->getBuffer(), actions).parse();
1534     return actions.numErrors == 0;
1535   }
1536 
1537 public:
1538   using ExternalCommand::ExternalCommand;
1539 
getShortDescription(SmallVectorImpl<char> & result)1540   virtual void getShortDescription(SmallVectorImpl<char> &result) override {
1541     llvm::raw_svector_ostream(result) << getDescription();
1542   }
1543 
getVerboseDescription(SmallVectorImpl<char> & result)1544   virtual void getVerboseDescription(SmallVectorImpl<char> &result) override {
1545     llvm::raw_svector_ostream os(result);
1546     bool first = true;
1547     for (const auto& arg: args) {
1548       if (!first) os << " ";
1549       first = false;
1550       basic::appendShellEscapedString(os, arg);
1551     }
1552   }
1553 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)1554   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1555                                   StringRef value) override {
1556     if (name == "args") {
1557       // When provided as a scalar string, we default to executing using the
1558       // shell.
1559       args.clear();
1560       args.push_back(ctx.getDelegate().getInternedString("/bin/sh"));
1561       args.push_back(ctx.getDelegate().getInternedString("-c"));
1562       args.push_back(ctx.getDelegate().getInternedString(value));
1563     } else if (name == "deps") {
1564       depsPaths.clear();
1565       depsPaths.emplace_back(value);
1566     } else if (name == "deps-style") {
1567       if (value == "makefile") {
1568         depsStyle = DepsStyle::Makefile;
1569       } else if (value == "dependency-info") {
1570         depsStyle = DepsStyle::DependencyInfo;
1571       } else {
1572         ctx.error("unknown 'deps-style': '" + value + "'");
1573         return false;
1574       }
1575       return true;
1576     } else if (name == "inherit-env") {
1577       if (value != "true" && value != "false") {
1578         ctx.error("invalid value: '" + value + "' for attribute '" +
1579                   name + "'");
1580         return false;
1581       }
1582       inheritEnv = value == "true";
1583     } else {
1584       return ExternalCommand::configureAttribute(ctx, name, value);
1585     }
1586 
1587     return true;
1588   }
1589 
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)1590   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1591                                   ArrayRef<StringRef> values) override {
1592     if (name == "args") {
1593       // Diagnose missing arguments.
1594       if (values.empty()) {
1595         ctx.error("invalid arguments for command '" + getName() + "'");
1596         return false;
1597       }
1598 
1599       args.clear();
1600       args.reserve(values.size());
1601       for (auto arg: values) {
1602         args.emplace_back(ctx.getDelegate().getInternedString(arg));
1603       }
1604     } else if (name == "deps") {
1605       depsPaths.clear();
1606       depsPaths.insert(depsPaths.begin(), values.begin(), values.end());
1607     } else {
1608       return ExternalCommand::configureAttribute(ctx, name, values);
1609     }
1610 
1611     return true;
1612   }
1613 
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)1614   virtual bool configureAttribute(
1615       const ConfigureContext& ctx, StringRef name,
1616       ArrayRef<std::pair<StringRef, StringRef>> values) override {
1617     if (name == "env") {
1618       env.clear();
1619       env.reserve(values.size());
1620       for (const auto& entry: values) {
1621         env.emplace_back(
1622             std::make_pair(
1623                 ctx.getDelegate().getInternedString(entry.first),
1624                 ctx.getDelegate().getInternedString(entry.second)));
1625       }
1626     } else {
1627       return ExternalCommand::configureAttribute(ctx, name, values);
1628     }
1629 
1630     return true;
1631   }
1632 
executeExternalCommand(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context)1633   virtual CommandResult executeExternalCommand(BuildSystemCommandInterface& bsci,
1634                                                Task* task,
1635                                                QueueJobContext* context) override {
1636     // Execute the command.
1637     auto result = bsci.getExecutionQueue().executeProcess(
1638         context, args,
1639         env, /*inheritEnvironment=*/inheritEnv);
1640 
1641     if (result != CommandResult::Succeeded) {
1642       // If the command failed, there is no need to gather dependencies.
1643       return result;
1644     }
1645 
1646     // Collect the discovered dependencies, if used.
1647     if (!depsPaths.empty()) {
1648       if (!processDiscoveredDependencies(bsci, task, context)) {
1649         // If we were unable to process the dependencies output, report a
1650         // failure.
1651         return CommandResult::Failed;
1652       }
1653     }
1654 
1655     return result;
1656   }
1657 };
1658 
1659 class ShellTool : public Tool {
1660 public:
1661   using Tool::Tool;
1662 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)1663   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1664                                   StringRef value) override {
1665     // No supported attributes.
1666     ctx.error("unexpected attribute: '" + name + "'");
1667     return false;
1668   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)1669   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1670                                   ArrayRef<StringRef> values) override {
1671     // No supported attributes.
1672     ctx.error("unexpected attribute: '" + name + "'");
1673     return false;
1674   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)1675   virtual bool configureAttribute(
1676       const ConfigureContext& ctx, StringRef name,
1677       ArrayRef<std::pair<StringRef, StringRef>> values) override {
1678     // No supported attributes.
1679     ctx.error("unexpected attribute: '" + name + "'");
1680     return false;
1681   }
1682 
createCommand(StringRef name)1683   virtual std::unique_ptr<Command> createCommand(StringRef name) override {
1684     return llvm::make_unique<ShellCommand>(name);
1685   }
1686 };
1687 
1688 #pragma mark - ClangTool implementation
1689 
1690 class ClangShellCommand : public ExternalCommand {
1691   /// The compiler command to invoke.
1692   std::vector<StringRef> args;
1693 
1694   /// The path to the dependency output file, if used.
1695   std::string depsPath;
1696 
getSignature()1697   virtual uint64_t getSignature() override {
1698     using llvm::hash_combine;
1699     llvm::hash_code code = ExternalCommand::getSignature();
1700     for (const auto& arg: args) {
1701       code = hash_combine(code, arg);
1702     }
1703     return size_t(code);
1704   }
1705 
processDiscoveredDependencies(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context)1706   bool processDiscoveredDependencies(BuildSystemCommandInterface& bsci,
1707                                      Task* task,
1708                                      QueueJobContext* context) {
1709     // Read the dependencies file.
1710     auto input = bsci.getDelegate().getFileSystem().getFileContents(depsPath);
1711     if (!input) {
1712       getBuildSystem(bsci.getBuildEngine()).error(
1713           depsPath, "unable to open dependencies file (" + depsPath + ")");
1714       return false;
1715     }
1716 
1717     // Parse the output.
1718     //
1719     // We just ignore the rule, and add any dependency that we encounter in the
1720     // file.
1721     struct DepsActions : public core::MakefileDepsParser::ParseActions {
1722       BuildSystemCommandInterface& bsci;
1723       Task* task;
1724       ClangShellCommand* command;
1725       unsigned numErrors{0};
1726 
1727       DepsActions(BuildSystemCommandInterface& bsci, Task* task,
1728                   ClangShellCommand* command)
1729           : bsci(bsci), task(task), command(command) {}
1730 
1731       virtual void error(const char* message, uint64_t position) override {
1732         getBuildSystem(bsci.getBuildEngine()).error(
1733             command->depsPath,
1734             "error reading dependency file: " + std::string(message));
1735         ++numErrors;
1736       }
1737 
1738       virtual void actOnRuleDependency(const char* dependency,
1739                                        uint64_t length,
1740                                        const StringRef unescapedWord) override {
1741         bsci.taskDiscoveredDependency(task, BuildKey::makeNode(unescapedWord));
1742       }
1743 
1744       virtual void actOnRuleStart(const char* name, uint64_t length,
1745                                   const StringRef unescapedWord) override {}
1746 
1747       virtual void actOnRuleEnd() override {}
1748     };
1749 
1750     DepsActions actions(bsci, task, this);
1751     core::MakefileDepsParser(input->getBufferStart(), input->getBufferSize(),
1752                              actions).parse();
1753     return actions.numErrors == 0;
1754   }
1755 
1756 public:
1757   using ExternalCommand::ExternalCommand;
1758 
getShortDescription(SmallVectorImpl<char> & result)1759   virtual void getShortDescription(SmallVectorImpl<char> &result) override {
1760     llvm::raw_svector_ostream(result) << getDescription();
1761   }
1762 
getVerboseDescription(SmallVectorImpl<char> & result)1763   virtual void getVerboseDescription(SmallVectorImpl<char> &result) override {
1764     llvm::raw_svector_ostream os(result);
1765     bool first = true;
1766     for (const auto& arg: args) {
1767       if (!first) os << " ";
1768       first = false;
1769       basic::appendShellEscapedString(os, arg);
1770     }
1771   }
1772 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)1773   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1774                                   StringRef value) override {
1775     if (name == "args") {
1776       // When provided as a scalar string, we default to executing using the
1777       // shell.
1778       args.clear();
1779       args.push_back(ctx.getDelegate().getInternedString("/bin/sh"));
1780       args.push_back(ctx.getDelegate().getInternedString("-c"));
1781       args.push_back(ctx.getDelegate().getInternedString(value));
1782     } else if (name == "deps") {
1783       depsPath = value;
1784     } else {
1785       return ExternalCommand::configureAttribute(ctx, name, value);
1786     }
1787 
1788     return true;
1789   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)1790   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1791                                   ArrayRef<StringRef> values) override {
1792     if (name == "args") {
1793       args.clear();
1794       args.reserve(values.size());
1795       for (auto arg: values) {
1796         args.emplace_back(ctx.getDelegate().getInternedString(arg));
1797       }
1798     } else {
1799         return ExternalCommand::configureAttribute(ctx, name, values);
1800     }
1801 
1802     return true;
1803   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)1804   virtual bool configureAttribute(
1805       const ConfigureContext& ctx, StringRef name,
1806       ArrayRef<std::pair<StringRef, StringRef>> values) override {
1807     return ExternalCommand::configureAttribute(ctx, name, values);
1808   }
1809 
executeExternalCommand(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context)1810   virtual CommandResult executeExternalCommand(BuildSystemCommandInterface& bsci,
1811                                                Task* task,
1812                                                QueueJobContext* context) override {
1813     // Execute the command.
1814     auto result = bsci.getExecutionQueue().executeProcess(context, args);
1815 
1816     if (result != CommandResult::Succeeded) {
1817       // If the command failed, there is no need to gather dependencies.
1818       return result;
1819     }
1820 
1821     // Otherwise, collect the discovered dependencies, if used.
1822     if (!depsPath.empty()) {
1823       if (!processDiscoveredDependencies(bsci, task, context)) {
1824         // If we were unable to process the dependencies output, report a
1825         // failure.
1826         return CommandResult::Failed;
1827       }
1828     }
1829 
1830     return result;
1831   }
1832 };
1833 
1834 class ClangTool : public Tool {
1835 public:
1836   using Tool::Tool;
1837 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)1838   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1839                                   StringRef value) override {
1840     // No supported attributes.
1841     ctx.error("unexpected attribute: '" + name + "'");
1842     return false;
1843   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)1844   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1845                                   ArrayRef<StringRef> values) override {
1846     // No supported attributes.
1847     ctx.error("unexpected attribute: '" + name + "'");
1848     return false;
1849   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)1850   virtual bool configureAttribute(
1851       const ConfigureContext& ctx, StringRef name,
1852       ArrayRef<std::pair<StringRef, StringRef>> values) override {
1853     // No supported attributes.
1854     ctx.error("unexpected attribute: '" + name + "'");
1855     return false;
1856   }
1857 
createCommand(StringRef name)1858   virtual std::unique_ptr<Command> createCommand(StringRef name) override {
1859     return llvm::make_unique<ClangShellCommand>(name);
1860   }
1861 };
1862 
1863 #pragma mark - MkdirTool implementation
1864 
1865 class MkdirCommand : public ExternalCommand {
getShortDescription(SmallVectorImpl<char> & result)1866   virtual void getShortDescription(SmallVectorImpl<char> &result) override {
1867     llvm::raw_svector_ostream(result) << getDescription();
1868   }
1869 
getVerboseDescription(SmallVectorImpl<char> & result)1870   virtual void getVerboseDescription(SmallVectorImpl<char> &result) override {
1871     llvm::raw_svector_ostream os(result);
1872     os << "mkdir -p ";
1873     // FIXME: This isn't correct, we need utilities for doing shell quoting.
1874     if (StringRef(getOutputs()[0]->getName()).find(' ') != StringRef::npos) {
1875       os << '"' << getOutputs()[0]->getName() << '"';
1876     } else {
1877       os << getOutputs()[0]->getName();
1878     }
1879   }
1880 
isResultValid(BuildSystem & system,const BuildValue & value)1881   virtual bool isResultValid(BuildSystem& system,
1882                              const BuildValue& value) override {
1883     // If the prior value wasn't for a successful command, recompute.
1884     if (!value.isSuccessfulCommand())
1885       return false;
1886 
1887     // Otherwise, the result is valid if the directory still exists.
1888     auto info = getOutputs()[0]->getFileInfo(
1889         system.getDelegate().getFileSystem());
1890     if (info.isMissing())
1891       return false;
1892 
1893     // If the item is not a directory, it needs to be recreated.
1894     if (!info.isDirectory())
1895       return false;
1896 
1897     // FIXME: We should strictly enforce the integrity of this validity routine
1898     // by ensuring that the build result for this command does not fully encode
1899     // the file info, but rather just encodes its success. As is, we are leaking
1900     // out the details of the file info (like the timestamp), but not rerunning
1901     // when they change. This is by design for this command, but it would still
1902     // be nice to be strict about it.
1903 
1904     return true;
1905   }
1906 
executeExternalCommand(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context)1907   virtual CommandResult executeExternalCommand(BuildSystemCommandInterface& bsci,
1908                                                Task* task,
1909                                                QueueJobContext* context) override {
1910     auto output = getOutputs()[0];
1911     if (!bsci.getDelegate().getFileSystem().createDirectories(
1912             output->getName())) {
1913       getBuildSystem(bsci.getBuildEngine()).error(
1914           "", "unable to create directory '" + output->getName() + "'");
1915       return CommandResult::Failed;
1916     }
1917     return CommandResult::Succeeded;
1918   }
1919 
1920 public:
1921   using ExternalCommand::ExternalCommand;
1922 };
1923 
1924 class MkdirTool : public Tool {
1925 public:
1926   using Tool::Tool;
1927 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)1928   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1929                                   StringRef value) override {
1930     // No supported attributes.
1931     ctx.error("unexpected attribute: '" + name + "'");
1932     return false;
1933   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)1934   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
1935                                   ArrayRef<StringRef> values) override {
1936     // No supported attributes.
1937     ctx.error("unexpected attribute: '" + name + "'");
1938     return false;
1939   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)1940   virtual bool configureAttribute(
1941       const ConfigureContext& ctx, StringRef name,
1942       ArrayRef<std::pair<StringRef, StringRef>> values) override {
1943     // No supported attributes.
1944     ctx.error("unexpected attribute: '" + name + "'");
1945     return false;
1946   }
1947 
createCommand(StringRef name)1948   virtual std::unique_ptr<Command> createCommand(StringRef name) override {
1949     return llvm::make_unique<MkdirCommand>(name);
1950   }
1951 };
1952 
1953 #pragma mark - SymlinkTool implementation
1954 
1955 class SymlinkCommand : public Command {
1956   /// The declared output node.
1957   BuildNode* output = nullptr;
1958 
1959   /// The path of the actual symbolic link to create, if different from the
1960   /// output node.
1961   std::string linkOutputPath;
1962 
1963   /// The command description.
1964   std::string description;
1965 
1966   /// Declared command inputs, used only for ordering purposes.
1967   std::vector<BuildNode*> inputs;
1968 
1969   /// The contents to write at the output path.
1970   std::string contents;
1971 
1972   /// Get the destination path.
getActualOutputPath() const1973   StringRef getActualOutputPath() const {
1974     return linkOutputPath.empty() ? output->getName() :
1975       StringRef(linkOutputPath);
1976   }
1977 
getSignature()1978   virtual uint64_t getSignature() {
1979     using llvm::hash_combine;
1980     llvm::hash_code code = hash_value(output->getName());
1981     code = hash_combine(code, contents);
1982     for (const auto* input: inputs) {
1983       code = hash_combine(code, input->getName());
1984     }
1985     return size_t(code);
1986   }
1987 
configureDescription(const ConfigureContext &,StringRef value)1988   virtual void configureDescription(const ConfigureContext&,
1989                                     StringRef value) override {
1990     description = value;
1991   }
1992 
getShortDescription(SmallVectorImpl<char> & result)1993   virtual void getShortDescription(SmallVectorImpl<char> &result) override {
1994     llvm::raw_svector_ostream(result) << description;
1995   }
1996 
getVerboseDescription(SmallVectorImpl<char> & result)1997   virtual void getVerboseDescription(SmallVectorImpl<char> &result) override {
1998     llvm::raw_svector_ostream os(result);
1999     os << "ln -sfh ";
2000     StringRef outputPath = getActualOutputPath();
2001     if (!output || !outputPath.empty()) {
2002       // FIXME: This isn't correct, we need utilities for doing shell quoting.
2003       if (outputPath.find(' ') != StringRef::npos) {
2004         os << '"' << outputPath << '"';
2005       } else {
2006         os << outputPath;
2007       }
2008     } else {
2009       os << "<<<missing output>>>";
2010     }
2011     os << ' ';
2012     // FIXME: This isn't correct, we need utilities for doing shell quoting.
2013     if (StringRef(contents).find(' ') != StringRef::npos) {
2014       os << '"' << contents << '"';
2015     } else {
2016       os << contents;
2017     }
2018   }
2019 
configureInputs(const ConfigureContext & ctx,const std::vector<Node * > & value)2020   virtual void configureInputs(const ConfigureContext& ctx,
2021                                const std::vector<Node*>& value) override {
2022     inputs.reserve(value.size());
2023     for (auto* node: value) {
2024       inputs.emplace_back(static_cast<BuildNode*>(node));
2025     }
2026   }
2027 
configureOutputs(const ConfigureContext & ctx,const std::vector<Node * > & value)2028   virtual void configureOutputs(const ConfigureContext& ctx,
2029                                 const std::vector<Node*>& value) override {
2030     if (value.size() == 1) {
2031       output = static_cast<BuildNode*>(value[0]);
2032     } else if (value.empty()) {
2033       ctx.error("missing declared output");
2034     } else {
2035       ctx.error("unexpected explicit output: '" + value[1]->getName() + "'");
2036     }
2037   }
2038 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)2039   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2040                                   StringRef value) override {
2041     if (name == "contents") {
2042       contents = value;
2043       return true;
2044     } else if (name == "link-output-path") {
2045       linkOutputPath = value;
2046       return true;
2047     } else {
2048       ctx.error("unexpected attribute: '" + name + "'");
2049       return false;
2050     }
2051   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)2052   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2053                                   ArrayRef<StringRef> values) override {
2054     // No supported attributes.
2055     ctx.error("unexpected attribute: '" + name + "'");
2056     return false;
2057   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)2058   virtual bool configureAttribute(
2059       const ConfigureContext& ctx, StringRef name,
2060       ArrayRef<std::pair<StringRef, StringRef>> values) override {
2061     // No supported attributes.
2062     ctx.error("unexpected attribute: '" + name + "'");
2063     return false;
2064   }
2065 
getResultForOutput(Node * node,const BuildValue & value)2066   virtual BuildValue getResultForOutput(Node* node,
2067                                         const BuildValue& value) override {
2068     // If the value was a failed command, propagate the failure.
2069     if (value.isFailedCommand() || value.isPropagatedFailureCommand() ||
2070         value.isCancelledCommand())
2071       return BuildValue::makeFailedInput();
2072     if (value.isSkippedCommand())
2073       return BuildValue::makeSkippedCommand();
2074 
2075     // Otherwise, we should have a successful command -- return the actual
2076     // result for the output.
2077     assert(value.isSuccessfulCommand());
2078 
2079     auto info = value.getOutputInfo();
2080     if (info.isMissing())
2081         return BuildValue::makeMissingOutput();
2082     return BuildValue::makeExistingInput(info);
2083   }
2084 
isResultValid(BuildSystem & system,const BuildValue & value)2085   virtual bool isResultValid(BuildSystem& system,
2086                              const BuildValue& value) override {
2087     // It is an error if this command isn't configured properly.
2088     StringRef outputPath = getActualOutputPath();
2089     if (!output || outputPath.empty())
2090       return false;
2091 
2092     // If the prior value wasn't for a successful command, recompute.
2093     if (!value.isSuccessfulCommand())
2094       return false;
2095 
2096     // If the command's signature has changed since it was built, rebuild.
2097     if (value.getCommandSignature() != getSignature())
2098       return false;
2099 
2100     // If the prior command doesn't look like one for a link, recompute.
2101     if (value.getNumOutputs() != 1)
2102       return false;
2103 
2104     // Otherwise, assume the result is valid if its link status matches the
2105     // previous one.
2106     auto info = system.getDelegate().getFileSystem().getLinkInfo(outputPath);
2107     if (info.isMissing())
2108       return false;
2109 
2110     return info == value.getOutputInfo();
2111   }
2112 
start(BuildSystemCommandInterface & bsci,core::Task * task)2113   virtual void start(BuildSystemCommandInterface& bsci,
2114                      core::Task* task) override {
2115     // The command itself takes no inputs, so just treat any declared inputs as
2116     // "must follow" directives.
2117     //
2118     // FIXME: We should make this explicit once we have actual support for must
2119     // follow inputs.
2120     for (auto it = inputs.begin(), ie = inputs.end(); it != ie; ++it) {
2121       bsci.taskMustFollow(task, BuildKey::makeNode(*it));
2122     }
2123   }
2124 
providePriorValue(BuildSystemCommandInterface &,core::Task *,const BuildValue & value)2125   virtual void providePriorValue(BuildSystemCommandInterface&, core::Task*,
2126                                  const BuildValue& value) override {
2127     // Ignored.
2128   }
2129 
provideValue(BuildSystemCommandInterface &,core::Task *,uintptr_t inputID,const BuildValue & value)2130   virtual void provideValue(BuildSystemCommandInterface&, core::Task*,
2131                             uintptr_t inputID,
2132                             const BuildValue& value) override {
2133     assert(0 && "unexpected API call");
2134   }
2135 
execute(BuildSystemCommandInterface & bsci,core::Task * task,QueueJobContext * context)2136   virtual BuildValue execute(BuildSystemCommandInterface& bsci,
2137                              core::Task* task,
2138                              QueueJobContext* context) override {
2139     // It is an error if this command isn't configured properly.
2140     StringRef outputPath = getActualOutputPath();
2141     if (!output || outputPath.empty()) {
2142       return BuildValue::makeFailedCommand();
2143     }
2144 
2145     // Create the directory containing the symlink, if necessary.
2146     //
2147     // FIXME: Shared behavior with ExternalCommand.
2148     {
2149       auto parent = llvm::sys::path::parent_path(outputPath);
2150       if (!parent.empty()) {
2151         (void) bsci.getDelegate().getFileSystem().createDirectories(parent);
2152       }
2153     }
2154 
2155     // Create the symbolic link (note that despite the poorly chosen LLVM
2156     // name, this is a symlink).
2157     //
2158     // FIXME: Need to use the filesystem interfaces.
2159     bsci.getDelegate().commandStarted(this);
2160     auto success = true;
2161     if (llvm::sys::fs::create_link(contents, outputPath)) {
2162       // On failure, we attempt to unlink the file and retry.
2163       basic::sys::unlink(outputPath.str().c_str());
2164 
2165       if (llvm::sys::fs::create_link(contents, outputPath)) {
2166         getBuildSystem(bsci.getBuildEngine()).error(
2167             "", "unable to create symlink at '" + outputPath + "'");
2168         success = false;
2169       }
2170     }
2171     bsci.getDelegate().commandFinished(this, success ? CommandResult::Succeeded : CommandResult::Failed);
2172 
2173     // Process the result.
2174     if (!success) {
2175       return BuildValue::makeFailedCommand();
2176     }
2177 
2178     // Capture the *link* information of the output.
2179     FileInfo outputInfo = bsci.getDelegate().getFileSystem().getLinkInfo(
2180         outputPath);
2181 
2182     // Complete with a successful result.
2183     return BuildValue::makeSuccessfulCommand(outputInfo, getSignature());
2184   }
2185 
2186 public:
2187   using Command::Command;
2188 };
2189 
2190 class SymlinkTool : public Tool {
2191 public:
2192   using Tool::Tool;
2193 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)2194   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2195                                   StringRef value) override {
2196     // No supported attributes.
2197     ctx.error("unexpected attribute: '" + name + "'");
2198     return false;
2199   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)2200   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2201                                   ArrayRef<StringRef> values) override {
2202     // No supported attributes.
2203     ctx.error("unexpected attribute: '" + name + "'");
2204     return false;
2205   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)2206   virtual bool configureAttribute(
2207       const ConfigureContext& ctx, StringRef name,
2208       ArrayRef<std::pair<StringRef, StringRef>> values) override {
2209     // No supported attributes.
2210     ctx.error("unexpected attribute: '" + name + "'");
2211     return false;
2212   }
2213 
createCommand(StringRef name)2214   virtual std::unique_ptr<Command> createCommand(StringRef name) override {
2215     return llvm::make_unique<SymlinkCommand>(name);
2216   }
2217 };
2218 
2219 #pragma mark - ArchiveTool implementation
2220 
2221 class ArchiveShellCommand : public ExternalCommand {
2222 
2223   std::string archiveName;
2224   std::vector<std::string> archiveInputs;
2225 
executeExternalCommand(BuildSystemCommandInterface & bsci,Task * task,QueueJobContext * context)2226   virtual CommandResult executeExternalCommand(BuildSystemCommandInterface& bsci,
2227                                                Task* task,
2228                                                QueueJobContext* context) override {
2229     // First delete the current archive
2230     // TODO instead insert, update and remove files from the archive
2231     if (llvm::sys::fs::remove(archiveName, /*IgnoreNonExisting*/ true)) {
2232       return CommandResult::Failed;
2233     }
2234 
2235     // Create archive
2236     auto args = getArgs();
2237     return bsci.getExecutionQueue().executeProcess(
2238         context, std::vector<StringRef>(args.begin(), args.end()));
2239   }
2240 
getShortDescription(SmallVectorImpl<char> & result)2241   virtual void getShortDescription(SmallVectorImpl<char> &result) override {
2242     if (getDescription().empty()) {
2243       llvm::raw_svector_ostream(result) << "Archiving " + archiveName;
2244     } else {
2245       llvm::raw_svector_ostream(result) << getDescription();
2246     }
2247   }
2248 
getVerboseDescription(SmallVectorImpl<char> & result)2249   virtual void getVerboseDescription(SmallVectorImpl<char> &result) override {
2250     llvm::raw_svector_ostream stream(result);
2251     bool first = true;
2252     for (const auto& arg: getArgs()) {
2253       stream << arg;
2254       if (!first) {
2255         stream << " ";
2256         first = false;
2257       }
2258     }
2259   }
2260 
configureInputs(const ConfigureContext & ctx,const std::vector<Node * > & value)2261   virtual void configureInputs(const ConfigureContext& ctx,
2262                                 const std::vector<Node*>& value) override {
2263     ExternalCommand::configureInputs(ctx, value);
2264 
2265     for (const auto& input: getInputs()) {
2266       if (!input->isVirtual()) {
2267         archiveInputs.push_back(input->getName());
2268       }
2269     }
2270     if (archiveInputs.empty()) {
2271       ctx.error("missing expected input");
2272     }
2273   }
2274 
configureOutputs(const ConfigureContext & ctx,const std::vector<Node * > & value)2275   virtual void configureOutputs(const ConfigureContext& ctx,
2276                                 const std::vector<Node*>& value) override {
2277     ExternalCommand::configureOutputs(ctx, value);
2278 
2279     for (const auto& output: getOutputs()) {
2280       if (!output->isVirtual()) {
2281         if (archiveName.empty()) {
2282           archiveName = output->getName();
2283         } else {
2284           ctx.error("unexpected explicit output: " + output->getName());
2285         }
2286       }
2287     }
2288     if (archiveName.empty()) {
2289       ctx.error("missing expected output");
2290     }
2291   }
2292 
getArgs()2293   std::vector<std::string> getArgs() {
2294     std::vector<std::string> args;
2295     args.push_back("ar");
2296     args.push_back("cr");
2297     args.push_back(archiveName);
2298     args.insert(args.end(), archiveInputs.begin(), archiveInputs.end());
2299     return args;
2300   }
2301 
2302 public:
2303   using ExternalCommand::ExternalCommand;
2304 };
2305 
2306 class ArchiveTool : public Tool {
2307 public:
2308   using Tool::Tool;
2309 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)2310   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2311                                   StringRef value) override {
2312     // No supported attributes.
2313     ctx.error("unexpected attribute: '" + name + "'");
2314     return false;
2315   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)2316   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2317                                   ArrayRef<StringRef> values) override {
2318     // No supported attributes.
2319     ctx.error("unexpected attribute: '" + name + "'");
2320     return false;
2321   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)2322   virtual bool configureAttribute(
2323       const ConfigureContext& ctx, StringRef name,
2324       ArrayRef<std::pair<StringRef, StringRef>> values) override {
2325     // No supported attributes.
2326     ctx.error("unexpected attribute: '" + name + "'");
2327     return false;
2328   }
2329 
createCommand(StringRef name)2330   virtual std::unique_ptr<Command> createCommand(StringRef name) override {
2331     return llvm::make_unique<ArchiveShellCommand>(name);
2332   }
2333 };
2334 
2335 #pragma mark - StaleFileRemovalTool implementation
2336 
2337 class StaleFileRemovalCommand : public Command {
2338   std::string description;
2339 
2340   std::vector<std::string> expectedOutputs;
2341   std::vector<std::string> filesToDelete;
2342   std::vector<std::string> roots;
2343   bool computedFilesToDelete = false;
2344 
2345   BuildValue priorValue;
2346   bool hasPriorResult = false;
2347 
2348   char path_separator = llvm::sys::path::get_separator()[0];
2349 
configureDescription(const ConfigureContext &,StringRef value)2350   virtual void configureDescription(const ConfigureContext&, StringRef value) override {
2351     description = value;
2352   }
2353 
getShortDescription(SmallVectorImpl<char> & result)2354   virtual void getShortDescription(SmallVectorImpl<char> &result) override {
2355     llvm::raw_svector_ostream(result) << (description.empty() ? "Stale file removal" : description);
2356   }
2357 
getVerboseDescription(SmallVectorImpl<char> & result)2358   virtual void getVerboseDescription(SmallVectorImpl<char> &result) override {
2359     computeFilesToDelete();
2360 
2361     getShortDescription(result);
2362     llvm::raw_svector_ostream(result) << ", stale files: [";
2363     for (auto fileToDelete : filesToDelete) {
2364       llvm::raw_svector_ostream(result) << fileToDelete;
2365       if (fileToDelete != *(--filesToDelete.end())) {
2366         llvm::raw_svector_ostream(result) << ", ";
2367       }
2368     }
2369     llvm::raw_svector_ostream(result) << "], roots: [";
2370     for (auto root : roots) {
2371       llvm::raw_svector_ostream(result) << root;
2372       if (root != *(--roots.end())) {
2373         llvm::raw_svector_ostream(result) << ", ";
2374       }
2375     }
2376     llvm::raw_svector_ostream(result) << "]";
2377   }
2378 
configureInputs(const ConfigureContext & ctx,const std::vector<Node * > & value)2379   virtual void configureInputs(const ConfigureContext& ctx,
2380                                const std::vector<Node*>& value) override {}
2381 
configureOutputs(const ConfigureContext & ctx,const std::vector<Node * > & value)2382   virtual void configureOutputs(const ConfigureContext& ctx,
2383                                 const std::vector<Node*>& value) override {}
2384 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)2385   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2386                                   StringRef value) override {
2387     // No supported attributes.
2388     ctx.error("unexpected attribute: '" + name + "'");
2389     return false;
2390   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)2391   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2392                                   ArrayRef<StringRef> values) override {
2393     if (name == "expectedOutputs") {
2394       expectedOutputs.reserve(values.size());
2395       for (auto value : values) {
2396         expectedOutputs.emplace_back(value.str());
2397       }
2398       return true;
2399     } else if (name == "roots") {
2400       roots.reserve(values.size());
2401       for (auto value : values) {
2402         roots.emplace_back(value.str());
2403       }
2404       return true;
2405     }
2406 
2407     ctx.error("unexpected attribute: '" + name + "'");
2408     return false;
2409   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)2410   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2411                                   ArrayRef<std::pair<StringRef, StringRef>> values) override {
2412     // No supported attributes.
2413     ctx.error("unexpected attribute: '" + name + "'");
2414     return false;
2415   }
2416 
getResultForOutput(Node * node,const BuildValue & value)2417   virtual BuildValue getResultForOutput(Node* node,
2418                                         const BuildValue& value) override {
2419     // If the value was a failed command, propagate the failure.
2420     if (value.isFailedCommand() || value.isPropagatedFailureCommand() ||
2421         value.isCancelledCommand())
2422       return BuildValue::makeFailedInput();
2423     if (value.isSkippedCommand())
2424       return BuildValue::makeSkippedCommand();
2425 
2426     // Otherwise, this was successful, return the value as-is.
2427     return BuildValue::fromData(value.toData());;
2428   }
2429 
isResultValid(BuildSystem & system,const BuildValue & value)2430   virtual bool isResultValid(BuildSystem& system,
2431                              const BuildValue& value) override {
2432     // Always re-run stale file removal.
2433     return false;
2434   }
2435 
start(BuildSystemCommandInterface & bsci,core::Task * task)2436   virtual void start(BuildSystemCommandInterface& bsci,
2437                      core::Task* task) override {}
2438 
providePriorValue(BuildSystemCommandInterface &,core::Task *,const BuildValue & value)2439   virtual void providePriorValue(BuildSystemCommandInterface&, core::Task*,
2440                                  const BuildValue& value) override {
2441     hasPriorResult = true;
2442     priorValue = BuildValue::fromData(value.toData());
2443   }
2444 
provideValue(BuildSystemCommandInterface &,core::Task *,uintptr_t inputID,const BuildValue & value)2445   virtual void provideValue(BuildSystemCommandInterface&, core::Task*,
2446                             uintptr_t inputID,
2447                             const BuildValue& value) override {
2448     assert(0 && "unexpected API call");
2449   }
2450 
computeFilesToDelete()2451   void computeFilesToDelete() {
2452     if (computedFilesToDelete) {
2453       return;
2454     }
2455 
2456     std::vector<StringRef> priorValueList = priorValue.getStaleFileList();
2457     std::set<std::string> priorNodes(priorValueList.begin(), priorValueList.end());
2458     std::set<std::string> expectedNodes(expectedOutputs.begin(), expectedOutputs.end());
2459 
2460     std::set_difference(priorNodes.begin(), priorNodes.end(),
2461                         expectedNodes.begin(), expectedNodes.end(),
2462                         std::back_inserter(filesToDelete));
2463 
2464     computedFilesToDelete = true;
2465   }
2466 
execute(BuildSystemCommandInterface & bsci,core::Task * task,QueueJobContext * context)2467   virtual BuildValue execute(BuildSystemCommandInterface& bsci,
2468                              core::Task* task,
2469                              QueueJobContext* context) override {
2470     // Nothing to do if we do not have a prior result.
2471     if (!hasPriorResult || !priorValue.isStaleFileRemoval()) {
2472       bsci.getDelegate().commandStarted(this);
2473       bsci.getDelegate().commandFinished(this, CommandResult::Succeeded);
2474       return BuildValue::makeStaleFileRemoval(expectedOutputs);
2475     }
2476 
2477     computeFilesToDelete();
2478 
2479     bsci.getDelegate().commandStarted(this);
2480 
2481     for (auto fileToDelete : filesToDelete) {
2482       // If no root paths are specified, any path is valid.
2483       bool isLocatedUnderRootPath = roots.size() == 0 ? true : false;
2484 
2485       // If root paths are defined, stale file paths should be absolute.
2486       if (roots.size() > 0 && fileToDelete[0] != path_separator) {
2487         bsci.getDelegate().commandHadWarning(this, "Stale file '" + fileToDelete + "' has a relative path. This is invalid in combination with the root path attribute.\n");
2488         continue;
2489       }
2490 
2491       // Check if the file is located under one of the allowed root paths.
2492       for (auto root : roots) {
2493         if (pathIsPrefixedByPath(fileToDelete, root)) {
2494           isLocatedUnderRootPath = true;
2495         }
2496       }
2497 
2498       if (!isLocatedUnderRootPath) {
2499         bsci.getDelegate().commandHadWarning(this, "Stale file '" + fileToDelete + "' is located outside of the allowed root paths.\n");
2500         continue;
2501       }
2502 
2503       if (getBuildSystem(bsci.getBuildEngine()).getDelegate().getFileSystem().remove(fileToDelete)) {
2504         bsci.getDelegate().commandHadNote(this, "Removed stale file '" + fileToDelete + "'\n");
2505       } else {
2506         bsci.getDelegate().commandHadWarning(this, "cannot remove stale file '" + fileToDelete + "': " + strerror(errno) + "\n");
2507       }
2508     }
2509 
2510     bsci.getDelegate().commandFinished(this, CommandResult::Succeeded);
2511 
2512     // Complete with a successful result.
2513     return BuildValue::makeStaleFileRemoval(expectedOutputs);
2514   }
2515 
2516 public:
StaleFileRemovalCommand(const StringRef name)2517   StaleFileRemovalCommand(const StringRef name)
2518   : Command(name), priorValue(BuildValue::makeInvalid()) {}
2519 };
2520 
2521 class StaleFileRemovalTool : public Tool {
2522 public:
2523   using Tool::Tool;
2524 
configureAttribute(const ConfigureContext & ctx,StringRef name,StringRef value)2525   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2526                                   StringRef value) override {
2527     // No supported attributes.
2528     ctx.error("unexpected attribute: '" + name + "'");
2529     return false;
2530   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<StringRef> values)2531   virtual bool configureAttribute(const ConfigureContext& ctx, StringRef name,
2532                                   ArrayRef<StringRef> values) override {
2533     // No supported attributes.
2534     ctx.error("unexpected attribute: '" + name + "'");
2535     return false;
2536   }
configureAttribute(const ConfigureContext & ctx,StringRef name,ArrayRef<std::pair<StringRef,StringRef>> values)2537   virtual bool configureAttribute(
2538                                   const ConfigureContext& ctx, StringRef name,
2539                                   ArrayRef<std::pair<StringRef, StringRef>> values) override {
2540     // No supported attributes.
2541     ctx.error("unexpected attribute: '" + name + "'");
2542     return false;
2543   }
2544 
createCommand(StringRef name)2545   virtual std::unique_ptr<Command> createCommand(StringRef name) override {
2546     return llvm::make_unique<StaleFileRemovalCommand>(name);
2547   }
2548 };
2549 
2550 #pragma mark - BuildSystemFileDelegate
2551 
getSystemDelegate()2552 BuildSystemDelegate& BuildSystemFileDelegate::getSystemDelegate() {
2553   return system.getDelegate();
2554 }
2555 
setFileContentsBeingParsed(StringRef buffer)2556 void BuildSystemFileDelegate::setFileContentsBeingParsed(StringRef buffer) {
2557   getSystemDelegate().setFileContentsBeingParsed(buffer);
2558 }
2559 
error(StringRef filename,const BuildFileToken & at,const Twine & message)2560 void BuildSystemFileDelegate::error(StringRef filename,
2561                                     const BuildFileToken& at,
2562                                     const Twine& message) {
2563   // Delegate to the system delegate.
2564   auto atSystemToken = BuildSystemDelegate::Token{at.start, at.length};
2565   system.error(filename, atSystemToken, message);
2566 }
2567 
2568 bool
configureClient(const ConfigureContext &,StringRef name,uint32_t version,const property_list_type & properties)2569 BuildSystemFileDelegate::configureClient(const ConfigureContext&,
2570                                          StringRef name,
2571                                          uint32_t version,
2572                                          const property_list_type& properties) {
2573   // The client must match the configured name of the build system.
2574   if (name != getSystemDelegate().getName())
2575     return false;
2576 
2577   // The client version must match the configured version.
2578   //
2579   // FIXME: We should give the client the opportunity to support a previous
2580   // schema version (auto-upgrade).
2581   if (version != getSystemDelegate().getVersion())
2582     return false;
2583 
2584   return true;
2585 }
2586 
2587 std::unique_ptr<Tool>
lookupTool(StringRef name)2588 BuildSystemFileDelegate::lookupTool(StringRef name) {
2589   // First, give the client an opportunity to create the tool.
2590   if (auto tool = getSystemDelegate().lookupTool(name)) {
2591     return tool;
2592   }
2593 
2594   // Otherwise, look for one of the builtin tool definitions.
2595   if (name == "shell") {
2596     return llvm::make_unique<ShellTool>(name);
2597   } else if (name == "phony") {
2598     return llvm::make_unique<PhonyTool>(name);
2599   } else if (name == "clang") {
2600     return llvm::make_unique<ClangTool>(name);
2601   } else if (name == "mkdir") {
2602     return llvm::make_unique<MkdirTool>(name);
2603   } else if (name == "symlink") {
2604     return llvm::make_unique<SymlinkTool>(name);
2605   } else if (name == "archive") {
2606     return llvm::make_unique<ArchiveTool>(name);
2607   } else if (name == "stale-file-removal") {
2608     return llvm::make_unique<StaleFileRemovalTool>(name);
2609   }
2610 
2611   return nullptr;
2612 }
2613 
loadedTarget(StringRef name,const Target & target)2614 void BuildSystemFileDelegate::loadedTarget(StringRef name,
2615                                            const Target& target) {
2616 }
2617 
loadedDefaultTarget(StringRef target)2618 void BuildSystemFileDelegate::loadedDefaultTarget(StringRef target) {
2619 }
2620 
loadedCommand(StringRef name,const Command & command)2621 void BuildSystemFileDelegate::loadedCommand(StringRef name,
2622                                             const Command& command) {
2623 }
2624 
2625 std::unique_ptr<Node>
lookupNode(StringRef name,bool isImplicit)2626 BuildSystemFileDelegate::lookupNode(StringRef name,
2627                                     bool isImplicit) {
2628   return system.lookupNode(name, isImplicit);
2629 }
2630 
2631 }
2632 
2633 #pragma mark - BuildSystem
2634 
BuildSystem(BuildSystemDelegate & delegate)2635 BuildSystem::BuildSystem(BuildSystemDelegate& delegate)
2636     : impl(new BuildSystemImpl(*this, delegate))
2637 {
2638 }
2639 
~BuildSystem()2640 BuildSystem::~BuildSystem() {
2641   delete static_cast<BuildSystemImpl*>(impl);
2642 }
2643 
getDelegate()2644 BuildSystemDelegate& BuildSystem::getDelegate() {
2645   return static_cast<BuildSystemImpl*>(impl)->getDelegate();
2646 }
2647 
loadDescription(StringRef mainFilename)2648 bool BuildSystem::loadDescription(StringRef mainFilename) {
2649   return static_cast<BuildSystemImpl*>(impl)->loadDescription(mainFilename);
2650 }
2651 
loadDescription(std::unique_ptr<BuildDescription> description)2652 void BuildSystem::loadDescription(
2653     std::unique_ptr<BuildDescription> description) {
2654   return static_cast<BuildSystemImpl*>(impl)->loadDescription(
2655       std::move(description));
2656 }
2657 
attachDB(StringRef path,std::string * error_out)2658 bool BuildSystem::attachDB(StringRef path,
2659                                 std::string* error_out) {
2660   return static_cast<BuildSystemImpl*>(impl)->attachDB(path, error_out);
2661 }
2662 
enableTracing(StringRef path,std::string * error_out)2663 bool BuildSystem::enableTracing(StringRef path,
2664                                 std::string* error_out) {
2665   return static_cast<BuildSystemImpl*>(impl)->enableTracing(path, error_out);
2666 }
2667 
build(BuildKey key)2668 llvm::Optional<BuildValue> BuildSystem::build(BuildKey key) {
2669   return static_cast<BuildSystemImpl*>(impl)->build(key);
2670 }
2671 
build(StringRef name)2672 bool BuildSystem::build(StringRef name) {
2673   return static_cast<BuildSystemImpl*>(impl)->build(name);
2674 }
2675 
cancel()2676 void BuildSystem::cancel() {
2677   if (impl) {
2678     static_cast<BuildSystemImpl*>(impl)->cancel();
2679   }
2680 }
2681 
resetForBuild()2682 void BuildSystem::resetForBuild() {
2683   static_cast<BuildSystemImpl*>(impl)->resetForBuild();
2684 }
2685 
2686 // This function checks if the given path is prefixed by another path.
pathIsPrefixedByPath(std::string path,std::string prefixPath)2687 bool llbuild::buildsystem::pathIsPrefixedByPath(std::string path, std::string prefixPath) {
2688   static char path_separator = llvm::sys::path::get_separator()[0];
2689   auto res = std::mismatch(prefixPath.begin(), prefixPath.end(), path.begin());
2690   // Check if `prefixPath` has been exhausted or just a separator remains.
2691   bool isPrefix = res.first == prefixPath.end() || (*(res.first++) == path_separator);
2692   // Check if `path` has been exhausted or just a separator remains.
2693   return isPrefix && (res.second == path.end() || (*(res.second++) == path_separator));
2694 }
2695