[clang] [Clang][Driver] Revise Cygwin ToolChain to call linker directly (PR #147960)

via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 12 10:15:40 PDT 2025


================
@@ -107,3 +110,293 @@ void Cygwin::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
   addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
   addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/w32api");
 }
+
+void cygwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+                                  const InputInfo &Output,
+                                  const InputInfoList &Inputs,
+                                  const ArgList &Args,
+                                  const char *LinkingOutput) const {
+  const auto &ToolChain = getToolChain();
+  const Driver &D = ToolChain.getDriver();
+
+  const bool IsStatic = Args.hasArg(options::OPT_static);
+
+  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 (ToolChain.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:
+    if (Args.hasArg(options::OPT_marm64x))
+      CmdArgs.push_back("arm64xpe");
+    else if (ToolChain.getEffectiveTriple().isWindowsArm64EC())
+      CmdArgs.push_back("arm64ecpe");
+    else
+      CmdArgs.push_back("arm64pe");
+    break;
+  case llvm::Triple::mipsel:
+    CmdArgs.push_back("mipspe");
+    break;
+  default:
+    D.Diag(diag::err_target_unknown_triple)
+        << ToolChain.getEffectiveTriple().str();
+  }
+
+  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 (ToolChain.getTriple().isArch32Bit()) {
+    CmdArgs.push_back("--wrap=_Znwj");
+    CmdArgs.push_back("--wrap=_Znaj");
+    CmdArgs.push_back("--wrap=_ZdlPv");
+    CmdArgs.push_back("--wrap=_ZdaPv");
+    CmdArgs.push_back("--wrap=_ZnwjRKSt9nothrow_t");
+    CmdArgs.push_back("--wrap=_ZnajRKSt9nothrow_t");
+    CmdArgs.push_back("--wrap=_ZdlPvRKSt9nothrow_t");
+    CmdArgs.push_back("--wrap=_ZdaPvRKSt9nothrow_t");
+  } else {
+    CmdArgs.push_back("--wrap=_Znwm");
+    CmdArgs.push_back("--wrap=_Znam");
+    CmdArgs.push_back("--wrap=_ZdlPv");
+    CmdArgs.push_back("--wrap=_ZdaPv");
+    CmdArgs.push_back("--wrap=_ZnwmRKSt9nothrow_t");
+    CmdArgs.push_back("--wrap=_ZnamRKSt9nothrow_t");
+    CmdArgs.push_back("--wrap=_ZdlPvRKSt9nothrow_t");
+    CmdArgs.push_back("--wrap=_ZdaPvRKSt9nothrow_t");
+  }
+
+  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");
+
+  CmdArgs.push_back("--dll-search-prefix=cyg");
+
+  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);
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+                   options::OPT_r)) {
+    const bool IsShared = Args.hasArg(options::OPT_shared);
+    if (Args.hasArg(options::OPT_mdll) || IsShared) {
+      CmdArgs.push_back("-e");
+      CmdArgs.push_back(ToolChain.getArch() == llvm::Triple::x86
+                            ? "__cygwin_dll_entry at 12"
+                            : "_cygwin_dll_entry");
+      CmdArgs.push_back("--enable-auto-image-base");
+    }
+
+    if (!Args.hasArg(options::OPT_mdll) && !IsShared)
+      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
+    if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
+      std::string crtbegin =
+          ToolChain.getCompilerRT(Args, "crtbegin", ToolChain::FT_Object);
+      if (ToolChain.getVFS().exists(crtbegin)) {
+        std::string P;
+        P = crtbegin;
+        CmdArgs.push_back(Args.MakeArgString(P));
+      }
+    }
+    if (IsShared)
+      CmdArgs.push_back(
+          Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
+    else
+      CmdArgs.push_back(
+          Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
+
+    // Add crtfastmath.o if available and fast math is enabled.
+    ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
+  }
+
+  Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
+
+  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+  if (D.isUsingLTO())
+    tools::addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,
+                         D.getLTOMode() == LTOK_Thin);
+
+  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+    CmdArgs.push_back("--no-demangle");
+
+  bool NeedsSanitizerDeps =
+      tools::addSanitizerRuntimes(ToolChain, Args, CmdArgs);
+  bool NeedsXRayDeps = tools::addXRayRuntime(ToolChain, Args, CmdArgs);
+  tools::addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
+  tools::AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+  bool saw_high_entropy_va = false;
+  bool saw_nxcompat = false;
+  for (const char *Arg : CmdArgs) {
+    if (StringRef(Arg) == "-high-entropy-va" ||
+        StringRef(Arg) == "--high-entropy-va" ||
+        StringRef(Arg) == "-disable-high-entropy-va" ||
+        StringRef(Arg) == "--disable-high-entropy-va")
+      saw_high_entropy_va = true;
+    if (StringRef(Arg) == "-nxcompat" || StringRef(Arg) == "--nxcompat" ||
+        StringRef(Arg) == "-disable-nxcompat" ||
+        StringRef(Arg) == "--disable-nxcompat")
+      saw_nxcompat = true;
+  }
+  if (!saw_high_entropy_va)
+    CmdArgs.push_back("--disable-high-entropy-va");
----------------
jeremyd2019 wrote:

Got an error on 32-bit due to the presence of this option.  Should only be added on 64-bit.

https://github.com/llvm/llvm-project/pull/147960


More information about the cfe-commits mailing list