diff --git a/VisualFSharp.sln b/VisualFSharp.sln
index 0e584f0c9fa..5f0ba007e8f 100644
--- a/VisualFSharp.sln
+++ b/VisualFSharp.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.27102.0
+VisualStudioVersion = 15.0.27116.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Private", "src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj", "{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}"
EndProject
@@ -138,6 +138,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceFile", "vsintegrati
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Build.UnitTests", "src\fsharp\FSharp.Build.UnitTests\FSharp.Build.UnitTests.fsproj", "{400FAB03-786E-40CC-85A8-04B0C2869B14}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PEVerify", "tests\fsharpqa\testenv\src\PEVerify\PEVerify.csproj", "{B0689A4E-07D8-494D-A0C8-791CB1D74E54}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -760,6 +762,18 @@ Global
{400FAB03-786E-40CC-85A8-04B0C2869B14}.Release|Any CPU.Build.0 = Release|Any CPU
{400FAB03-786E-40CC-85A8-04B0C2869B14}.Release|x86.ActiveCfg = Release|Any CPU
{400FAB03-786E-40CC-85A8-04B0C2869B14}.Release|x86.Build.0 = Release|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|x86.Build.0 = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|x86.Build.0 = Debug|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|x86.ActiveCfg = Release|Any CPU
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -823,6 +837,7 @@ Global
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B} = {35636A82-401A-4C3A-B2AB-EB7DC5E9C268}
{0385564F-07B4-4264-AB8A-17C393E9140C} = {F6DAEE9A-8BE1-4C4A-BC83-09215517C7DA}
{400FAB03-786E-40CC-85A8-04B0C2869B14} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {B0689A4E-07D8-494D-A0C8-791CB1D74E54} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {48EDBBBE-C8EE-4E3C-8B19-97184A487B37}
diff --git a/build-everything.proj b/build-everything.proj
index b171c83ae04..07e2fcbc687 100644
--- a/build-everything.proj
+++ b/build-everything.proj
@@ -73,11 +73,17 @@
+
+
+
+
+
+
@@ -112,4 +118,9 @@
+
+
+
+
+
diff --git a/build.cmd b/build.cmd
index 88c6be98fa1..1cf2de6040e 100644
--- a/build.cmd
+++ b/build.cmd
@@ -664,8 +664,11 @@ if "%BUILD_PROTO%" == "1" (
echo ---------------- Done with proto, starting build ------------------------
if "%BUILD_PHASE%" == "1" (
- echo %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN%
- %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN%
+ echo %_msbuildexe% %msbuildflags% build-everything.proj /t:Restore
+ %_msbuildexe% %msbuildflags% build-everything.proj /t:Restore
+
+ echo %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN%
+ %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN%
@if ERRORLEVEL 1 echo Error build failed && goto :failure
)
diff --git a/tests/fsharp/test-framework.fs b/tests/fsharp/test-framework.fs
index 5753bc1bbcb..5bb3776e8d3 100644
--- a/tests/fsharp/test-framework.fs
+++ b/tests/fsharp/test-framework.fs
@@ -106,7 +106,6 @@ module Commands =
type TestConfig =
{ EnvironmentVariables : Map
CORDIR : string
- CORSDK : string
CSC : string
csc_flags : string
BUILD_CONFIG : string
@@ -132,7 +131,7 @@ module WindowsPlatform =
[| "PROCESSOR_ARCHITECTURE" |] |> Seq.tryPick (fun s -> find s) |> function None -> "" | Some x -> x
value = "AMD64"
- let clrPaths envVars =
+ let clrPath envVars =
let windir =
match envVars |> Map.tryFind "windir" with
@@ -149,15 +148,7 @@ module WindowsPlatform =
if Is64BitOperatingSystem envVars then
CORDIR <- CORDIR.Replace("Framework", "Framework64")
- let CORSDK =
- let find s = envVars |> Map.tryFind s
- [| "WINSDKNETFXTOOLS"; "WindowsSDK_ExecutablePath_x64"; "WindowsSDK_ExecutablePath_x86" |]
- |> Seq.tryPick find
- |> function
- | None -> @"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\"
- | Some x -> x
-
- CORDIR, CORSDK
+ CORDIR
type FSLibPaths =
{ FSCOREDLLPATH : string }
@@ -173,13 +164,13 @@ let config configurationName envVars =
let csc_flags = "/nologo"
let fsc_flags = "-r:System.Core.dll --nowarn:20 --define:COMPILED"
let fsi_flags = "-r:System.Core.dll --nowarn:20 --define:INTERACTIVE --maxerrors:1 --abortonerror"
- let CORDIR, CORSDK = WindowsPlatform.clrPaths envVars
+ let CORDIR = WindowsPlatform.clrPath envVars
let Is64BitOperatingSystem = WindowsPlatform.Is64BitOperatingSystem envVars
let architectureMoniker = if Is64BitOperatingSystem then "x64" else "x86"
let CSC = requireFile (CORDIR ++ "csc.exe")
let ILDASM = requireFile (packagesDir ++ ("runtime.win-" + architectureMoniker + ".Microsoft.NETCore.ILDAsm.2.0.3") ++ "runtimes" ++ ("win-" + architectureMoniker) ++ "native" ++ "ildasm.exe")
let coreclrdll = requireFile (packagesDir ++ ("runtime.win-" + architectureMoniker + ".Microsoft.NETCore.Runtime.CoreCLR.2.0.3") ++ "runtimes" ++ ("win-" + architectureMoniker) ++ "native" ++ "coreclr.dll")
- let PEVERIFY = requireFile (CORSDK ++ "peverify.exe")
+ let PEVERIFY = requireFile (SCRIPT_ROOT ++ ".." ++ "fsharpqa" ++ "testenv" ++ "src" ++ "PEVerify" ++ "bin" ++ configurationName ++ "net46" ++ "PEVerify.exe")
let FSI_FOR_SCRIPTS =
match envVars |> Map.tryFind "_fsiexe" with
| Some fsiexe when (not (String.IsNullOrWhiteSpace fsiexe)) -> requireFile (SCRIPT_ROOT ++ ".." ++ ".." ++ (fsiexe.Trim([| '\"' |])))
@@ -214,7 +205,6 @@ let config configurationName envVars =
{ EnvironmentVariables = envVars
CORDIR = CORDIR |> Commands.pathAddBackslash
- CORSDK = CORSDK |> Commands.pathAddBackslash
FSCBinPath = FSCBinPath |> Commands.pathAddBackslash
FSCOREDLLPATH = FSCOREDLLPATH
ILDASM = ILDASM
@@ -236,7 +226,6 @@ let logConfig (cfg: TestConfig) =
log "Executables"
log ""
log "CORDIR =%s" cfg.CORDIR
- log "CORSDK =%s" cfg.CORSDK
log "CSC =%s" cfg.CSC
log "BUILD_CONFIG =%s" cfg.BUILD_CONFIG
log "csc_flags =%s" cfg.csc_flags
diff --git a/tests/fsharpqa/Source/run.pl b/tests/fsharpqa/Source/run.pl
index f168f6415ab..c999def6387 100644
--- a/tests/fsharpqa/Source/run.pl
+++ b/tests/fsharpqa/Source/run.pl
@@ -264,11 +264,14 @@
# check/set PEVerify
my $PEVERIFY = $ENV{PEVERIFY};
unless(defined($PEVERIFY)) {
- # Only use peverify if it is in the path
- foreach $_ (split /;/, $ENV{PATH}) {
- $PEVERIFY = "peverify.exe" if(-e "$_\\peverify.exe");
+ my $scriptPath = dirname(__FILE__);
+ $PEVERIFY = "$scriptPath\\..\\testenv\\src\\PEVerify\\bin\\Release\\net46\\PEVerify.exe";
+ if (-e $PEVERIFY) {
+ $ENV{PEVERIFY} = $PEVERIFY;
+ }
+ else {
+ $ENV{PEVERIFY} = "$scriptPath\\..\\testenv\\src\\PEVerify\\bin\\Debug\\net46\\PEVerify.exe";
}
- $ENV{PEVERIFY} = $PEVERIFY;
}
# Use $ENV{PEVER} if it is defined
diff --git a/tests/fsharpqa/testenv/src/PEVerify/CLRHelpers.cs b/tests/fsharpqa/testenv/src/PEVerify/CLRHelpers.cs
new file mode 100644
index 00000000000..be1d8346efb
--- /dev/null
+++ b/tests/fsharpqa/testenv/src/PEVerify/CLRHelpers.cs
@@ -0,0 +1,344 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+// ported from https://github.com/dotnet/roslyn/blob/aaee215045c03c4f4b38a66b56d35261ee7f0ddc/src/Test/Utilities/Portable/Platform/Desktop/CLRHelpers.cs
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using PEVerify;
+using Roslyn.Test.Utilities.Desktop.ComTypes;
+
+namespace Roslyn.Test.Utilities.Desktop
+{
+ public static class CLRHelpers
+ {
+ private static readonly Guid s_clsIdClrRuntimeHost = new Guid("90F1A06E-7712-4762-86B5-7A5EBA6BDB02");
+ private static readonly Guid s_clsIdCorMetaDataDispenser = new Guid("E5CB7A31-7512-11d2-89CE-0080C792E5D8");
+
+ public static event ResolveEventHandler ReflectionOnlyAssemblyResolve;
+
+ static CLRHelpers()
+ {
+ // Work around CLR bug:
+ // PE Verifier adds a handler to ReflectionOnlyAssemblyResolve event in AppDomain.EnableResolveAssembliesForIntrospection
+ // (called from ValidateWorker in Validator.cpp) in which it directly calls Assembly.ReflectionOnlyLoad.
+ // If that happens before we get a chance to resolve the assembly the resolution fails.
+ //
+ // The handlers are invoked in the order they were added until one of them returns non-null assembly.
+ // Therefore once we call Validate we can't add any more handlers -- they would all follow the CLR one, which fails.
+ //
+ // As A workaround we add a single forwarding handler before any calls to Validate and then subscribe all of our true handlers
+ // to this event.
+ AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ReflectionOnlyAssemblyResolveHandler;
+ }
+
+ private static Assembly ReflectionOnlyAssemblyResolveHandler(object sender, ResolveEventArgs args)
+ {
+ var handler = ReflectionOnlyAssemblyResolve;
+ if (handler != null)
+ {
+ return handler(sender, args);
+ }
+
+ return null;
+ }
+
+ public static object GetRuntimeInterfaceAsObject(Guid clsid, Guid riid)
+ {
+ // This API isn't available on Mono hence we must use reflection to access it.
+ Debug.Assert(!MonoHelpers.IsRunningOnMono());
+
+ var getRuntimeInterfaceAsObject = typeof(RuntimeEnvironment).GetMethod("GetRuntimeInterfaceAsObject", BindingFlags.Public | BindingFlags.Static);
+ return getRuntimeInterfaceAsObject.Invoke(null, new object[] { clsid, riid });
+ }
+
+ ///
+ /// Verifies the specified image. Subscribe to to provide a loader for dependent assemblies.
+ ///
+ public static string[] PeVerify(byte[] peImage, bool metadataOnly)
+ {
+ // fileName must be null, otherwise AssemblyResolve events won't fire
+ return PeVerify(peImage, AppDomain.CurrentDomain.Id, assemblyPath: null, metadataOnly: metadataOnly);
+ }
+
+ ///
+ /// Verifies the specified file. All dependencies must be on disk next to the file.
+ ///
+ public static string[] PeVerify(string filePath, bool metadataOnly)
+ {
+ return PeVerify(File.ReadAllBytes(filePath), AppDomain.CurrentDomain.Id, filePath, metadataOnly: metadataOnly);
+ }
+
+ private static readonly object s_guard = new object();
+
+ private static string[] PeVerify(byte[] peImage, int domainId, string assemblyPath, bool metadataOnly)
+ {
+ if (MonoHelpers.IsRunningOnMono())
+ {
+ // PEverify is currently unsupported on Mono hence return an empty
+ // set of messages
+ return new string[0];
+ }
+
+ lock (s_guard)
+ {
+ GCHandle pinned = GCHandle.Alloc(peImage, GCHandleType.Pinned);
+ try
+ {
+ IntPtr buffer = pinned.AddrOfPinnedObject();
+
+ ICLRValidator validator = (ICLRValidator)GetRuntimeInterfaceAsObject(s_clsIdClrRuntimeHost, typeof(ICLRRuntimeHost).GUID);
+ ValidationErrorHandler errorHandler = new ValidationErrorHandler(validator);
+
+ IMetaDataDispenser dispenser = (IMetaDataDispenser)GetRuntimeInterfaceAsObject(s_clsIdCorMetaDataDispenser, typeof(IMetaDataDispenser).GUID);
+
+ // the buffer needs to be pinned during validation
+ Guid riid = typeof(IMetaDataImport).GUID;
+ object metaDataImport = null;
+ if (assemblyPath != null)
+ {
+ dispenser.OpenScope(assemblyPath, CorOpenFlags.ofRead, ref riid, out metaDataImport);
+ }
+ else
+ {
+ dispenser.OpenScopeOnMemory(buffer, (uint)peImage.Length, CorOpenFlags.ofRead, ref riid, out metaDataImport);
+ }
+
+ IMetaDataValidate metaDataValidate = (IMetaDataValidate)metaDataImport;
+ metaDataValidate.ValidatorInit(CorValidatorModuleType.ValidatorModuleTypePE, errorHandler);
+ metaDataValidate.ValidateMetaData();
+
+ if (!metadataOnly)
+ {
+ validator.Validate(errorHandler, (uint)domainId, ValidatorFlags.VALIDATOR_EXTRA_VERBOSE,
+ ulMaxError: 10, token: 0, fileName: assemblyPath, pe: buffer, ulSize: (uint)peImage.Length);
+ }
+
+ return errorHandler.GetOutput();
+ }
+ finally
+ {
+ pinned.Free();
+ }
+ }
+ }
+
+ private class ValidationErrorHandler : IVEHandler
+ {
+ private readonly ICLRValidator _validator;
+ private readonly List _output;
+ private const int MessageLength = 256;
+
+ public ValidationErrorHandler(ICLRValidator validator)
+ {
+ _validator = validator;
+ _output = new List();
+ }
+
+ public void SetReporterFtn(long lFnPtr)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void VEHandler(int VECode, tag_VerError Context, Array psa)
+ {
+ StringBuilder sb = new StringBuilder(MessageLength);
+ string message = null;
+
+ if (Context.Flags == (uint)ValidatorFlags.VALIDATOR_CHECK_PEFORMAT_ONLY)
+ {
+ GetErrorResourceString(VECode, sb);
+ string formatString = ReplaceFormatItems(sb.ToString(), "%08x", ":x8");
+ formatString = ReplaceFormatItems(formatString, "%d", "");
+ if (psa == null)
+ {
+ psa = new object[0];
+ }
+
+ message = string.Format(formatString, (object[])psa);
+ }
+ else
+ {
+ _validator.FormatEventInfo(VECode, Context, sb, (uint)MessageLength - 1, psa);
+ message = sb.ToString();
+ }
+
+ // retail version of peverify.exe filters out CLS warnings...
+ if (!message.Contains("[CLS]"))
+ {
+ _output.Add(message);
+ }
+ }
+
+ public string[] GetOutput()
+ {
+ return _output.ToArray();
+ }
+
+ private static readonly string s_resourceFilePath = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "mscorrc.dll");
+ private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
+ private static readonly IntPtr s_hMod = LoadLibraryEx(s_resourceFilePath, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
+
+ private static void GetErrorResourceString(int code, StringBuilder message)
+ {
+ LoadString(s_hMod, (uint)(code & 0x0000FFFF), message, MessageLength - 1);
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ private static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax);
+
+ private static string ReplaceFormatItems(string input, string oldFormat, string newFormat)
+ {
+ // not foolproof/efficient, but easy to write/understand...
+ var parts = input.Replace(oldFormat, "|").Split('|');
+
+ var formatString = new StringBuilder();
+ for (int i = 0; i < parts.Length; i++)
+ {
+ formatString.Append(parts[i]);
+ if (i < (parts.Length - 1))
+ {
+ formatString.Append('{');
+ formatString.Append(i);
+ formatString.Append(newFormat);
+ formatString.Append('}');
+ }
+ }
+
+ return formatString.ToString();
+ }
+ }
+ }
+
+ namespace ComTypes
+ {
+ [ComImport, CoClass(typeof(object)), Guid("90F1A06C-7712-4762-86B5-7A5EBA6BDB02"), TypeIdentifier]
+ public interface CLRRuntimeHost : ICLRRuntimeHost
+ {
+ }
+
+ [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("90F1A06C-7712-4762-86B5-7A5EBA6BDB02"), TypeIdentifier]
+ public interface ICLRRuntimeHost
+ {
+ }
+
+ [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("63DF8730-DC81-4062-84A2-1FF943F59FDD"), TypeIdentifier]
+ public interface ICLRValidator
+ {
+ void Validate(
+ [In, MarshalAs(UnmanagedType.Interface)] IVEHandler veh,
+ [In] uint ulAppDomainId,
+ [In] ValidatorFlags ulFlags,
+ [In] uint ulMaxError,
+ [In] uint token,
+ [In, MarshalAs(UnmanagedType.LPWStr)] string fileName,
+ [In] IntPtr pe,
+ [In] uint ulSize);
+
+ void FormatEventInfo(
+ [In, MarshalAs(UnmanagedType.Error)] int hVECode,
+ [In] tag_VerError Context,
+ [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder msg,
+ [In] uint ulMaxLength,
+ [In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] Array psa);
+ }
+
+ [ComImport, Guid("856CA1B2-7DAB-11D3-ACEC-00C04F86C309"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier]
+ public interface IVEHandler
+ {
+ void VEHandler([In, MarshalAs(UnmanagedType.Error)] int VECode, [In] tag_VerError Context, [In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] Array psa);
+ void SetReporterFtn([In] long lFnPtr);
+ }
+
+ [ComImport, Guid("809C652E-7396-11D2-9771-00A0C9B4D50C"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier]
+ public interface IMetaDataDispenser
+ {
+ void DefineScope(
+ [In] ref Guid rclsid,
+ [In] uint dwCreateFlags,
+ [In] ref Guid riid,
+ [Out, MarshalAs(UnmanagedType.IUnknown)] out object ppIUnk);
+
+ void OpenScope(
+ [In, MarshalAs(UnmanagedType.LPWStr)] string szScope,
+ [In] CorOpenFlags dwOpenFlags,
+ [In] ref Guid riid,
+ [Out, MarshalAs(UnmanagedType.IUnknown)] out object ppIUnk);
+
+ void OpenScopeOnMemory(
+ [In] IntPtr pData,
+ [In] uint cbData,
+ [In] CorOpenFlags dwOpenFlags,
+ [In] ref Guid riid,
+ [Out, MarshalAs(UnmanagedType.IUnknown)] out object ppIUnk);
+ }
+
+ [ComImport, Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier]
+ public interface IMetaDataImport
+ {
+ }
+
+ [ComImport, Guid("4709C9C6-81FF-11D3-9FC7-00C04F79A0A3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier]
+ public interface IMetaDataValidate
+ {
+ void ValidatorInit([In] CorValidatorModuleType dwModuleType, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnk);
+ void ValidateMetaData();
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 4), TypeIdentifier("5477469e-83b1-11d2-8b49-00a0c9b7c9c4", "mscoree.tag_VerError")]
+ public struct tag_VerError
+ {
+ public uint Flags;
+ public uint opcode;
+ public uint uOffset;
+ public uint Token;
+ public uint item1_flags;
+ public IntPtr item1_data;
+ public uint item2_flags;
+ public IntPtr item2_data;
+ }
+
+ public enum ValidatorFlags : uint
+ {
+ VALIDATOR_EXTRA_VERBOSE = 0x00000001,
+ VALIDATOR_SHOW_SOURCE_LINES = 0x00000002,
+ VALIDATOR_CHECK_ILONLY = 0x00000004,
+ VALIDATOR_CHECK_PEFORMAT_ONLY = 0x00000008,
+ VALIDATOR_NOCHECK_PEFORMAT = 0x00000010
+ };
+
+ public enum CorValidatorModuleType : uint
+ {
+ ValidatorModuleTypeInvalid = 0x00000000,
+ ValidatorModuleTypeMin = 0x00000001,
+ ValidatorModuleTypePE = 0x00000001,
+ ValidatorModuleTypeObj = 0x00000002,
+ ValidatorModuleTypeEnc = 0x00000003,
+ ValidatorModuleTypeIncr = 0x00000004,
+ ValidatorModuleTypeMax = 0x00000004
+ };
+
+ public enum CorOpenFlags : uint
+ {
+ ofRead = 0x00000000,
+ ofWrite = 0x00000001,
+ ofReadWriteMask = 0x00000001,
+ ofCopyMemory = 0x00000002,
+ ofCacheImage = 0x00000004,
+ ofManifestMetadata = 0x00000008,
+ ofReadOnly = 0x00000010,
+ ofTakeOwnership = 0x00000020,
+ ofNoTypeLib = 0x00000080,
+ ofReserved1 = 0x00000100,
+ ofReserved2 = 0x00000200,
+ ofReserved = 0xffffff40,
+ };
+ }
+}
diff --git a/tests/fsharpqa/testenv/src/PEVerify/MonoHelpers.cs b/tests/fsharpqa/testenv/src/PEVerify/MonoHelpers.cs
new file mode 100644
index 00000000000..385dcacc5bb
--- /dev/null
+++ b/tests/fsharpqa/testenv/src/PEVerify/MonoHelpers.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+using System;
+
+namespace PEVerify
+{
+ public class MonoHelpers
+ {
+ public static bool IsRunningOnMono()
+ {
+ return Type.GetType("Mono.Runtime") != null;
+ }
+ }
+}
diff --git a/tests/fsharpqa/testenv/src/PEVerify/PEVerify.csproj b/tests/fsharpqa/testenv/src/PEVerify/PEVerify.csproj
new file mode 100644
index 00000000000..3af2b4d23db
--- /dev/null
+++ b/tests/fsharpqa/testenv/src/PEVerify/PEVerify.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ net46
+
+
+
diff --git a/tests/fsharpqa/testenv/src/PEVerify/Program.cs b/tests/fsharpqa/testenv/src/PEVerify/Program.cs
new file mode 100644
index 00000000000..ecc24afee3e
--- /dev/null
+++ b/tests/fsharpqa/testenv/src/PEVerify/Program.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using Roslyn.Test.Utilities.Desktop;
+
+namespace PEVerify
+{
+ class Program
+ {
+ static int Main(string[] args)
+ {
+ string assemblyPath = null;
+ bool metadataOnly = false;
+ foreach (var arg in args)
+ {
+ switch (arg.ToUpperInvariant())
+ {
+ case "/IL":
+ case "/NOLOGO":
+ case "/UNIQUE":
+ // ignore these options
+ break;
+ case "/MD":
+ metadataOnly = true;
+ break;
+ default:
+ if (assemblyPath != null)
+ {
+ Console.WriteLine("Assembly already specified or unknown option.");
+ return -1;
+ }
+
+ assemblyPath = arg;
+ break;
+ }
+ }
+
+ if (!Path.IsPathRooted(assemblyPath))
+ {
+ var workingDir = Directory.GetCurrentDirectory();
+ assemblyPath = Path.Combine(workingDir, assemblyPath);
+ }
+
+ var errors = CLRHelpers.PeVerify(assemblyPath, metadataOnly);
+ foreach (var error in errors)
+ {
+ Console.WriteLine(error);
+ }
+
+ return errors.Length;
+ }
+ }
+}
diff --git a/tests/service/FscTests.fs b/tests/service/FscTests.fs
index ca3d3999e0a..61c3a29003f 100644
--- a/tests/service/FscTests.fs
+++ b/tests/service/FscTests.fs
@@ -47,32 +47,12 @@ type PEVerifier () =
if runsOnMono then
Some ("pedump", "--verify all")
else
- let rec tryFindFile (fileName : string) (dir : DirectoryInfo) =
- let file = Path.Combine(dir.FullName, fileName)
- if File.Exists file then Some file
- else
- dir.GetDirectories()
- |> Array.sortBy(fun d -> d.Name)
- |> Array.filter(fun d ->
- match d.Name with
- // skip old SDK directories
- | "v6.0" | "v6.0A" | "v7.0" | "v7.0A" | "v7.1" | "v7.1A" -> false
- | _ -> true)
- |> Array.rev // order by descending -- get latest version
- |> Array.tryPick (tryFindFile fileName)
-
- let tryGetSdkDir (progFiles : Environment.SpecialFolder) =
- let progFilesFolder = Environment.GetFolderPath(progFiles)
- let dI = DirectoryInfo(Path.Combine(progFilesFolder, "Microsoft SDKs", "Windows"))
- if dI.Exists then Some dI
- else None
-
- match Array.tryPick tryGetSdkDir [| Environment.SpecialFolder.ProgramFilesX86; Environment.SpecialFolder.ProgramFiles |] with
- | None -> None
- | Some sdkDir ->
- match tryFindFile "peverify.exe" sdkDir with
- | None -> None
- | Some pe -> Some (pe, "/UNIQUE /IL /NOLOGO")
+ let peverifyPath configuration =
+ Path.Combine(__SOURCE_DIRECTORY__, "..", "fsharpqa", "testenv", "src", "PEVerify", "bin", configuration, "net46", "PEVerify.exe")
+ let peverify =
+ if File.Exists(peverifyPath "Debug") then peverifyPath "Debug"
+ else peverifyPath "Release"
+ Some (peverify, "/UNIQUE /IL /NOLOGO")
#endif
static let execute (fileName : string, arguments : string) =