Skip to content

Commit b4955d2

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 b4955d2

File tree

9 files changed

+326
-12
lines changed

9 files changed

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