1 //===-- BuildSystemFrontend.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/BuildSystemFrontend.h"
14
15 #include "llbuild/Basic/FileSystem.h"
16 #include "llbuild/Basic/LLVM.h"
17 #include "llbuild/Basic/PlatformUtility.h"
18 #include "llbuild/BuildSystem/BuildDescription.h"
19 #include "llbuild/BuildSystem/BuildExecutionQueue.h"
20 #include "llbuild/BuildSystem/BuildFile.h"
21 #include "llbuild/BuildSystem/BuildKey.h"
22
23 #include "llvm/ADT/DenseMap.h"
24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/Support/Format.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/SourceMgr.h"
28 #include "llvm/Support/raw_ostream.h"
29
30 #include <atomic>
31 #include <memory>
32 #include <mutex>
33 #include <thread>
34
35 using namespace llbuild;
36 using namespace llbuild::basic;
37 using namespace llbuild::buildsystem;
38
39 #pragma mark - BuildSystemInvocation implementation
40
getUsage(int optionWidth,raw_ostream & os)41 void BuildSystemInvocation::getUsage(int optionWidth, raw_ostream& os) {
42 const struct Options {
43 llvm::StringRef option, helpText;
44 } options[] = {
45 { "--help", "show this help message and exit" },
46 { "--version", "show the tool version" },
47 { "-C <PATH>, --chdir <PATH>", "change directory to PATH before building" },
48 { "--no-db", "disable use of a build database" },
49 { "--db <PATH>", "enable building against the database at PATH" },
50 { "-f <PATH>", "load the build task file at PATH" },
51 { "--serial", "do not build in parallel" },
52 { "-v, --verbose", "show verbose status information" },
53 { "--trace <PATH>", "trace build engine operation to PATH" },
54 };
55
56 for (const auto& entry: options) {
57 os << " " << llvm::format("%-*s", optionWidth, entry.option) << " "
58 << entry.helpText << "\n";
59 }
60 }
61
parse(llvm::ArrayRef<std::string> args,llvm::SourceMgr & sourceMgr)62 void BuildSystemInvocation::parse(llvm::ArrayRef<std::string> args,
63 llvm::SourceMgr& sourceMgr) {
64 auto error = [&](const Twine &message) {
65 sourceMgr.PrintMessage(llvm::SMLoc{}, llvm::SourceMgr::DK_Error, message);
66 hadErrors = true;
67 };
68
69 while (!args.empty()) {
70 const auto& option = args.front();
71 args = args.slice(1);
72
73 if (option == "-") {
74 for (const auto& arg: args) {
75 positionalArgs.push_back(arg);
76 }
77 break;
78 }
79
80 if (!option.empty() && option[0] != '-') {
81 positionalArgs.push_back(option);
82 continue;
83 }
84
85 if (option == "--help") {
86 showUsage = true;
87 break;
88 } else if (option == "--version") {
89 showVersion = true;
90 break;
91 } else if (option == "--no-db") {
92 dbPath = "";
93 } else if (option == "--db") {
94 if (args.empty()) {
95 error("missing argument to '" + option + "'");
96 break;
97 }
98 dbPath = args[0];
99 args = args.slice(1);
100 } else if (option == "-C" || option == "--chdir") {
101 if (args.empty()) {
102 error("missing argument to '" + option + "'");
103 break;
104 }
105 chdirPath = args[0];
106 args = args.slice(1);
107 } else if (option == "-f") {
108 if (args.empty()) {
109 error("missing argument to '" + option + "'");
110 break;
111 }
112 buildFilePath = args[0];
113 args = args.slice(1);
114 } else if (option == "--serial") {
115 useSerialBuild = true;
116 } else if (option == "-v" || option == "--verbose") {
117 showVerboseStatus = true;
118 } else if (option == "--trace") {
119 if (args.empty()) {
120 error("missing argument to '" + option + "'");
121 break;
122 }
123 traceFilePath = args[0];
124 args = args.slice(1);
125 } else {
126 error("invalid option '" + option + "'");
127 break;
128 }
129 }
130 }
131
formatDetectedCycle(const std::vector<core::Rule * > & cycle)132 std::string BuildSystemInvocation::formatDetectedCycle(const std::vector<core::Rule*>& cycle) {
133 // Compute a description of the cycle path.
134 SmallString<256> message;
135 llvm::raw_svector_ostream os(message);
136 os << "cycle detected while building: ";
137 bool first = true;
138 for (const auto* rule: cycle) {
139 if (!first)
140 os << " -> ";
141
142 // Convert to a build key.
143 auto key = BuildKey::fromData(rule->key);
144 switch (key.getKind()) {
145 case BuildKey::Kind::Unknown:
146 os << "((unknown))";
147 break;
148 case BuildKey::Kind::Command:
149 os << "command '" << key.getCommandName() << "'";
150 break;
151 case BuildKey::Kind::CustomTask:
152 os << "custom task '" << key.getCustomTaskName() << "'";
153 break;
154 case BuildKey::Kind::DirectoryContents:
155 os << "directory-contents '" << key.getDirectoryContentsPath() << "'";
156 break;
157 case BuildKey::Kind::DirectoryTreeSignature:
158 os << "directory-tree-signature '"
159 << key.getDirectoryTreeSignaturePath() << "'";
160 break;
161 case BuildKey::Kind::Node:
162 os << "node '" << key.getNodeName() << "'";
163 break;
164 case BuildKey::Kind::Target:
165 os << "target '" << key.getTargetName() << "'";
166 break;
167 }
168 first = false;
169 }
170
171 return os.str().str();
172 }
173
174 #pragma mark - BuildSystemFrontendDelegate implementation
175
176 namespace {
177
178 struct BuildSystemFrontendDelegateImpl;
179
180 class BuildSystemFrontendExecutionQueueDelegate
181 : public BuildExecutionQueueDelegate {
182 BuildSystemFrontendDelegateImpl &delegateImpl;
183
184 bool showVerboseOutput() const;
185
186 BuildSystem& getSystem() const;
187
188 public:
BuildSystemFrontendExecutionQueueDelegate(BuildSystemFrontendDelegateImpl & delegateImpl)189 BuildSystemFrontendExecutionQueueDelegate(
190 BuildSystemFrontendDelegateImpl& delegateImpl)
191 : delegateImpl(delegateImpl) { }
192
commandJobStarted(Command * command)193 virtual void commandJobStarted(Command* command) override {
194 static_cast<BuildSystemFrontendDelegate*>(&getSystem().getDelegate())->
195 commandJobStarted(command);
196 }
197
commandJobFinished(Command * command)198 virtual void commandJobFinished(Command* command) override {
199 static_cast<BuildSystemFrontendDelegate*>(&getSystem().getDelegate())->
200 commandJobFinished(command);
201 }
202
commandProcessStarted(Command * command,ProcessHandle handle)203 virtual void commandProcessStarted(Command* command,
204 ProcessHandle handle) override {
205 static_cast<BuildSystemFrontendDelegate*>(&getSystem().getDelegate())->
206 commandProcessStarted(
207 command, BuildSystemFrontendDelegate::ProcessHandle { handle.id });
208 }
209
commandProcessHadError(Command * command,ProcessHandle handle,const Twine & message)210 virtual void commandProcessHadError(Command* command, ProcessHandle handle,
211 const Twine& message) override {
212 static_cast<BuildSystemFrontendDelegate*>(&getSystem().getDelegate())->
213 commandProcessHadError(
214 command, BuildSystemFrontendDelegate::ProcessHandle { handle.id },
215 message);
216 }
217
commandProcessHadOutput(Command * command,ProcessHandle handle,StringRef data)218 virtual void commandProcessHadOutput(Command* command, ProcessHandle handle,
219 StringRef data) override {
220 static_cast<BuildSystemFrontendDelegate*>(&getSystem().getDelegate())->
221 commandProcessHadOutput(
222 command, BuildSystemFrontendDelegate::ProcessHandle { handle.id },
223 data);
224 }
225
commandProcessFinished(Command * command,ProcessHandle handle,CommandResult result,int exitStatus)226 virtual void commandProcessFinished(Command* command, ProcessHandle handle,
227 CommandResult result,
228 int exitStatus) override {
229 static_cast<BuildSystemFrontendDelegate*>(&getSystem().getDelegate())->
230 commandProcessFinished(
231 command, BuildSystemFrontendDelegate::ProcessHandle { handle.id },
232 result, exitStatus);
233 }
234 };
235
236 struct BuildSystemFrontendDelegateImpl {
237
238 /// The status of delegate.
239 enum class Status {
240 Uninitialized = 0,
241 Initialized,
242 InitializationFailure,
243 Cancelled,
244 };
245
246 llvm::SourceMgr& sourceMgr;
247 const BuildSystemInvocation& invocation;
248
249 StringRef bufferBeingParsed;
250 std::atomic<unsigned> numErrors{0};
251 std::atomic<unsigned> numFailedCommands{0};
252
253 BuildSystemFrontendExecutionQueueDelegate executionQueueDelegate;
254
255 BuildSystemFrontend* frontend = nullptr;
256 BuildSystem* system = nullptr;
257
258 /// The set of active command output buffers, by process handle.
259 llvm::DenseMap<uintptr_t, std::vector<uint8_t>> processOutputBuffers;
260
261 /// The lock protecting `processOutputBuffers`.
262 std::mutex processOutputBuffersMutex;
263
BuildSystemFrontendDelegateImpl__anon25a8402b0211::BuildSystemFrontendDelegateImpl264 BuildSystemFrontendDelegateImpl(llvm::SourceMgr& sourceMgr,
265 const BuildSystemInvocation& invocation)
266 : sourceMgr(sourceMgr), invocation(invocation),
267 executionQueueDelegate(*this) {}
268
269 private:
270 /// The status of the delegate.
271 std::atomic<Status> status{Status::Uninitialized};
272
273 public:
274
275 /// Set the status of delegate to the given value.
276 ///
277 /// It is not possible to update the status once status is set to initialization failure.
setStatus__anon25a8402b0211::BuildSystemFrontendDelegateImpl278 void setStatus(Status newStatus) {
279 // Disallow changing status if there was an initialization failure.
280 if (status == Status::InitializationFailure) {
281 return;
282 }
283 status = newStatus;
284 }
285
286 /// Returns the current status.
getStatus__anon25a8402b0211::BuildSystemFrontendDelegateImpl287 Status getStatus() {
288 return status;
289 }
290 };
291
showVerboseOutput() const292 bool BuildSystemFrontendExecutionQueueDelegate::showVerboseOutput() const {
293 return delegateImpl.invocation.showVerboseStatus;
294 }
295
getSystem() const296 BuildSystem& BuildSystemFrontendExecutionQueueDelegate::getSystem() const {
297 assert(delegateImpl.system);
298 return *delegateImpl.system;
299 }
300
301 }
302
303 BuildSystemFrontendDelegate::
BuildSystemFrontendDelegate(llvm::SourceMgr & sourceMgr,const BuildSystemInvocation & invocation,StringRef name,uint32_t version)304 BuildSystemFrontendDelegate(llvm::SourceMgr& sourceMgr,
305 const BuildSystemInvocation& invocation,
306 StringRef name,
307 uint32_t version)
308 : BuildSystemDelegate(name, version),
309 impl(new BuildSystemFrontendDelegateImpl(sourceMgr, invocation))
310 {
311
312 }
313
~BuildSystemFrontendDelegate()314 BuildSystemFrontendDelegate::~BuildSystemFrontendDelegate() {
315 delete static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
316 }
317
318 void
setFileContentsBeingParsed(StringRef buffer)319 BuildSystemFrontendDelegate::setFileContentsBeingParsed(StringRef buffer) {
320 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
321
322 impl->bufferBeingParsed = buffer;
323 }
324
getFrontend()325 BuildSystemFrontend& BuildSystemFrontendDelegate::getFrontend() {
326 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
327
328 return *impl->frontend;
329 }
330
getSourceMgr()331 llvm::SourceMgr& BuildSystemFrontendDelegate::getSourceMgr() {
332 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
333
334 return impl->sourceMgr;
335 }
336
getNumErrors()337 unsigned BuildSystemFrontendDelegate::getNumErrors() {
338 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
339
340 return impl->numErrors;
341 }
342
getNumFailedCommands()343 unsigned BuildSystemFrontendDelegate::getNumFailedCommands() {
344 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
345
346 return impl->numFailedCommands;
347 }
348
349 void
error(const Twine & message)350 BuildSystemFrontendDelegate::error(const Twine& message) {
351 error("", {}, message.str());
352 }
353
354 void
error(StringRef filename,const Token & at,const Twine & message)355 BuildSystemFrontendDelegate::error(StringRef filename,
356 const Token& at,
357 const Twine& message) {
358 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
359
360 ++impl->numErrors;
361
362 // If we have a file and token, resolve the location and range to one
363 // accessible by the source manager.
364 //
365 // FIXME: We shouldn't need to do this, but should switch llbuild to using
366 // SourceMgr natively.
367 llvm::SMLoc loc{};
368 llvm::SMRange range{};
369 if (!filename.empty() && at.start) {
370 // FIXME: We ignore errors here, for now, this will be resolved when we move
371 // to SourceMgr completely.
372 auto buffer = getFileSystem().getFileContents(filename);
373 if (buffer) {
374 unsigned offset = at.start - impl->bufferBeingParsed.data();
375 if (offset + at.length < buffer->getBufferSize()) {
376 range.Start = loc = llvm::SMLoc::getFromPointer(
377 buffer->getBufferStart() + offset);
378 range.End = llvm::SMLoc::getFromPointer(
379 buffer->getBufferStart() + (offset + at.length));
380 getSourceMgr().AddNewSourceBuffer(std::move(buffer), llvm::SMLoc{});
381 }
382 }
383 }
384
385 if (range.Start.isValid()) {
386 getSourceMgr().PrintMessage(loc, llvm::SourceMgr::DK_Error, message, range);
387 } else {
388 getSourceMgr().PrintMessage(loc, llvm::SourceMgr::DK_Error, message);
389 }
390 fflush(stderr);
391 }
392
393 std::unique_ptr<BuildExecutionQueue>
createExecutionQueue()394 BuildSystemFrontendDelegate::createExecutionQueue() {
395 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
396
397 if (impl->invocation.useSerialBuild) {
398 return std::unique_ptr<BuildExecutionQueue>(
399 createLaneBasedExecutionQueue(impl->executionQueueDelegate, 1,
400 impl->invocation.environment));
401 }
402
403 // Get the number of CPUs to use.
404 unsigned numCPUs = std::thread::hardware_concurrency();
405 unsigned numLanes;
406 if (numCPUs == 0) {
407 error("<unknown>", {}, "unable to detect number of CPUs");
408 numLanes = 1;
409 } else {
410 numLanes = numCPUs;
411 }
412
413 return std::unique_ptr<BuildExecutionQueue>(
414 createLaneBasedExecutionQueue(impl->executionQueueDelegate, numLanes,
415 impl->invocation.environment));
416 }
417
cancel()418 void BuildSystemFrontendDelegate::cancel() {
419 auto delegateImpl = static_cast<BuildSystemFrontendDelegateImpl*>(impl);
420 assert(delegateImpl->getStatus() != BuildSystemFrontendDelegateImpl::Status::Uninitialized);
421
422 // Update the status to cancelled.
423 delegateImpl->setStatus(BuildSystemFrontendDelegateImpl::Status::Cancelled);
424
425 auto system = delegateImpl->system;
426 if (system) {
427 system->cancel();
428 }
429 }
430
resetForBuild()431 void BuildSystemFrontendDelegate::resetForBuild() {
432 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
433
434 impl->numFailedCommands = 0;
435 impl->numErrors = 0;
436
437 // Update status back to initialized on reset.
438 if (impl->getStatus() == BuildSystemFrontendDelegateImpl::Status::Cancelled) {
439 impl->setStatus(BuildSystemFrontendDelegateImpl::Status::Initialized);
440 }
441
442 // Reset the build system.
443 auto system = impl->system;
444 if (system) {
445 system->resetForBuild();
446 }
447 }
448
hadCommandFailure()449 void BuildSystemFrontendDelegate::hadCommandFailure() {
450 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
451
452 // Increment the failed command count.
453 ++impl->numFailedCommands;
454 }
455
commandStatusChanged(Command *,CommandStatusKind)456 void BuildSystemFrontendDelegate::commandStatusChanged(Command*,
457 CommandStatusKind) {
458 }
459
commandPreparing(Command *)460 void BuildSystemFrontendDelegate::commandPreparing(Command*) {
461 }
462
shouldCommandStart(Command *)463 bool BuildSystemFrontendDelegate::shouldCommandStart(Command*) {
464 return true;
465 }
466
commandStarted(Command * command)467 void BuildSystemFrontendDelegate::commandStarted(Command* command) {
468 // Don't report status if opted out by the command.
469 if (!command->shouldShowStatus()) {
470 return;
471 }
472
473 // Log the command.
474 //
475 // FIXME: Design the logging and status output APIs.
476 SmallString<64> description;
477 if (getFrontend().getInvocation().showVerboseStatus) {
478 command->getVerboseDescription(description);
479 } else {
480 command->getShortDescription(description);
481
482 // If the short description is empty, always show the verbose one.
483 if (description.empty()) {
484 command->getVerboseDescription(description);
485 }
486 }
487 fprintf(stdout, "%s\n", description.c_str());
488 fflush(stdout);
489 }
490
commandHadError(Command * command,StringRef data)491 void BuildSystemFrontendDelegate::commandHadError(Command* command, StringRef data) {
492 fwrite(data.data(), data.size(), 1, stderr);
493 fflush(stderr);
494 }
495
commandHadNote(Command * command,StringRef data)496 void BuildSystemFrontendDelegate::commandHadNote(Command* command, StringRef data) {
497 fwrite(data.data(), data.size(), 1, stdout);
498 fflush(stdout);
499 }
500
commandHadWarning(Command * command,StringRef data)501 void BuildSystemFrontendDelegate::commandHadWarning(Command* command, StringRef data) {
502 fwrite(data.data(), data.size(), 1, stdout);
503 fflush(stdout);
504 }
505
commandFinished(Command *,CommandResult)506 void BuildSystemFrontendDelegate::commandFinished(Command*, CommandResult) {
507 }
508
commandJobStarted(Command *)509 void BuildSystemFrontendDelegate::commandJobStarted(Command*) {
510 }
511
commandJobFinished(Command *)512 void BuildSystemFrontendDelegate::commandJobFinished(Command*) {
513 }
514
commandProcessStarted(Command *,ProcessHandle)515 void BuildSystemFrontendDelegate::commandProcessStarted(Command*,
516 ProcessHandle) {
517 }
518
519 void BuildSystemFrontendDelegate::
commandProcessHadError(Command * command,ProcessHandle handle,const Twine & message)520 commandProcessHadError(Command* command, ProcessHandle handle,
521 const Twine& message) {
522 SmallString<256> buffer;
523 auto str = message.toStringRef(buffer);
524
525 // FIXME: Design the logging and status output APIs.
526 fwrite(str.data(), str.size(), 1, stderr);
527 fputc('\n', stderr);
528 fflush(stderr);
529 }
530
531 void BuildSystemFrontendDelegate::
commandProcessHadOutput(Command * command,ProcessHandle handle,StringRef data)532 commandProcessHadOutput(Command* command, ProcessHandle handle,
533 StringRef data) {
534 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
535 std::unique_lock<std::mutex> lock(impl->processOutputBuffersMutex);
536
537 // Append to the output buffer.
538 auto& buffer = impl->processOutputBuffers[handle.id];
539 buffer.insert(buffer.end(), data.begin(), data.end());
540 }
541
542 void BuildSystemFrontendDelegate::
commandProcessFinished(Command *,ProcessHandle handle,CommandResult result,int exitStatus)543 commandProcessFinished(Command*, ProcessHandle handle,
544 CommandResult result,
545 int exitStatus) {
546 auto impl = static_cast<BuildSystemFrontendDelegateImpl*>(this->impl);
547 std::unique_lock<std::mutex> lock(impl->processOutputBuffersMutex);
548
549 // If there was an output buffer, flush it.
550 auto it = impl->processOutputBuffers.find(handle.id);
551 if (it == impl->processOutputBuffers.end())
552 return;
553
554 fwrite(it->second.data(), it->second.size(), 1, stdout);
555 fflush(stdout);
556
557 impl->processOutputBuffers.erase(it);
558 }
559
560 #pragma mark - BuildSystemFrontend implementation
561
562 BuildSystemFrontend::
BuildSystemFrontend(BuildSystemFrontendDelegate & delegate,const BuildSystemInvocation & invocation)563 BuildSystemFrontend(BuildSystemFrontendDelegate& delegate,
564 const BuildSystemInvocation& invocation)
565 : delegate(delegate), invocation(invocation)
566 {
567 auto delegateImpl =
568 static_cast<BuildSystemFrontendDelegateImpl*>(delegate.impl);
569
570 delegateImpl->frontend = this;
571 }
572
initialize()573 bool BuildSystemFrontend::initialize() {
574 if (!invocation.chdirPath.empty()) {
575 if (!sys::chdir(invocation.chdirPath.c_str())) {
576 getDelegate().error(Twine("unable to honor --chdir: ") + strerror(errno));
577 return false;
578 }
579 }
580
581 // Create the build system.
582 buildSystem.emplace(delegate);
583
584 // Load the build file.
585 if (!buildSystem->loadDescription(invocation.buildFilePath))
586 return false;
587
588 // Register the system back pointer.
589 //
590 // FIXME: Eliminate this.
591 auto delegateImpl =
592 static_cast<BuildSystemFrontendDelegateImpl*>(delegate.impl);
593 delegateImpl->system = buildSystem.getPointer();
594
595 // Enable tracing, if requested.
596 if (!invocation.traceFilePath.empty()) {
597 std::string error;
598 if (!buildSystem->enableTracing(invocation.traceFilePath, &error)) {
599 getDelegate().error(Twine("unable to enable tracing: ") + error);
600 return false;
601 }
602 }
603
604 // Attach the database.
605 if (!invocation.dbPath.empty()) {
606 // If the database path is relative, always make it relative to the input
607 // file.
608 SmallString<256> tmp;
609 StringRef dbPath = invocation.dbPath;
610 if (llvm::sys::path::is_relative(invocation.dbPath) &&
611 dbPath.find("://") == StringRef::npos && !dbPath.startswith(":")) {
612 llvm::sys::path::append(
613 tmp, llvm::sys::path::parent_path(invocation.buildFilePath),
614 invocation.dbPath);
615 dbPath = tmp.str();
616 }
617
618 std::string error;
619 if (!buildSystem->attachDB(dbPath, &error)) {
620 getDelegate().error(Twine("unable to attach DB: ") + error);
621 return false;
622 }
623 }
624
625 return true;
626 }
627
build(StringRef targetToBuild)628 bool BuildSystemFrontend::build(StringRef targetToBuild) {
629
630 auto delegateImpl =
631 static_cast<BuildSystemFrontendDelegateImpl*>(delegate.impl);
632
633 // We expect build to be called in these states only.
634 assert(delegateImpl->getStatus() == BuildSystemFrontendDelegateImpl::Status::Uninitialized
635 || delegateImpl->getStatus() == BuildSystemFrontendDelegateImpl::Status::Initialized);
636
637 // Set the delegate status to initialized.
638 delegateImpl->setStatus(BuildSystemFrontendDelegateImpl::Status::Initialized);
639
640 // Initialize the build system, if necessary
641 if (!buildSystem.hasValue()) {
642 if (!initialize()) {
643 // Set status to initialization failure. It is not possible to recover from this state.
644 delegateImpl->setStatus(BuildSystemFrontendDelegateImpl::Status::InitializationFailure);
645 return false;
646 }
647 }
648
649 // If delegate was told to cancel while we were initializing, abort now.
650 if (delegateImpl->getStatus() == BuildSystemFrontendDelegateImpl::Status::Cancelled) {
651 return false;
652 }
653
654 // Build the target; if something unspecified failed about the build, return
655 // an error.
656 if (!buildSystem->build(targetToBuild))
657 return false;
658
659 // The build was successful if there were no failed commands or unspecified
660 // errors.
661 //
662 // It is the job of the client to report a summary, if desired.
663 return delegate.getNumFailedCommands() == 0 && delegate.getNumErrors() == 0;
664 }
665