Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.Net core x86 support #2161

Merged
merged 3 commits into from Sep 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 22 additions & 3 deletions scripts/build.ps1
Expand Up @@ -95,6 +95,9 @@ $TPB_TargetFrameworkUap = "uap10.0"
$TPB_TargetFrameworkNS2_0 = "netstandard2.0"
$TPB_Configuration = $Configuration
$TPB_TargetRuntime = $TargetRuntime
$TPB_X64_Runtime = "win7-x64"
$TPB_X86_Runtime = "win7-x86"

# Version suffix is empty for RTM releases
$TPB_Version = if ($VersionSuffix -ne '') { $Version + "-" + $VersionSuffix } else { $Version }
$TPB_CIBuild = $CIBuild
Expand Down Expand Up @@ -223,6 +226,8 @@ function Publish-Package
$testHostx86Project = Join-Path $env:TP_ROOT_DIR "src\testhost.x86\testhost.x86.csproj"
$testhostFullPackageDir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFramework\$TPB_TargetRuntime")
$testhostCorePackageDir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFrameworkCore20")
$testhostCorePackageX64Dir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFrameworkCore20\$TPB_X64_Runtime")
$testhostCorePackageX86Dir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFrameworkCore20\$TPB_X86_Runtime")
$testhostUapPackageDir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFrameworkUap")
$vstestConsoleProject = Join-Path $env:TP_ROOT_DIR "src\vstest.console\vstest.console.csproj"
$settingsMigratorProject = Join-Path $env:TP_ROOT_DIR "src\SettingsMigrator\SettingsMigrator.csproj"
Expand Down Expand Up @@ -252,10 +257,12 @@ function Publish-Package
Publish-PackageInternal $testHostProject $TPB_TargetFramework $testhostFullPackageDir
Publish-PackageInternal $testHostProject $TPB_TargetFrameworkCore20 $testhostCorePackageDir
Publish-PackageInternal $testHostProject $TPB_TargetFrameworkCore20 $testhostUapPackageDir
Publish-PackageWithRuntimeInternal $testHostProject $TPB_TargetFrameworkCore20 $TPB_X64_Runtime false $testhostCorePackageX64Dir

Write-Log "Package: Publish testhost.x86\testhost.x86.csproj"
Publish-PackageInternal $testHostx86Project $TPB_TargetFramework $testhostFullPackageDir

Publish-PackageInternal $testHostx86Project $TPB_TargetFramework $testhostFullPackageDir
Publish-PackageWithRuntimeInternal $testHostx86Project $TPB_TargetFrameworkCore20 $TPB_X86_Runtime false $testhostCorePackageX86Dir

# Copy over the Full CLR built testhost package assemblies to the Core CLR and Full CLR package folder.
$coreCLRFull_Dir = "TestHost"
$fullDestDir = Join-Path $coreCLR20PackageDir $coreCLRFull_Dir
Expand Down Expand Up @@ -292,6 +299,7 @@ function Publish-Package
$extensions_Dir = "Extensions"
$fullCLRExtensionsDir = Join-Path $fullCLRPackageDir $extensions_Dir
$coreCLRExtensionsDir = Join-Path $coreCLR20PackageDir $extensions_Dir

# Create an extensions directory.
New-Item -ItemType directory -Path $fullCLRExtensionsDir -Force | Out-Null
New-Item -ItemType directory -Path $coreCLRExtensionsDir -Force | Out-Null
Expand Down Expand Up @@ -437,6 +445,14 @@ function Publish-PackageInternal($packagename, $framework, $output)
Set-ScriptFailedOnError
}

function Publish-PackageWithRuntimeInternal($packagename, $framework, $runtime, $selfcontained, $output)
{
Write-Verbose "$dotnetExe publish $packagename --configuration $TPB_Configuration --framework $framework --runtime $runtime --output $output -v:minimal -p:Version=$TPB_Version -p:CIBuild=$TPB_CIBuild -p:LocalizedBuild=$TPB_LocalizedBuild"
& $dotnetExe publish $packagename --configuration $TPB_Configuration --framework $framework --runtime $runtime --self-contained $selfcontained --output $output -v:minimal -p:Version=$TPB_Version -p:CIBuild=$TPB_CIBuild -p:LocalizedBuild=$TPB_LocalizedBuild

Set-ScriptFailedOnError
}

function Copy-Loc-Files($sourceDir, $destinationDir, $dllName)
{
foreach($lang in $language) {
Expand Down Expand Up @@ -582,7 +598,10 @@ function Create-NugetPackages
$testhostUapPackageDir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFrameworkUap")
Copy-Item $tpNuspecDir\uap\"Microsoft.TestPlatform.TestHost.Uap.props" $testhostUapPackageDir\Microsoft.TestPlatform.TestHost.props -Force
Copy-Item $tpNuspecDir\uap\"Microsoft.TestPlatform.TestHost.Uap.targets" $testhostUapPackageDir\Microsoft.TestPlatform.TestHost.targets -Force


$testhostCorePackageDir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFrameworkCore20")
Copy-Item $tpNuspecDir\"Microsoft.TestPlatform.TestHost.NetCore.props" $testhostCorePackageDir\Microsoft.TestPlatform.TestHost.props -Force

# Call nuget pack on these components.
$nugetExe = Join-Path $env:TP_PACKAGES_DIR -ChildPath "Nuget.CommandLine" | Join-Path -ChildPath $env:NUGET_EXE_Version | Join-Path -ChildPath "tools\NuGet.exe"

Expand Down
2 changes: 1 addition & 1 deletion scripts/verify-nupkgs.ps1
Expand Up @@ -20,7 +20,7 @@ function Verify-Nuget-Packages($packageDirectory)
"Microsoft.TestPlatform.Extensions.TrxLogger" = 33;
"Microsoft.TestPlatform.ObjectModel" = 62;
"Microsoft.TestPlatform.Portable" = 502;
"Microsoft.TestPlatform.TestHost" = 140;
"Microsoft.TestPlatform.TestHost" = 145;
"Microsoft.TestPlatform.TranslationLayer" = 121}

$nugetPackages = Get-ChildItem -Filter "*.nupkg" $packageDirectory | % { $_.FullName}
Expand Down
Expand Up @@ -10,6 +10,7 @@
<TargetFrameworks Condition=" '$(DotNetBuildFromSource)' == 'true' ">netstandard2.0;netcoreapp2.1</TargetFrameworks>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<EnableCodeAnalysis>true</EnableCodeAnalysis>
<NoWarn>NU1605</NoWarn>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
Expand Down
Expand Up @@ -48,7 +48,7 @@ public class DotnetTestHostManager : ITestRuntimeProvider
private const string DataCollectorRegexPattern = @"Collector.dll";

private IDotnetHostHelper dotnetHostHelper;

private IEnvironment platformEnvironment;
private IProcessHelper processHelper;

private IFileHelper fileHelper;
Expand All @@ -65,11 +65,13 @@ public class DotnetTestHostManager : ITestRuntimeProvider

private string hostPackageVersion = "15.0.0";

private Architecture architecture;

/// <summary>
/// Initializes a new instance of the <see cref="DotnetTestHostManager"/> class.
/// </summary>
public DotnetTestHostManager()
: this(new ProcessHelper(), new FileHelper(), new DotnetHostHelper())
: this(new ProcessHelper(), new FileHelper(), new DotnetHostHelper(), new PlatformEnvironment())
{
}

Expand All @@ -79,14 +81,17 @@ public DotnetTestHostManager()
/// <param name="processHelper">Process helper instance.</param>
/// <param name="fileHelper">File helper instance.</param>
/// <param name="dotnetHostHelper">DotnetHostHelper helper instance.</param>
/// <param name="platformEnvironment">Platform Environment</param>
internal DotnetTestHostManager(
IProcessHelper processHelper,
IFileHelper fileHelper,
IDotnetHostHelper dotnetHostHelper)
IDotnetHostHelper dotnetHostHelper,
IEnvironment platformEnvironment)
{
this.processHelper = processHelper;
this.fileHelper = fileHelper;
this.dotnetHostHelper = dotnetHostHelper;
this.platformEnvironment = platformEnvironment;
}

/// <inheritdoc />
Expand Down Expand Up @@ -135,6 +140,9 @@ public void Initialize(IMessageLogger logger, string runsettingsXml)
{
this.messageLogger = logger;
this.hostExitedEventRaised = false;

var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettingsXml);
this.architecture = runConfiguration.TargetPlatform;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -163,25 +171,8 @@ public async Task<bool> LaunchTestHostAsync(TestProcessStartInfo testHostStartIn
{
var startInfo = new TestProcessStartInfo();

var currentProcessPath = this.processHelper.GetCurrentProcessFileName();

// This host manager can create process start info for dotnet core targets only.
// If already running with the dotnet executable, use it; otherwise pick up the dotnet available on path.
// Wrap the paths with quotes in case dotnet executable is installed on a path with whitespace.
if (currentProcessPath.EndsWith("dotnet", StringComparison.OrdinalIgnoreCase)
|| currentProcessPath.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase))
{
startInfo.FileName = currentProcessPath;
}
else
{
startInfo.FileName = this.dotnetHostHelper.GetDotnetPath();
}

EqtTrace.Verbose("DotnetTestHostmanager: Full path of dotnet.exe is {0}", startInfo.FileName);

// .NET core host manager is not a shared host. It will expect a single test source to be provided.
var args = "exec";
var args = string.Empty;
var sourcePath = sources.Single();
var sourceFile = Path.GetFileNameWithoutExtension(sourcePath);
var sourceDirectory = Path.GetDirectoryName(sourcePath);
Expand Down Expand Up @@ -212,11 +203,41 @@ public async Task<bool> LaunchTestHostAsync(TestProcessStartInfo testHostStartIn
EqtTrace.Verbose("DotnetTestHostmanager: File {0}, doesnot exist", depsFilePath);
}

var runtimeConfigDevPath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".runtimeconfig.dev.json"));
var testHostPath = this.GetTestHostPath(runtimeConfigDevPath, depsFilePath, sourceDirectory);
// If Testhost.exe is available use it
var exeName = this.architecture == Architecture.X86 ? "testhost.x86.exe" : "testhost.exe";
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved
var fullExePath = Path.Combine(sourceDirectory, exeName);
if (this.platformEnvironment.OperatingSystem.Equals(PlatformOperatingSystem.Windows) && this.fileHelper.Exists(fullExePath))
{
startInfo.FileName = fullExePath;
}
else
{
var currentProcessPath = this.processHelper.GetCurrentProcessFileName();

// This host manager can create process start info for dotnet core targets only.
// If already running with the dotnet executable, use it; otherwise pick up the dotnet available on path.
// Wrap the paths with quotes in case dotnet executable is installed on a path with whitespace.
if (currentProcessPath.EndsWith("dotnet", StringComparison.OrdinalIgnoreCase)
|| currentProcessPath.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase))
{
startInfo.FileName = currentProcessPath;
}
else
{
startInfo.FileName = this.dotnetHostHelper.GetDotnetPath();
}

var runtimeConfigDevPath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".runtimeconfig.dev.json"));
var testHostPath = this.GetTestHostPath(runtimeConfigDevPath, depsFilePath, sourceDirectory);

EqtTrace.Verbose("DotnetTestHostmanager: Full path of testhost.dll is {0}", testHostPath);
args = "exec" + args;
args += " " + testHostPath.AddDoubleQuote();
}

EqtTrace.Verbose("DotnetTestHostmanager: Full path of host exe is {0}", startInfo.FileName);

EqtTrace.Verbose("DotnetTestHostmanager: Full path of testhost.dll is {0}", testHostPath);
args += " " + testHostPath.AddDoubleQuote() + " " + connectionInfo.ToCommandLineOptions();
args += " " + connectionInfo.ToCommandLineOptions();

// Create a additional probing path args with Nuget.Client
// args += "--additionalprobingpath xxx"
Expand Down
27 changes: 27 additions & 0 deletions src/package/nuspec/Microsoft.TestPlatform.TestHost.NetCore.props
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition=" '$(Platform)' == 'x86' AND '$(OS)' == 'Windows_NT'">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is testhost.x86.exe copied only in case if Platform set to x86? dotnet publish prepare output that can be executed with dotnet vstest, which will get Platfrom parameter at runtime. If both testhost will be in output folder, it will be able to run test with appropriate bitness. Should separate bug for it be created?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thx.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it is last thing to allow resolve #1128, so I've mentioned it there with new comment instead of creating new issue.

<Content Include="$(MSBuildThisFileDirectory)x86\testhost.x86.exe">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is the testhost.dll copied over into the output directory today, without this change? Does this really need to be copied to the output directory when on .NET Core with deps.json support? Can't it just be invoked from the nuget package cache and copied over only when doing a dotnet publish? That should be the default afaik.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, testhost.dll today does not get copied, and we rely on the deps file for references.

We can't keep new binaries in the lib folder, they need to go into the build folder, reason being all the things in lib get referenced and better be AnyCPU.

Now I can device a logic to find the testhost.dll from the nuget cache and then walk out to build folder to find the appropriate executable, but then this won't work for dotnet publish. Is there a way to conditionally copy only during publish ?
Also we felt keeping this logic consistent made sense.

Do you see any issues in the current approach ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't keep new binaries in the lib folder, they need to go into the build folder, reason being all the things in lib get referenced and better be AnyCPU.

Why not put it into tools? We do the same for some other tools. Assembly there won't be referenced by the compiler.

Do you see any issues in the current approach ?

Mainly that the assembly will always be copied over. If there's a way to avoid that I would definitely prefer that.

Now I can device a logic to find the testhost.dll from the nuget cache and then walk out to build folder to find the appropriate executable, but then this won't work for dotnet publish. Is there a way to conditionally copy only during publish ?

Yes you can hook into the ResolvedFileToPublish item:

<ItemGroup>
    <ResolvedFileToPublish Include="C:\Users\vihofer\.nuget\packages\microsoft.testplatform.testhost\16.2.0\lib\uap10.0\testhost.dll" RelativePath="testhost.x86.dll" CopyToPublishDirectory="PreserveNewest" />
  </ItemGroup>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's up to you :)

<Link>testhost.x86.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)x86\testhost.x86.dll">
<Link>testhost.x86.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' == 'x64' AND '$(OS)' == 'Windows_NT'" >
<Content Include="$(MSBuildThisFileDirectory)x64\testhost.exe">
<Link>testhost.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)x64\testhost.dll">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MSBuildThisFileDirectory [](start = 24, length = 24)

check for errors/warning because this will try to replace anycpu "testhost.dll"

<Link>testhost.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
</ItemGroup>
</Project>
11 changes: 9 additions & 2 deletions src/package/nuspec/TestPlatform.TestHost.nuspec
@@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0"?>
<package >
<metadata>
<id>Microsoft.TestPlatform.TestHost</id>
Expand Down Expand Up @@ -41,7 +41,14 @@
<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\testhost.deps.json" target="lib\netcoreapp2.1\" />
<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\x86\msdia140.dll" target="lib\netcoreapp2.1\x86\" />
<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\x64\msdia140.dll" target="lib\netcoreapp2.1\x64\" />


<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\win7-x64\testhost.dll" target="build\netcoreapp2.1\x64" />
<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\win7-x64\testhost.exe" target="build\netcoreapp2.1\x64" />
<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\win7-x86\testhost.x86.dll" target="build\netcoreapp2.1\x86\" />
<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\win7-x86\testhost.x86.exe" target="build\netcoreapp2.1\x86\" />

<file src="Microsoft.TestPlatform.TestHost\netcoreapp2.1\Microsoft.TestPlatform.TestHost.props" target="build\netcoreapp2.1\" />

<!-- UWP -->
<file src="Microsoft.TestPlatform.TestHost\uap10.0\testhost.dll" target="lib\uap10.0\" />
<file src="Microsoft.TestPlatform.TestHost\uap10.0\Microsoft.TestPlatform.CommunicationUtilities.dll" target="lib\uap10.0\" />
Expand Down
2 changes: 0 additions & 2 deletions src/testhost.x86/testhost.x86.csproj
Expand Up @@ -13,8 +13,6 @@
<Prefer32Bit>true</Prefer32Bit>
<OutputType>Exe</OutputType>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net451'">
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
</PropertyGroup>
Expand Down
Expand Up @@ -528,7 +528,7 @@ private class TestableDotnetTestHostManager : DotnetTestHostManager
bool checkRequired,
IProcessHelper processHelper,
IFileHelper fileHelper,
IEnvironment environment) : base(processHelper, fileHelper, new DotnetHostHelper(fileHelper, environment))
IEnvironment environment) : base(processHelper, fileHelper, new DotnetHostHelper(fileHelper, environment), environment)
{
this.isVersionCheckRequired = checkRequired;
}
Expand Down