blob: 4c7c09e6a5c0825e55b91b1b530f564900a3a944 [file] [log] [blame]
//===- BuildSystemFrontend.h ------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef LLBUILD_BUILDSYSTEM_BUILDSYSTEMFRONTEND_H
#define LLBUILD_BUILDSYSTEM_BUILDSYSTEMFRONTEND_H
#include "llbuild/Basic/LLVM.h"
#include "llbuild/BuildSystem/BuildSystem.h"
#include "llbuild/Core/BuildEngine.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Optional.h"
#include <atomic>
#include <string>
#include <vector>
namespace llvm {
class SourceMgr;
}
namespace llbuild {
namespace basic {
class FileSystem;
}
namespace buildsystem {
class BuildSystemFrontendDelegate;
class BuildSystemInvocation;
enum class CommandResult;
/// This provides a standard "frontend" to the build system features, for use in
/// building bespoke build systems that can still take advantage of desirable
/// shared behavior.
///
/// The frontend glues together various parts of the build system functionality
/// to provide:
/// o Support for common command line options.
/// o Support for parallel, persistent builds.
/// o Support for command line diagnostics and status reporting.
///
/// NOTE: This class is *NOT* thread safe.
class BuildSystemFrontend {
BuildSystemFrontendDelegate& delegate;
const BuildSystemInvocation& invocation;
llvm::Optional<BuildSystem> buildSystem;
public:
BuildSystemFrontend(BuildSystemFrontendDelegate& delegate,
const BuildSystemInvocation& invocation);
/// @name Accessors
/// @{
BuildSystemFrontendDelegate& getDelegate() { return delegate; }
const BuildSystemFrontendDelegate& getDelegate() const { return delegate; }
const BuildSystemInvocation& getInvocation() { return invocation; }
/// @}
/// @name Client API
/// @{
/// Initialize the build system.
///
/// This will load the manifest and apply all of the command line options to
/// construct an appropriate underlying `BuildSystem` for use by subsequent
/// build calls.
///
/// \returns True on success, or false if there were errors. If initialization
/// fails, the frontend is in an indeterminant state and should not be reused.
bool initialize();
/// Build the named target using the specified invocation parameters.
///
/// \returns True on success, or false if there were errors.
bool build(StringRef targetToBuild);
/// @}
};
/// The frontend-specific delegate, which provides some shared behaviors.
class BuildSystemFrontendDelegate : public BuildSystemDelegate {
friend class BuildSystemFrontend;
public:
/// Handle used to communicate information about a launched process.
struct ProcessHandle {
/// Opaque ID.
uintptr_t id;
};
private:
void* impl;
/// Default implementation, cannot be overriden by subclasses.
virtual void setFileContentsBeingParsed(StringRef buffer) override;
/// Provides a default error implementation which will delegate to the
/// provided source manager. Cannot be overriden by subclasses.
virtual void error(StringRef filename, const Token& at,
const Twine& message) override;
public:
/// Create a frontend delegate.
///
/// \param sourceMgr The source manager to use for reporting diagnostics.
/// \param invocation The invocation parameters.
/// \param name The name of build system client.
/// \param version The version of the build system client.
BuildSystemFrontendDelegate(llvm::SourceMgr& sourceMgr,
const BuildSystemInvocation& invocation,
StringRef name,
uint32_t version);
virtual ~BuildSystemFrontendDelegate();
/// Get the file system to use for access.
virtual basic::FileSystem& getFileSystem() override = 0;
/// Called by the build system to get a tool definition, must be provided by
/// subclasses.
virtual std::unique_ptr<Tool> lookupTool(StringRef name) override = 0;
/// Provides an appropriate execution queue based on the invocation options.
virtual std::unique_ptr<BuildExecutionQueue> createExecutionQueue() override;
/// Cancels the current build.
virtual void cancel();
/// Reset mutable build state before a new build operation.
void resetForBuild();
/// Provides a default handler.
///
/// Subclass should call this method if overridden.
virtual void hadCommandFailure() override;
/// @name Frontend-specific APIs
/// @{
/// Report a non-file specific error message.
void error(const Twine& message);
/// @}
/// @name Status Reporting APIs
///
/// The frontend provides default implementations of these methods which
/// report the status to stdout. Clients should override if they wish to
/// direct the status elsewhere.
///
/// @{
/// Called by the build system to report that a declared command's state is
/// changing.
virtual void commandStatusChanged(Command*, CommandStatusKind) override;
/// Called by the build system to report that a declared command is preparing
/// to run.
///
/// The system guarantees that all such calls will be paired with a
/// corresponding \see commandFinished() call.
virtual void commandPreparing(Command*) override;
/// Called by the build system to allow the delegate to skip a command without
/// implicitly skipping its dependents.
///
/// WARNING: Clients need to take special care when using this. Skipping
/// commands without considering their dependencies or dependents can easily
/// produce an inconsistent build.
///
/// This method is called before the command starts, when the system has
/// identified that it will eventually need to run (after all of its inputs
/// have been satisfied).
///
/// The system guarantees that all such calls will be paired with a
/// corresponding \see commandFinished() call.
virtual bool shouldCommandStart(Command*) override;
/// Called by the build system to report that a declared command has started.
///
/// The system guarantees that all such calls will be paired with a
/// corresponding \see commandFinished() call.
virtual void commandStarted(Command*) override;
/// Called to report an error during the execution of a command.
///
/// \param data - The error message.
virtual void commandHadError(Command*, StringRef data) override;
/// Called to report a note during the execution of a command.
///
/// \param data - The note message.
virtual void commandHadNote(Command*, StringRef data) override;
/// Called to report a warning during the execution of a command.
///
/// \param data - The warning message.
virtual void commandHadWarning(Command*, StringRef data) override;
/// Called by the build system to report a command has completed.
///
/// \param result - The result of command (e.g. success, failure, etc).
virtual void commandFinished(Command*, CommandResult result) override;
/// Called when a command's job has been started.
///
/// The system guarantees that any commandStart() call will be paired with
/// exactly one \see commandFinished() call.
//
// FIXME: We may eventually want to allow the individual job to provide some
// additional context here, for complex commands.
//
// FIXME: Design a way to communicate the "lane" here, for use in "super
// console" like UIs.
virtual void commandJobStarted(Command*);
/// Called when a command's job has been finished.
virtual void commandJobFinished(Command*);
/// Called when a command's job has started executing an external process.
///
/// The system guarantees that any commandProcessStarted() call will be paired
/// with exactly one \see commandProcessFinished() call.
///
/// \param handle - A unique handle used in subsequent delegate calls to
/// identify the process. This handle should only be used to associate
/// different status calls relating to the same process. It is only guaranteed
/// to be unique from when it has been provided here to when it has been
/// provided to the \see commandProcessFinished() call.
virtual void commandProcessStarted(Command*, ProcessHandle handle);
/// Called to report an error in the management of a command process.
///
/// \param handle - The process handle.
/// \param message - The error message.
//
// FIXME: Need to move to more structured error handling.
virtual void commandProcessHadError(Command*, ProcessHandle handle,
const Twine& message);
/// Called to report a command processes' (merged) standard output and error.
///
/// \param handle - The process handle.
/// \param data - The process output.
virtual void commandProcessHadOutput(Command*, ProcessHandle handle,
StringRef data);
/// Called when a command's job has finished executing an external process.
///
/// \param handle - The handle used to identify the process. This handle will
/// become invalid as soon as the client returns from this API call.
///
/// \param result - Whether the process suceeded, failed or was cancelled.
/// \param exitStatus - The raw exit status of the process.
//
// FIXME: Need to include additional information on the status here, e.g., the
// signal status, and the process output (if buffering).
virtual void commandProcessFinished(Command*, ProcessHandle handle,
CommandResult result,
int exitStatus);
/// Called when a cycle is detected by the build engine and it cannot make
/// forward progress.
///
/// \param items The ordered list of items comprising the cycle, starting from
/// the node which was requested to build and ending with the first node in
/// the cycle (i.e., the node participating in the cycle will appear twice).
virtual void cycleDetected(const std::vector<core::Rule*>& items) = 0;
/// @}
/// @name Accessors
/// @{
BuildSystemFrontend& getFrontend();
llvm::SourceMgr& getSourceMgr();
/// Get the number of reported errors.
unsigned getNumErrors();
/// Get the number of failed commands.
unsigned getNumFailedCommands();
/// @}
};
/// This class wraps the common options which are used by the frontend.
class BuildSystemInvocation {
public:
/// Whether the command usage should be printed.
bool showUsage = false;
/// Whether the command version should be printed.
bool showVersion = false;
/// Whether to show verbose output.
bool showVerboseStatus = false;
/// Whether to use a serial build.
bool useSerialBuild = false;
/// The path of the database file to use, if any.
std::string dbPath = "build.db";
/// The path of a directory to change into before anything else, if any.
std::string chdirPath = "";
/// The path of the build file to use.
std::string buildFilePath = "build.llbuild";
/// The path of the build trace output file to use, if any.
std::string traceFilePath = "";
/// The base environment to use when executing subprocesses.
///
/// The format is expected to match that of `::main()`, i.e. a null-terminated
/// array of pointers to null terminated C strings.
///
/// If empty, the environment of the calling process will be used.
const char* const* environment = nullptr;
/// The positional arguments.
std::vector<std::string> positionalArgs;
/// Whether there were any parsing errors.
bool hadErrors = false;
public:
/// Get the appropriate "usage" text to use for the built in arguments.
static void getUsage(int optionWidth, raw_ostream& os);
/// Parse the invocation parameters from the given arguments.
///
/// \param sourceMgr The source manager to use for diagnostics.
void parse(ArrayRef<std::string> args, llvm::SourceMgr& sourceMgr);
/// Provides a default string representation for a cycle detected by the build engine.
static std::string formatDetectedCycle(const std::vector<core::Rule*>& cycle);
};
}
}
#endif