diff --git a/TestAssets/CrossPublishTestProjects/StandaloneAppCrossPublish/project.json b/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/.noautobuild similarity index 100% rename from TestAssets/CrossPublishTestProjects/StandaloneAppCrossPublish/project.json rename to TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/.noautobuild diff --git a/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/Program.cs b/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/Program.cs new file mode 100644 index 000000000..fbe8e9b0e --- /dev/null +++ b/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace PortableApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } + } +} diff --git a/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/project.json b/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/project.json new file mode 100644 index 000000000..8065921be --- /dev/null +++ b/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/project.json @@ -0,0 +1,17 @@ +{ + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": {}, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-*" + } + } + } + } +} + diff --git a/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/project.json.modified b/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/project.json.modified new file mode 100644 index 000000000..b80ab80b6 --- /dev/null +++ b/TestAssets/TestProjects/DependencyChangeTest/PortableApp_Standalone/project.json.modified @@ -0,0 +1,26 @@ +{ + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": {}, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-rc2-*" + } + } + } + }, + + "runtimes": { + "win7-x64": {}, + "win7-x86": {}, + "osx.10.10-x64": {}, + "osx.10.11-x64": {}, + "ubuntu.14.04-x64": {}, + "centos.7-x64": {}, + "rhel.7.2-x64": {}, + "debian.8-x64": {} + } +} diff --git a/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/.noautobuild b/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/Program.cs b/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/Program.cs new file mode 100644 index 000000000..529893b0e --- /dev/null +++ b/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace StandaloneApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } + } +} diff --git a/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/project.json b/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/project.json new file mode 100644 index 000000000..95649a930 --- /dev/null +++ b/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/project.json @@ -0,0 +1,22 @@ +{ + "compilationOptions": { + "emitEntryPoint": true + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": "1.0.0-rc2-*" + } + } + }, + "runtimes": { + "win7-x64": {}, + "win7-x86": {}, + "osx.10.10-x64": {}, + "osx.10.11-x64": {}, + "ubuntu.14.04-x64": {}, + "centos.7-x64": {}, + "rhel.7.2-x64": {}, + "debian.8-x64": {} + } +} diff --git a/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/project.json.modified b/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/project.json.modified new file mode 100644 index 000000000..3f57fac5f --- /dev/null +++ b/TestAssets/TestProjects/DependencyChangeTest/StandaloneApp_Portable/project.json.modified @@ -0,0 +1,25 @@ +{ + "compilationOptions": { + "emitEntryPoint": true + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-*" + } + } + } + }, + "runtimes": { + "win7-x64": {}, + "win7-x86": {}, + "osx.10.10-x64": {}, + "osx.10.11-x64": {}, + "ubuntu.14.04-x64": {}, + "centos.7-x64": {}, + "rhel.7.2-x64": {}, + "debian.8-x64": {} + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Microsoft.DotNet.Cli.Utils/Constants.cs index 1d10032ab..fa4dfb349 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Constants.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Constants.cs @@ -43,5 +43,12 @@ namespace Microsoft.DotNet.Cli.Utils (CurrentPlatform == Platform.Windows ? "hostfxr" : "libhostfxr") + DynamicLibSuffix }; + public static readonly string[] LibCoreClrBinaryNames = new string[] + { + "coreclr.dll", + "libcoreclr.so", + "libcoreclr.dylib" + }; + } } diff --git a/src/Microsoft.DotNet.Compiler.Common/Executable.cs b/src/Microsoft.DotNet.Compiler.Common/Executable.cs index 104c5fdc5..0ad3a7f97 100644 --- a/src/Microsoft.DotNet.Compiler.Common/Executable.cs +++ b/src/Microsoft.DotNet.Compiler.Common/Executable.cs @@ -56,6 +56,23 @@ namespace Microsoft.DotNet.Cli.Compiler.Common ExportRuntimeAssets(); } + private void VerifyCoreclrPresenceInPackageGraph() + { + var isCoreclrPresent = _exporter + .GetAllExports() + .SelectMany(e => e.NativeLibraryGroups) + .SelectMany(g => g.Assets) + .Select(a => a.FileName) + .Where(f => Constants.LibCoreClrBinaryNames.Contains(f)) + .Any(); + + // coreclr should be present for standalone apps + if (! isCoreclrPresent) + { + throw new InvalidOperationException("Expected coreclr library not found in package graph. Please try running restore again."); + } + } + private void ExportRuntimeAssets() { if (_context.TargetFramework.IsDesktop()) @@ -77,13 +94,15 @@ namespace Microsoft.DotNet.Cli.Compiler.Common } private void MakeCompilationOutputRunnableForCoreCLR() - { + { WriteDepsFileAndCopyProjectDependencies(_exporter); var emitEntryPoint = _compilerOptions.EmitEntryPoint ?? false; - if (emitEntryPoint && !string.IsNullOrEmpty(_context.RuntimeIdentifier)) + + if (emitEntryPoint && !_context.IsPortable) { // TODO: Pick a host based on the RID + VerifyCoreclrPresenceInPackageGraph(); CoreHost.CopyTo(_runtimeOutputPath, _compilerOptions.OutputName + Constants.ExeSuffix); } } diff --git a/src/dotnet/commands/dotnet-build/DotnetProjectBuilder.cs b/src/dotnet/commands/dotnet-build/DotnetProjectBuilder.cs index d43a88f14..9333c15a6 100644 --- a/src/dotnet/commands/dotnet-build/DotnetProjectBuilder.cs +++ b/src/dotnet/commands/dotnet-build/DotnetProjectBuilder.cs @@ -129,7 +129,7 @@ namespace Microsoft.DotNet.Tools.Build } catch (Exception e) { - throw new Exception($"Failed to make the following project runnable: {graphNode.ProjectContext.GetDisplayName()}", e); + throw new Exception($"Failed to make the following project runnable: {graphNode.ProjectContext.GetDisplayName()} reason: {e.Message}", e); } } diff --git a/test/dotnet-build.Tests/BuildOutputTests.cs b/test/dotnet-build.Tests/BuildOutputTests.cs index 1e97eb5fa..a34d47208 100644 --- a/test/dotnet-build.Tests/BuildOutputTests.cs +++ b/test/dotnet-build.Tests/BuildOutputTests.cs @@ -307,6 +307,30 @@ namespace Microsoft.DotNet.Tools.Builder.Tests } } + + [Fact] + private void StandaloneApp_WithoutCoreclrDll_Fails() + { + // Convert a Portable App to Standalone to simulate the customer scenario + var testInstance = TestAssetsManager.CreateTestInstance("DependencyChangeTest") + .WithLockFiles(); + + // Convert the portable test project to standalone by removing "type": "platform" and adding rids + var originalTestProject = Path.Combine(testInstance.TestRoot, "PortableApp_Standalone", "project.json"); + var modifiedTestProject = Path.Combine(testInstance.TestRoot, "PortableApp_Standalone", "project.json.modified"); + + // Simulate a user editting the project.json + File.Delete(originalTestProject); + File.Copy(modifiedTestProject, originalTestProject); + + var buildResult = new BuildCommand(originalTestProject, framework: DefaultFramework) + .ExecuteWithCapturedOutput(); + + buildResult.Should().Fail(); + + buildResult.StdErr.Should().Contain("Expected coreclr library not found in package graph. Please try running restore again."); + } + private void CopyProjectToTempDir(string projectDir, TempDirectory tempDir) { // copy all the files to temp dir