Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,8 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC,
StringRef ToolChain::getOSLibName() const {
if (Triple.isOSDarwin())
return "darwin";
if (Triple.isWindowsCygwinEnvironment())
return "cygwin";

switch (Triple.getOS()) {
case llvm::Triple::FreeBSD:
Expand Down
293 changes: 293 additions & 0 deletions clang/lib/Driver/ToolChains/Cygwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Cygwin.h"
#include "clang/Config/config.h"
#include "clang/Driver/CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/Support/Path.h"
Expand All @@ -30,6 +31,8 @@ Cygwin::Cygwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
Generic_GCC::PushPPaths(PPaths);

path_list &Paths = getFilePaths();
if (GCCInstallation.isValid())
Paths.push_back(GCCInstallation.getInstallPath().str());

Generic_GCC::AddMultiarchPaths(D, SysRoot, "lib", Paths);

Expand Down Expand Up @@ -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@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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!saw_high_entropy_va)
CmdArgs.push_back("--disable-high-entropy-va");
if (!saw_high_entropy_va && ToolChain.getTriple().isArch64Bit())
CmdArgs.push_back("--disable-high-entropy-va");

if (!saw_nxcompat)
CmdArgs.push_back("--disable-nxcompat");

tools::addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs);

// The profile runtime also needs access to system libraries.
getToolChain().addProfileRTLibs(Args, CmdArgs);

if (D.CCCIsCXX() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
options::OPT_r)) {
if (ToolChain.ShouldLinkCXXStdlib(Args)) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
if (OnlyLibstdcxxStatic)
CmdArgs.push_back("-Bstatic");
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (OnlyLibstdcxxStatic)
CmdArgs.push_back("-Bdynamic");
}
CmdArgs.push_back("-lm");
}

// Silence warnings when linking C code with a C++ '-stdlib' argument.
Args.ClaimAllArgs(options::OPT_stdlib_EQ);

// Additional linker set-up and flags for Fortran. This is required in order
// to generate executables. As Fortran runtime depends on the C runtime,
// these dependencies need to be listed before the C runtime below (i.e.
// AddRunTimeLibs).
if (D.IsFlangMode() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);
ToolChain.addFortranRuntimeLibs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}

if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
if (IsStatic)
CmdArgs.push_back("--start-group");

if (NeedsSanitizerDeps)
tools::linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);

if (NeedsXRayDeps)
tools::linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);

bool WantPthread = Args.hasArg(options::OPT_pthread) ||
Args.hasArg(options::OPT_pthreads);

// Use the static OpenMP runtime with -static-openmp
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
!Args.hasArg(options::OPT_static);

// FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
// require librt. Most modern Linux platforms do, but some may not.
if (tools::addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP,
JA.isHostOffloading(Action::OFK_OpenMP),
/* GompNeedsRT= */ true))
// OpenMP runtimes implies pthreads when using the GNU toolchain.
// FIXME: Does this really make sense for all GNU toolchains?
WantPthread = true;

tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);

if (WantPthread)
CmdArgs.push_back("-lpthread");

if (Args.hasArg(options::OPT_fsplit_stack))
CmdArgs.push_back("--wrap=pthread_create");

if (!Args.hasArg(options::OPT_nolibc))
CmdArgs.push_back("-lc");

// Cygwin specific
CmdArgs.push_back("-lcygwin");
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 (IsStatic)
CmdArgs.push_back("--end-group");
else
tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
}

if (!Args.hasArg(options::OPT_nostartfiles)) {
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
std::string crtend =
ToolChain.getCompilerRT(Args, "crtend", ToolChain::FT_Object);
if (ToolChain.getVFS().exists(crtend)) {
std::string P;
P = crtend;
CmdArgs.push_back(Args.MakeArgString(P));
}
}
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
}
}

Args.addAllArgs(CmdArgs, {options::OPT_T, options::OPT_t});

const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
}

auto Cygwin::buildLinker() const -> Tool * { return new cygwin::Linker(*this); }
18 changes: 18 additions & 0 deletions clang/lib/Driver/ToolChains/Cygwin.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,25 @@ class LLVM_LIBRARY_VISIBILITY Cygwin : public Generic_GCC {
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;

protected:
Tool *buildLinker() const override;
};

namespace cygwin {
class LLVM_LIBRARY_VISIBILITY Linker final : 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;
};
} // end namespace cygwin

} // end namespace toolchains
} // end namespace driver
Expand Down
Empty file.
Loading