hamzasood updated this revision to Diff 91962.
hamzasood added a comment.

Changed the call to GetEnvironmentStrings to use the unicode version


https://reviews.llvm.org/D30991

Files:
  include/clang/Driver/Job.h
  lib/Driver/Job.cpp
  lib/Driver/ToolChains/MSVC.cpp

Index: lib/Driver/ToolChains/MSVC.cpp
===================================================================
--- lib/Driver/ToolChains/MSVC.cpp
+++ lib/Driver/ToolChains/MSVC.cpp
@@ -45,17 +45,17 @@
   #endif
   #include <windows.h>
 
-// Make sure this comes before MSVCSetupApi.h
-#include <comdef.h>
+  // Make sure this comes before MSVCSetupApi.h
+  #include <comdef.h>
 
-#include "MSVCSetupApi.h"
-#include "llvm/Support/COM.h"
-_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
-_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
-_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
-_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
-_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
-_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
+  #include "MSVCSetupApi.h"
+  #include "llvm/Support/COM.h"
+  _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
+  _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
+  _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
+  _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
+  _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
+  _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
 #endif
 
 using namespace clang::driver;
@@ -441,6 +441,8 @@
 
   TC.addProfileRTLibs(Args, CmdArgs);
 
+  std::vector<const char *> Environment;
+
   // We need to special case some linker paths.  In the case of lld, we need to
   // translate 'lld' into 'lld-link', and in the case of the regular msvc
   // linker, we need to use a special search algorithm.
@@ -454,6 +456,68 @@
     // from the program PATH, because other environments like GnuWin32 install
     // their own link.exe which may come first.
     linkPath = FindVisualStudioExecutable(TC, "link.exe");
+
+#ifdef USE_WIN32
+    // When cross-compiling with VS2017 or newer, link.exe expects to have
+    // its containing bin directory at the top of PATH, followed by the
+    // native target bin directory.
+    // e.g. when compiling for x86 on an x64 host, PATH should start with:
+    // /bin/HostX64/x86;/bin/HostX64/x64
+    if (TC.getIsVS2017OrNewer() &&
+        llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
+      auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
+
+      auto EnvBlockWide = std::unique_ptr<wchar_t[],
+                                          decltype(&FreeEnvironmentStringsW)>(
+                            GetEnvironmentStringsW(), FreeEnvironmentStringsW);
+      if (!EnvBlockWide)
+        goto SkipSettingEnvironment;
+
+      size_t EnvCount = 0;
+      size_t EnvBlockLen = 0;
+      while (EnvBlockWide[EnvBlockLen] != '\0') {
+        ++EnvCount;
+        EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen])
+                       + 1/*string null-terminator*/;
+      }
+      ++EnvBlockLen;  // add the block null-terminator
+
+      std::string EnvBlock;
+      if (!llvm::convertUTF16ToUTF8String(
+             llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
+                                  EnvBlockLen * sizeof(EnvBlockWide[0])),
+             EnvBlock))
+        goto SkipSettingEnvironment;
+
+      Environment.reserve(EnvCount);
+
+      // Now loop over each string in the block and copy them into the
+      // environment vector, adjusting the PATH variable as needed when we
+      // find it.
+      for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
+        llvm::StringRef EnvVar(Cursor);
+        if (EnvVar.startswith_lower("path=")) {
+          using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
+          constexpr size_t PrefixLen = 5;  // strlen("path=")
+          Environment.push_back(Args.MakeArgString(
+              EnvVar.substr(0, PrefixLen)
+            + TC.getSubDirectoryPath(SubDirectoryType::Bin)
+            + llvm::Twine(llvm::sys::EnvPathSeparator)
+            + TC.getSubDirectoryPath(SubDirectoryType::Bin, HostArch)
+            + (EnvVar.size() > PrefixLen
+                  ? llvm::Twine(llvm::sys::EnvPathSeparator)
+                    + EnvVar.substr(PrefixLen)
+                  : "")
+          ));
+        } else {
+          Environment.push_back(Args.MakeArgString(EnvVar));
+        }
+        Cursor += EnvVar.size() + 1/*null-terminator*/;
+      }
+    }
+  SkipSettingEnvironment:
+    ;
+#endif
   } else {
     linkPath = Linker;
     llvm::sys::path::replace_extension(linkPath, "exe");
@@ -460,8 +524,11 @@
     linkPath = TC.GetProgramPath(linkPath.c_str());
   }
 
-  const char *Exec = Args.MakeArgString(linkPath);
-  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+  auto LinkCmd = llvm::make_unique<Command>(
+                   JA, *this, Args.MakeArgString(linkPath), CmdArgs, Inputs);
+  if (!Environment.empty())
+    LinkCmd->setEnvironment(std::move(Environment));
+  C.addCommand(std::move(LinkCmd));
 }
 
 void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
Index: lib/Driver/Job.cpp
===================================================================
--- lib/Driver/Job.cpp
+++ lib/Driver/Job.cpp
@@ -301,9 +301,17 @@
   ResponseFileFlag += FileName;
 }
 
+void Command::setEnvironment(std::vector<const char *> NewEnvironment) {
+  Environment = std::move(NewEnvironment);
+  Environment.push_back(nullptr);
+}
+
 int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
                      bool *ExecutionFailed) const {
   SmallVector<const char*, 128> Argv;
+  auto Envp = Environment.size() > 1
+                ? const_cast<const char **>(Environment.data())
+                : nullptr;
 
   if (ResponseFile == nullptr) {
     Argv.push_back(Executable);
@@ -310,7 +318,7 @@
     Argv.append(Arguments.begin(), Arguments.end());
     Argv.push_back(nullptr);
 
-    return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
+    return llvm::sys::ExecuteAndWait(Executable, Argv.data(), Envp,
                                      Redirects, /*secondsToWait*/ 0,
                                      /*memoryLimit*/ 0, ErrMsg,
                                      ExecutionFailed);
@@ -337,7 +345,7 @@
     return -1;
   }
 
-  return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
+  return llvm::sys::ExecuteAndWait(Executable, Argv.data(), Envp,
                                    Redirects, /*secondsToWait*/ 0,
                                    /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
 }
Index: include/clang/Driver/Job.h
===================================================================
--- include/clang/Driver/Job.h
+++ include/clang/Driver/Job.h
@@ -69,6 +69,9 @@
   /// file
   std::string ResponseFileFlag;
 
+  /// See Command::setEnvironment
+  std::vector<const char *> Environment;
+
   /// When a response file is needed, we try to put most arguments in an
   /// exclusive file, while others remains as regular command line arguments.
   /// This functions fills a vector with the regular command line arguments,
@@ -111,6 +114,12 @@
     InputFileList = std::move(List);
   }
 
+  /// \brief Set the environment to be used by the new process.
+  /// \param NewEnvironment A vector of environment variables.
+  /// \remark If NewEnvironment is empty, or infact if the environment remains
+  ///         unset, then the environment from this process will be used.
+  void setEnvironment(std::vector<const char *> NewEnvironment);
+
   const char *getExecutable() const { return Executable; }
 
   const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to