Skip to content

Commit bcc8d51

Browse files
committed
[Clang][Driver] Revise Cygwin ToolChain to call linker directly
...so that libc++, compiler-rt, and libunwind can be used by the options: -stdlib=libc++, -rtlib=compiler-rt, and -unwindlib=libunwind respectively. Along with this change, the test for this driver is also trimmed a bit. This is a follow-up patch to the commit 52924a2. Signed-off-by: Takashi Yano <[email protected]>
1 parent 7bbb65c commit bcc8d51

File tree

9 files changed

+349
-12
lines changed

9 files changed

+349
-12
lines changed

clang/lib/Driver/ToolChain.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,8 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC,
684684
StringRef ToolChain::getOSLibName() const {
685685
if (Triple.isOSDarwin())
686686
return "darwin";
687+
if (Triple.isWindowsCygwinEnvironment())
688+
return "cygwin";
687689

688690
switch (Triple.getOS()) {
689691
case llvm::Triple::FreeBSD:

clang/lib/Driver/ToolChains/Cygwin.cpp

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Cygwin.h"
1010
#include "clang/Config/config.h"
1111
#include "clang/Driver/CommonArgs.h"
12+
#include "clang/Driver/Compilation.h"
1213
#include "clang/Driver/Driver.h"
1314
#include "clang/Driver/Options.h"
1415
#include "llvm/Support/Path.h"
@@ -30,6 +31,8 @@ Cygwin::Cygwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
3031
Generic_GCC::PushPPaths(PPaths);
3132

3233
path_list &Paths = getFilePaths();
34+
if (GCCInstallation.isValid())
35+
Paths.push_back(GCCInstallation.getInstallPath().str());
3336

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

@@ -107,3 +110,272 @@ void Cygwin::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
107110
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
108111
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/w32api");
109112
}
113+
114+
void cygwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
115+
const InputInfo &Output,
116+
const InputInfoList &Inputs,
117+
const ArgList &Args,
118+
const char *LinkingOutput) const {
119+
const auto &ToolChain = getToolChain();
120+
const Driver &D = ToolChain.getDriver();
121+
122+
const bool IsStatic = Args.hasArg(options::OPT_static);
123+
124+
ArgStringList CmdArgs;
125+
126+
// Silence warning for "clang -g foo.o -o foo"
127+
Args.ClaimAllArgs(options::OPT_g_Group);
128+
// and "clang -emit-llvm foo.o -o foo"
129+
Args.ClaimAllArgs(options::OPT_emit_llvm);
130+
// and for "clang -w foo.o -o foo". Other warning options are already
131+
// handled somewhere else.
132+
Args.ClaimAllArgs(options::OPT_w);
133+
134+
if (!D.SysRoot.empty())
135+
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
136+
137+
if (Args.hasArg(options::OPT_s))
138+
CmdArgs.push_back("-s");
139+
140+
CmdArgs.push_back("-m");
141+
switch (ToolChain.getArch()) {
142+
case llvm::Triple::x86:
143+
CmdArgs.push_back("i386pe");
144+
break;
145+
case llvm::Triple::x86_64:
146+
CmdArgs.push_back("i386pep");
147+
break;
148+
case llvm::Triple::arm:
149+
case llvm::Triple::thumb:
150+
// FIXME: this is incorrect for WinCE
151+
CmdArgs.push_back("thumb2pe");
152+
break;
153+
case llvm::Triple::aarch64:
154+
if (Args.hasArg(options::OPT_marm64x))
155+
CmdArgs.push_back("arm64xpe");
156+
else if (ToolChain.getEffectiveTriple().isWindowsArm64EC())
157+
CmdArgs.push_back("arm64ecpe");
158+
else
159+
CmdArgs.push_back("arm64pe");
160+
break;
161+
case llvm::Triple::mipsel:
162+
CmdArgs.push_back("mipspe");
163+
break;
164+
default:
165+
D.Diag(diag::err_target_unknown_triple)
166+
<< ToolChain.getEffectiveTriple().str();
167+
}
168+
169+
Arg *SubsysArg =
170+
Args.getLastArg(options::OPT_mwindows, options::OPT_mconsole);
171+
if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mwindows)) {
172+
CmdArgs.push_back("--subsystem");
173+
CmdArgs.push_back("windows");
174+
} else if (SubsysArg &&
175+
SubsysArg->getOption().matches(options::OPT_mconsole)) {
176+
CmdArgs.push_back("--subsystem");
177+
CmdArgs.push_back("console");
178+
}
179+
180+
CmdArgs.push_back("--wrap=_Znwm");
181+
CmdArgs.push_back("--wrap=_Znam");
182+
CmdArgs.push_back("--wrap=_ZdlPv");
183+
CmdArgs.push_back("--wrap=_ZdaPv");
184+
CmdArgs.push_back("--wrap=_ZnwmRKSt9nothrow_t");
185+
CmdArgs.push_back("--wrap=_ZnamRKSt9nothrow_t");
186+
CmdArgs.push_back("--wrap=_ZdlPvRKSt9nothrow_t");
187+
CmdArgs.push_back("--wrap=_ZdaPvRKSt9nothrow_t");
188+
189+
if (Args.hasArg(options::OPT_mdll))
190+
CmdArgs.push_back("--dll");
191+
else if (Args.hasArg(options::OPT_shared))
192+
CmdArgs.push_back("--shared");
193+
if (Args.hasArg(options::OPT_static))
194+
CmdArgs.push_back("-Bstatic");
195+
else
196+
CmdArgs.push_back("-Bdynamic");
197+
198+
CmdArgs.push_back("--dll-search-prefix=cyg");
199+
200+
CmdArgs.push_back("-o");
201+
const char *OutputFile = Output.getFilename();
202+
// GCC implicitly adds an .exe extension if it is given an output file name
203+
// that lacks an extension.
204+
// GCC used to do this only when the compiler itself runs on windows, but
205+
// since GCC 8 it does the same when cross compiling as well.
206+
if (!llvm::sys::path::has_extension(OutputFile)) {
207+
CmdArgs.push_back(Args.MakeArgString(Twine(OutputFile) + ".exe"));
208+
OutputFile = CmdArgs.back();
209+
} else
210+
CmdArgs.push_back(OutputFile);
211+
212+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
213+
options::OPT_r)) {
214+
const bool IsShared = Args.hasArg(options::OPT_shared);
215+
if (Args.hasArg(options::OPT_mdll) || IsShared) {
216+
CmdArgs.push_back("-e");
217+
CmdArgs.push_back(ToolChain.getArch() == llvm::Triple::x86
218+
? "__cygwin_dll_entry@12"
219+
: "_cygwin_dll_entry");
220+
CmdArgs.push_back("--enable-auto-image-base");
221+
}
222+
223+
if (!Args.hasArg(options::OPT_mdll) && !IsShared)
224+
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
225+
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
226+
std::string crtbegin =
227+
ToolChain.getCompilerRT(Args, "crtbegin", ToolChain::FT_Object);
228+
if (ToolChain.getVFS().exists(crtbegin)) {
229+
std::string P;
230+
P = crtbegin;
231+
CmdArgs.push_back(Args.MakeArgString(P));
232+
}
233+
}
234+
if (IsShared)
235+
CmdArgs.push_back(
236+
Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
237+
else
238+
CmdArgs.push_back(
239+
Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
240+
241+
// Add crtfastmath.o if available and fast math is enabled.
242+
ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
243+
}
244+
245+
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
246+
247+
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
248+
249+
if (D.isUsingLTO())
250+
tools::addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,
251+
D.getLTOMode() == LTOK_Thin);
252+
253+
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
254+
CmdArgs.push_back("--no-demangle");
255+
256+
bool NeedsSanitizerDeps =
257+
tools::addSanitizerRuntimes(ToolChain, Args, CmdArgs);
258+
bool NeedsXRayDeps = tools::addXRayRuntime(ToolChain, Args, CmdArgs);
259+
tools::addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
260+
tools::AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
261+
262+
bool saw_high_entropy_va = false;
263+
for (const char *Arg : CmdArgs)
264+
if (StringRef(Arg) == "--high-entropy-va" ||
265+
StringRef(Arg) == "--disable-high-entropy-va")
266+
saw_high_entropy_va = true;
267+
if (!saw_high_entropy_va)
268+
CmdArgs.push_back("--disable-high-entropy-va");
269+
270+
tools::addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs);
271+
272+
// The profile runtime also needs access to system libraries.
273+
getToolChain().addProfileRTLibs(Args, CmdArgs);
274+
275+
if (D.CCCIsCXX() &&
276+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
277+
options::OPT_r)) {
278+
if (ToolChain.ShouldLinkCXXStdlib(Args)) {
279+
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
280+
!Args.hasArg(options::OPT_static);
281+
if (OnlyLibstdcxxStatic)
282+
CmdArgs.push_back("-Bstatic");
283+
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
284+
if (OnlyLibstdcxxStatic)
285+
CmdArgs.push_back("-Bdynamic");
286+
}
287+
CmdArgs.push_back("-lm");
288+
}
289+
290+
// Silence warnings when linking C code with a C++ '-stdlib' argument.
291+
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
292+
293+
// Additional linker set-up and flags for Fortran. This is required in order
294+
// to generate executables. As Fortran runtime depends on the C runtime,
295+
// these dependencies need to be listed before the C runtime below (i.e.
296+
// AddRunTimeLibs).
297+
if (D.IsFlangMode() &&
298+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
299+
ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);
300+
ToolChain.addFortranRuntimeLibs(Args, CmdArgs);
301+
CmdArgs.push_back("-lm");
302+
}
303+
304+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
305+
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
306+
if (IsStatic)
307+
CmdArgs.push_back("--start-group");
308+
309+
if (NeedsSanitizerDeps)
310+
tools::linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
311+
312+
if (NeedsXRayDeps)
313+
tools::linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
314+
315+
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
316+
Args.hasArg(options::OPT_pthreads);
317+
318+
// Use the static OpenMP runtime with -static-openmp
319+
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
320+
!Args.hasArg(options::OPT_static);
321+
322+
// FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
323+
// require librt. Most modern Linux platforms do, but some may not.
324+
if (tools::addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP,
325+
JA.isHostOffloading(Action::OFK_OpenMP),
326+
/* GompNeedsRT= */ true))
327+
// OpenMP runtimes implies pthreads when using the GNU toolchain.
328+
// FIXME: Does this really make sense for all GNU toolchains?
329+
WantPthread = true;
330+
331+
tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
332+
333+
if (WantPthread)
334+
CmdArgs.push_back("-lpthread");
335+
336+
if (Args.hasArg(options::OPT_fsplit_stack))
337+
CmdArgs.push_back("--wrap=pthread_create");
338+
339+
if (!Args.hasArg(options::OPT_nolibc))
340+
CmdArgs.push_back("-lc");
341+
342+
// Cygwin specific
343+
CmdArgs.push_back("-lcygwin");
344+
if (Args.hasArg(options::OPT_mwindows)) {
345+
CmdArgs.push_back("-lgdi32");
346+
CmdArgs.push_back("-lcomdlg32");
347+
}
348+
CmdArgs.push_back("-ladvapi32");
349+
CmdArgs.push_back("-lshell32");
350+
CmdArgs.push_back("-luser32");
351+
CmdArgs.push_back("-lkernel32");
352+
353+
if (IsStatic)
354+
CmdArgs.push_back("--end-group");
355+
else
356+
tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
357+
}
358+
359+
if (!Args.hasArg(options::OPT_nostartfiles)) {
360+
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
361+
std::string crtend =
362+
ToolChain.getCompilerRT(Args, "crtend", ToolChain::FT_Object);
363+
if (ToolChain.getVFS().exists(crtend)) {
364+
std::string P;
365+
P = crtend;
366+
CmdArgs.push_back(Args.MakeArgString(P));
367+
}
368+
}
369+
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
370+
}
371+
}
372+
373+
Args.addAllArgs(CmdArgs, {options::OPT_T, options::OPT_t});
374+
375+
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
376+
C.addCommand(std::make_unique<Command>(JA, *this,
377+
ResponseFileSupport::AtFileCurCP(),
378+
Exec, CmdArgs, Inputs, Output));
379+
}
380+
381+
auto Cygwin::buildLinker() const -> Tool * { return new cygwin::Linker(*this); }

clang/lib/Driver/ToolChains/Cygwin.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,25 @@ class LLVM_LIBRARY_VISIBILITY Cygwin : public Generic_GCC {
2727
void
2828
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
2929
llvm::opt::ArgStringList &CC1Args) const override;
30+
31+
protected:
32+
Tool *buildLinker() const override;
33+
};
34+
35+
namespace cygwin {
36+
class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
37+
public:
38+
Linker(const ToolChain &TC) : Tool("cygwin::Linker", "linker", TC) {}
39+
40+
bool hasIntegratedCPP() const override { return false; }
41+
bool isLinkJob() const override { return true; }
42+
43+
void ConstructJob(Compilation &C, const JobAction &JA,
44+
const InputInfo &Output, const InputInfoList &Inputs,
45+
const llvm::opt::ArgList &TCArgs,
46+
const char *LinkingOutput) const override;
3047
};
48+
} // end namespace cygwin
3149

3250
} // end namespace toolchains
3351
} // end namespace driver

clang/test/Driver/Inputs/basic_cross_cygwin_tree/usr/lib/gcc/i686-pc-msys/10/crtend.o

Whitespace-only changes.

clang/test/Driver/Inputs/basic_cross_cygwin_tree/usr/lib/gcc/x86_64-pc-cygwin/10/crtend.o

Whitespace-only changes.

clang/test/Driver/Inputs/basic_cygwin_tree/usr/lib/crt0.o

Whitespace-only changes.

clang/test/Driver/Inputs/basic_cygwin_tree/usr/lib/gcc/i686-pc-cygwin/10/crtend.o

Whitespace-only changes.

clang/test/Driver/Inputs/basic_cygwin_tree/usr/lib/gcc/x86_64-pc-msys/10/crtend.o

Whitespace-only changes.

0 commit comments

Comments
 (0)