2
0
Эх сурвалжийг харах

Enable build for dxa/dxl/dxopt/dxr/dxv on linux (#4895)

* Enable build for dxa/dxl/dxopt/dxr/dxv on linux

* Add CComBSTR and enable PdbUtils, Rewriter and recompile.
Xiang Li 2 жил өмнө
parent
commit
2eb641d56b
31 өөрчлөгдсөн 448 нэмэгдсэн , 168 устгасан
  1. 0 5
      docs/DxcOnUnix.rst
  2. 53 0
      include/dxc/Support/WinAdapter.h
  3. 2 2
      include/dxc/Support/WinFunctions.h
  4. 47 2
      lib/DxcSupport/WinAdapter.cpp
  5. 1 1
      tools/clang/test/CMakeLists.txt
  6. 4 0
      tools/clang/test/DXC/Inputs/inc2.hlsli
  7. 7 0
      tools/clang/test/DXC/Inputs/include/inc1.hlsli
  8. 15 0
      tools/clang/test/DXC/Inputs/lib_res_match.hlsl
  9. 22 0
      tools/clang/test/DXC/Inputs/smoke.hlsl
  10. 36 0
      tools/clang/test/DXC/dxa_tests.test
  11. 19 0
      tools/clang/test/DXC/dxopt_test.test
  12. 5 0
      tools/clang/test/DXC/dxr_test.test
  13. 31 0
      tools/clang/test/DXC/lib_entry4.hlsl
  14. 22 0
      tools/clang/test/DXC/recompile.test
  15. 19 1
      tools/clang/test/lit.cfg
  16. 1 0
      tools/clang/test/lit.site.cfg.in
  17. 5 5
      tools/clang/tools/CMakeLists.txt
  18. 7 4
      tools/clang/tools/dxa/dxa.cpp
  19. 7 7
      tools/clang/tools/dxclib/dxc.cpp
  20. 1 1
      tools/clang/tools/dxcompiler/CMakeLists.txt
  21. 7 7
      tools/clang/tools/dxcompiler/dxcapi.cpp
  22. 2 1
      tools/clang/tools/dxcompiler/dxclinker.cpp
  23. 31 29
      tools/clang/tools/dxcompiler/dxcpdbutils.cpp
  24. 1 1
      tools/clang/tools/dxl/dxl.cpp
  25. 30 14
      tools/clang/tools/dxopt/dxopt.cpp
  26. 15 87
      tools/clang/tools/dxr/dxr.cpp
  27. 4 0
      tools/clang/tools/dxv/dxv.cpp
  28. 0 1
      tools/clang/unittests/HLSL/DXIsenseTest.cpp
  29. 1 0
      unittests/CMakeLists.txt
  30. 8 0
      unittests/DxcSupport/CMakeLists.txt
  31. 45 0
      unittests/DxcSupport/WinAdapterTest.cpp

+ 0 - 5
docs/DxcOnUnix.rst

@@ -39,11 +39,6 @@ The following targets are currently disabled for non-Windows platforms and this
 is an area where further contributions can be made:
 
 * d3dcomp
-* dxa
-* dxopt
-* dxl
-* dxr
-* dxv
 * dxlib-sample
 
 Moreover, since the HLSL CodeGen tests were originally written with Windows in

+ 53 - 0
include/dxc/Support/WinAdapter.h

@@ -122,6 +122,7 @@
 #define ERROR_NOT_CAPABLE EPERM
 #define ERROR_NOT_FOUND ENOTSUP
 #define ERROR_UNHANDLED_EXCEPTION EBADF
+#define ERROR_BROKEN_PIPE EPIPE
 
 // Used by HRESULT <--> WIN32 error code conversion
 #define SEVERITY_ERROR 1
@@ -1039,8 +1040,60 @@ private:
   HANDLE m_h;
 };
 
+
+/////////////////////////////////////////////////////////////////////////////
+// CComBSTR
+
+class CComBSTR
+{
+public:
+    BSTR m_str;
+    CComBSTR() : m_str(nullptr) {};
+    CComBSTR(_In_ int nSize, LPCWSTR sz);
+    ~CComBSTR() throw() {
+      SysFreeString(m_str);
+    }
+
+    operator BSTR() const throw()
+    {
+        return m_str;
+    }
+
+    bool operator==(_In_ const CComBSTR& bstrSrc) const throw();
+
+    BSTR* operator&() throw()
+    {
+        return &m_str;
+    }
+
+    BSTR Detach() throw()
+    {
+        BSTR s = m_str;
+        m_str = NULL;
+        return s;
+    }
+
+};
+
+
 #endif // __cplusplus
 
 #endif // _WIN32
 
+#ifdef __cplusplus
+
+#include <string>
+#include <vector>
+//===--------- Convert argv to wchar ----------------===//
+class WArgV {
+  std::vector<std::wstring> WStringVector;
+  std::vector<const wchar_t *> WCharPtrVector;
+
+public:
+  WArgV(int argc, const char **argv);
+  WArgV(int argc, const wchar_t **argv);
+  const wchar_t **argv() { return WCharPtrVector.data();}
+};
+#endif
+
 #endif // LLVM_SUPPORT_WIN_ADAPTER_H

+ 2 - 2
include/dxc/Support/WinFunctions.h

@@ -15,10 +15,10 @@
 #ifndef LLVM_SUPPORT_WINFUNCTIONS_H
 #define LLVM_SUPPORT_WINFUNCTIONS_H
 
-#ifndef _WIN32
-
 #include "dxc/Support/WinAdapter.h"
 
+#ifndef _WIN32
+
 HRESULT StringCchCopyEx(LPSTR pszDest, size_t cchDest, LPCSTR pszSrc,
                         LPSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags);
 HRESULT StringCchPrintfA(char *dst, size_t dstSize, const char *format, ...);

+ 47 - 2
lib/DxcSupport/WinAdapter.cpp

@@ -7,10 +7,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/WinFunctions.h"
+#include "assert.h"
 #ifndef _WIN32
 
-#include "dxc/Support/WinAdapter.h"
-#include "dxc/Support/WinFunctions.h"
+#include "dxc/Support/Unicode.h"
 
 //===--------------------------- CAllocator -------------------------------===//
 
@@ -75,4 +77,47 @@ CHandle::CHandle(HANDLE h) { m_h = h; }
 CHandle::~CHandle() { CloseHandle(m_h); }
 CHandle::operator HANDLE() const throw() { return m_h; }
 
+// CComBSTR
+CComBSTR::CComBSTR(_In_ int nSize, LPCWSTR sz) {
+  if (nSize < 0) {
+    throw  std::invalid_argument("CComBSTR must have size >= 0");
+  }
+
+  if (nSize == 0) {
+    m_str = NULL;
+  } else {
+    m_str = SysAllocStringLen(sz, nSize);
+    if (!*this) {
+      std::runtime_error("out of memory");
+    }
+  }
+}
+
+bool CComBSTR::operator==(_In_ const CComBSTR &bstrSrc) const throw() {
+  return wcscmp(m_str, bstrSrc.m_str) == 0;
+}
+
 #endif
+
+//===--------------------------- WArgV -------------------------------===//
+WArgV::WArgV(int argc, const char **argv)
+    : WStringVector(argc), WCharPtrVector(argc) {
+  for (int i = 0; i < argc; ++i) {
+    std::string S(argv[i]);
+    const int wideLength = ::MultiByteToWideChar(
+        CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(), nullptr, 0);
+    assert(wideLength > 0 &&
+           "else it should have failed during size calculation");
+    WStringVector[i].resize(wideLength);
+    ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, S.data(), S.size(),
+                          &(WStringVector[i])[0], WStringVector[i].size());
+    WCharPtrVector[i] = WStringVector[i].data();
+  }
+}
+
+WArgV::WArgV(int argc, const wchar_t **argv)
+    : WCharPtrVector(argc) {
+  for (int i = 0; i < argc; ++i) {
+    WCharPtrVector[i] = argv[i];
+  }
+}

+ 1 - 1
tools/clang/test/CMakeLists.txt

@@ -69,7 +69,7 @@ endif()
 
 # HLSL Change Begin
 # Explicitly overriding check-clang dependencies for HLSL
-set(CLANG_TEST_DEPS dxc dxcompiler clang-tblgen llvm-config opt FileCheck count not ClangUnitTests)
+set(CLANG_TEST_DEPS dxc dxa dxopt dxl dxv dxr dxcompiler clang-tblgen llvm-config opt FileCheck count not ClangUnitTests)
 add_custom_target(clang-test-depends DEPENDS ${CLANG_TEST_DEPS})
 set_target_properties(clang-test-depends PROPERTIES FOLDER "Clang tests")
 # HLSL Change End

+ 4 - 0
tools/clang/test/DXC/Inputs/inc2.hlsli

@@ -0,0 +1,4 @@
+int f2(int g)
+{
+  return g*42;
+}

+ 7 - 0
tools/clang/test/DXC/Inputs/include/inc1.hlsli

@@ -0,0 +1,7 @@
+// Verify that we can find an include header in the original directory
+#include "inc2.hlsli"
+
+int f1(int g)
+{
+  return f2(g);
+}

+ 15 - 0
tools/clang/test/DXC/Inputs/lib_res_match.hlsl

@@ -0,0 +1,15 @@
+
+
+// Make sure same cbuffer decalred in different lib works.
+
+cbuffer A {
+  float a;
+  float v;
+}
+
+Texture2D	tex;
+SamplerState	samp;
+
+export float GetV() {
+  return v + tex.Load(uint3(a, v, a)).y;
+}

+ 22 - 0
tools/clang/test/DXC/Inputs/smoke.hlsl

@@ -0,0 +1,22 @@
+// Verify that we can successfully process an include
+#include "include/inc1.hlsli"
+
+int g;
+static int g_unused;
+
+#ifndef semantic
+#define semantic SV_Target
+#endif
+#ifdef DX12
+#define RS "CBV(b0)"
+[RootSignature ( RS )]
+#endif
+
+float4 main() : semantic
+{
+  #ifdef check_warning
+  int x = 3;
+  x;
+  #endif
+  return f1(g);
+}

+ 36 - 0
tools/clang/test/DXC/dxa_tests.test

@@ -0,0 +1,36 @@
+
+// RUN: %dxc %S/Inputs/smoke.hlsl /D "semantic = SV_Position" /T vs_6_0 /Zi /Qembed_debug /DDX12 /Fo %t.dxa.cso
+
+// RUN: %dxa %t.dxa.cso -listfiles | FileCheck %s --check-prefix=FILES
+// FILES:smoke.hlsl
+
+// RUN: %dxa %t.dxa.cso -listparts | FileCheck %s --check-prefix=PARTS
+// PARTS-DAG:DXIL
+// PARTS-DAG:ILDB
+// PARTS-DAG:RTS0
+// PARTS-DAG:PSV0
+// PARTS-DAG:STAT
+// PARTS-DAG:ILDN
+// PARTS-DAG:HASH
+// PARTS-DAG:ISG1
+// PARTS-DAG:OSG1
+
+
+// RUN: %dxa %t.dxa.cso -extractpart dbgmodule -o %t.dxa.cso.dbgmodule
+
+// RUN: %dxa %t.dxa.cso.dbgmodule -listfiles | FileCheck %s --check-prefix=DBG_FILES
+// DBG_FILES:smoke.hlsl
+
+// RUN: %dxa %t.dxa.cso.dbgmodule -extractfile=* | FileCheck %s --check-prefix=EXTRACT_FILE
+// EXTRACT_FILE:float4 main()
+
+
+// RUN: %dxa %t.dxa.cso -extractpart module -o %t.dxa.cso.plain.bc
+// RUN: %dxa %t.dxa.cso.plain.bc -o %t.rebuilt-container.cso
+// RUN: %dxc -dumpbin %t.rebuilt-container.cso | FileCheck %s --check-prefix=REBUILD
+
+// RUN: %dxc -dumpbin %t.dxa.cso -Fc %t.dxa.ll
+// RUN: %dxa %t.dxa.ll -o %t.rebuilt-container2.cso
+// RUN: %dxc -dumpbin %t.rebuilt-container2.cso | FileCheck %s --check-prefix=REBUILD
+
+// REBUILD:define void @main()

+ 19 - 0
tools/clang/test/DXC/dxopt_test.test

@@ -0,0 +1,19 @@
+// Smoke test for dxopt command line
+// RUN: %dxc /Odump  -Tps_6_0 %S/Inputs/smoke.hlsl > %t.opt.passes.txt
+
+// RUN: echo -print-module:test >> %t.opt.passes.txt
+
+// RUN: %dxc -T ps_6_0 %S/Inputs/smoke.hlsl -fcgl -Fc %t.smoke.hl.ll
+// RUN: FileCheck --input-file=%t.smoke.hl.ll %s --check-prefix=HL_LL
+
+// Make sure hl.ll not empty.
+// HL_LL:{{.+}}
+
+// RUN: %dxopt -pf %t.opt.passes.txt -o=%t.smoke.opt.bc %t.smoke.hl.ll | FileCheck %s --check-prefix=OPT_PRN
+
+// OPT_PRN:MODULE-PRINT
+
+// RUN: %dxc -dumpbin %t.smoke.opt.bc | FileCheck %s --check-prefix=OPT_BC
+
+// Make sure OPT_BC not empty.
+// OPT_BC:{{.+}}

+ 5 - 0
tools/clang/test/DXC/dxr_test.test

@@ -0,0 +1,5 @@
+// Basic Rewriter Smoke Test
+// RUN: %dxr -remove-unused-globals %S/Inputs/smoke.hlsl -Emain | FileCheck %s --check-prefix=DXR
+
+// DXR:int f2(int g)
+// DXR-not:g_unused

+ 31 - 0
tools/clang/test/DXC/lib_entry4.hlsl

@@ -0,0 +1,31 @@
+// Smoke test for dxl command line
+// RUN: %dxc /T lib_6_x %s -Fo %t.lib_entry4.dxbc
+// RUN: %dxc /T lib_6_x %S/Inputs/lib_res_match.hlsl -Fo %t.lib_res_match.dxbc
+// RUN: %dxl -T ps_6_0 "%t.lib_entry4.dxbc;%t.lib_res_match.dxbc" -Fo %t.res_match_entry.dxbc
+// RUN: %dxc -dumpbin %t.res_match_entry.dxbc | FileCheck %s
+
+// CHECK:; cbuffer A
+// CHECK-NEXT:; {
+// CHECK-NEXT:;
+// CHECK-NEXT:[8 x i8] (type annotation not present)
+// CHECK-NEXT:;
+// CHECK-NEXT:; }
+
+// Make sure same cbuffer decalred in different lib works.
+
+
+cbuffer A {
+  float a;
+  float v;
+}
+
+Texture2D	tex;
+SamplerState	samp;
+
+float GetV();
+
+[shader("pixel")]
+float4 main() : SV_Target
+{
+   return tex.Sample(samp, float2(a, GetV()));
+}

+ 22 - 0
tools/clang/test/DXC/recompile.test

@@ -0,0 +1,22 @@
+
+// Embed Debug, Recompile
+// RUN: %dxc /T ps_6_0 %S/Inputs/smoke.hlsl /Zi /Qembed_debug /Fo %t.recompile.cso
+// RUN: %dxc -dumpbin %t.recompile.cso | FileCheck %s --check-prefix=RECOMPILE_EMBED_DEBUG
+// RECOMPILE_EMBED_DEBUG:DICompileUnit
+
+// RUN: %dxc /T ps_6_0 %S/Inputs/smoke.hlsl /Zi /Qembed_debug /Fo %t.recompile.cc.cso /Cc /Ni /No /Lx
+// RUN: %dxc -dumpbin %t.recompile.cc.cso | FileCheck %s --check-prefix=RECOMPILE_CC_EMBED_DEBUG
+// RECOMPILE_CC_EMBED_DEBUG:DICompileUnit
+// RUN: %dxc  %t.recompile.cc.cso /recompile
+// RUN: %dxc  %t.recompile.cc.cso /recompile  /T ps_6_0 /E main
+
+// Strip Debug, Recompile PDB
+// RUN: %dxc /T ps_6_0 %S/Inputs/smoke.hlsl /Zi /Fd %t.recompiled.pdb
+// RUN: %dxc -dumpbin %t.recompiled.pdb | FileCheck %s --check-prefix=RECOMPILE_PDB
+// RECOMPILE_PDB:DICompileUnit
+// RUN: %dxc %t.recompiled.pdb  /recompile > %t.recompiled.pdb.ll
+// RUN: %dxc %t.recompiled.pdb /recompile /T ps_6_0 /E main
+
+// Command-line Defines, Recompile
+// RUN: %dxc  %S/Inputs/smoke.hlsl  /D "semantic = SV_Position" /T vs_6_0 /Zi /Qembed_debug /DDX12 /Fo %t.define.cso
+// RUN: %dxc %t.define.cso /recompile

+ 19 - 1
tools/clang/test/lit.cfg

@@ -44,7 +44,7 @@ else:
 config.test_format = lit.formats.ShTest(execute_external)
 
 # suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap', '.hlsl']
+config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap', '.hlsl', '.test']
 
 # excludes: A list of directories to exclude from the testsuite. The 'Inputs'
 # subdirectories contain auxiliary inputs for various tests in their parent
@@ -269,6 +269,24 @@ config.substitutions.append( ('%itanium_abi_triple', makeItaniumABITriple(config
 config.substitutions.append( ('%ms_abi_triple', makeMSABITriple(config.target_triple)) )
 config.substitutions.append( ('%dxc', lit.util.which('dxc', llvm_tools_dir)) )
 
+config.substitutions.append( ('%dxv',
+                            lit.util.which('dxv', llvm_tools_dir)) )
+
+config.substitutions.append( ('%dxa',
+                            lit.util.which('dxa', llvm_tools_dir)) )
+
+config.substitutions.append( ('%dxopt',
+                            lit.util.which('dxopt', llvm_tools_dir)) )
+
+config.substitutions.append( ('%dxr',
+                            lit.util.which('dxr', llvm_tools_dir)) )
+
+config.substitutions.append( ('%listparts',
+                            str(lit.util.which('dxa', llvm_tools_dir)) + ' -listparts ' ))
+
+config.substitutions.append( ('%dxl',
+                            lit.util.which('dxl', llvm_tools_dir)) )
+
 # The host triple might not be set, at least if we're compiling clang from
 # an already installed llvm.
 if config.host_triple and config.host_triple != '@LLVM_HOST_TRIPLE@':

+ 1 - 0
tools/clang/test/lit.site.cfg.in

@@ -20,6 +20,7 @@ config.clang_examples = @ENABLE_CLANG_EXAMPLES@
 config.enable_shared = @ENABLE_SHARED@
 config.enable_backtrace = "@ENABLE_BACKTRACES@"
 config.host_arch = "@HOST_ARCH@"
+config.spirv = "@ENABLE_SPIRV_CODEGEN@" =="ON"
 
 # Support substitution of the tools and libs dirs with user parameters. This is
 # used when we can't determine the tool dir at configuration time.

+ 5 - 5
tools/clang/tools/CMakeLists.txt

@@ -26,16 +26,16 @@ add_llvm_external_project(clang-tools-extra extra)
 add_subdirectory(dxcompiler)
 add_subdirectory(dxclib)
 add_subdirectory(dxc)
-
-# These targets can currently only be built on Windows.
-if (WIN32)
-add_subdirectory(d3dcomp)
-add_subdirectory(dxrfallbackcompiler)
 add_subdirectory(dxa)
 add_subdirectory(dxopt)
 add_subdirectory(dxl)
 add_subdirectory(dxr)
 add_subdirectory(dxv)
+
+# These targets can currently only be built on Windows.
+if (WIN32)
+add_subdirectory(d3dcomp)
+add_subdirectory(dxrfallbackcompiler)
 add_subdirectory(dxlib-sample)
 # UI powered by .NET.
 add_subdirectory(dotnetc)

+ 7 - 4
tools/clang/tools/dxa/dxa.cpp

@@ -24,8 +24,7 @@
 #include "llvm/Support//MSFileSystem.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/raw_ostream.h"
-#include <dia2.h>
-#include <intsafe.h>
+
 
 using namespace llvm;
 using namespace llvm::opt;
@@ -149,7 +148,7 @@ HRESULT DxaContext::FindModule(hlsl::DxilFourCC fourCC, IDxcBlob *pSource, IDxcL
   }
   if (fourCC == pDxilPartHeader->PartFourCC) {
     UINT32 pBlobSize;
-    hlsl::DxilProgramHeader *pDxilProgramHeader = (hlsl::DxilProgramHeader*)(pDxilPartHeader + 1);
+    const hlsl::DxilProgramHeader *pDxilProgramHeader = (const hlsl::DxilProgramHeader *)(pDxilPartHeader + 1);
     hlsl::GetDxilProgramBitcode(pDxilProgramHeader, &pBitcode, &pBlobSize);
     UINT32 offset = (UINT32)(pBitcode - (const char *)pSource->GetBufferPointer());
     pLibrary->CreateBlobFromBlob(pSource, offset, pBlobSize, ppTargetBlob);
@@ -282,7 +281,7 @@ bool DxaContext::ExtractPart(const char *pName) {
 
   WriteBlobToFile(pContent, StringRefWide(OutputFilename),
                   DXC_CP_UTF8); // TODO: Support DefaultTextCodePage
-  printf("%Iu bytes written to %s\n", pContent->GetBufferSize(),
+  printf("%zu bytes written to %s\n", pContent->GetBufferSize(),
          OutputFilename.c_str());
   return true;
 }
@@ -381,7 +380,11 @@ void DxaContext::DumpRDAT() {
 
 using namespace hlsl::options;
 
+#ifdef _WIN32
 int __cdecl main(int argc, _In_reads_z_(argc) char **argv) {
+#else
+int main(int argc, const char **argv) {
+#endif
   if (llvm::sys::fs::SetupPerThreadFileSystem())
     return 1;
   llvm::sys::fs::AutoCleanupPerThreadFileSystem auto_cleanup_fs;

+ 7 - 7
tools/clang/tools/dxclib/dxc.cpp

@@ -651,7 +651,7 @@ public:
 #else
       // Note: try_emplace is only available in C++17 on Linux.
       // try_emplace does nothing if the key already exists in the map.
-      if (includeFiles.find(std::wstring(pFilename)) != includeFiles.end())
+      if (includeFiles.find(std::wstring(pFilename)) == includeFiles.end())
         includeFiles.emplace(std::wstring(pFilename), pBlob);
 #endif // _WIN32
     }
@@ -682,8 +682,7 @@ void DxcContext::Recompile(IDxcBlob *pSource, IDxcLibrary *pLibrary,
                            std::wstring &outputPDBPath,
                            CComPtr<IDxcBlob> &pDebugBlob,
                            IDxcOperationResult **ppCompileResult) {
-// Recompile currently only supported on Windows
-#ifdef _WIN32
+
   CComPtr<IDxcPdbUtils> pPdbUtils;
   IFT(CreateInstance(CLSID_DxcPdbUtils, &pPdbUtils));
   IFT(pPdbUtils->Load(pSource));
@@ -770,11 +769,12 @@ void DxcContext::Recompile(IDxcBlob *pSource, IDxcLibrary *pLibrary,
       NewDefines.size(), pIncludeHandler, &pResult));
   }
 
+#ifndef _WIN32
+  // FIXME: fix crash on linux when not detach pCompileSource.
+  pCompileSource.Detach();
+#endif
+
   *ppCompileResult = pResult.Detach();
-#else
-  assert(false && "Recompile is currently only supported on Windows.");
-  *ppCompileResult = nullptr;
-#endif // _WIN32
 }
 
 int DxcContext::Compile() {

+ 1 - 1
tools/clang/tools/dxcompiler/CMakeLists.txt

@@ -76,11 +76,11 @@ set(SOURCES
   dxcpdbutils.cpp
   dxillib.cpp
   dxcvalidator.cpp
+  dxclinker.cpp
   dxcshadersourceinfo.cpp
 )
 set (HLSL_IGNORE_SOURCES
   dxcdia.cpp
-  dxclinker.cpp
 )
 endif(WIN32)
 

+ 7 - 7
tools/clang/tools/dxcompiler/dxcapi.cpp

@@ -111,19 +111,19 @@ static HRESULT ThreadMallocDxcCreateInstance(
   else if (IsEqualCLSID(rclsid, CLSID_DxcContainerReflection)) {
     hr = CreateDxcContainerReflection(riid, ppv);
   }
-// Note: The following targets are not yet enabled for non-Windows platforms.
-#ifdef _WIN32
+  else if (IsEqualCLSID(rclsid, CLSID_DxcPdbUtils)) {
+    hr = CreateDxcPdbUtils(riid, ppv);
+  }
   else if (IsEqualCLSID(rclsid, CLSID_DxcRewriter)) {
     hr = CreateDxcRewriter(riid, ppv);
   }
-  else if (IsEqualCLSID(rclsid, CLSID_DxcDiaDataSource)) {
-    hr = CreateDxcDiaDataSource(riid, ppv);
-  }
   else if (IsEqualCLSID(rclsid, CLSID_DxcLinker)) {
     hr = CreateDxcLinker(riid, ppv);
   }
-  else if (IsEqualCLSID(rclsid, CLSID_DxcPdbUtils)) {
-    hr = CreateDxcPdbUtils(riid, ppv);
+// Note: The following targets are not yet enabled for non-Windows platforms.
+#ifdef _WIN32
+  else if (IsEqualCLSID(rclsid, CLSID_DxcDiaDataSource)) {
+    hr = CreateDxcDiaDataSource(riid, ppv);
   }
 #endif
   else {

+ 2 - 1
tools/clang/tools/dxcompiler/dxclinker.cpp

@@ -10,6 +10,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/WinFunctions.h"
 #include "dxc/DxilContainer/DxilContainer.h"
 #include "dxc/Support/ErrorCodes.h"
 #include "dxc/Support/Global.h"
@@ -87,7 +88,7 @@ public:
     return S_OK;
   }
 
-  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override {
     return DoBasicQueryInterface<IDxcLinker>(this, riid, ppvObject);
   }
 

+ 31 - 29
tools/clang/tools/dxcompiler/dxcpdbutils.cpp

@@ -10,8 +10,6 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-#ifdef _WIN32
-
 #include "dxc/Support/Global.h"
 #include "dxc/Support/WinIncludes.h"
 #include "dxc/Support/dxcapi.use.h"
@@ -27,7 +25,6 @@
 
 #include "dxc/dxcapi.h"
 #include "dxc/dxcapi.internal.h"
-#include "dxc/dxcpix.h"
 #include "dxc/Support/microcom.h"
 #include "dxc/DxilContainer/DxilContainer.h"
 #include "dxc/DXIL/DxilUtil.h"
@@ -48,7 +45,11 @@
 #include <locale>
 #include <codecvt>
 #include <string>
+
+#ifdef _WIN32
+#include "dxc/dxcpix.h"
 #include <dia2.h>
+#endif
 
 using namespace dxc;
 using namespace llvm;
@@ -94,13 +95,13 @@ public:
     return S_OK;
   }
 
-  virtual HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) {
+  virtual HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) override {
     if (!pFlags) return E_POINTER;
     *pFlags = m_Version.VersionFlags;
     return S_OK;
   }
 
-  virtual HRESULT STDMETHODCALLTYPE GetCommitInfo(_Out_ UINT32 *pCommitCount, _Outptr_result_z_ char **pCommitHash) {
+  virtual HRESULT STDMETHODCALLTYPE GetCommitInfo(_Out_ UINT32 *pCommitCount, _Outptr_result_z_ char **pCommitHash) override {
     if (!pCommitHash)
       return E_POINTER;
 
@@ -110,7 +111,7 @@ public:
     return S_OK;
   }
 
-  virtual HRESULT STDMETHODCALLTYPE GetCustomVersionString(_Outptr_result_z_ char **pVersionString) {
+  virtual HRESULT STDMETHODCALLTYPE GetCustomVersionString(_Outptr_result_z_ char **pVersionString) override {
     if (!pVersionString)
       return E_POINTER;
     IFR(CopyStringToOutStringPtr(m_VersionString, pVersionString));
@@ -143,7 +144,7 @@ public:
   ULONG STDMETHODCALLTYPE Release() override {
     return m_pImpl->Release();
   }
-  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
      return m_pImpl->QueryInterface(iid, ppvObject);
   }
 
@@ -207,7 +208,7 @@ public:
     IFR(m_pImpl->GetEntryPoint(&pBlob));
     return CopyBlobWideToBSTR(pBlob, pResult);
   }
-  virtual HRESULT STDMETHODCALLTYPE GetMainFileName(_Outptr_result_z_ BSTR *pResult) {
+  virtual HRESULT STDMETHODCALLTYPE GetMainFileName(_Outptr_result_z_ BSTR *pResult) override {
     CComPtr<IDxcBlobWide> pBlob;
     IFR(m_pImpl->GetMainFileName(&pBlob));
     return CopyBlobWideToBSTR(pBlob, pResult);
@@ -225,7 +226,7 @@ public:
     return E_NOTIMPL;
   }
 
-  virtual HRESULT STDMETHODCALLTYPE CompileForFullPDB(_COM_Outptr_ IDxcResult **ppResult) {
+  virtual HRESULT STDMETHODCALLTYPE CompileForFullPDB(_COM_Outptr_ IDxcResult **ppResult) override {
     return E_NOTIMPL;
   }
 
@@ -243,7 +244,7 @@ public:
     return CopyBlobWideToBSTR(pBlob, pResult);
   }
 
-  virtual HRESULT STDMETHODCALLTYPE GetVersionInfo(_COM_Outptr_ IDxcVersionInfo **ppVersionInfo) {
+  virtual HRESULT STDMETHODCALLTYPE GetVersionInfo(_COM_Outptr_ IDxcVersionInfo **ppVersionInfo) override {
     return m_pImpl->GetVersionInfo(ppVersionInfo);
   }
 
@@ -252,7 +253,11 @@ public:
   }
 };
 
-struct DxcPdbUtils : public IDxcPdbUtils2, public IDxcPixDxilDebugInfoFactory
+struct DxcPdbUtils : public IDxcPdbUtils2
+#ifdef _WIN32
+  // Skip Pix debug info on linux for dia dependence.
+, public IDxcPixDxilDebugInfoFactory
+#endif
 {
 private:
   // Making the adapter and this interface the same object and share reference counting.
@@ -694,7 +699,7 @@ private:
       case hlsl::DFCC_ShaderDebugName:
       {
         const hlsl::DxilShaderDebugName *name_header = (const hlsl::DxilShaderDebugName *)(part+1);
-        const char *ptr = (char *)(name_header+1);
+        const char *ptr = (const char *)(name_header+1);
         IFR(Utf8ToBlobWide(ptr, &m_Name));
       } break;
 
@@ -794,10 +799,16 @@ public:
   DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
   DXC_MICROCOM_TM_ALLOC(DxcPdbUtils)
 
-  DxcPdbUtils(IMalloc *pMalloc) : m_dwRef(0), m_pMalloc(pMalloc), m_Adapter(this) {}
+  DxcPdbUtils(IMalloc *pMalloc) : m_Adapter(this), m_dwRef(0), m_pMalloc(pMalloc) {}
 
   HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
-    HRESULT hr = DoBasicQueryInterface<IDxcPdbUtils2, IDxcPixDxilDebugInfoFactory>(this, iid, ppvObject);
+#ifdef _WIN32
+    HRESULT hr =
+        DoBasicQueryInterface<IDxcPdbUtils2, IDxcPixDxilDebugInfoFactory>(
+            this, iid, ppvObject);
+#else
+    HRESULT hr = DoBasicQueryInterface<IDxcPdbUtils2>(this, iid, ppvObject);
+#endif
     if (FAILED(hr)) {
       return DoBasicQueryInterface<IDxcPdbUtils>(&m_Adapter, iid, ppvObject);
     }
@@ -933,7 +944,7 @@ public:
   virtual HRESULT STDMETHODCALLTYPE GetEntryPoint(_COM_Outptr_ IDxcBlobWide **ppResult) override {
     return CopyBlobWide(m_EntryPoint, ppResult);
   }
-  virtual HRESULT STDMETHODCALLTYPE GetMainFileName(_COM_Outptr_ IDxcBlobWide **ppResult) {
+  virtual HRESULT STDMETHODCALLTYPE GetMainFileName(_COM_Outptr_ IDxcBlobWide **ppResult) override {
     return CopyBlobWide(m_MainFileName, ppResult);
   }
 
@@ -962,7 +973,7 @@ public:
     return E_FAIL;
   }
 
-  virtual HRESULT STDMETHODCALLTYPE GetWholeDxil(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) {
+  virtual HRESULT STDMETHODCALLTYPE GetWholeDxil(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) override {
     if (!ppResult) return E_POINTER;
     *ppResult = nullptr;
     if (m_WholeDxil)
@@ -974,6 +985,7 @@ public:
     return CopyBlobWide(m_Name, ppResult);
   }
 
+#ifdef _WIN32
   virtual STDMETHODIMP NewDxcPixDxilDebugInfo(
       _COM_Outptr_ IDxcPixDxilDebugInfo **ppDxilDebugInfo) override
   {
@@ -1005,7 +1017,9 @@ public:
     return E_NOTIMPL;
   }
 
-  virtual HRESULT STDMETHODCALLTYPE GetVersionInfo(_COM_Outptr_result_maybenull_ IDxcVersionInfo **ppVersionInfo) {
+#endif
+
+  virtual HRESULT STDMETHODCALLTYPE GetVersionInfo(_COM_Outptr_result_maybenull_ IDxcVersionInfo **ppVersionInfo) override {
     if (!ppVersionInfo)
       return E_POINTER;
 
@@ -1089,15 +1103,3 @@ HRESULT CreateDxcPdbUtils(_In_ REFIID riid, _Out_ LPVOID *ppv) {
   }
   return E_NOINTERFACE;
 }
-
-#else
-
-#include "dxc/Support/WinIncludes.h"
-
-HRESULT CreateDxcPdbUtils(_In_ REFIID riid, _Out_ LPVOID *ppv) {
-  return E_NOTIMPL;
-}
-
-#endif
-
-

+ 1 - 1
tools/clang/tools/dxl/dxl.cpp

@@ -23,7 +23,7 @@ int __cdecl wmain(int argc, const wchar_t **argv_)
     return dxc::main(args.size(), args.data());
 #else
 int main(int argc, const char **argv_) {
-    std::vector<const wchar_t *> args;
+    std::vector<const char *> args;
     for (int i=0;i<argc;i++)
       args.emplace_back(argv_[i]);
     args.emplace_back("-link");

+ 30 - 14
tools/clang/tools/dxopt/dxopt.cpp

@@ -22,8 +22,9 @@
 #include "dxc/Support/HLSLOptions.h"
 #include "dxc/DxilContainer/DxilContainer.h"
 #include "dxc/Support/FileIOHelper.h"
+#include "dxc/Support/WinFunctions.h"
 #include "dxc/Support/microcom.h"
-#include <comdef.h>
+
 #include <iostream>
 #include <limits>
 
@@ -57,30 +58,32 @@ bool isStdIn(LPCWSTR fName) {
 // Arg does not start with '-' or '/' and so assume it is a filename,
 // or next arg equals '-' which is the name of stdin.
 bool isFileInputArg(LPCWSTR arg) {
-  const bool isNonOptionArg = !wcsistarts(arg, L"-") && !wcsistarts(arg, L"/");
+  const bool isNonOptionArg = !wcsistarts(arg, L"-") && wcsrchr(arg, L'/') != arg;
   return isNonOptionArg || isStdIn(arg);
 }
 
 static HRESULT ReadStdin(std::string &input) {
-  HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
-  std::vector<unsigned char> buffer(1024);
-  DWORD numBytesRead = -1;
-  BOOL ok = FALSE;
-
-  // Read all data from stdin.
-  while (ok = ReadFile(hStdIn, buffer.data(), buffer.size(), &numBytesRead, NULL)) {
-    if (numBytesRead == 0)
+  bool emptyLine = false;
+  while (!std::cin.eof()) {
+    std::string line;
+    std::getline(std::cin, line);
+    if (line.empty()) {
+      emptyLine = true;
       break;
-    std::copy(buffer.begin(), buffer.begin() + numBytesRead, std::back_inserter(input));
+    }
+
+    std::copy(line.begin(), line.end(),
+              std::back_inserter(input));
   }
 
   DWORD lastError = GetLastError();
 
   // Make sure we reached finished successfully.
-  if (ok)
+  if (std::cin.eof())
     return S_OK;
   // Or reached the end of a pipe.
-  else if (!ok && numBytesRead == 0 && lastError == ERROR_BROKEN_PIPE)
+  else if (!std::cin.good() && emptyLine &&
+           lastError == ERROR_BROKEN_PIPE)
     return S_OK;
   else
     return HRESULT_FROM_WIN32(lastError);
@@ -106,9 +109,15 @@ static void PrintOptOutput(LPCWSTR pFileName, IDxcBlob *pBlob, IDxcBlobEncoding
   CComPtr<IDxcLibrary> pLibrary;
   CComPtr<IDxcBlobEncoding> pOutputText16;
   IFT(g_DxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+#ifdef _WIN32
   IFT(pLibrary->GetBlobAsWide(pOutputText, &pOutputText16));
   wprintf(L"%*s", (int)pOutputText16->GetBufferSize(),
           (wchar_t *)pOutputText16->GetBufferPointer());
+#else
+  IFT(pLibrary->GetBlobAsUtf8(pOutputText, &pOutputText16));
+  printf("%*s", (int)pOutputText16->GetBufferSize(),
+          (char *)pOutputText16->GetBufferPointer());
+#endif
   if (pBlob && pFileName && *pFileName) {
     dxc::WriteBlobToFile(pBlob, pFileName, DXC_CP_UTF8); // TODO: Support DefaultTextCodePage
   }
@@ -210,7 +219,14 @@ static void PrintHelp() {
   );
 }
 
+#ifdef _WIN32
 int __cdecl wmain(int argc, const wchar_t **argv_) {
+#else
+int main(int argc, const char **argv) {
+  // Convert argv to wchar.
+  WArgV ArgV(argc, argv);
+  const wchar_t **argv_ = ArgV.argv();
+#endif
   const char *pStage = "Operation";
   int retVal = 0;
   if (llvm::sys::fs::SetupPerThreadFileSystem())
@@ -223,7 +239,7 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
     ProgramAction action = ProgramAction::PrintHelp;
     LPCWSTR inFileName = nullptr;
     LPCWSTR outFileName = nullptr;
-    LPCWSTR externalLib = nullptr;
+    LPCWSTR externalLib = nullptr; 
     LPCWSTR externalFn = nullptr;
     LPCWSTR passFileName = nullptr;
     const wchar_t **optArgs = nullptr;

+ 15 - 87
tools/clang/tools/dxr/dxr.cpp

@@ -22,95 +22,21 @@
 #include "dxc/dxctools.h"
 #include "dxc/Support/dxcapi.use.h"
 #include "dxc/Support/HLSLOptions.h"
+#include "dxc/Support/WinFunctions.h"
 #include "llvm/Support/raw_ostream.h"
 
+
 inline bool wcsieq(LPCWSTR a, LPCWSTR b) { return _wcsicmp(a, b) == 0; }
 
 using namespace dxc;
 using namespace llvm::opt;
 using namespace hlsl::options;
 
-
-class FileMapDxcBlobEncoding : public IDxcBlobEncoding {
-private:
-  DXC_MICROCOM_REF_FIELD(m_dwRef)
-  CHandle m_FileHandle;
-  CHandle m_MappingHandle;
-  void* m_MappedView;
-  UINT32 m_FileSize;
-public:
-  DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
-  FileMapDxcBlobEncoding() : m_dwRef(0), m_MappedView(nullptr) {
-  }
-  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
-    return DoBasicQueryInterface<IDxcBlob, IDxcBlobEncoding>(this, iid, ppvObject);
-  }
-
-  ~FileMapDxcBlobEncoding() {
-    if (m_MappedView != nullptr) {
-      UnmapViewOfFile(m_MappedView);
-    }
-  }
-
-  static HRESULT CreateForFile(_In_ LPCWSTR pFileName,
-                               _COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) {
-    *ppBlobEncoding = nullptr;
-
-    CComPtr<FileMapDxcBlobEncoding> pResult = new FileMapDxcBlobEncoding();
-    HRESULT hr = pResult->Open(pFileName);
-    if (FAILED(hr)) {
-      return hr;
-    }
-    return pResult.QueryInterface(ppBlobEncoding);
-  }
-
-  virtual LPVOID STDMETHODCALLTYPE GetBufferPointer(void) override {
-    return m_MappedView;
-  }
-  virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(void) override {
-    return m_FileSize;
-  }
-  virtual HRESULT STDMETHODCALLTYPE GetEncoding(_Out_ BOOL *pKnown, _Out_ UINT32 *pCodePage) {
-    *pKnown = FALSE;
-    *pCodePage = 0;
-    return S_OK;
-  }
-
-  HRESULT Open(_In_ LPCWSTR pFileName) {
-    DXASSERT_NOMSG(m_FileHandle == nullptr);
-
-    HANDLE fileHandle = CreateFileW(pFileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
-    if (fileHandle == INVALID_HANDLE_VALUE) {
-      return HRESULT_FROM_WIN32(GetLastError());
-    }
-    m_FileHandle.Attach(fileHandle);
-
-    HANDLE mappingHandle = CreateFileMapping(fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
-    if (mappingHandle == INVALID_HANDLE_VALUE) {
-      return HRESULT_FROM_WIN32(GetLastError());
-    }
-    m_MappingHandle.Attach(mappingHandle);
-
-    void* fileView = MapViewOfFile(mappingHandle, FILE_MAP_READ, 0, 0, 0);
-    if (fileView == nullptr) {
-      return HRESULT_FROM_WIN32(GetLastError());
-    }
-    m_MappedView = fileView;
-
-    LARGE_INTEGER FileSize;
-    if (!GetFileSizeEx(fileHandle, &FileSize)) {
-      return HRESULT_FROM_WIN32(GetLastError());
-    }
-    if (FileSize.u.HighPart != 0 || FileSize.u.LowPart == UINT_MAX) {
-      return DXC_E_INPUT_FILE_TOO_LARGE;
-    }
-    m_FileSize = FileSize.u.LowPart;
-
-    return S_OK;
-  }
-};
-
+#ifdef _WIN32
 int __cdecl wmain(int argc, const wchar_t **argv_) {
+#else
+int main(int argc, const char **argv_) {
+#endif
   if (FAILED(DxcInitThreadMalloc())) return 1;
   DxcSetThreadMallocToDefault();
   try {
@@ -195,19 +121,21 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
     CComPtr<IDxcOperationResult> pRewriteResult;
     CComPtr<IDxcBlobEncoding> pSource;
     std::wstring wName(CA2W(dxcOpts.InputFile.empty()? "" : dxcOpts.InputFile.data()));
-    if (!dxcOpts.InputFile.empty()) {
-      IFT_Data(FileMapDxcBlobEncoding::CreateForFile(wName.c_str(), &pSource), wName.c_str());
-    }
+    if (!dxcOpts.InputFile.empty())
+      ReadFileIntoBlob(dxcSupport, wName.c_str(), &pSource);
+
     CComPtr<IDxcLibrary> pLibrary;
     CComPtr<IDxcIncludeHandler> pIncludeHandler;
     IFT(dxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
     IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
     IFT(dxcSupport.CreateInstance(CLSID_DxcRewriter, &pRewriter));
-    IFT(pRewriter->RewriteWithOptions(pSource, wName.c_str(),
-                                      argv_, argc,
-                                      nullptr, 0, pIncludeHandler,
-                                      &pRewriteResult));
 
+    // Convert argv to wchar.
+    WArgV ArgV(argc, argv_);
+    IFT(pRewriter->RewriteWithOptions(pSource, wName.c_str(),
+                                      ArgV.argv(), argc, nullptr, 0,
+                                      pIncludeHandler, &pRewriteResult));
+                        
     if (dxcOpts.OutputObject.empty()) {
       // No -Fo, print to console
       WriteOperationResultToConsole(pRewriteResult, !dxcOpts.OutputWarnings);

+ 4 - 0
tools/clang/tools/dxv/dxv.cpp

@@ -125,7 +125,11 @@ void DxvContext::Validate() {
   }
 }
 
+#ifdef _WIN32
 int __cdecl main(int argc,  _In_reads_z_(argc) const char **argv) {
+#else
+int main(int argc, const char **argv) {
+#endif
   const char *pStage = "Operation";
   if (llvm::sys::fs::SetupPerThreadFileSystem())
     return 1;

+ 0 - 1
tools/clang/unittests/HLSL/DXIsenseTest.cpp

@@ -23,7 +23,6 @@
 #ifdef _WIN32
 class DXIntellisenseTest {
 #else
-typedef BSTR CComBSTR;
 class DXIntellisenseTest : public ::testing::Test {
 #endif
 public:

+ 1 - 0
unittests/CMakeLists.txt

@@ -17,6 +17,7 @@ add_subdirectory(AsmParser)
 add_subdirectory(Bitcode)
 # add_subdirectory(CodeGen) - HLSL doesn't codegen...
 # add_subdirectory(DebugInfo) - HLSL doesn't generate dwarf
+add_subdirectory(DxcSupport)
 # add_subdirectory(ExecutionEngine) - HLSL Change - removed
 add_subdirectory(IR)
 # add_subdirectory(LineEditor) - HLSL Change - removed

+ 8 - 0
unittests/DxcSupport/CMakeLists.txt

@@ -0,0 +1,8 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  dxcSupport
+  )
+
+add_clang_unittest(DxcSupportTests
+  WinAdapterTest.cpp
+  )

+ 45 - 0
unittests/DxcSupport/WinAdapterTest.cpp

@@ -0,0 +1,45 @@
+//===- unittests/Basic/WinAdapterTest.cpp -- Windows Adapter tests --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _WIN32
+
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/WinFunctions.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+namespace {
+
+// Check that WArgV.
+TEST(WArgVTest, suppressAndTrap) {
+  int argc=2;
+  std::wstring data [] = {L"a", L"b"};
+  const wchar_t *ref_argv[] = {data[0].c_str(), data[1].c_str()};
+  {
+    WArgV ArgV(argc, ref_argv);
+    const wchar_t **wargv = ArgV.argv();
+    for (int i=0;i<argc;++i) {
+      EXPECT_EQ(0, std::wcscmp(ref_argv[i], wargv[i]));
+    }
+  }
+  {
+    int argc=2;
+    const char *argv [] = {"a", "b"};
+
+    WArgV ArgV(argc, argv);
+    const wchar_t **wargv = ArgV.argv();
+    for (int i=0;i<argc;++i) {
+      EXPECT_EQ(0, std::wcscmp(ref_argv[i], wargv[i]));
+    }
+  }
+}
+
+}
+#endif