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 
17 using namespace clang::diag;
18 using namespace clang::driver;
19 using namespace clang::driver::toolchains;
20 using namespace clang;
21 using namespace llvm::opt;
22 
23 namespace {
24 // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
findGccVersion(StringRef LibDir,std::string & GccLibDir,std::string & Ver)25 bool 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 
findGccLibDir()45 void 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 
MinGW(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)65 MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
66     : ToolChain(D, Triple, Args) {
67   getProgramPaths().push_back(getDriver().getInstalledDir());
68 
69   // On Windows if there is no sysroot we search for gcc on the PATH.
70   if (getDriver().SysRoot.size())
71   Base = getDriver().SysRoot;
72 #ifdef LLVM_ON_WIN32
73   else if (llvm::ErrorOr<std::string> GPPName =
74                llvm::sys::findProgramByName("gcc"))
75     Base = llvm::sys::path::parent_path(
76         llvm::sys::path::parent_path(GPPName.get()));
77 #endif
78   if (!Base.size())
79     Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
80 
81   Base += llvm::sys::path::get_separator();
82   findGccLibDir();
83   // GccLibDir must precede Base/lib so that the
84   // correct crtbegin.o ,cetend.o would be found.
85   getFilePaths().push_back(GccLibDir);
86   getFilePaths().push_back(
87       (Base + Arch + llvm::sys::path::get_separator() + "lib").str());
88   getFilePaths().push_back(Base + "lib");
89   // openSUSE
90   getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib");
91 }
92 
IsIntegratedAssemblerDefault() const93 bool MinGW::IsIntegratedAssemblerDefault() const { return true; }
94 
getTool(Action::ActionClass AC) const95 Tool *MinGW::getTool(Action::ActionClass AC) const {
96   switch (AC) {
97   case Action::PreprocessJobClass:
98     if (!Preprocessor)
99       Preprocessor.reset(new tools::gcc::Preprocessor(*this));
100     return Preprocessor.get();
101   case Action::CompileJobClass:
102     if (!Compiler)
103       Compiler.reset(new tools::gcc::Compiler(*this));
104     return Compiler.get();
105   default:
106     return ToolChain::getTool(AC);
107   }
108 }
109 
buildAssembler() const110 Tool *MinGW::buildAssembler() const {
111   return new tools::MinGW::Assembler(*this);
112 }
113 
buildLinker() const114 Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); }
115 
IsUnwindTablesDefault() const116 bool MinGW::IsUnwindTablesDefault() const {
117   return getArch() == llvm::Triple::x86_64;
118 }
119 
isPICDefault() const120 bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; }
121 
isPIEDefault() const122 bool MinGW::isPIEDefault() const { return false; }
123 
isPICDefaultForced() const124 bool MinGW::isPICDefaultForced() const {
125   return getArch() == llvm::Triple::x86_64;
126 }
127 
UseSEHExceptions() const128 bool MinGW::UseSEHExceptions() const {
129   return getArch() == llvm::Triple::x86_64;
130 }
131 
132 // Include directories for various hosts:
133 
134 // Windows, mingw.org
135 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++
136 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32
137 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward
138 // c:\mingw\lib\gcc\mingw32\4.8.1\include
139 // c:\mingw\include
140 // c:\mingw\lib\gcc\mingw32\4.8.1\include-fixed
141 // c:\mingw\mingw32\include
142 
143 // Windows, mingw-w64 mingw-builds
144 // c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include
145 // c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include-fixed
146 // c:\mingw32\i686-w64-mingw32\include
147 // c:\mingw32\i686-w64-mingw32\include\c++
148 // c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32
149 // c:\mingw32\i686-w64-mingw32\include\c++\backward
150 
151 // Windows, mingw-w64 msys2
152 // c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include
153 // c:\msys64\mingw32\include
154 // c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include-fixed
155 // c:\msys64\mingw32\i686-w64-mingw32\include
156 // c:\msys64\mingw32\include\c++\4.9.2
157 // c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32
158 // c:\msys64\mingw32\include\c++\4.9.2\backward
159 
160 // openSUSE
161 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++
162 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32
163 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward
164 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include
165 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include-fixed
166 // /usr/x86_64-w64-mingw32/sys-root/mingw/include
167 
168 // Arch Linux
169 // /usr/i686-w64-mingw32/include/c++/5.1.0
170 // /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32
171 // /usr/i686-w64-mingw32/include/c++/5.1.0/backward
172 // /usr/lib/gcc/i686-w64-mingw32/5.1.0/include
173 // /usr/lib/gcc/i686-w64-mingw32/5.1.0/include-fixed
174 // /usr/i686-w64-mingw32/include
175 
176 // Ubuntu
177 // /usr/include/c++/4.8
178 // /usr/include/c++/4.8/x86_64-w64-mingw32
179 // /usr/include/c++/4.8/backward
180 // /usr/lib/gcc/x86_64-w64-mingw32/4.8/include
181 // /usr/lib/gcc/x86_64-w64-mingw32/4.8/include-fixed
182 // /usr/x86_64-w64-mingw32/include
183 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const184 void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
185                                       ArgStringList &CC1Args) const {
186   if (DriverArgs.hasArg(options::OPT_nostdinc))
187     return;
188 
189   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
190     SmallString<1024> P(getDriver().ResourceDir);
191     llvm::sys::path::append(P, "include");
192     addSystemInclude(DriverArgs, CC1Args, P.str());
193   }
194 
195   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
196     return;
197 
198   if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
199     llvm::SmallString<1024> IncludeDir(GccLibDir);
200     llvm::sys::path::append(IncludeDir, "include");
201     addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
202     IncludeDir += "-fixed";
203     // openSUSE
204     addSystemInclude(DriverArgs, CC1Args,
205                      Base + Arch + "/sys-root/mingw/include");
206     addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
207   }
208   addSystemInclude(DriverArgs, CC1Args,
209                    Base + Arch + llvm::sys::path::get_separator() + "include");
210   addSystemInclude(DriverArgs, CC1Args, Base + "include");
211 }
212 
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const213 void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
214                                          ArgStringList &CC1Args) const {
215   if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
216       DriverArgs.hasArg(options::OPT_nostdincxx))
217     return;
218 
219   switch (GetCXXStdlibType(DriverArgs)) {
220   case ToolChain::CST_Libcxx:
221     addSystemInclude(DriverArgs, CC1Args,
222                      Base + "include" + llvm::sys::path::get_separator() +
223                          "c++" + llvm::sys::path::get_separator() + "v1");
224     break;
225 
226   case ToolChain::CST_Libstdcxx:
227     llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
228     CppIncludeBases.emplace_back(Base);
229     llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
230     CppIncludeBases.emplace_back(Base);
231     llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
232     CppIncludeBases.emplace_back(Base);
233     llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
234     CppIncludeBases.emplace_back(GccLibDir);
235     llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
236     for (auto &CppIncludeBase : CppIncludeBases) {
237       addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
238       CppIncludeBase += llvm::sys::path::get_separator();
239       addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
240       addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
241     }
242     break;
243   }
244 }
245