Index: llvm/lib/Support/Windows/Process.inc =================================================================== --- llvm/lib/Support/Windows/Process.inc +++ llvm/lib/Support/Windows/Process.inc @@ -209,21 +209,63 @@ return ec; } -static std::error_code ExpandShortFileName(const wchar_t *Arg, - SmallVectorImpl &Args, - BumpPtrAllocator &Alloc) { - SmallVector LongPath; - DWORD Length = GetLongPathNameW(Arg, LongPath.data(), LongPath.capacity()); +static std::error_code GetLongArgv0FullPath(SmallVectorImpl &LongArgv0) { + // The first argument may contain just the name of the executable (e.g., + // "clang") rather than the full path, so swap it with the full path. + wchar_t ModuleName[MAX_PATH]; + int Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); + if (Length == 0 || Length == MAX_PATH) { + return mapWindowsError(GetLastError()); + } + + // If the first argument is a shortened (8.3) name (which is possible even + // if we got the module name), the driver will have trouble distinguishing it + // (e.g., clang.exe v. clang++.exe), so expand it now. + Length = GetLongPathNameW(ModuleName, LongArgv0.data(), LongArgv0.capacity()); if (Length == 0) return mapWindowsError(GetLastError()); - if (Length > LongPath.capacity()) { + if (static_cast(Length) > LongArgv0.capacity()) { // We're not going to try to deal with paths longer than MAX_PATH, so we'll // treat this as an error. GetLastError() returns ERROR_SUCCESS, which // isn't useful, so we'll hardcode an appropriate error value. return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); } - LongPath.set_size(Length); - return ConvertAndPushArg(LongPath.data(), Args, Alloc); + LongArgv0.set_size(Length); + return std::error_code(); +} + +static std::error_code GetLongArgv0Path(const wchar_t *Argv0, + SmallVectorImpl &LongArgv0) { + // Replace filename in original argv0 with expanded filename. + // This may change original filename argv0 like below, + // * clang -> clang.exe (just add extension) + // * CLANG_~1.EXE -> clang++.exe (extend shorname) + // This is for keeping relativeness of original argv0 path. + + SmallVector UTF16LongArgv0Full; + + std::error_code ec = GetLongArgv0FullPath(UTF16LongArgv0Full); + if (ec) + return ec; + + SmallVector UTF8LongArgv0Full; + ec = windows::UTF16ToUTF8(UTF16LongArgv0Full.data(), UTF16LongArgv0Full.size(), + UTF8LongArgv0Full); + if (ec) + return ec; + + ec = windows::UTF16ToUTF8(Argv0, wcslen(Argv0), LongArgv0); + if (ec) + return ec; + + sys::path::remove_filename(LongArgv0); + sys::path::append(LongArgv0, sys::path::filename(UTF8LongArgv0Full.data())); + + // null terminates. + LongArgv0.push_back(0); + LongArgv0.pop_back(); + + return std::error_code(); } std::error_code @@ -236,19 +278,11 @@ return mapWindowsError(::GetLastError()); Args.reserve(ArgCount); - std::error_code ec; + SmallVector LongArgv0; + std::error_code ec = GetLongArgv0Path(UnicodeCommandLine[0], LongArgv0); - // The first argument may contain just the name of the executable (e.g., - // "clang") rather than the full path, so swap it with the full path. - wchar_t ModuleName[MAX_PATH]; - int Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); - if (0 < Length && Length < MAX_PATH) - UnicodeCommandLine[0] = ModuleName; - - // If the first argument is a shortened (8.3) name (which is possible even - // if we got the module name), the driver will have trouble distinguishing it - // (e.g., clang.exe v. clang++.exe), so expand it now. - ec = ExpandShortFileName(UnicodeCommandLine[0], Args, Alloc); + if (!ec) + Args.push_back(AllocateString(LongArgv0, Alloc)); for (int i = 1; i < ArgCount && !ec; ++i) { ec = WildcardExpand(UnicodeCommandLine[i], Args, Alloc); Index: llvm/unittests/Support/CommandLineTest.cpp =================================================================== --- llvm/unittests/Support/CommandLineTest.cpp +++ llvm/unittests/Support/CommandLineTest.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/Config/config.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/StringSaver.h" @@ -821,4 +822,22 @@ EXPECT_TRUE(Errs.empty()); } +#ifdef _WIN32 +TEST(CommandLineTest, GetCommandLineArguments) { + int argc = __argc; + char **argv = __argv; + + // GetCommandLineArguments is called in InitLLVM. + llvm::InitLLVM X(argc, argv); + + EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]), + llvm::sys::path::is_absolute(__argv[0])); + + EXPECT_TRUE(llvm::sys::path::filename(argv[0]) + .equals_lower("supporttests.exe")) + << "Filename of test executable is " + << llvm::sys::path::filename(argv[0]); +} +#endif + } // anonymous namespace