Skip to content

Commit efab30c

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 <takashi.yano@nifty.ne.jp>
1 parent 7bbb65c commit efab30c

File tree

9 files changed

+311
-8
lines changed

9 files changed

+311
-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: 282 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,282 @@ 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+
CmdArgs.push_back("--wrap=_Znwm");
185+
CmdArgs.push_back("--wrap=_Znam");
186+
CmdArgs.push_back("--wrap=_ZdlPv");
187+
CmdArgs.push_back("--wrap=_ZdaPv");
188+
CmdArgs.push_back("--wrap=_ZnwmRKSt9nothrow_t");
189+
CmdArgs.push_back("--wrap=_ZnamRKSt9nothrow_t");
190+
CmdArgs.push_back("--wrap=_ZdlPvRKSt9nothrow_t");
191+
CmdArgs.push_back("--wrap=_ZdaPvRKSt9nothrow_t");
192+
193+
const bool IsShared = Args.hasArg(options::OPT_shared);
194+
if (IsShared)
195+
CmdArgs.push_back("-shared");
196+
bool IsPIE = false;
197+
if (IsStaticPIE) {
198+
CmdArgs.push_back("-static");
199+
CmdArgs.push_back("-pie");
200+
CmdArgs.push_back("--no-dynamic-linker");
201+
CmdArgs.push_back("-z");
202+
CmdArgs.push_back("text");
203+
} else if (IsStatic) {
204+
CmdArgs.push_back("-static");
205+
} else if (!Args.hasArg(options::OPT_r)) {
206+
if (Args.hasArg(options::OPT_rdynamic))
207+
CmdArgs.push_back("-export-dynamic");
208+
if (!IsShared) {
209+
IsPIE = Args.hasFlag(options::OPT_pie, options::OPT_no_pie,
210+
ToolChain.isPIEDefault(Args));
211+
if (IsPIE)
212+
CmdArgs.push_back("-pie");
213+
}
214+
}
215+
216+
CmdArgs.push_back("-o");
217+
CmdArgs.push_back(Output.getFilename());
218+
219+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
220+
options::OPT_r)) {
221+
if (IsVE) {
222+
CmdArgs.push_back("-z");
223+
CmdArgs.push_back("max-page-size=0x4000000");
224+
}
225+
226+
if (IsShared) {
227+
CmdArgs.push_back("-e");
228+
CmdArgs.push_back(ToolChain.getTriple().isArch32Bit()
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+
tools::addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs);
274+
275+
// The profile runtime also needs access to system libraries.
276+
getToolChain().addProfileRTLibs(Args, CmdArgs);
277+
278+
if (D.CCCIsCXX() &&
279+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
280+
options::OPT_r)) {
281+
if (ToolChain.ShouldLinkCXXStdlib(Args)) {
282+
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
283+
!Args.hasArg(options::OPT_static);
284+
if (OnlyLibstdcxxStatic)
285+
CmdArgs.push_back("-Bstatic");
286+
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
287+
if (OnlyLibstdcxxStatic)
288+
CmdArgs.push_back("-Bdynamic");
289+
}
290+
CmdArgs.push_back("-lm");
291+
}
292+
293+
// Silence warnings when linking C code with a C++ '-stdlib' argument.
294+
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
295+
296+
// Additional linker set-up and flags for Fortran. This is required in order
297+
// to generate executables. As Fortran runtime depends on the C runtime,
298+
// these dependencies need to be listed before the C runtime below (i.e.
299+
// AddRunTimeLibs).
300+
if (D.IsFlangMode() &&
301+
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
302+
ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);
303+
ToolChain.addFortranRuntimeLibs(Args, CmdArgs);
304+
CmdArgs.push_back("-lm");
305+
}
306+
307+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
308+
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
309+
if (IsStatic || IsStaticPIE)
310+
CmdArgs.push_back("--start-group");
311+
312+
if (NeedsSanitizerDeps)
313+
tools::linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs);
314+
315+
if (NeedsXRayDeps)
316+
tools::linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
317+
318+
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
319+
Args.hasArg(options::OPT_pthreads);
320+
321+
// Use the static OpenMP runtime with -static-openmp
322+
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
323+
!Args.hasArg(options::OPT_static);
324+
325+
// FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
326+
// require librt. Most modern Linux platforms do, but some may not.
327+
if (tools::addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP,
328+
JA.isHostOffloading(Action::OFK_OpenMP),
329+
/* GompNeedsRT= */ true))
330+
// OpenMP runtimes implies pthreads when using the GNU toolchain.
331+
// FIXME: Does this really make sense for all GNU toolchains?
332+
WantPthread = true;
333+
334+
tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
335+
336+
if (WantPthread)
337+
CmdArgs.push_back("-lpthread");
338+
339+
if (Args.hasArg(options::OPT_fsplit_stack))
340+
CmdArgs.push_back("--wrap=pthread_create");
341+
342+
if (!Args.hasArg(options::OPT_nolibc))
343+
CmdArgs.push_back("-lc");
344+
345+
// Cygwin specific
346+
CmdArgs.push_back("-lcygwin");
347+
CmdArgs.push_back("-ladvapi32");
348+
CmdArgs.push_back("-lshell32");
349+
CmdArgs.push_back("-luser32");
350+
CmdArgs.push_back("-lkernel32");
351+
352+
// Add IAMCU specific libs, if needed.
353+
if (IsIAMCU)
354+
CmdArgs.push_back("-lgloss");
355+
356+
if (IsStatic || IsStaticPIE)
357+
CmdArgs.push_back("--end-group");
358+
else
359+
tools::AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
360+
361+
// Add IAMCU specific libs (outside the group), if needed.
362+
if (IsIAMCU) {
363+
CmdArgs.push_back("--as-needed");
364+
CmdArgs.push_back("-lsoftfp");
365+
CmdArgs.push_back("--no-as-needed");
366+
}
367+
}
368+
369+
if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) {
370+
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
371+
std::string crtend =
372+
ToolChain.getCompilerRT(Args, "crtend", ToolChain::FT_Object);
373+
if (ToolChain.getVFS().exists(crtend)) {
374+
std::string P;
375+
P = crtend;
376+
CmdArgs.push_back(Args.MakeArgString(P));
377+
}
378+
}
379+
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
380+
}
381+
}
382+
383+
Args.addAllArgs(CmdArgs, {options::OPT_T, options::OPT_t});
384+
385+
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
386+
C.addCommand(std::make_unique<Command>(JA, *this,
387+
ResponseFileSupport::AtFileCurCP(),
388+
Exec, CmdArgs, Inputs, Output));
389+
}
390+
391+
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.

clang/test/Driver/cygwin.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@
1515
// CHECK-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include/w32api"
1616
// CHECK-SAME: "-femulated-tls"
1717
// CHECK-SAME: "-exception-model=dwarf"
18-
// CHECK: "{{.*}}gcc{{(\.exe)?}}"
19-
// CHECK-SAME: "-m32"
18+
// CHECK: "{{.*}}ld{{(\.exe)?}}"
19+
// CHECK-SAME: "-m" "i386pe"
2020

2121
// RUN: %clang -### %s --target=i686-pc-cygwin --sysroot=%S/Inputs/basic_cygwin_tree \
2222
// RUN: --stdlib=platform -static 2>&1 | FileCheck --check-prefix=CHECK-STATIC %s
2323
// CHECK-STATIC: "-cc1" "-triple" "i686-pc-windows-cygnus"
2424
// CHECK-STATIC-SAME: "-static-define"
25-
// CHECK-STATIC: "{{.*}}gcc{{(\.exe)?}}"
25+
// CHECK-STATIC: "{{.*}}ld{{(\.exe)?}}"
2626
// CHECK-STATIC-SAME: "-static"
2727

2828
// RUN: %clang -### %s --target=i686-pc-cygwin --sysroot=%S/Inputs/basic_cygwin_tree \
2929
// RUN: -shared 2>&1 | FileCheck --check-prefix=CHECK-SHARED %s
30-
// CHECK-SHARED: "{{.*}}gcc{{(\.exe)?}}"
30+
// CHECK-SHARED: "{{.*}}ld{{(\.exe)?}}"
3131
// CHECK-SHARED-SAME: "-shared"
3232

3333
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
@@ -54,19 +54,19 @@
5454
// CHECK-64-SAME: {{^}} "-internal-externc-isystem" "[[SYSROOT]]/usr/include/w32api"
5555
// CHECK-64-SAME: "-femulated-tls"
5656
// CHECK-64-SAME: "-exception-model=seh"
57-
// CHECK-64: "{{.*}}gcc{{(\.exe)?}}"
58-
// CHECK-64-SAME: "-m64"
57+
// CHECK-64: "{{.*}}ld{{(\.exe)?}}"
58+
// CHECK-64-SAME: "-m" "i386pep"
5959

6060
// RUN: %clang -### %s --target=x86_64-pc-cygwin --sysroot=%S/Inputs/basic_cygwin_tree \
6161
// RUN: --stdlib=platform -static 2>&1 | FileCheck --check-prefix=CHECK-64-STATIC %s
6262
// CHECK-64-STATIC: "-cc1" "-triple" "x86_64-pc-windows-cygnus"
6363
// CHECK-64-STATIC-SAME: "-static-define"
64-
// CHECK-64-STATIC: "{{.*}}gcc{{(\.exe)?}}"
64+
// CHECK-64-STATIC: "{{.*}}ld{{(\.exe)?}}"
6565
// CHECK-64-STATIC-SAME: "-static"
6666

6767
// RUN: %clang -### %s --target=x86_64-pc-cygwin --sysroot=%S/Inputs/basic_cygwin_tree \
6868
// RUN: -shared 2>&1 | FileCheck --check-prefix=CHECK-64-SHARED %s
69-
// CHECK-64-SHARED: "{{.*}}gcc{{(\.exe)?}}"
69+
// CHECK-64-SHARED: "{{.*}}ld{{(\.exe)?}}"
7070
// CHECK-64-SHARED-SAME: "-shared"
7171

7272
// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \

0 commit comments

Comments
 (0)