summaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/tools
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/.gitmirror1
-rw-r--r--src/tools/CMakeLists.txt2
-rw-r--r--src/tools/GenClrDebugResource/.gitmirror1
-rw-r--r--src/tools/GenClrDebugResource/CMakeLists.txt6
-rw-r--r--src/tools/GenClrDebugResource/GenClrDebugResource.cpp220
-rw-r--r--src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj24
-rw-r--r--src/tools/InjectResource/.gitmirror1
-rw-r--r--src/tools/InjectResource/CMakeLists.txt9
-rw-r--r--src/tools/InjectResource/InjectResource.cpp158
-rw-r--r--src/tools/InjectResource/InjectResource.nativeproj24
-rw-r--r--src/tools/crossgen/.gitmirror1
-rw-r--r--src/tools/crossgen/Native.rc3
-rw-r--r--src/tools/crossgen/compare.bat186
-rw-r--r--src/tools/crossgen/crossgen.cpp989
-rw-r--r--src/tools/crossgen/crossgen.nativeproj97
-rw-r--r--src/tools/dirs.proj68
16 files changed, 1790 insertions, 0 deletions
diff --git a/src/tools/.gitmirror b/src/tools/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/.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/CMakeLists.txt b/src/tools/CMakeLists.txt
new file mode 100644
index 0000000000..d8f881a92e
--- /dev/null
+++ b/src/tools/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(GenClrDebugResource)
+add_subdirectory(InjectResource) \ No newline at end of file
diff --git a/src/tools/GenClrDebugResource/.gitmirror b/src/tools/GenClrDebugResource/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/GenClrDebugResource/.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/GenClrDebugResource/CMakeLists.txt b/src/tools/GenClrDebugResource/CMakeLists.txt
new file mode 100644
index 0000000000..c23a603adf
--- /dev/null
+++ b/src/tools/GenClrDebugResource/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_definitions(-MT)
+add_executable(GenClrDebugResource GenClrDebugResource.cpp)
+
+target_link_libraries(GenClrDebugResource
+ ${STATIC_MT_CRT_LIB}
+) \ No newline at end of file
diff --git a/src/tools/GenClrDebugResource/GenClrDebugResource.cpp b/src/tools/GenClrDebugResource/GenClrDebugResource.cpp
new file mode 100644
index 0000000000..158b0a1b76
--- /dev/null
+++ b/src/tools/GenClrDebugResource/GenClrDebugResource.cpp
@@ -0,0 +1,220 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+/* This app writes out the data for a special resource which is embedded in clr.dll
+ * The resource serves two purposes, to differentiate a random dll named clr.dll from
+ * an official microsoft clr dll (it isn't foolproof but it should prevent anyone from
+ * accidentally appearing to be a clr) and to provide file information about DAC and DBI
+ * which correspond to this build of the CLR.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windows.h>
+#include <clrinternal.h>
+
+char* g_appName;
+
+
+struct ClrDebugResource
+{
+ DWORD dwVersion;
+ GUID signature;
+ DWORD dwDacTimeStamp;
+ DWORD dwDacSizeOfImage;
+ DWORD dwDbiTimeStamp;
+ DWORD dwDbiSizeOfImage;
+};
+
+BOOL
+GetBinFileData(__in_z char* binFileName, DWORD* pTimeStamp, DWORD* pSizeOfImage)
+{
+ HANDLE binFileHandle;
+ DWORD peHeaderOffset;
+ ULONG done;
+
+ binFileHandle = CreateFileA(binFileName, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (!binFileHandle || binFileHandle == INVALID_HANDLE_VALUE)
+ {
+ printf("%s: Unable to open '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ // Read the 4 byte value at 0x3c, which is the offset to PE header
+ if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, 0x3c, NULL, FILE_BEGIN))
+ {
+ printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ if (!ReadFile(binFileHandle, &peHeaderOffset, 4, &done, NULL) ||
+ done != 4)
+ {
+ printf("%s: Unable to read '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ // Read the 4 byte value at 8 bytes after peHeader, that is the timestamp
+ if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, peHeaderOffset + 8, NULL, FILE_BEGIN))
+ {
+ printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ if (!ReadFile(binFileHandle, pTimeStamp, 4, &done, NULL) ||
+ done != 4)
+ {
+ printf("%s: Unable to read '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ // Read the 4 byte value at 80 bytes after peHeader, that is the sizeOfImage
+ if (INVALID_SET_FILE_POINTER == SetFilePointer(binFileHandle, peHeaderOffset + 80, NULL, FILE_BEGIN))
+ {
+ printf("%s: Unable to move file pointer '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ if (!ReadFile(binFileHandle, pSizeOfImage, 4, &done, NULL) ||
+ done != 4)
+ {
+ printf("%s: Unable to read '%s', %d\n", g_appName,
+ binFileName, GetLastError());
+ goto error;
+ }
+
+ CloseHandle(binFileHandle);
+ return TRUE;
+
+error:
+ CloseHandle(binFileHandle);
+ return FALSE;
+}
+
+void
+Usage(void)
+{
+ printf("Usage: %s [options]\n", g_appName);
+ printf("Options are:\n");
+ printf(" /out:<file> - output binary file that contains the raw resource data\n");
+ printf(" /dac:<file> - path to mscordacwks that should be referenced\n");
+ printf(" /dbi:<file> - path to mscordbi that should be referenced\n");
+ printf(" /sku:<sku_name> - Either clr, coreclr, or phoneclr indicating the CLR sku\n");
+}
+
+void __cdecl
+main(int argc, __in_z char** argv)
+{
+ char* outFile = NULL;
+ char* dacFile = NULL;
+ char* dbiFile = NULL;
+ char* sku = NULL;
+
+ g_appName = argv[0];
+
+ while (--argc)
+ {
+ argv++;
+
+ if (!strncmp(*argv, "/out:", 5))
+ {
+ outFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/dac:", 5))
+ {
+ dacFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/dbi:", 5))
+ {
+ dbiFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/sku:", 5))
+ {
+ sku = *argv + 5;
+ }
+ else
+ {
+ Usage();
+ exit(1);
+ }
+ }
+
+ if (!outFile || !dacFile || !dbiFile || !sku)
+ {
+ Usage();
+ exit(1);
+ }
+
+ ClrDebugResource res;
+ res.dwVersion = 0;
+
+ if(strcmp(sku, "clr")==0)
+ {
+ res.signature = CLR_ID_V4_DESKTOP;
+ }
+ else if(strcmp(sku, "coreclr")==0)
+ {
+ res.signature = CLR_ID_CORECLR;
+ }
+ else if(strcmp(sku, "phoneclr")==0)
+ {
+ res.signature = CLR_ID_PHONE_CLR;
+ }
+ else if (strcmp(sku, "onecoreclr") == 0)
+ {
+ res.signature = CLR_ID_ONECORE_CLR;
+ }
+ else
+ {
+ printf("Error: Unrecognized sku option: %s\n", sku);
+ Usage();
+ exit(1);
+ }
+
+ printf("%s: Reading data from DAC: %s\n", g_appName, dacFile);
+ if(!GetBinFileData(dacFile, &(res.dwDacTimeStamp), &(res.dwDacSizeOfImage)))
+ exit(1);
+ printf("%s: DAC timeStamp = 0x%x sizeOfImage = 0x%x\n", g_appName, res.dwDacTimeStamp, res.dwDacSizeOfImage);
+
+ printf("%s: Reading data from DBI: %s\n", g_appName, dbiFile);
+ if(!GetBinFileData(dbiFile, &(res.dwDbiTimeStamp), &(res.dwDbiSizeOfImage)))
+ exit(1);
+ printf("%s: DBI timeStamp = 0x%x sizeOfImage = 0x%x\n", g_appName, res.dwDbiTimeStamp, res.dwDbiSizeOfImage);
+
+ printf("%s: Writing binary resource file: %s\n", g_appName, outFile);
+ HANDLE outFileHandle = CreateFileA(outFile, GENERIC_WRITE, 0,
+ NULL, CREATE_ALWAYS, 0, NULL);
+ if (!outFileHandle || outFileHandle == INVALID_HANDLE_VALUE)
+ {
+ printf("%s: Unable to create '%s', %d\n",
+ g_appName, outFile, GetLastError());
+ goto error;
+ }
+
+
+ DWORD done = 0;
+ if(!WriteFile(outFileHandle, &res, sizeof(res), &done, NULL) || done != sizeof(res))
+ {
+ printf("%s: Unable to write file data '%s', %d\n",
+ g_appName, outFile, GetLastError());
+ goto error;
+ }
+
+ CloseHandle(outFileHandle);
+ printf("%s: Success. Returning 0\n", g_appName);
+ exit(0);
+
+error:
+ CloseHandle(outFileHandle);
+ exit(1);
+}
diff --git a/src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj b/src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj
new file mode 100644
index 0000000000..d5ce2158ca
--- /dev/null
+++ b/src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj
@@ -0,0 +1,24 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <OutputName>GenClrDebugResource</OutputName>
+ <TargetType>PROGRAM</TargetType>
+ <LinkSubsystem>console</LinkSubsystem>
+ <BinplaceSymbols>false</BinplaceSymbols>
+ <LinkGenerateManifest>true</LinkGenerateManifest>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions>
+ <UseMsvcrt>false</UseMsvcrt>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <CppCompile Include="GenClrDebugResource.cpp" />
+ </ItemGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project> \ No newline at end of file
diff --git a/src/tools/InjectResource/.gitmirror b/src/tools/InjectResource/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/InjectResource/.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/InjectResource/CMakeLists.txt b/src/tools/InjectResource/CMakeLists.txt
new file mode 100644
index 0000000000..b530923fcf
--- /dev/null
+++ b/src/tools/InjectResource/CMakeLists.txt
@@ -0,0 +1,9 @@
+remove_definitions(-DUNICODE)
+remove_definitions(-D_UNICODE)
+add_definitions(-MT)
+
+add_executable(InjectResource InjectResource.cpp)
+
+target_link_libraries(InjectResource
+ ${STATIC_MT_CRT_LIB}
+) \ No newline at end of file
diff --git a/src/tools/InjectResource/InjectResource.cpp b/src/tools/InjectResource/InjectResource.cpp
new file mode 100644
index 0000000000..29921f5ac5
--- /dev/null
+++ b/src/tools/InjectResource/InjectResource.cpp
@@ -0,0 +1,158 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windows.h>
+#include <daccess.h>
+
+char* g_appName;
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+void
+AddBinaryResourceToDll(__in_z char* dllName,
+ __in_z char* resName,
+ PVOID resData,
+ ULONG resDataSize)
+{
+ // a retry loop in case we get transient file access issues
+ // does exponential backoff with retries after 1,2,4,8,16, and 32 seconds
+ for(int seconds = 0; seconds < 60; seconds = MAX(seconds*2,1))
+ {
+ if(seconds != 0)
+ Sleep(seconds * 1000);
+
+ HANDLE dllUpdate = BeginUpdateResourceA(dllName, FALSE);
+ if (!dllUpdate)
+ {
+ printf("Unable to open '%s' for update, error=%d\n",
+ dllName, GetLastError());
+ continue;
+ }
+
+ if (!UpdateResourceA(dllUpdate,
+ RT_RCDATA,
+ resName,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
+ resData,
+ resDataSize))
+ {
+ printf("Unable to update '%s', error=%d\n",
+ dllName, GetLastError());
+ continue;
+ }
+
+ if(!EndUpdateResource(dllUpdate, FALSE))
+ {
+ printf("Unable to write updates to '%s', error=%d\n",
+ dllName, GetLastError());
+ continue;
+ }
+
+ return;
+ }
+
+ printf("Stopping after excessive failures\n");
+ exit(1);
+}
+
+void
+GetBinFileData(__in_z char* binFileName, PVOID* binData, PULONG binDataSize)
+{
+ HANDLE binFileHandle;
+ PVOID data;
+ ULONG size, done;
+
+ binFileHandle = CreateFileA(binFileName, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (!binFileHandle || binFileHandle == INVALID_HANDLE_VALUE)
+ {
+ printf("Unable to open '%s', %d\n",
+ binFileName, GetLastError());
+ exit(1);
+ }
+
+ size = GetFileSize(binFileHandle, NULL);
+ data = malloc(size);
+ if (!data)
+ {
+ printf("Out of memory\n");
+ exit(1);
+ }
+
+ if (!ReadFile(binFileHandle, data, size, &done, NULL) ||
+ done != size)
+ {
+ printf("Unable to read '%s', %d\n",
+ binFileName, GetLastError());
+ exit(1);
+ }
+
+ CloseHandle(binFileHandle);
+
+ *binData = data;
+ *binDataSize = size;
+}
+
+void
+Usage(void)
+{
+ printf("Usage: %s [options]\n", g_appName);
+ printf("Options are:\n");
+ printf(" /bin:<file> - Binary data to attach to DLL\n");
+ printf(" /dll:<file> - DLL to modify\n");
+ printf(" /name:<name> - resource name [Optional]\n");
+ exit(1);
+}
+
+void __cdecl
+main(int argc, __in_z char** argv)
+{
+ char* binFile = NULL;
+ char* dllFile = NULL;
+ char* resName = NULL;
+
+ g_appName = argv[0];
+
+ while (--argc)
+ {
+ argv++;
+
+ if (!strncmp(*argv, "/bin:", 5))
+ {
+ binFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/dll:", 5))
+ {
+ dllFile = *argv + 5;
+ }
+ else if (!strncmp(*argv, "/name:", 6))
+ {
+ resName = *argv + 6;
+ }
+ else
+ {
+ Usage();
+ }
+ }
+
+ if (!binFile || !dllFile)
+ {
+ Usage();
+ }
+
+ PVOID resData;
+ ULONG resDataSize;
+
+ GetBinFileData(binFile, &resData, &resDataSize);
+
+ AddBinaryResourceToDll(dllFile, resName?resName:DACCESS_TABLE_RESOURCE,
+ resData, resDataSize);
+
+ free(resData);
+
+ printf("Updated %s\n", dllFile);
+}
diff --git a/src/tools/InjectResource/InjectResource.nativeproj b/src/tools/InjectResource/InjectResource.nativeproj
new file mode 100644
index 0000000000..fc77425a2e
--- /dev/null
+++ b/src/tools/InjectResource/InjectResource.nativeproj
@@ -0,0 +1,24 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <OutputName>InjectResource</OutputName>
+ <TargetType>PROGRAM</TargetType>
+ <LinkSubsystem>console</LinkSubsystem>
+ <BinplaceSymbols>false</BinplaceSymbols>
+ <LinkGenerateManifest>true</LinkGenerateManifest>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions>
+ <UseMsvcrt>false</UseMsvcrt>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <CppCompile Include="InjectResource.cpp" />
+ </ItemGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project> \ No newline at end of file
diff --git a/src/tools/crossgen/.gitmirror b/src/tools/crossgen/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/tools/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/tools/crossgen/Native.rc b/src/tools/crossgen/Native.rc
new file mode 100644
index 0000000000..c2eb725a5c
--- /dev/null
+++ b/src/tools/crossgen/Native.rc
@@ -0,0 +1,3 @@
+#define FX_VER_FILEDESCRIPTION_STR "Microsoft Common Language Runtime native cross compiler\0"
+
+#include "..\..\dlls\mscorrc\mscorrc.rc"
diff --git a/src/tools/crossgen/compare.bat b/src/tools/crossgen/compare.bat
new file mode 100644
index 0000000000..fcb506433b
--- /dev/null
+++ b/src/tools/crossgen/compare.bat
@@ -0,0 +1,186 @@
+::mscorlib
+::System
+::System.Core
+::System.Xml
+::System.Configuration
+::System.Drawing
+::System.Data
+::System.Windows.Forms
+::System.Runtime.Remoting
+::System.Serviceprocess
+::System.Management
+::Accessibility
+::Microsoft.VisualBasic
+::System.DirectoryServices
+::System.Transactions
+::System.Web.Services
+::CustomMarshalers
+::System.Configuration.Install
+::System.Xaml
+::WindowsBase
+::System.Net.Http
+::System.Xml.Linq
+::System.Runtime.WindowsRuntime
+::System.Runtime.WindowsRuntime.UI.Xaml
+::System.Runtime.Serialization
+::System.ServiceModel
+::PresentationCore
+::PresentationFramework
+::System.EnterpriseServices
+::System.Collections.Concurrent
+::System.Collections
+::System.ComponentModel.Annotations
+::System.ComponentModel
+::System.ComponentModel.EventBasedAsync
+::System.Diagnostics.Contracts
+::System.Diagnostics.Debug
+::System.Diagnostics.Tools
+::System.Diagnostics.Tracing
+::System.Dynamic.Runtime
+::System.Globalization
+::System.IO
+::System.Linq
+::System.Linq.Expressions
+::System.Linq.Parallel
+::System.Linq.Queryable
+::System.Net.Http.Rtc
+::System.Net.NetworkInformation
+::System.Net.Primitives
+::System.Net.Requests
+::System.ObjectModel
+::System.Reflection
+::System.Reflection.Emit
+::System.Reflection.Emit.ILGeneration
+::System.Reflection.Emit.Lightweight
+::System.Reflection.Extensions
+::System.Reflection.Primitives
+::System.Resources.ResourceManager
+::System.Runtime
+::System.Runtime.Extensions
+::System.Runtime.InteropServices
+::System.Runtime.InteropServices.WindowsRuntime
+::System.Runtime.Numerics
+::System.Runtime.Serialization.Json
+::System.Runtime.Serialization.Primitives
+::System.Runtime.Serialization.Xml
+::System.Security.Principal
+::System.ServiceModel.Duplex
+::System.ServiceModel.Http
+::System.ServiceModel.NetTcp
+::System.ServiceModel.Primitives
+::System.ServiceModel.Security
+::System.Text.Encoding
+::System.Text.Encoding.Extensions
+::System.Text.RegularExpressions
+::System.Threading
+::System.Threading.Tasks
+::System.Threading.Tasks.Parallel
+::System.Windows
+::System.Xml.ReaderWriter
+::System.Xml.XDocument
+::System.Xml.XmlSerializer
+::Windows.ApplicationModel
+::Windows.Data
+::Windows.Devices
+::Windows.Foundation
+::Windows.Globalization
+::Windows.Graphics
+::Windows.Management
+::Windows.Media
+::Windows.Networking
+::Windows.Security
+::Windows.Storage
+::Windows.System
+::Windows.UI
+::Windows.UI.Xaml
+::Windows.Web
+::END_OF_LIST
+
+@echo off
+
+rem
+rem This script compares ngen and crossgen output for framework assemblies
+rem
+
+SETLOCAL ENABLEDELAYEDEXPANSION
+
+set BITNESS=
+IF /I "%_BuildArch%" == "amd64" set BITNESS=64
+set FRAMEWORKDIR=%SYSTEMROOT%\Microsoft.NET\Framework%BITNESS%\%COMPLUS_Version%
+IF "%BITNESS%" == "" set BITNESS=32
+
+set NATIVEIMAGEPATH=%FRAMEWORKDIR%\assembly\NativeImages_%COMPLUS_Version%_%BITNESS%
+
+rem rmdir /S /Q %NATIVEIMAGEPATH%
+rem %FRAMEWORKDIR%\ngen install mscorlib
+rem %FRAMEWORKDIR%\ngen update
+
+%FRAMEWORKDIR%\gacutil /if %_NTTREE%\System.Runtime.WindowsRuntime.dll
+%FRAMEWORKDIR%\gacutil /if %_NTTREE%\System.Runtime.WindowsRuntime.UI.Xaml.dll
+
+set ILIMAGEPATH=%_NTTREE%\il
+rmdir /S /Q %ILIMAGEPATH%
+if not exist %ILIMAGEPATH% mkdir %ILIMAGEPATH%
+
+rem Collect all files from the GAC into ILIMAGEPATH directory to guaranteed that we get the exact same IL images
+rem between ngen and crossgen. It is important on non-x86 builds because of non-x86 layouts pull files from x86 build.
+forfiles /P %FRAMEWORKDIR%\assembly\GAC_%BITNESS% /M *.dll /S /C "cmd /c copy @path %ILIMAGEPATH%\@file > nul"
+forfiles /P %FRAMEWORKDIR%\assembly\GAC_MSIL /M *.dll /S /C "cmd /c copy @path %ILIMAGEPATH%\@file > nul"
+rem clr.dll and clrjit.dll are required for timestamps
+copy %FRAMEWORKDIR%\clr.dll %ILIMAGEPATH%\clr.dll >nul
+copy %FRAMEWORKDIR%\clrjit.dll %ILIMAGEPATH%\clrjit.dll >nul
+
+set CROSSGENIMAGEPATH=%_NTTREE%\ni
+rmdir /S /Q %CROSSGENIMAGEPATH%
+if not exist %CROSSGENIMAGEPATH% mkdir %CROSSGENIMAGEPATH%
+
+set WINMDPATH=%WINDIR%\System32\WinMetadata
+
+set SELF=%~fd0
+set FAILED=
+
+for /f "eol=; usebackq tokens=1,2,3* delims=,:" %%I in ("%SELF%") DO (
+ if "%%I"=="END_OF_LIST" goto LDone
+ call :ProcessFile %%I
+ if "!FAILED!"=="1" goto LFailed
+)
+
+:LDone
+echo DONE
+exit /B 0
+
+:LFailed
+echo FAILED
+exit /B 1
+
+:ProcessFile
+
+set FILEPATH=
+call :ProbeFile %ILIMAGEPATH%\%1.dll
+call :ProbeFile %WINMDPATH%\%1.winmd
+
+if "%FILEPATH%" == "" ( echo File not found: %1 & goto LError )
+
+echo.
+echo ========= COMPILE and COMPARE %1 ==========
+echo ngen install /nodependencies %FILEPATH%
+ngen install /nodependencies %FILEPATH%
+echo.
+echo %_NTTREE%\crossgen /platform_assemblies_paths %ILIMAGEPATH%;%CROSSGENIMAGEPATH% /Platform_Winmd_Paths %WINMDPATH% /in %FILEPATH% /out %CROSSGENIMAGEPATH%\%1.ni.dll
+%_NTTREE%\crossgen /platform_assemblies_paths %ILIMAGEPATH%;%CROSSGENIMAGEPATH% /Platform_Winmd_Paths %WINMDPATH% /in %FILEPATH% /out %CROSSGENIMAGEPATH%\%1.ni.dll
+IF NOT "%ERRORLEVEL%"=="0" set FAILED=1
+echo.
+forfiles /P %NATIVEIMAGEPATH% /M %1.ni.dll /S /C "cmd /c echo Compare: @path & fc /B @path %CROSSGENIMAGEPATH%\%1.ni.dll > %CROSSGENIMAGEPATH%\diff.txt & IF NOT ERRORLEVEL 1 del %CROSSGENIMAGEPATH%\diff.txt"
+IF not exist %CROSSGENIMAGEPATH%\diff.txt goto LExit
+echo ----- DIFFERENT -----
+:LError
+set FAILED=1
+goto LExit
+
+:ProbeFile
+if NOT "%FILEPATH%" == "" goto LExit
+if NOT exist "%1" goto LExit
+set FILEPATH=%1
+goto LExit
+
+:LExit
diff --git a/src/tools/crossgen/crossgen.cpp b/src/tools/crossgen/crossgen.cpp
new file mode 100644
index 0000000000..d1bbba80af
--- /dev/null
+++ b/src/tools/crossgen/crossgen.cpp
@@ -0,0 +1,989 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// 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.
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+
+#include <windows.h>
+#include <fxver.h>
+#include <mscorsvc.h>
+
+#include "palclr.h"
+
+#include <sstring.h>
+#include "ex.h"
+
+#include "coregen.h"
+#include "consoleargs.h"
+
+#define SEPARATOR_CHAR_W W('\\')
+#define SEPARATOR_STRING_W W("\\")
+
+// Return values from wmain() in case of error
+enum ReturnValues
+{
+ FAILURE_RESULT = 1,
+ CLR_INIT_ERROR = -2,
+ ASSEMBLY_NOT_FOUND = -3,
+ INVALID_ARGUMENTS = -4
+};
+
+#define NumItems(s) (sizeof(s) / sizeof(s[0]))
+
+STDAPI CreatePDBWorker(LPCWSTR pwzAssemblyPath, LPCWSTR pwzPlatformAssembliesPaths, LPCWSTR pwzTrustedPlatformAssemblies, LPCWSTR pwzPlatformResourceRoots, LPCWSTR pwzAppPaths, LPCWSTR pwzAppNiPaths, LPCWSTR pwzPdbPath, BOOL fGeneratePDBLinesInfo, LPCWSTR pwzManagedPdbSearchPath, LPCWSTR pwzPlatformWinmdPaths);
+STDAPI NGenWorker(LPCWSTR pwzFilename, DWORD dwFlags, LPCWSTR pwzPlatformAssembliesPaths, LPCWSTR pwzTrustedPlatformAssemblies, LPCWSTR pwzPlatformResourceRoots, LPCWSTR pwzAppPaths, LPCWSTR pwzOutputFilename=NULL, LPCWSTR pwzPlatformWinmdPaths=NULL, ICorSvcLogger *pLogger = NULL);
+void SetSvcLogger(ICorSvcLogger *pCorSvcLogger);
+#ifdef FEATURE_CORECLR
+void SetMscorlibPath(LPCWCHAR wzSystemDirectory);
+#endif
+
+/* --------------------------------------------------------------------------- *
+ * Console stuff
+ * --------------------------------------------------------------------------- */
+
+void Output(LPCWSTR str)
+{
+ wprintf(W("%s"), str);
+}
+
+void Outputf(LPCWSTR szFormat, ...)
+{
+ va_list args;
+ va_start(args, szFormat);
+ vwprintf(szFormat, args);
+ va_end(args);
+}
+
+void OutputErr(LPCWSTR str)
+{
+ fwprintf(stderr, W("%s"), str);
+}
+
+void OutputErrf(LPCWSTR szFormat, ...)
+{
+ va_list args;
+ va_start(args, szFormat);
+ vfwprintf(stderr, szFormat, args);
+ va_end(args);
+}
+
+void ErrorHR(HRESULT hr)
+{
+ OutputErrf(W("Error: failed to initialize CoreCLR: 0x%08x\n"), hr);
+}
+
+void ErrorWin32(DWORD err)
+{
+ ErrorHR(HRESULT_FROM_WIN32(err));
+}
+
+// Some error messages are useless to callers, so make them generic, except in debug builds, where we want as much
+// information as possible.
+
+#ifdef _DEBUG
+#define ERROR_HR(msg,hr) Outputf(msg, hr)
+#define ERROR_WIN32(msg,err) Outputf(msg, err)
+#else // _DEBUG
+#define ERROR_HR(msg,hr) ErrorHR(hr)
+#define ERROR_WIN32(msg,err) ErrorWin32(err)
+#endif // _DEBUG
+
+
+void PrintLogoHelper()
+{
+#ifdef FEATURE_CORECLR
+ Output(W("Microsoft (R) CoreCLR Native Image "));
+#else
+ Output(W("Microsoft (R) CLR Native Image "));
+#endif
+#ifdef MDIL
+ Output(W("/ MDIL "));
+#endif
+ Outputf(W("Generator - Version %S\n"), VER_FILEVERSION_STR);
+ Outputf(W("%S\n"), VER_LEGALCOPYRIGHT_LOGO_STR);
+ Output(W("\n"));
+}
+
+void PrintUsageHelper()
+{
+ // Always print the logo when we print the usage, even if they've specified /nologo and we've parsed that already.
+ PrintLogoHelper();
+
+ Output(
+ W("Usage: crossgen [args] <assembly name>\n")
+ W("\n")
+ W(" /? or /help - Display this screen\n")
+ W(" /nologo - Prevents displaying the logo\n")
+ W(" @response.rsp - Process command line arguments from specified\n")
+ W(" response file\n")
+ W(" /partialtrust - Assembly will be run in a partial trust domain.\n")
+ W(" /in <file> - Specifies input filename (optional)\n")
+#ifdef MDIL
+ W(" /out <file> - Specifies output filename (optional with native images,\n")
+ W(" required with MDIL)\n")
+#else
+ W(" /out <file> - Specifies output filename (optional)\n")
+#endif
+#ifdef FEATURE_CORECLR
+ W(" /Trusted_Platform_Assemblies <path[;path]>\n")
+ W(" - List of assemblies treated as trusted platform\n")
+ W(" - Cannot be used with Platform_Assemblies_Paths\n")
+ 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")
+ 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 // FEATURE_CORECLR
+
+ W(" /Platform_Assemblies_Paths\n")
+ W(" - List of paths containing target platform assemblies\n")
+#ifdef FEATURE_CORECLR
+ // If Platform_Assemblies_Paths, we will use it to build the TPA list and thus,
+ // TPA list cannot be explicitly specified.
+ W(" - Cannot be used with Trusted_Platform_Assemblies\n")
+#endif // FEATURE_CORECLR
+
+#ifdef FEATURE_COMINTEROP
+ W(" /Platform_Winmd_Paths\n")
+ W(" - List of paths containing target platform WinMDs used\n")
+ W(" for emulating RoResolveNamespace\n")
+#endif
+ W(" /MissingDependenciesOK\n")
+ W(" - Specifies that crossgen should attempt not to fail\n")
+ W(" if a dependency is missing.\n")
+#if 0
+ W(" /Tuning - Generate an instrumented image to collect\n")
+ W(" scenario traces, which can be used with ibcmerge.exe\n")
+#endif
+#ifdef FEATURE_READYTORUN_COMPILER
+ W(" /ReadyToRun - Generate images resilient to the runtime and\n")
+ W(" dependency versions\n")
+#endif
+#ifdef FEATURE_LEGACYNETCF
+ W(" Compatability Modes\n")
+ W(" /PreWP8App - Set the Windows Phone 8 \"Quirks\" mode, namely AppDomainCompatSwitch=\n")
+ W(" WindowsPhone_3.7.0.0 or WindowsPhone_3.8.0.0.\n")
+#endif
+#ifdef MDIL
+ W(" MDIL Generation Parameters\n")
+ W(" /mdil - Generate MDIL rather than native code. Requires presence of /out switch.\n")
+ W(" /nomdil - create MDIL image with no MDIL code or CTL data structures, use to force\n")
+ W(" fall back to JIT\n")
+ W(" /EmbedMDIL - Embed a previously created mdil data in IL image into native image.\n")
+ W(" /fxmdil - Generate framework assembly MDIL images containing minimal MDIL\n")
+#endif // MDIL
+#ifdef FEATURE_WINMD_RESILIENT
+ W(" WinMD Parameters\n")
+ W(" /WinMDResilient - Generate images resilient to WinMD dependency changes.\n")
+#endif
+#ifdef FEATURE_CORECLR
+ W(" Size on Disk Parameters\n")
+ W(" /NoMetaData - Do not copy metadata and IL into native image.\n")
+ 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 // FEATURE_CORECLR
+ );
+}
+
+class CrossgenLogger : public ICorSvcLogger
+{
+ STDMETHODIMP_(ULONG) AddRef() {return E_NOTIMPL;}
+ STDMETHODIMP_(ULONG) Release() {return E_NOTIMPL;}
+ STDMETHODIMP QueryInterface(REFIID riid,void ** ppv)
+ {
+ if (ppv==0)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, IID_ICorSvcLogger) || IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = this;
+ return S_OK;
+ }
+ else
+ {
+ return E_NOINTERFACE;
+ }
+ }
+
+ HRESULT STDMETHODCALLTYPE Log(
+ /*[in] */CorSvcLogLevel logLevel,
+ /*[in] */BSTR message
+ )
+ {
+ if (logLevel == LogLevel_Error)
+ OutputErr(message);
+ else
+ Output(message);
+ return S_OK;
+ }
+};
+
+CrossgenLogger g_CrossgenLogger;
+
+//
+// Tests whether szArg, the currently indexed argv matches the specified parameter name, szTestParamName.
+// Specify szTestParamName without a switch. This method handles testing for - and / switches.
+//
+bool MatchParameter(LPCWSTR szArg, LPCWSTR szTestParamName)
+{
+ if (wcslen(szArg) == 0)
+ {
+ return false;
+ }
+
+ if (szArg[0] != W('/') && szArg[0] != W('-'))
+ {
+ return false;
+ }
+
+ return !_wcsicmp(szArg + 1, szTestParamName) || !_wcsicmp(szArg + 1, szTestParamName);
+}
+
+//
+// Returns true if pwzString ends with the string in pwzCandidate
+// Ignores case
+//
+bool StringEndsWith(LPWSTR pwzString, LPWSTR pwzCandidate)
+{
+ size_t stringLength = wcslen(pwzString);
+ size_t candidateLength = wcslen(pwzCandidate);
+
+ if (candidateLength > stringLength || stringLength == 0 || candidateLength == 0)
+ {
+ return false;
+ }
+
+ LPWSTR pwzStringEnd = pwzString + stringLength - candidateLength;
+
+ return !_wcsicmp(pwzStringEnd, pwzCandidate);
+}
+
+#ifdef FEATURE_CORECLR
+//
+// When using the Phone binding model (TrustedPlatformAssemblies), automatically
+// detect which path mscorlib.[ni.]dll lies in.
+//
+bool ComputeMscorlibPathFromTrustedPlatformAssemblies(LPWSTR pwzMscorlibPath, DWORD cbMscorlibPath, LPCWSTR pwzTrustedPlatformAssemblies)
+{
+ LPWSTR wszTrustedPathCopy = new WCHAR[wcslen(pwzTrustedPlatformAssemblies) + 1];
+ wcscpy_s(wszTrustedPathCopy, wcslen(pwzTrustedPlatformAssemblies) + 1, pwzTrustedPlatformAssemblies);
+ LPWSTR wszSingleTrustedPath = wcstok(wszTrustedPathCopy, W(";"));
+
+ while (wszSingleTrustedPath != NULL)
+ {
+ size_t pathLength = wcslen(wszSingleTrustedPath);
+ // Strip off enclosing quotes, if present
+ if (wszSingleTrustedPath[0] == W('\"') && wszSingleTrustedPath[pathLength-1] == W('\"'))
+ {
+ wszSingleTrustedPath[pathLength-1] = '\0';
+ wszSingleTrustedPath++;
+ }
+
+ if (StringEndsWith(wszSingleTrustedPath, W("\\mscorlib.dll")) ||
+ StringEndsWith(wszSingleTrustedPath, W("\\mscorlib.ni.dll")))
+ {
+ wcscpy_s(pwzMscorlibPath, cbMscorlibPath, wszSingleTrustedPath);
+
+ LPWSTR pwzSeparator = wcsrchr(pwzMscorlibPath, W('\\'));
+ if (pwzSeparator == NULL)
+ {
+ delete [] wszTrustedPathCopy;
+ return false;
+ }
+ pwzSeparator[1] = W('\0'); // after '\'
+
+ delete [] wszTrustedPathCopy;
+ return true;
+ }
+
+ wszSingleTrustedPath = wcstok(NULL, W(";"));
+ }
+ delete [] wszTrustedPathCopy;
+
+ return false;
+}
+
+// Given a path terminated with "\\" and a search mask, this function will add
+// the enumerated files, corresponding to the search mask, from the path into
+// the refTPAList.
+void PopulateTPAList(SString path, LPWSTR pwszMask, SString &refTPAList, bool fCompilingMscorlib, bool fCreatePDB)
+{
+ _ASSERTE(path.GetCount() > 0);
+ ClrDirectoryEnumerator folderEnumerator(path.GetUnicode(), pwszMask);
+
+ while (folderEnumerator.Next())
+ {
+ // Got a valid enumeration handle and the data about the first file.
+ DWORD dwAttributes = folderEnumerator.GetFileAttributes();
+ if ((!(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (!(dwAttributes & FILE_ATTRIBUTE_DEVICE)))
+ {
+ bool fAddDelimiter = (refTPAList.GetCount() > 0)?true:false;
+ bool fAddFileToTPAList = true;
+ LPCWSTR pwszFilename = folderEnumerator.GetFileName();
+ if (fCompilingMscorlib)
+ {
+ // When compiling mscorlib.dll, no ".ni.dll" should be on the TPAList.
+ if (StringEndsWith((LPWSTR)pwszFilename, W(".ni.dll")))
+ {
+ fAddFileToTPAList = false;
+ }
+ }
+ else
+ {
+ // When creating PDBs, we must ensure that .ni.dlls are in the TPAList
+ if (!fCreatePDB)
+ {
+ // Only mscorlib.ni.dll should be in the TPAList for the compilation of non-mscorlib assemblies.
+ if (StringEndsWith((LPWSTR)pwszFilename, W(".ni.dll")))
+ {
+ if (!StringEndsWith((LPWSTR)pwszFilename, W("mscorlib.ni.dll")))
+ {
+ fAddFileToTPAList = false;
+ }
+ }
+ }
+
+ // Ensure that mscorlib.dll is also not on the TPAlist for this case.
+ if (StringEndsWith((LPWSTR)pwszFilename, W("mscorlib.dll")))
+ {
+ fAddFileToTPAList = false;
+ }
+ }
+
+ if (fAddFileToTPAList)
+ {
+ if (fAddDelimiter)
+ {
+ // Add the path delimiter if we already have entries in the TPAList
+ refTPAList.Append(W(";"));
+ }
+ // Add the path to the TPAList
+ refTPAList.Append(path);
+ refTPAList.Append(pwszFilename);
+ }
+ }
+ }
+ }
+
+// Given a semi-colon delimited set of absolute folder paths (pwzPlatformAssembliesPaths), this function
+// will enumerate all EXE/DLL modules in those folders and add them to the TPAList buffer (refTPAList).
+void ComputeTPAListFromPlatformAssembliesPath(LPCWSTR pwzPlatformAssembliesPaths, SString &refTPAList, bool fCompilingMscorlib, bool fCreatePDB)
+{
+ // We should have a valid pointer to the paths
+ _ASSERTE(pwzPlatformAssembliesPaths != NULL);
+
+ SString ssPlatformAssembliesPath(pwzPlatformAssembliesPaths);
+
+ // Platform Assemblies Path List is semi-colon delimited
+ if(ssPlatformAssembliesPath.GetCount() > 0)
+ {
+ SString::CIterator start = ssPlatformAssembliesPath.Begin();
+ SString::CIterator itr = ssPlatformAssembliesPath.Begin();
+ SString::CIterator end = ssPlatformAssembliesPath.End();
+ SString qualifiedPath;
+
+ while (itr != end)
+ {
+ start = itr;
+ BOOL found = ssPlatformAssembliesPath.Find(itr, W(';'));
+ if (!found)
+ {
+ itr = end;
+ }
+
+ SString qualifiedPath(ssPlatformAssembliesPath,start,itr);
+
+ if (found)
+ {
+ itr++;
+ }
+
+ unsigned len = qualifiedPath.GetCount();
+
+ if (len > 0)
+ {
+ if (qualifiedPath[len-1]!='\\')
+ {
+ qualifiedPath.Append('\\');
+ }
+
+ // Enumerate the EXE/DLL modules within this path and add them to the TPAList
+ EX_TRY
+ {
+ PopulateTPAList(qualifiedPath, W("*.exe"), refTPAList, fCompilingMscorlib, fCreatePDB);
+ PopulateTPAList(qualifiedPath, W("*.dll"), refTPAList, fCompilingMscorlib, fCreatePDB);
+ }
+ EX_CATCH
+ {
+ Outputf(W("Warning: Error enumerating files under %s.\n"), qualifiedPath.GetUnicode());
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+ }
+ }
+ }
+}
+#endif // FEATURE_CORECLR
+
+extern HMODULE g_hThisInst;
+
+int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv)
+{
+ g_hThisInst = WszGetModuleHandle(NULL);
+
+ /////////////////////////////////////////////////////////////////////////
+ //
+ // Parse the arguments
+ //
+ bool fDisplayLogo = true;
+ DWORD dwFlags = 0;
+ LPCWSTR pwzFilename = NULL;
+ LPCWSTR pwzPlatformResourceRoots = nullptr;
+ LPCWSTR pwzTrustedPlatformAssemblies = nullptr;
+ LPCWSTR pwzAppPaths = nullptr;
+ LPCWSTR pwzAppNiPaths = nullptr;
+ LPCWSTR pwzPlatformAssembliesPaths = nullptr;
+ LPCWSTR pwzPlatformWinmdPaths = nullptr;
+ WCHAR wzDirectoryToStorePDB[MAX_PATH] = W("\0");
+ bool fCreatePDB = false;
+ bool fGeneratePDBLinesInfo = false;
+ LPWSTR pwzSearchPathForManagedPDB = NULL;
+ LPCWSTR pwzOutputFilename = NULL;
+ LPCWSTR pwzPublicKeys = nullptr;
+
+ HRESULT hr;
+
+ // This is required to properly display Unicode characters
+ _setmode(_fileno(stdout), _O_U8TEXT);
+
+ // Skip this executable path
+ argv++;
+ argc--;
+
+ ConsoleArgs consoleArgs;
+ int argc2;
+ LPWSTR *argv2;
+
+ if (argc == 0)
+ {
+ PrintUsageHelper();
+ exit(INVALID_ARGUMENTS);
+ }
+
+ if (!consoleArgs.ExpandResponseFiles(argc, argv, &argc2, &argv2))
+ {
+ if (consoleArgs.ErrorMessage() != nullptr)
+ {
+ wprintf(consoleArgs.ErrorMessage());
+ exit(FAILURE_RESULT);
+ }
+ }
+
+ argc = argc2;
+ argv = argv2;
+
+ bool fCopySourceToOut = false;
+
+ // By default, Crossgen will assume code-generation for fulltrust domains unless /PartialTrust switch is specified
+ dwFlags |= NGENWORKER_FLAGS_FULLTRUSTDOMAIN;
+
+ while (argc > 0)
+ {
+ if (MatchParameter(*argv, W("?"))
+ || MatchParameter(*argv, W("help")))
+ {
+ PrintUsageHelper();
+ exit(INVALID_ARGUMENTS);
+ }
+ else if (MatchParameter(*argv, W("nologo")))
+ {
+ fDisplayLogo = false;
+ }
+ else if (MatchParameter(*argv, W("Tuning")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_TUNING;
+ }
+ else if (MatchParameter(*argv, W("MissingDependenciesOK")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_MISSINGDEPENDENCIESOK;
+ }
+ else if (MatchParameter(*argv, W("PartialTrust")))
+ {
+ // Clear the /fulltrust flag
+ dwFlags = dwFlags & ~NGENWORKER_FLAGS_FULLTRUSTDOMAIN;
+ }
+ else if (MatchParameter(*argv, W("FullTrust")))
+ {
+ // Keep the "/fulltrust" switch around but let it be no-nop. Without this, any usage of /fulltrust will result in crossgen command-line
+ // parsing failure. Considering that scripts all over (CLR, Phone Build, etc) specify that switch, we let it be as opposed to going
+ // and fixing all the scripts.
+ //
+ // We dont explicitly set the flag here again so that if "/PartialTrust" is specified, then it will successfully override the default
+ // fulltrust behaviour.
+ }
+#ifdef FEATURE_LEGACYNETCF
+ else if (MatchParameter(*argv, W("PreWP8App")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_APPCOMPATWP8;
+ }
+#endif
+#ifdef MDIL
+ else if (MatchParameter(*argv, W("mdil")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_CREATEMDIL;
+ }
+ else if (MatchParameter(*argv, W("fxmdil")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_MINIMAL_MDIL | NGENWORKER_FLAGS_CREATEMDIL;
+ }
+ else if (MatchParameter(*argv, W("EmbedMDIL")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_EMBEDMDIL;
+ }
+ else if (MatchParameter(*argv, W("NoMDIL")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_NOMDIL;
+ }
+#else // !MDIL
+ else if (MatchParameter(*argv, W("mdil")) || MatchParameter(*argv, W("fxmdil")) || MatchParameter(*argv, W("NoMDIL")))
+ {
+ // Copy the "in" file as the "out" file
+ fCopySourceToOut = true;
+ }
+ else if (MatchParameter(*argv, W("EmbedMDIL")))
+ {
+ // Dont do anything - simply generate the NI
+ }
+#endif
+#ifdef FEATURE_WINMD_RESILIENT
+ else if (MatchParameter(*argv, W("WinMDResilient")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_WINMD_RESILIENT;
+ }
+#endif
+#ifdef FEATURE_READYTORUN_COMPILER
+ else if (MatchParameter(*argv, W("ReadyToRun")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_READYTORUN;
+ }
+#endif
+#ifdef FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("NoMetaData")))
+ {
+ dwFlags |= NGENWORKER_FLAGS_NO_METADATA;
+ }
+#endif
+ else if (MatchParameter(*argv, W("out")))
+ {
+ if (pwzOutputFilename != NULL)
+ {
+ Output(W("Cannot specify multiple output files.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+ pwzOutputFilename = argv[1];
+ argv++;
+ argc--;
+ }
+ else if (MatchParameter(*argv, W("in")))
+ {
+ if (pwzFilename != NULL)
+ {
+ Output(W("Cannot specify multiple input files.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+ pwzFilename = argv[1];
+ argv++;
+ argc--;
+ }
+#ifdef FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("Trusted_Platform_Assemblies")) && (argc > 1))
+ {
+ pwzTrustedPlatformAssemblies = argv[1];
+
+ // skip path list
+ argv++;
+ argc--;
+ }
+ else if (MatchParameter(*argv, W("Platform_Resource_Roots")) && (argc > 1))
+ {
+ pwzPlatformResourceRoots = argv[1];
+
+ // skip path list
+ argv++;
+ argc--;
+ }
+ else if (MatchParameter(*argv, W("App_Paths")) && (argc > 1))
+ {
+ pwzAppPaths = argv[1];
+
+ // skip User app path
+ argv++;
+ argc--;
+ }
+ else if (MatchParameter(*argv, W("App_Ni_Paths")) && (argc > 1))
+ {
+ pwzAppNiPaths = argv[1];
+
+ // skip User app path
+ argv++;
+ argc--;
+ }
+#endif // FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("Platform_Assemblies_Paths")) && (argc > 1))
+ {
+ pwzPlatformAssembliesPaths = argv[1];
+
+ // skip path list
+ argv++;
+ argc--;
+ }
+#ifdef FEATURE_COMINTEROP
+ else if (MatchParameter(*argv, W("Platform_Winmd_Paths")) && (argc > 1))
+ {
+ pwzPlatformWinmdPaths = argv[1];
+
+ // skip User app path
+ argv++;
+ argc--;
+ }
+#endif // FEATURE_COMINTEROP
+#ifdef FEATURE_CORECLR
+ else if (MatchParameter(*argv, W("CreatePDB")) && (argc > 1))
+ {
+ // syntax: /CreatePDB <directory to store PDB> [/lines [<search path for managed PDB>] ]
+
+ // Parse: /CreatePDB
+ fCreatePDB = true;
+ argv++;
+ argc--;
+
+ // Clear the /fulltrust flag - /CreatePDB does not work with any other flags.
+ dwFlags = dwFlags & ~NGENWORKER_FLAGS_FULLTRUSTDOMAIN;
+
+ // Parse: <directory to store PDB>
+ if (wcscpy_s(
+ wzDirectoryToStorePDB,
+ _countof(wzDirectoryToStorePDB),
+ argv[0]) != 0)
+ {
+ Output(W("Unable to parse output directory to store PDB"));
+ exit(FAILURE_RESULT);
+ }
+ argv++;
+ argc--;
+
+ // Ensure output dir ends in a backslash, or else diasymreader has issues
+ if (wzDirectoryToStorePDB[wcslen(wzDirectoryToStorePDB)-1] != SEPARATOR_CHAR_W)
+ {
+ if (wcscat_s(
+ wzDirectoryToStorePDB,
+ _countof(wzDirectoryToStorePDB),
+ SEPARATOR_STRING_W) != 0)
+ {
+ Output(W("Unable to parse output directory to store PDB"));
+ exit(FAILURE_RESULT);
+ }
+ }
+
+ if (argc == 0)
+ {
+ Output(W("The /CreatePDB switch requires <directory to store PDB> and <assembly name>.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ // [/lines [<search path for managed PDB>] ]
+ if (MatchParameter(*argv, W("lines")) && (argc > 1))
+ {
+ // Parse: /lines
+ fGeneratePDBLinesInfo = true;
+ argv++;
+ argc--;
+
+ if (argc == 0)
+ {
+ Output(W("The /CreatePDB switch requires <directory to store PDB> and <assembly name>.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ if (argc > 1)
+ {
+ // Parse: <search path for managed PDB>
+ pwzSearchPathForManagedPDB = argv[0];
+ argv++;
+ argc--;
+ }
+ }
+
+ // Undo last arg iteration, since we do it for all cases at the bottom of
+ // the loop
+ argv--;
+ argc++;
+ }
+#endif // FEATURE_CORECLR
+ else
+ {
+ if (argc == 1)
+ {
+#if !defined(FEATURE_PAL)
+ // When not running on Mac, which can have forward-slash pathnames, we know
+ // a command switch here means an invalid argument.
+ if (*argv[0] == W('-') || *argv[0] == W('/'))
+ {
+ Outputf(W("Invalid parameter: %s\n"), *argv);
+ exit(INVALID_ARGUMENTS);
+ }
+#endif //!FEATURE_PAL
+ // The last thing on the command line is an assembly name or path, and
+ // because we got this far is not an argument like /nologo. Because this
+ // code works on Mac, with forward-slash pathnames, we can't assume
+ // anything with a forward slash is an argument. So we just always
+ // assume the last thing on the command line must be an assembly name.
+
+ if (pwzFilename != NULL)
+ {
+ Output(W("Cannot use /In and specify an input file as the last argument.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+
+ pwzFilename = *argv;
+ break;
+ }
+ else
+ {
+ Outputf(W("Invalid parameter: %s\n"), *argv);
+ exit(INVALID_ARGUMENTS);
+ }
+ }
+
+ argv++;
+ argc--;
+ }
+
+ if (pwzFilename == NULL)
+ {
+ Output(W("You must specify an assembly to compile\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+
+#ifdef MDIL
+ if (pwzOutputFilename == NULL)
+ {
+ if (dwFlags & NGENWORKER_FLAGS_CREATEMDIL)
+ {
+ Output(W("You must specify an output filename (/out <file>)\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+ }
+
+ if ((dwFlags & NGENWORKER_FLAGS_EMBEDMDIL) && (dwFlags & NGENWORKER_FLAGS_CREATEMDIL))
+ {
+ Output(W("The /EmbedMDIL switch cannot be used with the /mdil or /createmdil switch.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+
+ if ((dwFlags & NGENWORKER_FLAGS_NOMDIL) && !(dwFlags & NGENWORKER_FLAGS_CREATEMDIL))
+ {
+ Output(W("The /NoMDIL switch must be used with the /mdil or /createmdil switch.\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+#else // !MDIL
+ if (fCopySourceToOut == true)
+ {
+ if (pwzOutputFilename == NULL)
+ {
+ Output(W("You must specify an output filename (/out <file>)\n"));
+ exit(INVALID_ARGUMENTS);
+ }
+ if (CopyFileExW(pwzFilename, pwzOutputFilename, NULL, NULL, NULL, 0) == 0)
+ {
+ DWORD dwLastError = GetLastError();
+ OutputErrf(W("Error: x86 copy failed for \"%s\" (0x%08x)\n"), pwzFilename, HRESULT_FROM_WIN32(dwLastError));
+ }
+ else
+ {
+ Outputf(W("[x86] %s generated successfully\n"),pwzOutputFilename);
+ }
+
+ return 0;
+ }
+#endif //MDIL
+
+ if (fCreatePDB && (dwFlags != 0))
+ {
+ Output(W("The /CreatePDB switch cannot be used with other switches, except /lines and the various path switches.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ if (pwzAppNiPaths != nullptr && !fCreatePDB)
+ {
+ Output(W("The /App_Ni_Paths switch can only be used with the /CreatePDB switch.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+#if defined(FEATURE_CORECLR)
+ if ((pwzTrustedPlatformAssemblies != nullptr) && (pwzPlatformAssembliesPaths != nullptr))
+ {
+ Output(W("The /Trusted_Platform_Assemblies and /Platform_Assemblies_Paths switches cannot be both specified.\n"));
+ exit(FAILURE_RESULT);
+ }
+
+ if ((dwFlags & NGENWORKER_FLAGS_NO_METADATA) != 0)
+ {
+ const size_t windowsDotWinmdLength = 13; // Length of string "Windows.winmd"
+ size_t filenameLength = wcslen(pwzFilename);
+ bool isWindowsDotWinmd = true;
+ if (filenameLength < windowsDotWinmdLength ||
+ _wcsicmp(pwzFilename + filenameLength - windowsDotWinmdLength, W("windows.winmd")) != 0)
+ {
+ isWindowsDotWinmd = false;
+ }
+ else if (filenameLength > windowsDotWinmdLength)
+ {
+ WCHAR pathSeparator = pwzFilename[filenameLength - windowsDotWinmdLength - 1];
+ if (pathSeparator != W('\\') && pathSeparator != W('/') && pathSeparator != W(':'))
+ {
+ isWindowsDotWinmd = false;
+ }
+ }
+ if (!isWindowsDotWinmd)
+ {
+ Output(W("The /NoMetaData switch can only be used with Windows.winmd.\n"));
+ exit(FAILURE_RESULT);
+ }
+ }
+#endif // FEATURE_CORESYSTEM
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ if (((dwFlags & NGENWORKER_FLAGS_TUNING) != 0) && ((dwFlags & NGENWORKER_FLAGS_READYTORUN) != 0))
+ {
+ Output(W("The /Tuning switch cannot be used with /ReadyToRun switch.\n"));
+ exit(FAILURE_RESULT);
+ }
+#endif
+
+ // All argument processing has happened by now. The only messages that should appear before here are errors
+ // related to argument parsing, such as the Usage message. Afterwards, other messages can appear.
+
+ /////////////////////////////////////////////////////////////////////////
+ //
+ // Start processing
+ //
+
+ if (fDisplayLogo)
+ {
+ PrintLogoHelper();
+ }
+
+ WCHAR wzTrustedPathRoot[MAX_PATH];
+
+#ifdef FEATURE_CORECLR
+ SString ssTPAList;
+
+ // Are we compiling mscorlib.dll?
+ bool fCompilingMscorlib = StringEndsWith((LPWSTR)pwzFilename, W("mscorlib.dll"));
+
+ if(pwzPlatformAssembliesPaths != nullptr)
+ {
+ // Platform_Assemblies_Paths command line switch has been specified.
+ _ASSERTE(pwzTrustedPlatformAssemblies == nullptr);
+
+ // Formulate the TPAList from Platform_Assemblies_Paths
+ ComputeTPAListFromPlatformAssembliesPath(pwzPlatformAssembliesPaths, ssTPAList, fCompilingMscorlib, fCreatePDB);
+ pwzTrustedPlatformAssemblies = (WCHAR *)ssTPAList.GetUnicode();
+ pwzPlatformAssembliesPaths = NULL;
+ }
+
+ if (pwzTrustedPlatformAssemblies != nullptr)
+ {
+ if (ComputeMscorlibPathFromTrustedPlatformAssemblies(wzTrustedPathRoot, MAX_PATH, pwzTrustedPlatformAssemblies))
+ {
+ pwzPlatformAssembliesPaths = wzTrustedPathRoot;
+ SetMscorlibPath(pwzPlatformAssembliesPaths);
+ }
+ }
+#endif // FEATURE_CORECLR
+
+ if (pwzPlatformAssembliesPaths == NULL)
+ {
+ if (!WszGetModuleFileName(NULL, wzTrustedPathRoot, MAX_PATH))
+ {
+ ERROR_WIN32(W("Error: GetModuleFileName failed (%d)\n"), GetLastError());
+ exit(CLR_INIT_ERROR);
+ }
+
+ wchar_t* pszSep = wcsrchr(wzTrustedPathRoot, SEPARATOR_CHAR_W);
+ if (pszSep == NULL)
+ {
+ ERROR_HR(W("Error: wcsrchr returned NULL; GetModuleFileName must have given us something bad\n"), E_UNEXPECTED);
+ exit(CLR_INIT_ERROR);
+ }
+ *pszSep = '\0';
+
+ pwzPlatformAssembliesPaths = wzTrustedPathRoot;
+ }
+
+ // Initialize the logger
+ SetSvcLogger(&g_CrossgenLogger);
+
+ //Step - Compile the assembly
+
+ if (fCreatePDB)
+ {
+ hr = CreatePDBWorker(
+ pwzFilename,
+ pwzPlatformAssembliesPaths,
+ pwzTrustedPlatformAssemblies,
+ pwzPlatformResourceRoots,
+ pwzAppPaths,
+ pwzAppNiPaths,
+ wzDirectoryToStorePDB,
+ fGeneratePDBLinesInfo,
+ pwzSearchPathForManagedPDB,
+ pwzPlatformWinmdPaths);
+
+ }
+ else
+ {
+ hr = NGenWorker(pwzFilename, dwFlags,
+ pwzPlatformAssembliesPaths,
+ pwzTrustedPlatformAssemblies,
+ pwzPlatformResourceRoots,
+ pwzAppPaths,
+ pwzOutputFilename,
+ pwzPlatformWinmdPaths
+ );
+ }
+
+
+ if (FAILED(hr))
+ {
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ OutputErrf(W("Error: file \"%s\" or one of its dependencies was not found\n"), pwzFilename);
+ exit(ASSEMBLY_NOT_FOUND);
+ }
+ else
+ {
+ OutputErrf(W("Error: compilation failed for \"%s\" (0x%08x)\n"), pwzFilename, hr);
+ exit(hr);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/tools/crossgen/crossgen.nativeproj b/src/tools/crossgen/crossgen.nativeproj
new file mode 100644
index 0000000000..da37792489
--- /dev/null
+++ b/src/tools/crossgen/crossgen.nativeproj
@@ -0,0 +1,97 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE</ClAdditionalOptions>
+ <OutputName>crossgen</OutputName>
+ <TargetType>PROGRAM</TargetType>
+ <LinkSubsystem>console</LinkSubsystem>
+ <EntryPoint>wmain</EntryPoint>
+ <LinkGenerateManifest>true</LinkGenerateManifest>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /MANIFEST</LinkAdditionalOptions>
+ <UserIncludes>$(UserIncludes);$(ClrSrcDirectory)tools\util</UserIncludes>
+ <IsDesktopTool>true</IsDesktopTool>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <TargetLib Include="$(SdkLibPath)\ole32.lib" />
+ <TargetLib Include="$(SdkLibPath)\oleaut32.lib" />
+ <TargetLib Include="$(SdkLibPath)\uuid.lib" />
+ <TargetLib Include="$(SdkLibPath)\user32.lib" />
+ <TargetLib Include="$(SdkLibPath)\version.lib" />
+ <TargetLib Include="$(SdkLibPath)\shlwapi.lib" />
+ <TargetLib Include="$(SdkLibPath)\bcrypt.lib" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <TargetLib Condition="'$(_BuildArch)' != 'amd64'" Include="$(ClrLibPath)\corguids_x86.lib">
+ <ProjectReference>$(ClrSrcDirectory)incx86\corguids.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Condition="'$(_BuildArch)' == 'amd64'" Include="$(ClrLibPath)\corguids_amd64.lib">
+ <ProjectReference>$(ClrSrcDirectory)incamd64\corguids.nativeproj</ProjectReference>
+ </TargetLib>
+ <LinkPreCrtLibs Include="$(ClrLibPath)\utilcode_crossgen.lib" />
+ <TargetLib Include="$(ClrLibPath)\utilcode_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)utilcode\crossgen\utilcode_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\corzap_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)zap\crossgen\zap_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+
+ <TargetLib Condition="'$(MDILGenerator)' != 'true'" Include="$(ClrLibPath)\jit_crossgen.lib">
+ <ProjectReference Condition="'$(_BuildArch)' != 'amd64' and '$(_BuildArch)' != 'arm64'">$(ClrSrcDirectory)jit32\crossgen\jit_crossgen.nativeproj</ProjectReference>
+ <ProjectReference Condition="'$(_BuildArch)' == 'amd64' or '$(_BuildArch)' == 'arm64'">$(ClrSrcDirectory)jit\crossgen\jit_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+
+ <TargetLib Condition="'$(MDILGenerator)' == 'true'" Include="$(ClrLibPath)\jitmdil_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)jitmdil\crossgen\jit_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+
+ <TargetLib Include="$(ClrLibPath)\gcinfo_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)gcinfo\crossgen\gcinfo_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\gcdump_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)gcdump\crossgen\gcdump_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\strongname_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)strongname\api\crossgen\strongname_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdcompiler_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\compiler\crossgen\mdcompiler_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdwinmd_crossgen.lib" Condition="'$(FeatureCominterop)' == 'true'">
+ <ProjectReference>$(ClrSrcDirectory)md\winmd\crossgen\mdwinmd_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdruntimerw_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\enc\crossgen\mdruntimerw_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdhotdata_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\hotdata\crossgen\mdhotdata_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mdruntime_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)md\runtime\crossgen\mdruntime_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\cee_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)vm\crossgen\wks_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\mscorlib_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)vm\crossgen_mscorlib\mscorlib_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Include="$(ClrLibPath)\v3binder_crossgen.lib">
+ <ProjectReference>$(ClrSrcDirectory)binder\v3binder_crossgen\v3binder_crossgen.nativeproj</ProjectReference>
+ </TargetLib>
+ </ItemGroup>
+ <ItemGroup>
+ <RCResourceFile Include="native.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <CppCompile Include="crossgen.cpp" />
+ <CppCompile Include="$(ClrSrcDirectory)\tools\util\consoleargs.cpp" />
+ </ItemGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+
+</Project>
diff --git a/src/tools/dirs.proj b/src/tools/dirs.proj
new file mode 100644
index 0000000000..2a17d6d703
--- /dev/null
+++ b/src/tools/dirs.proj
@@ -0,0 +1,68 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1' and '$(FeatureCoreClr)' != 'true'">
+ <ProjectFile Include="allocationsprofiler\allocationsprofiler.nativeproj" />
+ <ProjectFile Include="appcompatgenerator\appcompatgenerator.nativeproj" />
+ <ProjectFile Include="applaunch\applaunch.nativeproj" />
+ <ProjectFile Include="asmlist\asmlist.nativeproj" />
+ <ProjectFile Include="asmmeta\asmmeta.nativeproj" />
+ <ProjectFile Include="bbsweep\bbsweep.nativeproj" />
+ <ProjectFile Include="bindingsnapshot\bindingsnapshot.nativeproj" />
+ <ProjectFile Include="clrver\clrver.nativeproj" />
+ <ProjectFile Include="cordmpmerge\cordmpmerge.nativeproj" />
+ <ProjectFile Include="corflags\corflags.nativeproj" />
+ <ProjectFile Include="fixpdbpath\fixpdbpath.nativeproj" />
+ <ProjectFile Include="gac\dirs.proj" />
+ <ProjectFile Include="installhook\dirs.proj" />
+ <ProjectFile Include="ismgd\ismgd.nativeproj" />
+ <ProjectFile Include="jitmanager\jitmgr.nativeproj" />
+ <ProjectFile Include="ldr64\ldr64.nativeproj" Condition="'$(BuildArchitecture)' == 'amd64'" />
+ <ProjectFile Include="logdiff\Logdiff.csproj" />
+ <ProjectFile Include="mdepends\mdepends.nativeproj" />
+ <ProjectFile Include="metainfo\metainfo.nativeproj" />
+ <ProjectFile Include="ngen\ngen.nativeproj" />
+ <ProjectFile Include="ngenoffline\ngenoffline.nativeproj" />
+ <ProjectFile Include="nidump\nidump.nativeproj" />
+ <ProjectFile Include="ndpsetup\ndpsetup.nativeproj" />
+ <ProjectFile Include="peverify\dirs.proj" />
+ <ProjectFile Include="profpick\profpick.nativeproj" />
+ <ProjectFile Include="regtlb\regtlb.nativeproj" />
+ <ProjectFile Include="resetdelaysign\resetdelaysign.nativeproj" />
+ <ProjectFile Include="showname\showname.nativeproj" />
+ <ProjectFile Include="strikers\strikers.nativeproj" />
+ <ProjectFile Include="tlbref\tlbref.nativeproj" />
+ <ProjectFile Include="verifyasmhash\verifyasmhash.nativeproj" />
+ <ProjectFile Include="verstamp\verstamp.nativeproj" Condition="'$(BuildArchitecture)' == 'i386'" />
+ <ProjectFile Include="ngentask\ngentask.csproj"/>
+ <ProjectFile Include="ngentasklauncher\ngentasklauncher.csproj"/>
+ <ProjectFile Include="McjProfofileUtil\McjProfileUtil.csproj" Condition="'$(BuildArchitecture)' != 'arm' and '$(BuildArchitecture)' != 'arm64'" />
+ <ProjectFile Include="winphoneintegrate\winphoneintegrate.csproj" />
+ <ProjectFile Include="crossgen\crossgen.nativeproj" />
+ <ProjectFile Include="GenClrDebugResource\GenClrDebugResource.nativeproj" />
+ </ItemGroup>
+
+ <!-- CoreClr -->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1' and '$(FeatureCoreClr)' == 'true'">
+ <ProjectFile Include="bbsweep\bbsweep.nativeproj" Condition="'$(BuildProjectName)' == 'CoreSys'" />
+ <ProjectFile Condition="'$(BuildArchitecture)' != 'arm' and '$(BuildArchitecture)' != 'arm64' and '$(BuildProjectName)' != 'CoreSys'" Include="ildbsymbols\ildbsymbols.nativeproj" />
+ <ProjectFile Include="coregen\coregen.nativeproj" />
+ <ProjectFile Include="nidump\nidump.nativeproj" Condition="!('$(BuildProjectName)' == 'CoreSys' and ('$(BuildArchitecture)' == 'arm' or '$(BuildArchitecture)' == 'arm64'))"/>
+ <ProjectFile Include="MDILBind\dirs.proj" Condition="'$(BuildArchitecture)' == 'arm'" />
+ <ProjectFile Include="mdilxapcompile\mdilxapcompile.csproj" />
+ <ProjectFile Include="crossgen\crossgen.nativeproj" />
+ <ProjectFile Include="spawnnowow\spawnnowow.nativeproj" Condition="('$(BuildArchitecture)' == 'i386' or '$(BuildArchitecture)' == 'amd64' or '$(BuildArchitecture)' == 'ia64') and '$(BuildProjectName)' != 'CoreSys'" />
+ <ProjectFile Condition="'$(BuildProjectName)' == 'CoreSys'" Include="winphoneintegrate\winphoneintegrate.csproj" />
+ </ItemGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>