Skip to content

Commit 06af0fe

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. Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
1 parent 7bbb65c commit 06af0fe

File tree

9 files changed

+321
-8
lines changed

9 files changed

+321
-8
lines changed

clang/lib/Driver/ToolChain.cpp

Lines changed: 3 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:
@@ -1504,6 +1506,7 @@ void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
15041506
switch (Type) {
15051507
case ToolChain::CST_Libcxx:
15061508
CmdArgs.push_back("-lc++");
1509+
CmdArgs.push_back("-lc++abi");
15071510
if (Args.hasArg(options::OPT_fexperimental_library))
15081511
CmdArgs.push_back("-lc++experimental");
15091512
break;

clang/lib/Driver/ToolChains/Cygwin.cpp

Lines changed: 289 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,289 @@ 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 = static_cast<const Cygwin &>(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) << ToolChain.getEffectiveTriple().str();
181+
}
182+
183+
CmdArgs.push_back("--wrap=_Znwm");
184+
CmdArgs.push_back("--wrap=_Znam");
185+
CmdArgs.push_back("--wrap=_ZdlPv");
186+
CmdArgs.push_back("--wrap=_ZdaPv");
187+
CmdArgs.push_back("--wrap=_ZnwmRKSt9nothrow_t");
188+
CmdArgs.push_back("--wrap=_ZnamRKSt9nothrow_t");
189+
CmdArgs.push_back("--wrap=_ZdlPvRKSt9nothrow_t");
190+
CmdArgs.push_back("--wrap=_ZdaPvRKSt9nothrow_t");
191+
192+
const bool IsShared = Args.hasArg(options::OPT_shared);
193+
if (IsShared)
194+
CmdArgs.push_back("-shared");
195+
bool IsPIE = false;
196+
if (IsStaticPIE) {
197+
CmdArgs.push_back("-static");
198+
CmdArgs.push_back("-pie");
199+
CmdArgs.push_back("--no-dynamic-linker");
200+
CmdArgs.push_back("-z");
201+
CmdArgs.push_back("text");
202+
} else if (IsStatic) {
203+
CmdArgs.push_back("-static");
204+
} else if (!Args.hasArg(options::OPT_r)) {
205+
if (Args.hasArg(options::OPT_rdynamic))
206+
CmdArgs.push_back("-export-dynamic");
207+
if (!IsShared) {
208+
IsPIE = Args.hasFlag(options::OPT_pie, options::OPT_no_pie,
209+
ToolChain.isPIEDefault(Args));
210+
if (IsPIE)
211+
CmdArgs.push_back("-pie");
212+
}
213+
}
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+
if (IsShared) {
226+
CmdArgs.push_back("-e");
227+
CmdArgs.push_back("_cygwin_dll_entry");
228+
CmdArgs.push_back("--enable-auto-image-base");
229+
}
230+
231+
if (!IsShared)
232+
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
233+
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
234+
std::string crtbegin = ToolChain.getCompilerRT(Args, "crtbegin",
235+
ToolChain::FT_Object);
236+
if (ToolChain.getVFS().exists(crtbegin)) {
237+
std::string P;
238+
P = crtbegin;
239+
CmdArgs.push_back(Args.MakeArgString(P));
240+
}
241+
}
242+
if (IsShared)
243+
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
244+
else
245+
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
246+
247+
// Add crtfastmath.o if available and fast math is enabled.
248+
ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
249+
}
250+
251+
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});
252+
253+
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
254+
255+
CmdArgs.push_back(Args.MakeArgString(
256+
"-L" + ToolChain.getGCCInstallation().getInstallPath()));
257+
258+
if (D.isUsingLTO()) {
259+
assert(!Inputs.empty() && "Must have at least one input.");
260+
// Find the first filename InputInfo object.
261+
auto Input = llvm::find_if(
262+
Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
263+
if (Input == Inputs.end())
264+
// For a very rare case, all of the inputs to the linker are
265+
// InputArg. If that happens, just use the first InputInfo.
266+
Input = Inputs.begin();
267+
268+
tools::addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
269+
D.getLTOMode() == LTOK_Thin);
270+
}
271+
272+
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
273+
CmdArgs.push_back("--no-demangle");
274+
275+
bool NeedsSanitizerDeps = tools::addSanitizerRuntimes(ToolChain, Args, CmdArgs);
276+
bool NeedsXRayDeps = tools::addXRayRuntime(ToolChain, Args, CmdArgs);
277+
tools::addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
278+
tools::AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
279+
280+
tools::addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs);
281+
282+
// The profile runtime also needs access to system libraries.
283+
getToolChain().addProfileRTLibs(Args, CmdArgs);
284+
285+
if (D.CCCIsCXX() &&
286+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
287+
options::OPT_r)) {
288+
if (ToolChain.ShouldLinkCXXStdlib(Args)) {
289+
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
290+
!Args.hasArg(options::OPT_static);
291+
if (OnlyLibstdcxxStatic)
292+
CmdArgs.push_back("-Bstatic");
293+
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
294+
if (OnlyLibstdcxxStatic)
295+
CmdArgs.push_back("-Bdynamic");
296+
}
297+
CmdArgs.push_back("-lm");
298+
}
299+
300+
// Silence warnings when linking C code with a C++ '-stdlib' argument.
301+
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
302+
303+
// Additional linker set-up and flags for Fortran. This is required in order
304+
// to generate executables. As Fortran runtime depends on the C runtime,
305+
// these dependencies need to be listed before the C runtime below (i.e.
306+
// AddRunTimeLibs).
307+
if (D.IsFlangMode() &&
308+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
309+
tools::addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
310+
tools::addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
311+
CmdArgs.push_back("-lm");
312+
}
313+
314+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
315+
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
316+
if (IsStatic || IsStaticPIE)
317+
CmdArgs.push_back("--start-group");
318+
319+
if (NeedsSanitizerDeps)
320+
tools::linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
321+
322+
if (NeedsXRayDeps)
323+
tools::linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
324+
325+
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
326+
Args.hasArg(options::OPT_pthreads);
327+
328+
// Use the static OpenMP runtime with -static-openmp
329+
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
330+
!Args.hasArg(options::OPT_static);
331+
332+
// FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
333+
// require librt. Most modern Linux platforms do, but some may not.
334+
if (tools::addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP,
335+
JA.isHostOffloading(Action::OFK_OpenMP),
336+
/* GompNeedsRT= */ true))
337+
// OpenMP runtimes implies pthreads when using the GNU toolchain.
338+
// FIXME: Does this really make sense for all GNU toolchains?
339+
WantPthread = true;
340+
341+
tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
342+
343+
if (WantPthread)
344+
CmdArgs.push_back("-lpthread");
345+
346+
if (Args.hasArg(options::OPT_fsplit_stack))
347+
CmdArgs.push_back("--wrap=pthread_create");
348+
349+
if (!Args.hasArg(options::OPT_nolibc))
350+
CmdArgs.push_back("-lc");
351+
352+
// Cygwin specific
353+
CmdArgs.push_back("-lcygwin");
354+
CmdArgs.push_back("-ladvapi32");
355+
CmdArgs.push_back("-lshell32");
356+
CmdArgs.push_back("-luser32");
357+
CmdArgs.push_back("-lkernel32");
358+
359+
// Add IAMCU specific libs, if needed.
360+
if (IsIAMCU)
361+
CmdArgs.push_back("-lgloss");
362+
363+
if (IsStatic || IsStaticPIE)
364+
CmdArgs.push_back("--end-group");
365+
else
366+
tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
367+
368+
// Add IAMCU specific libs (outside the group), if needed.
369+
if (IsIAMCU) {
370+
CmdArgs.push_back("--as-needed");
371+
CmdArgs.push_back("-lsoftfp");
372+
CmdArgs.push_back("--no-as-needed");
373+
}
374+
}
375+
376+
if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) {
377+
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
378+
std::string crtend = ToolChain.getCompilerRT(Args, "crtend",
379+
ToolChain::FT_Object);
380+
if (ToolChain.getVFS().exists(crtend)) {
381+
std::string P;
382+
P = crtend;
383+
CmdArgs.push_back(Args.MakeArgString(P));
384+
}
385+
}
386+
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
387+
}
388+
}
389+
390+
Args.addAllArgs(CmdArgs, {options::OPT_T, options::OPT_t});
391+
392+
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
393+
C.addCommand(std::make_unique<Command>(JA, *this,
394+
ResponseFileSupport::AtFileCurCP(),
395+
Exec, CmdArgs, Inputs, Output));
396+
}
397+
398+
auto Cygwin::buildLinker() const -> Tool * { return new cygwin::Linker(*this); }

clang/lib/Driver/ToolChains/Cygwin.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,28 @@ 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+
const GCCInstallationDetector &
32+
getGCCInstallation() const { return GCCInstallation; };
33+
34+
protected:
35+
Tool *buildLinker() const override;
36+
};
37+
38+
namespace cygwin {
39+
class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
40+
public:
41+
Linker(const ToolChain &TC) : Tool("cygwin::Linker", "linker", TC) {}
42+
43+
bool hasIntegratedCPP() const override { return false; }
44+
bool isLinkJob() const override { return true; }
45+
46+
void ConstructJob(Compilation &C, const JobAction &JA,
47+
const InputInfo &Output, const InputInfoList &Inputs,
48+
const llvm::opt::ArgList &TCArgs,
49+
const char *LinkingOutput) const override;
3050
};
51+
} // end namespace cygwin
3152

3253
} // end namespace toolchains
3354
} // 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)