summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.cmd14
-rw-r--r--crossgen.cmake20
-rw-r--r--src/binder/CMakeLists.txt11
-rw-r--r--src/binder/v3binder/CMakeLists.txt4
-rw-r--r--src/binder/v3binder_crossgen/CMakeLists.txt6
-rw-r--r--src/gcinfo/CMakeLists.txt10
-rw-r--r--src/gcinfo/crossgen/CMakeLists.txt6
-rw-r--r--src/gcinfo/lib/.gitmirror1
-rw-r--r--src/gcinfo/lib/CMakeLists.txt4
-rw-r--r--src/gcinfo/lib/GCInfo.nativeproj15
-rw-r--r--src/jit/CMakeLists.txt41
-rw-r--r--src/jit/crossgen/.gitmirror1
-rw-r--r--src/jit/crossgen/CMakeLists.txt3
-rw-r--r--src/jit/crossgen/jit_crossgen.nativeproj20
-rw-r--r--src/jit/dll/.gitmirror1
-rw-r--r--src/jit/dll/CMakeLists.txt33
-rw-r--r--src/jit/dll/altjit.def8
-rw-r--r--src/jit/dll/clrjit.def8
-rw-r--r--src/jit/dll/jit.nativeproj93
-rw-r--r--src/md/compiler/CMakeLists.txt3
-rw-r--r--src/md/compiler/crossgen/CMakeLists.txt5
-rw-r--r--src/md/enc/CMakeLists.txt3
-rw-r--r--src/md/enc/crossgen/CMakeLists.txt5
-rw-r--r--src/md/hotdata/CMakeLists.txt3
-rw-r--r--src/md/hotdata/crossgen/CMakeLists.txt5
-rw-r--r--src/md/runtime/CMakeLists.txt3
-rw-r--r--src/md/runtime/crossgen/CMakeLists.txt5
-rw-r--r--src/md/winmd/CMakeLists.txt3
-rw-r--r--src/md/winmd/crossgen/CMakeLists.txt5
-rw-r--r--src/strongname/api/CMakeLists.txt5
-rw-r--r--src/strongname/api/crossgen/CMakeLists.txt3
-rw-r--r--src/tools/CMakeLists.txt1
-rw-r--r--src/tools/crossgen/CMakeLists.txt67
-rw-r--r--src/tools/crossgen/crossgen.cpp15
-rw-r--r--src/tools/util/.gitmirror1
-rw-r--r--src/tools/util/consoleargs.cpp939
-rw-r--r--src/tools/util/consoleargs.h71
-rw-r--r--src/tools/util/file_can.h70
-rw-r--r--src/tools/util/list.h26
-rw-r--r--src/tools/util/tree.h243
-rw-r--r--src/utilcode/CMakeLists.txt3
-rw-r--r--src/utilcode/crossgen/CMakeLists.txt8
-rw-r--r--src/vm/compile.cpp23
-rw-r--r--src/vm/crossgen/CMakeLists.txt124
-rw-r--r--src/vm/crossgen_mscorlib/CMakeLists.txt15
-rw-r--r--src/zap/crossgen/CMakeLists.txt21
46 files changed, 1921 insertions, 53 deletions
diff --git a/build.cmd b/build.cmd
index a50cbddb8b..8f8393cb5c 100644
--- a/build.cmd
+++ b/build.cmd
@@ -164,12 +164,24 @@ set "__MScorlibBuildLog=%__LogsDir%\MScorlib_%__BuildOS%__%__BuildArch%__%__Buil
%_msbuildexe% "%__ProjectFilesDir%\build.proj" %__MSBCleanBuildArgs% /nologo /maxcpucount /verbosity:minimal /nodeReuse:false /fileloggerparameters:Verbosity=diag;LogFile="%__MScorlibBuildLog%" /p:OS=%__BuildOS% %__AdditionalMSBuildArgs%
IF NOT ERRORLEVEL 1 (
if defined __MscorlibOnly goto :eof
- goto PerformTestBuild
+ goto CrossGenMscorlib
)
echo MScorlib build failed. Refer !__MScorlibBuildLog! for details.
goto :eof
+:CrossGenMscorlib
+echo Generating native image of mscorlib for %__BuildOS%.%__BuildArch%.%__BuildType%
+echo.
+set "__CrossGenMScorlibLog=%__LogsDir%\CrossgenMScorlib_%__BuildOS%__%__BuildArch%__%__BuildType%.log"
+%__BinDir%\crossgen.exe %__BinDir%\mscorlib.dll > "%__CrossGenMScorlibLog%" 2>&1
+IF NOT ERRORLEVEL 1 (
+ goto PerformTestBuild
+)
+
+echo CrossGen mscorlib failed. Refer !__CrossGenMScorlibLog! for details.
+goto :eof
+
:PerformTestBuild
echo.
echo Commencing build of tests for %__BuildOS%.%__BuildArch%.%__BuildType%
diff --git a/crossgen.cmake b/crossgen.cmake
new file mode 100644
index 0000000000..f8bdbd0567
--- /dev/null
+++ b/crossgen.cmake
@@ -0,0 +1,20 @@
+# Contains the crossgen build specific definitions. Included by the leaf crossgen cmake files.
+
+add_definitions(
+ -DCROSSGEN_COMPILE
+ -DCROSS_COMPILE
+ -DFEATURE_NATIVE_IMAGE_GENERATION
+ -DSELF_NO_HOST)
+
+remove_definitions(
+ -DEnC_SUPPORTED
+ -DFEATURE_EVENT_TRACE=1
+ -DFEATURE_LOADER_OPTIMIZATION
+ -DFEATURE_MULTICOREJIT
+ -DFEATURE_RANDOMIZED_STRING_HASHING
+ -DFEATURE_VERSIONING_LOG
+)
+
+if(WIN32)
+ add_definitions(-MT)
+endif(WIN32)
diff --git a/src/binder/CMakeLists.txt b/src/binder/CMakeLists.txt
index 12a61ac0d0..7641e02e63 100644
--- a/src/binder/CMakeLists.txt
+++ b/src/binder/CMakeLists.txt
@@ -28,11 +28,14 @@ set(BINDER_SOURCES
fusionhelpers.cpp
)
+convert_to_absolute_path(BINDER_SOURCES ${BINDER_SOURCES})
+
if(CLR_CMAKE_PLATFORM_UNIX)
add_compile_options(-fPIC)
endif(CLR_CMAKE_PLATFORM_UNIX)
-add_library(v3binder
- STATIC
- ${BINDER_SOURCES}
-)
+add_subdirectory(v3binder)
+if(WIN32)
+ add_subdirectory(v3binder_crossgen)
+endif()
+
diff --git a/src/binder/v3binder/CMakeLists.txt b/src/binder/v3binder/CMakeLists.txt
new file mode 100644
index 0000000000..6af80fcf9a
--- /dev/null
+++ b/src/binder/v3binder/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(v3binder
+ STATIC
+ ${BINDER_SOURCES}
+)
diff --git a/src/binder/v3binder_crossgen/CMakeLists.txt b/src/binder/v3binder_crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..811d2db834
--- /dev/null
+++ b/src/binder/v3binder_crossgen/CMakeLists.txt
@@ -0,0 +1,6 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+add_library(v3binder_crossgen
+ STATIC
+ ${BINDER_SOURCES}
+)
diff --git a/src/gcinfo/CMakeLists.txt b/src/gcinfo/CMakeLists.txt
index 528b9223ba..2764b68cf5 100644
--- a/src/gcinfo/CMakeLists.txt
+++ b/src/gcinfo/CMakeLists.txt
@@ -6,11 +6,13 @@ set( GCINFO_SOURCES
dbggcinfoencoder.cpp
)
+convert_to_absolute_path(GCINFO_SOURCES ${GCINFO_SOURCES})
+
if(CLR_CMAKE_PLATFORM_UNIX)
add_compile_options(-fPIC)
endif(CLR_CMAKE_PLATFORM_UNIX)
-add_library(gcinfo
- STATIC
- ${GCINFO_SOURCES}
-)
+add_subdirectory(lib)
+if(WIN32)
+ add_subdirectory(crossgen)
+endif()
diff --git a/src/gcinfo/crossgen/CMakeLists.txt b/src/gcinfo/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..ac04eaadf0
--- /dev/null
+++ b/src/gcinfo/crossgen/CMakeLists.txt
@@ -0,0 +1,6 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+add_library(gcinfo_crossgen
+ STATIC
+ ${GCINFO_SOURCES}
+)
diff --git a/src/gcinfo/lib/.gitmirror b/src/gcinfo/lib/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/gcinfo/lib/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/gcinfo/lib/CMakeLists.txt b/src/gcinfo/lib/CMakeLists.txt
new file mode 100644
index 0000000000..7e426ea3b6
--- /dev/null
+++ b/src/gcinfo/lib/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(gcinfo
+ STATIC
+ ${GCINFO_SOURCES}
+)
diff --git a/src/gcinfo/lib/GCInfo.nativeproj b/src/gcinfo/lib/GCInfo.nativeproj
new file mode 100644
index 0000000000..cc27db5e91
--- /dev/null
+++ b/src/gcinfo/lib/GCInfo.nativeproj
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <SccProjectName>SAK</SccProjectName>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccProvider>SAK</SccProvider>
+ </PropertyGroup>
+ <PropertyGroup>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>GCInfo</OutputName>
+ </PropertyGroup>
+ <Import Project="..\gcinfo.settings.targets" />
+</Project>
diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt
index 3848fa7a61..d5f26233cc 100644
--- a/src/jit/CMakeLists.txt
+++ b/src/jit/CMakeLists.txt
@@ -1,5 +1,3 @@
-project(ClrJit)
-
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories("./jitstd")
@@ -64,9 +62,11 @@ set( SOURCES
unwindamd64.cpp
)
+convert_to_absolute_path(SOURCES ${SOURCES})
+
if( WIN32 )
- add_precompiled_header(jitpch.h jitpch.cpp SOURCES)
+ add_precompiled_header(jitpch.h ../jitpch.cpp SOURCES)
# Create .def file containing a list of exports preceeded by
# 'EXPORTS'. The file "ClrJit.exports" already contains the list, so we
@@ -89,34 +89,7 @@ endif()
set(CLR_EXPORTED_SYMBOL_FILE ${CLRJIT_EXPORTS_DEF})
-# Disable the following for UNIX altjit on Windows
-if(CLR_CMAKE_PLATFORM_UNIX)
- add_compile_options(-Wno-trigraphs)
- add_compile_options(-fPIC)
- add_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE)
-
- add_library(ClrJit
- STATIC
- ${SHARED_LIB_SOURCES}
- )
- add_dependencies(ClrJit coreclrpal gcinfo)
-else()
- add_library(ClrJit
- ${SOURCES}
- )
-# Disable up to here (see above) the following for UNIX altjit on Windows
-# Enable the following for UNIX altjit on Windows
-# add_library(ClrJit
-# SHARED
-# ${SHARED_LIB_SOURCES}
-# )
-
-# Enable the following for UNIX altjit on Windows
-#target_link_libraries(ClrJit
-# utilcode
-# gcinfo
-# runtime_library
-# )
-
-# Disable the following for UNIX altjit on Windows
-endif(CLR_CMAKE_PLATFORM_UNIX)
+add_subdirectory(dll)
+if(WIN32)
+ add_subdirectory(crossgen)
+endif()
diff --git a/src/jit/crossgen/.gitmirror b/src/jit/crossgen/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/jit/crossgen/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/jit/crossgen/CMakeLists.txt b/src/jit/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..8b9c3a3690
--- /dev/null
+++ b/src/jit/crossgen/CMakeLists.txt
@@ -0,0 +1,3 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+add_library(jit_crossgen ${SOURCES})
diff --git a/src/jit/crossgen/jit_crossgen.nativeproj b/src/jit/crossgen/jit_crossgen.nativeproj
new file mode 100644
index 0000000000..f8552dc2f5
--- /dev/null
+++ b/src/jit/crossgen/jit_crossgen.nativeproj
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>jit_crossgen</OutputName>
+ <FeatureMergeJitAndEngine>true</FeatureMergeJitAndEngine>
+ <TargetType>LIBRARY</TargetType>
+
+ <ClDefines Condition="'$(BuildArchitecture)' == 'i386'">$(ClDefines);LEGACY_BACKEND</ClDefines>
+ <ClDefines Condition="'$(BuildArchitecture)' == 'arm'">$(ClDefines);LEGACY_BACKEND</ClDefines>
+ </PropertyGroup>
+
+ <Import Project="..\jit.settings.targets" />
+
+</Project>
diff --git a/src/jit/dll/.gitmirror b/src/jit/dll/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/jit/dll/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/jit/dll/CMakeLists.txt b/src/jit/dll/CMakeLists.txt
new file mode 100644
index 0000000000..4c056da191
--- /dev/null
+++ b/src/jit/dll/CMakeLists.txt
@@ -0,0 +1,33 @@
+project(ClrJit)
+
+# Disable the following for UNIX altjit on Windows
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-Wno-trigraphs)
+ add_compile_options(-fPIC)
+ add_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE)
+
+ add_library(ClrJit
+ STATIC
+ ${SHARED_LIB_SOURCES}
+ )
+ add_dependencies(ClrJit coreclrpal gcinfo)
+else()
+ add_library(ClrJit
+ ${SOURCES}
+ )
+# Disable up to here (see above) the following for UNIX altjit on Windows
+# Enable the following for UNIX altjit on Windows
+# add_library(ClrJit
+# SHARED
+# ${SHARED_LIB_SOURCES}
+# )
+
+# Enable the following for UNIX altjit on Windows
+#target_link_libraries(ClrJit
+# utilcode
+# gcinfo
+# runtime_library
+# )
+
+# Disable the following for UNIX altjit on Windows
+endif(CLR_CMAKE_PLATFORM_UNIX)
diff --git a/src/jit/dll/altjit.def b/src/jit/dll/altjit.def
new file mode 100644
index 0000000000..ec1a3c7a75
--- /dev/null
+++ b/src/jit/dll/altjit.def
@@ -0,0 +1,8 @@
+; ==++==
+;
+; Copyright (c) Microsoft Corporation. All rights reserved.
+;
+; ==--==
+EXPORTS
+ getJit
+ sxsJitStartup \ No newline at end of file
diff --git a/src/jit/dll/clrjit.def b/src/jit/dll/clrjit.def
new file mode 100644
index 0000000000..ec1a3c7a75
--- /dev/null
+++ b/src/jit/dll/clrjit.def
@@ -0,0 +1,8 @@
+; ==++==
+;
+; Copyright (c) Microsoft Corporation. All rights reserved.
+;
+; ==--==
+EXPORTS
+ getJit
+ sxsJitStartup \ No newline at end of file
diff --git a/src/jit/dll/jit.nativeproj b/src/jit/dll/jit.nativeproj
new file mode 100644
index 0000000000..011db75005
--- /dev/null
+++ b/src/jit/dll/jit.nativeproj
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+
+ <!-- Import the CLR's settings -->
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup Label="Globals">
+ <SccProjectName>SAK</SccProjectName>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccProvider>SAK</SccProvider>
+ </PropertyGroup>
+
+ <PropertyGroup>
+
+ <!-- Set the output -->
+
+ <OutputName>clrjit</OutputName>
+ <TargetType Condition="'$(FeatureMergeJitAndEngine)'=='true'">LIBRARY</TargetType>
+ <TargetType Condition="'$(FeatureMergeJitAndEngine)'!='true'">DYNLINK</TargetType>
+ <FileToMarkForSigning>$(BinariesDirectory)\clrjit.dll</FileToMarkForSigning>
+ <StaticLinkJit>false</StaticLinkJit>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+
+ <DllEntryPoint>_DllMainCRTStartup</DllEntryPoint>
+ <LinkSubsystem>windows</LinkSubsystem>
+ <LibCLib Condition="'$(StaticLinkJit)'!='true'">$(ClrCrtLib)</LibCLib>
+
+ <LinkModuleDefinitionFile>$(OutputName).def</LinkModuleDefinitionFile>
+
+ <ClDefines Condition="'$(BuildArchitecture)' == 'i386'">$(ClDefines);LEGACY_BACKEND</ClDefines>
+ <ClDefines Condition="'$(BuildArchitecture)' == 'arm'">$(ClDefines);LEGACY_BACKEND</ClDefines>
+ <ClDefines Condition="'$(BuildArchitecture)' == 'amd64'">$(ClDefines);FEATURE_SIMD;FEATURE_AVX_SUPPORT</ClDefines>
+
+ <Win32DllLibs>$(SdkLibPath)\kernel32.lib;$(SdkLibPath)\user32.lib;$(SdkLibPath)\advapi32.lib;$(SdkLibPath)\oleaut32.lib;$(SdkLibPath)\uuid.lib</Win32DllLibs>
+ <Win32DllLibs>$(Win32DllLibs);$(ClrLibPath)\utilcode.lib</Win32DllLibs>
+
+ <!-- Profile-guided optimization -->
+
+ <PogoOptimize Condition="('$(BuildArchitecture)' == 'arm')">false</PogoOptimize>
+ <PogoInstrument Condition="('$(BuildArchitecture)' == 'arm') and ('$(_BuildType)' == 'ret') and ('$(BuildProjectName)' == '')">true</PogoInstrument>
+ <PogoUpdate Condition="('$(BuildArchitecture)' == 'arm') and ('$(_BuildType)' == 'ret') and ('$(BuildProjectName)' == '')">true</PogoUpdate>
+ <Win32DllLibs Condition="'$(PogoInstrument)' == 'true' and '$(BuildArchitecture)' == 'amd64'">$(Win32DllLibs);$(CrtLibPath)\pgort.lib</Win32DllLibs>
+ <Win32DllLibs Condition="'$(PogoInstrument)' == 'true' and '$(BuildArchitecture)' == 'arm'">$(Win32DllLibs);$(CrtLibPath)\pgort.lib;$(SdkLibPath)\ntdll.lib</Win32DllLibs>
+ <OptimizationDataRelativeDir>$(_BuildArch)\CLR\Base</OptimizationDataRelativeDir>
+
+ <!-- Do we want to build with msvcdis disassembly capability? This should be enabled for DEBUG, disabled otherwise.
+ However, it can be useful for debugging purposes, such as generating assembly diffs between CHK and RET JITs,
+ to enable it temporarily in non-DEBUG builds, by forcing the EnableLateDisasm property to 'true'.
+ -->
+ <EnableLateDisasm Condition="'$(DebugBuild)' == 'true' and '$(BuildArchitecture)' != 'arm' and '$(BuildProjectName)' != 'CoreSys'">true</EnableLateDisasm>
+ <!--
+ <EnableLateDisasm Condition="'$(BuildArchitecture)' != 'arm' and '$(BuildProjectName)' != 'CoreSys'">true</EnableLateDisasm>
+ -->
+ <ClDefines Condition="'$(EnableLateDisasm)' == 'true'">$(ClDefines);LATE_DISASM=1</ClDefines>
+ <LinkDelayLoad Condition="'$(EnableLateDisasm)' == 'true'">$(LinkDelayLoad);msvcdis$(VC_NONCRT_ProdVerX).dll</LinkDelayLoad>
+ <UseDelayimpLib Condition="'$(EnableLateDisasm)' == 'true' and '$(FeatureMergeJitAndEngine)'!='true'">true</UseDelayimpLib>
+
+ <!-- For debugging purposes only, temporarily enable these in RET builds so GenTree debugging is easier. -->
+ <!--
+ <ClDefines>$(ClDefines);DEBUGGABLE_GENTREE=1</ClDefines>
+ <ClAdditionalOptions Condition="'$(DebugBuild)' != 'true'">$(ClAdditionalOptions) /Ob0</ClAdditionalOptions>
+ <LinkAdditionalOptions Condition="'$(DebugBuild)' != 'true'">$(LinkAdditionalOptions) /OPT:NOICF</LinkAdditionalOptions>
+ -->
+
+ <!-- Disable merge of text and rdata for DevDiv:696146-->
+ <LinkMergeRData Condition="'$(BuildArchitecture)'=='i386'">false</LinkMergeRData>
+ </PropertyGroup>
+
+ <!-- Leaf Project Items -->
+
+ <ItemGroup>
+ <ProjectReference Include="$(ClrSrcDirectory)utilcode\dyncrt\dyncrt.nativeproj" />
+ <TargetLib Include="$(SdkLibPath)\mscoree.lib" />
+ <TargetLib Condition="'$(BuildArchitecture)'!='i386'" Include="$(ClrLibPath)\gcinfo.lib">
+ <ProjectReference>$(ClrSrcDirectory)gcinfo\lib\gcinfo.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Condition="'$(UseDelayimpLib)' == 'true'" Include="$(ClrLibPath)\delayimp.lib">
+ <ProjectReference>$(ClrSrcDirectory)delayimp\delayimp.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Condition="'$(DebugBuild)' == 'true'" Include="$(ClrLibPath)\gcdump.lib">
+ <ProjectReference>$(ClrSrcDirectory)gcdump\lib\gcdump.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Condition="'$(DebugBuild)' == 'true'" Include="$(SdkLibPath)\ole32.lib" />
+ <TargetLib Condition="'$(EnableLateDisasm)' == 'true'" Include="$(VCToolsLibPath)\msvcdis.lib" />
+ <RCResourceFile Include="..\native.rc" />
+ </ItemGroup>
+
+ <Import Project="..\jit.settings.targets" />
+
+</Project>
diff --git a/src/md/compiler/CMakeLists.txt b/src/md/compiler/CMakeLists.txt
index c2d84f3766..130a8d2d64 100644
--- a/src/md/compiler/CMakeLists.txt
+++ b/src/md/compiler/CMakeLists.txt
@@ -31,3 +31,6 @@ endif(CLR_CMAKE_PLATFORM_UNIX)
add_subdirectory(dac)
add_subdirectory(wks)
add_subdirectory(dbi)
+if(WIN32)
+ add_subdirectory(crossgen)
+endif(WIN32)
diff --git a/src/md/compiler/crossgen/CMakeLists.txt b/src/md/compiler/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..8a23065335
--- /dev/null
+++ b/src/md/compiler/crossgen/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(${CLR_DIR}/crossgen.cmake)
+include(../../md_wks.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDCOMPILER_SOURCES)
+add_library(mdcompiler_crossgen ${MDCOMPILER_SOURCES})
diff --git a/src/md/enc/CMakeLists.txt b/src/md/enc/CMakeLists.txt
index 5eda2db690..8ba256ba30 100644
--- a/src/md/enc/CMakeLists.txt
+++ b/src/md/enc/CMakeLists.txt
@@ -21,3 +21,6 @@ endif(CLR_CMAKE_PLATFORM_UNIX)
add_subdirectory(dac)
add_subdirectory(wks)
add_subdirectory(dbi)
+if(WIN32)
+ add_subdirectory(crossgen)
+endif(WIN32)
diff --git a/src/md/enc/crossgen/CMakeLists.txt b/src/md/enc/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..d619c5c3f7
--- /dev/null
+++ b/src/md/enc/crossgen/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(${CLR_DIR}/crossgen.cmake)
+include(../../md_wks.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDRUNTIMERW_SOURCES)
+add_library(mdruntimerw_crossgen ${MDRUNTIMERW_SOURCES})
diff --git a/src/md/hotdata/CMakeLists.txt b/src/md/hotdata/CMakeLists.txt
index 8ce023f575..246dc63985 100644
--- a/src/md/hotdata/CMakeLists.txt
+++ b/src/md/hotdata/CMakeLists.txt
@@ -17,4 +17,5 @@ add_subdirectory(dac)
add_subdirectory(full)
if(WIN32)
add_subdirectory(full-staticcrt)
-endif(WIN32) \ No newline at end of file
+ add_subdirectory(crossgen)
+endif(WIN32)
diff --git a/src/md/hotdata/crossgen/CMakeLists.txt b/src/md/hotdata/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..323edc91e2
--- /dev/null
+++ b/src/md/hotdata/crossgen/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(${CLR_DIR}/crossgen.cmake)
+include(../../md_wks.cmake)
+
+add_precompiled_header(external.h ../external.cpp MDHOTDATA_SOURCES)
+add_library(mdhotdata_crossgen ${MDHOTDATA_SOURCES})
diff --git a/src/md/runtime/CMakeLists.txt b/src/md/runtime/CMakeLists.txt
index ed938707ef..eb25640f36 100644
--- a/src/md/runtime/CMakeLists.txt
+++ b/src/md/runtime/CMakeLists.txt
@@ -20,3 +20,6 @@ endif(CLR_CMAKE_PLATFORM_UNIX)
add_subdirectory(dac)
add_subdirectory(wks)
add_subdirectory(dbi)
+if(WIN32)
+ add_subdirectory(crossgen)
+endif(WIN32)
diff --git a/src/md/runtime/crossgen/CMakeLists.txt b/src/md/runtime/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..8ec8e7e4a8
--- /dev/null
+++ b/src/md/runtime/crossgen/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(${CLR_DIR}/crossgen.cmake)
+include(../../md_wks.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDRUNTIME_SOURCES)
+add_library(mdruntime_crossgen ${MDRUNTIME_SOURCES})
diff --git a/src/md/winmd/CMakeLists.txt b/src/md/winmd/CMakeLists.txt
index d517df0715..540f1e1db7 100644
--- a/src/md/winmd/CMakeLists.txt
+++ b/src/md/winmd/CMakeLists.txt
@@ -16,4 +16,5 @@ add_subdirectory(dac)
add_subdirectory(wks)
if(WIN32)
add_subdirectory(dbi)
-endif(WIN32) \ No newline at end of file
+ add_subdirectory(crossgen)
+endif(WIN32)
diff --git a/src/md/winmd/crossgen/CMakeLists.txt b/src/md/winmd/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..fdf5040757
--- /dev/null
+++ b/src/md/winmd/crossgen/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(${CLR_DIR}/crossgen.cmake)
+include(../../md_wks.cmake)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp MDWINMD_SOURCES)
+add_library(mdwinmd_crossgen ${MDWINMD_SOURCES})
diff --git a/src/strongname/api/CMakeLists.txt b/src/strongname/api/CMakeLists.txt
index 1eeed75267..9b1a49025e 100644
--- a/src/strongname/api/CMakeLists.txt
+++ b/src/strongname/api/CMakeLists.txt
@@ -23,4 +23,7 @@ if(CLR_CMAKE_PLATFORM_UNIX)
endif(CLR_CMAKE_PLATFORM_UNIX)
add_subdirectory(dac)
-add_subdirectory(wks) \ No newline at end of file
+add_subdirectory(wks)
+if(WIN32)
+ add_subdirectory(crossgen)
+endif(WIN32)
diff --git a/src/strongname/api/crossgen/CMakeLists.txt b/src/strongname/api/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..4436ed1689
--- /dev/null
+++ b/src/strongname/api/crossgen/CMakeLists.txt
@@ -0,0 +1,3 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+add_library(strongname_crossgen ${STRONGNAME_SOURCES})
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index d8f881a92e..d23b7e0b82 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -1,2 +1,3 @@
+add_subdirectory(crossgen)
add_subdirectory(GenClrDebugResource)
add_subdirectory(InjectResource) \ No newline at end of file
diff --git a/src/tools/crossgen/CMakeLists.txt b/src/tools/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..e7e2b65086
--- /dev/null
+++ b/src/tools/crossgen/CMakeLists.txt
@@ -0,0 +1,67 @@
+project(crossgen)
+
+include(${CLR_DIR}/crossgen.cmake)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+include_directories(../util)
+include_directories(../../pal/prebuilt/corerror)
+
+set(crossgen_SOURCES crossgen.cpp ../util/consoleargs.cpp)
+set(crossgen_RESOURCES Native.rc)
+
+add_definitions(-DFX_VER_INTERNALNAME_STR=crossgen.exe)
+add_definitions(-DNO_NGENPDB)
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ # This does not compile on Linux yet
+ if(CAN_BE_COMPILED_ON_LINUX)
+ add_executable(crossgen
+ ${crossgen_SOURCES}
+ ${crossgen_RESOURCES}
+ )
+ endif(CAN_BE_COMPILED_ON_LINUX)
+
+else()
+ add_executable(crossgen
+ ${crossgen_SOURCES}
+ ${crossgen_RESOURCES}
+ )
+
+ target_link_libraries(crossgen
+ advapi32
+ ole32
+ oleaut32
+ uuid
+ user32
+ version
+ shlwapi
+ bcrypt
+ corguids
+ utilcode_crossgen
+ corzap_crossgen
+ jit_crossgen
+ gcinfo_crossgen
+ strongname_crossgen
+ mdcompiler_crossgen
+ mdwinmd_crossgen
+ mdruntimerw_crossgen
+ mdhotdata_crossgen
+ mdruntime_crossgen
+ cee_crossgen
+ mscorlib_crossgen
+ v3binder_crossgen
+ ${STATIC_MT_CRT_LIB}
+ )
+
+ # Can't compile on linux yet so only add for windows
+ # add the install targets
+ install (TARGETS crossgen DESTINATION .)
+
+ # We will generate PDB only for the debug configuration
+ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/crossgen.pdb DESTINATION PDB)
+
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_subdirectory(../../zap/crossgen ../../zap/crossgen)
+add_subdirectory(../../vm/crossgen ../../vm/crossgen)
+add_subdirectory(../../vm/crossgen_mscorlib ../../vm/crossgen_mscorlib)
diff --git a/src/tools/crossgen/crossgen.cpp b/src/tools/crossgen/crossgen.cpp
index d1bbba80af..db663f0c81 100644
--- a/src/tools/crossgen/crossgen.cpp
+++ b/src/tools/crossgen/crossgen.cpp
@@ -3,11 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-// ==++==
-//
-
-//
-// ==--==
//
// TO DO: we currently use raw printf() for output. Maybe we need to pick up something like ngen's Output() handling
// to handle multiple code pages, etc, better.
@@ -143,9 +138,11 @@ void PrintUsageHelper()
W(" /Platform_Resource_Roots <path[;path]>\n")
W(" - List of paths containing localized assembly directories\n")
W(" /App_Paths <path> - List of paths containing user-application assemblies and resources\n")
+#ifndef NO_NGENPDB
W(" /App_Ni_Paths <path[;path]>\n")
W(" - List of paths containing user-application native images\n")
W(" - Must be used with /CreatePDB switch\n")
+#endif // NO_NGENPDB
#endif // FEATURE_CORECLR
W(" /Platform_Assemblies_Paths\n")
@@ -192,10 +189,12 @@ void PrintUsageHelper()
#ifdef FEATURE_CORECLR
W(" Size on Disk Parameters\n")
W(" /NoMetaData - Do not copy metadata and IL into native image.\n")
+#ifndef NO_NGENPDB
W(" Debugging Parameters\n")
W(" /CreatePDB <Dir to store PDB> [/lines [<search path for managed PDB>] ]\n")
W(" When specifying /CreatePDB, the native image should be created\n")
W(" first, and <assembly name> should be the path to the NI.")
+#endif // NO_NGENPDB
#endif // FEATURE_CORECLR
);
}
@@ -636,6 +635,7 @@ int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
argv++;
argc--;
}
+#ifndef NO_NGENPDB
else if (MatchParameter(*argv, W("App_Ni_Paths")) && (argc > 1))
{
pwzAppNiPaths = argv[1];
@@ -644,6 +644,7 @@ int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
argv++;
argc--;
}
+#endif // NO_NGENPDB
#endif // FEATURE_CORECLR
else if (MatchParameter(*argv, W("Platform_Assemblies_Paths")) && (argc > 1))
{
@@ -663,7 +664,7 @@ int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
argc--;
}
#endif // FEATURE_COMINTEROP
-#ifdef FEATURE_CORECLR
+#if defined(FEATURE_CORECLR) && !defined(NO_NGENPDB)
else if (MatchParameter(*argv, W("CreatePDB")) && (argc > 1))
{
// syntax: /CreatePDB <directory to store PDB> [/lines [<search path for managed PDB>] ]
@@ -735,7 +736,7 @@ int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
argv--;
argc++;
}
-#endif // FEATURE_CORECLR
+#endif // FEATURE_CORECLR && !NO_NGENPDB
else
{
if (argc == 1)
diff --git a/src/tools/util/.gitmirror b/src/tools/util/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/util/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/tools/util/consoleargs.cpp b/src/tools/util/consoleargs.cpp
new file mode 100644
index 0000000000..ad316e7a55
--- /dev/null
+++ b/src/tools/util/consoleargs.cpp
@@ -0,0 +1,939 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#include "consoleargs.h"
+#include <strsafe.h>
+
+typedef unsigned char byte;
+
+size_t SafeStrCopy( _In_ LPCWSTR wszSrc, _In_ size_t cchSrc, _Out_ LPWSTR wszDest, _In_ size_t cchDest)
+{
+ if (cchSrc == (size_t)-1)
+ cchSrc = wcslen(wszSrc);
+
+ if (cchSrc >= cchDest) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+
+ if (FAILED(StringCchCopyNW( wszDest, cchDest, wszSrc, cchSrc))) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+ return cchSrc;
+}
+
+size_t SafeStrLower( _In_ LPCWSTR wszSrc, _In_ size_t cchSrc, _Out_ LPWSTR wszDest, _In_ size_t cchDest)
+{
+ if (cchSrc == (size_t)-1)
+ cchSrc = wcslen(wszSrc);
+
+ if (cchSrc >= cchDest) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return 0;
+ }
+
+ SafeStrCopy(wszSrc, cchSrc, wszDest, cchDest);
+ _wcslwr_s((WCHAR*)wszDest, cchDest);
+ return wcslen(wszDest);
+}
+
+inline int HexValue (WCHAR c)
+{
+ return (c >= '0' && c <= '9') ? c - '0' : (c & 0xdf) - 'A' + 10;
+}
+
+// Get canonical file path from a user specified path. wszSrcfileName can include relative paths, etc.
+// Much of this function was taken from csc.exe.
+DWORD GetCanonFilePath(_In_z_ LPCWSTR wszSrcFileName, _Out_z_cap_(cchDestFileName) LPWSTR wszDestFileName, _In_ DWORD cchDestFileName, _In_ bool fPreserveSrcCasing)
+{
+ DWORD full_len;
+ WCHAR * full_path = new WCHAR[cchDestFileName]; // an intermediate buffer
+ WCHAR * temp_path = new WCHAR[cchDestFileName]; // Used if FindFile fails
+ WCHAR * full_cur;
+ WCHAR * out_cur;
+ WCHAR * out_end;
+ bool hasDrive = false;
+
+ memset(full_path, 0, cchDestFileName * sizeof(WCHAR));
+ out_cur = wszDestFileName;
+ out_end = out_cur + cchDestFileName;
+ if (wszSrcFileName != wszDestFileName)
+ *out_cur = L'\0';
+ full_cur = full_path;
+
+ // Replace '\\' with single backslashes in paths, because W_GetFullPathName fails to do this on win9x.
+ size_t i = 0;
+ size_t j = 0;
+ size_t length = wcslen(wszSrcFileName);
+ while (j<length)
+ {
+ // UNC paths start with '\\' so skip the first character if it is a backslash.
+ if (j!= 0 && wszSrcFileName[j] == '\\' && wszSrcFileName[j+1] == '\\')
+ j++;
+ else
+ temp_path[i++] = wszSrcFileName[j++];
+ if (i >= cchDestFileName) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+ }
+ temp_path[i] = L'\0';
+
+ full_len = GetFullPathNameW(temp_path, cchDestFileName, full_path, NULL);
+ if (wszSrcFileName == wszDestFileName)
+ wszDestFileName[cchDestFileName-1] = L'\0';
+ if (full_len == 0) {
+ goto FAIL;
+ } else if (full_len >= cchDestFileName) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+
+ // Allow only 1 ':' for drives and no long paths with "\\?\"
+ if (((full_path[0] >= L'a' && full_path[0] <= L'z') ||
+ (full_path[0] >= L'A' && full_path[0] <= L'Z')) &&
+ full_path[1] == L':')
+ hasDrive = true;
+
+ // We don't allow colons (except after the drive letter)
+ // long paths beginning with "\\?\"
+ // devices beginning with "\\.\"
+ // or wildcards
+ // or characters 0-31
+ if (wcschr( full_path + (hasDrive ? 2 : 0), L':') != NULL ||
+ wcsncmp( full_path, L"\\\\?\\", 4) == 0 ||
+ wcsncmp( full_path, L"\\\\.\\", 4) == 0 ||
+ wcspbrk(full_path, L"?*\x1\x2\x3\x4\x5\x6\x7\x8\x9"
+ L"\xA\xB\xC\xD\xE\xF\x10\x11\x12\x13\x14\x15"
+ L"\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\0") != NULL) {
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ }
+
+
+ if (hasDrive) {
+ size_t len = SafeStrLower( full_path, 3, out_cur, out_end - out_cur);
+ if (len == 0)
+ goto FAIL;
+
+ full_cur += 3;
+ out_cur += len;
+
+ } else if (full_path[0] == L'\\' && full_path[1] == L'\\') {
+ // Must be a UNC pathname, so lower-case the server and share
+ // since there's no known way to get the 'correct casing'
+ WCHAR * slash = wcschr(full_path + 2, L'\\');
+ // slash should now point to the backslash between the server and share
+ if (slash == NULL || slash == full_path + 2) {
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ }
+
+ slash = wcschr(slash + 1, L'\\');
+ if (slash == NULL) {
+ slash = full_path + wcslen(full_path);
+ } else if (slash[-1] == L'\\') {
+ // An empty share-name?
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ } else
+ slash++;
+ // slash should now point to char after the slash after the share name
+ // or the end of the sharename if there's no trailing slash
+
+ size_t len = SafeStrLower( full_path, slash - full_path, out_cur, out_end - out_cur);
+ if (len == 0)
+ goto FAIL;
+
+ full_cur = slash;
+ out_cur += len;
+
+ } else {
+ // Not a drive-leter path or a UNC path, so assume it's invalid
+ SetLastError(ERROR_INVALID_NAME);
+ goto FAIL;
+ }
+
+ // We either have a lower-cased drive letter or a UNC name
+ // with it's trailing slash
+ // out_cur points to the trailing NULL
+ // full_cur points to the character after the slash
+
+ // Now iterate over each element of the path and attempt to canonicalize it
+ // It's possible for this loop to never run
+ // (for strings like "C:\" or "\\unc\share" or "\\unc\share2\")
+ while (*full_cur) {
+ WIN32_FIND_DATAW find_data;
+ bool hasSlash = true;
+ WCHAR * slash = wcschr(full_cur, '\\');
+ if (slash == NULL) {
+ // This means we're on the last element of the path
+ // so work with everything left in the string
+ hasSlash = false;
+ slash = full_cur + wcslen(full_cur);
+ }
+
+ // Check to make sure we have enough room for the next part of the path
+ if (out_cur + (slash - full_cur) >= out_end) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+
+ // Copy over the next path part into the output buffer
+ // so we can run FindFile to get the correct casing/long filename
+ memcpy(out_cur, full_cur, (BYTE*)slash - (BYTE*)full_cur);
+ out_cur[slash - full_cur] = L'\0';
+ HANDLE hFind = FindFirstFileW(wszDestFileName, &find_data);
+ if (hFind == INVALID_HANDLE_VALUE) {
+ size_t temp_len;
+
+ // We coundn't find the file, the general causes are the file doesn't exist
+ // or we don't have access to it. Either way we still try to get a canonical filename
+ // but preserve the passed in casing for the filename
+
+ if (!hasSlash && fPreserveSrcCasing) {
+ // This is the last component in the filename, we should preserve the user's input text
+ // even if we can't find it
+ out_cur += slash - full_cur;
+ full_cur = slash;
+ break;
+ }
+
+ // This will succeed even if we don't have access to the file
+ // (And on NT4 if the filename is already in 8.3 form)
+ temp_len = GetShortPathNameW(wszDestFileName, temp_path, cchDestFileName);
+ if (temp_len == 0) {
+ // GetShortPathName failed, we have no other way of figuring out the
+ // The filename, so just lowercase it so it hashes in a case-insensitive manner
+
+ if (!hasSlash) {
+ // If it doesn't have a slash, then it must be the last part of the filename,
+ // so don't lowercase it, preserve whatever casing the user gave
+ temp_len = SafeStrCopy( full_cur, slash - full_cur, out_cur, out_end - out_cur);
+ } else {
+ temp_len = SafeStrLower( full_cur, slash - full_cur, out_cur, out_end - out_cur);
+ }
+ if (temp_len == 0)
+ goto FAIL;
+
+ full_cur = slash;
+ out_cur += temp_len;
+
+ } else if (temp_len >= cchDestFileName) {
+ // The short filename is longer than the whole thing?
+ // This shouldn't ever happen, right?
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ } else {
+ // GetShortPathName succeeded with a path that is less than BUFFER_LEN
+ // find the last slash and copy it. (We don't want to copy previous
+ // path components that we've already 'resolved')
+ // However, GetShortPathName doesn't always correct the casing
+ // so as a safe-guard, lower-case it (unless it's the last filename)
+ WCHAR * temp_slash = wcsrchr(temp_path, L'\\');
+
+ temp_slash++;
+ size_t len = 0;
+ if (!hasSlash) {
+ len = SafeStrCopy( temp_slash, -1, out_cur, out_end - out_cur);
+ } else {
+ len = SafeStrLower( temp_slash, -1, out_cur, out_end - out_cur);
+ }
+ if (len == 0)
+ goto FAIL;
+
+ full_cur = slash;
+ out_cur += len;
+
+ }
+ } else {
+ // Copy over the properly cased long filename
+ FindClose(hFind);
+ size_t name_len = wcslen(find_data.cFileName);
+ if (out_cur + name_len + (hasSlash ? 1 : 0) >= out_end) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+
+ // out_cur already has the filename with the input casing, so we can just leave it alone
+ // if this is not a directory name and the caller asked to perserve the casing
+ if (hasSlash || !fPreserveSrcCasing) {
+ memcpy(out_cur, find_data.cFileName, name_len * sizeof(WCHAR));
+ }
+ else if (name_len != (slash - full_cur) || _wcsnicmp(find_data.cFileName, full_cur, name_len) != 0) {
+ // The user asked us to preserve the casing of the filename
+ // and the filename is different by more than just casing so report
+ // an error indicating we can't create the file
+ SetLastError(ERROR_FILE_EXISTS);
+ goto FAIL;
+ }
+
+ out_cur += name_len;
+ full_cur = slash;
+ }
+
+ if (hasSlash) {
+ if (out_cur + 1 >= out_end) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ goto FAIL;
+ }
+ full_cur++;
+ *out_cur++ = L'\\';
+ }
+ *out_cur = '\0';
+ }
+
+ return (DWORD)(out_cur - wszDestFileName);
+
+FAIL:
+ if (full_path)
+ {
+ delete [] full_path;
+ }
+ if (temp_path)
+ {
+ delete [] temp_path;
+ }
+ return 0;
+}
+
+bool FreeString(LPCWSTR szText)
+{
+ if (szText)
+ delete [] (const_cast<LPWSTR>(szText));
+ return true;
+}
+
+bool IsWhitespace(WCHAR c)
+{
+ return c == L' ' || c == L'\t' || c == L'\n' || c == L'\r';
+}
+
+void ConsoleArgs::CleanUpArgs()
+{
+ while (m_listArgs)
+ {
+ WStrList * next = m_listArgs->next;
+ if (m_listArgs->arg)
+ delete [] m_listArgs->arg;
+ delete m_listArgs;
+ m_listArgs = next;
+ }
+
+ if (m_rgArgs)
+ delete[] m_rgArgs;
+
+ m_rgArgs = NULL;
+
+ if(m_lastErrorMessage)
+ {
+ delete[] m_lastErrorMessage;
+ }
+}
+
+bool ConsoleArgs::GetFullFileName(LPCWSTR szSource, __deref_out_ecount(cbFilenameBuffer) LPWSTR filenameBuffer, DWORD cbFilenameBuffer, bool fOutputFilename)
+{
+ if (0 == GetCanonFilePath( szSource, filenameBuffer, cbFilenameBuffer, fOutputFilename))
+ {
+ if (filenameBuffer[0] == L'\0')
+ {
+ // This could easily fail because of an overflow, but that's OK
+ // we only want what will fit in the output buffer so we can print
+ // a good error message
+ StringCchCopyW(filenameBuffer, cbFilenameBuffer - 4, szSource);
+ // Don't cat on the ..., only stick it in the last 4 characters
+ // to indicate truncation (if the string is short than this it just won't print)
+ StringCchCopyW(filenameBuffer + cbFilenameBuffer - 4, 4, L"...");
+ }
+ return false;
+ }
+ return true;
+}
+
+//
+// Clear previous error message if any and set the new one by copying into m_lastErrorMessage.
+// We are responsible for freeing the memory destruction.
+//
+void ConsoleArgs::SetErrorMessage(__deref_in LPCWSTR pwzMessage)
+{
+ if (m_lastErrorMessage != nullptr)
+ {
+ delete[] m_lastErrorMessage;
+ }
+ m_errorOccured = true;
+ m_lastErrorMessage = new WCHAR[wcslen(pwzMessage) + 1];
+ if (m_lastErrorMessage == nullptr)
+ {
+ //
+ // Out of memory allocating error string
+ //
+ m_lastErrorMessage = kOutOfMemory;
+ return;
+ }
+
+ wcscpy_s(m_lastErrorMessage, wcslen(pwzMessage) + 1, pwzMessage);
+}
+
+//
+// Create a simple leaf tree node with the given text
+//
+b_tree * ConsoleArgs::MakeLeaf(LPCWSTR text)
+{
+ b_tree * t = NULL;
+ size_t name_len = wcslen(text) + 1;
+ LPWSTR szCopy = new WCHAR[name_len];
+
+ if (!szCopy)
+ {
+ return NULL;
+ }
+
+ HRESULT hr;
+ hr = StringCchCopyW (szCopy, name_len, text);
+
+ t = new b_tree(szCopy);
+ if (!t)
+ {
+ delete [] szCopy;
+ return NULL;
+ }
+ return t;
+}
+
+//
+// Free the memory allocated by the tree (recursive)
+//
+void ConsoleArgs::CleanupTree(b_tree *root)
+{
+ if (root == NULL)
+ return ;
+ root->InOrderWalk(FreeString);
+ delete root;
+}
+
+//
+// Search the binary tree and add the given string
+// return true if it was added or false if it already
+// exists
+//
+HRESULT ConsoleArgs::TreeAdd(b_tree **root, LPCWSTR add
+ )
+{
+ // Special case - init the tree if it
+ // doesn't already exist
+ if (*root == NULL)
+ {
+ *root = MakeLeaf(add
+ );
+ return *root == NULL ? E_OUTOFMEMORY : S_OK;
+ }
+
+ size_t name_len = wcslen(add
+ ) + 1;
+ LPWSTR szCopy = new WCHAR[name_len];
+
+ if (!szCopy)
+ {
+ return NULL;
+ }
+
+ HRESULT hr = StringCchCopyW (szCopy, name_len, add
+ );
+ // otherwise, just let the template do the work
+ hr = (*root)->Add(szCopy, _wcsicmp);
+
+ if (hr != S_OK) // S_FALSE means it already existed
+ delete [] szCopy;
+
+ return hr;
+}
+
+//
+// Parse the text into a list of argument
+// return the total count
+// and set 'args' to point to the last list element's 'next'
+// This function assumes the text is NULL terminated
+//
+void ConsoleArgs::TextToArgs(LPCWSTR szText, WStrList ** listReplace)
+{
+ WStrList **argLast;
+ const WCHAR *pCur;
+ size_t iSlash;
+ int iCount;
+
+ argLast = listReplace;
+ pCur = szText;
+ iCount = 0;
+
+ // Guaranteed that all tokens are no bigger than the entire file.
+ LPWSTR szTemp = new WCHAR[wcslen(szText) + 1];
+ if (!szTemp)
+ {
+ return ;
+ }
+ while (*pCur != '\0')
+ {
+ WCHAR *pPut, *pFirst, *pLast;
+ WCHAR chIllegal;
+
+LEADINGWHITE:
+ while (IsWhitespace( *pCur) && *pCur != '\0')
+ pCur++;
+
+ if (*pCur == '\0')
+ break;
+ else if (*pCur == L'#')
+ {
+ while ( *pCur != '\0' && *pCur != '\n')
+ pCur++; // Skip to end of line
+ goto LEADINGWHITE;
+ }
+
+ // The treatment of quote marks is a bit different than the standard
+ // treatment. We only remove quote marks at the very beginning and end of the
+ // string. We still consider interior quotemarks for space ignoring purposes.
+ // All the below are considered a single argument:
+ // "foo bar" -> foo bar
+ // "foo bar";"baz" -> "foo bar";"baz"
+ // fo"o ba"r -> fo"o ba"r
+ //
+ // Additionally, in order to allow multi-line arguments we allow a ^ at the
+ // end of a line to specify "invisible space". A character sequence matching
+ // "\^(\r\n|\r|\n)[ \t]*" will be completely ignored (whether inside a quoted
+ // string or not). The below transformations occur (and represent a single
+ // argument):
+ // "foo ^
+ // bar" -> foo bar
+ // foo;^
+ // bar -> foo;bar
+ // Notes:
+ // 1. Comments are not recognized in a multi-line argument
+ // 2. A caret escapes only one new-line followed by an arbitrary number of
+ // tabs or blanks.
+ // The following will be parsed as the names suggest, into several different
+ // arguments:
+ // /option1 ^
+ // val1_1;^
+ // val1_2;^
+ // val1_3;^
+ //
+ // /option2
+ // /opt^
+ // ion3 -> /option1 val1_1;val1_2;val1_3; /option2 /option3
+ int cQuotes = 0;
+ pPut = pFirst = szTemp;
+ chIllegal = 0;
+ while ((!IsWhitespace( *pCur) || !!(cQuotes & 1)) && *pCur != '\0')
+ {
+ switch (*pCur)
+ {
+ // All this weird slash stuff follows the standard argument processing routines
+ case L'\\':
+ iSlash = 0;
+ // Copy and advance while counting slashes
+ while (*pCur == L'\\')
+ {
+ *pPut++ = *pCur++;
+ iSlash++;
+ }
+
+ // Slashes not followed by a quote character don't matter now
+ if (*pCur != L'\"')
+ break;
+
+ // If there's an odd count of slashes, it's escaping the quote
+ // Otherwise the quote is a quote
+ if ((iSlash & 1) == 0)
+ {
+ ++cQuotes;
+ }
+ *pPut++ = *pCur++;
+ break;
+
+ case L'\"':
+ ++cQuotes;
+ *pPut++ = *pCur++;
+ break;
+
+ case L'^':
+ // ignore this sequence: \^[\r\n|\r|\n]( \t)*
+ if (pCur[1] == L'\r' || pCur[1] == L'\n')
+ {
+ if (pCur[1] == L'\r' && pCur[2] == L'\n')
+ pCur += 3;
+ else
+ pCur += 2;
+
+ while (*pCur == L' ' || *pCur == L'\t')
+ ++pCur;
+ }
+ else
+ {
+ *pPut++ = *pCur++; // Copy the caret and advance
+ }
+ break;
+
+ case L'\x01':
+ case L'\x02':
+ case L'\x03':
+ case L'\x04':
+ case L'\x05':
+ case L'\x06':
+ case L'\x07':
+ case L'\x08':
+ case L'\x09':
+ case L'\x0A':
+ case L'\x0B':
+ case L'\x0C':
+ case L'\x0D':
+ case L'\x0E':
+ case L'\x0F':
+ case L'\x10':
+ case L'\x11':
+ case L'\x12':
+ case L'\x13':
+ case L'\x14':
+ case L'\x15':
+ case L'\x16':
+ case L'\x17':
+ case L'\x18':
+ case L'\x19':
+ case L'\x1A':
+ case L'\x1B':
+ case L'\x1C':
+ case L'\x1D':
+ case L'\x1E':
+ case L'\x1F':
+ case L'|':
+ // Save the first legal character and skip over them
+ if (chIllegal == 0)
+ chIllegal = *pCur;
+ pCur++;
+ break;
+
+ default:
+ *pPut++ = *pCur++; // Copy the char and advance
+ break;
+ }
+ }
+
+ pLast = pPut;
+ *pPut++ = '\0';
+
+ // If the string is surrounded by quotes, with no interior quotes, remove them.
+ if (cQuotes == 2 && *pFirst == L'\"' && *(pLast - 1) == L'\"')
+ {
+ ++pFirst;
+ --pLast;
+ *pLast = L'\0';
+ }
+
+ if (chIllegal != 0)
+ {
+ SetErrorMessage(L"Illegal option character.");
+ break;
+ }
+
+ size_t cchLen = pLast - pFirst + 1;
+ WCHAR * szArgCopy = new WCHAR[cchLen];
+ if (!szArgCopy || FAILED(StringCchCopyW(szArgCopy, cchLen, pFirst)))
+ {
+ SetErrorMessage(L"Out of memory.");
+ break;
+ }
+ WStrList * listArgNew = new WStrList( szArgCopy, (*argLast));
+ if (!listArgNew)
+ {
+ SetErrorMessage(L"Out of memory.");
+ break;
+ }
+
+ *argLast = listArgNew;
+ argLast = &listArgNew->next;
+ }
+
+ delete szTemp;
+
+}
+
+//
+// Pass in the command line args, argc and argv
+//
+// We expand any response files that may be contained in the args and return a new
+// set of args, pargc2 and pppargv2 that contain the full flat command line.
+//
+bool ConsoleArgs::ExpandResponseFiles(__in int argc, __deref_in_ecount(argc) const LPCWSTR * argv, __deref_out int * pargc2, __out LPWSTR ** pppargv2)
+{
+ *pargc2 = 0;
+ *pppargv2 = NULL;
+ WStrList **argLast = &m_listArgs;
+ while (argc > 0)
+ {
+ // Make a copy of the original var args so we can just delete[] everything
+ // once parsing is done: original args and new args from response files
+ // mixed in amongst the originals.
+ LPWSTR copyArg = new WCHAR[wcslen(argv[0]) + 1];
+ if (!copyArg)
+ {
+ SetErrorMessage(L"Out of memory.");
+ return false;
+ }
+ wcscpy_s(copyArg, wcslen(argv[0]) + 1, argv[0]);
+
+ WStrList * listArgNew = new WStrList(copyArg, (*argLast));
+ if (!listArgNew)
+ {
+ SetErrorMessage(L"Out of memory.");
+ return false;
+ }
+
+ *argLast = listArgNew;
+ argLast = &listArgNew->next;
+
+ argc--;
+ argv++;
+ }
+
+ // Process Response Files
+ ProcessResponseArgs();
+ if (m_errorOccured)
+ return false;
+
+ // Now convert to an argc/argv form for remaining processing.
+ int newArgc = 0;
+ for (WStrList * listCurArg = m_listArgs; listCurArg != NULL; listCurArg = listCurArg->next)
+ {
+ if (listCurArg->arg)
+ ++newArgc;
+ }
+
+ m_rgArgs = new LPWSTR[newArgc];
+ if (!m_rgArgs)
+ {
+ SetErrorMessage(L"Out of memory.");
+ return false;
+ }
+ int i = 0;
+ for (WStrList * listCurArg = m_listArgs; listCurArg != NULL; listCurArg = listCurArg->next)
+ {
+ if (listCurArg->arg)
+ {
+ LPWSTR newString = new WCHAR[wcslen(listCurArg->arg) + 1];
+ wcscpy_s(newString, wcslen(listCurArg->arg) + 1, listCurArg->arg);
+ m_rgArgs[i++] = newString;
+ }
+ }
+
+ *pargc2 = newArgc;
+ *pppargv2 = m_rgArgs;
+ return !m_errorOccured;
+}
+
+//
+// Read file to end, converting to unicode
+// ppwzTextBuffer is allocated. Caller is responsible for freeing
+//
+bool ConsoleArgs::ReadTextFile(LPCWSTR pwzFilename, __deref_out LPWSTR *ppwzTextBuffer)
+{
+ bool success = false;
+ char *bufA = nullptr;
+ WCHAR *bufW = nullptr;
+
+ HANDLE hFile = CreateFile(pwzFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ SetErrorMessage(L"Cannot open response file.");
+ goto ErrExit;
+ }
+ DWORD size = GetFileSize(hFile, NULL);
+ bufA = new char[size];
+
+ if (!bufA)
+ {
+ SetErrorMessage(L"Out of memory");
+ goto ErrExit;
+ }
+ DWORD numRead = 0;
+ if (!ReadFile(hFile, bufA, size, &numRead, NULL) || numRead != size)
+ {
+ SetErrorMessage(L"Failure reading response file.");
+ goto ErrExit;
+ }
+
+ char *postByteOrderMarks = bufA;
+
+ //
+ // If there are Byte Order Marks, skip them make sure they are ones that don't
+ // require us to handle the wrong endianness
+ //
+
+ byte byte0 = (byte)bufA[0];
+ byte byte1 = (byte)bufA[1];
+ byte byte2 = (byte)bufA[2];
+ byte byte3 = (byte)bufA[3];
+
+ bool alreadyUtf16 = false;
+
+ if (byte0 == 0xEF && byte1 == 0xBB && byte2 == 0xBF)
+ {
+ postByteOrderMarks += 3;
+ size -= 3;
+ }
+ else if (byte0 == 0xFF && byte1 == 0xFE)
+ {
+ postByteOrderMarks += 2;
+ size -= 2;
+ alreadyUtf16 = true;
+ }
+ else if (byte0 == 0xFE && byte1 == 0xFF)
+ {
+ SetErrorMessage(L"Invalid response file format. Use little endian encoding with Unicode");
+ goto ErrExit;
+ }
+ else if (byte0 == 0xFF && byte1 == 0xFE && byte2 == 0x00 && byte3 == 0x00 ||
+ byte0 == 0x00 && byte1 == 0x00 && byte2 == 0xFE && byte3 == 0xFF)
+ {
+ SetErrorMessage(L"Invalid response file format. Use ANSI, UTF-8, or UTF-16");
+ goto ErrExit;
+ }
+
+ if (alreadyUtf16)
+ {
+ //
+ // File is already formatted as UTF-16; just copy the bytes into the output buffer
+ //
+ int requiredSize = size + 2; // space for 2 nullptr bytes
+
+ // Sanity check - requiredSize better be an even number since we're dealing with UTF-16
+ if (requiredSize % 2 != 0)
+ {
+ SetErrorMessage(L"Response file corrupt. Expected UTF-16 encoding but we had an odd number of bytes");
+ goto ErrExit;
+ }
+
+ requiredSize /= 2;
+
+ bufW = new WCHAR[requiredSize];
+ if (!bufW)
+ {
+ SetErrorMessage(L"Out of memory");
+ goto ErrExit;
+ }
+
+ memcpy(bufW, postByteOrderMarks, size);
+ bufW[requiredSize - 1] = L'\0';
+ }
+ else
+ {
+ //
+ // File is formated as ANSI or UTF-8 and needs converting to UTF-16
+ //
+ int requiredSize = MultiByteToWideChar(CP_UTF8, 0, postByteOrderMarks, size, nullptr, 0);
+ bufW = new WCHAR[requiredSize + 1];
+ if (!bufW)
+ {
+ SetErrorMessage(L"Out of memory");
+ goto ErrExit;
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8, 0, postByteOrderMarks, size, bufW, requiredSize))
+ {
+ SetErrorMessage(L"Failure reading response file.");
+ goto ErrExit;
+ }
+
+ bufW[requiredSize] = L'\0';
+ }
+
+ *ppwzTextBuffer = bufW;
+
+ success = true;
+
+ErrExit:
+ if (bufA)
+ {
+ delete[] bufA;
+ }
+ CloseHandle(hFile);
+ return success;
+}
+
+/*
+ * Process Response files on the command line
+ */
+void ConsoleArgs::ProcessResponseArgs()
+{
+ HRESULT hr;
+ b_tree *response_files = NULL;
+
+ WCHAR szFilename[MAX_PATH];
+
+ for (WStrList * listCurArg = m_listArgs;
+ listCurArg != NULL && !m_errorOccured;
+ listCurArg = listCurArg->next)
+ {
+ WCHAR * szArg = listCurArg->arg;
+
+ // Skip everything except Response files
+ if (szArg == NULL || szArg[0] != '@')
+ continue;
+
+ if (wcslen(szArg) == 1)
+ {
+ SetErrorMessage(L"No response file specified");
+ goto CONTINUE;
+ }
+
+ // Check for duplicates
+ if (!GetFullFileName(&szArg[1], szFilename, MAX_PATH, false))
+ continue;
+
+
+ hr = TreeAdd(&response_files, szFilename);
+ if (hr == E_OUTOFMEMORY)
+ {
+ SetErrorMessage(L"Out of memory.");
+ goto CONTINUE;
+ }
+ else if (hr == S_FALSE)
+ {
+ SetErrorMessage(L"Duplicate response file.");
+ goto CONTINUE;
+ }
+
+ LPWSTR pwzFileBuffer = nullptr;
+ if (!ReadTextFile(szFilename, &pwzFileBuffer))
+ {
+ goto CONTINUE;
+ }
+
+ LPWSTR szActualText = nullptr;
+ DWORD dwNumChars = ExpandEnvironmentStrings(pwzFileBuffer, NULL, 0);
+ LPWSTR szExpandedBuffer = new WCHAR[dwNumChars];
+ if (szExpandedBuffer != nullptr)
+ {
+ DWORD dwRetVal = ExpandEnvironmentStrings(pwzFileBuffer, szExpandedBuffer, dwNumChars);
+
+ if (dwRetVal != 0)
+ {
+ szActualText = szExpandedBuffer;
+ }
+ else
+ {
+ // Expand failed
+
+ }
+ }
+
+ TextToArgs(szActualText, &listCurArg->next);
+
+CONTINUE: // remove the response file argument, and continue to the next.
+ listCurArg->arg = NULL;
+ }
+
+ CleanupTree(response_files);
+}
+
diff --git a/src/tools/util/consoleargs.h b/src/tools/util/consoleargs.h
new file mode 100644
index 0000000000..869cee3629
--- /dev/null
+++ b/src/tools/util/consoleargs.h
@@ -0,0 +1,71 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#ifndef __CONSOLEARGS_H__
+#define __CONSOLEARGS_H__
+
+#include "list.h"
+#include "tree.h"
+#include <strsafe.h>
+
+typedef tree<LPCWSTR> b_tree;
+typedef list<WCHAR*> WStrList;
+
+const LPWSTR kOutOfMemory = L"Out of memory";
+
+class ConsoleArgs
+{
+public:
+ // Place the fully-qualified filename in the given output buffer
+ bool GetFullFileName(LPCWSTR szSource, __deref_out_ecount(cbFilenameBuffer) LPWSTR filenameBuffer, DWORD cbFilenameBuffer, bool fOutputFilename);
+
+ ConsoleArgs() :
+ m_rgArgs(NULL),
+ m_listArgs(NULL),
+ m_errorOccured(false),
+ m_lastErrorMessage(nullptr)
+ {
+ };
+
+ ~ConsoleArgs()
+ {
+ CleanUpArgs();
+ };
+
+ // returns false if there are errors
+ bool ExpandResponseFiles(__in int argc, __deref_in_ecount(argc) const LPCWSTR * argv, __deref_out int * pargc2, __out LPWSTR ** pppargv2);
+
+ // Frees all memory used by the arg list and the argv/argc array
+ void CleanUpArgs();
+
+ LPWSTR ErrorMessage()
+ {
+ if (m_errorOccured)
+ {
+ return m_lastErrorMessage;
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+
+private:
+ void SetErrorMessage(__deref_in LPCWSTR pwzMessage);
+ b_tree * MakeLeaf( LPCWSTR szText);
+ void CleanupTree( b_tree * root);
+ HRESULT TreeAdd( b_tree ** root, LPCWSTR szAdd);
+ void TextToArgs( LPCWSTR szText, WStrList ** listReplace);
+ bool ReadTextFile(LPCWSTR pwzFilename, __deref_out LPWSTR *ppwzTextBuffer);
+ void ProcessResponseArgs();
+
+ LPWSTR * m_rgArgs;
+ WStrList * m_listArgs;
+
+ bool m_errorOccured;
+ LPWSTR m_lastErrorMessage;
+};
+
+#endif // __CONSOLEARGS_H__
diff --git a/src/tools/util/file_can.h b/src/tools/util/file_can.h
new file mode 100644
index 0000000000..a346a201e2
--- /dev/null
+++ b/src/tools/util/file_can.h
@@ -0,0 +1,70 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#ifndef __FILE_CAN_H__
+#define __FILE_CAN_H__
+
+class CFileChecksum;
+
+enum FileType
+{
+ ftUnknown = 0,
+ ftUnicode,
+ ftSwappedUnicode,
+ ftUTF8,
+ ftASCII,
+ ftBinary
+};
+
+HANDLE OpenFileEx( LPCWSTR filename, DWORD *fileLen, LPCWSTR relPath = NULL, bool bWrite = false);
+HRESULT ReadTextFile (PCWSTR pszFileName, UINT uiCodePage, WCAllocBuffer & textBuffer, FileType *fileType);
+#if !defined(FEATURE_PAL) && !defined(CSEE)
+// If you call ReadTextFile a lot you should create one HCRYPTPROV and pass it in to every call, otherwise
+// ReadTextFile indirectly creates and destroys a new HCRYPTPROV for every call, which is slow and unnecessary.
+// You can use CryptProvider to manage an HCRYPTPROV for you.
+HRESULT ReadTextFile (PCWSTR pszFileName, UINT uiCodePage, WCAllocBuffer & textBuffer, FileType *fileType, CFileChecksum *pChecksum, HCRYPTPROV hCryptProv = NULL);
+#endif
+
+// Src and Dest may be the same buffer
+// Returns 0 for error (check via GetLastError()) or count of characters
+// (not including NULL) copied to Dest.
+// if fPreserveSrcCasing is set, ignores on-disk casing of filename (but still gets on-disk casing of directories)
+// if fPreserveSrcCasing is set and and existing file matches with different short/longness it will fail
+// and set the error code to ERROR_FILE_EXISTS
+DWORD GetCanonFilePath(LPCWSTR wszSrcFileName, WCBuffer outBuffer, bool fPreserveSrcCasing);
+
+// GetCanonFilePath uses a cache to eliminate redundant calls to FindFirstFile. This cache
+// is global and is thus long lived. The IDE would like to minimize memory impact, so
+// ClearGetCanonFilePathCache is provided here for them to clear the cache when appropriate.
+void ClearGetCanonFilePathCache();
+
+// Remove quote marks from a string.
+// Translation is done in-place
+LPWSTR RemoveQuotes(WCBuffer textBuffer);
+
+// Remove quote marks from a string.
+// Replace various characters with other illegal characters if unquoted.
+// Translation is done in-place.
+LPWSTR RemoveQuotesAndReplaceComma(WCBuffer textBuffer); // "," -> "|"
+LPWSTR RemoveQuotesAndReplacePathDelim(WCBuffer textBuffer); // ",;" -> "|"
+LPWSTR RemoveQuotesAndReplaceAlias(WCBuffer textBuffer); // ",;" -> "|" and "=" -> "\x1"
+
+// Safe version of ToLowerCase
+// Gaurantees null termination even if buffer size is too small
+inline PWSTR WINAPI SafeToLowerCase (PCWSTR pSrc, WCBuffer textBuffer)
+{
+ PWSTR returnValue = ToLowerCase(pSrc, textBuffer.GetData(), textBuffer.Count());
+ if (textBuffer.Count() > 0)
+ {
+ textBuffer.SetAt(textBuffer.Count() - 1, 0);
+ }
+ return returnValue;
+}
+
+// Joins a relative or absolute filename to the given path and stores the new
+// filename in lpBuffer
+bool MakePath( /*[in]*/LPCWSTR lpPath, /*[in]*/LPCWSTR lpFileName, WCBuffer pathBuffer);
+
+#endif // __FILE_CAN_H__
diff --git a/src/tools/util/list.h b/src/tools/util/list.h
new file mode 100644
index 0000000000..5dc0aa4c6a
--- /dev/null
+++ b/src/tools/util/list.h
@@ -0,0 +1,26 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#ifndef __GENERIC_LIST_H__
+#define __GENERIC_LIST_H__
+
+// Simple parameterized linked list
+// with some good ctors
+template <typename _T>
+struct list
+{
+ _T arg;
+ list<_T> *next;
+
+ list(_T t, list<_T> *n)
+ {
+ arg = t, next = n;
+ }
+ list() : arg(), next(NULL)
+ {
+ }
+};
+
+#endif // __GENERIC_LIST_H__
diff --git a/src/tools/util/tree.h b/src/tools/util/tree.h
new file mode 100644
index 0000000000..527f718b00
--- /dev/null
+++ b/src/tools/util/tree.h
@@ -0,0 +1,243 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#ifndef __GENERIC_TREE_H__
+#define __GENERIC_TREE_H__
+
+#include <windows.h>
+
+// Partially balanced binary tree
+// it does individual rotations on insertion, but does nto allow deletion.
+// thus the worst case depth is not (n), but (n/2)
+// Generic paramter is the element type
+// Find and Add require a method that compares 2 elements
+template <typename _E>
+struct tree
+{
+ _E name;
+ tree<_E> *lChild;
+ tree<_E> *rChild;
+ size_t lDepth;
+ size_t rDepth;
+
+ tree(_E e)
+ {
+ name = e;
+ lChild = rChild = NULL;
+ lDepth = rDepth = 0;
+ }
+ ~tree()
+ {
+ Cleanup();
+ }
+
+ bool InOrderWalk( bool (WalkFunc)(_E))
+ {
+ if (lChild != NULL && !lChild->InOrderWalk(WalkFunc))
+ return false;
+ if (!WalkFunc(name))
+ return false;
+ if (rChild != NULL)
+ return rChild->InOrderWalk(WalkFunc);
+ return true;
+ }
+
+ /*
+ * return the depths of the tree from here down (minimum of 1)
+ */
+ size_t MaxDepth()
+ {
+ return lDepth > rDepth ? lDepth + 1 : rDepth + 1;
+ }
+
+ /*
+ * Search the binary tree for the given string
+ * return a pointer to it was added or NULL if it
+ * doesn't exist
+ */
+ _E * Find(_E SearchVal, int (__cdecl CompFunc)(_E, _E))
+ {
+ int cmp = CompFunc(name, SearchVal);
+ if (cmp < 0)
+ {
+ if (lChild == NULL)
+ return NULL;
+ else
+ return lChild->Find(SearchVal, CompFunc);
+ }
+ else if (cmp > 0)
+ {
+ if (rChild == NULL)
+ return NULL;
+ else
+ return rChild->Find(SearchVal, CompFunc);
+ }
+ else
+ return &name;
+ }
+
+ /*
+ * Search the binary tree and add the given string
+ * return S_OK if it was added or S_FALSE if it already
+ * exists (or E_OUTOFMEMORY)
+ */
+ HRESULT Add(_E add
+ , int (__cdecl CompFunc)(_E, _E))
+ {
+ int cmp = CompFunc(name, add
+ );
+REDO:
+ if (cmp == 0)
+ return S_FALSE;
+
+ if (cmp < 0)
+ {
+ if (lChild == NULL)
+ {
+ lDepth = 1;
+ lChild = new tree<_E>(add
+ );
+ if (lChild == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+ }
+ else if (rDepth < lDepth)
+ {
+ tree<_E> *temp = new tree<_E>(name);
+ if (temp == NULL)
+ return E_OUTOFMEMORY;
+ temp->rChild = rChild;
+ temp->rDepth = rDepth;
+ if (lChild != NULL &&
+ (cmp = CompFunc(lChild->name, add
+ )) > 0)
+ {
+ // push right
+ temp->lChild = NULL;
+ temp->lDepth = 0;
+ name = add
+ ;
+ rChild = temp;
+ rDepth++;
+ return S_OK;
+ }
+ else if (cmp == 0)
+ {
+ temp->rChild = NULL;
+ delete temp;
+ return S_FALSE;
+ }
+ else
+ {
+ // Rotate right
+ temp->lChild = lChild->rChild;
+ temp->lDepth = lChild->rDepth;
+ name = lChild->name;
+ lDepth = lChild->lDepth;
+ rDepth = temp->MaxDepth();
+ rChild = temp;
+ temp = lChild->lChild;
+ lChild->lChild = lChild->rChild = NULL;
+ delete lChild;
+ lChild = temp;
+ goto REDO;
+ }
+ }
+ else
+ {
+ HRESULT hr = lChild->Add(add
+ , CompFunc);
+ lDepth = lChild->MaxDepth();
+ return hr;
+ }
+ }
+ else
+ {
+ if (rChild == NULL)
+ {
+ rDepth = 1;
+ rChild = new tree<_E>(add
+ );
+ if (rChild == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+ }
+ else if (lDepth < rDepth)
+ {
+ tree<_E> *temp = new tree<_E>(name);
+ if (temp == NULL)
+ return E_OUTOFMEMORY;
+ temp->lChild = lChild;
+ temp->lDepth = lDepth;
+ if (rChild != NULL &&
+ (cmp = CompFunc(rChild->name, add
+ )) < 0)
+ {
+ // push left
+ temp->rChild = NULL;
+ temp->rDepth = 0;
+ name = add
+ ;
+ lChild = temp;
+ lDepth++;
+ return S_OK;
+ }
+ else if (cmp == 0)
+ {
+ temp->lChild = NULL;
+ delete temp;
+ return S_FALSE;
+ }
+ else
+ {
+ // Rotate left
+ temp->rChild = rChild->lChild;
+ temp->rDepth = rChild->lDepth;
+ name = rChild->name;
+ rDepth = rChild->rDepth;
+ lDepth = temp->MaxDepth();
+ lChild = temp;
+ temp = rChild->rChild;
+ rChild->rChild = rChild->lChild = NULL;
+ delete rChild;
+ rChild = temp;
+ goto REDO;
+ }
+ }
+ else
+ {
+ HRESULT hr = rChild->Add(add
+ , CompFunc);
+ rDepth = rChild->MaxDepth();
+ return hr;
+ }
+ }
+ }
+
+ /*
+ * Free the memory allocated by the tree (recursive)
+ */
+ void Cleanup()
+ {
+ if (this == NULL)
+ return ;
+ if (lChild != NULL)
+ {
+ lChild->Cleanup();
+ delete lChild;
+ lChild = NULL;
+ }
+ if (rChild != NULL)
+ {
+ rChild->Cleanup();
+ delete rChild;
+ rChild = NULL;
+
+ }
+ }
+
+};
+
+#endif // __GENERIC_TREE_H__
diff --git a/src/utilcode/CMakeLists.txt b/src/utilcode/CMakeLists.txt
index 4f5020e2ab..d8ea9f10cd 100644
--- a/src/utilcode/CMakeLists.txt
+++ b/src/utilcode/CMakeLists.txt
@@ -95,4 +95,7 @@ endif(CLR_CMAKE_PLATFORM_UNIX)
add_subdirectory(dac)
add_subdirectory(dyncrt)
add_subdirectory(staticnohost)
+if(WIN32)
+ add_subdirectory(crossgen)
+endif(WIN32)
diff --git a/src/utilcode/crossgen/CMakeLists.txt b/src/utilcode/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..1f427e1e63
--- /dev/null
+++ b/src/utilcode/crossgen/CMakeLists.txt
@@ -0,0 +1,8 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+list(APPEND UTILCODE_SOURCES
+ ../hostimpl.cpp
+)
+
+add_precompiled_header(stdafx.h ../stdafx.cpp UTILCODE_SOURCES)
+add_library(utilcode_crossgen STATIC ${UTILCODE_SOURCES})
diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp
index c9c0603c61..86e28c450b 100644
--- a/src/vm/compile.cpp
+++ b/src/vm/compile.cpp
@@ -67,7 +67,9 @@
#include "crossgenroresolvenamespace.h"
#endif
+#ifndef NO_NGENPDB
#include <cvinfo.h>
+#endif
#ifdef MDIL
#include <mdil.h>
@@ -2624,6 +2626,26 @@ BOOL CEECompileInfo::AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle
// public\devdiv\inc\corsym.h and debugger\sh\symwrtr\ngenpdbwriter.h,cpp
// ----------------------------------------------------------------------------
+#ifdef NO_NGENPDB
+BOOL CEECompileInfo::GetIsGeneratingNgenPDB()
+{
+ return FALSE;
+}
+
+void CEECompileInfo::SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB)
+{
+}
+
+BOOL IsNgenPDBCompilationProcess()
+{
+ return FALSE;
+}
+
+HRESULT __stdcall CreatePdb(CORINFO_ASSEMBLY_HANDLE hAssembly, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath)
+{
+ return E_NOTIMPL;
+}
+#else // NO_NGENPDB
BOOL CEECompileInfo::GetIsGeneratingNgenPDB()
{
@@ -4421,6 +4443,7 @@ HRESULT __stdcall CreatePdb(CORINFO_ASSEMBLY_HANDLE hAssembly, BSTR pNativeImage
return S_OK;
}
+#endif // NO_NGENPDB
// End of PDB writing code
// ----------------------------------------------------------------------------
diff --git a/src/vm/crossgen/CMakeLists.txt b/src/vm/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..2bf63c424a
--- /dev/null
+++ b/src/vm/crossgen/CMakeLists.txt
@@ -0,0 +1,124 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+set(VM_CROSSGEN_SOURCES
+ ../class.cpp
+ ../AppDomain.cpp
+ ../array.cpp
+ ../Assembly.cpp
+ ../AssemblySpec.cpp
+ ../binder.cpp
+ ../ceeload.cpp
+ ../ceemain.cpp
+ ../classhash.cpp
+ ../clrex.cpp
+ ../CLRPrivBinderUtil.cpp
+ ../CLRPrivBinderWinRT.cpp
+ ../CLRPrivTypeCacheWinRT.cpp
+ ../clsload.cpp
+ ../comdelegate.cpp
+ ../codeman.cpp
+ ../compile.cpp
+ ../ConstrainedExecutionRegion.cpp
+ ../CustomMarshalerInfo.cpp
+ ../Domainfile.cpp
+ ../BaseAssemblySpec.cpp
+ ../corebindresult.cpp
+ ../coreassemblyspec.cpp
+ ../crossdomaincalls.cpp
+ ../dataimage.cpp
+ ../decodeMD.cpp
+ ../DebugInfoStore.cpp
+ ../ecall.cpp
+ ../eeconfig.cpp
+ ../eehash.cpp
+ ../eetwain.cpp
+ ../excep.cpp
+ ../Field.cpp
+ ../Fieldmarshaler.cpp
+ ../formattype.cpp
+ ../TypeEquivalenceHash.cpp
+ ../GCDecode.cpp
+ ../genericdict.cpp
+ ../generics.cpp
+ ../genmeth.cpp
+ ../hash.cpp
+ ../ILMarshalers.cpp
+ ../ILStubCache.cpp
+ ../ILStubResolver.cpp
+ ../instmethhash.cpp
+ ../interoputil.cpp
+ ../invokeutil.cpp
+ ../inlinetracking.cpp
+ ../contractImpl.cpp
+ ../JITInterface.cpp
+ ../LoaderAllocator.cpp
+ ../ListLock.cpp
+ ../memberload.cpp
+ ../Method.cpp
+ ../MethodImpl.cpp
+ ../MethodTable.cpp
+ ../methodtablebuilder.cpp
+ ../mscorlib.cpp
+ ../stubcache.cpp
+ ../mlinfo.cpp
+ ../DllImport.cpp
+ ../DllImportCallback.cpp
+ ../PEFile.cpp
+ ../PEFingerprint.cpp
+ ../PEImage.cpp
+ ../PEImageLayout.cpp
+ ../pendingload.cpp
+ ../Precode.cpp
+ ../olevariant.cpp
+ ../security.cpp
+ ../securitypolicy.cpp
+ ../securityAttributes.cpp
+ ../SecurityDeclarative.cpp
+ ../SecurityDeclarativeCache.cpp
+ ../SecurityDescriptor.cpp
+ ../SecurityDescriptorAppdomain.cpp
+ ../SecurityDescriptorAssembly.cpp
+ ../securitymeta.cpp
+ ../SecurityTransparentAssembly.cpp
+ ../siginfo.cpp
+ ../SigFormat.cpp
+ ../SimpleRWLock.cpp
+ ../spinlock.cpp
+ ../StackingAllocator.cpp
+ ../stubgen.cpp
+ ../stublink.cpp
+ ../typectxt.cpp
+ ../typedesc.cpp
+ ../typehandle.cpp
+ ../typehash.cpp
+ ../typeparse.cpp
+ ../typestring.cpp
+ ../util.cpp
+ ../vars.cpp
+ ../zapsig.cpp
+ ../classcompat.cpp
+ ../COMtoCLRCall.cpp
+ ../CLRtoCOMCall.cpp
+ ../RuntimeCallableWrapper.cpp
+ ../WinRTHelpers.cpp
+ ../WinRTTypeNameConverter.cpp
+ ../DbgGcInfoDecoder.cpp
+ ../GcInfoDecoder.cpp
+ ../SHA1.cpp
+ ../amd64/StubLinkerAMD64.cpp
+ ../crossgencompile.cpp
+ ../CrossgenRoParseTypeName.cpp
+ ../CrossgenRoResolveNamespace.cpp
+)
+
+include_directories(BEFORE ..)
+include_directories(${CLR_DIR}/src/gc)
+include_directories(../amd64)
+
+if (WIN32)
+ add_precompiled_header(common.h ../common.cpp VM_CROSSGEN_SOURCES)
+ # mscorlib.cpp does not compile with precompiled header file
+ set_source_files_properties(../mscorlib.cpp PROPERTIES COMPILE_FLAGS "/Y-")
+endif (WIN32)
+
+add_library(cee_crossgen ${VM_CROSSGEN_SOURCES})
diff --git a/src/vm/crossgen_mscorlib/CMakeLists.txt b/src/vm/crossgen_mscorlib/CMakeLists.txt
new file mode 100644
index 0000000000..88786c6b4b
--- /dev/null
+++ b/src/vm/crossgen_mscorlib/CMakeLists.txt
@@ -0,0 +1,15 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+# Add back some of the macro removed by crossgen.cmake.
+add_definitions(
+ -DEnC_SUPPORTED
+ -DFEATURE_EVENT_TRACE=1
+ -DFEATURE_LOADER_OPTIMIZATION
+ -DFEATURE_MULTICOREJIT
+ -DFEATURE_RANDOMIZED_STRING_HASHING
+ -DFEATURE_VERSIONING_LOG
+)
+
+add_definitions(-DCROSSGEN_MSCORLIB)
+
+add_library(mscorlib_crossgen ../mscorlib.cpp)
diff --git a/src/zap/crossgen/CMakeLists.txt b/src/zap/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..dc7d0e8794
--- /dev/null
+++ b/src/zap/crossgen/CMakeLists.txt
@@ -0,0 +1,21 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+set(ZAP_SOURCES
+ ../svcworker.cpp
+ ../zapper.cpp
+ ../zaprelocs.cpp
+ ../zapcode.cpp
+ ../zapheaders.cpp
+ ../zapimage.cpp
+ ../zapinfo.cpp
+ ../zapimport.cpp
+ ../zapinnerptr.cpp
+ ../zapmetadata.cpp
+ ../zapwriter.cpp
+ ../zapwrapper.cpp
+ ../zapperstats.cpp
+ ../nativeformatwriter.cpp
+)
+
+add_precompiled_header(common.h ../common.cpp ZAP_SOURCES)
+add_library(corzap_crossgen STATIC ${ZAP_SOURCES})