xref: /minix3/external/bsd/llvm/dist/clang/lib/Driver/MSVCToolChain.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1  //===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
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/Basic/CharInfo.h"
12  #include "clang/Basic/Version.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/ADT/StringExtras.h"
18  #include "llvm/Config/llvm-config.h"
19  #include "llvm/Option/Arg.h"
20  #include "llvm/Option/ArgList.h"
21  #include "llvm/Support/ErrorHandling.h"
22  #include "llvm/Support/FileSystem.h"
23  #include "llvm/Support/Process.h"
24  
25  // Include the necessary headers to interface with the Windows registry and
26  // environment.
27  #if defined(LLVM_ON_WIN32)
28  #define USE_WIN32
29  #endif
30  
31  #ifdef USE_WIN32
32    #define WIN32_LEAN_AND_MEAN
33    #define NOGDI
34    #ifndef NOMINMAX
35      #define NOMINMAX
36    #endif
37    #include <windows.h>
38  #endif
39  
40  using namespace clang::driver;
41  using namespace clang::driver::toolchains;
42  using namespace clang;
43  using namespace llvm::opt;
44  
MSVCToolChain(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)45  MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple& Triple,
46                               const ArgList &Args)
47    : ToolChain(D, Triple, Args) {
48    getProgramPaths().push_back(getDriver().getInstalledDir());
49    if (getDriver().getInstalledDir() != getDriver().Dir)
50      getProgramPaths().push_back(getDriver().Dir);
51  }
52  
buildLinker() const53  Tool *MSVCToolChain::buildLinker() const {
54    return new tools::visualstudio::Link(*this);
55  }
56  
buildAssembler() const57  Tool *MSVCToolChain::buildAssembler() const {
58    if (getTriple().isOSBinFormatMachO())
59      return new tools::darwin::Assemble(*this);
60    getDriver().Diag(clang::diag::err_no_external_assembler);
61    return nullptr;
62  }
63  
IsIntegratedAssemblerDefault() const64  bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
65    return true;
66  }
67  
IsUnwindTablesDefault() const68  bool MSVCToolChain::IsUnwindTablesDefault() const {
69    // Emit unwind tables by default on Win64. All non-x86_32 Windows platforms
70    // such as ARM and PPC actually require unwind tables, but LLVM doesn't know
71    // how to generate them yet.
72    return getArch() == llvm::Triple::x86_64;
73  }
74  
isPICDefault() const75  bool MSVCToolChain::isPICDefault() const {
76    return getArch() == llvm::Triple::x86_64;
77  }
78  
isPIEDefault() const79  bool MSVCToolChain::isPIEDefault() const {
80    return false;
81  }
82  
isPICDefaultForced() const83  bool MSVCToolChain::isPICDefaultForced() const {
84    return getArch() == llvm::Triple::x86_64;
85  }
86  
87  #ifdef USE_WIN32
readFullStringValue(HKEY hkey,const char * valueName,std::string & value)88  static bool readFullStringValue(HKEY hkey, const char *valueName,
89                                  std::string &value) {
90    // FIXME: We should be using the W versions of the registry functions, but
91    // doing so requires UTF8 / UTF16 conversions similar to how we handle command
92    // line arguments.  The UTF8 conversion functions are not exposed publicly
93    // from LLVM though, so in order to do this we will probably need to create
94    // a registry abstraction in LLVMSupport that is Windows only.
95    DWORD result = 0;
96    DWORD valueSize = 0;
97    DWORD type = 0;
98    // First just query for the required size.
99    result = RegQueryValueEx(hkey, valueName, NULL, &type, NULL, &valueSize);
100    if (result != ERROR_SUCCESS || type != REG_SZ)
101      return false;
102    std::vector<BYTE> buffer(valueSize);
103    result = RegQueryValueEx(hkey, valueName, NULL, NULL, &buffer[0], &valueSize);
104    if (result == ERROR_SUCCESS)
105      value.assign(reinterpret_cast<const char *>(buffer.data()));
106    return result;
107  }
108  #endif
109  
110  /// \brief Read registry string.
111  /// This also supports a means to look for high-versioned keys by use
112  /// of a $VERSION placeholder in the key path.
113  /// $VERSION in the key path is a placeholder for the version number,
114  /// causing the highest value path to be searched for and used.
115  /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
116  /// There can be additional characters in the component.  Only the numeric
117  /// characters are compared.  This function only searches HKLM.
getSystemRegistryString(const char * keyPath,const char * valueName,std::string & value,std::string * phValue)118  static bool getSystemRegistryString(const char *keyPath, const char *valueName,
119                                      std::string &value, std::string *phValue) {
120  #ifndef USE_WIN32
121    return false;
122  #else
123    HKEY hRootKey = HKEY_LOCAL_MACHINE;
124    HKEY hKey = NULL;
125    long lResult;
126    bool returnValue = false;
127  
128    const char *placeHolder = strstr(keyPath, "$VERSION");
129    std::string bestName;
130    // If we have a $VERSION placeholder, do the highest-version search.
131    if (placeHolder) {
132      const char *keyEnd = placeHolder - 1;
133      const char *nextKey = placeHolder;
134      // Find end of previous key.
135      while ((keyEnd > keyPath) && (*keyEnd != '\\'))
136        keyEnd--;
137      // Find end of key containing $VERSION.
138      while (*nextKey && (*nextKey != '\\'))
139        nextKey++;
140      size_t partialKeyLength = keyEnd - keyPath;
141      char partialKey[256];
142      if (partialKeyLength > sizeof(partialKey))
143        partialKeyLength = sizeof(partialKey);
144      strncpy(partialKey, keyPath, partialKeyLength);
145      partialKey[partialKeyLength] = '\0';
146      HKEY hTopKey = NULL;
147      lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
148                             &hTopKey);
149      if (lResult == ERROR_SUCCESS) {
150        char keyName[256];
151        double bestValue = 0.0;
152        DWORD index, size = sizeof(keyName) - 1;
153        for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
154            NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
155          const char *sp = keyName;
156          while (*sp && !isDigit(*sp))
157            sp++;
158          if (!*sp)
159            continue;
160          const char *ep = sp + 1;
161          while (*ep && (isDigit(*ep) || (*ep == '.')))
162            ep++;
163          char numBuf[32];
164          strncpy(numBuf, sp, sizeof(numBuf) - 1);
165          numBuf[sizeof(numBuf) - 1] = '\0';
166          double dvalue = strtod(numBuf, NULL);
167          if (dvalue > bestValue) {
168            // Test that InstallDir is indeed there before keeping this index.
169            // Open the chosen key path remainder.
170            bestName = keyName;
171            // Append rest of key.
172            bestName.append(nextKey);
173            lResult = RegOpenKeyEx(hTopKey, bestName.c_str(), 0,
174                                   KEY_READ | KEY_WOW64_32KEY, &hKey);
175            if (lResult == ERROR_SUCCESS) {
176              lResult = readFullStringValue(hKey, valueName, value);
177              if (lResult == ERROR_SUCCESS) {
178                bestValue = dvalue;
179                if (phValue)
180                  *phValue = bestName;
181                returnValue = true;
182              }
183              RegCloseKey(hKey);
184            }
185          }
186          size = sizeof(keyName) - 1;
187        }
188        RegCloseKey(hTopKey);
189      }
190    } else {
191      lResult =
192          RegOpenKeyEx(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
193      if (lResult == ERROR_SUCCESS) {
194        lResult = readFullStringValue(hKey, valueName, value);
195        if (lResult == ERROR_SUCCESS)
196          returnValue = true;
197        if (phValue)
198          phValue->clear();
199        RegCloseKey(hKey);
200      }
201    }
202    return returnValue;
203  #endif // USE_WIN32
204  }
205  
206  /// \brief Get Windows SDK installation directory.
getWindowsSDKDir(std::string & path,int & major,int & minor) const207  bool MSVCToolChain::getWindowsSDKDir(std::string &path, int &major,
208                                       int &minor) const {
209    std::string sdkVersion;
210    // Try the Windows registry.
211    bool hasSDKDir = getSystemRegistryString(
212        "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
213        "InstallationFolder", path, &sdkVersion);
214    if (!sdkVersion.empty())
215      ::sscanf(sdkVersion.c_str(), "v%d.%d", &major, &minor);
216    return hasSDKDir && !path.empty();
217  }
218  
219  // Gets the library path required to link against the Windows SDK.
getWindowsSDKLibraryPath(std::string & path) const220  bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
221    std::string sdkPath;
222    int sdkMajor = 0;
223    int sdkMinor = 0;
224  
225    path.clear();
226    if (!getWindowsSDKDir(sdkPath, sdkMajor, sdkMinor))
227      return false;
228  
229    llvm::SmallString<128> libPath(sdkPath);
230    llvm::sys::path::append(libPath, "Lib");
231    if (sdkMajor <= 7) {
232      switch (getArch()) {
233      // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
234      case llvm::Triple::x86:
235        break;
236      case llvm::Triple::x86_64:
237        llvm::sys::path::append(libPath, "x64");
238        break;
239      case llvm::Triple::arm:
240        // It is not necessary to link against Windows SDK 7.x when targeting ARM.
241        return false;
242      default:
243        return false;
244      }
245    } else {
246      // Windows SDK 8.x installs libraries in a folder whose names depend on the
247      // version of the OS you're targeting.  By default choose the newest, which
248      // usually corresponds to the version of the OS you've installed the SDK on.
249      const char *tests[] = {"winv6.3", "win8", "win7"};
250      bool found = false;
251      for (const char *test : tests) {
252        llvm::SmallString<128> testPath(libPath);
253        llvm::sys::path::append(testPath, test);
254        if (llvm::sys::fs::exists(testPath.c_str())) {
255          libPath = testPath;
256          found = true;
257          break;
258        }
259      }
260  
261      if (!found)
262        return false;
263  
264      llvm::sys::path::append(libPath, "um");
265      switch (getArch()) {
266      case llvm::Triple::x86:
267        llvm::sys::path::append(libPath, "x86");
268        break;
269      case llvm::Triple::x86_64:
270        llvm::sys::path::append(libPath, "x64");
271        break;
272      case llvm::Triple::arm:
273        llvm::sys::path::append(libPath, "arm");
274        break;
275      default:
276        return false;
277      }
278    }
279  
280    path = libPath.str();
281    return true;
282  }
283  
284  // Get the location to use for Visual Studio binaries.  The location priority
285  // is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on
286  // system (as reported by the registry).
getVisualStudioBinariesFolder(const char * clangProgramPath,std::string & path) const287  bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath,
288                                                    std::string &path) const {
289    path.clear();
290  
291    SmallString<128> BinDir;
292  
293    // First check the environment variables that vsvars32.bat sets.
294    llvm::Optional<std::string> VcInstallDir =
295        llvm::sys::Process::GetEnv("VCINSTALLDIR");
296    if (VcInstallDir.hasValue()) {
297      BinDir = VcInstallDir.getValue();
298      llvm::sys::path::append(BinDir, "bin");
299    } else {
300      // Next walk the PATH, trying to find a cl.exe in the path.  If we find one,
301      // use that.  However, make sure it's not clang's cl.exe.
302      llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
303      if (OptPath.hasValue()) {
304        const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
305        SmallVector<StringRef, 8> PathSegments;
306        llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr);
307  
308        for (StringRef PathSegment : PathSegments) {
309          if (PathSegment.empty())
310            continue;
311  
312          SmallString<128> FilePath(PathSegment);
313          llvm::sys::path::append(FilePath, "cl.exe");
314          if (llvm::sys::fs::can_execute(FilePath.c_str()) &&
315              !llvm::sys::fs::equivalent(FilePath.c_str(), clangProgramPath)) {
316            // If we found it on the PATH, use it exactly as is with no
317            // modifications.
318            path = PathSegment;
319            return true;
320          }
321        }
322      }
323  
324      std::string installDir;
325      // With no VCINSTALLDIR and nothing on the PATH, if we can't find it in the
326      // registry then we have no choice but to fail.
327      if (!getVisualStudioInstallDir(installDir))
328        return false;
329  
330      // Regardless of what binary we're ultimately trying to find, we make sure
331      // that this is a Visual Studio directory by checking for cl.exe.  We use
332      // cl.exe instead of other binaries like link.exe because programs such as
333      // GnuWin32 also have a utility called link.exe, so cl.exe is the least
334      // ambiguous.
335      BinDir = installDir;
336      llvm::sys::path::append(BinDir, "VC", "bin");
337      SmallString<128> ClPath(BinDir);
338      llvm::sys::path::append(ClPath, "cl.exe");
339  
340      if (!llvm::sys::fs::can_execute(ClPath.c_str()))
341        return false;
342    }
343  
344    if (BinDir.empty())
345      return false;
346  
347    switch (getArch()) {
348    case llvm::Triple::x86:
349      break;
350    case llvm::Triple::x86_64:
351      llvm::sys::path::append(BinDir, "amd64");
352      break;
353    case llvm::Triple::arm:
354      llvm::sys::path::append(BinDir, "arm");
355      break;
356    default:
357      // Whatever this is, Visual Studio doesn't have a toolchain for it.
358      return false;
359    }
360    path = BinDir.str();
361    return true;
362  }
363  
364  // Get Visual Studio installation directory.
getVisualStudioInstallDir(std::string & path) const365  bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const {
366    // First check the environment variables that vsvars32.bat sets.
367    const char *vcinstalldir = getenv("VCINSTALLDIR");
368    if (vcinstalldir) {
369      path = vcinstalldir;
370      path = path.substr(0, path.find("\\VC"));
371      return true;
372    }
373  
374    std::string vsIDEInstallDir;
375    std::string vsExpressIDEInstallDir;
376    // Then try the windows registry.
377    bool hasVCDir =
378        getSystemRegistryString("SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
379                                "InstallDir", vsIDEInstallDir, nullptr);
380    if (hasVCDir && !vsIDEInstallDir.empty()) {
381      path = vsIDEInstallDir.substr(0, vsIDEInstallDir.find("\\Common7\\IDE"));
382      return true;
383    }
384  
385    bool hasVCExpressDir =
386        getSystemRegistryString("SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
387                                "InstallDir", vsExpressIDEInstallDir, nullptr);
388    if (hasVCExpressDir && !vsExpressIDEInstallDir.empty()) {
389      path = vsExpressIDEInstallDir.substr(
390          0, vsIDEInstallDir.find("\\Common7\\IDE"));
391      return true;
392    }
393  
394    // Try the environment.
395    const char *vs120comntools = getenv("VS120COMNTOOLS");
396    const char *vs100comntools = getenv("VS100COMNTOOLS");
397    const char *vs90comntools = getenv("VS90COMNTOOLS");
398    const char *vs80comntools = getenv("VS80COMNTOOLS");
399  
400    const char *vscomntools = nullptr;
401  
402    // Find any version we can
403    if (vs120comntools)
404      vscomntools = vs120comntools;
405    else if (vs100comntools)
406      vscomntools = vs100comntools;
407    else if (vs90comntools)
408      vscomntools = vs90comntools;
409    else if (vs80comntools)
410      vscomntools = vs80comntools;
411  
412    if (vscomntools && *vscomntools) {
413      const char *p = strstr(vscomntools, "\\Common7\\Tools");
414      path = p ? std::string(vscomntools, p) : vscomntools;
415      return true;
416    }
417    return false;
418  }
419  
AddSystemIncludeWithSubfolder(const ArgList & DriverArgs,ArgStringList & CC1Args,const std::string & folder,const char * subfolder) const420  void MSVCToolChain::AddSystemIncludeWithSubfolder(const ArgList &DriverArgs,
421                                                    ArgStringList &CC1Args,
422                                                    const std::string &folder,
423                                                    const char *subfolder) const {
424    llvm::SmallString<128> path(folder);
425    llvm::sys::path::append(path, subfolder);
426    addSystemInclude(DriverArgs, CC1Args, path.str());
427  }
428  
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const429  void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
430                                                ArgStringList &CC1Args) const {
431    if (DriverArgs.hasArg(options::OPT_nostdinc))
432      return;
433  
434    if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
435      SmallString<128> P(getDriver().ResourceDir);
436      llvm::sys::path::append(P, "include");
437      addSystemInclude(DriverArgs, CC1Args, P.str());
438    }
439  
440    if (DriverArgs.hasArg(options::OPT_nostdlibinc))
441      return;
442  
443    // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
444    if (const char *cl_include_dir = getenv("INCLUDE")) {
445      SmallVector<StringRef, 8> Dirs;
446      StringRef(cl_include_dir)
447          .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
448      for (StringRef Dir : Dirs)
449        addSystemInclude(DriverArgs, CC1Args, Dir);
450      if (!Dirs.empty())
451        return;
452    }
453  
454    std::string VSDir;
455  
456    // When built with access to the proper Windows APIs, try to actually find
457    // the correct include paths first.
458    if (getVisualStudioInstallDir(VSDir)) {
459      AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include");
460  
461      std::string WindowsSDKDir;
462      int major, minor;
463      if (getWindowsSDKDir(WindowsSDKDir, major, minor)) {
464        if (major >= 8) {
465          AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
466                                        "include\\shared");
467          AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
468                                        "include\\um");
469          AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
470                                        "include\\winrt");
471        } else {
472          AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
473                                        "include");
474        }
475      } else {
476        addSystemInclude(DriverArgs, CC1Args, VSDir);
477      }
478      return;
479    }
480  
481    // As a fallback, select default install paths.
482    // FIXME: Don't guess drives and paths like this on Windows.
483    const StringRef Paths[] = {
484      "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
485      "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
486      "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
487      "C:/Program Files/Microsoft Visual Studio 8/VC/include",
488      "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
489    };
490    addSystemIncludes(DriverArgs, CC1Args, Paths);
491  }
492  
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const493  void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
494                                                   ArgStringList &CC1Args) const {
495    // FIXME: There should probably be logic here to find libc++ on Windows.
496  }
497