1 //===--- MinGW.cpp - MinGWToolChain Implementation ------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "MinGW.h" 11 #include "InputInfo.h" 12 #include "CommonArgs.h" 13 #include "clang/Driver/Compilation.h" 14 #include "clang/Driver/Driver.h" 15 #include "clang/Driver/DriverDiagnostic.h" 16 #include "clang/Driver/Options.h" 17 #include "llvm/Option/ArgList.h" 18 #include "llvm/Support/FileSystem.h" 19 #include "llvm/Support/Path.h" 20 #include <system_error> 21 22 using namespace clang::diag; 23 using namespace clang::driver; 24 using namespace clang; 25 using namespace llvm::opt; 26 27 /// MinGW Tools 28 void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 29 const InputInfo &Output, 30 const InputInfoList &Inputs, 31 const ArgList &Args, 32 const char *LinkingOutput) const { 33 claimNoWarnArgs(Args); 34 ArgStringList CmdArgs; 35 36 if (getToolChain().getArch() == llvm::Triple::x86) { 37 CmdArgs.push_back("--32"); 38 } else if (getToolChain().getArch() == llvm::Triple::x86_64) { 39 CmdArgs.push_back("--64"); 40 } 41 42 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 43 44 CmdArgs.push_back("-o"); 45 CmdArgs.push_back(Output.getFilename()); 46 47 for (const auto &II : Inputs) 48 CmdArgs.push_back(II.getFilename()); 49 50 const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); 51 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 52 53 if (Args.hasArg(options::OPT_gsplit_dwarf)) 54 SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, 55 SplitDebugName(Args, Inputs[0])); 56 } 57 58 void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, 59 ArgStringList &CmdArgs) const { 60 if (Args.hasArg(options::OPT_mthreads)) 61 CmdArgs.push_back("-lmingwthrd"); 62 CmdArgs.push_back("-lmingw32"); 63 64 // Make use of compiler-rt if --rtlib option is used 65 ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args); 66 if (RLT == ToolChain::RLT_Libgcc) { 67 bool Static = Args.hasArg(options::OPT_static_libgcc) || 68 Args.hasArg(options::OPT_static); 69 bool Shared = Args.hasArg(options::OPT_shared); 70 bool CXX = getToolChain().getDriver().CCCIsCXX(); 71 72 if (Static || (!CXX && !Shared)) { 73 CmdArgs.push_back("-lgcc"); 74 CmdArgs.push_back("-lgcc_eh"); 75 } else { 76 CmdArgs.push_back("-lgcc_s"); 77 CmdArgs.push_back("-lgcc"); 78 } 79 } else { 80 AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args); 81 } 82 83 CmdArgs.push_back("-lmoldname"); 84 CmdArgs.push_back("-lmingwex"); 85 for (auto Lib : Args.getAllArgValues(options::OPT_l)) 86 if (StringRef(Lib).startswith("msvcr") || StringRef(Lib).startswith("ucrt")) 87 return; 88 CmdArgs.push_back("-lmsvcrt"); 89 } 90 91 void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, 92 const InputInfo &Output, 93 const InputInfoList &Inputs, 94 const ArgList &Args, 95 const char *LinkingOutput) const { 96 const ToolChain &TC = getToolChain(); 97 const Driver &D = TC.getDriver(); 98 // const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); 99 100 ArgStringList CmdArgs; 101 102 // Silence warning for "clang -g foo.o -o foo" 103 Args.ClaimAllArgs(options::OPT_g_Group); 104 // and "clang -emit-llvm foo.o -o foo" 105 Args.ClaimAllArgs(options::OPT_emit_llvm); 106 // and for "clang -w foo.o -o foo". Other warning options are already 107 // handled somewhere else. 108 Args.ClaimAllArgs(options::OPT_w); 109 110 if (!D.SysRoot.empty()) 111 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 112 113 if (Args.hasArg(options::OPT_s)) 114 CmdArgs.push_back("-s"); 115 116 CmdArgs.push_back("-m"); 117 switch (TC.getArch()) { 118 case llvm::Triple::x86: 119 CmdArgs.push_back("i386pe"); 120 break; 121 case llvm::Triple::x86_64: 122 CmdArgs.push_back("i386pep"); 123 break; 124 case llvm::Triple::arm: 125 case llvm::Triple::thumb: 126 // FIXME: this is incorrect for WinCE 127 CmdArgs.push_back("thumb2pe"); 128 break; 129 case llvm::Triple::aarch64: 130 CmdArgs.push_back("arm64pe"); 131 break; 132 default: 133 llvm_unreachable("Unsupported target architecture."); 134 } 135 136 if (Args.hasArg(options::OPT_mwindows)) { 137 CmdArgs.push_back("--subsystem"); 138 CmdArgs.push_back("windows"); 139 } else if (Args.hasArg(options::OPT_mconsole)) { 140 CmdArgs.push_back("--subsystem"); 141 CmdArgs.push_back("console"); 142 } 143 144 if (Args.hasArg(options::OPT_mdll)) 145 CmdArgs.push_back("--dll"); 146 else if (Args.hasArg(options::OPT_shared)) 147 CmdArgs.push_back("--shared"); 148 if (Args.hasArg(options::OPT_static)) 149 CmdArgs.push_back("-Bstatic"); 150 else 151 CmdArgs.push_back("-Bdynamic"); 152 if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) { 153 CmdArgs.push_back("-e"); 154 if (TC.getArch() == llvm::Triple::x86) 155 CmdArgs.push_back("_DllMainCRTStartup@12"); 156 else 157 CmdArgs.push_back("DllMainCRTStartup"); 158 CmdArgs.push_back("--enable-auto-image-base"); 159 } 160 161 CmdArgs.push_back("-o"); 162 CmdArgs.push_back(Output.getFilename()); 163 164 Args.AddAllArgs(CmdArgs, options::OPT_e); 165 // FIXME: add -N, -n flags 166 Args.AddLastArg(CmdArgs, options::OPT_r); 167 Args.AddLastArg(CmdArgs, options::OPT_s); 168 Args.AddLastArg(CmdArgs, options::OPT_t); 169 Args.AddAllArgs(CmdArgs, options::OPT_u_Group); 170 Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); 171 172 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { 173 if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { 174 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o"))); 175 } else { 176 if (Args.hasArg(options::OPT_municode)) 177 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o"))); 178 else 179 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o"))); 180 } 181 if (Args.hasArg(options::OPT_pg)) 182 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o"))); 183 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); 184 } 185 186 Args.AddAllArgs(CmdArgs, options::OPT_L); 187 TC.AddFilePathLibArgs(Args, CmdArgs); 188 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); 189 190 // TODO: Add ASan stuff here 191 192 // TODO: Add profile stuff here 193 194 if (TC.ShouldLinkCXXStdlib(Args)) { 195 bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && 196 !Args.hasArg(options::OPT_static); 197 if (OnlyLibstdcxxStatic) 198 CmdArgs.push_back("-Bstatic"); 199 TC.AddCXXStdlibLibArgs(Args, CmdArgs); 200 if (OnlyLibstdcxxStatic) 201 CmdArgs.push_back("-Bdynamic"); 202 } 203 204 bool HasWindowsApp = false; 205 for (auto Lib : Args.getAllArgValues(options::OPT_l)) { 206 if (Lib == "windowsapp") { 207 HasWindowsApp = true; 208 break; 209 } 210 } 211 212 if (!Args.hasArg(options::OPT_nostdlib)) { 213 if (!Args.hasArg(options::OPT_nodefaultlibs)) { 214 if (Args.hasArg(options::OPT_static)) 215 CmdArgs.push_back("--start-group"); 216 217 if (Args.hasArg(options::OPT_fstack_protector) || 218 Args.hasArg(options::OPT_fstack_protector_strong) || 219 Args.hasArg(options::OPT_fstack_protector_all)) { 220 CmdArgs.push_back("-lssp_nonshared"); 221 CmdArgs.push_back("-lssp"); 222 } 223 if (Args.hasArg(options::OPT_fopenmp)) 224 CmdArgs.push_back("-lgomp"); 225 226 AddLibGCC(Args, CmdArgs); 227 228 if (Args.hasArg(options::OPT_pg)) 229 CmdArgs.push_back("-lgmon"); 230 231 if (Args.hasArg(options::OPT_pthread)) 232 CmdArgs.push_back("-lpthread"); 233 234 if (!HasWindowsApp) { 235 // Add system libraries. If linking to libwindowsapp.a, that import 236 // library replaces all these and we shouldn't accidentally try to 237 // link to the normal desktop mode dlls. 238 if (Args.hasArg(options::OPT_mwindows)) { 239 CmdArgs.push_back("-lgdi32"); 240 CmdArgs.push_back("-lcomdlg32"); 241 } 242 CmdArgs.push_back("-ladvapi32"); 243 CmdArgs.push_back("-lshell32"); 244 CmdArgs.push_back("-luser32"); 245 CmdArgs.push_back("-lkernel32"); 246 } 247 248 if (Args.hasArg(options::OPT_static)) 249 CmdArgs.push_back("--end-group"); 250 else 251 AddLibGCC(Args, CmdArgs); 252 } 253 254 if (!Args.hasArg(options::OPT_nostartfiles)) { 255 // Add crtfastmath.o if available and fast math is enabled. 256 TC.AddFastMathRuntimeIfAvailable(Args, CmdArgs); 257 258 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); 259 } 260 } 261 const char *Exec = Args.MakeArgString(TC.GetLinkerPath()); 262 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 263 } 264 265 // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. 266 static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, 267 std::string &Ver) { 268 auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); 269 std::error_code EC; 270 for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; 271 LI = LI.increment(EC)) { 272 StringRef VersionText = llvm::sys::path::filename(LI->path()); 273 auto CandidateVersion = 274 toolchains::Generic_GCC::GCCVersion::Parse(VersionText); 275 if (CandidateVersion.Major == -1) 276 continue; 277 if (CandidateVersion <= Version) 278 continue; 279 Ver = VersionText; 280 GccLibDir = LI->path(); 281 } 282 return Ver.size(); 283 } 284 285 void toolchains::MinGW::findGccLibDir() { 286 llvm::SmallVector<llvm::SmallString<32>, 2> Archs; 287 Archs.emplace_back(getTriple().getArchName()); 288 Archs[0] += "-w64-mingw32"; 289 Archs.emplace_back("mingw32"); 290 if (Arch.empty()) 291 Arch = Archs[0].str(); 292 // lib: Arch Linux, Ubuntu, Windows 293 // lib64: openSUSE Linux 294 for (StringRef CandidateLib : {"lib", "lib64"}) { 295 for (StringRef CandidateArch : Archs) { 296 llvm::SmallString<1024> LibDir(Base); 297 llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch); 298 if (findGccVersion(LibDir, GccLibDir, Ver)) { 299 Arch = CandidateArch; 300 return; 301 } 302 } 303 } 304 } 305 306 llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { 307 llvm::SmallVector<llvm::SmallString<32>, 2> Gccs; 308 Gccs.emplace_back(getTriple().getArchName()); 309 Gccs[0] += "-w64-mingw32-gcc"; 310 Gccs.emplace_back("mingw32-gcc"); 311 // Please do not add "gcc" here 312 for (StringRef CandidateGcc : Gccs) 313 if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc)) 314 return GPPName; 315 return make_error_code(std::errc::no_such_file_or_directory); 316 } 317 318 llvm::ErrorOr<std::string> toolchains::MinGW::findClangRelativeSysroot() { 319 llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs; 320 Subdirs.emplace_back(getTriple().str()); 321 Subdirs.emplace_back(getTriple().getArchName()); 322 Subdirs[1] += "-w64-mingw32"; 323 StringRef ClangRoot = 324 llvm::sys::path::parent_path(getDriver().getInstalledDir()); 325 StringRef Sep = llvm::sys::path::get_separator(); 326 for (StringRef CandidateSubdir : Subdirs) { 327 if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) { 328 Arch = CandidateSubdir; 329 return (ClangRoot + Sep + CandidateSubdir).str(); 330 } 331 } 332 return make_error_code(std::errc::no_such_file_or_directory); 333 } 334 335 toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, 336 const ArgList &Args) 337 : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { 338 getProgramPaths().push_back(getDriver().getInstalledDir()); 339 340 if (getDriver().SysRoot.size()) 341 Base = getDriver().SysRoot; 342 // Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the 343 // base as it could still be a base for a gcc setup with libgcc. 344 else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot()) 345 Base = llvm::sys::path::parent_path(TargetSubdir.get()); 346 else if (llvm::ErrorOr<std::string> GPPName = findGcc()) 347 Base = llvm::sys::path::parent_path( 348 llvm::sys::path::parent_path(GPPName.get())); 349 else 350 Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); 351 352 Base += llvm::sys::path::get_separator(); 353 findGccLibDir(); 354 // GccLibDir must precede Base/lib so that the 355 // correct crtbegin.o ,cetend.o would be found. 356 getFilePaths().push_back(GccLibDir); 357 getFilePaths().push_back( 358 (Base + Arch + llvm::sys::path::get_separator() + "lib").str()); 359 getFilePaths().push_back(Base + "lib"); 360 // openSUSE 361 getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib"); 362 } 363 364 bool toolchains::MinGW::IsIntegratedAssemblerDefault() const { return true; } 365 366 Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const { 367 switch (AC) { 368 case Action::PreprocessJobClass: 369 if (!Preprocessor) 370 Preprocessor.reset(new tools::gcc::Preprocessor(*this)); 371 return Preprocessor.get(); 372 case Action::CompileJobClass: 373 if (!Compiler) 374 Compiler.reset(new tools::gcc::Compiler(*this)); 375 return Compiler.get(); 376 default: 377 return ToolChain::getTool(AC); 378 } 379 } 380 381 Tool *toolchains::MinGW::buildAssembler() const { 382 return new tools::MinGW::Assembler(*this); 383 } 384 385 Tool *toolchains::MinGW::buildLinker() const { 386 return new tools::MinGW::Linker(*this); 387 } 388 389 bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { 390 return getArch() == llvm::Triple::x86_64; 391 } 392 393 bool toolchains::MinGW::isPICDefault() const { 394 return getArch() == llvm::Triple::x86_64; 395 } 396 397 bool toolchains::MinGW::isPIEDefault() const { return false; } 398 399 bool toolchains::MinGW::isPICDefaultForced() const { 400 return getArch() == llvm::Triple::x86_64; 401 } 402 403 llvm::ExceptionHandling 404 toolchains::MinGW::GetExceptionModel(const ArgList &Args) const { 405 if (getArch() == llvm::Triple::x86_64) 406 return llvm::ExceptionHandling::WinEH; 407 return llvm::ExceptionHandling::DwarfCFI; 408 } 409 410 void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, 411 ArgStringList &CC1Args) const { 412 CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); 413 } 414 415 void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { 416 CudaInstallation.print(OS); 417 } 418 419 // Include directories for various hosts: 420 421 // Windows, mingw.org 422 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++ 423 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32 424 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward 425 // c:\mingw\include 426 // c:\mingw\mingw32\include 427 428 // Windows, mingw-w64 mingw-builds 429 // c:\mingw32\i686-w64-mingw32\include 430 // c:\mingw32\i686-w64-mingw32\include\c++ 431 // c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32 432 // c:\mingw32\i686-w64-mingw32\include\c++\backward 433 434 // Windows, mingw-w64 msys2 435 // c:\msys64\mingw32\include 436 // c:\msys64\mingw32\i686-w64-mingw32\include 437 // c:\msys64\mingw32\include\c++\4.9.2 438 // c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32 439 // c:\msys64\mingw32\include\c++\4.9.2\backward 440 441 // openSUSE 442 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++ 443 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32 444 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward 445 // /usr/x86_64-w64-mingw32/sys-root/mingw/include 446 447 // Arch Linux 448 // /usr/i686-w64-mingw32/include/c++/5.1.0 449 // /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32 450 // /usr/i686-w64-mingw32/include/c++/5.1.0/backward 451 // /usr/i686-w64-mingw32/include 452 453 // Ubuntu 454 // /usr/include/c++/4.8 455 // /usr/include/c++/4.8/x86_64-w64-mingw32 456 // /usr/include/c++/4.8/backward 457 // /usr/x86_64-w64-mingw32/include 458 459 void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 460 ArgStringList &CC1Args) const { 461 if (DriverArgs.hasArg(options::OPT_nostdinc)) 462 return; 463 464 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 465 SmallString<1024> P(getDriver().ResourceDir); 466 llvm::sys::path::append(P, "include"); 467 addSystemInclude(DriverArgs, CC1Args, P.str()); 468 } 469 470 if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 471 return; 472 473 if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { 474 // openSUSE 475 addSystemInclude(DriverArgs, CC1Args, 476 Base + Arch + "/sys-root/mingw/include"); 477 } 478 479 addSystemInclude(DriverArgs, CC1Args, 480 Base + Arch + llvm::sys::path::get_separator() + "include"); 481 addSystemInclude(DriverArgs, CC1Args, Base + "include"); 482 } 483 484 void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( 485 const ArgList &DriverArgs, ArgStringList &CC1Args) const { 486 if (DriverArgs.hasArg(options::OPT_nostdlibinc) || 487 DriverArgs.hasArg(options::OPT_nostdincxx)) 488 return; 489 490 StringRef Slash = llvm::sys::path::get_separator(); 491 492 switch (GetCXXStdlibType(DriverArgs)) { 493 case ToolChain::CST_Libcxx: 494 addSystemInclude(DriverArgs, CC1Args, Base + Arch + Slash + "include" + 495 Slash + "c++" + Slash + "v1"); 496 addSystemInclude(DriverArgs, CC1Args, 497 Base + "include" + Slash + "c++" + Slash + "v1"); 498 break; 499 500 case ToolChain::CST_Libstdcxx: 501 llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases; 502 CppIncludeBases.emplace_back(Base); 503 llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); 504 CppIncludeBases.emplace_back(Base); 505 llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver); 506 CppIncludeBases.emplace_back(Base); 507 llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); 508 CppIncludeBases.emplace_back(GccLibDir); 509 llvm::sys::path::append(CppIncludeBases[3], "include", "c++"); 510 for (auto &CppIncludeBase : CppIncludeBases) { 511 addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); 512 CppIncludeBase += Slash; 513 addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); 514 addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); 515 } 516 break; 517 } 518 } 519