[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 07:19:21 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/4] [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/4] 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/4] 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/4] 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) {



More information about the cfe-commits mailing list