1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Cygwin.h"
10#include "clang/Config/config.h"
11#include "clang/Driver/CommonArgs.h"
12#include "clang/Driver/Compilation.h"
13#include "clang/Driver/Driver.h"
14#include "clang/Options/Options.h"
15#include "llvm/Support/Path.h"
16#include "llvm/Support/VirtualFileSystem.h"
17
18using namespace clang::driver;
19using namespace clang::driver::toolchains;
20using namespace clang;
21using namespace llvm::opt;
22
23using tools::addPathIfExists;
24
25Cygwin::Cygwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
26 : Generic_GCC(D, Triple, Args) {
27 GCCInstallation.init(TargetTriple: Triple, Args);
28 std::string SysRoot = computeSysRoot();
29 ToolChain::path_list &PPaths = getProgramPaths();
30
31 Generic_GCC::PushPPaths(PPaths);
32
33 path_list &Paths = getFilePaths();
34 if (GCCInstallation.isValid())
35 Paths.push_back(Elt: GCCInstallation.getInstallPath().str());
36
37 Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir: "lib", Paths);
38
39 // Similar to the logic for GCC above, if we are currently running Clang
40 // inside of the requested system root, add its parent library path to those
41 // searched.
42 // FIXME: It's not clear whether we should use the driver's installed
43 // directory ('Dir' below) or the ResourceDir.
44 if (StringRef(D.Dir).starts_with(Prefix: SysRoot))
45 addPathIfExists(D, Path: D.Dir + "/../lib", Paths);
46
47 addPathIfExists(D, Path: SysRoot + "/lib", Paths);
48 addPathIfExists(D, Path: SysRoot + "/usr/lib", Paths);
49 addPathIfExists(D, Path: SysRoot + "/usr/lib/w32api", Paths);
50}
51
52llvm::ExceptionHandling Cygwin::GetExceptionModel(const ArgList &Args) const {
53 if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64 ||
54 getArch() == llvm::Triple::arm || getArch() == llvm::Triple::thumb)
55 return llvm::ExceptionHandling::WinEH;
56 return llvm::ExceptionHandling::DwarfCFI;
57}
58
59void Cygwin::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
60 ArgStringList &CC1Args) const {
61 const Driver &D = getDriver();
62 std::string SysRoot = computeSysRoot();
63
64 if (DriverArgs.hasArg(Ids: options::OPT_nostdinc))
65 return;
66
67 if (!DriverArgs.hasArg(Ids: options::OPT_nostdlibinc))
68 addSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/usr/local/include");
69
70 if (!DriverArgs.hasArg(Ids: options::OPT_nobuiltininc)) {
71 SmallString<128> P(D.ResourceDir);
72 llvm::sys::path::append(path&: P, a: "include");
73 addSystemInclude(DriverArgs, CC1Args, Path: P);
74 }
75
76 if (DriverArgs.hasArg(Ids: options::OPT_nostdlibinc))
77 return;
78
79 // Check for configure-time C include directories.
80 StringRef CIncludeDirs(C_INCLUDE_DIRS);
81 if (CIncludeDirs != "") {
82 SmallVector<StringRef, 5> Dirs;
83 CIncludeDirs.split(A&: Dirs, Separator: ":");
84 for (StringRef Dir : Dirs) {
85 StringRef Prefix =
86 llvm::sys::path::is_absolute(path: Dir) ? "" : StringRef(SysRoot);
87 addExternCSystemInclude(DriverArgs, CC1Args, Path: Prefix + Dir);
88 }
89 return;
90 }
91
92 // Lacking those, try to detect the correct set of system includes for the
93 // target triple.
94
95 AddMultilibIncludeArgs(DriverArgs, CC1Args);
96
97 // On systems using multiarch, add /usr/include/$triple before
98 // /usr/include.
99 std::string MultiarchIncludeDir = getTriple().str();
100 if (!MultiarchIncludeDir.empty() &&
101 D.getVFS().exists(Path: SysRoot + "/usr/include/" + MultiarchIncludeDir))
102 addExternCSystemInclude(DriverArgs, CC1Args,
103 Path: SysRoot + "/usr/include/" + MultiarchIncludeDir);
104
105 // Add an include of '/include' directly. This isn't provided by default by
106 // system GCCs, but is often used with cross-compiling GCCs, and harmless to
107 // add even when Clang is acting as-if it were a system compiler.
108 addExternCSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/include");
109
110 addExternCSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/usr/include");
111 addExternCSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/usr/include/w32api");
112}
113
114void Cygwin::addClangTargetOptions(
115 const ArgList &DriverArgs, ArgStringList &CC1Args, BoundArch BA,
116 Action::OffloadKind DeviceOffloadKind) const {
117 CC1Args.push_back(Elt: "-fno-use-init-array");
118}
119
120void cygwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
121 const InputInfo &Output,
122 const InputInfoList &Inputs,
123 const ArgList &Args,
124 const char *LinkingOutput) const {
125 const auto &ToolChain = getToolChain();
126 const Driver &D = ToolChain.getDriver();
127
128 const bool IsStatic = Args.hasArg(Ids: options::OPT_static);
129
130 ArgStringList CmdArgs;
131
132 // Silence warning for "clang -g foo.o -o foo"
133 Args.ClaimAllArgs(Id0: options::OPT_g_Group);
134 // and "clang -emit-llvm foo.o -o foo"
135 Args.ClaimAllArgs(Id0: options::OPT_emit_llvm);
136 // and for "clang -w foo.o -o foo". Other warning options are already
137 // handled somewhere else.
138 Args.ClaimAllArgs(Id0: options::OPT_w);
139
140 if (!D.SysRoot.empty())
141 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "--sysroot=" + D.SysRoot));
142
143 if (Args.hasArg(Ids: options::OPT_s))
144 CmdArgs.push_back(Elt: "-s");
145
146 CmdArgs.push_back(Elt: "-m");
147 switch (ToolChain.getArch()) {
148 case llvm::Triple::x86:
149 CmdArgs.push_back(Elt: "i386pe");
150 break;
151 case llvm::Triple::x86_64:
152 CmdArgs.push_back(Elt: "i386pep");
153 break;
154 case llvm::Triple::arm:
155 case llvm::Triple::thumb:
156 // FIXME: this is incorrect for WinCE
157 CmdArgs.push_back(Elt: "thumb2pe");
158 break;
159 case llvm::Triple::aarch64:
160 if (Args.hasArg(Ids: options::OPT_marm64x))
161 CmdArgs.push_back(Elt: "arm64xpe");
162 else if (ToolChain.getEffectiveTriple().isWindowsArm64EC())
163 CmdArgs.push_back(Elt: "arm64ecpe");
164 else
165 CmdArgs.push_back(Elt: "arm64pe");
166 break;
167 case llvm::Triple::mipsel:
168 CmdArgs.push_back(Elt: "mipspe");
169 break;
170 default:
171 D.Diag(DiagID: diag::err_target_unknown_triple)
172 << ToolChain.getEffectiveTriple().str();
173 }
174
175 Arg *SubsysArg =
176 Args.getLastArg(Ids: options::OPT_mwindows, Ids: options::OPT_mconsole);
177 if (SubsysArg && SubsysArg->getOption().matches(ID: options::OPT_mwindows)) {
178 CmdArgs.push_back(Elt: "--subsystem");
179 CmdArgs.push_back(Elt: "windows");
180 } else if (SubsysArg &&
181 SubsysArg->getOption().matches(ID: options::OPT_mconsole)) {
182 CmdArgs.push_back(Elt: "--subsystem");
183 CmdArgs.push_back(Elt: "console");
184 }
185
186 if (ToolChain.getTriple().isArch32Bit()) {
187 CmdArgs.push_back(Elt: "--wrap=_Znwj");
188 CmdArgs.push_back(Elt: "--wrap=_Znaj");
189 CmdArgs.push_back(Elt: "--wrap=_ZdlPv");
190 CmdArgs.push_back(Elt: "--wrap=_ZdaPv");
191 CmdArgs.push_back(Elt: "--wrap=_ZnwjRKSt9nothrow_t");
192 CmdArgs.push_back(Elt: "--wrap=_ZnajRKSt9nothrow_t");
193 CmdArgs.push_back(Elt: "--wrap=_ZdlPvRKSt9nothrow_t");
194 CmdArgs.push_back(Elt: "--wrap=_ZdaPvRKSt9nothrow_t");
195 } else {
196 CmdArgs.push_back(Elt: "--wrap=_Znwm");
197 CmdArgs.push_back(Elt: "--wrap=_Znam");
198 CmdArgs.push_back(Elt: "--wrap=_ZdlPv");
199 CmdArgs.push_back(Elt: "--wrap=_ZdaPv");
200 CmdArgs.push_back(Elt: "--wrap=_ZnwmRKSt9nothrow_t");
201 CmdArgs.push_back(Elt: "--wrap=_ZnamRKSt9nothrow_t");
202 CmdArgs.push_back(Elt: "--wrap=_ZdlPvRKSt9nothrow_t");
203 CmdArgs.push_back(Elt: "--wrap=_ZdaPvRKSt9nothrow_t");
204 }
205
206 if (Args.hasArg(Ids: options::OPT_mdll))
207 CmdArgs.push_back(Elt: "--dll");
208 else if (Args.hasArg(Ids: options::OPT_shared))
209 CmdArgs.push_back(Elt: "--shared");
210 if (Args.hasArg(Ids: options::OPT_static))
211 CmdArgs.push_back(Elt: "-Bstatic");
212 else
213 CmdArgs.push_back(Elt: "-Bdynamic");
214
215 CmdArgs.push_back(Elt: "--dll-search-prefix=cyg");
216 if (Args.hasArg(Ids: options::OPT_rdynamic))
217 CmdArgs.push_back(Elt: "--export-all-symbols");
218
219 // Cygwin-specific linker options for executables (matching GCC behavior).
220 // These flags must be set on the main executable header rather than DLLs.
221 if (!Args.hasArg(Ids: options::OPT_shared) && !Args.hasArg(Ids: options::OPT_mdll)) {
222 // 32-bit Cygwin relies heavily on a predictable memory layout to emulate
223 // fork(). Enabling '--large-address-aware' expands the virtual address
224 // space, reducing 'unable to remap' fatal errors during fork().
225 if (ToolChain.getTriple().isArch32Bit())
226 CmdArgs.push_back(Elt: "--large-address-aware");
227 // Mark as Terminal Server Aware to prevent legacy Windows loader from
228 // applying file/registry virtualization, which breaks POSIX path
229 // expectations.
230 CmdArgs.push_back(Elt: "--tsaware");
231 }
232
233 CmdArgs.push_back(Elt: "-o");
234 // GCC implicitly adds an .exe extension if it is given an output file name
235 // that lacks an extension.
236 // GCC used to do this only when the compiler itself runs on windows, but
237 // since GCC 8 it does the same when cross compiling as well.
238 if (const char *OutputFile = Output.getFilename();
239 !llvm::sys::path::has_extension(path: OutputFile))
240 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Twine(OutputFile) + ".exe"));
241 else
242 CmdArgs.push_back(Elt: OutputFile);
243
244 if (!Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nostartfiles,
245 Ids: options::OPT_r)) {
246 const bool IsShared = Args.hasArg(Ids: options::OPT_shared);
247 if (Args.hasArg(Ids: options::OPT_mdll) || IsShared) {
248 CmdArgs.push_back(Elt: "-e");
249 CmdArgs.push_back(Elt: ToolChain.getArch() == llvm::Triple::x86
250 ? "__cygwin_dll_entry@12"
251 : "_cygwin_dll_entry");
252 CmdArgs.push_back(Elt: "--enable-auto-image-base");
253 }
254
255 if (!Args.hasArg(Ids: options::OPT_mdll) && !IsShared)
256 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crt0.o")));
257 if (IsShared)
258 CmdArgs.push_back(
259 Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crtbeginS.o")));
260 else
261 CmdArgs.push_back(
262 Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crtbegin.o")));
263
264 // Add crtfastmath.o if available and fast math is enabled.
265 ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
266 }
267
268 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_L, options::OPT_u});
269
270 ToolChain.AddFilePathLibArgs(Args, CmdArgs);
271
272 if (auto LTO = ToolChain.getLTOMode(Args); LTO != LTOK_None)
273 tools::addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,
274 IsThinLTO: LTO == LTOK_Thin);
275
276 if (Args.hasArg(Ids: options::OPT_Z_Xlinker__no_demangle))
277 CmdArgs.push_back(Elt: "--no-demangle");
278
279 // Default. Can be overridden by the user by explicitly
280 // passing an option after this one.
281 if (ToolChain.getTriple().isArch64Bit())
282 CmdArgs.push_back(Elt: "--disable-high-entropy-va");
283 CmdArgs.push_back(Elt: "--disable-nxcompat");
284
285 bool NeedsSanitizerDeps =
286 tools::addSanitizerRuntimes(TC: ToolChain, Args, CmdArgs, C);
287 bool NeedsXRayDeps = tools::addXRayRuntime(TC: ToolChain, Args, CmdArgs);
288 tools::addLinkerCompressDebugSectionsOption(TC: ToolChain, Args, CmdArgs);
289 tools::AddLinkerInputs(TC: ToolChain, Inputs, Args, CmdArgs, JA);
290
291 // The profile runtime also needs access to system libraries.
292 getToolChain().addProfileRTLibs(Args, CmdArgs);
293
294 if (D.CCCIsCXX() &&
295 !Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs,
296 Ids: options::OPT_r)) {
297 if (ToolChain.ShouldLinkCXXStdlib(Args)) {
298 bool OnlyLibstdcxxStatic = Args.hasArg(Ids: options::OPT_static_libstdcxx) &&
299 !Args.hasArg(Ids: options::OPT_static);
300 if (OnlyLibstdcxxStatic)
301 CmdArgs.push_back(Elt: "-Bstatic");
302 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
303 if (OnlyLibstdcxxStatic)
304 CmdArgs.push_back(Elt: "-Bdynamic");
305 }
306 CmdArgs.push_back(Elt: "-lm");
307 }
308
309 // Silence warnings when linking C code with a C++ '-stdlib' argument.
310 Args.ClaimAllArgs(Id0: options::OPT_stdlib_EQ);
311
312 // Additional linker set-up and flags for Fortran. This is required in order
313 // to generate executables. As Fortran runtime depends on the C runtime,
314 // these dependencies need to be listed before the C runtime below (i.e.
315 // AddRunTimeLibs).
316 if (D.IsFlangMode() &&
317 !Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs)) {
318 ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);
319 ToolChain.addFortranRuntimeLibs(Args, CmdArgs);
320 CmdArgs.push_back(Elt: "-lm");
321 }
322
323 if (!Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_r)) {
324 if (!Args.hasArg(Ids: options::OPT_nodefaultlibs)) {
325 if (IsStatic)
326 CmdArgs.push_back(Elt: "--start-group");
327
328 if (NeedsSanitizerDeps)
329 tools::linkSanitizerRuntimeDeps(TC: ToolChain, Args, CmdArgs);
330
331 if (NeedsXRayDeps)
332 tools::linkXRayRuntimeDeps(TC: ToolChain, Args, CmdArgs);
333
334 bool WantPthread = Args.hasArg(Ids: options::OPT_pthread) ||
335 Args.hasArg(Ids: options::OPT_pthreads);
336
337 // Use the static OpenMP runtime with -static-openmp
338 bool StaticOpenMP = Args.hasArg(Ids: options::OPT_static_openmp) &&
339 !Args.hasArg(Ids: options::OPT_static);
340
341 // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
342 // require librt. Most modern Linux platforms do, but some may not.
343 if (tools::addOpenMPRuntime(C, CmdArgs, TC: ToolChain, Args, ForceStaticHostRuntime: StaticOpenMP,
344 IsOffloadingHost: JA.isHostOffloading(OKind: Action::OFK_OpenMP),
345 /* GompNeedsRT= */ true))
346 // OpenMP runtimes implies pthreads when using the GNU toolchain.
347 // FIXME: Does this really make sense for all GNU toolchains?
348 WantPthread = true;
349
350 tools::AddRunTimeLibs(TC: ToolChain, D, CmdArgs, Args);
351
352 if (WantPthread)
353 CmdArgs.push_back(Elt: "-lpthread");
354
355 if (Args.hasArg(Ids: options::OPT_fsplit_stack))
356 CmdArgs.push_back(Elt: "--wrap=pthread_create");
357
358 if (!Args.hasArg(Ids: options::OPT_nolibc))
359 CmdArgs.push_back(Elt: "-lc");
360
361 // Cygwin specific
362 CmdArgs.push_back(Elt: "-lcygwin");
363 if (Args.hasArg(Ids: options::OPT_mwindows)) {
364 CmdArgs.push_back(Elt: "-lgdi32");
365 CmdArgs.push_back(Elt: "-lcomdlg32");
366 }
367 CmdArgs.push_back(Elt: "-ladvapi32");
368 CmdArgs.push_back(Elt: "-lshell32");
369 CmdArgs.push_back(Elt: "-luser32");
370 CmdArgs.push_back(Elt: "-lkernel32");
371
372 if (IsStatic)
373 CmdArgs.push_back(Elt: "--end-group");
374 else
375 tools::AddRunTimeLibs(TC: ToolChain, D, CmdArgs, Args);
376 }
377
378 if (!Args.hasArg(Ids: options::OPT_nostartfiles)) {
379 if (!Args.hasArg(Ids: options::OPT_mdll, Ids: options::OPT_shared)) {
380 if (auto O = ToolChain.GetFilePathIfExists(Name: "default-manifest.o"))
381 CmdArgs.push_back(Elt: Args.MakeArgString(Str: std::move(*O)));
382 }
383 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: "crtend.o")));
384 }
385 }
386
387 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_T, options::OPT_t});
388
389 const char *Exec = Args.MakeArgString(Str: ToolChain.GetLinkerPath());
390 C.addCommand(Cmd: std::make_unique<Command>(args: JA, args: *this,
391 args: ResponseFileSupport::AtFileCurCP(),
392 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
393}
394
395auto Cygwin::buildLinker() const -> Tool * { return new cygwin::Linker(*this); }
396