1//===--- MinGWToolChain.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 "ToolChains.h"
11#include "clang/Driver/Driver.h"
12#include "clang/Driver/Options.h"
13#include "llvm/Option/ArgList.h"
14#include "llvm/Support/FileSystem.h"
15#include "llvm/Support/Path.h"
16
17using namespace clang::diag;
18using namespace clang::driver;
19using namespace clang::driver::toolchains;
20using namespace clang;
21using namespace llvm::opt;
22
23namespace {
24// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
25bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
26                    std::string &Ver) {
27  Generic_GCC::GCCVersion Version = Generic_GCC::GCCVersion::Parse("0.0.0");
28  std::error_code EC;
29  for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
30       LI = LI.increment(EC)) {
31    StringRef VersionText = llvm::sys::path::filename(LI->path());
32    Generic_GCC::GCCVersion CandidateVersion =
33        Generic_GCC::GCCVersion::Parse(VersionText);
34    if (CandidateVersion.Major == -1)
35      continue;
36    if (CandidateVersion <= Version)
37      continue;
38    Ver = VersionText;
39    GccLibDir = LI->path();
40  }
41  return Ver.size();
42}
43}
44
45void MinGW::findGccLibDir() {
46  llvm::SmallVector<llvm::SmallString<32>, 2> Archs;
47  Archs.emplace_back(getTriple().getArchName());
48  Archs[0] += "-w64-mingw32";
49  Archs.emplace_back("mingw32");
50  Arch = Archs[0].str();
51  // lib: Arch Linux, Ubuntu, Windows
52  // lib64: openSUSE Linux
53  for (StringRef CandidateLib : {"lib", "lib64"}) {
54    for (StringRef CandidateArch : Archs) {
55      llvm::SmallString<1024> LibDir(Base);
56      llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch);
57      if (findGccVersion(LibDir, GccLibDir, Ver)) {
58        Arch = CandidateArch;
59        return;
60      }
61    }
62  }
63}
64
65MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
66    : ToolChain(D, Triple, Args) {
67  getProgramPaths().push_back(getDriver().getInstalledDir());
68
69// In Windows there aren't any standard install locations, we search
70// for gcc on the PATH. In Linux the base is always /usr.
71#ifdef LLVM_ON_WIN32
72  if (getDriver().SysRoot.size())
73    Base = getDriver().SysRoot;
74  else if (llvm::ErrorOr<std::string> GPPName =
75               llvm::sys::findProgramByName("gcc"))
76    Base = llvm::sys::path::parent_path(
77        llvm::sys::path::parent_path(GPPName.get()));
78  else
79    Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
80#else
81  if (getDriver().SysRoot.size())
82    Base = getDriver().SysRoot;
83  else
84    Base = "/usr";
85#endif
86
87  Base += llvm::sys::path::get_separator();
88  findGccLibDir();
89  // GccLibDir must precede Base/lib so that the
90  // correct crtbegin.o ,cetend.o would be found.
91  getFilePaths().push_back(GccLibDir);
92  getFilePaths().push_back(
93      (Base + Arch + llvm::sys::path::get_separator() + "lib").str());
94  getFilePaths().push_back(Base + "lib");
95  // openSUSE
96  getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib");
97}
98
99bool MinGW::IsIntegratedAssemblerDefault() const { return true; }
100
101Tool *MinGW::getTool(Action::ActionClass AC) const {
102  switch (AC) {
103  case Action::PreprocessJobClass:
104    if (!Preprocessor)
105      Preprocessor.reset(new tools::gcc::Preprocessor(*this));
106    return Preprocessor.get();
107  case Action::CompileJobClass:
108    if (!Compiler)
109      Compiler.reset(new tools::gcc::Compiler(*this));
110    return Compiler.get();
111  default:
112    return ToolChain::getTool(AC);
113  }
114}
115
116Tool *MinGW::buildAssembler() const {
117  return new tools::MinGW::Assembler(*this);
118}
119
120Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); }
121
122bool MinGW::IsUnwindTablesDefault() const {
123  return getArch() == llvm::Triple::x86_64;
124}
125
126bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; }
127
128bool MinGW::isPIEDefault() const { return false; }
129
130bool MinGW::isPICDefaultForced() const {
131  return getArch() == llvm::Triple::x86_64;
132}
133
134bool MinGW::UseSEHExceptions() const {
135  return getArch() == llvm::Triple::x86_64;
136}
137
138// Include directories for various hosts:
139
140// Windows, mingw.org
141// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++
142// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32
143// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward
144// c:\mingw\lib\gcc\mingw32\4.8.1\include
145// c:\mingw\include
146// c:\mingw\lib\gcc\mingw32\4.8.1\include-fixed
147// c:\mingw\mingw32\include
148
149// Windows, mingw-w64 mingw-builds
150// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include
151// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include-fixed
152// c:\mingw32\i686-w64-mingw32\include
153// c:\mingw32\i686-w64-mingw32\include\c++
154// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32
155// c:\mingw32\i686-w64-mingw32\include\c++\backward
156
157// Windows, mingw-w64 msys2
158// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include
159// c:\msys64\mingw32\include
160// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include-fixed
161// c:\msys64\mingw32\i686-w64-mingw32\include
162// c:\msys64\mingw32\include\c++\4.9.2
163// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32
164// c:\msys64\mingw32\include\c++\4.9.2\backward
165
166// openSUSE
167// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++
168// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32
169// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward
170// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include
171// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include-fixed
172// /usr/x86_64-w64-mingw32/sys-root/mingw/include
173
174// Arch Linux
175// /usr/i686-w64-mingw32/include/c++/5.1.0
176// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32
177// /usr/i686-w64-mingw32/include/c++/5.1.0/backward
178// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include
179// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include-fixed
180// /usr/i686-w64-mingw32/include
181
182// Ubuntu
183// /usr/include/c++/4.8
184// /usr/include/c++/4.8/x86_64-w64-mingw32
185// /usr/include/c++/4.8/backward
186// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include
187// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include-fixed
188// /usr/x86_64-w64-mingw32/include
189
190void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
191                                      ArgStringList &CC1Args) const {
192  if (DriverArgs.hasArg(options::OPT_nostdinc))
193    return;
194
195  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
196    SmallString<1024> P(getDriver().ResourceDir);
197    llvm::sys::path::append(P, "include");
198    addSystemInclude(DriverArgs, CC1Args, P.str());
199  }
200
201  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
202    return;
203
204  if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
205    llvm::SmallString<1024> IncludeDir(GccLibDir);
206    llvm::sys::path::append(IncludeDir, "include");
207    addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
208    IncludeDir += "-fixed";
209    // openSUSE
210    addSystemInclude(DriverArgs, CC1Args,
211                     Base + Arch + "/sys-root/mingw/include");
212    addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
213  }
214  addSystemInclude(DriverArgs, CC1Args,
215                   Base + Arch + llvm::sys::path::get_separator() + "include");
216  addSystemInclude(DriverArgs, CC1Args, Base + "include");
217}
218
219void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
220                                         ArgStringList &CC1Args) const {
221  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
222      DriverArgs.hasArg(options::OPT_nostdincxx))
223    return;
224
225  switch (GetCXXStdlibType(DriverArgs)) {
226  case ToolChain::CST_Libcxx:
227    addSystemInclude(DriverArgs, CC1Args,
228                     Base + "include" + llvm::sys::path::get_separator() +
229                         "c++" + llvm::sys::path::get_separator() + "v1");
230    break;
231
232  case ToolChain::CST_Libstdcxx:
233    llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
234    CppIncludeBases.emplace_back(Base);
235    llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
236    CppIncludeBases.emplace_back(Base);
237    llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
238    CppIncludeBases.emplace_back(Base);
239    llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
240    CppIncludeBases.emplace_back(GccLibDir);
241    llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
242    for (auto &CppIncludeBase : CppIncludeBases) {
243      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
244      CppIncludeBase += llvm::sys::path::get_separator();
245      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
246      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
247    }
248    break;
249  }
250}
251