cpsughrue updated this revision to Diff 554583.
cpsughrue added a comment.

Remove unnecessary header files


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158496/new/

https://reviews.llvm.org/D158496

Files:
  clang/include/clang/Basic/DiagnosticFrontendKinds.td
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Driver/Options.td
  clang/include/clang/Frontend/FrontendOptions.h
  clang/include/clang/Tooling/ModuleBuildDaemon/Protocol.h
  clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
  clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Tooling/CMakeLists.txt
  clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
  clang/lib/Tooling/ModuleBuildDaemon/Protocol.cpp
  clang/lib/Tooling/ModuleBuildDaemon/SocketMsgSupport.cpp
  clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
  clang/test/Driver/unknown-arg.c
  clang/tools/driver/CMakeLists.txt
  clang/tools/driver/cc1_main.cpp
  clang/tools/driver/cc1modbuildd_main.cpp
  clang/tools/driver/driver.cpp

Index: clang/tools/driver/driver.cpp
===================================================================
--- clang/tools/driver/driver.cpp
+++ clang/tools/driver/driver.cpp
@@ -213,6 +213,9 @@
 extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
                                   const char *Argv0, void *MainAddr,
                                   const llvm::ToolContext &);
+#if LLVM_ON_UNIX
+extern int cc1modbuildd_main(ArrayRef<const char *> Argv);
+#endif
 
 static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
                                     SmallVectorImpl<const char *> &ArgVector,
@@ -369,9 +372,15 @@
   if (Tool == "-cc1gen-reproducer")
     return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0],
                                   GetExecutablePathVP, ToolContext);
-  // Reject unknown tools.
-  llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
-               << "Valid tools include '-cc1' and '-cc1as'.\n";
+#if LLVM_ON_UNIX
+  if (Tool == "-cc1modbuildd")
+    return cc1modbuildd_main(ArrayRef(ArgV).slice(2));
+#endif
+
+  // Reject unknown tools
+  llvm::errs()
+      << "error: unknown integrated tool '" << Tool << "'. "
+      << "Valid tools include '-cc1', '-cc1as', and '-cc1gen-reproducer'.\n";
   return 1;
 }
 
Index: clang/tools/driver/cc1modbuildd_main.cpp
===================================================================
--- /dev/null
+++ clang/tools/driver/cc1modbuildd_main.cpp
@@ -0,0 +1,361 @@
+//===------- cc1modbuildd_main.cpp - Clang CC1 Module Build Daemon --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/DiagnosticCategories.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
+#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
+#include "clang/Tooling/ModuleBuildDaemon/Protocol.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+
+// TODO: Make portable
+#if LLVM_ON_UNIX
+
+#include <errno.h>
+#include <fstream>
+#include <signal.h>
+#include <sstream>
+#include <stdbool.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+using namespace llvm;
+using namespace clang;
+using namespace tooling::dependencies;
+
+namespace {
+class ModuleBuildDaemonServer {
+public:
+  SmallString<128> BasePath;
+  SmallString<128> SocketPath;
+  SmallString<128> PidPath;
+
+  ModuleBuildDaemonServer(SmallString<128> Path, ArrayRef<const char *> Argv)
+      : BasePath(Path), SocketPath(Path),
+        Diags(constructDiagnosticsEngine(Argv)) {
+    llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+
+    if (find(Argv, StringRef("-Rmodule-build-daemon")) != Argv.end())
+      Diags.setSeverityForGroup(diag::Flavor::Remark,
+                                diag::Group::ModuleBuildDaemon,
+                                diag::Severity::Remark);
+  }
+
+  ~ModuleBuildDaemonServer() { Shutdown(SIGTERM); }
+
+  int Fork();
+  int Launch();
+  int Listen();
+  static llvm::Error Service(int Client);
+
+  void Shutdown(int signal) {
+    unlink(SocketPath.c_str());
+    shutdown(ListenSocketFD, SHUT_RD);
+    close(ListenSocketFD);
+    exit(EXIT_SUCCESS);
+  }
+
+private:
+  // Initializes and returns DiagnosticsEngine
+  static DiagnosticsEngine
+  constructDiagnosticsEngine(ArrayRef<const char *> Argv) {
+    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+        CreateAndPopulateDiagOpts(Argv);
+    TextDiagnosticPrinter *DiagsBuffer =
+        new TextDiagnosticPrinter(cc1modbuildd::unbuff_outs(), &*DiagOpts);
+    return DiagnosticsEngine(DiagID, &*DiagOpts, DiagsBuffer);
+  }
+
+  pid_t Pid = -1;
+  int ListenSocketFD = -1;
+  DiagnosticsEngine Diags;
+};
+
+// Required to handle SIGTERM by calling Shutdown
+ModuleBuildDaemonServer *DaemonPtr = nullptr;
+void handleSignal(int Signal) {
+  if (DaemonPtr != nullptr) {
+    DaemonPtr->Shutdown(Signal);
+  }
+}
+} // namespace
+
+static Expected<TranslationUnitDeps>
+scanTranslationUnit(cc1modbuildd::SocketMsg Request) {
+
+  DependencyScanningService Service(ScanningMode::DependencyDirectivesScan,
+                                    ScanningOutputFormat::Full,
+                                    /*OptimizeArgs*/ false,
+                                    /*EagerLoadModules*/ false);
+
+  DependencyScanningTool Tool(Service);
+
+  llvm::DenseSet<ModuleID> AlreadySeenModules;
+  auto LookupOutput = [&](const ModuleID &MID, ModuleOutputKind MOK) {
+    return MID.ContextHash;
+  };
+
+  auto MaybeTUDeps = Tool.getTranslationUnitDependencies(
+      Request.Argv0PlusCC1CommandLine.value(), Request.WorkingDirectory.value(),
+      AlreadySeenModules, LookupOutput);
+
+  if (!MaybeTUDeps)
+    return std::move(MaybeTUDeps.takeError());
+
+  return std::move(*MaybeTUDeps);
+}
+
+// GOAL: take a client request in the form of a cc1modbuildd::SocketMsg and
+// return an updated cc1 command line for the registered cc1 invocation
+static Expected<std::vector<std::string>>
+getUpdatedCC1(cc1modbuildd::SocketMsg Request) {
+
+  Expected<TranslationUnitDeps> MaybeTUDeps = scanTranslationUnit(Request);
+  if (!MaybeTUDeps)
+    return std::move(MaybeTUDeps.takeError());
+  TranslationUnitDeps TUDeps = std::move(*MaybeTUDeps);
+
+  // For now write dependencies to log file
+  for (auto const &Dep : TUDeps.FileDeps) {
+    cc1modbuildd::unbuff_outs() << Dep << '\n';
+  }
+
+  if (!TUDeps.ModuleGraph.empty())
+    errs() << "Warning: translation unit contained modules. Module build "
+              "daemon not yet able to build modules"
+           << '\n';
+
+  // TODO: implement building modules and returning updated cc1 command line
+  // Until then just return original command line
+  return Request.Argv0PlusCC1CommandLine.value();
+}
+
+// Forks and detaches process, creating module build daemon
+int ModuleBuildDaemonServer::Fork() {
+
+  pid_t pid = fork();
+
+  if (pid < 0) {
+    exit(EXIT_FAILURE);
+  }
+  if (pid > 0) {
+    exit(EXIT_SUCCESS);
+  }
+
+  Pid = getpid();
+
+  close(STDIN_FILENO);
+  close(STDOUT_FILENO);
+  close(STDERR_FILENO);
+
+  SmallString<128> STDOUT = BasePath;
+  llvm::sys::path::append(STDOUT, STDOUT_FILE_NAME);
+  freopen(STDOUT.c_str(), "a", stdout);
+
+  SmallString<128> STDERR = BasePath;
+  llvm::sys::path::append(STDERR, STDERR_FILE_NAME);
+  freopen(STDERR.c_str(), "a", stderr);
+
+  if (signal(SIGTERM, handleSignal) == SIG_ERR) {
+    errs() << "failed to handle SIGTERM" << '\n';
+    exit(EXIT_FAILURE);
+  }
+  if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
+    errs() << "failed to ignore SIGHUP" << '\n';
+    exit(EXIT_FAILURE);
+  }
+  if (setsid() == -1) {
+    errs() << "setsid failed" << '\n';
+    exit(EXIT_FAILURE);
+  }
+
+  return EXIT_SUCCESS;
+}
+
+// Creates unix socket for IPC with module build daemon
+int ModuleBuildDaemonServer::Launch() {
+
+  // new socket
+  if ((ListenSocketFD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+    std::perror("Socket create error: ");
+    exit(EXIT_FAILURE);
+  }
+
+  struct sockaddr_un addr;
+  memset(&addr, 0, sizeof(struct sockaddr_un));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, SocketPath.c_str(), sizeof(addr.sun_path) - 1);
+
+  // bind to local address
+  if (bind(ListenSocketFD, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+
+    // If the socket address is already in use, exit because another module
+    // build daemon has successfully launched. When translation units are
+    // compiled in parallel, until the socket file is created, all clang
+    // invocations will spawn a module build daemon.
+    if (errno == EADDRINUSE) {
+      close(ListenSocketFD);
+      exit(EXIT_SUCCESS);
+    }
+    std::perror("Socket bind error: ");
+    exit(EXIT_FAILURE);
+  }
+  Diags.Report(diag::remark_mbd_socket_addr) << SocketPath;
+
+  // set socket to accept incoming connection request
+  unsigned MaxBacklog = llvm::hardware_concurrency().compute_thread_count();
+  if (listen(ListenSocketFD, MaxBacklog) == -1) {
+    std::perror("Socket listen error: ");
+    exit(EXIT_FAILURE);
+  }
+
+  Diags.Report(diag::remark_mbd_generic_msg)
+      << "module build daemon launch complete!";
+  return 0;
+}
+
+// Function submitted to thread pool with each client connection. Not
+// responsible for closing client connections
+llvm::Error ModuleBuildDaemonServer::Service(int Client) {
+
+  // Read request from client
+  Expected<cc1modbuildd::SocketMsg> MaybeClientRequest =
+      cc1modbuildd::readSocketMsgFromSocket(Client);
+  if (!MaybeClientRequest)
+    return std::move(MaybeClientRequest.takeError());
+  cc1modbuildd::SocketMsg ClientRequest = std::move(*MaybeClientRequest);
+
+  // Handle HANDSHAKE
+  if (ClientRequest.MsgAction == cc1modbuildd::ActionType::HANDSHAKE) {
+    std::string ServerResponse = cc1modbuildd::getBufferFromSocketMsg(
+        {cc1modbuildd::ActionType::HANDSHAKE,
+         cc1modbuildd::StatusType::SUCCESS});
+    llvm::Error WriteErr = cc1modbuildd::writeToSocket(ServerResponse, Client);
+    if (WriteErr)
+      return std::move(WriteErr);
+    return llvm::Error::success();
+  }
+
+  // Handle REGISTER
+  if (ClientRequest.MsgAction == cc1modbuildd::ActionType::REGISTER) {
+
+    Expected<std::vector<std::string>> MaybeUpdatedCC1 =
+        getUpdatedCC1(ClientRequest);
+
+    if (!MaybeUpdatedCC1) {
+      // TODO: Add error message to cc1modbuildd::SocketMsg
+      llvm::Error FailureWriteErr = cc1modbuildd::writeSocketMsgToSocket(
+          {cc1modbuildd::ActionType::REGISTER,
+           cc1modbuildd::StatusType::FAILURE},
+          Client);
+
+      if (FailureWriteErr)
+        return llvm::joinErrors(std::move(FailureWriteErr),
+                                std::move(MaybeUpdatedCC1.takeError()));
+
+      return std::move(MaybeUpdatedCC1.takeError());
+    }
+
+    llvm::Error SuccessWriteErr = cc1modbuildd::writeSocketMsgToSocket(
+        {cc1modbuildd::ActionType::REGISTER, cc1modbuildd::StatusType::SUCCESS,
+         std::nullopt, std::move(*MaybeUpdatedCC1)},
+        Client);
+
+    if (SuccessWriteErr)
+      return std::move(SuccessWriteErr);
+
+    return llvm::Error::success();
+  }
+
+  // Should never be reached. Conditional should exist for each ActionType
+  llvm_unreachable("Unrecognized Action");
+}
+
+int ModuleBuildDaemonServer::Listen() {
+
+  llvm::ThreadPool Pool;
+  int Client;
+
+  while (true) {
+
+    if ((Client = accept(ListenSocketFD, NULL, NULL)) == -1) {
+      std::perror("Socket accept error: ");
+      continue;
+    }
+
+    // FIXME: Error message could be overwritten before being handled if two
+    // threads return their results simultaneously
+    std::shared_future<llvm::Error> result = Pool.async(Service, Client);
+    llvm::Error Err = std::move(const_cast<llvm::Error &>(result.get()));
+
+    if (Err) {
+      handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+        errs() << "Error while scanning: " << EIB.message() << '\n';
+      });
+    }
+
+    close(Client);
+  }
+  return 0;
+}
+
+// Module build daemon is spawned with the following command line:
+//
+// clang -cc1modbuildd <path> -Rmodule-build-daemon
+//
+// <path> defines the location of all files created by the module build daemon
+// and should follow the format /path/to/dir. For example, `clang -cc1modbuildd
+// /tmp/` creates a socket file at `/tmp/mbd.sock`. /tmp is also valid.
+//
+// When module build daemons are spawned by cc1 invocations, <path> follows the
+// format /tmp/clang-<BLAKE3HashOfClangFullVersion>
+//
+// -Rmodule-build-daemon is optional and provides some debug information
+//
+int cc1modbuildd_main(ArrayRef<const char *> Argv) {
+
+  if (Argv.size() < 1) {
+    outs() << "spawning a module build daemon requies a command line format of "
+              "`clang -cc1modbuildd <path>`. <path> defines where the module "
+              "build daemon will create files"
+           << '\n';
+    return 1;
+  }
+
+  // Where to store log files and socket address
+  // TODO: Add check to confirm BasePath is directory
+  SmallString<128> BasePath(Argv[0]);
+  llvm::sys::fs::create_directories(BasePath);
+  ModuleBuildDaemonServer Daemon(BasePath, Argv);
+
+  // Used to handle signals
+  DaemonPtr = &Daemon;
+
+  Daemon.Fork();
+  Daemon.Launch();
+  Daemon.Listen();
+
+  return 0;
+}
+
+#endif // LLVM_ON_UNIX
\ No newline at end of file
Index: clang/tools/driver/cc1_main.cpp
===================================================================
--- clang/tools/driver/cc1_main.cpp
+++ clang/tools/driver/cc1_main.cpp
@@ -25,6 +25,7 @@
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Frontend/Utils.h"
 #include "clang/FrontendTool/Utils.h"
+#include "clang/Tooling/ModuleBuildDaemon/Protocol.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/LinkAllPasses.h"
@@ -205,11 +206,56 @@
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
   DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
 
+  // Create the actual diagnostics engine.
+
+  Clang->createDiagnostics();
+  if (!Clang->hasDiagnostics())
+    return 1;
+
   // Setup round-trip remarks for the DiagnosticsEngine used in CreateFromArgs.
   if (find(Argv, StringRef("-Rround-trip-cc1-args")) != Argv.end())
     Diags.setSeverity(diag::remark_cc1_round_trip_generated,
                       diag::Severity::Remark, {});
 
+#if LLVM_ON_UNIX
+  std::vector<std::string> UpdatedArgv;
+  std::vector<const char *> CharUpdatedArgv;
+
+  // handle module build daemon functionality if enabled
+  if (find(Argv, StringRef("-fmodule-build-daemon")) != Argv.end()) {
+
+    // Create FileManager
+    if (!Clang->hasFileManager())
+      Clang->createFileManager(createVFSFromCompilerInvocation(
+          Clang->getInvocation(), Clang->getDiagnostics()));
+
+    // Get current working directory for when module build daemon scans TU
+    llvm::ErrorOr<std::string> MaybeCWD = Clang->getFileManager()
+                                              .getVirtualFileSystem()
+                                              .getCurrentWorkingDirectory();
+    if (MaybeCWD.getError()) {
+      llvm::errs() << "Could not get working directory: "
+                   << MaybeCWD.getError().message() << "\n";
+      return 1;
+    }
+
+    Expected<std::vector<std::string>> MaybeUpdatedArgv =
+        cc1modbuildd::updateCC1WithModuleBuildDaemon(Argv, Argv0, *MaybeCWD);
+    if (!MaybeUpdatedArgv)
+      llvm::errs() << toString(std::move(MaybeUpdatedArgv.takeError())) << '\n';
+    UpdatedArgv = std::move(*MaybeUpdatedArgv);
+
+    // Command line in SocketMsg is stored as std::vector<std::string> to
+    // accomadate the dependency scanner
+    CharUpdatedArgv.reserve(UpdatedArgv.size());
+    for (const auto &str : UpdatedArgv) {
+      CharUpdatedArgv.push_back(str.c_str());
+    }
+
+    Argv = llvm::ArrayRef<const char *>(CharUpdatedArgv);
+  }
+#endif
+
   bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
                                                     Argv, Diags, Argv0);
 
@@ -227,11 +273,6 @@
     Clang->getHeaderSearchOpts().ResourceDir =
       CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
 
-  // Create the actual diagnostics engine.
-  Clang->createDiagnostics();
-  if (!Clang->hasDiagnostics())
-    return 1;
-
   // Set an error handler, so that any LLVM backend diagnostics go through our
   // error handler.
   llvm::install_fatal_error_handler(LLVMErrorHandler,
Index: clang/tools/driver/CMakeLists.txt
===================================================================
--- clang/tools/driver/CMakeLists.txt
+++ clang/tools/driver/CMakeLists.txt
@@ -28,6 +28,7 @@
   cc1_main.cpp
   cc1as_main.cpp
   cc1gen_reproducer_main.cpp
+  cc1modbuildd_main.cpp
 
   DEPENDS
   intrinsics_gen
@@ -39,9 +40,11 @@
   PRIVATE
   clangBasic
   clangCodeGen
+  clangDependencyScanning
   clangDriver
   clangFrontend
   clangFrontendTool
+  clangModuleBuildDaemon
   clangSerialization
   )
 
Index: clang/test/Driver/unknown-arg.c
===================================================================
--- clang/test/Driver/unknown-arg.c
+++ clang/test/Driver/unknown-arg.c
@@ -59,7 +59,7 @@
 // SILENT-NOT: warning:
 // CC1AS-DID-YOU-MEAN: error: unknown argument '-hell'; did you mean '-help'?
 // CC1AS-DID-YOU-MEAN: error: unknown argument '--version'; did you mean '-version'?
-// UNKNOWN-INTEGRATED: error: unknown integrated tool '-cc1asphalt'. Valid tools include '-cc1' and '-cc1as'.
+// UNKNOWN-INTEGRATED: error: unknown integrated tool '-cc1asphalt'. Valid tools include '-cc1', '-cc1as', and '-cc1gen-reproducer'.
 
 // RUN: %clang -S %s -o %t.s  -Wunknown-to-clang-option 2>&1 | FileCheck --check-prefix=IGNORED %s
 
Index: clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
===================================================================
--- /dev/null
+++ clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
@@ -0,0 +1,106 @@
+//===------------------------- SocketSupport.cpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Tooling/ModuleBuildDaemon/Protocol.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/BLAKE3.h"
+
+// TODO: Make portable
+#if LLVM_ON_UNIX
+
+#include <cerrno>
+#include <filesystem>
+#include <fstream>
+#include <signal.h>
+#include <spawn.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+Expected<int> cc1modbuildd::createSocket() {
+  int FD;
+  if ((FD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+    std::string Msg = "socket create error: " + std::string(strerror(errno));
+    return createStringError(inconvertibleErrorCode(), Msg);
+  }
+  return FD;
+}
+
+Expected<int> cc1modbuildd::connectToSocket(StringRef SocketPath) {
+
+  Expected<int> MaybeFD = cc1modbuildd::createSocket();
+  if (!MaybeFD)
+    return std::move(MaybeFD.takeError());
+
+  int FD = std::move(*MaybeFD);
+
+  struct sockaddr_un Addr;
+  memset(&Addr, 0, sizeof(Addr));
+  Addr.sun_family = AF_UNIX;
+  strncpy(Addr.sun_path, SocketPath.str().c_str(), sizeof(Addr.sun_path) - 1);
+
+  if (connect(FD, (struct sockaddr *)&Addr, sizeof(Addr)) == -1) {
+    close(FD);
+    std::string msg = "socket connect error: " + std::string(strerror(errno));
+    return createStringError(inconvertibleErrorCode(), msg);
+  }
+  return FD;
+}
+
+Expected<int> cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
+                                                    StringRef SocketPath) {
+
+  Expected<int> MaybeConnectedFD = connectToSocket(SocketPath);
+  if (!MaybeConnectedFD)
+    return std::move(MaybeConnectedFD.takeError());
+
+  int ConnectedFD = std::move(*MaybeConnectedFD);
+  llvm::Error Err = writeToSocket(Buffer, ConnectedFD);
+  if (Err)
+    return std::move(Err);
+
+  return ConnectedFD;
+}
+
+Expected<std::unique_ptr<char[]>> cc1modbuildd::readFromSocket(int FD) {
+
+  std::unique_ptr<char[]> Buffer(new char[MAX_BUFFER]);
+  memset(Buffer.get(), 0, MAX_BUFFER);
+  int n = read(FD, Buffer.get(), MAX_BUFFER);
+
+  if (n < 0) {
+    std::string Msg = "socket read error: " + std::string(strerror(errno));
+    return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+  }
+  if (n == 0)
+    return llvm::make_error<StringError>("EOF", inconvertibleErrorCode());
+
+  return Buffer;
+}
+
+llvm::Error cc1modbuildd::writeToSocket(std::string Buffer, int WriteFD) {
+
+  ssize_t MessageSize = static_cast<ssize_t>(Buffer.size());
+
+  if (write(WriteFD, Buffer.c_str(), Buffer.size()) != MessageSize) {
+    std::string Msg = "socket write error: " + std::string(strerror(errno));
+    return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+  }
+  return llvm::Error::success();
+}
+
+#endif // LLVM_ON_UNIX
\ No newline at end of file
Index: clang/lib/Tooling/ModuleBuildDaemon/SocketMsgSupport.cpp
===================================================================
--- /dev/null
+++ clang/lib/Tooling/ModuleBuildDaemon/SocketMsgSupport.cpp
@@ -0,0 +1,74 @@
+//===------------------------ SocketMsgSupport.cpp ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/Protocol.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+
+std::string cc1modbuildd::getBufferFromSocketMsg(SocketMsg SocketMsg) {
+
+  std::string Buffer;
+  llvm::raw_string_ostream OS(Buffer);
+  llvm::yaml::Output YamlOut(OS);
+
+  YamlOut << SocketMsg;
+  return Buffer;
+}
+
+Expected<cc1modbuildd::SocketMsg>
+cc1modbuildd::getSocketMsgFromBuffer(char *Buffer) {
+
+  SocketMsg ClientRequest;
+  llvm::yaml::Input YamlIn(Buffer);
+  YamlIn >> ClientRequest;
+
+  if (YamlIn.error()) {
+    std::string Msg = "Syntax or semantic error during YAML parsing";
+    return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+  }
+
+  return ClientRequest;
+}
+
+Expected<cc1modbuildd::SocketMsg>
+cc1modbuildd::readSocketMsgFromSocket(int FD) {
+  Expected<std::unique_ptr<char[]>> MaybeResponseBuffer = readFromSocket(FD);
+  if (!MaybeResponseBuffer)
+    return std::move(MaybeResponseBuffer.takeError());
+
+  // Wait for response from module build daemon
+  Expected<SocketMsg> MaybeResponse =
+      getSocketMsgFromBuffer(std::move(*MaybeResponseBuffer).get());
+  if (!MaybeResponse)
+    return std::move(MaybeResponse.takeError());
+
+  return std::move(*MaybeResponse);
+}
+
+llvm::Error cc1modbuildd::writeSocketMsgToSocket(SocketMsg Msg, int FD) {
+
+  std::string Buffer = getBufferFromSocketMsg(Msg);
+  if (llvm::Error Err = writeToSocket(Buffer, FD))
+    return std::move(Err);
+
+  return llvm::Error::success();
+}
+
+Expected<int>
+cc1modbuildd::connectAndWriteSocketMsgToSocket(SocketMsg Msg,
+                                               StringRef SocketPath) {
+  Expected<int> MaybeFD = connectToSocket(SocketPath);
+  if (!MaybeFD)
+    return std::move(MaybeFD.takeError());
+  int FD = std::move(*MaybeFD);
+
+  if (llvm::Error Err = writeSocketMsgToSocket(Msg, FD))
+    return std::move(Err);
+
+  return FD;
+}
\ No newline at end of file
Index: clang/lib/Tooling/ModuleBuildDaemon/Protocol.cpp
===================================================================
--- /dev/null
+++ clang/lib/Tooling/ModuleBuildDaemon/Protocol.cpp
@@ -0,0 +1,255 @@
+//===---------------------------- Protocol.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ModuleBuildDaemon/Protocol.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/BLAKE3.h"
+
+// TODO: Make portable
+#if LLVM_ON_UNIX
+
+#include <cerrno>
+#include <filesystem>
+#include <fstream>
+#include <signal.h>
+#include <spawn.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+using namespace clang;
+using namespace llvm;
+
+raw_fd_ostream &cc1modbuildd::unbuff_outs() {
+  static raw_fd_ostream S(STDOUT_FILENO, false, true);
+  return S;
+}
+
+std::string cc1modbuildd::getBasePath() {
+  llvm::BLAKE3 Hash;
+  Hash.update(getClangFullVersion());
+  auto HashResult = Hash.final<sizeof(uint64_t)>();
+  uint64_t HashValue =
+      llvm::support::endian::read<uint64_t, llvm::support::native>(
+          HashResult.data());
+  std::string Key = toString(llvm::APInt(64, HashValue), 36, /*Signed*/ false);
+
+  // set paths
+  SmallString<128> BasePath;
+  llvm::sys::path::system_temp_directory(/*erasedOnReboot*/ true, BasePath);
+  llvm::sys::path::append(BasePath, "clang-" + Key);
+  return BasePath.c_str();
+}
+
+bool cc1modbuildd::daemonExists(StringRef BasePath) {
+
+  SmallString<128> SocketPath = BasePath;
+  llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+
+  if (!llvm::sys::fs::exists(SocketPath))
+    return false;
+
+  Expected<int> ConnectedFD = connectToSocketAndHandshake(SocketPath);
+  if (ConnectedFD) {
+    close(std::move(*ConnectedFD));
+    return true;
+  }
+
+  consumeError(ConnectedFD.takeError());
+  return false;
+}
+
+llvm::Error cc1modbuildd::attemptHandshake(int SocketFD) {
+
+  cc1modbuildd::SocketMsg Request{ActionType::HANDSHAKE, StatusType::REQUEST};
+  std::string Buffer = cc1modbuildd::getBufferFromSocketMsg(Request);
+
+  if (llvm::Error Err = writeToSocket(Buffer, SocketFD))
+    return std::move(Err);
+
+  Expected<SocketMsg> MaybeServerResponse = readSocketMsgFromSocket(SocketFD);
+  if (!MaybeServerResponse)
+    return std::move(MaybeServerResponse.takeError());
+  SocketMsg ServerResponse = std::move(*MaybeServerResponse);
+
+  assert(ServerResponse.MsgAction == ActionType::HANDSHAKE &&
+         "At this point response ActionType should only ever be HANDSHAKE");
+
+  if (ServerResponse.MsgStatus == StatusType::SUCCESS)
+    return llvm::Error::success();
+
+  return llvm::make_error<StringError>("Handshake failed",
+                                       inconvertibleErrorCode());
+}
+
+Expected<int> cc1modbuildd::connectToSocketAndHandshake(StringRef SocketPath) {
+
+  Expected<int> ConnectedFD = connectToSocket(SocketPath);
+  if (!ConnectedFD)
+    return std::move(ConnectedFD.takeError());
+
+  llvm::Error Err = attemptHandshake(std::move(*ConnectedFD));
+  if (Err)
+    return std::move(Err);
+
+  return ConnectedFD;
+}
+
+llvm::Error cc1modbuildd::spawnModuleBuildDaemon(StringRef BasePath,
+                                                 const char *Argv0) {
+  std::string BasePathStr = BasePath.str();
+  const char *Args[] = {Argv0, "-cc1modbuildd", BasePathStr.c_str(), nullptr};
+  pid_t pid;
+  int EC = posix_spawn(&pid, Args[0],
+                       /*file_actions*/ nullptr,
+                       /*spawnattr*/ nullptr, const_cast<char **>(Args),
+                       /*envp*/ nullptr);
+  if (EC)
+    return createStringError(std::error_code(EC, std::generic_category()),
+                             "failed to spawn module build daemon process");
+
+  return llvm::Error::success();
+}
+
+llvm::Error cc1modbuildd::getModuleBuildDaemon(const char *Argv0,
+                                               StringRef BasePath) {
+
+  // If module build daemon already exist return success
+  if (cc1modbuildd::daemonExists(BasePath)) {
+    return llvm::Error::success();
+  }
+
+  if (llvm::Error Err = cc1modbuildd::spawnModuleBuildDaemon(BasePath, Argv0))
+    return std::move(Err);
+
+  const unsigned int MICROSEC_IN_SEC = 1000000;
+  constexpr unsigned int MAX_TIME = 30 * MICROSEC_IN_SEC;
+  const unsigned short INTERVAL = 100;
+
+  unsigned int CumulativeTime = 0;
+  unsigned int WaitTime = 0;
+
+  while (CumulativeTime <= MAX_TIME) {
+    // Wait a bit then check to see if the module build daemon was created
+    usleep(WaitTime);
+    if (cc1modbuildd::daemonExists(BasePath))
+      return llvm::Error::success();
+    CumulativeTime += INTERVAL;
+  }
+
+  // After waiting 30 seconds give up
+  return llvm::make_error<StringError>(
+      "Module build daemon did not exist after spawn attempt",
+      inconvertibleErrorCode());
+}
+
+Expected<int>
+cc1modbuildd::registerTranslationUnit(ArrayRef<const char *> CC1Cmd,
+                                      StringRef Argv0, StringRef BasePath,
+                                      StringRef CWD) {
+
+  std::vector<std::string> Argv0PlusCC1;
+  Argv0PlusCC1.push_back(Argv0.str());
+  Argv0PlusCC1.insert(Argv0PlusCC1.end(), CC1Cmd.begin(), CC1Cmd.end());
+
+  // FIXME: Should not need to append again here
+  SmallString<128> SocketPath = BasePath;
+  llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+
+  cc1modbuildd::SocketMsg Request{ActionType::REGISTER, StatusType::REQUEST,
+                                  CWD.str(), Argv0PlusCC1};
+
+  Expected<int> MaybeServerFD =
+      connectAndWriteSocketMsgToSocket(Request, SocketPath);
+  if (!MaybeServerFD)
+    return std::move(MaybeServerFD.takeError());
+
+  return std::move(*MaybeServerFD);
+}
+
+Expected<std::vector<std::string>> cc1modbuildd::getUpdatedCC1(int ServerFD) {
+
+  // Blocks cc1 invocation until module build daemon is done processing
+  // translation unit. Currently receives a SUCCESS message and returns
+  // llvm::Error::success() but will eventually recive updated cc1 command line
+  Expected<SocketMsg> MaybeServerResponse = readSocketMsgFromSocket(ServerFD);
+  if (!MaybeServerResponse)
+    return std::move(MaybeServerResponse.takeError());
+  SocketMsg ServerResponse = std::move(*MaybeServerResponse);
+
+  // Confirm response is REGISTER and MsgStatus is SUCCESS
+  assert(ServerResponse.MsgAction == ActionType::REGISTER &&
+         "At this point response ActionType should only ever be REGISTER");
+
+  if (ServerResponse.MsgStatus == StatusType::SUCCESS)
+    return ServerResponse.Argv0PlusCC1CommandLine.value();
+
+  return llvm::make_error<StringError>(
+      "Daemon failed to processes registered translation unit",
+      inconvertibleErrorCode());
+}
+
+Expected<std::vector<std::string>>
+cc1modbuildd::updateCC1WithModuleBuildDaemon(ArrayRef<const char *> CC1Cmd,
+                                             const char *Argv0, StringRef CWD) {
+
+  std::string BasePath = cc1modbuildd::getBasePath();
+  std::string ErrMessage;
+
+  // If module build daemon does not exist spawn module build daemon
+  llvm::Error DaemonErr = cc1modbuildd::getModuleBuildDaemon(Argv0, BasePath);
+  if (DaemonErr) {
+    handleAllErrors(std::move(DaemonErr), [&](ErrorInfoBase &EIB) {
+      ErrMessage = "Connect to daemon failed: " + EIB.message();
+    });
+    return llvm::make_error<StringError>(ErrMessage, inconvertibleErrorCode());
+  }
+
+  // Send translation unit information to module build daemon for processing
+  Expected<int> MaybeServerFD =
+      cc1modbuildd::registerTranslationUnit(CC1Cmd, Argv0, BasePath, CWD);
+  if (!MaybeServerFD) {
+    handleAllErrors(
+        std::move(MaybeServerFD.takeError()), [&](ErrorInfoBase &EIB) {
+          ErrMessage = "Register translation unit failed: " + EIB.message();
+        });
+    return llvm::make_error<StringError>(ErrMessage, inconvertibleErrorCode());
+  }
+
+  // Wait for response from module build daemon. Response will hopefully be an
+  // updated cc1 command line with additional -fmodule-file=<file> flags and
+  // implicit module flags removed
+  Expected<std::vector<std::string>> MaybeUpdatedCC1 =
+      cc1modbuildd::getUpdatedCC1(std::move(*MaybeServerFD));
+  if (!MaybeUpdatedCC1) {
+    handleAllErrors(std::move(MaybeUpdatedCC1.takeError()),
+                    [&](ErrorInfoBase &EIB) {
+                      ErrMessage = "Get updated cc1 failed: " + EIB.message();
+                    });
+    return llvm::make_error<StringError>(ErrMessage, inconvertibleErrorCode());
+  }
+
+  // Remove the Argv0 from SocketMsg.Argv0PlusCC1CommandLine
+  std::vector<std::string> UpdatedCC1 = std::move(*MaybeUpdatedCC1);
+  if (!UpdatedCC1.empty()) {
+    UpdatedCC1.erase(UpdatedCC1.begin());
+  }
+  return UpdatedCC1;
+}
+
+#endif // LLVM_ON_UNIX
\ No newline at end of file
Index: clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_library(clangModuleBuildDaemon
+  Protocol.cpp
+  SocketSupport.cpp
+  SocketMsgSupport.cpp
+  )
\ No newline at end of file
Index: clang/lib/Tooling/CMakeLists.txt
===================================================================
--- clang/lib/Tooling/CMakeLists.txt
+++ clang/lib/Tooling/CMakeLists.txt
@@ -13,6 +13,7 @@
 add_subdirectory(Syntax)
 add_subdirectory(DependencyScanning)
 add_subdirectory(Transformer)
+add_subdirectory(ModuleBuildDaemon)
 
 # Replace the last lib component of the current binary directory with include
 string(FIND ${CMAKE_CURRENT_BINARY_DIR} "/lib/" PATH_LIB_START REVERSE)
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5,7 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-
 #include "Clang.h"
 #include "AMDGPU.h"
 #include "Arch/AArch64.h"
@@ -3735,6 +3734,10 @@
        Std->containsValue("c++latest") || Std->containsValue("gnu++latest"));
   bool HaveModules = HaveStdCXXModules;
 
+  // -fmodule-build-daemon enables the module build daemon functionality
+  if (Args.hasArg(options::OPT_fmodule_build_daemon))
+    Args.AddLastArg(CmdArgs, options::OPT_fmodule_build_daemon);
+
   // -fmodules enables the use of precompiled modules (off by default).
   // Users can pass -fno-cxx-modules to turn off modules support for
   // C++/Objective-C++ programs.
Index: clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
===================================================================
--- /dev/null
+++ clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
@@ -0,0 +1,31 @@
+//===-------------------------- SocketSupport.h ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace cc1modbuildd {
+
+Expected<int> createSocket();
+Expected<int> connectToSocket(StringRef SocketPath);
+Expected<int> connectAndWriteToSocket(std::string Buffer, StringRef SocketPath);
+Expected<std::unique_ptr<char[]>> readFromSocket(int FD);
+llvm::Error writeToSocket(std::string Buffer, int WriteFD);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
\ No newline at end of file
Index: clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
===================================================================
--- /dev/null
+++ clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
@@ -0,0 +1,77 @@
+//===------------------------- SocketMsgSupport.h -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
+
+#include "clang/Tooling/ModuleBuildDaemon/Protocol.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace cc1modbuildd {
+
+enum class ActionType { REGISTER, HANDSHAKE };
+enum class StatusType { REQUEST, SUCCESS, FAILURE };
+
+struct SocketMsg {
+  ActionType MsgAction;
+  StatusType MsgStatus;
+  std::optional<std::string> WorkingDirectory;
+  // First element needs to be path to compiler
+  std::optional<std::vector<std::string>> Argv0PlusCC1CommandLine;
+
+  SocketMsg() = default;
+
+  SocketMsg(ActionType Action, StatusType Status,
+            const std::optional<std::string> &CurrentWD,
+            const std::optional<std::vector<std::string>> &CommandLine)
+      : MsgAction(Action), MsgStatus(Status), WorkingDirectory(CurrentWD),
+        Argv0PlusCC1CommandLine(CommandLine) {}
+
+  SocketMsg(ActionType Action, StatusType Status)
+      : MsgAction(Action), MsgStatus(Status), WorkingDirectory(std::nullopt),
+        Argv0PlusCC1CommandLine(std::nullopt) {}
+};
+
+std::string getBufferFromSocketMsg(SocketMsg SocketMsg);
+Expected<SocketMsg> getSocketMsgFromBuffer(char *Buffer);
+Expected<SocketMsg> readSocketMsgFromSocket(int FD);
+llvm::Error writeSocketMsgToSocket(SocketMsg Msg, int FD);
+Expected<int> connectAndWriteSocketMsgToSocket(SocketMsg Msg,
+                                               StringRef SocketPath);
+
+} // namespace cc1modbuildd
+
+template <>
+struct llvm::yaml::ScalarEnumerationTraits<cc1modbuildd::StatusType> {
+  static void enumeration(IO &io, cc1modbuildd::StatusType &value) {
+    io.enumCase(value, "REQUEST", cc1modbuildd::StatusType::REQUEST);
+    io.enumCase(value, "SUCCESS", cc1modbuildd::StatusType::SUCCESS);
+    io.enumCase(value, "FAILURE", cc1modbuildd::StatusType::FAILURE);
+  }
+};
+
+template <>
+struct llvm::yaml::ScalarEnumerationTraits<cc1modbuildd::ActionType> {
+  static void enumeration(IO &io, cc1modbuildd::ActionType &value) {
+    io.enumCase(value, "REGISTER", cc1modbuildd::ActionType::REGISTER);
+    io.enumCase(value, "HANDSHAKE", cc1modbuildd::ActionType::HANDSHAKE);
+  }
+};
+
+template <> struct llvm::yaml::MappingTraits<cc1modbuildd::SocketMsg> {
+  static void mapping(IO &io, cc1modbuildd::SocketMsg &info) {
+    io.mapRequired("Action", info.MsgAction);
+    io.mapRequired("Status", info.MsgStatus);
+    io.mapOptional("WorkingDirectory", info.WorkingDirectory);
+    io.mapOptional("FullCommandLine", info.Argv0PlusCC1CommandLine);
+  }
+};
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
\ No newline at end of file
Index: clang/include/clang/Tooling/ModuleBuildDaemon/Protocol.h
===================================================================
--- /dev/null
+++ clang/include/clang/Tooling/ModuleBuildDaemon/Protocol.h
@@ -0,0 +1,63 @@
+//===----------------------------- Protocol.h -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_PROTOCAL_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_PROTOCAL_H
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#define MAX_BUFFER 4096
+#define SOCKET_FILE_NAME "mbd.sock"
+#define STDOUT_FILE_NAME "mbd.out"
+#define STDERR_FILE_NAME "mbd.err"
+
+using namespace clang;
+using namespace llvm;
+
+namespace cc1modbuildd {
+
+// Create unbuffered STDOUT stream so that any logging done by module build
+// daemon can be viewed without having to terminate the process
+raw_fd_ostream &unbuff_outs();
+
+// Returns where to store log files and socket address. Of the format
+// /tmp/clang-<BLAKE3HashOfClagnFullVersion>/
+std::string getBasePath();
+
+bool daemonExists(StringRef BasePath);
+
+llvm::Error attemptHandshake(int SocketFD);
+
+Expected<int> connectToSocketAndHandshake(StringRef SocketPath);
+
+llvm::Error spawnModuleBuildDaemon(StringRef BasePath, const char *Argv0);
+
+llvm::Error getModuleBuildDaemon(const char *Argv0, StringRef BasePath);
+
+// Sends request to module build daemon
+Expected<int> registerTranslationUnit(ArrayRef<const char *> CC1Cmd,
+                                      StringRef Argv0, StringRef BasePath,
+                                      StringRef CWD);
+
+// Processes response from module build daemon
+Expected<std::vector<std::string>> getUpdatedCC1(int ServerFD);
+
+// Work in progress. Eventually function will modify CC1 command line to include
+// path to modules already built by the daemon
+Expected<std::vector<std::string>>
+updateCC1WithModuleBuildDaemon(ArrayRef<const char *> CC1Cmd, const char *Argv0,
+                               StringRef CWD);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_PROTOCAL_H
Index: clang/include/clang/Frontend/FrontendOptions.h
===================================================================
--- clang/include/clang/Frontend/FrontendOptions.h
+++ clang/include/clang/Frontend/FrontendOptions.h
@@ -347,6 +347,9 @@
   /// Whether to share the FileManager when building modules.
   unsigned ModulesShareFileManager : 1;
 
+  /// Connect to module build daemon
+  unsigned ModuleBuildDaemon : 1;
+
   CodeCompleteOptions CodeCompleteOpts;
 
   /// Specifies the output format of the AST.
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2823,6 +2823,13 @@
   NegFlag<SetFalse, [], [ClangOption], "Disallow">,
   BothFlags<[], [ClangOption, CC1Option],
           " __declspec as a keyword">>, Group<f_clang_Group>;
+
+def fmodule_build_daemon : Flag<["-"], "fmodule-build-daemon">, Group<f_Group>,
+  Flags<[NoXarchOption]>, 
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Enables module build daemon functionality">,
+  MarshallingInfoFlag<FrontendOpts<"ModuleBuildDaemon">>;
+
 def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group<i_Group>,
   Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
   MetaVarName<"<directory>">,
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -514,6 +514,7 @@
 def ModuleConflict : DiagGroup<"module-conflict">;
 def ModuleFileExtension : DiagGroup<"module-file-extension">;
 def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">;
+def ModuleBuildDaemon : DiagGroup<"module-build-daemon">;
 def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">;
 def NewlineEOF : DiagGroup<"newline-eof">;
 def Nullability : DiagGroup<"nullability">;
Index: clang/include/clang/Basic/DiagnosticFrontendKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -261,6 +261,11 @@
   "test module file extension '%0' has different version (%1.%2) than expected "
   "(%3.%4)">;
 
+def remark_mbd_socket_addr : Remark<"mbd created socket address at %0">,
+  InGroup<ModuleBuildDaemon>;
+def remark_mbd_generic_msg : Remark<"%0">,
+  InGroup<ModuleBuildDaemon>;
+
 def err_missing_vfs_overlay_file : Error<
   "virtual filesystem overlay file '%0' not found">, DefaultFatal;
 def err_invalid_vfs_overlay : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to