[clang] [WIP][clang][MBD] Initial implementation of module build daemon (PR #68498)

Connor Sughrue via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 15 12:57:29 PDT 2024


https://github.com/cpsughrue updated https://github.com/llvm/llvm-project/pull/68498

>From 9fe97509277fbce0333c454bb4e2619fed04b189 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sun, 9 Jul 2023 23:19:58 -0400
Subject: [PATCH 1/6] [WIP][clang][MBD] module build daemon

---
 clang/include/clang/Driver/Options.td         |  12 +
 .../include/clang/Frontend/FrontendOptions.h  |   7 +
 .../clang/Tooling/ModuleBuildDaemon/Client.h  |  56 ++
 .../ModuleBuildDaemon/SocketMsgSupport.h      | 166 ++++++
 .../Tooling/ModuleBuildDaemon/SocketSupport.h |  31 +
 .../clang/Tooling/ModuleBuildDaemon/Utils.h   |  28 +
 clang/lib/Driver/ToolChains/Clang.cpp         |  14 +-
 clang/lib/Tooling/CMakeLists.txt              |   1 +
 .../Tooling/ModuleBuildDaemon/CMakeLists.txt  |   9 +
 .../lib/Tooling/ModuleBuildDaemon/Client.cpp  | 224 +++++++
 .../ModuleBuildDaemon/SocketSupport.cpp       | 128 ++++
 clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp |  32 +
 clang/test/Driver/unknown-arg.c               |   2 +-
 clang/test/ModuleBuildDaemon/launch.c         |  10 +
 clang/test/ModuleBuildDaemon/parallel-scan.c  |  31 +
 clang/test/ModuleBuildDaemon/scan.c           |  20 +
 clang/tools/driver/CMakeLists.txt             |   3 +
 clang/tools/driver/cc1_main.cpp               |  74 ++-
 clang/tools/driver/cc1modbuildd_main.cpp      | 553 ++++++++++++++++++
 clang/tools/driver/driver.cpp                 |  17 +-
 20 files changed, 1408 insertions(+), 10 deletions(-)
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
 create mode 100644 clang/test/ModuleBuildDaemon/launch.c
 create mode 100644 clang/test/ModuleBuildDaemon/parallel-scan.c
 create mode 100644 clang/test/ModuleBuildDaemon/scan.c
 create mode 100644 clang/tools/driver/cc1modbuildd_main.cpp

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 5415b18d3f406d..33c24e182fccca 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2883,6 +2883,18 @@ defm declspec : BoolOption<"f", "declspec",
   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 fmodule_build_daemon_EQ : Joined<["-"], "fmodule-build-daemon=">, Group<f_Group>,
+  Flags<[NoXarchOption]>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Enables module build daemon functionality and defines location of output files">,
+  MarshallingInfoString<FrontendOpts<"ModuleBuildDaemonPath">>;
+
 def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group<i_Group>,
   Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
   MetaVarName<"<directory>">,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 117e35de6f76c4..8ce97a57d413c0 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -350,6 +350,9 @@ class FrontendOptions {
   /// 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.
@@ -435,6 +438,10 @@ class FrontendOptions {
   /// The output file, if any.
   std::string OutputFile;
 
+  /// If given, the path to the module build daemon's output files and socket
+  /// address
+  std::string ModuleBuildDaemonPath;
+
   /// If given, the new suffix for fix-it rewritten files.
   std::string FixItSuffix;
 
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
new file mode 100644
index 00000000000000..5d5df74743a6a6
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
@@ -0,0 +1,56 @@
+//===----------------------------- 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_CLIENT_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_CLIENT_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 {
+
+// Returns where to store log files and socket address. Of the format
+// /tmp/clang-<BLAKE3HashOfClagnFullVersion>/
+std::string getBasePath();
+
+llvm::Error attemptHandshake(int SocketFD);
+
+llvm::Error spawnModuleBuildDaemon(StringRef BasePath, const char *Argv0);
+
+Expected<int> getModuleBuildDaemon(const char *Argv0, StringRef BasePath);
+
+// Sends request to module build daemon
+llvm::Error registerTranslationUnit(ArrayRef<const char *> CC1Cmd,
+                                    StringRef Argv0, StringRef CWD,
+                                    int ServerFD);
+
+// 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(const CompilerInvocation &Clang,
+                               ArrayRef<const char *> CC1Cmd, const char *Argv0,
+                               StringRef CWD);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_PROTOCAL_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
new file mode 100644
index 00000000000000..c02a426054f117
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
@@ -0,0 +1,166 @@
+//===------------------------- 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/Client.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace cc1modbuildd {
+
+enum class ActionType { REGISTER, HANDSHAKE };
+enum class StatusType { REQUEST, SUCCESS, FAILURE };
+
+struct BaseMsg {
+  ActionType MsgAction;
+  StatusType MsgStatus;
+
+  BaseMsg() = default;
+  BaseMsg(ActionType Action, StatusType Status)
+      : MsgAction(Action), MsgStatus(Status) {}
+};
+
+struct RegisterMsg : public BaseMsg {
+  std::optional<std::string> WorkingDirectory;
+  // The scanner requires the path to the clang executable
+  std::optional<std::string> ExecutablePath;
+  // Does not include executable
+  std::optional<std::vector<std::string>> CC1CommandLine;
+
+  RegisterMsg() = default;
+
+  RegisterMsg(ActionType Action, StatusType Status,
+              const std::optional<std::string> &CurrentWD,
+              const std::optional<std::string> &Argv0,
+              const std::optional<std::vector<std::string>> &Argv)
+      : BaseMsg(Action, Status), WorkingDirectory(CurrentWD),
+        ExecutablePath(Argv0), CC1CommandLine(Argv) {}
+
+  RegisterMsg(ActionType Action, StatusType Status)
+      : BaseMsg(Action, Status), WorkingDirectory(std::nullopt),
+        ExecutablePath(std::nullopt), CC1CommandLine(std::nullopt) {}
+};
+
+struct HandshakeMsg : public BaseMsg {
+  HandshakeMsg() = default;
+  HandshakeMsg(ActionType Action, StatusType Status)
+      : BaseMsg(Action, Status) {}
+};
+
+template <typename T> std::string getBufferFromSocketMsg(T Msg) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  std::string Buffer;
+  llvm::raw_string_ostream OS(Buffer);
+  llvm::yaml::Output YamlOut(OS);
+
+  YamlOut << Msg;
+  return Buffer;
+}
+
+template <typename T> Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  T 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;
+}
+
+template <typename T> Expected<T> readSocketMsgFromSocket(int FD) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  Expected<std::string> MaybeResponseBuffer = readFromSocket(FD);
+  if (!MaybeResponseBuffer)
+    return std::move(MaybeResponseBuffer.takeError());
+
+  // Wait for response from module build daemon
+  Expected<T> MaybeResponse =
+      getSocketMsgFromBuffer<T>(std::move(*MaybeResponseBuffer).c_str());
+  if (!MaybeResponse)
+    return std::move(MaybeResponse.takeError());
+  return std::move(*MaybeResponse);
+}
+
+template <typename T> llvm::Error writeSocketMsgToSocket(T Msg, int FD) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  std::string Buffer = getBufferFromSocketMsg(Msg);
+  if (llvm::Error Err = writeToSocket(Buffer, FD))
+    return std::move(Err);
+
+  return llvm::Error::success();
+}
+
+template <typename T>
+Expected<int> connectAndWriteSocketMsgToSocket(T Msg, StringRef SocketPath) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  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;
+}
+
+} // 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::RegisterMsg> {
+  static void mapping(IO &Io, cc1modbuildd::RegisterMsg &Info) {
+    Io.mapRequired("Action", Info.MsgAction);
+    Io.mapRequired("Status", Info.MsgStatus);
+    Io.mapOptional("WorkingDirectory", Info.WorkingDirectory);
+    Io.mapOptional("ExecutablePath", Info.ExecutablePath);
+    Io.mapOptional("CC1CommandLine", Info.CC1CommandLine);
+  }
+};
+
+template <> struct llvm::yaml::MappingTraits<cc1modbuildd::HandshakeMsg> {
+  static void mapping(IO &Io, cc1modbuildd::HandshakeMsg &Info) {
+    Io.mapRequired("Action", Info.MsgAction);
+    Io.mapRequired("Status", Info.MsgStatus);
+  }
+};
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
new file mode 100644
index 00000000000000..bc21084faab396
--- /dev/null
+++ b/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::string> readFromSocket(int FD);
+llvm::Error writeToSocket(std::string Buffer, int WriteFD);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
new file mode 100644
index 00000000000000..79a2ffc3c1804d
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
@@ -0,0 +1,28 @@
+//===------------------------------ Utils.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions required by both the module build daemon (server) and clang
+// invocation (client)
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
+
+#include "llvm/Support/Error.h"
+#include <string>
+
+namespace cc1modbuildd {
+
+void writeError(llvm::Error Err, std::string Msg);
+std::string getFullErrorMsg(llvm::Error Err, std::string Msg);
+llvm::Error makeStringError(llvm::Error Err, std::string Msg);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
\ No newline at end of file
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index bfd6c5c2864abf..62fbcae0f87cf4 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/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"
@@ -3740,6 +3739,19 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
        Std->containsValue("c++latest") || Std->containsValue("gnu++latest"));
   bool HaveModules = HaveStdCXXModules;
 
+  // -fmodule-build-daemon enables module build daemon functionality
+  if (Args.hasArg(options::OPT_fmodule_build_daemon))
+    Args.AddLastArg(CmdArgs, options::OPT_fmodule_build_daemon);
+
+  // by default module build daemon socket address and output files are saved
+  // under /tmp/ but that can be overridden by providing the
+  // -fmodule-build-daemon=<path> flag
+  if (Arg *A = Args.getLastArg(options::OPT_fmodule_build_daemon_EQ)) {
+    CmdArgs.push_back(
+        Args.MakeArgString(Twine("-fmodule-build-daemon=") + A->getValue()));
+    CmdArgs.push_back("-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.
diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt
index aff39e4de13c0b..85752e57733265 100644
--- a/clang/lib/Tooling/CMakeLists.txt
+++ b/clang/lib/Tooling/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(DumpTool)
 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)
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt b/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
new file mode 100644
index 00000000000000..9c1f5dc1aa2c0c
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_library(clangModuleBuildDaemon
+  Client.cpp
+  SocketSupport.cpp
+  Utils.cpp
+  )
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
new file mode 100644
index 00000000000000..08fe14476c901b
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
@@ -0,0 +1,224 @@
+//===----------------------------- Client.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/Client.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/Utils.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;
+using namespace cc1modbuildd;
+
+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();
+}
+
+llvm::Error cc1modbuildd::attemptHandshake(int SocketFD) {
+
+  cc1modbuildd::HandshakeMsg Request{ActionType::HANDSHAKE,
+                                     StatusType::REQUEST};
+  std::string Buffer = cc1modbuildd::getBufferFromSocketMsg(Request);
+
+  if (llvm::Error Err = writeToSocket(Buffer, SocketFD))
+    return std::move(Err);
+
+  Expected<RegisterMsg> MaybeServerResponse =
+      readSocketMsgFromSocket<RegisterMsg>(SocketFD);
+  if (!MaybeServerResponse)
+    return std::move(MaybeServerResponse.takeError());
+  RegisterMsg 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());
+}
+
+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();
+}
+
+Expected<int> cc1modbuildd::getModuleBuildDaemon(const char *Argv0,
+                                                 StringRef BasePath) {
+
+  SmallString<128> SocketPath = BasePath;
+  llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+
+  if (llvm::sys::fs::exists(SocketPath)) {
+    Expected<int> MaybeFD = connectToSocket(SocketPath);
+    if (MaybeFD)
+      return std::move(*MaybeFD);
+    consumeError(MaybeFD.takeError());
+  }
+
+  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 has initialized
+    usleep(WaitTime);
+
+    if (llvm::sys::fs::exists(SocketPath)) {
+      Expected<int> MaybeFD = connectToSocket(SocketPath);
+      if (MaybeFD)
+        return std::move(*MaybeFD);
+      consumeError(MaybeFD.takeError());
+    }
+
+    CumulativeTime += INTERVAL;
+  }
+
+  // After waiting 30 seconds give up
+  return llvm::make_error<StringError>(
+      "Module build daemon did not exist after spawn attempt",
+      inconvertibleErrorCode());
+}
+
+llvm::Error
+cc1modbuildd::registerTranslationUnit(ArrayRef<const char *> CC1Command,
+                                      StringRef Argv0, StringRef CWD,
+                                      int ServerFD) {
+
+  std::vector<std::string> StrCC1Command;
+  for (const char *Arg : CC1Command)
+    StrCC1Command.emplace_back(Arg);
+
+  cc1modbuildd::RegisterMsg Request{ActionType::REGISTER, StatusType::REQUEST,
+                                    CWD.str(), Argv0.str(), StrCC1Command};
+
+  llvm::Error WriteErr = writeSocketMsgToSocket(Request, ServerFD);
+  if (WriteErr)
+    return std::move(WriteErr);
+
+  return llvm::Error::success();
+}
+
+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<RegisterMsg> MaybeServerResponse =
+      readSocketMsgFromSocket<RegisterMsg>(ServerFD);
+  if (!MaybeServerResponse)
+    return std::move(MaybeServerResponse.takeError());
+  RegisterMsg 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.CC1CommandLine.value();
+
+  return llvm::make_error<StringError>(
+      "Daemon failed to processes registered translation unit",
+      inconvertibleErrorCode());
+}
+
+Expected<std::vector<std::string>>
+cc1modbuildd::updateCC1WithModuleBuildDaemon(const CompilerInvocation &Clang,
+                                             ArrayRef<const char *> CC1Cmd,
+                                             const char *Argv0, StringRef CWD) {
+
+  // The module build daemon stores all output files and its socket address
+  // under BasePath. Either set BasePath to a user provided option or create an
+  // appropriate BasePath based on the hash of the clang version
+  std::string BasePath;
+  if (!Clang.getFrontendOpts().ModuleBuildDaemonPath.empty())
+    BasePath = Clang.getFrontendOpts().ModuleBuildDaemonPath;
+  else
+    BasePath = cc1modbuildd::getBasePath();
+
+  // If module build daemon does not exist spawn module build daemon
+  Expected<int> MaybeDaemonFD =
+      cc1modbuildd::getModuleBuildDaemon(Argv0, BasePath);
+  if (!MaybeDaemonFD)
+    return makeStringError(MaybeDaemonFD.takeError(),
+                           "Connect to daemon failed: ");
+  int DaemonFD = std::move(*MaybeDaemonFD);
+
+  if (llvm::Error HandshakeErr = attemptHandshake(DaemonFD))
+    return makeStringError(std::move(HandshakeErr),
+                           "Failed to hadshake with daemon: ");
+
+  // Send translation unit information to module build daemon for processing
+  if (llvm::Error RegisterErr =
+          registerTranslationUnit(CC1Cmd, Argv0, CWD, DaemonFD))
+    return makeStringError(std::move(RegisterErr),
+                           "Register translation unti failed: ");
+
+  // 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 = getUpdatedCC1(DaemonFD);
+  if (!MaybeUpdatedCC1)
+    return makeStringError(MaybeUpdatedCC1.takeError(),
+                           "Failed to get updated CC1: ");
+  return std::move(*MaybeUpdatedCC1);
+}
+
+#endif // LLVM_ON_UNIX
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
new file mode 100644
index 00000000000000..58526e4422f457
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
@@ -0,0 +1,128 @@
+//===------------------------- 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/Client.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::string> cc1modbuildd::readFromSocket(int FD) {
+
+  const size_t BUFFER_SIZE = 4096;
+  std::vector<char> Buffer(BUFFER_SIZE);
+  size_t TotalBytesRead = 0;
+
+  ssize_t n;
+  while ((n = read(FD, Buffer.data() + TotalBytesRead,
+                   Buffer.size() - TotalBytesRead)) > 0) {
+
+    TotalBytesRead += n;
+    // Read until ...\n encountered (last line of YAML document)
+    if (std::string(&Buffer[TotalBytesRead - 4], 4) == "...\n")
+      break;
+    if (Buffer.size() - TotalBytesRead < BUFFER_SIZE)
+      Buffer.resize(Buffer.size() + BUFFER_SIZE);
+  }
+
+  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 std::string(Buffer.begin(), Buffer.end());
+}
+
+llvm::Error cc1modbuildd::writeToSocket(std::string Buffer, int WriteFD) {
+
+  ssize_t BytesToWrite = static_cast<ssize_t>(Buffer.size());
+  const char *Bytes = Buffer.c_str();
+
+  while (BytesToWrite) {
+    ssize_t BytesWritten = write(WriteFD, Bytes, BytesToWrite);
+    if (BytesWritten == -1) {
+      std::string Msg = "socket write error: " + std::string(strerror(errno));
+      return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+    }
+
+    if (!BytesWritten || BytesWritten > BytesToWrite)
+      return llvm::errorCodeToError(
+          std::error_code(EIO, std::generic_category()));
+
+    BytesToWrite -= BytesWritten;
+    Bytes += BytesWritten;
+  }
+  return llvm::Error::success();
+}
+
+#endif // LLVM_ON_UNIX
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
new file mode 100644
index 00000000000000..c03e8e3762114f
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
@@ -0,0 +1,32 @@
+//===------------------------------ Utils.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/Utils.h>
+#include <llvm/Support/Error.h>
+#include <string>
+
+using namespace llvm;
+
+void cc1modbuildd::writeError(llvm::Error Err, std::string Msg) {
+  handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+    errs() << Msg << EIB.message() << '\n';
+  });
+}
+
+std::string cc1modbuildd::getFullErrorMsg(llvm::Error Err, std::string Msg) {
+  std::string ErrMessage;
+  handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+    ErrMessage = Msg + EIB.message();
+  });
+  return ErrMessage;
+}
+
+llvm::Error cc1modbuildd::makeStringError(llvm::Error Err, std::string Msg) {
+  std::string ErrMsg = getFullErrorMsg(std::move(Err), Msg);
+  return llvm::make_error<StringError>(ErrMsg, inconvertibleErrorCode());
+}
\ No newline at end of file
diff --git a/clang/test/Driver/unknown-arg.c b/clang/test/Driver/unknown-arg.c
index 52ea0f5ff3220f..3a22b824adc5c7 100644
--- a/clang/test/Driver/unknown-arg.c
+++ b/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', '-cc1gen-reproducer', and '-cc1modbuildd'.
 
 // RUN: %clang -S %s -o %t.s  -Wunknown-to-clang-option 2>&1 | FileCheck --check-prefix=IGNORED %s
 
diff --git a/clang/test/ModuleBuildDaemon/launch.c b/clang/test/ModuleBuildDaemon/launch.c
new file mode 100644
index 00000000000000..575aba0ac3ce60
--- /dev/null
+++ b/clang/test/ModuleBuildDaemon/launch.c
@@ -0,0 +1,10 @@
+// REQUIRES: !system-windows
+
+// RUN: if pgrep -f "cc1modbuildd mbd-launch"; then pkill -f "cc1modbuildd mbd-launch"; fi
+
+// RUN: %clang -cc1modbuildd mbd-launch -v
+// RUN: cat mbd-launch/mbd.out | FileCheck %s -DPREFIX=%t
+
+// CHECK: mbd created and binded to socket address at: mbd-launch/mbd.sock
+
+// RUN: if pgrep -f "cc1modbuildd mbd-launch"; then pkill -f "cc1modbuildd mbd-launch"; fi
\ No newline at end of file
diff --git a/clang/test/ModuleBuildDaemon/parallel-scan.c b/clang/test/ModuleBuildDaemon/parallel-scan.c
new file mode 100644
index 00000000000000..0dddaa0f161457
--- /dev/null
+++ b/clang/test/ModuleBuildDaemon/parallel-scan.c
@@ -0,0 +1,31 @@
+// Confirm module build daemon can handle two translation units simultaneously
+
+// REQUIRES: !system-windows
+
+// RUN: if pgrep -f "cc1modbuildd parallel-scan"; then pkill -f "cc1modbuildd parallel-scan"; fi
+// : rm -rf parallel-scan
+// RUN: split-file %s %t
+
+//--- main.c
+#include "app.h"
+int main() {return 0;}
+
+//--- app.c
+#include "util.h"
+
+//--- app.h
+
+//--- util.h
+
+// RUN: %clang -fmodule-build-daemon=parallel-scan %t/main.c %t/app.c
+// RUN: pwd && ls 
+// RUN: cat parallel-scan/mbd.out
+// RUN: cat parallel-scan/mbd.out | FileCheck %s -DPREFIX=%t
+
+// CHECK: main.c
+// CHECK: app.h
+// CHECK: app.c
+// CHECK: util.h
+
+// RUN: if pgrep -f "cc1modbuildd parallel-scan"; then pkill -f "cc1modbuildd parallel-scan"; fi
+// : rm -rf parallel-scan
diff --git a/clang/test/ModuleBuildDaemon/scan.c b/clang/test/ModuleBuildDaemon/scan.c
new file mode 100644
index 00000000000000..f70210362ab644
--- /dev/null
+++ b/clang/test/ModuleBuildDaemon/scan.c
@@ -0,0 +1,20 @@
+// REQUIRES: !system-windows
+
+// RUN: if pgrep -f "cc1modbuildd scan"; then pkill -f "cc1modbuildd scan"; fi
+// RUN: rm -rf scan
+// RUN: split-file %s %t
+
+//--- main.c
+#include "header.h"
+int main() {return 0;}
+
+//--- header.h
+
+// RUN: %clang -fmodule-build-daemon=scan %t/main.c
+// RUN: cat scan/mbd.out | FileCheck %s -DPREFIX=%t
+
+// CHECK: main.c
+// CHECK: header.h
+
+// RUN: if pgrep -f "cc1modbuildd scan"; then pkill -f "cc1modbuildd scan"; fi
+// RUN: rm -rf scan
diff --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt
index 2182486f93a555..9f4c7a01f84893 100644
--- a/clang/tools/driver/CMakeLists.txt
+++ b/clang/tools/driver/CMakeLists.txt
@@ -28,6 +28,7 @@ add_clang_tool(clang
   cc1_main.cpp
   cc1as_main.cpp
   cc1gen_reproducer_main.cpp
+  cc1modbuildd_main.cpp
 
   DEPENDS
   intrinsics_gen
@@ -39,9 +40,11 @@ clang_target_link_libraries(clang
   PRIVATE
   clangBasic
   clangCodeGen
+  clangDependencyScanning
   clangDriver
   clangFrontend
   clangFrontendTool
+  clangModuleBuildDaemon
   clangSerialization
   )
 
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index e9d2c6aad371db..b4b19c7e778226 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/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/Client.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/LinkAllPasses.h"
@@ -63,7 +64,7 @@ using namespace llvm::opt;
 
 static void LLVMErrorHandler(void *UserData, const char *Message,
                              bool GenCrashDiag) {
-  DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+  DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine *>(UserData);
 
   Diags.Report(diag::err_fe_error_backend) << Message;
 
@@ -251,8 +252,69 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
     Diags.setSeverity(diag::remark_cc1_round_trip_generated,
                       diag::Severity::Remark, {});
 
-  bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
-                                                    Argv, Diags, Argv0);
+  std::shared_ptr<CompilerInvocation> Invocation =
+      std::make_shared<CompilerInvocation>();
+  bool Success =
+      CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags, Argv0);
+
+  // FIXME: does not actually flush any diagnostics
+  DiagsBuffer->FlushDiagnostics(Diags);
+  if (!Success) {
+    DiagsBuffer->finish();
+    return 1;
+  }
+
+  // The module build daemon may update the cc1 args and needs someplace to
+  // store a modified command line for the lifetime of the compilation
+  std::vector<std::string> UpdatedArgv;
+  std::vector<const char *> CharUpdatedArgv;
+
+#if LLVM_ON_UNIX
+  // Handle module build daemon functionality if enabled
+  if (Invocation->getFrontendOpts().ModuleBuildDaemon) {
+
+    // Scanner needs cc1 invocations working directory
+    IntrusiveRefCntPtr<vfs::FileSystem> System =
+        createVFSFromCompilerInvocation(*Invocation, Diags);
+    ErrorOr<std::string> MaybeCWD = System->getCurrentWorkingDirectory();
+
+    if (MaybeCWD.getError()) {
+      errs() << "Could not get working directory: "
+             << MaybeCWD.getError().message() << "\n";
+      return 1;
+    }
+
+    Expected<std::vector<std::string>> MaybeUpdatedArgv =
+        cc1modbuildd::updateCC1WithModuleBuildDaemon(*Invocation, Argv, Argv0,
+                                                     *MaybeCWD);
+    if (!MaybeUpdatedArgv) {
+      errs() << toString(std::move(MaybeUpdatedArgv.takeError())) << '\n';
+      return 1;
+    }
+
+    // CompilerInvocation::CreateFromArgs expects an ArrayRef<const char *>
+    UpdatedArgv = std::move(*MaybeUpdatedArgv);
+    CharUpdatedArgv.reserve(UpdatedArgv.size());
+    for (const auto &Arg : UpdatedArgv) {
+      CharUpdatedArgv.push_back(Arg.c_str());
+    }
+  }
+#endif
+
+  outs() << "translation unit command line" << '\n';
+  for (const auto &Arg : Argv)
+    outs() << Arg << " ";
+  outs() << "\n";
+
+  // If Argv was modified by the module build daemon create new Invocation
+  if (!Argv.equals(ArrayRef<const char *>(CharUpdatedArgv)) &&
+      !CharUpdatedArgv.empty()) {
+    Argv = ArrayRef<const char *>(CharUpdatedArgv);
+    Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv,
+                                                 Diags, Argv0);
+  } else {
+    Clang->setInvocation(Invocation);
+  }
 
   if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
     llvm::timeTraceProfilerInitialize(
@@ -270,7 +332,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
     Clang->getHeaderSearchOpts().ResourceDir =
-      CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
+        CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
 
   // Create the actual diagnostics engine.
   Clang->createDiagnostics();
@@ -279,8 +341,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
   // Set an error handler, so that any LLVM backend diagnostics go through our
   // error handler.
-  llvm::install_fatal_error_handler(LLVMErrorHandler,
-                                  static_cast<void*>(&Clang->getDiagnostics()));
+  llvm::install_fatal_error_handler(
+      LLVMErrorHandler, static_cast<void *>(&Clang->getDiagnostics()));
 
   DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
   if (!Success) {
diff --git a/clang/tools/driver/cc1modbuildd_main.cpp b/clang/tools/driver/cc1modbuildd_main.cpp
new file mode 100644
index 00000000000000..96b95c1c8509bf
--- /dev/null
+++ b/clang/tools/driver/cc1modbuildd_main.cpp
@@ -0,0 +1,553 @@
+//===------- 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/SocketMsgSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/Utils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Program.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 <mutex>
+#include <optional>
+#include <signal.h>
+#include <sstream>
+#include <stdbool.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <type_traits>
+#include <unistd.h>
+#include <unordered_map>
+
+using namespace llvm;
+using namespace clang;
+using namespace tooling::dependencies;
+using namespace cc1modbuildd;
+
+// Create unbuffered STDOUT stream so that any logging done by module build
+// daemon can be viewed without having to terminate the process
+static raw_fd_ostream &unbuff_outs() {
+  static raw_fd_ostream S(STDOUT_FILENO, false, true);
+  return S;
+}
+
+namespace {
+
+enum class BuildStatus { WAITING, BUILDING, BUILT };
+
+struct ModuleIDHash {
+  std::size_t
+  operator()(const clang::tooling::dependencies::ModuleID &ID) const {
+    return llvm::hash_value(ID);
+  }
+};
+
+struct ModuleBuildInfo {
+  const ModuleDeps Info;
+  BuildStatus ModuleBuildStatus;
+};
+
+// Thread safe hash map that stores dependency and build information
+class DependencyBuildData {
+public:
+  void insert(ModuleID Key, ModuleBuildInfo Value) {
+    std::lock_guard<std::mutex> lock(Mutex);
+    HashMap.insert({Key, Value});
+  }
+
+  std::optional<std::reference_wrapper<ModuleBuildInfo>> get(ModuleID Key) {
+    std::lock_guard<std::mutex> lock(Mutex);
+    if (auto search = HashMap.find(Key); search != HashMap.end())
+      return std::ref(search->second);
+    return std::nullopt;
+  }
+
+  bool updateBuildStatus(ModuleID Key, BuildStatus newStatus) {
+    std::lock_guard<std::mutex> lock(Mutex);
+    if (auto search = HashMap.find(Key); search != HashMap.end()) {
+      search->second.ModuleBuildStatus = newStatus;
+      return true;
+    }
+    return false;
+  }
+
+  void print() {
+    unbuff_outs() << "printing hash table keys" << '\n';
+    for (const auto &i : HashMap) {
+      unbuff_outs() << "Module: " << i.first.ModuleName << '\n';
+      unbuff_outs() << "Dependencies: ";
+      for (const auto &Dep : i.second.Info.ClangModuleDeps)
+        unbuff_outs() << Dep.ModuleName << ", ";
+      unbuff_outs() << '\n';
+    }
+  }
+
+private:
+  std::unordered_map<ModuleID, ModuleBuildInfo, ModuleIDHash> HashMap;
+  std::mutex Mutex;
+};
+
+class ModuleBuildDaemonServer {
+public:
+  SmallString<128> BasePath;
+  SmallString<128> SocketPath;
+  SmallString<128> PidPath;
+
+  ModuleBuildDaemonServer(SmallString<128> Path, ArrayRef<const char *> Argv)
+      : BasePath(Path), SocketPath(Path) {
+    llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+  }
+
+  ~ModuleBuildDaemonServer() { shutdownDaemon(SIGTERM); }
+
+  int forkDaemon();
+  int launchDaemon();
+  int listenForClients();
+
+  static void handleClient(int Client);
+  static void handleRegister(int Client, RegisterMsg ClientRequest);
+
+  void shutdownDaemon(int signal) {
+    unlink(SocketPath.c_str());
+    shutdown(ListenSocketFD, SHUT_RD);
+    close(ListenSocketFD);
+    exit(EXIT_SUCCESS);
+  }
+
+private:
+  // Initializes and returns DiagnosticsEngine
+  pid_t Pid = -1;
+  int ListenSocketFD = -1;
+};
+
+// Required to handle SIGTERM by calling Shutdown
+ModuleBuildDaemonServer *DaemonPtr = nullptr;
+void handleSignal(int Signal) {
+  if (DaemonPtr != nullptr) {
+    DaemonPtr->shutdownDaemon(Signal);
+  }
+}
+} // namespace
+
+static bool verbose = false;
+static void verbose_print(const llvm::Twine &message) {
+  if (verbose) {
+    unbuff_outs() << message << '\n';
+  }
+}
+
+static DependencyBuildData DaemonBuildData;
+
+static Expected<TranslationUnitDeps>
+scanTranslationUnit(cc1modbuildd::RegisterMsg 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 "/tmp/" + MID.ContextHash;
+  };
+
+  // Add executable path to cc1 command line for dependency scanner
+  std::vector<std::string> ScannerCommandLine;
+  ScannerCommandLine.push_back(Request.ExecutablePath.value());
+  ScannerCommandLine.insert(ScannerCommandLine.end(),
+                            Request.CC1CommandLine.value().begin(),
+                            Request.CC1CommandLine.value().end());
+
+  Expected<TranslationUnitDeps> MaybeTUDeps =
+      Tool.getTranslationUnitDependencies(ScannerCommandLine,
+                                          Request.WorkingDirectory.value(),
+                                          AlreadySeenModules, LookupOutput);
+
+  if (!MaybeTUDeps)
+    return std::move(MaybeTUDeps.takeError());
+
+  return std::move(*MaybeTUDeps);
+}
+
+static void storeScanResults(const TranslationUnitDeps &Results) {
+
+  if (Results.ModuleGraph.empty())
+    return;
+
+  // Insert children
+  for (const ModuleDeps &MD : Results.ModuleGraph)
+    DaemonBuildData.insert(MD.ID, {MD, BuildStatus::WAITING});
+}
+
+// Remove -fmodule-build-daemon and add -fno-implicit-modules to command line.
+// Return value can either be a std::vector of std::string or StringRef
+template <typename T>
+static std::vector<T> modifyCC1(const std::vector<std::string> &CommandLine) {
+  static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, StringRef>);
+
+  std::vector<T> ReturnArgs;
+  ReturnArgs.reserve(CommandLine.size());
+
+  for (const auto &Arg : CommandLine) {
+    if (Arg != "-fmodule-build-daemon")
+      ReturnArgs.emplace_back(Arg);
+  }
+  ReturnArgs.emplace_back("-fno-implicit-modules");
+  return ReturnArgs;
+}
+
+// TODO: Return llvm::Error
+static void precompileModuleID(const StringRef Executable, const ModuleID ID) {
+  unbuff_outs() << "module " << ID.ModuleName << " will be built" << '\n';
+
+  std::optional<std::reference_wrapper<ModuleBuildInfo>> MaybeDeps =
+      DaemonBuildData.get(ID);
+  if (!MaybeDeps)
+    return;
+  ModuleBuildInfo &Deps = MaybeDeps->get();
+
+  // TODO: look into making getBuildArguments a const method
+  ModuleDeps &NonConstDepsInfo = const_cast<ModuleDeps &>(Deps.Info);
+  const std::vector<std::string> &Args = NonConstDepsInfo.getBuildArguments();
+  std::vector<std::string> NonConstArgs =
+      const_cast<std::vector<std::string> &>(Args);
+
+  unbuff_outs() << "original command line" << '\n';
+  for (const auto &Arg : Args)
+    unbuff_outs() << Arg << " ";
+  unbuff_outs() << "\n\n";
+
+  const std::vector<StringRef> ProcessedArgs =
+      modifyCC1<StringRef>(NonConstArgs);
+
+  std::vector<StringRef> ExecuteCommandLine;
+  ExecuteCommandLine.push_back(Executable);
+  ExecuteCommandLine.insert(ExecuteCommandLine.end(), ProcessedArgs.begin(),
+                            ProcessedArgs.end());
+
+  unbuff_outs() << "new command line" << '\n';
+  for (const auto &Arg : NonConstArgs)
+    unbuff_outs() << Arg << " ";
+  unbuff_outs() << "\n";
+
+  // TODO: Handle error code returned from ExecuteAndWait
+  llvm::sys::ExecuteAndWait(Executable,
+                            ArrayRef<StringRef>(ExecuteCommandLine));
+  DaemonBuildData.updateBuildStatus(ID, BuildStatus::BUILT);
+
+  unbuff_outs() << "module " << ID.ModuleName << " finished building" << '\n';
+  unbuff_outs() << "\n\n";
+
+  return;
+}
+
+// TODO: implement concurrent approach
+// can only handle one translation unit at a time
+static void buildModuleID(const StringRef Executable, const ModuleID ID) {
+
+  std::optional<std::reference_wrapper<ModuleBuildInfo>> MaybeDeps =
+      DaemonBuildData.get(ID);
+  if (!MaybeDeps)
+    return;
+  ModuleBuildInfo &Deps = MaybeDeps->get();
+
+  if (Deps.ModuleBuildStatus == BuildStatus::BUILT)
+    return;
+
+  for (const ModuleID &Dep : Deps.Info.ClangModuleDeps)
+    buildModuleID(Executable, Dep);
+
+  // Do not build the root ID aka the registered translation unit
+  if (ID.ModuleName.empty())
+    return;
+
+  precompileModuleID(Executable, ID);
+  return;
+}
+
+// Takes a client request in the form of a cc1modbuildd::SocketMsg and
+// returns an updated cc1 command line for the registered cc1 invocation
+// after building all modular dependencies
+static Expected<std::vector<std::string>>
+processRegisterRequest(cc1modbuildd::RegisterMsg Request) {
+
+  Expected<TranslationUnitDeps> MaybeTUDeps = scanTranslationUnit(Request);
+  if (!MaybeTUDeps)
+    return std::move(MaybeTUDeps.takeError());
+  const TranslationUnitDeps TUDeps = std::move(*MaybeTUDeps);
+
+  // For now write dependencies to log file
+  for (const auto &Dep : TUDeps.FileDeps)
+    unbuff_outs() << Dep << '\n';
+
+  // If TU does not depend on modules then return command line as is
+  if (TUDeps.ModuleGraph.empty())
+    return Request.CC1CommandLine.value();
+
+  unbuff_outs() << "modules detected" << '\n';
+  storeScanResults(TUDeps);
+  DaemonBuildData.print();
+
+  // Build all direct and transitive dependencies by iterating over direct
+  // dependencies
+  for (const ModuleID &Dep : TUDeps.ClangModuleDeps)
+    buildModuleID(Request.ExecutablePath.value(), Dep);
+
+  return modifyCC1<std::string>(TUDeps.Commands[0].Arguments);
+}
+
+// Forks and detaches process, creating module build daemon
+int ModuleBuildDaemonServer::forkDaemon() {
+
+  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::launchDaemon() {
+
+  // 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);
+  }
+  verbose_print("mbd created and binded to socket address at: " + 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);
+  }
+
+  return 0;
+}
+
+void ModuleBuildDaemonServer::handleRegister(int Client,
+                                             RegisterMsg ClientRequest) {
+
+  Expected<std::vector<std::string>> MaybeExplicitCC1 =
+      processRegisterRequest(ClientRequest);
+
+  // if getUpdatedCC1 fails emit error
+  if (!MaybeExplicitCC1) {
+
+    RegisterMsg Msg(ActionType::REGISTER, StatusType::FAILURE);
+    llvm::Error RegisterFailureWriteErr = writeSocketMsgToSocket(Msg, Client);
+
+    if (RegisterFailureWriteErr) {
+      writeError(llvm::joinErrors(std::move(RegisterFailureWriteErr),
+                                  std::move(MaybeExplicitCC1.takeError())),
+                 "Failed to process register request and was unable to notify "
+                 "clang infocation: ");
+      return;
+    }
+    writeError(MaybeExplicitCC1.takeError(),
+               "Failed to process register request: ");
+    return;
+  }
+
+  // getUpdateCC1 success
+  std::vector<std::string> ExplicitCC1 = std::move(*MaybeExplicitCC1);
+
+  unbuff_outs() << "modified command line for translation unit" << '\n';
+  for (const auto &Arg : ExplicitCC1)
+    unbuff_outs() << Arg << " ";
+  unbuff_outs() << "\n";
+
+  // Send new CC1 command line to waiting clang invocation
+  RegisterMsg Msg(ActionType::REGISTER, StatusType::SUCCESS,
+                  ClientRequest.WorkingDirectory, ClientRequest.ExecutablePath,
+                  ExplicitCC1);
+
+  llvm::Error RegisterSuccessWriteErr = writeSocketMsgToSocket(Msg, Client);
+
+  if (RegisterSuccessWriteErr) {
+    writeError(std::move(RegisterSuccessWriteErr),
+               "Failed to notify clang invocation that register request was a "
+               "success: ");
+    return;
+  }
+  return;
+}
+
+// Function submitted to thread pool with each client connection. Not
+// responsible for closing client connections
+void ModuleBuildDaemonServer::handleClient(int Client) {
+
+  // Read handshake from client
+  Expected<HandshakeMsg> MaybeHandshake =
+      readSocketMsgFromSocket<HandshakeMsg>(Client);
+
+  if (!MaybeHandshake) {
+    writeError(MaybeHandshake.takeError(),
+               "Failed to read handshake message from socket: ");
+    return;
+  }
+
+  // Handle HANDSHAKE
+  RegisterMsg Msg(ActionType::HANDSHAKE, StatusType::SUCCESS);
+  llvm::Error WriteErr = writeSocketMsgToSocket(Msg, Client);
+
+  if (WriteErr) {
+    writeError(std::move(WriteErr),
+               "Failed to notify client that handshake was received");
+    return;
+  }
+
+  // Read register request from client
+  Expected<RegisterMsg> MaybeRegister =
+      readSocketMsgFromSocket<RegisterMsg>(Client);
+
+  if (!MaybeRegister) {
+    writeError(MaybeRegister.takeError(),
+               "Failed to read registration message from socket: ");
+    return;
+  }
+
+  RegisterMsg Register = std::move(*MaybeRegister);
+  handleRegister(Client, Register);
+  return;
+}
+
+int ModuleBuildDaemonServer::listenForClients() {
+
+  llvm::ThreadPool Pool;
+  int Client;
+
+  while (true) {
+
+    if ((Client = accept(ListenSocketFD, NULL, NULL)) == -1) {
+      std::perror("Socket accept error: ");
+      continue;
+    }
+
+    Pool.async(handleClient, Client);
+  }
+  return 0;
+}
+
+// Module build daemon is spawned with the following command line:
+//
+// clang -cc1modbuildd <path> -v
+//
+// <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>
+//
+// -v is optional and provides 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;
+
+  if (find(Argv, StringRef("-v")) != Argv.end())
+    verbose = true;
+
+  Daemon.forkDaemon();
+  Daemon.launchDaemon();
+  Daemon.listenForClients();
+
+  return 0;
+}
+
+#endif // LLVM_ON_UNIX
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 531b5b4a61c180..9697bc6d457776 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -213,6 +213,9 @@ extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
 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,19 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
   if (Tool == "-cc1gen-reproducer")
     return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0],
                                   GetExecutablePathVP, ToolContext);
-  // Reject unknown tools.
+  if (Tool == "-cc1modbuildd") {
+#if LLVM_ON_UNIX
+    return cc1modbuildd_main(ArrayRef(ArgV).slice(2));
+#else
+    llvm::errs() << "-cc1modbuildd not supported by current platform" << '\n';
+    return 1;
+#endif
+  }
+
+  // Reject unknown tools
   llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
-               << "Valid tools include '-cc1' and '-cc1as'.\n";
+               << "Valid tools include '-cc1', '-cc1as', '-cc1gen-reproducer', "
+                  "and '-cc1modbuildd'.\n";
   return 1;
 }
 

>From 749d0489b403686b225dbaa39af5ba4f2626ff50 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sat, 7 Oct 2023 16:54:25 -0400
Subject: [PATCH 2/6] temporarily remove tests. if a test fails daemon will
 never terminate

---
 clang/test/ModuleBuildDaemon/launch.c        | 10 -------
 clang/test/ModuleBuildDaemon/parallel-scan.c | 31 --------------------
 clang/test/ModuleBuildDaemon/scan.c          | 20 -------------
 3 files changed, 61 deletions(-)
 delete mode 100644 clang/test/ModuleBuildDaemon/launch.c
 delete mode 100644 clang/test/ModuleBuildDaemon/parallel-scan.c
 delete mode 100644 clang/test/ModuleBuildDaemon/scan.c

diff --git a/clang/test/ModuleBuildDaemon/launch.c b/clang/test/ModuleBuildDaemon/launch.c
deleted file mode 100644
index 575aba0ac3ce60..00000000000000
--- a/clang/test/ModuleBuildDaemon/launch.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// REQUIRES: !system-windows
-
-// RUN: if pgrep -f "cc1modbuildd mbd-launch"; then pkill -f "cc1modbuildd mbd-launch"; fi
-
-// RUN: %clang -cc1modbuildd mbd-launch -v
-// RUN: cat mbd-launch/mbd.out | FileCheck %s -DPREFIX=%t
-
-// CHECK: mbd created and binded to socket address at: mbd-launch/mbd.sock
-
-// RUN: if pgrep -f "cc1modbuildd mbd-launch"; then pkill -f "cc1modbuildd mbd-launch"; fi
\ No newline at end of file
diff --git a/clang/test/ModuleBuildDaemon/parallel-scan.c b/clang/test/ModuleBuildDaemon/parallel-scan.c
deleted file mode 100644
index 0dddaa0f161457..00000000000000
--- a/clang/test/ModuleBuildDaemon/parallel-scan.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// Confirm module build daemon can handle two translation units simultaneously
-
-// REQUIRES: !system-windows
-
-// RUN: if pgrep -f "cc1modbuildd parallel-scan"; then pkill -f "cc1modbuildd parallel-scan"; fi
-// : rm -rf parallel-scan
-// RUN: split-file %s %t
-
-//--- main.c
-#include "app.h"
-int main() {return 0;}
-
-//--- app.c
-#include "util.h"
-
-//--- app.h
-
-//--- util.h
-
-// RUN: %clang -fmodule-build-daemon=parallel-scan %t/main.c %t/app.c
-// RUN: pwd && ls 
-// RUN: cat parallel-scan/mbd.out
-// RUN: cat parallel-scan/mbd.out | FileCheck %s -DPREFIX=%t
-
-// CHECK: main.c
-// CHECK: app.h
-// CHECK: app.c
-// CHECK: util.h
-
-// RUN: if pgrep -f "cc1modbuildd parallel-scan"; then pkill -f "cc1modbuildd parallel-scan"; fi
-// : rm -rf parallel-scan
diff --git a/clang/test/ModuleBuildDaemon/scan.c b/clang/test/ModuleBuildDaemon/scan.c
deleted file mode 100644
index f70210362ab644..00000000000000
--- a/clang/test/ModuleBuildDaemon/scan.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// REQUIRES: !system-windows
-
-// RUN: if pgrep -f "cc1modbuildd scan"; then pkill -f "cc1modbuildd scan"; fi
-// RUN: rm -rf scan
-// RUN: split-file %s %t
-
-//--- main.c
-#include "header.h"
-int main() {return 0;}
-
-//--- header.h
-
-// RUN: %clang -fmodule-build-daemon=scan %t/main.c
-// RUN: cat scan/mbd.out | FileCheck %s -DPREFIX=%t
-
-// CHECK: main.c
-// CHECK: header.h
-
-// RUN: if pgrep -f "cc1modbuildd scan"; then pkill -f "cc1modbuildd scan"; fi
-// RUN: rm -rf scan

>From e5c4868c5c4647ed330aed1234dea4f4abdc55c5 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Thu, 15 Aug 2024 08:49:18 -0400
Subject: [PATCH 3/6] fix formatting

---
 clang/include/clang/Frontend/FrontendOptions.h | 2 +-
 clang/tools/driver/cc1_main.cpp                | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 5821e121bfd76c..d928e11a973347 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -397,7 +397,7 @@ class FrontendOptions {
 
   /// Connect to module build daemon
   unsigned ModuleBuildDaemon : 1;
-  
+
   /// Whether to emit symbol graph files as a side effect of compilation.
   LLVM_PREFERRED_TYPE(bool)
   unsigned EmitSymbolGraph : 1;
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index f08958f93e74ee..6547d74a31fcd3 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -25,8 +25,8 @@
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Frontend/Utils.h"
 #include "clang/FrontendTool/Utils.h"
-#include "clang/Tooling/ModuleBuildDaemon/Client.h"
 #include "clang/Serialization/ObjectFilePCHContainerReader.h"
+#include "clang/Tooling/ModuleBuildDaemon/Client.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/llvm-config.h"

>From 579a69c5e4faa92d5fdd7e31547095026bce90f6 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Thu, 15 Aug 2024 10:19:09 -0400
Subject: [PATCH 4/6] Changes to get clang to compile

---
 .../clang/Tooling/ModuleBuildDaemon/Client.h  | 22 ++++++++---------
 .../ModuleBuildDaemon/SocketMsgSupport.h      | 17 ++++++-------
 .../Tooling/ModuleBuildDaemon/SocketSupport.h | 11 ++++-----
 .../lib/Tooling/ModuleBuildDaemon/Client.cpp  |  2 +-
 .../ModuleBuildDaemon/SocketSupport.cpp       | 24 +++++++++----------
 clang/tools/driver/cc1_main.cpp               | 14 +++++------
 clang/tools/driver/cc1modbuildd_main.cpp      |  6 ++---
 7 files changed, 43 insertions(+), 53 deletions(-)

diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
index 5d5df74743a6a6..f8bd93267c9126 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
@@ -15,15 +15,13 @@
 #include "llvm/Config/llvm-config.h"
 #include "llvm/Support/YAMLParser.h"
 #include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/Error.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 {
 
 // Returns where to store log files and socket address. Of the format
@@ -32,24 +30,24 @@ std::string getBasePath();
 
 llvm::Error attemptHandshake(int SocketFD);
 
-llvm::Error spawnModuleBuildDaemon(StringRef BasePath, const char *Argv0);
+llvm::Error spawnModuleBuildDaemon(llvm::StringRef BasePath, const char *Argv0);
 
-Expected<int> getModuleBuildDaemon(const char *Argv0, StringRef BasePath);
+llvm::Expected<int> getModuleBuildDaemon(const char *Argv0, llvm::StringRef BasePath);
 
 // Sends request to module build daemon
-llvm::Error registerTranslationUnit(ArrayRef<const char *> CC1Cmd,
-                                    StringRef Argv0, StringRef CWD,
+llvm::Error registerTranslationUnit(llvm::ArrayRef<const char *> CC1Cmd,
+                                    llvm::StringRef Argv0, llvm::StringRef CWD,
                                     int ServerFD);
 
 // Processes response from module build daemon
-Expected<std::vector<std::string>> getUpdatedCC1(int ServerFD);
+llvm::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(const CompilerInvocation &Clang,
-                               ArrayRef<const char *> CC1Cmd, const char *Argv0,
-                               StringRef CWD);
+llvm::Expected<std::vector<std::string>>
+updateCC1WithModuleBuildDaemon(const clang::CompilerInvocation &Clang,
+                               llvm::ArrayRef<const char *> CC1Cmd, const char *Argv0,
+                               llvm::StringRef CWD);
 
 } // namespace cc1modbuildd
 
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
index c02a426054f117..482fed3830a1ee 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
@@ -12,9 +12,6 @@
 #include "clang/Tooling/ModuleBuildDaemon/Client.h"
 #include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
 
-using namespace clang;
-using namespace llvm;
-
 namespace cc1modbuildd {
 
 enum class ActionType { REGISTER, HANDSHAKE };
@@ -68,7 +65,7 @@ template <typename T> std::string getBufferFromSocketMsg(T Msg) {
   return Buffer;
 }
 
-template <typename T> Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
+template <typename T> llvm::Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
   static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
                 "T must inherit from cc1modbuildd::BaseMsg");
 
@@ -78,22 +75,22 @@ template <typename T> Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
 
   if (YamlIn.error()) {
     std::string Msg = "Syntax or semantic error during YAML parsing";
-    return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+    return llvm::make_error<llvm::StringError>(Msg, llvm::inconvertibleErrorCode());
   }
 
   return ClientRequest;
 }
 
-template <typename T> Expected<T> readSocketMsgFromSocket(int FD) {
+template <typename T> llvm::Expected<T> readSocketMsgFromSocket(int FD) {
   static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
                 "T must inherit from cc1modbuildd::BaseMsg");
 
-  Expected<std::string> MaybeResponseBuffer = readFromSocket(FD);
+  llvm::Expected<std::string> MaybeResponseBuffer = readFromSocket(FD);
   if (!MaybeResponseBuffer)
     return std::move(MaybeResponseBuffer.takeError());
 
   // Wait for response from module build daemon
-  Expected<T> MaybeResponse =
+  llvm::Expected<T> MaybeResponse =
       getSocketMsgFromBuffer<T>(std::move(*MaybeResponseBuffer).c_str());
   if (!MaybeResponse)
     return std::move(MaybeResponse.takeError());
@@ -112,11 +109,11 @@ template <typename T> llvm::Error writeSocketMsgToSocket(T Msg, int FD) {
 }
 
 template <typename T>
-Expected<int> connectAndWriteSocketMsgToSocket(T Msg, StringRef SocketPath) {
+llvm::Expected<int> connectAndWriteSocketMsgToSocket(T Msg, llvm::StringRef SocketPath) {
   static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
                 "T must inherit from cc1modbuildd::BaseMsg");
 
-  Expected<int> MaybeFD = connectToSocket(SocketPath);
+  llvm::Expected<int> MaybeFD = connectToSocket(SocketPath);
   if (!MaybeFD)
     return std::move(MaybeFD.takeError());
   int FD = std::move(*MaybeFD);
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
index bc21084faab396..645ea1d8db11e2 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
@@ -15,15 +15,12 @@
 #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::string> readFromSocket(int FD);
+llvm::Expected<int> createSocket();
+llvm::Expected<int> connectToSocket(llvm::StringRef SocketPath);
+llvm::Expected<int> connectAndWriteToSocket(std::string Buffer, llvm::StringRef SocketPath);
+llvm::Expected<std::string> readFromSocket(int FD);
 llvm::Error writeToSocket(std::string Buffer, int WriteFD);
 
 } // namespace cc1modbuildd
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
index 08fe14476c901b..4018d70a30ea5e 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
@@ -42,7 +42,7 @@ std::string cc1modbuildd::getBasePath() {
   Hash.update(getClangFullVersion());
   auto HashResult = Hash.final<sizeof(uint64_t)>();
   uint64_t HashValue =
-      llvm::support::endian::read<uint64_t, llvm::support::native>(
+      llvm::support::endian::read<uint64_t, llvm::endianness::native>(
           HashResult.data());
   std::string Key = toString(llvm::APInt(64, HashValue), 36, /*Signed*/ false);
 
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
index 58526e4422f457..bfecf18d9e86ea 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
+++ b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
@@ -31,18 +31,18 @@
 #include <sys/un.h>
 #include <unistd.h>
 
-Expected<int> cc1modbuildd::createSocket() {
+llvm::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 llvm::createStringError(llvm::inconvertibleErrorCode(), Msg);
   }
   return FD;
 }
 
-Expected<int> cc1modbuildd::connectToSocket(StringRef SocketPath) {
+llvm::Expected<int> cc1modbuildd::connectToSocket(llvm::StringRef SocketPath) {
 
-  Expected<int> MaybeFD = cc1modbuildd::createSocket();
+  llvm::Expected<int> MaybeFD = cc1modbuildd::createSocket();
   if (!MaybeFD)
     return std::move(MaybeFD.takeError());
 
@@ -56,15 +56,15 @@ Expected<int> cc1modbuildd::connectToSocket(StringRef SocketPath) {
   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 llvm::createStringError(llvm::inconvertibleErrorCode(), msg);
   }
   return FD;
 }
 
-Expected<int> cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
-                                                    StringRef SocketPath) {
+llvm::Expected<int> cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
+                                                    llvm::StringRef SocketPath) {
 
-  Expected<int> MaybeConnectedFD = connectToSocket(SocketPath);
+  llvm::Expected<int> MaybeConnectedFD = connectToSocket(SocketPath);
   if (!MaybeConnectedFD)
     return std::move(MaybeConnectedFD.takeError());
 
@@ -76,7 +76,7 @@ Expected<int> cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
   return ConnectedFD;
 }
 
-Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
+llvm::Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
 
   const size_t BUFFER_SIZE = 4096;
   std::vector<char> Buffer(BUFFER_SIZE);
@@ -96,10 +96,10 @@ Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
 
   if (n < 0) {
     std::string Msg = "socket read error: " + std::string(strerror(errno));
-    return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+    return llvm::make_error<llvm::StringError>(Msg, llvm::inconvertibleErrorCode());
   }
   if (n == 0)
-    return llvm::make_error<StringError>("EOF", inconvertibleErrorCode());
+    return llvm::make_error<llvm::StringError>("EOF", llvm::inconvertibleErrorCode());
   return std::string(Buffer.begin(), Buffer.end());
 }
 
@@ -112,7 +112,7 @@ llvm::Error cc1modbuildd::writeToSocket(std::string Buffer, int WriteFD) {
     ssize_t BytesWritten = write(WriteFD, Bytes, BytesToWrite);
     if (BytesWritten == -1) {
       std::string Msg = "socket write error: " + std::string(strerror(errno));
-      return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+      return llvm::make_error<llvm::StringError>(Msg, llvm::inconvertibleErrorCode());
     }
 
     if (!BytesWritten || BytesWritten > BytesToWrite)
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 6547d74a31fcd3..b8d3ebf239cbef 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -260,12 +260,12 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (Invocation->getFrontendOpts().ModuleBuildDaemon) {
 
     // Scanner needs cc1 invocations working directory
-    IntrusiveRefCntPtr<vfs::FileSystem> System =
+    IntrusiveRefCntPtr<llvm::vfs::FileSystem> System =
         createVFSFromCompilerInvocation(*Invocation, Diags);
-    ErrorOr<std::string> MaybeCWD = System->getCurrentWorkingDirectory();
+    llvm::ErrorOr<std::string> MaybeCWD = System->getCurrentWorkingDirectory();
 
     if (MaybeCWD.getError()) {
-      errs() << "Could not get working directory: "
+      llvm::errs() << "Could not get working directory: "
              << MaybeCWD.getError().message() << "\n";
       return 1;
     }
@@ -274,7 +274,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
         cc1modbuildd::updateCC1WithModuleBuildDaemon(*Invocation, Argv, Argv0,
                                                      *MaybeCWD);
     if (!MaybeUpdatedArgv) {
-      errs() << toString(std::move(MaybeUpdatedArgv.takeError())) << '\n';
+      llvm::errs() << toString(std::move(MaybeUpdatedArgv.takeError())) << '\n';
       return 1;
     }
 
@@ -287,10 +287,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   }
 #endif
 
-  outs() << "translation unit command line" << '\n';
+  llvm::outs() << "translation unit command line" << '\n';
   for (const auto &Arg : Argv)
-    outs() << Arg << " ";
-  outs() << "\n";
+    llvm::outs() << Arg << " ";
+  llvm::outs() << "\n";
 
   // If Argv was modified by the module build daemon create new Invocation
   if (!Argv.equals(ArrayRef<const char *>(CharUpdatedArgv)) &&
diff --git a/clang/tools/driver/cc1modbuildd_main.cpp b/clang/tools/driver/cc1modbuildd_main.cpp
index 96b95c1c8509bf..df30a3b8787f68 100644
--- a/clang/tools/driver/cc1modbuildd_main.cpp
+++ b/clang/tools/driver/cc1modbuildd_main.cpp
@@ -166,9 +166,7 @@ static Expected<TranslationUnitDeps>
 scanTranslationUnit(cc1modbuildd::RegisterMsg Request) {
 
   DependencyScanningService Service(ScanningMode::DependencyDirectivesScan,
-                                    ScanningOutputFormat::Full,
-                                    /*OptimizeArgs*/ false,
-                                    /*EagerLoadModules*/ false);
+                                    ScanningOutputFormat::Full);
 
   DependencyScanningTool Tool(Service);
   llvm::DenseSet<ModuleID> AlreadySeenModules;
@@ -492,7 +490,7 @@ void ModuleBuildDaemonServer::handleClient(int Client) {
 
 int ModuleBuildDaemonServer::listenForClients() {
 
-  llvm::ThreadPool Pool;
+  llvm::DefaultThreadPool Pool;
   int Client;
 
   while (true) {

>From b0f4d9cf8bfa19bb981d52e85ce960768ff1e839 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Thu, 15 Aug 2024 10:29:32 -0400
Subject: [PATCH 5/6] formatting fixes

---
 .../clang/Tooling/ModuleBuildDaemon/Client.h       |  9 +++++----
 .../Tooling/ModuleBuildDaemon/SocketMsgSupport.h   |  9 ++++++---
 .../Tooling/ModuleBuildDaemon/SocketSupport.h      |  3 ++-
 .../Tooling/ModuleBuildDaemon/SocketSupport.cpp    | 14 +++++++++-----
 clang/tools/driver/cc1_main.cpp                    |  2 +-
 5 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
index f8bd93267c9126..c17f46cfe25104 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
@@ -13,9 +13,9 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/YAMLParser.h"
 #include "llvm/Support/YAMLTraits.h"
-#include "llvm/Support/Error.h"
 
 #define MAX_BUFFER 4096
 #define SOCKET_FILE_NAME "mbd.sock"
@@ -32,7 +32,8 @@ llvm::Error attemptHandshake(int SocketFD);
 
 llvm::Error spawnModuleBuildDaemon(llvm::StringRef BasePath, const char *Argv0);
 
-llvm::Expected<int> getModuleBuildDaemon(const char *Argv0, llvm::StringRef BasePath);
+llvm::Expected<int> getModuleBuildDaemon(const char *Argv0,
+                                         llvm::StringRef BasePath);
 
 // Sends request to module build daemon
 llvm::Error registerTranslationUnit(llvm::ArrayRef<const char *> CC1Cmd,
@@ -46,8 +47,8 @@ llvm::Expected<std::vector<std::string>> getUpdatedCC1(int ServerFD);
 // path to modules already built by the daemon
 llvm::Expected<std::vector<std::string>>
 updateCC1WithModuleBuildDaemon(const clang::CompilerInvocation &Clang,
-                               llvm::ArrayRef<const char *> CC1Cmd, const char *Argv0,
-                               llvm::StringRef CWD);
+                               llvm::ArrayRef<const char *> CC1Cmd,
+                               const char *Argv0, llvm::StringRef CWD);
 
 } // namespace cc1modbuildd
 
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
index 482fed3830a1ee..2408a852e995fe 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
@@ -65,7 +65,8 @@ template <typename T> std::string getBufferFromSocketMsg(T Msg) {
   return Buffer;
 }
 
-template <typename T> llvm::Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
+template <typename T>
+llvm::Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
   static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
                 "T must inherit from cc1modbuildd::BaseMsg");
 
@@ -75,7 +76,8 @@ template <typename T> llvm::Expected<T> getSocketMsgFromBuffer(const char *Buffe
 
   if (YamlIn.error()) {
     std::string Msg = "Syntax or semantic error during YAML parsing";
-    return llvm::make_error<llvm::StringError>(Msg, llvm::inconvertibleErrorCode());
+    return llvm::make_error<llvm::StringError>(Msg,
+                                               llvm::inconvertibleErrorCode());
   }
 
   return ClientRequest;
@@ -109,7 +111,8 @@ template <typename T> llvm::Error writeSocketMsgToSocket(T Msg, int FD) {
 }
 
 template <typename T>
-llvm::Expected<int> connectAndWriteSocketMsgToSocket(T Msg, llvm::StringRef SocketPath) {
+llvm::Expected<int>
+connectAndWriteSocketMsgToSocket(T Msg, llvm::StringRef SocketPath) {
   static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
                 "T must inherit from cc1modbuildd::BaseMsg");
 
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
index 645ea1d8db11e2..3dae1a00779da0 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
@@ -19,7 +19,8 @@ namespace cc1modbuildd {
 
 llvm::Expected<int> createSocket();
 llvm::Expected<int> connectToSocket(llvm::StringRef SocketPath);
-llvm::Expected<int> connectAndWriteToSocket(std::string Buffer, llvm::StringRef SocketPath);
+llvm::Expected<int> connectAndWriteToSocket(std::string Buffer,
+                                            llvm::StringRef SocketPath);
 llvm::Expected<std::string> readFromSocket(int FD);
 llvm::Error writeToSocket(std::string Buffer, int WriteFD);
 
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
index bfecf18d9e86ea..8a25b8f0bfd9df 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
+++ b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
@@ -61,8 +61,9 @@ llvm::Expected<int> cc1modbuildd::connectToSocket(llvm::StringRef SocketPath) {
   return FD;
 }
 
-llvm::Expected<int> cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
-                                                    llvm::StringRef SocketPath) {
+llvm::Expected<int>
+cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
+                                      llvm::StringRef SocketPath) {
 
   llvm::Expected<int> MaybeConnectedFD = connectToSocket(SocketPath);
   if (!MaybeConnectedFD)
@@ -96,10 +97,12 @@ llvm::Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
 
   if (n < 0) {
     std::string Msg = "socket read error: " + std::string(strerror(errno));
-    return llvm::make_error<llvm::StringError>(Msg, llvm::inconvertibleErrorCode());
+    return llvm::make_error<llvm::StringError>(Msg,
+                                               llvm::inconvertibleErrorCode());
   }
   if (n == 0)
-    return llvm::make_error<llvm::StringError>("EOF", llvm::inconvertibleErrorCode());
+    return llvm::make_error<llvm::StringError>("EOF",
+                                               llvm::inconvertibleErrorCode());
   return std::string(Buffer.begin(), Buffer.end());
 }
 
@@ -112,7 +115,8 @@ llvm::Error cc1modbuildd::writeToSocket(std::string Buffer, int WriteFD) {
     ssize_t BytesWritten = write(WriteFD, Bytes, BytesToWrite);
     if (BytesWritten == -1) {
       std::string Msg = "socket write error: " + std::string(strerror(errno));
-      return llvm::make_error<llvm::StringError>(Msg, llvm::inconvertibleErrorCode());
+      return llvm::make_error<llvm::StringError>(
+          Msg, llvm::inconvertibleErrorCode());
     }
 
     if (!BytesWritten || BytesWritten > BytesToWrite)
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index b8d3ebf239cbef..3573d6f7e43b27 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -266,7 +266,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
     if (MaybeCWD.getError()) {
       llvm::errs() << "Could not get working directory: "
-             << MaybeCWD.getError().message() << "\n";
+                   << MaybeCWD.getError().message() << "\n";
       return 1;
     }
 

>From 9f1a11ad20d82983488252891e4288ebf4dd35b2 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Thu, 15 Aug 2024 14:37:27 -0400
Subject: [PATCH 6/6] Incorporate raw_socket_stream work

---
 .../clang/Basic/DiagnosticFrontendKinds.td    |  21 +
 clang/include/clang/Basic/DiagnosticGroups.td |   1 +
 .../clang/Tooling/ModuleBuildDaemon/Client.h  |  55 ---
 .../Tooling/ModuleBuildDaemon/Frontend.h      |  50 +++
 .../ModuleBuildDaemon/SocketMsgSupport.h      | 166 --------
 .../Tooling/ModuleBuildDaemon/SocketSupport.h | 155 ++++++-
 .../clang/Tooling/ModuleBuildDaemon/Utils.h   |  39 +-
 .../Tooling/ModuleBuildDaemon/CMakeLists.txt  |   2 +-
 .../lib/Tooling/ModuleBuildDaemon/Client.cpp  | 224 ----------
 .../Tooling/ModuleBuildDaemon/Frontend.cpp    | 222 ++++++++++
 .../ModuleBuildDaemon/SocketSupport.cpp       | 138 ++-----
 clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp |  48 ++-
 clang/tools/driver/cc1_main.cpp               |   8 +-
 clang/tools/driver/cc1modbuildd_main.cpp      | 381 ++++++++++--------
 clang/tools/driver/driver.cpp                 |   2 -
 15 files changed, 755 insertions(+), 757 deletions(-)
 delete mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/Frontend.h
 delete mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
 delete mode 100644 clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/Frontend.cpp

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 8a1462c670d68f..293b19227a521e 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -267,6 +267,27 @@ def err_test_module_file_extension_version : Error<
   "test module file extension '%0' has different version (%1.%2) than expected "
   "(%3.%4)">;
 
+// Module Build Daemon
+def err_path_length :
+  Error<"path '%0' is longer then the max length of %1">,
+  DefaultFatal;
+def err_mbd_handshake :
+  Error<"attempt to handshake with module build daemon has failed: %0">,
+  DefaultFatal;
+def err_mbd_connect :
+  Error<"attempt to connect to module build daemon has failed: %0">,
+  DefaultFatal;
+def remark_mbd_spawn :
+  Remark<"successfully spawned module build daemon">,
+  InGroup<ModuleBuildDaemon>;
+def remark_mbd_connection :
+  Remark<"successfully connected to module build daemon at %0">,
+  InGroup<ModuleBuildDaemon>;
+def remark_mbd_handshake :
+  Remark<"clang invocation responsible for %0 successfully completed handshake "
+         "with module build daemon">,
+  InGroup<ModuleBuildDaemon>;
+
 def warn_eagerly_load_for_standard_cplusplus_modules : Warning<
   "the form '-fmodule-file=<BMI-path>' is deprecated for standard C++ named modules;"
   "consider to use '-fmodule-file=<module-name>=<BMI-path>' instead">,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 19c3f1e0433496..427540fe12443c 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -552,6 +552,7 @@ def MissingFieldInitializers : DiagGroup<"missing-field-initializers",
                                          [MissingDesignatedFieldInitializers]>;
 def ModuleLock : DiagGroup<"module-lock">;
 def ModuleBuild : DiagGroup<"module-build">;
+def ModuleBuildDaemon : DiagGroup<"module-build-daemon">;
 def ModuleImport : DiagGroup<"module-import">;
 def ModuleConflict : DiagGroup<"module-conflict">;
 def ModuleFileExtension : DiagGroup<"module-file-extension">;
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
deleted file mode 100644
index c17f46cfe25104..00000000000000
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//===----------------------------- 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_CLIENT_H
-#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_CLIENT_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/Error.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"
-
-namespace cc1modbuildd {
-
-// Returns where to store log files and socket address. Of the format
-// /tmp/clang-<BLAKE3HashOfClagnFullVersion>/
-std::string getBasePath();
-
-llvm::Error attemptHandshake(int SocketFD);
-
-llvm::Error spawnModuleBuildDaemon(llvm::StringRef BasePath, const char *Argv0);
-
-llvm::Expected<int> getModuleBuildDaemon(const char *Argv0,
-                                         llvm::StringRef BasePath);
-
-// Sends request to module build daemon
-llvm::Error registerTranslationUnit(llvm::ArrayRef<const char *> CC1Cmd,
-                                    llvm::StringRef Argv0, llvm::StringRef CWD,
-                                    int ServerFD);
-
-// Processes response from module build daemon
-llvm::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
-llvm::Expected<std::vector<std::string>>
-updateCC1WithModuleBuildDaemon(const clang::CompilerInvocation &Clang,
-                               llvm::ArrayRef<const char *> CC1Cmd,
-                               const char *Argv0, llvm::StringRef CWD);
-
-} // namespace cc1modbuildd
-
-#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_PROTOCAL_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Frontend.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Frontend.h
new file mode 100644
index 00000000000000..c885473a51dfc9
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Frontend.h
@@ -0,0 +1,50 @@
+//===----------------------------- Frontend.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_FRONTEND_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_FRONTEND_H
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_socket_stream.h"
+
+namespace clang::tooling::cc1modbuildd {
+
+llvm::Error attemptHandshake(llvm::raw_socket_stream &Client);
+
+llvm::Error spawnModuleBuildDaemon(const clang::CompilerInvocation &Clang,
+                                   const char *Argv0,
+                                   clang::DiagnosticsEngine &Diag,
+                                   std::string BasePath);
+
+llvm::Expected<std::unique_ptr<llvm::raw_socket_stream>>
+getModuleBuildDaemon(const clang::CompilerInvocation &Clang, const char *Argv0,
+                     clang::DiagnosticsEngine &Diag, llvm::StringRef BasePath);
+
+// Sends request to module build daemon
+llvm::Error registerTranslationUnit(llvm::ArrayRef<const char *> CC1Cmd,
+                                    llvm::StringRef Argv0, llvm::StringRef CWD,
+                                    llvm::raw_socket_stream &Client);
+
+// Processes response from module build daemon
+llvm::Expected<std::vector<std::string>>
+getUpdatedCC1(llvm::raw_socket_stream &Client);
+
+// Work in progress. Eventually function will modify CC1 command line to include
+// path to modules already built by the daemon
+llvm::Expected<std::vector<std::string>> updateCC1WithModuleBuildDaemon(
+    const clang::CompilerInvocation &Clang, llvm::ArrayRef<const char *> CC1Cmd,
+    const char *Argv0, llvm::StringRef CWD, clang::DiagnosticsEngine &Diag);
+
+} // namespace clang::tooling::cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_FRONTEND_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
deleted file mode 100644
index 2408a852e995fe..00000000000000
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
+++ /dev/null
@@ -1,166 +0,0 @@
-//===------------------------- 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/Client.h"
-#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
-
-namespace cc1modbuildd {
-
-enum class ActionType { REGISTER, HANDSHAKE };
-enum class StatusType { REQUEST, SUCCESS, FAILURE };
-
-struct BaseMsg {
-  ActionType MsgAction;
-  StatusType MsgStatus;
-
-  BaseMsg() = default;
-  BaseMsg(ActionType Action, StatusType Status)
-      : MsgAction(Action), MsgStatus(Status) {}
-};
-
-struct RegisterMsg : public BaseMsg {
-  std::optional<std::string> WorkingDirectory;
-  // The scanner requires the path to the clang executable
-  std::optional<std::string> ExecutablePath;
-  // Does not include executable
-  std::optional<std::vector<std::string>> CC1CommandLine;
-
-  RegisterMsg() = default;
-
-  RegisterMsg(ActionType Action, StatusType Status,
-              const std::optional<std::string> &CurrentWD,
-              const std::optional<std::string> &Argv0,
-              const std::optional<std::vector<std::string>> &Argv)
-      : BaseMsg(Action, Status), WorkingDirectory(CurrentWD),
-        ExecutablePath(Argv0), CC1CommandLine(Argv) {}
-
-  RegisterMsg(ActionType Action, StatusType Status)
-      : BaseMsg(Action, Status), WorkingDirectory(std::nullopt),
-        ExecutablePath(std::nullopt), CC1CommandLine(std::nullopt) {}
-};
-
-struct HandshakeMsg : public BaseMsg {
-  HandshakeMsg() = default;
-  HandshakeMsg(ActionType Action, StatusType Status)
-      : BaseMsg(Action, Status) {}
-};
-
-template <typename T> std::string getBufferFromSocketMsg(T Msg) {
-  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
-                "T must inherit from cc1modbuildd::BaseMsg");
-
-  std::string Buffer;
-  llvm::raw_string_ostream OS(Buffer);
-  llvm::yaml::Output YamlOut(OS);
-
-  YamlOut << Msg;
-  return Buffer;
-}
-
-template <typename T>
-llvm::Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
-  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
-                "T must inherit from cc1modbuildd::BaseMsg");
-
-  T 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<llvm::StringError>(Msg,
-                                               llvm::inconvertibleErrorCode());
-  }
-
-  return ClientRequest;
-}
-
-template <typename T> llvm::Expected<T> readSocketMsgFromSocket(int FD) {
-  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
-                "T must inherit from cc1modbuildd::BaseMsg");
-
-  llvm::Expected<std::string> MaybeResponseBuffer = readFromSocket(FD);
-  if (!MaybeResponseBuffer)
-    return std::move(MaybeResponseBuffer.takeError());
-
-  // Wait for response from module build daemon
-  llvm::Expected<T> MaybeResponse =
-      getSocketMsgFromBuffer<T>(std::move(*MaybeResponseBuffer).c_str());
-  if (!MaybeResponse)
-    return std::move(MaybeResponse.takeError());
-  return std::move(*MaybeResponse);
-}
-
-template <typename T> llvm::Error writeSocketMsgToSocket(T Msg, int FD) {
-  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
-                "T must inherit from cc1modbuildd::BaseMsg");
-
-  std::string Buffer = getBufferFromSocketMsg(Msg);
-  if (llvm::Error Err = writeToSocket(Buffer, FD))
-    return std::move(Err);
-
-  return llvm::Error::success();
-}
-
-template <typename T>
-llvm::Expected<int>
-connectAndWriteSocketMsgToSocket(T Msg, llvm::StringRef SocketPath) {
-  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
-                "T must inherit from cc1modbuildd::BaseMsg");
-
-  llvm::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;
-}
-
-} // 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::RegisterMsg> {
-  static void mapping(IO &Io, cc1modbuildd::RegisterMsg &Info) {
-    Io.mapRequired("Action", Info.MsgAction);
-    Io.mapRequired("Status", Info.MsgStatus);
-    Io.mapOptional("WorkingDirectory", Info.WorkingDirectory);
-    Io.mapOptional("ExecutablePath", Info.ExecutablePath);
-    Io.mapOptional("CC1CommandLine", Info.CC1CommandLine);
-  }
-};
-
-template <> struct llvm::yaml::MappingTraits<cc1modbuildd::HandshakeMsg> {
-  static void mapping(IO &Io, cc1modbuildd::HandshakeMsg &Info) {
-    Io.mapRequired("Action", Info.MsgAction);
-    Io.mapRequired("Status", Info.MsgStatus);
-  }
-};
-
-#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
index 3dae1a00779da0..255b2bf0c7916d 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
@@ -5,7 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-
 #ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
 #define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
 
@@ -14,16 +13,154 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/YAMLParser.h"
 #include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_socket_stream.h"
+
+namespace clang::tooling::cc1modbuildd {
+
+enum class ActionType { REGISTER, HANDSHAKE };
+enum class StatusType { REQUEST, SUCCESS, FAILURE };
+
+struct BaseMsg {
+  ActionType MsgAction;
+  StatusType MsgStatus;
+
+  BaseMsg() = default;
+  BaseMsg(ActionType Action, StatusType Status)
+      : MsgAction(Action), MsgStatus(Status) {}
+};
+
+struct RegisterMsg : public BaseMsg {
+  std::optional<std::string> WorkingDirectory;
+  // The scanner requires the path to the clang executable
+  std::optional<std::string> ExecutablePath;
+  // Does not include executable
+  std::optional<std::vector<std::string>> CC1CommandLine;
+
+  RegisterMsg() = default;
+
+  RegisterMsg(ActionType Action, StatusType Status,
+              const std::optional<std::string> &CurrentWD,
+              const std::optional<std::string> &Argv0,
+              const std::optional<std::vector<std::string>> &Argv)
+      : BaseMsg(Action, Status), WorkingDirectory(CurrentWD),
+        ExecutablePath(Argv0), CC1CommandLine(Argv) {}
+
+  RegisterMsg(ActionType Action, StatusType Status)
+      : BaseMsg(Action, Status), WorkingDirectory(std::nullopt),
+        ExecutablePath(std::nullopt), CC1CommandLine(std::nullopt) {}
+};
+
+struct HandshakeMsg : public BaseMsg {
+  HandshakeMsg() = default;
+  HandshakeMsg(ActionType Action, StatusType Status)
+      : BaseMsg(Action, Status) {}
+};
+
+llvm::Expected<std::string>
+readBufferFromSocket(llvm::raw_socket_stream &Socket);
+llvm::Error writeBufferToSocket(llvm::raw_socket_stream &Socket,
+                                llvm::StringRef Buffer);
+
+template <typename T> std::string convertMsgStructToBuffer(T MsgStruct) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value);
+
+  std::string Buffer;
+  llvm::raw_string_ostream OS(Buffer);
+  llvm::yaml::Output YamlOut(OS);
+
+  // TODO confirm yaml::Output does not have any error messages
+  YamlOut << MsgStruct;
+
+  return Buffer;
+}
+
+template <typename T>
+llvm::Expected<T> convertBufferToMsgStruct(llvm::StringRef Buffer) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value);
+
+  T MsgStruct;
+  llvm::yaml::Input YamlIn(Buffer);
+  YamlIn >> MsgStruct;
+
+  // YamlIn.error() dumps an error message if there is one
+  if (YamlIn.error())
+    return llvm::make_error<llvm::StringError>(
+        "Syntax or semantic error during YAML parsing",
+        llvm::inconvertibleErrorCode());
+
+  return MsgStruct;
+}
+
+template <typename T>
+llvm::Expected<T> readMsgStructFromSocket(llvm::raw_socket_stream &Socket) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value);
+
+  llvm::Expected<std::string> MaybeBuffer = readBufferFromSocket(Socket);
+  if (!MaybeBuffer)
+    return std::move(MaybeBuffer.takeError());
+  std::string Buffer = std::move(*MaybeBuffer);
+
+  llvm::Expected<T> MaybeMsgStruct = convertBufferToMsgStruct<T>(Buffer);
+  if (!MaybeMsgStruct)
+    return std::move(MaybeMsgStruct.takeError());
+  return std::move(*MaybeMsgStruct);
+}
+
+template <typename T>
+llvm::Error writeMsgStructToSocket(llvm::raw_socket_stream &Socket,
+                                   T MsgStruct) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value);
+
+  std::string Buffer = convertMsgStructToBuffer(MsgStruct);
+  if (llvm::Error Err = writeBufferToSocket(Socket, Buffer))
+    return Err;
+  return llvm::Error::success();
+}
+} // namespace clang::tooling::cc1modbuildd
 
-namespace cc1modbuildd {
+template <>
+struct llvm::yaml::ScalarEnumerationTraits<
+    clang::tooling::cc1modbuildd::StatusType> {
+  static void enumeration(IO &Io,
+                          clang::tooling::cc1modbuildd::StatusType &Value) {
+    Io.enumCase(Value, "REQUEST",
+                clang::tooling::cc1modbuildd::StatusType::REQUEST);
+    Io.enumCase(Value, "SUCCESS",
+                clang::tooling::cc1modbuildd::StatusType::SUCCESS);
+    Io.enumCase(Value, "FAILURE",
+                clang::tooling::cc1modbuildd::StatusType::FAILURE);
+  }
+};
 
-llvm::Expected<int> createSocket();
-llvm::Expected<int> connectToSocket(llvm::StringRef SocketPath);
-llvm::Expected<int> connectAndWriteToSocket(std::string Buffer,
-                                            llvm::StringRef SocketPath);
-llvm::Expected<std::string> readFromSocket(int FD);
-llvm::Error writeToSocket(std::string Buffer, int WriteFD);
+template <>
+struct llvm::yaml::ScalarEnumerationTraits<
+    clang::tooling::cc1modbuildd::ActionType> {
+  static void enumeration(IO &Io,
+                          clang::tooling::cc1modbuildd::ActionType &Value) {
+    Io.enumCase(Value, "REGISTER",
+                clang::tooling::cc1modbuildd::ActionType::REGISTER);
+    Io.enumCase(Value, "HANDSHAKE",
+                clang::tooling::cc1modbuildd::ActionType::HANDSHAKE);
+  }
+};
 
-} // namespace cc1modbuildd
+template <>
+struct llvm::yaml::MappingTraits<clang::tooling::cc1modbuildd::RegisterMsg> {
+  static void mapping(IO &Io, clang::tooling::cc1modbuildd::RegisterMsg &Info) {
+    Io.mapRequired("Action", Info.MsgAction);
+    Io.mapRequired("Status", Info.MsgStatus);
+    Io.mapOptional("WorkingDirectory", Info.WorkingDirectory);
+    Io.mapOptional("ExecutablePath", Info.ExecutablePath);
+    Io.mapOptional("CC1CommandLine", Info.CC1CommandLine);
+  }
+};
 
+template <>
+struct llvm::yaml::MappingTraits<clang::tooling::cc1modbuildd::HandshakeMsg> {
+  static void mapping(IO &Io,
+                      clang::tooling::cc1modbuildd::HandshakeMsg &Info) {
+    Io.mapRequired("Action", Info.MsgAction);
+    Io.mapRequired("Status", Info.MsgStatus);
+  }
+};
 #endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
index 79a2ffc3c1804d..6d4acc3a348b9e 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
@@ -15,14 +15,47 @@
 #define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
 
 #include "llvm/Support/Error.h"
+
+#include <chrono>
 #include <string>
 
-namespace cc1modbuildd {
+#ifdef _WIN32
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+// winsock2.h must be included before afunix.h
+// clang-format off
+#include <winsock2.h>
+#include <afunix.h>
+// clang-format on
+#else
+#include <sys/un.h>
+#endif
+
+namespace clang::tooling::cc1modbuildd {
+
+constexpr std::string_view SocketFileName = "mbd.sock";
+constexpr std::string_view StdoutFileName = "mbd.out";
+constexpr std::string_view StderrFileName = "mbd.err";
+constexpr std::string_view ModuleBuildDaemonFlag = "-cc1modbuildd";
+
+// A llvm::raw_socket_stream uses sockaddr_un
+constexpr size_t SocketAddrMaxLength = sizeof(sockaddr_un::sun_path);
+
+constexpr size_t BasePathMaxLength =
+    SocketAddrMaxLength - SocketFileName.length();
+
+// Get a temprary location where the daemon can store log files and a socket
+// address. Of the format /tmp/clang-<BLAKE3HashOfClangFullVersion>/
+std::string getBasePath();
+
+// Check if the user provided BasePath is short enough
+bool validBasePathLength(llvm::StringRef);
 
 void writeError(llvm::Error Err, std::string Msg);
 std::string getFullErrorMsg(llvm::Error Err, std::string Msg);
 llvm::Error makeStringError(llvm::Error Err, std::string Msg);
 
-} // namespace cc1modbuildd
+} // namespace clang::tooling::cc1modbuildd
 
-#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
\ No newline at end of file
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt b/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
index 9c1f5dc1aa2c0c..c043557206ef9e 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
+++ b/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
@@ -3,7 +3,7 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_clang_library(clangModuleBuildDaemon
-  Client.cpp
+  Frontend.cpp
   SocketSupport.cpp
   Utils.cpp
   )
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
deleted file mode 100644
index 4018d70a30ea5e..00000000000000
--- a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-//===----------------------------- Client.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/Client.h"
-#include "clang/Basic/Version.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
-#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
-#include "clang/Tooling/ModuleBuildDaemon/Utils.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;
-using namespace cc1modbuildd;
-
-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::endianness::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();
-}
-
-llvm::Error cc1modbuildd::attemptHandshake(int SocketFD) {
-
-  cc1modbuildd::HandshakeMsg Request{ActionType::HANDSHAKE,
-                                     StatusType::REQUEST};
-  std::string Buffer = cc1modbuildd::getBufferFromSocketMsg(Request);
-
-  if (llvm::Error Err = writeToSocket(Buffer, SocketFD))
-    return std::move(Err);
-
-  Expected<RegisterMsg> MaybeServerResponse =
-      readSocketMsgFromSocket<RegisterMsg>(SocketFD);
-  if (!MaybeServerResponse)
-    return std::move(MaybeServerResponse.takeError());
-  RegisterMsg 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());
-}
-
-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();
-}
-
-Expected<int> cc1modbuildd::getModuleBuildDaemon(const char *Argv0,
-                                                 StringRef BasePath) {
-
-  SmallString<128> SocketPath = BasePath;
-  llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
-
-  if (llvm::sys::fs::exists(SocketPath)) {
-    Expected<int> MaybeFD = connectToSocket(SocketPath);
-    if (MaybeFD)
-      return std::move(*MaybeFD);
-    consumeError(MaybeFD.takeError());
-  }
-
-  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 has initialized
-    usleep(WaitTime);
-
-    if (llvm::sys::fs::exists(SocketPath)) {
-      Expected<int> MaybeFD = connectToSocket(SocketPath);
-      if (MaybeFD)
-        return std::move(*MaybeFD);
-      consumeError(MaybeFD.takeError());
-    }
-
-    CumulativeTime += INTERVAL;
-  }
-
-  // After waiting 30 seconds give up
-  return llvm::make_error<StringError>(
-      "Module build daemon did not exist after spawn attempt",
-      inconvertibleErrorCode());
-}
-
-llvm::Error
-cc1modbuildd::registerTranslationUnit(ArrayRef<const char *> CC1Command,
-                                      StringRef Argv0, StringRef CWD,
-                                      int ServerFD) {
-
-  std::vector<std::string> StrCC1Command;
-  for (const char *Arg : CC1Command)
-    StrCC1Command.emplace_back(Arg);
-
-  cc1modbuildd::RegisterMsg Request{ActionType::REGISTER, StatusType::REQUEST,
-                                    CWD.str(), Argv0.str(), StrCC1Command};
-
-  llvm::Error WriteErr = writeSocketMsgToSocket(Request, ServerFD);
-  if (WriteErr)
-    return std::move(WriteErr);
-
-  return llvm::Error::success();
-}
-
-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<RegisterMsg> MaybeServerResponse =
-      readSocketMsgFromSocket<RegisterMsg>(ServerFD);
-  if (!MaybeServerResponse)
-    return std::move(MaybeServerResponse.takeError());
-  RegisterMsg 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.CC1CommandLine.value();
-
-  return llvm::make_error<StringError>(
-      "Daemon failed to processes registered translation unit",
-      inconvertibleErrorCode());
-}
-
-Expected<std::vector<std::string>>
-cc1modbuildd::updateCC1WithModuleBuildDaemon(const CompilerInvocation &Clang,
-                                             ArrayRef<const char *> CC1Cmd,
-                                             const char *Argv0, StringRef CWD) {
-
-  // The module build daemon stores all output files and its socket address
-  // under BasePath. Either set BasePath to a user provided option or create an
-  // appropriate BasePath based on the hash of the clang version
-  std::string BasePath;
-  if (!Clang.getFrontendOpts().ModuleBuildDaemonPath.empty())
-    BasePath = Clang.getFrontendOpts().ModuleBuildDaemonPath;
-  else
-    BasePath = cc1modbuildd::getBasePath();
-
-  // If module build daemon does not exist spawn module build daemon
-  Expected<int> MaybeDaemonFD =
-      cc1modbuildd::getModuleBuildDaemon(Argv0, BasePath);
-  if (!MaybeDaemonFD)
-    return makeStringError(MaybeDaemonFD.takeError(),
-                           "Connect to daemon failed: ");
-  int DaemonFD = std::move(*MaybeDaemonFD);
-
-  if (llvm::Error HandshakeErr = attemptHandshake(DaemonFD))
-    return makeStringError(std::move(HandshakeErr),
-                           "Failed to hadshake with daemon: ");
-
-  // Send translation unit information to module build daemon for processing
-  if (llvm::Error RegisterErr =
-          registerTranslationUnit(CC1Cmd, Argv0, CWD, DaemonFD))
-    return makeStringError(std::move(RegisterErr),
-                           "Register translation unti failed: ");
-
-  // 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 = getUpdatedCC1(DaemonFD);
-  if (!MaybeUpdatedCC1)
-    return makeStringError(MaybeUpdatedCC1.takeError(),
-                           "Failed to get updated CC1: ");
-  return std::move(*MaybeUpdatedCC1);
-}
-
-#endif // LLVM_ON_UNIX
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Frontend.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Frontend.cpp
new file mode 100644
index 00000000000000..ee5cd05606f67d
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Frontend.cpp
@@ -0,0 +1,222 @@
+//===---------------------------- Frontend.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/Frontend.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/Utils.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"
+#include "llvm/Support/ExponentialBackoff.h"
+#include "llvm/Support/Program.h"
+
+#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;
+
+namespace clang::tooling::cc1modbuildd {
+
+llvm::Error attemptHandshake(llvm::raw_socket_stream &Client) {
+  // Send HandshakeMsg to module build daemon
+  HandshakeMsg Request{ActionType::HANDSHAKE, StatusType::REQUEST};
+  if (llvm::Error Err = writeMsgStructToSocket(Client, Request))
+    return Err;
+
+  // Read response from module build daemon
+  Expected<HandshakeMsg> MaybeResponse =
+      readMsgStructFromSocket<HandshakeMsg>(Client);
+  if (!MaybeResponse) {
+    return MaybeResponse.takeError();
+  }
+  HandshakeMsg Response = std::move(*MaybeResponse);
+
+  assert(Response.MsgAction == ActionType::HANDSHAKE &&
+         "The response ActionType should only ever be HANDSHAKE");
+
+  if (Response.MsgStatus == StatusType::SUCCESS) {
+    return llvm::Error::success();
+  }
+
+  return llvm::make_error<llvm::StringError>(
+      "Received handshake response 'FAILURE' from module build daemon",
+      std::make_error_code(std::errc::operation_not_permitted));
+}
+
+llvm::Error spawnModuleBuildDaemon(const CompilerInvocation &Clang,
+                                   const char *Argv0, DiagnosticsEngine &Diag,
+                                   std::string BasePath) {
+  std::vector<StringRef> Args = {Argv0, ModuleBuildDaemonFlag};
+  if (!Clang.getFrontendOpts().ModuleBuildDaemonPath.empty())
+    Args.push_back(BasePath.c_str());
+
+  std::string ErrorBuffer;
+  llvm::sys::ExecuteNoWait(Argv0, Args, std::nullopt, {}, 0, &ErrorBuffer,
+                           nullptr, nullptr, /*DetachProcess*/ true);
+
+  // llvm::sys::ExecuteNoWait can fail for a variety of reasons which can't be
+  // generalized to one error code
+  if (!ErrorBuffer.empty())
+    return llvm::make_error<llvm::StringError>(ErrorBuffer,
+                                               llvm::inconvertibleErrorCode());
+
+  Diag.Report(diag::remark_mbd_spawn);
+  return llvm::Error::success();
+}
+
+Expected<std::unique_ptr<llvm::raw_socket_stream>>
+getModuleBuildDaemon(const CompilerInvocation &Clang, const char *Argv0,
+                     DiagnosticsEngine &Diag, StringRef BasePath) {
+  SmallString<128> SocketPath = BasePath;
+  llvm::sys::path::append(SocketPath, SocketFileName);
+
+  if (llvm::sys::fs::exists(SocketPath)) {
+    Expected<std::unique_ptr<llvm::raw_socket_stream>> MaybeClient =
+        llvm::raw_socket_stream::createConnectedUnix(SocketPath);
+    if (MaybeClient)
+      return std::move(*MaybeClient);
+    consumeError(MaybeClient.takeError());
+  }
+
+  if (llvm::Error Err =
+          spawnModuleBuildDaemon(Clang, Argv0, Diag, BasePath.str()))
+    return std::move(Err);
+
+  std::chrono::seconds MaxWaitTime(30);
+  llvm::ExponentialBackoff Backoff(MaxWaitTime);
+  do {
+    if (llvm::sys::fs::exists(SocketPath)) {
+      Expected<std::unique_ptr<llvm::raw_socket_stream>> MaybeClient =
+          llvm::raw_socket_stream::createConnectedUnix(SocketPath);
+      if (MaybeClient) {
+        Diag.Report(diag::remark_mbd_connection) << SocketPath;
+        return std::move(*MaybeClient);
+      }
+      consumeError(MaybeClient.takeError());
+    }
+  } while (Backoff.waitForNextAttempt());
+
+  // After waiting around 30 seconds give up and return an error
+  return llvm::make_error<llvm::StringError>(
+      "Max wait time exceeded",
+      std::make_error_code(std::errc::no_such_process));
+}
+
+llvm::Error registerTranslationUnit(ArrayRef<const char *> CC1Command,
+                                    StringRef Argv0, StringRef CWD,
+                                    llvm::raw_socket_stream &Client) {
+
+  std::vector<std::string> StrCC1Command;
+  for (const char *Arg : CC1Command)
+    StrCC1Command.emplace_back(Arg);
+
+  cc1modbuildd::RegisterMsg Request{ActionType::REGISTER, StatusType::REQUEST,
+                                    CWD.str(), Argv0.str(), StrCC1Command};
+
+  llvm::Error WriteErr = writeMsgStructToSocket(Client, Request);
+  if (WriteErr)
+    return std::move(WriteErr);
+
+  return llvm::Error::success();
+}
+
+Expected<std::vector<std::string>>
+getUpdatedCC1(llvm::raw_socket_stream &Server) {
+
+  // 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<RegisterMsg> MaybeServerResponse =
+      readMsgStructFromSocket<RegisterMsg>(Server);
+  if (!MaybeServerResponse)
+    return std::move(MaybeServerResponse.takeError());
+  RegisterMsg 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.CC1CommandLine.value();
+
+  return llvm::make_error<StringError>(
+      "Daemon failed to processes registered translation unit",
+      inconvertibleErrorCode());
+}
+
+Expected<std::vector<std::string>>
+updateCC1WithModuleBuildDaemon(const CompilerInvocation &Clang,
+                               ArrayRef<const char *> CC1Cmd, const char *Argv0,
+                               StringRef CWD, DiagnosticsEngine &Diag) {
+  // The module build daemon stores all output files and its socket address
+  // under BasePath. Either set BasePath to a user provided option or create an
+  // appropriate BasePath based on the BLAKE3 hash of the full clang version
+  std::string BasePath;
+  if (Clang.getFrontendOpts().ModuleBuildDaemonPath.empty())
+    BasePath = getBasePath();
+  else {
+    // Get user provided BasePath and confirm it is short enough
+    BasePath = Clang.getFrontendOpts().ModuleBuildDaemonPath;
+    if (!validBasePathLength(BasePath)) {
+      Diag.Report(diag::err_path_length) << BasePath << BasePathMaxLength;
+      return make_error<StringError>(inconvertibleErrorCode(),
+                                     "BasePath is too long");
+    }
+  }
+
+  // If module build daemon does not exist spawn module build daemon
+  Expected<std::unique_ptr<llvm::raw_socket_stream>> MaybeClient =
+      getModuleBuildDaemon(Clang, Argv0, Diag, BasePath);
+  if (!MaybeClient) {
+    Diag.Report(diag::err_mbd_connect) << MaybeClient.takeError();
+    return make_error<StringError>(inconvertibleErrorCode(),
+                                   "Could not connect to ModuleBuildDaemon");
+  }
+  llvm::raw_socket_stream &Client = **MaybeClient;
+
+  if (llvm::Error HandshakeErr = attemptHandshake(Client)) {
+    Diag.Report(diag::err_mbd_handshake) << std::move(HandshakeErr);
+    return makeStringError(std::move(HandshakeErr),
+                           "Failed to hadshake with daemon");
+  }
+
+  Diag.Report(diag::remark_mbd_handshake)
+      << Clang.getFrontendOpts().Inputs[0].getFile();
+
+  // Send translation unit information to module build daemon for processing
+  if (llvm::Error RegisterErr =
+          registerTranslationUnit(CC1Cmd, Argv0, CWD, Client))
+    return makeStringError(std::move(RegisterErr),
+                           "Register translation unti failed");
+
+  // 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 = getUpdatedCC1(Client);
+  if (!MaybeUpdatedCC1)
+    return makeStringError(MaybeUpdatedCC1.takeError(),
+                           "Failed to get updated CC1");
+  return std::move(*MaybeUpdatedCC1);
+}
+
+} // namespace clang::tooling::cc1modbuildd
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
index 8a25b8f0bfd9df..8797fb2f4cb499 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
+++ b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
@@ -6,127 +6,49 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
-#include "clang/Basic/Version.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Tooling/ModuleBuildDaemon/Client.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"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_socket_stream.h"
 
-// TODO: Make portable
-#if LLVM_ON_UNIX
-
-#include <cerrno>
-#include <filesystem>
-#include <fstream>
-#include <signal.h>
-#include <spawn.h>
+#include <memory>
 #include <string>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-llvm::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 llvm::createStringError(llvm::inconvertibleErrorCode(), Msg);
-  }
-  return FD;
-}
-
-llvm::Expected<int> cc1modbuildd::connectToSocket(llvm::StringRef SocketPath) {
-
-  llvm::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 llvm::createStringError(llvm::inconvertibleErrorCode(), msg);
-  }
-  return FD;
-}
 
-llvm::Expected<int>
-cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
-                                      llvm::StringRef SocketPath) {
+namespace clang::tooling::cc1modbuildd {
 
-  llvm::Expected<int> MaybeConnectedFD = connectToSocket(SocketPath);
-  if (!MaybeConnectedFD)
-    return std::move(MaybeConnectedFD.takeError());
+llvm::Expected<std::string>
+readBufferFromSocket(llvm::raw_socket_stream &Socket) {
+  constexpr unsigned short MAX_BUFFER = 4096;
+  constexpr std::chrono::milliseconds TIMEOUT(5000);
+  char Buffer[MAX_BUFFER];
+  std::string ReturnBuffer;
 
-  int ConnectedFD = std::move(*MaybeConnectedFD);
-  llvm::Error Err = writeToSocket(Buffer, ConnectedFD);
-  if (Err)
-    return std::move(Err);
-
-  return ConnectedFD;
-}
-
-llvm::Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
-
-  const size_t BUFFER_SIZE = 4096;
-  std::vector<char> Buffer(BUFFER_SIZE);
-  size_t TotalBytesRead = 0;
-
-  ssize_t n;
-  while ((n = read(FD, Buffer.data() + TotalBytesRead,
-                   Buffer.size() - TotalBytesRead)) > 0) {
-
-    TotalBytesRead += n;
-    // Read until ...\n encountered (last line of YAML document)
-    if (std::string(&Buffer[TotalBytesRead - 4], 4) == "...\n")
+  ssize_t n = 0;
+  while ((n = Socket.read(Buffer, MAX_BUFFER, TIMEOUT)) > 0) {
+    ReturnBuffer.append(Buffer, n);
+    // Read until \n... encountered which is the last line of a YAML document
+    if (ReturnBuffer.find("\n...") != std::string::npos)
       break;
-    if (Buffer.size() - TotalBytesRead < BUFFER_SIZE)
-      Buffer.resize(Buffer.size() + BUFFER_SIZE);
   }
 
-  if (n < 0) {
-    std::string Msg = "socket read error: " + std::string(strerror(errno));
-    return llvm::make_error<llvm::StringError>(Msg,
-                                               llvm::inconvertibleErrorCode());
+  if (Socket.has_error()) {
+    std::error_code EC = Socket.error();
+    Socket.clear_error();
+    return llvm::make_error<llvm::StringError>("Failed socket read", EC);
   }
-  if (n == 0)
-    return llvm::make_error<llvm::StringError>("EOF",
-                                               llvm::inconvertibleErrorCode());
-  return std::string(Buffer.begin(), Buffer.end());
+  return ReturnBuffer;
 }
 
-llvm::Error cc1modbuildd::writeToSocket(std::string Buffer, int WriteFD) {
-
-  ssize_t BytesToWrite = static_cast<ssize_t>(Buffer.size());
-  const char *Bytes = Buffer.c_str();
-
-  while (BytesToWrite) {
-    ssize_t BytesWritten = write(WriteFD, Bytes, BytesToWrite);
-    if (BytesWritten == -1) {
-      std::string Msg = "socket write error: " + std::string(strerror(errno));
-      return llvm::make_error<llvm::StringError>(
-          Msg, llvm::inconvertibleErrorCode());
-    }
-
-    if (!BytesWritten || BytesWritten > BytesToWrite)
-      return llvm::errorCodeToError(
-          std::error_code(EIO, std::generic_category()));
-
-    BytesToWrite -= BytesWritten;
-    Bytes += BytesWritten;
+llvm::Error writeBufferToSocket(llvm::raw_socket_stream &Socket,
+                                llvm::StringRef Buffer) {
+  Socket << Buffer;
+  if (Socket.has_error()) {
+    std::error_code EC = Socket.error();
+    Socket.clear_error();
+    return llvm::make_error<llvm::StringError>("Failed socket write", EC);
   }
+
+  Socket.flush();
   return llvm::Error::success();
 }
 
-#endif // LLVM_ON_UNIX
+} // namespace clang::tooling::cc1modbuildd
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
index c03e8e3762114f..d4dcfa7392d5a5 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
@@ -6,19 +6,28 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <clang/Tooling/ModuleBuildDaemon/Utils.h>
-#include <llvm/Support/Error.h>
+#include "clang/Tooling/ModuleBuildDaemon/Utils.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/BLAKE3.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
+
 #include <string>
 
 using namespace llvm;
 
-void cc1modbuildd::writeError(llvm::Error Err, std::string Msg) {
+namespace clang::tooling::cc1modbuildd {
+
+void writeError(llvm::Error Err, std::string Msg) {
   handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
     errs() << Msg << EIB.message() << '\n';
   });
 }
 
-std::string cc1modbuildd::getFullErrorMsg(llvm::Error Err, std::string Msg) {
+std::string getFullErrorMsg(llvm::Error Err, std::string Msg) {
   std::string ErrMessage;
   handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
     ErrMessage = Msg + EIB.message();
@@ -26,7 +35,34 @@ std::string cc1modbuildd::getFullErrorMsg(llvm::Error Err, std::string Msg) {
   return ErrMessage;
 }
 
-llvm::Error cc1modbuildd::makeStringError(llvm::Error Err, std::string Msg) {
+llvm::Error makeStringError(llvm::Error Err, std::string Msg) {
   std::string ErrMsg = getFullErrorMsg(std::move(Err), Msg);
   return llvm::make_error<StringError>(ErrMsg, inconvertibleErrorCode());
-}
\ No newline at end of file
+}
+
+std::string getBasePath() {
+  llvm::BLAKE3 Hash;
+  Hash.update(clang::getClangFullVersion());
+  auto HashResult = Hash.final<sizeof(uint64_t)>();
+  uint64_t HashValue =
+      llvm::support::endian::read<uint64_t, llvm::endianness::native>(
+          HashResult.data());
+  std::string Key = toString(llvm::APInt(64, HashValue), 36, /*Signed*/ false);
+
+  // Set paths
+  llvm::SmallString<128> BasePath;
+  llvm::sys::path::system_temp_directory(/*erasedOnReboot*/ true, BasePath);
+  llvm::sys::path::append(BasePath, "clang-" + Key);
+  return BasePath.c_str();
+}
+
+bool validBasePathLength(llvm::StringRef Address) {
+  // Confirm that the user provided BasePath is short enough to allow the socket
+  // address to fit within the space alloted to sockaddr_un::sun_path
+  if (Address.str().length() > BasePathMaxLength) {
+    return false;
+  }
+  return true;
+}
+
+} // namespace clang::tooling::cc1modbuildd
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 3573d6f7e43b27..11829076142e70 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -26,7 +26,7 @@
 #include "clang/Frontend/Utils.h"
 #include "clang/FrontendTool/Utils.h"
 #include "clang/Serialization/ObjectFilePCHContainerReader.h"
-#include "clang/Tooling/ModuleBuildDaemon/Client.h"
+#include "clang/Tooling/ModuleBuildDaemon/Frontend.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/llvm-config.h"
@@ -255,7 +255,6 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   std::vector<std::string> UpdatedArgv;
   std::vector<const char *> CharUpdatedArgv;
 
-#if LLVM_ON_UNIX
   // Handle module build daemon functionality if enabled
   if (Invocation->getFrontendOpts().ModuleBuildDaemon) {
 
@@ -271,8 +270,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
     }
 
     Expected<std::vector<std::string>> MaybeUpdatedArgv =
-        cc1modbuildd::updateCC1WithModuleBuildDaemon(*Invocation, Argv, Argv0,
-                                                     *MaybeCWD);
+        clang::tooling::cc1modbuildd::updateCC1WithModuleBuildDaemon(
+            *Invocation, Argv, Argv0, *MaybeCWD, Diags);
     if (!MaybeUpdatedArgv) {
       llvm::errs() << toString(std::move(MaybeUpdatedArgv.takeError())) << '\n';
       return 1;
@@ -285,7 +284,6 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
       CharUpdatedArgv.push_back(Arg.c_str());
     }
   }
-#endif
 
   llvm::outs() << "translation unit command line" << '\n';
   for (const auto &Arg : Argv)
diff --git a/clang/tools/driver/cc1modbuildd_main.cpp b/clang/tools/driver/cc1modbuildd_main.cpp
index df30a3b8787f68..6098d9910563a1 100644
--- a/clang/tools/driver/cc1modbuildd_main.cpp
+++ b/clang/tools/driver/cc1modbuildd_main.cpp
@@ -13,7 +13,6 @@
 #include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
 #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
-#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
 #include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
 #include "clang/Tooling/ModuleBuildDaemon/Utils.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -24,10 +23,9 @@
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/YAMLParser.h"
 #include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_socket_stream.h"
 
-// TODO: Make portable
-#if LLVM_ON_UNIX
-
+#include <csignal>
 #include <errno.h>
 #include <fstream>
 #include <mutex>
@@ -44,17 +42,40 @@
 #include <unordered_map>
 
 using namespace llvm;
-using namespace clang;
-using namespace tooling::dependencies;
-using namespace cc1modbuildd;
+using namespace clang::tooling::dependencies;
+using namespace clang::tooling::cc1modbuildd;
 
-// Create unbuffered STDOUT stream so that any logging done by module build
+// Create unbuffered STDOUT stream so that any logging done by the module build
 // daemon can be viewed without having to terminate the process
-static raw_fd_ostream &unbuff_outs() {
-  static raw_fd_ostream S(STDOUT_FILENO, false, true);
+static llvm::raw_fd_ostream &unbuff_outs() {
+  static llvm::raw_fd_ostream S(fileno(stdout), false, true);
   return S;
 }
 
+static bool LogVerbose = false;
+static void logVerbose(const llvm::Twine &message) {
+  if (LogVerbose) {
+    unbuff_outs() << message << '\n';
+  }
+}
+
+static void modifySignals(decltype(SIG_DFL) handler) {
+  if (std::signal(SIGTERM, handler) == SIG_ERR) {
+    llvm::errs() << "failed to handle SIGTERM" << '\n';
+    exit(EXIT_FAILURE);
+  }
+  if (std::signal(SIGINT, handler) == SIG_ERR) {
+    llvm::errs() << "failed to handle SIGINT" << '\n';
+    exit(EXIT_FAILURE);
+  }
+#ifdef SIGHUP
+  if (::signal(SIGHUP, SIG_IGN) == SIG_ERR) {
+    llvm::errs() << "failed to handle SIGHUP" << '\n';
+    exit(EXIT_FAILURE);
+  }
+#endif
+}
+
 namespace {
 
 enum class BuildStatus { WAITING, BUILDING, BUILT };
@@ -113,57 +134,56 @@ class DependencyBuildData {
 
 class ModuleBuildDaemonServer {
 public:
-  SmallString<128> BasePath;
-  SmallString<128> SocketPath;
-  SmallString<128> PidPath;
-
-  ModuleBuildDaemonServer(SmallString<128> Path, ArrayRef<const char *> Argv)
-      : BasePath(Path), SocketPath(Path) {
-    llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+  llvm::SmallString<256> SocketPath;
+  llvm::SmallString<256> Stderr; // path to stderr
+  llvm::SmallString<256> Stdout; // path to stdout
+
+  explicit ModuleBuildDaemonServer(llvm::StringRef Path)
+      : SocketPath(Path), Stderr(Path), Stdout(Path) {
+    llvm::sys::path::append(SocketPath, SocketFileName);
+    llvm::sys::path::append(Stdout, StdoutFileName);
+    llvm::sys::path::append(Stderr, StderrFileName);
   }
 
-  ~ModuleBuildDaemonServer() { shutdownDaemon(SIGTERM); }
-
-  int forkDaemon();
-  int launchDaemon();
-  int listenForClients();
-
-  static void handleClient(int Client);
-  static void handleRegister(int Client, RegisterMsg ClientRequest);
-
-  void shutdownDaemon(int signal) {
-    unlink(SocketPath.c_str());
-    shutdown(ListenSocketFD, SHUT_RD);
-    close(ListenSocketFD);
-    exit(EXIT_SUCCESS);
+  ~ModuleBuildDaemonServer() { shutdownDaemon(); }
+
+  void setupDaemonEnv();
+  void createDaemonSocket();
+  void listenForClients();
+
+  static void handleRegister(llvm::raw_socket_stream &Client,
+                             RegisterMsg ClientRequest);
+  static void
+  handleConnection(std::shared_ptr<llvm::raw_socket_stream> Connection);
+
+  // TODO: modify so when shutdownDaemon is called the daemon stops accepting
+  // new client connections and waits for all existing client connections to
+  // terminate before closing the file descriptor and exiting
+  // Meant to be called by signal handler to clean up resources
+  void shutdownDaemon() {
+    RunServiceLoop = false;
+    // Signal handler is installed after ServerListener is created and emplaced
+    // into the std::optional<llvm::ListeningSocket>
+    ServerListener.value().shutdown();
   }
 
 private:
-  // Initializes and returns DiagnosticsEngine
-  pid_t Pid = -1;
-  int ListenSocketFD = -1;
+  std::atomic<bool> RunServiceLoop = true;
+  // llvm::ListeningSocket does not have a default constructor so use
+  // std::optional as storage
+  std::optional<llvm::ListeningSocket> ServerListener;
 };
 
-// Required to handle SIGTERM by calling Shutdown
+// Used to handle signals
 ModuleBuildDaemonServer *DaemonPtr = nullptr;
-void handleSignal(int Signal) {
-  if (DaemonPtr != nullptr) {
-    DaemonPtr->shutdownDaemon(Signal);
-  }
-}
+// DaemonPtr is set to a valid ModuleBuildDaemonServer before the signal handler
+// is installed so there is no need to check if DaemonPtr equals nullptr
+void handleSignal(int) { DaemonPtr->shutdownDaemon(); }
 } // namespace
 
-static bool verbose = false;
-static void verbose_print(const llvm::Twine &message) {
-  if (verbose) {
-    unbuff_outs() << message << '\n';
-  }
-}
-
 static DependencyBuildData DaemonBuildData;
 
-static Expected<TranslationUnitDeps>
-scanTranslationUnit(cc1modbuildd::RegisterMsg Request) {
+static Expected<TranslationUnitDeps> scanTranslationUnit(RegisterMsg Request) {
 
   DependencyScanningService Service(ScanningMode::DependencyDirectivesScan,
                                     ScanningOutputFormat::Full);
@@ -292,7 +312,7 @@ static void buildModuleID(const StringRef Executable, const ModuleID ID) {
 // returns an updated cc1 command line for the registered cc1 invocation
 // after building all modular dependencies
 static Expected<std::vector<std::string>>
-processRegisterRequest(cc1modbuildd::RegisterMsg Request) {
+processRegisterRequest(RegisterMsg Request) {
 
   Expected<TranslationUnitDeps> MaybeTUDeps = scanTranslationUnit(Request);
   if (!MaybeTUDeps)
@@ -319,89 +339,69 @@ processRegisterRequest(cc1modbuildd::RegisterMsg Request) {
   return modifyCC1<std::string>(TUDeps.Commands[0].Arguments);
 }
 
-// Forks and detaches process, creating module build daemon
-int ModuleBuildDaemonServer::forkDaemon() {
-
-  pid_t pid = fork();
-
-  if (pid < 0) {
+// Sets up file descriptors and signals for module build daemon
+void ModuleBuildDaemonServer::setupDaemonEnv() {
+#ifdef _WIN32
+  if (std::freopen("NUL", "r", stdin) == NULL) {
+#else
+  if (std::freopen("/dev/null", "r", stdin) == NULL) {
+#endif
+    llvm::errs() << "Failed to close stdin" << '\n';
     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';
+  if (std::freopen(Stdout.c_str(), "a", stdout) == NULL) {
+    llvm::errs() << "Failed to redirect stdout to " << Stdout << '\n';
     exit(EXIT_FAILURE);
   }
-  if (setsid() == -1) {
-    errs() << "setsid failed" << '\n';
+  if (std::freopen(Stderr.c_str(), "a", stderr) == NULL) {
+    llvm::errs() << "Failed to redirect stderr to " << Stderr << '\n';
     exit(EXIT_FAILURE);
   }
-
-  return EXIT_SUCCESS;
 }
 
-// Creates unix socket for IPC with module build daemon
-int ModuleBuildDaemonServer::launchDaemon() {
-
-  // 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);
+// Creates unix socket for IPC with frontends
+void ModuleBuildDaemonServer::createDaemonSocket() {
+  while (true) {
+    llvm::Expected<llvm::ListeningSocket> MaybeServerListener =
+        llvm::ListeningSocket::createUnix(SocketPath);
+
+    if (llvm::Error Err = MaybeServerListener.takeError()) {
+      llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &SE) {
+        std::error_code EC = SE.convertToErrorCode();
+
+        // Exit successfully if the socket address is already in use. When
+        // TUs are compiled in parallel, until the socket file is created, all
+        // clang invocations will try to spawn a module build daemon.
+#ifdef _WIN32
+        if (EC.value() == WSAEADDRINUSE) {
+#else
+        if (EC == std::errc::address_in_use) {
+#endif
+          exit(EXIT_SUCCESS);
+        } else if (EC == std::errc::file_exists) {
+          if (std::remove(SocketPath.c_str()) != 0) {
+            llvm::errs() << "Failed to remove " << SocketPath << ": "
+                         << strerror(errno) << '\n';
+            exit(EXIT_FAILURE);
+          }
+          // If a previous module build daemon invocation crashes, the socket
+          // file will need to be removed before the address can be bound to
+          logVerbose("Removing ineligible file: " + SocketPath);
+        } else {
+          llvm::errs() << "MBD failed to create unix socket: "
+                       << SE.getMessage() << ": " << EC.message() << '\n';
+          exit(EXIT_FAILURE);
+        }
+      });
+    } else {
+      logVerbose("MBD created and bound to socket at: " + SocketPath);
+      ServerListener.emplace(std::move(*MaybeServerListener));
+      break;
     }
-    std::perror("Socket bind error: ");
-    exit(EXIT_FAILURE);
   }
-  verbose_print("mbd created and binded to socket address at: " + 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);
-  }
-
-  return 0;
 }
 
-void ModuleBuildDaemonServer::handleRegister(int Client,
+void ModuleBuildDaemonServer::handleRegister(llvm::raw_socket_stream &Client,
                                              RegisterMsg ClientRequest) {
 
   Expected<std::vector<std::string>> MaybeExplicitCC1 =
@@ -411,7 +411,7 @@ void ModuleBuildDaemonServer::handleRegister(int Client,
   if (!MaybeExplicitCC1) {
 
     RegisterMsg Msg(ActionType::REGISTER, StatusType::FAILURE);
-    llvm::Error RegisterFailureWriteErr = writeSocketMsgToSocket(Msg, Client);
+    llvm::Error RegisterFailureWriteErr = writeMsgStructToSocket(Client, Msg);
 
     if (RegisterFailureWriteErr) {
       writeError(llvm::joinErrors(std::move(RegisterFailureWriteErr),
@@ -438,7 +438,7 @@ void ModuleBuildDaemonServer::handleRegister(int Client,
                   ClientRequest.WorkingDirectory, ClientRequest.ExecutablePath,
                   ExplicitCC1);
 
-  llvm::Error RegisterSuccessWriteErr = writeSocketMsgToSocket(Msg, Client);
+  llvm::Error RegisterSuccessWriteErr = writeMsgStructToSocket(Client, Msg);
 
   if (RegisterSuccessWriteErr) {
     writeError(std::move(RegisterSuccessWriteErr),
@@ -449,60 +449,76 @@ void ModuleBuildDaemonServer::handleRegister(int Client,
   return;
 }
 
-// Function submitted to thread pool with each client connection. Not
-// responsible for closing client connections
-void ModuleBuildDaemonServer::handleClient(int Client) {
-
-  // Read handshake from client
-  Expected<HandshakeMsg> MaybeHandshake =
-      readSocketMsgFromSocket<HandshakeMsg>(Client);
-
-  if (!MaybeHandshake) {
-    writeError(MaybeHandshake.takeError(),
-               "Failed to read handshake message from socket: ");
+// Function submitted to thread pool with each frontend connection. Not
+// responsible for closing frontend socket connections
+void ModuleBuildDaemonServer::handleConnection(
+    std::shared_ptr<llvm::raw_socket_stream> MovableConnection) {
+  llvm::raw_socket_stream &Connection = *MovableConnection;
+
+  // Read request from frontend
+  llvm::Expected<HandshakeMsg> MaybeHandshakeMsg =
+      readMsgStructFromSocket<HandshakeMsg>(Connection);
+  if (!MaybeHandshakeMsg) {
+    llvm::errs() << "MBD failed to read frontend request: "
+                 << llvm::toString(MaybeHandshakeMsg.takeError()) << '\n';
     return;
   }
 
-  // Handle HANDSHAKE
-  RegisterMsg Msg(ActionType::HANDSHAKE, StatusType::SUCCESS);
-  llvm::Error WriteErr = writeSocketMsgToSocket(Msg, Client);
-
-  if (WriteErr) {
-    writeError(std::move(WriteErr),
-               "Failed to notify client that handshake was received");
+  // Send response to frontend
+  HandshakeMsg Msg(ActionType::HANDSHAKE, StatusType::SUCCESS);
+  if (llvm::Error WriteErr = writeMsgStructToSocket(Connection, Msg)) {
+    llvm::errs() << "MBD failed to respond to frontend request: "
+                 << llvm::toString(std::move(WriteErr)) << '\n';
     return;
   }
 
-  // Read register request from client
+  // Read request from frontend
   Expected<RegisterMsg> MaybeRegister =
-      readSocketMsgFromSocket<RegisterMsg>(Client);
-
+      readMsgStructFromSocket<RegisterMsg>(Connection);
   if (!MaybeRegister) {
-    writeError(MaybeRegister.takeError(),
-               "Failed to read registration message from socket: ");
+    llvm::errs() << "Failed to read registration message from socket: "
+                 << llvm::toString(std::move(MaybeRegister.takeError()))
+                 << '\n';
     return;
   }
 
   RegisterMsg Register = std::move(*MaybeRegister);
-  handleRegister(Client, Register);
+  handleRegister(Connection, Register);
+
   return;
 }
 
-int ModuleBuildDaemonServer::listenForClients() {
-
+void ModuleBuildDaemonServer::listenForClients() {
   llvm::DefaultThreadPool Pool;
-  int Client;
-
-  while (true) {
-
-    if ((Client = accept(ListenSocketFD, NULL, NULL)) == -1) {
-      std::perror("Socket accept error: ");
+  std::chrono::seconds DaemonTimeout(15);
+  modifySignals(handleSignal);
+
+  while (RunServiceLoop) {
+    llvm::Expected<std::unique_ptr<llvm::raw_socket_stream>> MaybeConnection =
+        ServerListener.value().accept(DaemonTimeout);
+
+    if (llvm::Error Err = MaybeConnection.takeError()) {
+      llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &SE) {
+        std::error_code EC = SE.convertToErrorCode();
+
+        if (EC == std::errc::timed_out) {
+          RunServiceLoop = false;
+          logVerbose("ListeningServer::accept timed out, shutting down");
+        } else if (EC == std::errc::operation_canceled &&
+                   RunServiceLoop == false) {
+          logVerbose("Signal received, shutting down");
+        } else
+          llvm::errs() << "MBD failed to accept incoming connection: "
+                       << SE.getMessage() << ": " << EC.message() << '\n';
+      });
       continue;
     }
 
-    Pool.async(handleClient, Client);
+    // Connection must be copy constructable to be passed to Pool.async
+    std::shared_ptr<llvm::raw_socket_stream> Connection(
+        std::move(*MaybeConnection));
+    Pool.async(handleConnection, Connection);
   }
-  return 0;
 }
 
 // Module build daemon is spawned with the following command line:
@@ -520,32 +536,41 @@ int ModuleBuildDaemonServer::listenForClients() {
 // -v is optional and provides 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;
+  // -cc1modbuildd is sliced away when Argv is pased to cc1modbuildd_main
+  if (find(Argv, llvm::StringRef("-v")) != Argv.end())
+    LogVerbose = true;
+
+  std::string BasePath;
+  // If an argument exists and it is not -v then it must be a BasePath
+  if (!Argv.empty() && strcmp(Argv[0], "-v") != 0)
+    BasePath = Argv[0];
+  else
+    BasePath = getBasePath();
+
+  if (!validBasePathLength(BasePath)) {
+    llvm::errs() << "BasePath '" << BasePath
+                 << "' is longer then the max length of "
+                 << std::to_string(BasePathMaxLength) << '\n';
+    return EXIT_FAILURE;
   }
 
-  // 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;
+  {
+    ModuleBuildDaemonServer Daemon(BasePath);
 
-  if (find(Argv, StringRef("-v")) != Argv.end())
-    verbose = true;
+    // Used to handle signals
+    DaemonPtr = &Daemon;
 
-  Daemon.forkDaemon();
-  Daemon.launchDaemon();
-  Daemon.listenForClients();
+    Daemon.setupDaemonEnv();
+    Daemon.createDaemonSocket();
+    Daemon.listenForClients();
 
-  return 0;
-}
+    // Prevents the signal handler from being called after the
+    // ModuleBuildDaemonServer is destructed. The daemon is shutting down and
+    // the program is about to return so signals can be ignored
+    modifySignals(SIG_IGN);
+  }
 
-#endif // LLVM_ON_UNIX
+  return EXIT_SUCCESS;
+}
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index e7de591c79340d..0cd7db725328f0 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -84,9 +84,7 @@ extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
 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,



More information about the cfe-commits mailing list