diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/tools | |
download | coreclr-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/.gitmirror | 1 | ||||
-rw-r--r-- | src/tools/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/tools/GenClrDebugResource/.gitmirror | 1 | ||||
-rw-r--r-- | src/tools/GenClrDebugResource/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/tools/GenClrDebugResource/GenClrDebugResource.cpp | 220 | ||||
-rw-r--r-- | src/tools/GenClrDebugResource/GenClrDebugResource.nativeproj | 24 | ||||
-rw-r--r-- | src/tools/InjectResource/.gitmirror | 1 | ||||
-rw-r--r-- | src/tools/InjectResource/CMakeLists.txt | 9 | ||||
-rw-r--r-- | src/tools/InjectResource/InjectResource.cpp | 158 | ||||
-rw-r--r-- | src/tools/InjectResource/InjectResource.nativeproj | 24 | ||||
-rw-r--r-- | src/tools/crossgen/.gitmirror | 1 | ||||
-rw-r--r-- | src/tools/crossgen/Native.rc | 3 | ||||
-rw-r--r-- | src/tools/crossgen/compare.bat | 186 | ||||
-rw-r--r-- | src/tools/crossgen/crossgen.cpp | 989 | ||||
-rw-r--r-- | src/tools/crossgen/crossgen.nativeproj | 97 | ||||
-rw-r--r-- | src/tools/dirs.proj | 68 |
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> |