[clang] [Cygwin] Cygwin driver (PR #74933)

εΎζŒζ’ Xu Chiheng via cfe-commits cfe-commits at lists.llvm.org
Sat Dec 9 06:22:31 PST 2023


https://github.com/xu-chiheng updated https://github.com/llvm/llvm-project/pull/74933

>From daa6702f698724655b91c4fa52272c09924d2d83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BE=90=E6=8C=81=E6=81=92=20Xu=20Chiheng?=
 <chiheng.xu at gmail.com>
Date: Sat, 9 Dec 2023 21:51:29 +0800
Subject: [PATCH] 1

---
 clang/lib/Driver/CMakeLists.txt        |   1 +
 clang/lib/Driver/Driver.cpp            |   4 +
 clang/lib/Driver/ToolChains/Cygwin.cpp | 731 +++++++++++++++++++++++++
 clang/lib/Driver/ToolChains/Cygwin.h   | 125 +++++
 clang/lib/Lex/InitHeaderSearch.cpp     |  30 +-
 5 files changed, 865 insertions(+), 26 deletions(-)
 create mode 100644 clang/lib/Driver/ToolChains/Cygwin.cpp
 create mode 100644 clang/lib/Driver/ToolChains/Cygwin.h

diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 58427e3f83c42..7ab5a1ee96351 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -51,6 +51,7 @@ add_clang_library(clangDriver
   ToolChains/CrossWindows.cpp
   ToolChains/CSKYToolChain.cpp
   ToolChains/Cuda.cpp
+  ToolChains/Cygwin.cpp
   ToolChains/Darwin.cpp
   ToolChains/DragonFly.cpp
   ToolChains/Flang.cpp
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index e241706b9082e..b6f3da3a006f4 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -17,6 +17,7 @@
 #include "ToolChains/Clang.h"
 #include "ToolChains/CrossWindows.h"
 #include "ToolChains/Cuda.h"
+#include "ToolChains/Cygwin.h"
 #include "ToolChains/Darwin.h"
 #include "ToolChains/DragonFly.h"
 #include "ToolChains/FreeBSD.h"
@@ -6263,6 +6264,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
         else
           TC = std::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
         break;
+      case llvm::Triple::Cygnus:
+        TC = std::make_unique<toolchains::Cygwin>(*this, Target, Args);
+        break;
       case llvm::Triple::GNU:
         TC = std::make_unique<toolchains::MinGW>(*this, Target, Args);
         break;
diff --git a/clang/lib/Driver/ToolChains/Cygwin.cpp b/clang/lib/Driver/ToolChains/Cygwin.cpp
new file mode 100644
index 0000000000000..8aa9cf5c8ec03
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Cygwin.cpp
@@ -0,0 +1,731 @@
+//===--- Cygwin.cpp - CygwinToolChain Implementation ------------------------===//
+//
+// 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 "Cygwin.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/InputInfo.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include <system_error>
+
+using namespace clang::diag;
+using namespace clang::driver;
+using namespace clang;
+using namespace llvm::opt;
+
+/// Cygwin Tools
+void tools::Cygwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+                                           const InputInfo &Output,
+                                           const InputInfoList &Inputs,
+                                           const ArgList &Args,
+                                           const char *LinkingOutput) const {
+  claimNoWarnArgs(Args);
+  ArgStringList CmdArgs;
+
+  if (getToolChain().getArch() == llvm::Triple::x86) {
+    CmdArgs.push_back("--32");
+  } else if (getToolChain().getArch() == llvm::Triple::x86_64) {
+    CmdArgs.push_back("--64");
+  }
+
+  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  for (const auto &II : Inputs)
+    CmdArgs.push_back(II.getFilename());
+
+  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
+                                         Exec, CmdArgs, Inputs, Output));
+
+  if (Args.hasArg(options::OPT_gsplit_dwarf))
+    SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
+                   SplitDebugName(JA, Args, Inputs[0], Output));
+}
+
+void tools::Cygwin::Linker::AddLibGCC(const ArgList &Args,
+                                     ArgStringList &CmdArgs) const {
+  // Make use of compiler-rt if --rtlib option is used
+  ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args);
+  if (RLT == ToolChain::RLT_Libgcc) {
+    bool Static = Args.hasArg(options::OPT_static_libgcc) ||
+                  Args.hasArg(options::OPT_static);
+    bool Shared = Args.hasArg(options::OPT_shared);
+    bool CXX = getToolChain().getDriver().CCCIsCXX();
+
+    if (Static || (!CXX && !Shared)) {
+      CmdArgs.push_back("-lgcc");
+      CmdArgs.push_back("-lgcc_eh");
+    } else {
+      CmdArgs.push_back("-lgcc_s");
+      CmdArgs.push_back("-lgcc");
+    }
+  } else {
+    AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args);
+  }
+
+  CmdArgs.push_back("-lcygwin");
+}
+
+void tools::Cygwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+                                        const InputInfo &Output,
+                                        const InputInfoList &Inputs,
+                                        const ArgList &Args,
+                                        const char *LinkingOutput) const {
+  const ToolChain &TC = getToolChain();
+  const Driver &D = TC.getDriver();
+  const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args);
+
+  ArgStringList CmdArgs;
+
+  // Silence warning for "clang -g foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_g_Group);
+  // and "clang -emit-llvm foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_emit_llvm);
+  // and for "clang -w foo.o -o foo". Other warning options are already
+  // handled somewhere else.
+  Args.ClaimAllArgs(options::OPT_w);
+
+  if (!D.SysRoot.empty())
+    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+  if (Args.hasArg(options::OPT_s))
+    CmdArgs.push_back("-s");
+
+  CmdArgs.push_back("-m");
+  switch (TC.getArch()) {
+  case llvm::Triple::x86:
+    CmdArgs.push_back("i386pe");
+    break;
+  case llvm::Triple::x86_64:
+    CmdArgs.push_back("i386pep");
+    break;
+  case llvm::Triple::arm:
+  case llvm::Triple::thumb:
+    // FIXME: this is incorrect for WinCE
+    CmdArgs.push_back("thumb2pe");
+    break;
+  case llvm::Triple::aarch64:
+    CmdArgs.push_back("arm64pe");
+    break;
+  default:
+    D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str();
+  }
+
+  if (!Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link").equals_insensitive("lld")) {
+    if (TC.getArch() == llvm::Triple::x86) {
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_Znwj");
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_Znaj");
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_ZnwjRKSt9nothrow_t");
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_ZnajRKSt9nothrow_t");
+    } else {
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_Znwm");
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_Znam");
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_ZnwmRKSt9nothrow_t");
+      CmdArgs.push_back("--wrap");
+      CmdArgs.push_back("_ZnamRKSt9nothrow_t");
+    }
+    CmdArgs.push_back("--wrap");
+    CmdArgs.push_back("_ZdlPv");
+    CmdArgs.push_back("--wrap");
+    CmdArgs.push_back("_ZdaPv");
+    CmdArgs.push_back("--wrap");
+    CmdArgs.push_back("_ZdlPvRKSt9nothrow_t");
+    CmdArgs.push_back("--wrap");
+    CmdArgs.push_back("_ZdaPvRKSt9nothrow_t");
+  }
+
+  Arg *SubsysArg =
+      Args.getLastArg(options::OPT_mwindows, options::OPT_mconsole);
+  if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mwindows)) {
+    CmdArgs.push_back("--subsystem");
+    CmdArgs.push_back("windows");
+  } else if (SubsysArg &&
+             SubsysArg->getOption().matches(options::OPT_mconsole)) {
+    CmdArgs.push_back("--subsystem");
+    CmdArgs.push_back("console");
+  }
+
+  if (Args.hasArg(options::OPT_mdll))
+    CmdArgs.push_back("--dll");
+  else if (Args.hasArg(options::OPT_shared))
+    CmdArgs.push_back("--shared");
+  if (Args.hasArg(options::OPT_static))
+    CmdArgs.push_back("-Bstatic");
+  else
+    CmdArgs.push_back("-Bdynamic");
+  if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) {
+    CmdArgs.push_back("-e");
+    if (TC.getArch() == llvm::Triple::x86)
+      CmdArgs.push_back("__cygwin_dll_entry at 12");
+    else
+      CmdArgs.push_back("_cygwin_dll_entry");
+    CmdArgs.push_back("--enable-auto-image-base");
+  }
+  CmdArgs.push_back("--dynamicbase");
+
+  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+    CmdArgs.push_back("--no-demangle");
+
+  if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) {
+    StringRef GuardArgs = A->getValue();
+    if (GuardArgs == "none")
+      CmdArgs.push_back("--no-guard-cf");
+    else if (GuardArgs == "cf" || GuardArgs == "cf-nochecks")
+      CmdArgs.push_back("--guard-cf");
+    else
+      D.Diag(diag::err_drv_unsupported_option_argument)
+          << A->getSpelling() << GuardArgs;
+  }
+
+  CmdArgs.push_back("-o");
+  const char *OutputFile = Output.getFilename();
+  // GCC implicitly adds an .exe extension if it is given an output file name
+  // that lacks an extension.
+  // GCC used to do this only when the compiler itself runs on windows, but
+  // since GCC 8 it does the same when cross compiling as well.
+  if (!llvm::sys::path::has_extension(OutputFile)) {
+    CmdArgs.push_back(Args.MakeArgString(Twine(OutputFile) + ".exe"));
+    OutputFile = CmdArgs.back();
+  } else
+    CmdArgs.push_back(OutputFile);
+
+  // FIXME: add -N, -n flags
+  Args.AddLastArg(CmdArgs, options::OPT_r);
+  Args.AddLastArg(CmdArgs, options::OPT_s);
+  Args.AddLastArg(CmdArgs, options::OPT_t);
+  Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
+  Args.AddLastArg(CmdArgs, options::OPT_Z_Flag);
+
+  // Add asan_dynamic as the first import lib before other libs. This allows
+  // asan to be initialized as early as possible to increase its instrumentation
+  // coverage to include other user DLLs which has not been built with asan.
+  if (Sanitize.needsAsanRt() && !Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nodefaultlibs)) {
+    // Cygwin always links against a shared Cygwin DLL.
+    CmdArgs.push_back(
+        TC.getCompilerRTArgString(Args, "asan_dynamic", ToolChain::FT_Shared));
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) {
+      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbeginS.o")));
+    } else {
+      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt0.o")));
+      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
+    }
+    if (Args.hasArg(options::OPT_pg))
+      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt0.o")));
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_L);
+  TC.AddFilePathLibArgs(Args, CmdArgs);
+
+  // Add the compiler-rt library directories if they exist to help
+  // the linker find the various sanitizer, builtin, and profiling runtimes.
+  for (const auto &LibPath : TC.getLibraryPaths()) {
+    if (TC.getVFS().exists(LibPath))
+      CmdArgs.push_back(Args.MakeArgString("-L" + LibPath));
+  }
+  auto CRTPath = TC.getCompilerRTPath();
+  if (TC.getVFS().exists(CRTPath))
+    CmdArgs.push_back(Args.MakeArgString("-L" + CRTPath));
+
+  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+
+  if (C.getDriver().IsFlangMode()) {
+    addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
+    addFortranRuntimeLibs(TC, CmdArgs);
+  }
+
+  // TODO: Add profile stuff here
+
+  if (TC.ShouldLinkCXXStdlib(Args)) {
+    bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
+                               !Args.hasArg(options::OPT_static);
+    if (OnlyLibstdcxxStatic)
+      CmdArgs.push_back("-Bstatic");
+    TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+    if (OnlyLibstdcxxStatic)
+      CmdArgs.push_back("-Bdynamic");
+  }
+
+  bool HasWindowsApp = false;
+  for (auto Lib : Args.getAllArgValues(options::OPT_l)) {
+    if (Lib == "windowsapp") {
+      HasWindowsApp = true;
+      break;
+    }
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib)) {
+    if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+      if (Args.hasArg(options::OPT_static))
+        CmdArgs.push_back("--start-group");
+
+      if (Args.hasArg(options::OPT_fstack_protector) ||
+          Args.hasArg(options::OPT_fstack_protector_strong) ||
+          Args.hasArg(options::OPT_fstack_protector_all)) {
+        CmdArgs.push_back("-lssp_nonshared");
+        CmdArgs.push_back("-lssp");
+      }
+
+      if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+                       options::OPT_fno_openmp, false)) {
+        switch (TC.getDriver().getOpenMPRuntime(Args)) {
+        case Driver::OMPRT_OMP:
+          CmdArgs.push_back("-lomp");
+          break;
+        case Driver::OMPRT_IOMP5:
+          CmdArgs.push_back("-liomp5md");
+          break;
+        case Driver::OMPRT_GOMP:
+          CmdArgs.push_back("-lgomp");
+          break;
+        case Driver::OMPRT_Unknown:
+          // Already diagnosed.
+          break;
+        }
+      }
+
+      AddLibGCC(Args, CmdArgs);
+
+      if (Sanitize.needsAsanRt()) {
+        // Cygwin always links against a shared Cygwin DLL.
+        CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic",
+                                                    ToolChain::FT_Shared));
+        CmdArgs.push_back(
+            TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk"));
+        CmdArgs.push_back("--require-defined");
+        CmdArgs.push_back(TC.getArch() == llvm::Triple::x86
+                              ? "___asan_seh_interceptor"
+                              : "__asan_seh_interceptor");
+        // Make sure the linker consider all object files from the dynamic
+        // runtime thunk.
+        CmdArgs.push_back("--whole-archive");
+        CmdArgs.push_back(
+            TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk"));
+        CmdArgs.push_back("--no-whole-archive");
+      }
+
+      TC.addProfileRTLibs(Args, CmdArgs);
+
+      if (!HasWindowsApp) {
+        // Add system libraries. If linking to libwindowsapp.a, that import
+        // library replaces all these and we shouldn't accidentally try to
+        // link to the normal desktop mode dlls.
+        if (Args.hasArg(options::OPT_mwindows)) {
+          CmdArgs.push_back("-lgdi32");
+          CmdArgs.push_back("-lcomdlg32");
+        }
+        CmdArgs.push_back("-ladvapi32");
+        CmdArgs.push_back("-lshell32");
+        CmdArgs.push_back("-luser32");
+        CmdArgs.push_back("-lkernel32");
+      }
+
+      if (Args.hasArg(options::OPT_static)) {
+        CmdArgs.push_back("--end-group");
+      } else {
+        AddLibGCC(Args, CmdArgs);
+        if (!HasWindowsApp)
+          CmdArgs.push_back("-lkernel32");
+      }
+    }
+
+    if (!Args.hasArg(options::OPT_nostartfiles)) {
+      // Add crtfastmath.o if available and fast math is enabled.
+      TC.addFastMathRuntimeIfAvailable(Args, CmdArgs);
+
+      CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
+    }
+  }
+  const char *Exec = Args.MakeArgString(TC.GetLinkerPath());
+  C.addCommand(std::make_unique<Command>(JA, *this,
+                                         ResponseFileSupport::AtFileUTF8(),
+                                         Exec, CmdArgs, Inputs, Output));
+}
+
+static bool isCrossCompiling(const llvm::Triple &T, bool RequireArchMatch) {
+  llvm::Triple HostTriple(llvm::Triple::normalize(LLVM_HOST_TRIPLE));
+  if (!HostTriple.isWindowsCygwinEnvironment())
+    return true;
+  if (RequireArchMatch && HostTriple.getArch() != T.getArch())
+    return true;
+  return false;
+}
+
+// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
+static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
+                           std::string &Ver,
+                           toolchains::Generic_GCC::GCCVersion &Version) {
+  Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
+  std::error_code EC;
+  for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
+       LI = LI.increment(EC)) {
+    StringRef VersionText = llvm::sys::path::filename(LI->path());
+    auto CandidateVersion =
+        toolchains::Generic_GCC::GCCVersion::Parse(VersionText);
+    if (CandidateVersion.Major == -1)
+      continue;
+    if (CandidateVersion <= Version)
+      continue;
+    Version = CandidateVersion;
+    Ver = std::string(VersionText);
+    GccLibDir = LI->path();
+  }
+  return Ver.size();
+}
+
+static llvm::Triple getLiteralTriple(const Driver &D, const llvm::Triple &T) {
+  llvm::Triple LiteralTriple(D.getTargetTriple());
+  // The arch portion of the triple may be overridden by -m32/-m64.
+  LiteralTriple.setArchName(T.getArchName());
+  return LiteralTriple;
+}
+
+void toolchains::Cygwin::findGccLibDir(const llvm::Triple &LiteralTriple) {
+  llvm::SmallVector<llvm::SmallString<32>, 5> SubdirNames;
+  SubdirNames.emplace_back(getTriple().getArchName());
+  SubdirNames[0] += "-pc-cygwin";
+  SubdirNames.emplace_back("cygwin");
+  if (SubdirName.empty())
+    SubdirName = SubdirNames[0].str();
+  // lib: Arch Linux, Ubuntu, Windows
+  // lib64: openSUSE Linux
+  for (StringRef CandidateLib : {"lib", "lib64"}) {
+    for (StringRef CandidateSysroot : SubdirNames) {
+      llvm::SmallString<1024> LibDir(Base);
+      llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot);
+      if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) {
+        SubdirName = std::string(CandidateSysroot);
+        return;
+      }
+    }
+  }
+}
+
+static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &LiteralTriple,
+                                          const llvm::Triple &T) {
+  llvm::SmallVector<llvm::SmallString<32>, 5> Gccs;
+  Gccs.emplace_back(T.getArchName());
+  Gccs[0] += "-pc-cygwin-gcc";
+  Gccs.emplace_back("cygwin-gcc");
+  // Please do not add "gcc" here
+  for (StringRef CandidateGcc : Gccs)
+    if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc))
+      return GPPName;
+  return make_error_code(std::errc::no_such_file_or_directory);
+}
+
+static llvm::ErrorOr<std::string>
+findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple,
+                         const llvm::Triple &T, std::string &SubdirName) {
+  llvm::SmallVector<llvm::SmallString<32>, 4> Subdirs;
+  Subdirs.emplace_back(T.str());
+  Subdirs.emplace_back(T.getArchName());
+  Subdirs[1] += "-pc-cygwin";
+  StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir());
+  StringRef Sep = llvm::sys::path::get_separator();
+  for (StringRef CandidateSubdir : Subdirs) {
+    if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) {
+      SubdirName = std::string(CandidateSubdir);
+      return (ClangRoot + Sep + CandidateSubdir).str();
+    }
+  }
+  return make_error_code(std::errc::no_such_file_or_directory);
+}
+
+toolchains::Cygwin::Cygwin(const Driver &D, const llvm::Triple &Triple,
+                         const ArgList &Args)
+    : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
+      RocmInstallation(D, Triple, Args) {
+  getProgramPaths().push_back(getDriver().getInstalledDir());
+
+  // The sequence for detecting a sysroot here should be kept in sync with
+  // the testTriple function below.
+  llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple());
+  if (getDriver().SysRoot.size())
+    Base = getDriver().SysRoot;
+  // Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the
+  // base as it could still be a base for a gcc setup with libgcc.
+  else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot(
+               getDriver(), LiteralTriple, getTriple(), SubdirName))
+    Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get()));
+  else if (llvm::ErrorOr<std::string> GPPName =
+               findGcc(LiteralTriple, getTriple()))
+    Base = std::string(llvm::sys::path::parent_path(
+        llvm::sys::path::parent_path(GPPName.get())));
+  else
+    Base = std::string(
+        llvm::sys::path::parent_path(getDriver().getInstalledDir()));
+
+  Base += llvm::sys::path::get_separator();
+  findGccLibDir(LiteralTriple);
+  TripleDirName = SubdirName;
+  // GccLibDir must precede Base/lib so that the
+  // correct crtbegin.o ,cetend.o would be found.
+  getFilePaths().push_back(GccLibDir);
+  getFilePaths().push_back(
+      (Base + SubdirName + llvm::sys::path::get_separator() + "lib").str());
+  getFilePaths().push_back(
+      (Base + SubdirName + llvm::sys::path::get_separator() + "usr/lib").str());
+  getFilePaths().push_back(
+      (Base + SubdirName + llvm::sys::path::get_separator() + "usr/lib/w32api").str());
+
+  // Only include <base>/lib if we're not cross compiling (not even for
+  // windows->windows to a different arch), or if the sysroot has been set
+  // (where we presume the user has pointed it at an arch specific
+  // subdirectory).
+  if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/true) ||
+      getDriver().SysRoot.size())
+    getFilePaths().push_back(Base + "lib");
+
+  // for Cygwin's crt0.o
+  getFilePaths().push_back(getDriver().SysRoot + "/lib");
+  getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+
+  NativeLLVMSupport =
+      Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER)
+          .equals_insensitive("lld");
+}
+
+Tool *toolchains::Cygwin::getTool(Action::ActionClass AC) const {
+  switch (AC) {
+  case Action::PreprocessJobClass:
+    if (!Preprocessor)
+      Preprocessor.reset(new tools::gcc::Preprocessor(*this));
+    return Preprocessor.get();
+  case Action::CompileJobClass:
+    if (!Compiler)
+      Compiler.reset(new tools::gcc::Compiler(*this));
+    return Compiler.get();
+  default:
+    return ToolChain::getTool(AC);
+  }
+}
+
+Tool *toolchains::Cygwin::buildAssembler() const {
+  return new tools::Cygwin::Assembler(*this);
+}
+
+Tool *toolchains::Cygwin::buildLinker() const {
+  return new tools::Cygwin::Linker(*this);
+}
+
+bool toolchains::Cygwin::HasNativeLLVMSupport() const {
+  return NativeLLVMSupport;
+}
+
+ToolChain::UnwindTableLevel
+toolchains::Cygwin::getDefaultUnwindTableLevel(const ArgList &Args) const {
+  Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions,
+                                      options::OPT_fseh_exceptions,
+                                      options::OPT_fdwarf_exceptions);
+  if (ExceptionArg &&
+      ExceptionArg->getOption().matches(options::OPT_fseh_exceptions))
+    return UnwindTableLevel::Asynchronous;
+
+  if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
+      getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
+    return UnwindTableLevel::Asynchronous;
+  return UnwindTableLevel::None;
+}
+
+bool toolchains::Cygwin::isPICDefault() const {
+  return getArch() == llvm::Triple::x86_64 ||
+         getArch() == llvm::Triple::aarch64;
+}
+
+bool toolchains::Cygwin::isPIEDefault(const llvm::opt::ArgList &Args) const {
+  return false;
+}
+
+bool toolchains::Cygwin::isPICDefaultForced() const { return true; }
+
+llvm::ExceptionHandling
+toolchains::Cygwin::GetExceptionModel(const ArgList &Args) const {
+  if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64 ||
+      getArch() == llvm::Triple::arm || getArch() == llvm::Triple::thumb)
+    return llvm::ExceptionHandling::WinEH;
+  return llvm::ExceptionHandling::DwarfCFI;
+}
+
+SanitizerMask toolchains::Cygwin::getSupportedSanitizers() const {
+  SanitizerMask Res = ToolChain::getSupportedSanitizers();
+  Res |= SanitizerKind::Address;
+  Res |= SanitizerKind::PointerCompare;
+  Res |= SanitizerKind::PointerSubtract;
+  Res |= SanitizerKind::Vptr;
+  return Res;
+}
+
+void toolchains::Cygwin::AddCudaIncludeArgs(const ArgList &DriverArgs,
+                                           ArgStringList &CC1Args) const {
+  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+}
+
+void toolchains::Cygwin::AddHIPIncludeArgs(const ArgList &DriverArgs,
+                                          ArgStringList &CC1Args) const {
+  RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
+}
+
+void toolchains::Cygwin::printVerboseInfo(raw_ostream &OS) const {
+  CudaInstallation.print(OS);
+  RocmInstallation.print(OS);
+}
+
+void toolchains::Cygwin::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+                                                  ArgStringList &CC1Args) const {
+  if (DriverArgs.hasArg(options::OPT_nostdinc))
+    return;
+
+  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+    SmallString<1024> P(getDriver().ResourceDir);
+    llvm::sys::path::append(P, "include");
+    addSystemInclude(DriverArgs, CC1Args, P.str());
+  }
+
+  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+    return;
+
+  addSystemInclude(DriverArgs, CC1Args,
+                   Base + SubdirName + llvm::sys::path::get_separator() +
+                       "include");
+  addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/local/include");
+  addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include");
+  addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/w32api");
+}
+
+void toolchains::Cygwin::addClangTargetOptions(
+    const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+    Action::OffloadKind DeviceOffloadKind) const {
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) {
+    StringRef GuardArgs = A->getValue();
+    if (GuardArgs == "none") {
+      // Do nothing.
+    } else if (GuardArgs == "cf") {
+      // Emit CFG instrumentation and the table of address-taken functions.
+      CC1Args.push_back("-cfguard");
+    } else if (GuardArgs == "cf-nochecks") {
+      // Emit only the table of address-taken functions.
+      CC1Args.push_back("-cfguard-no-checks");
+    } else {
+      getDriver().Diag(diag::err_drv_unsupported_option_argument)
+          << A->getSpelling() << GuardArgs;
+    }
+  }
+
+  if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_mthreads))
+    A->ignoreTargetSpecific();
+}
+
+void toolchains::Cygwin::AddClangCXXStdlibIncludeArgs(
+    const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+  if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+                        options::OPT_nostdincxx))
+    return;
+
+  StringRef Slash = llvm::sys::path::get_separator();
+
+  switch (GetCXXStdlibType(DriverArgs)) {
+  case ToolChain::CST_Libcxx:
+    addSystemInclude(DriverArgs, CC1Args,
+                     Base + "include" + Slash + "c++" + Slash + "v1");
+    break;
+
+  case ToolChain::CST_Libstdcxx:
+    llvm::SmallVector<llvm::SmallString<1024>, 7> CppIncludeBases;
+    CppIncludeBases.emplace_back(Base);
+    llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++");
+    CppIncludeBases.emplace_back(Base);
+    llvm::sys::path::append(CppIncludeBases[1], SubdirName, "include", "c++",
+                            Ver);
+    CppIncludeBases.emplace_back(Base);
+    llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
+    CppIncludeBases.emplace_back(GccLibDir);
+    llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
+    for (auto &CppIncludeBase : CppIncludeBases) {
+      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
+      CppIncludeBase += Slash;
+      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + TripleDirName);
+      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
+    }
+    break;
+  }
+}
+
+static bool testTriple(const Driver &D, const llvm::Triple &Triple,
+                       const ArgList &Args) {
+  // If an explicit sysroot is set, that will be used and we shouldn't try to
+  // detect anything else.
+  std::string SubdirName;
+  if (D.SysRoot.size())
+    return true;
+  llvm::Triple LiteralTriple = getLiteralTriple(D, Triple);
+  if (llvm::ErrorOr<std::string> TargetSubdir =
+          findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName))
+    return true;
+  if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple))
+    return true;
+  // If we neither found a colocated sysroot or a matching gcc executable,
+  // conclude that we can't know if this is the correct spelling of the triple.
+  return false;
+}
+
+static llvm::Triple adjustTriple(const Driver &D, const llvm::Triple &Triple,
+                                 const ArgList &Args) {
+  // First test if the original triple can find a sysroot with the triple
+  // name.
+  if (testTriple(D, Triple, Args))
+    return Triple;
+  llvm::SmallVector<llvm::StringRef, 3> Archs;
+  // If not, test a couple other possible arch names that might be what was
+  // intended.
+  if (Triple.getArch() == llvm::Triple::x86) {
+    Archs.emplace_back("i386");
+    Archs.emplace_back("i586");
+    Archs.emplace_back("i686");
+  } else if (Triple.getArch() == llvm::Triple::arm ||
+             Triple.getArch() == llvm::Triple::thumb) {
+    Archs.emplace_back("armv7");
+  }
+  for (auto A : Archs) {
+    llvm::Triple TestTriple(Triple);
+    TestTriple.setArchName(A);
+    if (testTriple(D, TestTriple, Args))
+      return TestTriple;
+  }
+  // If none was found, just proceed with the original value.
+  return Triple;
+}
+
+void toolchains::Cygwin::fixTripleArch(const Driver &D, llvm::Triple &Triple,
+                                      const ArgList &Args) {
+  if (Triple.getArch() == llvm::Triple::x86 ||
+      Triple.getArch() == llvm::Triple::arm ||
+      Triple.getArch() == llvm::Triple::thumb)
+    Triple = adjustTriple(D, Triple, Args);
+}
diff --git a/clang/lib/Driver/ToolChains/Cygwin.h b/clang/lib/Driver/ToolChains/Cygwin.h
new file mode 100644
index 0000000000000..9866863389eb6
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Cygwin.h
@@ -0,0 +1,125 @@
+//===--- Cygwin.h - Cygwin ToolChain Implementations --------------*- C++ -*-===//
+//
+// 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_LIB_DRIVER_TOOLCHAINS_CYGWIN_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CYGWIN_H
+
+#include "Cuda.h"
+#include "Gnu.h"
+#include "ROCm.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+#include "llvm/Support/ErrorOr.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// Cygwin -- Directly call GNU Binutils assembler and linker
+namespace Cygwin {
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+public:
+  Assembler(const ToolChain &TC) : Tool("Cygwin::Assemble", "assembler", TC) {}
+
+  bool hasIntegratedCPP() const override { return false; }
+
+  void ConstructJob(Compilation &C, const JobAction &JA,
+                    const InputInfo &Output, const InputInfoList &Inputs,
+                    const llvm::opt::ArgList &TCArgs,
+                    const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+  Linker(const ToolChain &TC) : Tool("Cygwin::Linker", "linker", TC) {}
+
+  bool hasIntegratedCPP() const override { return false; }
+  bool isLinkJob() const override { return true; }
+
+  void ConstructJob(Compilation &C, const JobAction &JA,
+                    const InputInfo &Output, const InputInfoList &Inputs,
+                    const llvm::opt::ArgList &TCArgs,
+                    const char *LinkingOutput) const override;
+
+private:
+  void AddLibGCC(const llvm::opt::ArgList &Args,
+                 llvm::opt::ArgStringList &CmdArgs) const;
+};
+} // end namespace Cygwin
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Cygwin : public ToolChain {
+public:
+  Cygwin(const Driver &D, const llvm::Triple &Triple,
+        const llvm::opt::ArgList &Args);
+
+  static void fixTripleArch(const Driver &D, llvm::Triple &Triple,
+                            const llvm::opt::ArgList &Args);
+
+  bool HasNativeLLVMSupport() const override;
+
+  UnwindTableLevel
+  getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
+  bool isPICDefault() const override;
+  bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
+  bool isPICDefaultForced() const override;
+
+  SanitizerMask getSupportedSanitizers() const override;
+
+  llvm::ExceptionHandling GetExceptionModel(
+      const llvm::opt::ArgList &Args) const override;
+
+  void
+  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                            llvm::opt::ArgStringList &CC1Args) const override;
+  void
+  addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+                        llvm::opt::ArgStringList &CC1Args,
+                        Action::OffloadKind DeviceOffloadKind) const override;
+  void AddClangCXXStdlibIncludeArgs(
+      const llvm::opt::ArgList &DriverArgs,
+      llvm::opt::ArgStringList &CC1Args) const override;
+
+  void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                          llvm::opt::ArgStringList &CC1Args) const override;
+  void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                         llvm::opt::ArgStringList &CC1Args) const override;
+
+  void printVerboseInfo(raw_ostream &OS) const override;
+
+  unsigned GetDefaultDwarfVersion() const override { return 4; }
+
+protected:
+  Tool *getTool(Action::ActionClass AC) const override;
+  Tool *buildLinker() const override;
+  Tool *buildAssembler() const override;
+
+private:
+  CudaInstallationDetector CudaInstallation;
+  RocmInstallationDetector RocmInstallation;
+
+  std::string Base;
+  std::string GccLibDir;
+  clang::driver::toolchains::Generic_GCC::GCCVersion GccVer;
+  std::string Ver;
+  std::string SubdirName;
+  std::string TripleDirName;
+  mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
+  mutable std::unique_ptr<tools::gcc::Compiler> Compiler;
+  void findGccLibDir(const llvm::Triple &LiteralTriple);
+
+  bool NativeLLVMSupport;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CYGWIN_H
diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp
index 5b1b7c859c85d..344a5cb88cef9 100644
--- a/clang/lib/Lex/InitHeaderSearch.cpp
+++ b/clang/lib/Lex/InitHeaderSearch.cpp
@@ -205,9 +205,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
   if (HSOpts.UseStandardSystemIncludes) {
     switch (os) {
     case llvm::Triple::Win32:
-      if (triple.getEnvironment() != llvm::Triple::Cygnus)
-        break;
-      [[fallthrough]];
+      break;
     default:
       // FIXME: temporary hack: hard-coded paths.
       AddPath("/usr/local/include", System, false);
@@ -242,14 +240,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
 
   switch (os) {
   case llvm::Triple::Win32:
-    switch (triple.getEnvironment()) {
-    default: llvm_unreachable("Include management is handled in the driver.");
-    case llvm::Triple::Cygnus:
-      AddPath("/usr/include/w32api", System, false);
-      break;
-    case llvm::Triple::GNU:
-      break;
-    }
+    llvm_unreachable("Include management is handled in the driver.");
     break;
   default:
     break;
@@ -268,17 +259,7 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
   llvm::Triple::OSType os = triple.getOS();
   switch (os) {
   case llvm::Triple::Win32:
-    switch (triple.getEnvironment()) {
-    default: llvm_unreachable("Include management is handled in the driver.");
-    case llvm::Triple::Cygnus:
-      // Cygwin-1.7
-      AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.7.3");
-      AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.5.3");
-      AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
-      // g++-4 / Cygwin-1.5
-      AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
-      break;
-    }
+    llvm_unreachable("Include management is handled in the driver.");
     break;
   default:
     break;
@@ -310,10 +291,7 @@ bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
     return false;
 
   case llvm::Triple::Win32:
-    if (triple.getEnvironment() != llvm::Triple::Cygnus ||
-        triple.isOSBinFormatMachO())
-      return false;
-    break;
+    return false;
 
   case llvm::Triple::UnknownOS:
     if (triple.isWasm())



More information about the cfe-commits mailing list