diff --git a/scripts/bootstrap.cmd b/scripts/bootstrap.cmd index 68ba3c8d1..8befd5dd5 100644 --- a/scripts/bootstrap.cmd +++ b/scripts/bootstrap.cmd @@ -66,7 +66,7 @@ echo Building stage1 dotnet-publish.exe ... dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE1_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Publish" if errorlevel 1 goto fail -echo Building stage1 dotnet-publish.exe ... +echo Building stage1 resgen.exe ... dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE1_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Resgen" if errorlevel 1 goto fail @@ -103,7 +103,7 @@ echo Building stage2 dotnet-publish.exe ... dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE2_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Publish" if errorlevel 1 goto fail -echo Building stage2 dotnet-publish.exe ... +echo Building stage2 resgen.exe ... dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE2_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Resgen" if errorlevel 1 goto fail @@ -132,7 +132,7 @@ REM Smoke-test the output set PATH=%STAGE2_DIR%;%START_PATH% del "%REPOROOT%\test\TestApp\project.lock.json" -dotnet restore "%REPOROOT%\test\TestApp" --runtime "%RID%" --quiet +dotnet restore "%REPOROOT%\test\TestApp" --quiet dotnet compile "%REPOROOT%\test\TestApp" --output "%REPOROOT%\artifacts\%RID%\smoketest" set CLRHOST_CLR_PATH=%STAGE2_DIR% diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 6e69ef0ec..8f73bf8dc 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -108,8 +108,8 @@ dotnet compile "$REPOROOT/test/TestApp" --output "$REPOROOT/artifacts/$RID/smoke export CLRHOST_CLR_PATH=$STAGE2_DIR -OUTPUT=$($REPOROOT/artifacts/$RID/smoketest/TestApp) -[ "$OUTPUT" == "This is a test app" ] || (error "Smoke test failed!" && exit 1) +# set -e will abort if the exit code of this is non-zero +$REPOROOT/artifacts/$RID/smoketest/TestApp # Check that a compiler error is reported set +e diff --git a/scripts/dev-install.cmd b/scripts/dev-install.cmd new file mode 100644 index 000000000..7def98e76 --- /dev/null +++ b/scripts/dev-install.cmd @@ -0,0 +1,19 @@ +@echo off + +REM This trick gets the absolute path from a relative path +pushd %~dp0.. +set REPOROOT=%CD% +popd + +set RID=win7-x64 +set STAGE2_DIR=%REPOROOT%\artifacts\%RID%\stage2 +set DESTINATION=%USERPROFILE%\.dotnet\sdks\dotnet-win-x64.0.0.1-dev + +echo Junctioning %STAGE2_DIR% to %DESTINATION% + +if not exist %DESTINATION% goto link +echo Removing old junction %DESTINATION% +rd /s /q %DESTINATION% + +:link +mklink /J %DESTINATION% %STAGE2_DIR% diff --git a/scripts/dotnet-restore.cmd b/scripts/dotnet-restore.cmd index 54dd3237f..c25786378 100644 --- a/scripts/dotnet-restore.cmd +++ b/scripts/dotnet-restore.cmd @@ -2,7 +2,7 @@ SETLOCAL SET ERRORLEVEL= -"%~dp0dnx\dnx" "%~dp0dnx\lib\Microsoft.Dnx.Tooling\Microsoft.Dnx.Tooling.dll" restore --runtime "osx.10.10-x64" --runtime "ubuntu.14.04-x64" %* +"%~dp0dnx\dnx" "%~dp0dnx\lib\Microsoft.Dnx.Tooling\Microsoft.Dnx.Tooling.dll" restore --runtime "osx.10.10-x64" --runtime "ubuntu.14.04-x64" --runtime "win7-x64" %* exit /b %ERRORLEVEL% ENDLOCAL diff --git a/scripts/package.ps1 b/scripts/package.ps1 index 1d221e70b..20050e7bd 100644 --- a/scripts/package.ps1 +++ b/scripts/package.ps1 @@ -16,12 +16,16 @@ if(![string]::IsNullOrEmpty($env:DOTNET_BUILD_VERSION)) { $PackageName = Join-Path $PackageDir "dotnet-win-x64.$PackageVersion.zip" +if (Test-Path $PackageName) +{ + del $PackageName +} + Add-Type -Assembly System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::CreateFromDirectory($Stage2Dir, $PackageName, "Optimal", $false) Write-Host "Packaged stage2 to $PackageName" - $PublishScript = Join-Path $PSScriptRoot "publish.ps1" & $PublishScript -file $PackageName diff --git a/src/Microsoft.DotNet.Cli.Utils/Command.cs b/src/Microsoft.DotNet.Cli.Utils/Command.cs index d085c6b95..f80c49c78 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Command.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Command.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; +using Microsoft.Dnx.Runtime.Common.CommandLine; namespace Microsoft.DotNet.Cli.Utils { @@ -16,8 +17,8 @@ namespace Microsoft.DotNet.Cli.Utils private StringWriter _stdOutCapture; private StringWriter _stdErrCapture; - private TextWriter _stdOutForward; - private TextWriter _stdErrForward; + private Action _stdOutForward; + private Action _stdErrForward; private Action _stdOutHandler; private Action _stdErrHandler; @@ -128,7 +129,7 @@ namespace Microsoft.DotNet.Cli.Utils #if DEBUG var sw = Stopwatch.StartNew(); - Reporter.Output.WriteLine($"> {FormatProcessInfo(_process.StartInfo)}".White()); + Reporter.Verbose.WriteLine($"> {FormatProcessInfo(_process.StartInfo)}".White()); #endif _process.Start(); _process.BeginOutputReadLine(); @@ -142,11 +143,11 @@ namespace Microsoft.DotNet.Cli.Utils var message = $"< {FormatProcessInfo(_process.StartInfo)} exited with {exitCode} in {sw.ElapsedMilliseconds} ms."; if (exitCode == 0) { - Reporter.Output.WriteLine(message.Green()); + Reporter.Verbose.WriteLine(message.Green()); } else { - Reporter.Output.WriteLine(message.Red().Bold()); + Reporter.Verbose.WriteLine(message.Red().Bold()); } #endif @@ -176,17 +177,37 @@ namespace Microsoft.DotNet.Cli.Utils return this; } - public Command ForwardStdOut(TextWriter to = null) + public Command ForwardStdOut(TextWriter to = null, bool onlyIfVerbose = false) { ThrowIfRunning(); - _stdOutForward = to ?? Console.Out; + if (!onlyIfVerbose || CommandContext.IsVerbose()) + { + if (to == null) + { + _stdOutForward = Reporter.Output.WriteLine; + } + else + { + _stdOutForward = to.WriteLine; + } + } return this; } - public Command ForwardStdErr(TextWriter to = null) + public Command ForwardStdErr(TextWriter to = null, bool onlyIfVerbose = false) { ThrowIfRunning(); - _stdErrForward = to ?? Console.Error; + if (!onlyIfVerbose || CommandContext.IsVerbose()) + { + if (to == null) + { + _stdErrForward = Reporter.Error.WriteLine; + } + else + { + _stdErrForward = to.WriteLine; + } + } return this; } @@ -230,7 +251,7 @@ namespace Microsoft.DotNet.Cli.Utils } } - private void ProcessData(string data, StringWriter capture, TextWriter forward, Action handler) + private void ProcessData(string data, StringWriter capture, Action forward, Action handler) { if (data == null) { @@ -244,7 +265,7 @@ namespace Microsoft.DotNet.Cli.Utils if (forward != null) { - forward.WriteLine(data); + forward(data); } if (handler != null) diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandContext.cs b/src/Microsoft.DotNet.Cli.Utils/CommandContext.cs new file mode 100644 index 000000000..bfdd5ac2c --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/CommandContext.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.DotNet.Cli.Utils +{ + internal static class CommandContext + { + internal static class Variables + { + private static readonly string Prefix = "DOTNET_CLI_CONTEXT_"; + internal static readonly string Verbose = Prefix + "VERBOSE"; + internal static readonly string AnsiPassThru = Prefix + "ANSI_PASS_THRU"; + } + + private static Lazy _verbose = new Lazy(() => GetBool(Variables.Verbose)); + private static Lazy _ansiPassThru = new Lazy(() => GetBool(Variables.AnsiPassThru)); + + public static bool IsVerbose() + { + return _verbose.Value; + } + + public static bool ShouldPassAnsiCodesThrough() + { + return _ansiPassThru.Value; + } + + private static bool GetBool(string name, bool defaultValue = false) + { + var str = Environment.GetEnvironmentVariable(name); + bool value; + if(string.IsNullOrEmpty(str) || !bool.TryParse(str, out value)) + { + return defaultValue; + } + return value; + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/Reporter.cs b/src/Microsoft.DotNet.Cli.Utils/Reporter.cs index f5b5ea57f..e4481732f 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Reporter.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Reporter.cs @@ -1,12 +1,54 @@ -using System.Runtime.InteropServices; +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; using Microsoft.Dnx.Runtime.Common.CommandLine; namespace Microsoft.DotNet.Cli.Utils { // Stupid-simple console manager - internal static class Reporter + internal class Reporter { - public static AnsiConsole Output { get; } = AnsiConsole.GetOutput(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); - public static AnsiConsole Error { get; } = AnsiConsole.GetError(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + private static readonly Reporter Null = new Reporter(console: null); + private static object _lock = new object(); + + private AnsiConsole _console; + + private Reporter(AnsiConsole console) + { + _console = console; + } + + public static Reporter Output { get; } = Create(AnsiConsole.GetOutput); + public static Reporter Error { get; } = Create(AnsiConsole.GetError); + public static Reporter Verbose { get; } = CommandContext.IsVerbose() ? Create(AnsiConsole.GetError) : Null; + + public static Reporter Create(Func getter) + { + return new Reporter(getter(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))); + } + + public void WriteLine(string message) + { + lock(_lock) + { + if (CommandContext.ShouldPassAnsiCodesThrough()) + { + _console?.Writer?.WriteLine(message); + } + else + { + _console?.WriteLine(message); + } + } + } + + public void WriteLine() + { + lock(_lock) + { + _console?.Writer?.WriteLine(); + } + } } } diff --git a/src/Microsoft.DotNet.Cli/Program.cs b/src/Microsoft.DotNet.Cli/Program.cs index 13a946d41..eaa9021ca 100644 --- a/src/Microsoft.DotNet.Cli/Program.cs +++ b/src/Microsoft.DotNet.Cli/Program.cs @@ -1,54 +1,101 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.Dnx.Runtime.Common.CommandLine; using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Cli { public class Program { + private const string HelpText = @".NET Command Line Interface +Usage: dotnet [common-options] [command] [arguments] + +Arguments: + [command] The command to execute + [arguments] Arguments to pass to the command + +Common Options (passed before the command): + -v|--verbose Enable verbose output + +Common Commands: + compile Compiles a .NET project + publish Publishes a .NET project for deployment + run Compiles and immediately executes a .NET project"; + public static int Main(string[] args) { - if (args.Length < 1) - { - // Handle missing args - PrintCommandList(); - return 1; - } + // CommandLineApplication is a bit restrictive, so we parse things ourselves here. Individual apps should use CLA. + var verbose = false; + var command = string.Empty; + var lastArg = 0; - if (args[0].Equals("help", StringComparison.OrdinalIgnoreCase)) + for (; lastArg < args.Length; lastArg++) { - if (args.Length > 1) + if (IsArg(args[lastArg], "v", "verbose")) { - return Command.Create("dotnet-" + args[1], "--help") - .ForwardStdErr() - .ForwardStdOut() - .Execute() - .ExitCode; + verbose = true; + } + else if (args[lastArg].StartsWith("-")) + { + PrintHelp($"Unknown option: ${args[lastArg]}"); } else { - PrintCommandList(); - return 0; + // It's the command, and we're done! + command = args[lastArg]; + break; } } - else + + var appArgs = (lastArg + 1) >= args.Length ? Enumerable.Empty() : args.Skip(lastArg + 1).ToArray(); + + if (string.IsNullOrEmpty(command) || command.Equals("help", StringComparison.OrdinalIgnoreCase)) { - return Command.Create("dotnet-" + args[0], args.Skip(1)) + return RunHelpCommand(appArgs); + } + + return Command.Create("dotnet-" + command, appArgs) + .EnvironmentVariable(CommandContext.Variables.Verbose, verbose.ToString()) + .EnvironmentVariable(CommandContext.Variables.AnsiPassThru, bool.TrueString) + .ForwardStdErr() + .ForwardStdOut() + .Execute() + .ExitCode; + } + + private static int RunHelpCommand(IEnumerable appArgs) + { + if (appArgs.Any()) + { + return Command.Create("dotnet-" + appArgs.First(), "--help") .ForwardStdErr() .ForwardStdOut() .Execute() .ExitCode; } + else + { + PrintHelp(); + return 0; + } } - private static void PrintCommandList() + private static void PrintHelp(string errorMessage = null) { - Console.WriteLine("Some dotnet Commands (use 'dotnet help ' to get help):"); - Console.WriteLine("* compile - Compiles code"); - Console.WriteLine("* publish - Publishes a project to a self-contained application"); - Console.WriteLine("* run - Publishes and immediately runs a project"); + if(!string.IsNullOrEmpty(errorMessage)) + { + Reporter.Error.WriteLine(errorMessage.Red()); + } + Reporter.Output.WriteLine(HelpText); + } + + private static bool IsArg(string candidate, string shortName, string longName) + { + return candidate.Equals("-" + shortName) || candidate.Equals("--" + longName); } } } diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs index 5b18609bb..a84901108 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExport.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace Microsoft.Extensions.ProjectModel.Compilation { + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class LibraryExport { /// @@ -39,5 +41,13 @@ namespace Microsoft.Extensions.ProjectModel.Compilation RuntimeAssemblies = runtimeAssemblies; NativeLibraries = nativeLibraries; } + + private string DebuggerDisplay + { + get + { + return Library.Identity.ToString(); + } + } } } diff --git a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs index 2be7626f7..77d416e9f 100644 --- a/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs +++ b/src/Microsoft.DotNet.ProjectModel/Compilation/LibraryExporter.cs @@ -32,16 +32,33 @@ namespace Microsoft.Extensions.ProjectModel.Compilation public LibraryManager LibraryManager { get; } + /// + /// Gets all the exports specified by this project, including the root project itself + /// public IEnumerable GetAllExports() { - // Export all but the main project return ExportLibraries(_ => true); } - public IEnumerable GetCompilationDependencies() + /// + /// Gets all exports required by the project, NOT including the project itself + /// + /// + public IEnumerable GetDependencies() + { + return GetDependencies(LibraryType.Unspecified); + } + + /// + /// Gets all exports required by the project, of the specified , NOT including the project itself + /// + /// + public IEnumerable GetDependencies(LibraryType type) { // Export all but the main project - return ExportLibraries(library => library != _rootProject); + return ExportLibraries(library => + library != _rootProject && + LibraryIsOfType(type, library)); } /// @@ -157,7 +174,7 @@ namespace Microsoft.Extensions.ProjectModel.Compilation // No support for ref or native in projects, so runtimeAssemblies is just the same as compileAssemblies and nativeLibraries are empty return new LibraryExport(project, compileAssemblies, sourceReferences, compileAssemblies, Enumerable.Empty()); } - + private static string ResolvePath(Project project, string configuration, string path) { if (string.IsNullOrEmpty(path)) @@ -214,5 +231,11 @@ namespace Microsoft.Extensions.ProjectModel.Compilation Path.Combine(package.Path, assemblyPath))); } } + + private static bool LibraryIsOfType(LibraryType type, LibraryDescription library) + { + return type.Equals(LibraryType.Unspecified) || // No type filter was requested + library.Identity.Type.Equals(type); // OR, library type matches requested type + } } } diff --git a/src/Microsoft.DotNet.Tools.Compiler/Program.cs b/src/Microsoft.DotNet.Tools.Compiler/Program.cs index a228ba851..f0b179423 100644 --- a/src/Microsoft.DotNet.Tools.Compiler/Program.cs +++ b/src/Microsoft.DotNet.Tools.Compiler/Program.cs @@ -8,6 +8,7 @@ using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Tools.Common; using Microsoft.Extensions.ProjectModel; using Microsoft.Extensions.ProjectModel.Compilation; +using Microsoft.Extensions.ProjectModel.Graph; using NuGet.Frameworks; namespace Microsoft.DotNet.Tools.Compiler @@ -51,7 +52,7 @@ namespace Microsoft.DotNet.Tools.Compiler foreach (var context in framework.Values.Select(f => ProjectContext.Create(path, NuGetFramework.Parse(f)))) { success &= Compile(context, configuration.Value() ?? Constants.DefaultConfiguration, output.Value(), intermediateOutput.Value(), buildProjectReferences); - + if (isNative) { success &= CompileNative(context, configuration.Value() ?? Constants.DefaultConfiguration, output.Value(), buildProjectReferences); @@ -63,7 +64,7 @@ namespace Microsoft.DotNet.Tools.Compiler foreach (var context in ProjectContext.CreateContextForEachFramework(path)) { success &= Compile(context, configuration.Value() ?? Constants.DefaultConfiguration, output.Value(), intermediateOutput.Value(), buildProjectReferences); - + if (isNative) { success &= CompileNative(context, configuration.Value() ?? Constants.DefaultConfiguration, output.Value(), buildProjectReferences); @@ -91,23 +92,21 @@ namespace Microsoft.DotNet.Tools.Compiler private static bool CompileNative(ProjectContext context, string configuration, string outputOptionValue, bool buildProjectReferences) { string outputPath = Path.Combine(GetOutputPath(context, configuration, outputOptionValue), "native"); - + var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); var managedBinaryPath = Path.Combine(outputPath, context.ProjectFile.Name + (compilationOptions.EmitEntryPoint.GetValueOrDefault() ? ".exe" : ".dll")); - + // Do Native Compilation var result = Command.Create($"dotnet-compile-native", $"\"{managedBinaryPath}\" \"{outputPath}\"") .ForwardStdErr() .ForwardStdOut() .Execute(); - + return result.ExitCode == 0; } private static bool Compile(ProjectContext context, string configuration, string outputOptionValue, string intermediateOutputValue, bool buildProjectReferences) { - Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); - // Set up Output Paths string outputPath = GetOutputPath(context, configuration, outputOptionValue); string intermediateOutputPath = GetIntermediateOutputPath(context, configuration, intermediateOutputValue, outputOptionValue); @@ -124,7 +123,7 @@ namespace Microsoft.DotNet.Tools.Compiler diagnostics.AddRange(context.LibraryManager.GetAllDiagnostics()); // Gather exports for the project - var dependencies = exporter.GetCompilationDependencies().ToList(); + var dependencies = exporter.GetDependencies().ToList(); if (buildProjectReferences) { @@ -158,6 +157,8 @@ namespace Microsoft.DotNet.Tools.Compiler projects.Clear(); } + Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); + // Dump dependency data // TODO: Turn on only if verbose, we can look at the response // file anyways @@ -228,7 +229,7 @@ namespace Microsoft.DotNet.Tools.Compiler } else { - Console.Error.WriteLine(line); + Reporter.Error.WriteLine(line); } }) .OnOutputLine(line => @@ -241,7 +242,7 @@ namespace Microsoft.DotNet.Tools.Compiler } else { - Console.Out.WriteLine(line); + Reporter.Output.WriteLine(line); } }) .Execute(); @@ -256,8 +257,8 @@ namespace Microsoft.DotNet.Tools.Compiler if (success && compilationOptions.EmitEntryPoint.GetValueOrDefault()) { var runtimeContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, new[] { RuntimeIdentifier.Current }); - MakeRunnable(runtimeContext, - outputPath, + MakeRunnable(runtimeContext, + outputPath, runtimeContext.CreateExporter(configuration)); } @@ -325,7 +326,7 @@ namespace Microsoft.DotNet.Tools.Compiler if (string.IsNullOrEmpty(outputOptionValue)) { - rootOutputPath = context.ProjectFile.ProjectDirectory; + rootOutputPath = context.ProjectFile.ProjectDirectory; } return rootOutputPath; @@ -334,18 +335,18 @@ namespace Microsoft.DotNet.Tools.Compiler private static void CleanOrCreateDirectory(string path) { if (Directory.Exists(path)) - { + { try { Directory.Delete(path, recursive: true); } - catch(Exception e) + catch (Exception e) { Console.WriteLine("Unable to remove directory: " + path); Console.WriteLine(e.Message); } } - + Directory.CreateDirectory(path); } @@ -354,15 +355,9 @@ namespace Microsoft.DotNet.Tools.Compiler if (runtimeContext.TargetFramework.IsDesktop()) { // On desktop we need to copy dependencies since we don't own the host - foreach (var export in exporter.GetAllExports()) + foreach (var export in exporter.GetDependencies()) { - if (export.Library == runtimeContext.RootProject) - { - continue; - } - - CopyFiles(export.RuntimeAssemblies, outputPath); - CopyFiles(export.NativeLibraries, outputPath); + CopyExport(outputPath, export); } } else @@ -370,17 +365,30 @@ namespace Microsoft.DotNet.Tools.Compiler EmitHost(runtimeContext, outputPath, exporter); } } - + + private static void CopyExport(string outputPath, LibraryExport export) + { + CopyFiles(export.RuntimeAssemblies, outputPath); + CopyFiles(export.NativeLibraries, outputPath); + } + private static void EmitHost(ProjectContext runtimeContext, string outputPath, LibraryExporter exporter) { // Write the Host information file (basically a simplified form of the lock file) var lines = new List(); - foreach(var export in exporter.GetAllExports()) + foreach (var export in exporter.GetAllExports()) { - if (export.Library is ProjectDescription) + if (export.Library == runtimeContext.RootProject) { continue; } + + if (export.Library is ProjectDescription) + { + // Copy project dependencies to the output folder + CopyFiles(export.RuntimeAssemblies, outputPath); + CopyFiles(export.NativeLibraries, outputPath); + } else { lines.AddRange(GenerateLines(export, export.RuntimeAssemblies, "runtime")); @@ -419,7 +427,7 @@ namespace Microsoft.DotNet.Tools.Compiler private static void PrintSummary(bool success, List diagnostics) { - Reporter.Output.Writer.WriteLine(); + Reporter.Output.WriteLine(); var errorCount = diagnostics.Count(d => d.Severity == DiagnosticMessageSeverity.Error); var warningCount = diagnostics.Count(d => d.Severity == DiagnosticMessageSeverity.Warning); @@ -436,7 +444,7 @@ namespace Microsoft.DotNet.Tools.Compiler Reporter.Output.WriteLine($" {warningCount} Warning(s)"); Reporter.Output.WriteLine($" {errorCount} Error(s)"); - Reporter.Output.Writer.WriteLine(); + Reporter.Output.WriteLine(); } private static bool AddResources(Project project, List compilerArgs, string intermediateOutputPath) diff --git a/src/Microsoft.DotNet.Tools.Publish/Program.cs b/src/Microsoft.DotNet.Tools.Publish/Program.cs index f747c5825..4be759488 100644 --- a/src/Microsoft.DotNet.Tools.Publish/Program.cs +++ b/src/Microsoft.DotNet.Tools.Publish/Program.cs @@ -88,7 +88,7 @@ namespace Microsoft.DotNet.Tools.Publish private static int Publish(ProjectContext context, string outputPath, string configuration) { - Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier}"); + Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}"); var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); @@ -140,7 +140,7 @@ namespace Microsoft.DotNet.Tools.Publish continue; } - Reporter.Output.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ..."); + Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ..."); PublishFiles(export.RuntimeAssemblies, outputPath); PublishFiles(export.NativeLibraries, outputPath); diff --git a/src/Microsoft.DotNet.Tools.Run/Microsoft.DotNet.Tools.Compiler.xproj b/src/Microsoft.DotNet.Tools.Run/Microsoft.DotNet.Tools.Run.xproj similarity index 87% rename from src/Microsoft.DotNet.Tools.Run/Microsoft.DotNet.Tools.Compiler.xproj rename to src/Microsoft.DotNet.Tools.Run/Microsoft.DotNet.Tools.Run.xproj index ced479ff8..dcf20c34f 100644 --- a/src/Microsoft.DotNet.Tools.Run/Microsoft.DotNet.Tools.Compiler.xproj +++ b/src/Microsoft.DotNet.Tools.Run/Microsoft.DotNet.Tools.Run.xproj @@ -4,11 +4,10 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - 0a309227-a9d8-4ddf-88dd-326b57b04378 - Microsoft.DotNet.Tools.Compiler + 1c16108c-c786-482d-bb0a-36bdafe109ed + Microsoft.DotNet.Tools.Run ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\$(MSBuildProjectName)\ @@ -17,4 +16,4 @@ 2.0 - + \ No newline at end of file diff --git a/src/Microsoft.DotNet.Tools.Run/Program.cs b/src/Microsoft.DotNet.Tools.Run/Program.cs index 1f231eb00..52f82af3b 100644 --- a/src/Microsoft.DotNet.Tools.Run/Program.cs +++ b/src/Microsoft.DotNet.Tools.Run/Program.cs @@ -24,16 +24,16 @@ namespace Microsoft.DotNet.Tools.Run var framework = app.Option("-f|--framework ", "Compile a specific framework", CommandOptionType.MultipleValue); var configuration = app.Option("-c|--configuration ", "Configuration under which to build", CommandOptionType.SingleValue); - var preserveTemporaryOutput = app.Option("-p|--preserve-temporary", "Keep the output's temporary directory around", CommandOptionType.NoValue); - var project = app.Argument("", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory"); + var preserveTemporaryOutput = app.Option("-t|--preserve-temporary", "Keep the output's temporary directory around", CommandOptionType.NoValue); + var project = app.Option("-p|--project ", "The path to the project to run (defaults to the current directory)", CommandOptionType.SingleValue); app.OnExecute(() => { // Locate the project and get the name and full path - var path = project.Value; - if (string.IsNullOrEmpty(path)) + var path = Directory.GetCurrentDirectory(); + if(project.HasValue()) { - path = Directory.GetCurrentDirectory(); + path = project.Value(); } var contexts = ProjectContext.CreateContextForEachFramework(path); @@ -69,8 +69,8 @@ namespace Microsoft.DotNet.Tools.Run var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); // Compile to that directory - var result = Command.Create($"dotnet-compile", $"--output \"{tempDir}\" --framework \"{context.TargetFramework}\" --configuration \"{configuration}\"") - .ForwardStdOut() + var result = Command.Create($"dotnet-compile", $"--output \"{tempDir}\" --framework \"{context.TargetFramework}\" --configuration \"{configuration}\" {context.ProjectFile.ProjectDirectory}") + .ForwardStdOut(onlyIfVerbose: true) .ForwardStdErr() .Execute(); diff --git a/src/corehost/inc/args.h b/src/corehost/inc/args.h index 23217d138..0a363d20b 100644 --- a/src/corehost/inc/args.h +++ b/src/corehost/inc/args.h @@ -6,15 +6,15 @@ struct arguments_t { - trace::level_t trace_level; - pal::string_t own_path; - pal::string_t managed_application; - pal::string_t clr_path; + trace::level_t trace_level; + pal::string_t own_path; + pal::string_t managed_application; + pal::string_t clr_path; - int app_argc; - const pal::char_t** app_argv; + int app_argc; + const pal::char_t** app_argv; - arguments_t(); + arguments_t(); }; bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args); diff --git a/src/corehost/inc/coreclr.h b/src/corehost/inc/coreclr.h index dc48d2ced..06d5462fe 100644 --- a/src/corehost/inc/coreclr.h +++ b/src/corehost/inc/coreclr.h @@ -6,31 +6,31 @@ namespace coreclr { - typedef void* host_handle_t; - typedef unsigned int domain_id_t; + typedef void* host_handle_t; + typedef unsigned int domain_id_t; - bool bind(const pal::string_t& libcoreclr_path); + bool bind(const pal::string_t& libcoreclr_path); - void unload(); + void unload(); - pal::hresult_t initialize( - const char* exe_path, - const char* app_domain_friendly_name, - const char** property_keys, - const char** property_values, - int property_count, - host_handle_t* host_handle, - domain_id_t* domain_id); + pal::hresult_t initialize( + const char* exe_path, + const char* app_domain_friendly_name, + const char** property_keys, + const char** property_values, + int property_count, + host_handle_t* host_handle, + domain_id_t* domain_id); - pal::hresult_t shutdown(host_handle_t host_handle, domain_id_t domain_id); + pal::hresult_t shutdown(host_handle_t host_handle, domain_id_t domain_id); - pal::hresult_t execute_assembly( - host_handle_t host_handle, - domain_id_t domain_id, - int argc, - const char** argv, - const char* managed_assembly_path, - unsigned int* exit_code); + pal::hresult_t execute_assembly( + host_handle_t host_handle, + domain_id_t domain_id, + int argc, + const char** argv, + const char* managed_assembly_path, + unsigned int* exit_code); }; #endif diff --git a/src/corehost/inc/pal.h b/src/corehost/inc/pal.h index 6ba564f0f..4bc9bb2d5 100644 --- a/src/corehost/inc/pal.h +++ b/src/corehost/inc/pal.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -58,50 +59,52 @@ namespace pal { #if defined(_WIN32) - typedef wchar_t char_t; - typedef std::wstring string_t; - typedef std::ifstream ifstream_t; - typedef HRESULT hresult_t; - typedef HMODULE dll_t; - typedef FARPROC proc_t; + typedef wchar_t char_t; + typedef std::wstring string_t; + typedef std::wstringstream stringstream_t; + typedef std::ifstream ifstream_t; + typedef HRESULT hresult_t; + typedef HMODULE dll_t; + typedef FARPROC proc_t; - inline int strcmp(const char_t* str1, const char_t* str2) { return ::wcscmp(str1, str2); } - inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::_wcsicmp(str1, str2); } - inline size_t strlen(const char_t* str) { return ::wcslen(str); } - inline void err_vprintf(const char_t* format, va_list vl) { ::vfwprintf(stderr, format, vl); ::fputws(_X("\r\n"), stderr); } + inline int strcmp(const char_t* str1, const char_t* str2) { return ::wcscmp(str1, str2); } + inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::_wcsicmp(str1, str2); } + inline size_t strlen(const char_t* str) { return ::wcslen(str); } + inline void err_vprintf(const char_t* format, va_list vl) { ::vfwprintf(stderr, format, vl); ::fputws(_X("\r\n"), stderr); } - pal::string_t to_palstring(const std::string& str); - std::string to_stdstring(const pal::string_t& str); + pal::string_t to_palstring(const std::string& str); + std::string to_stdstring(const pal::string_t& str); #else - typedef char char_t; - typedef std::string string_t; - typedef std::ifstream ifstream_t; - typedef long hresult_t; - typedef void* dll_t; - typedef void* proc_t; + typedef char char_t; + typedef std::string string_t; + typedef std::stringstream stringstream_t; + typedef std::ifstream ifstream_t; + typedef long hresult_t; + typedef void* dll_t; + typedef void* proc_t; - inline int strcmp(const char_t* str1, const char_t* str2) { return ::strcmp(str1, str2); } - inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::strcasecmp(str1, str2); } - inline size_t strlen(const char_t* str) { return ::strlen(str); } - inline void err_vprintf(const char_t* format, va_list vl) { ::vfprintf(stderr, format, vl); ::fputc('\n', stderr); } - inline pal::string_t to_palstring(const std::string& str) { return str; } - inline std::string to_stdstring(const pal::string_t& str) { return str; } + inline int strcmp(const char_t* str1, const char_t* str2) { return ::strcmp(str1, str2); } + inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::strcasecmp(str1, str2); } + inline size_t strlen(const char_t* str) { return ::strlen(str); } + inline void err_vprintf(const char_t* format, va_list vl) { ::vfprintf(stderr, format, vl); ::fputc('\n', stderr); } + inline pal::string_t to_palstring(const std::string& str) { return str; } + inline std::string to_stdstring(const pal::string_t& str) { return str; } #endif - bool realpath(string_t& path); - bool file_exists(const string_t& path); - std::vector readdir(const string_t& path); + bool realpath(string_t& path); + bool file_exists(const string_t& path); + std::vector readdir(const string_t& path); - bool get_own_executable_path(string_t& recv); - bool getenv(const char_t* name, string_t& recv); - bool get_default_packages_directory(string_t& recv); - bool is_path_rooted(const string_t& path); + bool get_own_executable_path(string_t& recv); + bool getenv(const char_t* name, string_t& recv); + bool get_default_packages_directory(string_t& recv); + bool is_path_rooted(const string_t& path); - int xtoi(const char_t* input); + int xtoi(const char_t* input); - bool load_library(const char_t* path, dll_t& dll); - proc_t get_symbol(dll_t library, const char* name); - void unload_library(dll_t library); + bool load_library(const char_t* path, dll_t& dll); + proc_t get_symbol(dll_t library, const char* name); + void unload_library(dll_t library); } #endif // PAL_H diff --git a/src/corehost/inc/tpafile.h b/src/corehost/inc/tpafile.h index fe9564a46..d8c347d3f 100644 --- a/src/corehost/inc/tpafile.h +++ b/src/corehost/inc/tpafile.h @@ -8,31 +8,31 @@ struct tpaentry_t { - pal::string_t library_type; - pal::string_t library_name; - pal::string_t library_version; - pal::string_t library_hash; - pal::string_t asset_type; - pal::string_t asset_name; - pal::string_t relative_path; + pal::string_t library_type; + pal::string_t library_name; + pal::string_t library_version; + pal::string_t library_hash; + pal::string_t asset_type; + pal::string_t asset_name; + pal::string_t relative_path; }; class tpafile { public: - bool load(pal::string_t path); + bool load(pal::string_t path); - void add_from_local_dir(const pal::string_t& dir); - void add_package_dir(pal::string_t dir); - void add_native_search_path(pal::string_t dir); + void add_from_local_dir(const pal::string_t& dir); + void add_package_dir(pal::string_t dir); + void add_native_search_path(pal::string_t dir); - void write_tpa_list(pal::string_t& output); - void write_native_paths(pal::string_t& output); + void write_tpa_list(pal::string_t& output); + void write_native_paths(pal::string_t& output); private: - std::vector m_entries; - std::vector m_native_search_paths; - std::vector m_package_search_paths; + std::vector m_entries; + std::vector m_native_search_paths; + std::vector m_package_search_paths; }; #endif // TPAFILE_H diff --git a/src/corehost/inc/trace.h b/src/corehost/inc/trace.h index 7eb40c99b..2479d955f 100644 --- a/src/corehost/inc/trace.h +++ b/src/corehost/inc/trace.h @@ -5,20 +5,20 @@ namespace trace { - enum class level_t - { - Error = 0, - Warning = 1, - Info = 2, - Verbose = 3 - }; + enum class level_t + { + Error = 0, + Warning = 1, + Info = 2, + Verbose = 3 + }; - void set_level(level_t level); - bool is_enabled(level_t level); - void verbose(const pal::char_t* format, ...); - void info(const pal::char_t* format, ...); - void warning(const pal::char_t* format, ...); - void error(const pal::char_t* format, ...); + void set_level(level_t level); + bool is_enabled(level_t level); + void verbose(const pal::char_t* format, ...); + void info(const pal::char_t* format, ...); + void warning(const pal::char_t* format, ...); + void error(const pal::char_t* format, ...); }; #endif // TRACE_H diff --git a/src/corehost/inc/utils.h b/src/corehost/inc/utils.h index 717e18466..3d49f4e27 100644 --- a/src/corehost/inc/utils.h +++ b/src/corehost/inc/utils.h @@ -7,6 +7,7 @@ bool ends_with(const pal::string_t& value, const pal::string_t& suffix); pal::string_t get_executable(const pal::string_t& filename); pal::string_t get_directory(const pal::string_t& path); pal::string_t get_filename(const pal::string_t& path); +bool find_coreclr(const pal::string_t& appbase, pal::string_t& recv); void append_path(pal::string_t& path1, const pal::char_t* path2); #endif diff --git a/src/corehost/src/args.cpp b/src/corehost/src/args.cpp index 1824391c8..0129e7491 100644 --- a/src/corehost/src/args.cpp +++ b/src/corehost/src/args.cpp @@ -2,73 +2,73 @@ #include "utils.h" arguments_t::arguments_t() : - trace_level(trace::level_t::Error), - managed_application(_X("")), - clr_path(_X("")), - app_argc(0), - app_argv(nullptr) + trace_level(trace::level_t::Error), + managed_application(_X("")), + clr_path(_X("")), + app_argc(0), + app_argv(nullptr) { } void display_help() { - xerr << - _X("Usage: " HOST_EXE_NAME " [ASSEMBLY] [ARGUMENTS]\n") - _X("Execute the specified managed assembly with the passed in arguments\n\n") - _X("The Host's behavior can be altered using the following environment variables:\n") - _X(" CLRHOST_CLR_PATH Set the directory which contains the CoreCLR runtime. Overrides all other values for CLR search paths\n") - _X(" CLRHOST_TRACE Set to affect trace levels (0 = Errors only (default), 1 = Warnings, 2 = Info, 3 = Verbose)\n"); + xerr << + _X("Usage: " HOST_EXE_NAME " [ASSEMBLY] [ARGUMENTS]\n") + _X("Execute the specified managed assembly with the passed in arguments\n\n") + _X("The Host's behavior can be altered using the following environment variables:\n") + _X(" CLRHOST_CLR_PATH Set the directory which contains the CoreCLR runtime. Overrides all other values for CLR search paths\n") + _X(" CLRHOST_TRACE Set to affect trace levels (0 = Errors only (default), 1 = Warnings, 2 = Info, 3 = Verbose)\n"); } bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args) { - // Get the full name of the application - if (!pal::get_own_executable_path(args.own_path) || !pal::realpath(args.own_path)) - { - trace::error(_X("failed to locate current executable")); - return false; - } + // Get the full name of the application + if (!pal::get_own_executable_path(args.own_path) || !pal::realpath(args.own_path)) + { + trace::error(_X("failed to locate current executable")); + return false; + } - auto own_name = get_filename(args.own_path); - auto own_dir = get_directory(args.own_path); + auto own_name = get_filename(args.own_path); + auto own_dir = get_directory(args.own_path); - if (own_name.compare(HOST_EXE_NAME) == 0) - { - // corerun mode. First argument is managed app - if (argc < 2) - { - display_help(); - return false; - } - args.managed_application = pal::string_t(argv[1]); - args.app_argc = argc - 2; - args.app_argv = &argv[2]; - } - else - { - // coreconsole mode. Find the managed app in the same directory - pal::string_t managed_app(own_dir); - managed_app.push_back(DIR_SEPARATOR); - managed_app.append(get_executable(own_name)); - managed_app.append(_X(".dll")); - args.managed_application = managed_app; - args.app_argv = &argv[1]; - args.app_argc = argc - 1; - } + if (own_name.compare(HOST_EXE_NAME) == 0) + { + // corerun mode. First argument is managed app + if (argc < 2) + { + display_help(); + return false; + } + args.managed_application = pal::string_t(argv[1]); + args.app_argc = argc - 2; + args.app_argv = &argv[2]; + } + else + { + // coreconsole mode. Find the managed app in the same directory + pal::string_t managed_app(own_dir); + managed_app.push_back(DIR_SEPARATOR); + managed_app.append(get_executable(own_name)); + managed_app.append(_X(".dll")); + args.managed_application = managed_app; + args.app_argv = &argv[1]; + args.app_argc = argc - 1; + } - // Read trace environment variable - pal::string_t trace_str; - if (pal::getenv(_X("CLRHOST_TRACE"), trace_str)) - { - auto trace_val = pal::xtoi(trace_str.c_str()); - if (trace_val >= (int)trace::level_t::Error && trace_val <= (int)trace::level_t::Verbose) - { - args.trace_level = (trace::level_t)trace_val; - } - } + // Read trace environment variable + pal::string_t trace_str; + if (pal::getenv(_X("CLRHOST_TRACE"), trace_str)) + { + auto trace_val = pal::xtoi(trace_str.c_str()); + if (trace_val >= (int)trace::level_t::Error && trace_val <= (int)trace::level_t::Verbose) + { + args.trace_level = (trace::level_t)trace_val; + } + } - // Read CLR path from environment variable - pal::getenv(_X("CLRHOST_CLR_PATH"), args.clr_path); + // Read CLR path from environment variable + pal::getenv(_X("CLRHOST_CLR_PATH"), args.clr_path); - return true; + return true; } diff --git a/src/corehost/src/coreclr.cpp b/src/corehost/src/coreclr.cpp index 5f7aeaa45..533f2d65d 100644 --- a/src/corehost/src/coreclr.cpp +++ b/src/corehost/src/coreclr.cpp @@ -6,28 +6,28 @@ static pal::dll_t g_coreclr = nullptr; // Prototype of the coreclr_initialize function from coreclr.dll -typedef pal::hresult_t (*coreclr_initialize_fn)( - const char* exePath, - const char* appDomainFriendlyName, - int propertyCount, - const char** propertyKeys, - const char** propertyValues, - coreclr::host_handle_t* hostHandle, - unsigned int* domainId); +typedef pal::hresult_t(*coreclr_initialize_fn)( + const char* exePath, + const char* appDomainFriendlyName, + int propertyCount, + const char** propertyKeys, + const char** propertyValues, + coreclr::host_handle_t* hostHandle, + unsigned int* domainId); // Prototype of the coreclr_shutdown function from coreclr.dll -typedef pal::hresult_t (*coreclr_shutdown_fn)( - coreclr::host_handle_t hostHandle, - unsigned int domainId); +typedef pal::hresult_t(*coreclr_shutdown_fn)( + coreclr::host_handle_t hostHandle, + unsigned int domainId); // Prototype of the coreclr_execute_assembly function from coreclr.dll -typedef pal::hresult_t (*coreclr_execute_assembly_fn)( - coreclr::host_handle_t hostHandle, - unsigned int domainId, - int argc, - const char** argv, - const char* managedAssemblyPath, - unsigned int* exitCode); +typedef pal::hresult_t(*coreclr_execute_assembly_fn)( + coreclr::host_handle_t hostHandle, + unsigned int domainId, + int argc, + const char** argv, + const char* managedAssemblyPath, + unsigned int* exitCode); static coreclr_shutdown_fn coreclr_shutdown = nullptr; static coreclr_initialize_fn coreclr_initialize = nullptr; @@ -35,73 +35,73 @@ static coreclr_execute_assembly_fn coreclr_execute_assembly = nullptr; bool coreclr::bind(const pal::string_t& libcoreclr_path) { - assert(g_coreclr == nullptr); + assert(g_coreclr == nullptr); - pal::string_t coreclr_dll_path(libcoreclr_path); - append_path(coreclr_dll_path, LIBCORECLR_NAME); + pal::string_t coreclr_dll_path(libcoreclr_path); + append_path(coreclr_dll_path, LIBCORECLR_NAME); - if(!pal::load_library(coreclr_dll_path.c_str(), g_coreclr)) - { - return false; - } + if (!pal::load_library(coreclr_dll_path.c_str(), g_coreclr)) + { + return false; + } - coreclr_initialize = (coreclr_initialize_fn)pal::get_symbol(g_coreclr, "coreclr_initialize"); - coreclr_shutdown = (coreclr_shutdown_fn)pal::get_symbol(g_coreclr, "coreclr_shutdown"); - coreclr_execute_assembly = (coreclr_execute_assembly_fn)pal::get_symbol(g_coreclr, "coreclr_execute_assembly"); + coreclr_initialize = (coreclr_initialize_fn)pal::get_symbol(g_coreclr, "coreclr_initialize"); + coreclr_shutdown = (coreclr_shutdown_fn)pal::get_symbol(g_coreclr, "coreclr_shutdown"); + coreclr_execute_assembly = (coreclr_execute_assembly_fn)pal::get_symbol(g_coreclr, "coreclr_execute_assembly"); - return true; + return true; } void coreclr::unload() { - assert(g_coreclr != nullptr && coreclr_initialize != nullptr); + assert(g_coreclr != nullptr && coreclr_initialize != nullptr); - pal::unload_library(g_coreclr); + pal::unload_library(g_coreclr); } pal::hresult_t coreclr::initialize( - const char* exe_path, - const char* app_domain_friendly_name, - const char** property_keys, - const char** property_values, - int property_count, - host_handle_t* host_handle, - domain_id_t* domain_id) + const char* exe_path, + const char* app_domain_friendly_name, + const char** property_keys, + const char** property_values, + int property_count, + host_handle_t* host_handle, + domain_id_t* domain_id) { - assert(g_coreclr != nullptr && coreclr_initialize != nullptr); + assert(g_coreclr != nullptr && coreclr_initialize != nullptr); - return coreclr_initialize( - exe_path, - app_domain_friendly_name, - property_count, - property_keys, - property_values, - host_handle, - domain_id); + return coreclr_initialize( + exe_path, + app_domain_friendly_name, + property_count, + property_keys, + property_values, + host_handle, + domain_id); } pal::hresult_t coreclr::shutdown(host_handle_t host_handle, domain_id_t domain_id) { - assert(g_coreclr != nullptr && coreclr_shutdown != nullptr); + assert(g_coreclr != nullptr && coreclr_shutdown != nullptr); - return coreclr_shutdown(host_handle, domain_id); + return coreclr_shutdown(host_handle, domain_id); } pal::hresult_t coreclr::execute_assembly( - host_handle_t host_handle, - domain_id_t domain_id, - int argc, - const char** argv, - const char* managed_assembly_path, - unsigned int* exit_code) + host_handle_t host_handle, + domain_id_t domain_id, + int argc, + const char** argv, + const char* managed_assembly_path, + unsigned int* exit_code) { - assert(g_coreclr != nullptr && coreclr_execute_assembly != nullptr); + assert(g_coreclr != nullptr && coreclr_execute_assembly != nullptr); - return coreclr_execute_assembly( - host_handle, - domain_id, - argc, - argv, - managed_assembly_path, - exit_code); + return coreclr_execute_assembly( + host_handle, + domain_id, + argc, + argv, + managed_assembly_path, + exit_code); } diff --git a/src/corehost/src/main.cpp b/src/corehost/src/main.cpp index 957b3a451..a5b6c7235 100644 --- a/src/corehost/src/main.cpp +++ b/src/corehost/src/main.cpp @@ -7,143 +7,143 @@ void get_tpafile_path(const pal::string_t& app_base, const pal::string_t& app_name, pal::string_t& tpapath) { - tpapath.reserve(app_base.length() + app_name.length() + 5); + tpapath.reserve(app_base.length() + app_name.length() + 5); - tpapath.append(app_base); - tpapath.push_back(DIR_SEPARATOR); + tpapath.append(app_base); + tpapath.push_back(DIR_SEPARATOR); - // Remove the extension from the app_name - auto ext_location = app_name.find_last_of('.'); - if (ext_location != std::string::npos) - { - tpapath.append(app_name.substr(0, ext_location)); - } - else - { - tpapath.append(app_name); - } - tpapath.append(_X(".deps")); + // Remove the extension from the app_name + auto ext_location = app_name.find_last_of('.'); + if (ext_location != std::string::npos) + { + tpapath.append(app_name.substr(0, ext_location)); + } + else + { + tpapath.append(app_name); + } + tpapath.append(_X(".deps")); } int run(arguments_t args, pal::string_t app_base, tpafile tpa) { - tpa.add_from_local_dir(app_base); + tpa.add_from_local_dir(app_base); - // Add packages directory - pal::string_t packages_dir; - if (!pal::get_default_packages_directory(packages_dir)) - { - trace::info(_X("did not find local packages directory")); + // Add packages directory + pal::string_t packages_dir; + if (!pal::get_default_packages_directory(packages_dir)) + { + trace::info(_X("did not find local packages directory")); - // We can continue, the app may have it's dependencies locally - } - else - { - trace::info(_X("using packages directory: %s"), packages_dir.c_str()); - tpa.add_package_dir(packages_dir); - } + // We can continue, the app may have it's dependencies locally + } + else + { + trace::info(_X("using packages directory: %s"), packages_dir.c_str()); + tpa.add_package_dir(packages_dir); + } - // Add native search path - trace::info(_X("using native search path: %s"), packages_dir.c_str()); - tpa.add_native_search_path(args.clr_path); + // Add native search path + trace::info(_X("using native search path: %s"), packages_dir.c_str()); + tpa.add_native_search_path(args.clr_path); - // Build TPA list and search paths - pal::string_t tpalist; - tpa.write_tpa_list(tpalist); + // Build TPA list and search paths + pal::string_t tpalist; + tpa.write_tpa_list(tpalist); - pal::string_t search_paths; - tpa.write_native_paths(search_paths); + pal::string_t search_paths; + tpa.write_native_paths(search_paths); - // Build CoreCLR properties - const char* property_keys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", - "APP_PATHS", - "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", - "AppDomainCompatSwitch" - }; + // Build CoreCLR properties + const char* property_keys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", + "APP_PATHS", + "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", + "AppDomainCompatSwitch" + }; - auto tpa_cstr = pal::to_stdstring(tpalist); - auto app_base_cstr = pal::to_stdstring(app_base); - auto search_paths_cstr = pal::to_stdstring(search_paths); + auto tpa_cstr = pal::to_stdstring(tpalist); + auto app_base_cstr = pal::to_stdstring(app_base); + auto search_paths_cstr = pal::to_stdstring(search_paths); - const char* property_values[] = { - // TRUSTED_PLATFORM_ASSEMBLIES - tpa_cstr.c_str(), - // APP_PATHS - app_base_cstr.c_str(), - // APP_NI_PATHS - app_base_cstr.c_str(), - // NATIVE_DLL_SEARCH_DIRECTORIES - search_paths_cstr.c_str(), - // AppDomainCompatSwitch - "UseLatestBehaviorWhenTFMNotSpecified" - }; + const char* property_values[] = { + // TRUSTED_PLATFORM_ASSEMBLIES + tpa_cstr.c_str(), + // APP_PATHS + app_base_cstr.c_str(), + // APP_NI_PATHS + app_base_cstr.c_str(), + // NATIVE_DLL_SEARCH_DIRECTORIES + search_paths_cstr.c_str(), + // AppDomainCompatSwitch + "UseLatestBehaviorWhenTFMNotSpecified" + }; - // Dump TPA list - trace::verbose(_X("TPA List: %s"), tpalist.c_str()); + // Dump TPA list + trace::verbose(_X("TPA List: %s"), tpalist.c_str()); - // Dump native search paths - trace::verbose(_X("Native Paths: %s"), search_paths.c_str()); + // Dump native search paths + trace::verbose(_X("Native Paths: %s"), search_paths.c_str()); - // Bind CoreCLR - if (!coreclr::bind(args.clr_path)) - { - trace::error(_X("failed to bind to coreclr")); - return 1; - } + // Bind CoreCLR + if (!coreclr::bind(args.clr_path)) + { + trace::error(_X("failed to bind to coreclr")); + return 1; + } - // Initialize CoreCLR - coreclr::host_handle_t host_handle; - coreclr::domain_id_t domain_id; - auto hr = coreclr::initialize( - pal::to_stdstring(args.own_path).c_str(), - "clrhost", - property_keys, - property_values, - sizeof(property_keys) / sizeof(property_keys[0]), - &host_handle, - &domain_id); - if (!SUCCEEDED(hr)) - { - trace::error(_X("failed to initialize CoreCLR, HRESULT: 0x%X"), hr); - return 1; - } + // Initialize CoreCLR + coreclr::host_handle_t host_handle; + coreclr::domain_id_t domain_id; + auto hr = coreclr::initialize( + pal::to_stdstring(args.own_path).c_str(), + "clrhost", + property_keys, + property_values, + sizeof(property_keys) / sizeof(property_keys[0]), + &host_handle, + &domain_id); + if (!SUCCEEDED(hr)) + { + trace::error(_X("failed to initialize CoreCLR, HRESULT: 0x%X"), hr); + return 1; + } - // Convert the args (probably not the most performant way to do this...) - auto argv_strs = new std::string[args.app_argc]; - auto argv = new const char*[args.app_argc]; - for (int i = 0; i < args.app_argc; i++) - { - argv_strs[i] = pal::to_stdstring(pal::string_t(args.app_argv[i])); - argv[i] = argv_strs[i].c_str(); - } + // Convert the args (probably not the most performant way to do this...) + auto argv_strs = new std::string[args.app_argc]; + auto argv = new const char*[args.app_argc]; + for (int i = 0; i < args.app_argc; i++) + { + argv_strs[i] = pal::to_stdstring(pal::string_t(args.app_argv[i])); + argv[i] = argv_strs[i].c_str(); + } - // Execute the application - unsigned int exit_code = 1; - hr = coreclr::execute_assembly( - host_handle, - domain_id, - args.app_argc, - argv, - pal::to_stdstring(args.managed_application).c_str(), - &exit_code); - if (!SUCCEEDED(hr)) - { - trace::error(_X("failed to execute managed app, HRESULT: 0x%X"), hr); - return 1; - } + // Execute the application + unsigned int exit_code = 1; + hr = coreclr::execute_assembly( + host_handle, + domain_id, + args.app_argc, + argv, + pal::to_stdstring(args.managed_application).c_str(), + &exit_code); + if (!SUCCEEDED(hr)) + { + trace::error(_X("failed to execute managed app, HRESULT: 0x%X"), hr); + return 1; + } - // Shut down the CoreCLR - hr = coreclr::shutdown(host_handle, domain_id); - if (!SUCCEEDED(hr)) - { - trace::warning(_X("failed to shut down CoreCLR, HRESULT: 0x%X"), hr); - } + // Shut down the CoreCLR + hr = coreclr::shutdown(host_handle, domain_id); + if (!SUCCEEDED(hr)) + { + trace::warning(_X("failed to shut down CoreCLR, HRESULT: 0x%X"), hr); + } - coreclr::unload(); + coreclr::unload(); - return exit_code; + return exit_code; } #if defined(_WIN32) @@ -152,63 +152,66 @@ int __cdecl wmain(const int argc, const pal::char_t* argv[]) int main(const int argc, const pal::char_t* argv[]) #endif { - arguments_t args; - if (!parse_arguments(argc, argv, args)) - { - return 1; - } + arguments_t args; + if (!parse_arguments(argc, argv, args)) + { + return 1; + } - // Configure tracing - trace::set_level(args.trace_level); - trace::info(_X("tracing enabled")); + // Configure tracing + trace::set_level(args.trace_level); + trace::info(_X("tracing enabled")); - // Resolve paths - if (!pal::realpath(args.managed_application)) - { - trace::error(_X("failed to locate managed application: %s"), args.managed_application.c_str()); - return 1; - } - trace::info(_X("preparing to launch managed application: %s"), args.managed_application.c_str()); - trace::info(_X("host path: %s"), args.own_path.c_str()); + // Resolve paths + if (!pal::realpath(args.managed_application)) + { + trace::error(_X("failed to locate managed application: %s"), args.managed_application.c_str()); + return 1; + } + trace::info(_X("preparing to launch managed application: %s"), args.managed_application.c_str()); + trace::info(_X("host path: %s"), args.own_path.c_str()); - pal::string_t argstr; - for (int i = 0; i < args.app_argc; i++) - { - argstr.append(args.app_argv[i]); - argstr.append(_X(",")); - } - trace::info(_X("App argc: %d"), args.app_argc); - trace::info(_X("App argv: %s"), argstr.c_str()); + pal::string_t argstr; + for (int i = 0; i < args.app_argc; i++) + { + argstr.append(args.app_argv[i]); + argstr.append(_X(",")); + } + trace::info(_X("App argc: %d"), args.app_argc); + trace::info(_X("App argv: %s"), argstr.c_str()); - auto app_base = get_directory(args.managed_application); - auto app_name = get_filename(args.managed_application); + auto app_base = get_directory(args.managed_application); + auto app_name = get_filename(args.managed_application); - if (args.clr_path.empty()) - { - // Use the directory containing the managed assembly - args.clr_path = app_base; - } + if (args.clr_path.empty()) + { + // Use the directory containing the managed assembly + if (!find_coreclr(app_base, args.clr_path)) + { + trace::error(_X("failed to locate CLR files")); + return 1; + } + } - if (!pal::realpath(args.clr_path)) - { - trace::error(_X("failed to locate CLR files at %s"), args.clr_path.c_str()); - return 1; - } + if (!pal::realpath(args.clr_path)) + { + trace::error(_X("failed to locate CLR files at %s"), args.clr_path.c_str()); + return 1; + } - trace::info(_X("using CLR files from: %s"), args.clr_path.c_str()); + trace::info(_X("using CLR files from: %s"), args.clr_path.c_str()); + trace::info(_X("preparing to launch: %s"), app_name.c_str()); + trace::info(_X("using app base: %s"), app_base.c_str()); - trace::info(_X("preparing to launch: %s"), app_name.c_str()); - trace::info(_X("using app base: %s"), app_base.c_str()); - - // Check for and load tpa file - pal::string_t tpafile_path; - get_tpafile_path(app_base, app_name, tpafile_path); - trace::info(_X("checking for TPA File at: %s"), tpafile_path.c_str()); - tpafile tpa; - if (!tpa.load(tpafile_path)) - { - trace::error(_X("invalid TPA file")); - return 1; - } - return run(args, app_base, tpa); + // Check for and load tpa file + pal::string_t tpafile_path; + get_tpafile_path(app_base, app_name, tpafile_path); + trace::info(_X("checking for TPA File at: %s"), tpafile_path.c_str()); + tpafile tpa; + if (!tpa.load(tpafile_path)) + { + trace::error(_X("invalid TPA file")); + return 1; + } + return run(args, app_base, tpa); } diff --git a/src/corehost/src/pal.windows.cpp b/src/corehost/src/pal.windows.cpp index c5b3e7cff..6366885e3 100644 --- a/src/corehost/src/pal.windows.cpp +++ b/src/corehost/src/pal.windows.cpp @@ -9,148 +9,148 @@ static std::wstring_convert, wchar_t> g_converter; bool pal::load_library(const char_t* path, dll_t& dll) { - dll = ::LoadLibraryW(path); - if (dll == nullptr) - { - trace::error(_X("failed to load coreclr.dll from %s, HRESULT: 0x%X"), path, HRESULT_FROM_WIN32(GetLastError())); - return false; - } + dll = ::LoadLibraryW(path); + if (dll == nullptr) + { + trace::error(_X("failed to load coreclr.dll from %s, HRESULT: 0x%X"), path, HRESULT_FROM_WIN32(GetLastError())); + return false; + } - // Pin the module - HMODULE dummy_module; - if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, path, &dummy_module)) - { - trace::error(_X("failed to pin library: %s")); - return false; - } + // Pin the module + HMODULE dummy_module; + if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, path, &dummy_module)) + { + trace::error(_X("failed to pin library: %s")); + return false; + } - if (trace::is_enabled(trace::level_t::Info)) - { - pal::char_t buf[PATH_MAX]; - ::GetModuleFileNameW(dll, buf, PATH_MAX); - trace::info(_X("loaded library from %s"), buf); - } + if (trace::is_enabled(trace::level_t::Info)) + { + pal::char_t buf[PATH_MAX]; + ::GetModuleFileNameW(dll, buf, PATH_MAX); + trace::info(_X("loaded library from %s"), buf); + } - return true; + return true; } pal::proc_t pal::get_symbol(dll_t library, const char* name) { - return ::GetProcAddress(library, name); + return ::GetProcAddress(library, name); } void pal::unload_library(dll_t library) { - // No-op. On windows, we pin the library, so it can't be unloaded. + // No-op. On windows, we pin the library, so it can't be unloaded. } bool pal::get_default_packages_directory(string_t& recv) { - if (!pal::getenv(_X("USERPROFILE"), recv)) - { - return false; - } - append_path(recv, _X(".dnx")); - append_path(recv, _X("packages")); - return true; + if (!pal::getenv(_X("USERPROFILE"), recv)) + { + return false; + } + append_path(recv, _X(".dnx")); + append_path(recv, _X("packages")); + return true; } bool pal::is_path_rooted(const string_t& path) { - return path.length() >= 2 && path[1] == L':'; + return path.length() >= 2 && path[1] == L':'; } bool pal::getenv(const char_t* name, string_t& recv) { - auto length = ::GetEnvironmentVariableW(name, nullptr, 0); - if (length == 0) - { - auto err = GetLastError(); - if (err == ERROR_ENVVAR_NOT_FOUND) - { - // Leave the receiver empty and return success - return true; - } - trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError())); - return false; - } - auto buf = new char_t[length]; - if (::GetEnvironmentVariableW(name, buf, length) == 0) - { - trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError())); - return false; - } + auto length = ::GetEnvironmentVariableW(name, nullptr, 0); + if (length == 0) + { + auto err = GetLastError(); + if (err == ERROR_ENVVAR_NOT_FOUND) + { + // Leave the receiver empty and return success + return true; + } + trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError())); + return false; + } + auto buf = new char_t[length]; + if (::GetEnvironmentVariableW(name, buf, length) == 0) + { + trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError())); + return false; + } - recv.assign(buf); - delete[] buf; + recv.assign(buf); + delete[] buf; - return true; + return true; } int pal::xtoi(const char_t* input) { - return ::_wtoi(input); + return ::_wtoi(input); } bool pal::get_own_executable_path(string_t& recv) { - char_t program_path[MAX_PATH]; - DWORD dwModuleFileName = ::GetModuleFileNameW(NULL, program_path, MAX_PATH); - if (dwModuleFileName == 0 || dwModuleFileName >= MAX_PATH) { - return false; - } - recv.assign(program_path); - return true; + char_t program_path[MAX_PATH]; + DWORD dwModuleFileName = ::GetModuleFileNameW(NULL, program_path, MAX_PATH); + if (dwModuleFileName == 0 || dwModuleFileName >= MAX_PATH) { + return false; + } + recv.assign(program_path); + return true; } std::string pal::to_stdstring(const string_t& str) { - return g_converter.to_bytes(str); + return g_converter.to_bytes(str); } pal::string_t pal::to_palstring(const std::string& str) { - return g_converter.from_bytes(str); + return g_converter.from_bytes(str); } bool pal::realpath(string_t& path) { - char_t buf[MAX_PATH]; - auto res = ::GetFullPathNameW(path.c_str(), MAX_PATH, buf, nullptr); - if (res == 0 || res > MAX_PATH) - { - trace::error(_X("error resolving path: %s"), path.c_str()); - return false; - } - path.assign(buf); - return true; + char_t buf[MAX_PATH]; + auto res = ::GetFullPathNameW(path.c_str(), MAX_PATH, buf, nullptr); + if (res == 0 || res > MAX_PATH) + { + trace::error(_X("error resolving path: %s"), path.c_str()); + return false; + } + path.assign(buf); + return true; } bool pal::file_exists(const string_t& path) { - WIN32_FIND_DATAW data; - auto find_handle = ::FindFirstFileW(path.c_str(), &data); - bool found = find_handle != INVALID_HANDLE_VALUE; - ::FindClose(find_handle); - return found; + WIN32_FIND_DATAW data; + auto find_handle = ::FindFirstFileW(path.c_str(), &data); + bool found = find_handle != INVALID_HANDLE_VALUE; + ::FindClose(find_handle); + return found; } std::vector pal::readdir(const string_t& path) { - std::vector files; + std::vector files; - string_t search_string(path); - search_string.push_back(DIR_SEPARATOR); - search_string.push_back(L'*'); + string_t search_string(path); + search_string.push_back(DIR_SEPARATOR); + search_string.push_back(L'*'); - WIN32_FIND_DATAW data; - auto handle = ::FindFirstFileW(search_string.c_str(), &data); - do - { - string_t filepath(data.cFileName); - files.push_back(filepath); - } while (::FindNextFileW(handle, &data)); - ::FindClose(handle); + WIN32_FIND_DATAW data; + auto handle = ::FindFirstFileW(search_string.c_str(), &data); + do + { + string_t filepath(data.cFileName); + files.push_back(filepath); + } while (::FindNextFileW(handle, &data)); + ::FindClose(handle); - return files; + return files; } diff --git a/src/corehost/src/tpafile.cpp b/src/corehost/src/tpafile.cpp index e36f4b496..1d45a45fc 100644 --- a/src/corehost/src/tpafile.cpp +++ b/src/corehost/src/tpafile.cpp @@ -7,242 +7,242 @@ bool read_field(pal::string_t line, int& offset, pal::string_t& value_recv) { - // The first character should be a '"' - if (line[offset] != '"') - { - trace::error(_X("error reading TPA file")); - return false; - } - offset++; + // The first character should be a '"' + if (line[offset] != '"') + { + trace::error(_X("error reading TPA file")); + return false; + } + offset++; - // Set up destination buffer (it can't be bigger than the original line) - pal::char_t buf[PATH_MAX]; - auto buf_offset = 0; + // Set up destination buffer (it can't be bigger than the original line) + pal::char_t buf[PATH_MAX]; + auto buf_offset = 0; - // Iterate through characters in the string - for (; offset < line.length(); offset++) - { - // Is this a '\'? - if (line[offset] == '\\') - { - // Skip this character and read the next character into the buffer - offset++; - buf[buf_offset] = line[offset]; - } - // Is this a '"'? - else if (line[offset] == '\"') - { - // Done! Advance to the pointer after the input - offset++; - break; - } - else - { - // Take the character - buf[buf_offset] = line[offset]; - } - buf_offset++; - } - buf[buf_offset] = '\0'; - value_recv.assign(buf); + // Iterate through characters in the string + for (; offset < line.length(); offset++) + { + // Is this a '\'? + if (line[offset] == '\\') + { + // Skip this character and read the next character into the buffer + offset++; + buf[buf_offset] = line[offset]; + } + // Is this a '"'? + else if (line[offset] == '\"') + { + // Done! Advance to the pointer after the input + offset++; + break; + } + else + { + // Take the character + buf[buf_offset] = line[offset]; + } + buf_offset++; + } + buf[buf_offset] = '\0'; + value_recv.assign(buf); - // Consume the ',' if we have one - if (line[offset] == ',') - { - offset++; - } - return true; + // Consume the ',' if we have one + if (line[offset] == ',') + { + offset++; + } + return true; } bool tpafile::load(pal::string_t path) { - // Check if the file exists, if not, there is nothing to add - if (!pal::file_exists(path)) - { - return true; - } + // Check if the file exists, if not, there is nothing to add + if (!pal::file_exists(path)) + { + return true; + } - // Open the file - pal::ifstream_t file(path); - if (!file.good()) - { - // Failed to open the file! - return false; - } + // Open the file + pal::ifstream_t file(path); + if (!file.good()) + { + // Failed to open the file! + return false; + } - // Read lines from the file - while (true) - { - std::string line; - std::getline(file, line); - auto line_palstr = pal::to_palstring(line); - if (file.eof()) - { - break; - } + // Read lines from the file + while (true) + { + std::string line; + std::getline(file, line); + auto line_palstr = pal::to_palstring(line); + if (file.eof()) + { + break; + } - auto offset = 0; + auto offset = 0; - tpaentry_t entry; + tpaentry_t entry; - // Read fields - if (!(read_field(line_palstr, offset, entry.library_type))) return false; - if (!(read_field(line_palstr, offset, entry.library_name))) return false; - if (!(read_field(line_palstr, offset, entry.library_version))) return false; - if (!(read_field(line_palstr, offset, entry.library_hash))) return false; - if (!(read_field(line_palstr, offset, entry.asset_type))) return false; - if (!(read_field(line_palstr, offset, entry.asset_name))) return false; - if (!(read_field(line_palstr, offset, entry.relative_path))) return false; + // Read fields + if (!(read_field(line_palstr, offset, entry.library_type))) return false; + if (!(read_field(line_palstr, offset, entry.library_name))) return false; + if (!(read_field(line_palstr, offset, entry.library_version))) return false; + if (!(read_field(line_palstr, offset, entry.library_hash))) return false; + if (!(read_field(line_palstr, offset, entry.asset_type))) return false; + if (!(read_field(line_palstr, offset, entry.asset_name))) return false; + if (!(read_field(line_palstr, offset, entry.relative_path))) return false; - m_entries.push_back(entry); - } + m_entries.push_back(entry); + } - return true; + return true; } void tpafile::add_from_local_dir(const pal::string_t& dir) { - trace::verbose(_X("adding files from %s to TPA"), dir.c_str()); - const pal::char_t * const tpa_extensions[] = { - _X(".ni.dll"), // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - _X(".dll"), - _X(".ni.exe"), - _X(".exe"), - }; + trace::verbose(_X("adding files from %s to TPA"), dir.c_str()); + const pal::char_t * const tpa_extensions[] = { + _X(".ni.dll"), // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + _X(".dll"), + _X(".ni.exe"), + _X(".exe"), + }; - std::set added_assemblies; + std::set added_assemblies; - // Get directory entries - auto files = pal::readdir(dir); - for (auto ext : tpa_extensions) - { - auto len = pal::strlen(ext); - for (auto file : files) - { - // Can't be a match if it's the same length as the extension :) - if (file.length() > len) - { - // Extract the same amount of text from the end of file name - auto file_ext = file.substr(file.length() - len, len); + // Get directory entries + auto files = pal::readdir(dir); + for (auto ext : tpa_extensions) + { + auto len = pal::strlen(ext); + for (auto file : files) + { + // Can't be a match if it's the same length as the extension :) + if (file.length() > len) + { + // Extract the same amount of text from the end of file name + auto file_ext = file.substr(file.length() - len, len); - // Check if this file name matches - if (pal::strcasecmp(ext, file_ext.c_str()) == 0) - { - // Get the assembly name by stripping the extension - // and add it to the set so we can de-dupe - auto asm_name = file.substr(0, file.length() - len); + // Check if this file name matches + if (pal::strcasecmp(ext, file_ext.c_str()) == 0) + { + // Get the assembly name by stripping the extension + // and add it to the set so we can de-dupe + auto asm_name = file.substr(0, file.length() - len); - // TODO(anurse): Also check if already in TPA file - if (added_assemblies.find(asm_name) == added_assemblies.end()) - { - added_assemblies.insert(asm_name); + // TODO(anurse): Also check if already in TPA file + if (added_assemblies.find(asm_name) == added_assemblies.end()) + { + added_assemblies.insert(asm_name); - tpaentry_t entry; - entry.asset_type = pal::string_t(_X("runtime")); - entry.library_name = pal::string_t(asm_name); - entry.library_version = pal::string_t(_X("")); + tpaentry_t entry; + entry.asset_type = pal::string_t(_X("runtime")); + entry.library_name = pal::string_t(asm_name); + entry.library_version = pal::string_t(_X("")); - pal::string_t relpath(dir); - relpath.push_back(DIR_SEPARATOR); - relpath.append(file); - entry.relative_path = relpath; - entry.asset_name = asm_name; + pal::string_t relpath(dir); + relpath.push_back(DIR_SEPARATOR); + relpath.append(file); + entry.relative_path = relpath; + entry.asset_name = asm_name; - trace::verbose(_X("adding %s to TPA list from %s"), asm_name.c_str(), relpath.c_str()); - m_entries.push_back(entry); - } - } - } - } - } + trace::verbose(_X("adding %s to TPA list from %s"), asm_name.c_str(), relpath.c_str()); + m_entries.push_back(entry); + } + } + } + } + } } void tpafile::write_tpa_list(pal::string_t& output) { - std::set items; - for (auto entry : m_entries) - { - if (pal::strcmp(entry.asset_type.c_str(), _X("runtime")) == 0 && items.find(entry.asset_name) == items.end()) - { - // Resolve the full path - for (auto search_path : m_package_search_paths) - { - pal::string_t candidate; - candidate.reserve(search_path.length() + - entry.library_name.length() + - entry.library_version.length() + - entry.relative_path.length() + 3); - candidate.append(search_path); + std::set items; + for (auto entry : m_entries) + { + if (pal::strcmp(entry.asset_type.c_str(), _X("runtime")) == 0 && items.find(entry.asset_name) == items.end()) + { + // Resolve the full path + for (auto search_path : m_package_search_paths) + { + pal::string_t candidate; + candidate.reserve(search_path.length() + + entry.library_name.length() + + entry.library_version.length() + + entry.relative_path.length() + 3); + candidate.append(search_path); - append_path(candidate, entry.library_name.c_str()); - append_path(candidate, entry.library_version.c_str()); - append_path(candidate, entry.relative_path.c_str()); - if (pal::file_exists(candidate)) - { - trace::verbose(_X("adding tpa entry: %s"), candidate.c_str()); + append_path(candidate, entry.library_name.c_str()); + append_path(candidate, entry.library_version.c_str()); + append_path(candidate, entry.relative_path.c_str()); + if (pal::file_exists(candidate)) + { + trace::verbose(_X("adding tpa entry: %s"), candidate.c_str()); - output.append(candidate); - output.push_back(PATH_SEPARATOR); - items.insert(entry.asset_name); - break; - } - } - } - } + output.append(candidate); + output.push_back(PATH_SEPARATOR); + items.insert(entry.asset_name); + break; + } + } + } + } } void tpafile::write_native_paths(pal::string_t& output) { - std::set items; - for (auto search_path : m_native_search_paths) - { - if (items.find(search_path) == items.end()) - { - trace::verbose(_X("adding native search path: %s"), search_path.c_str()); - output.append(search_path); - output.push_back(PATH_SEPARATOR); - items.insert(search_path); - } - } + std::set items; + for (auto search_path : m_native_search_paths) + { + if (items.find(search_path) == items.end()) + { + trace::verbose(_X("adding native search path: %s"), search_path.c_str()); + output.append(search_path); + output.push_back(PATH_SEPARATOR); + items.insert(search_path); + } + } - for (auto entry : m_entries) - { - auto dir = entry.relative_path.substr(0, entry.relative_path.find_last_of(DIR_SEPARATOR)); - if (pal::strcmp(entry.asset_type.c_str(), _X("native")) == 0 && items.find(dir) == items.end()) - { - // Resolve the full path - for (auto search_path : m_package_search_paths) - { - pal::string_t candidate; - candidate.reserve(search_path.length() + - entry.library_name.length() + - entry.library_version.length() + - dir.length() + 3); - candidate.append(search_path); + for (auto entry : m_entries) + { + auto dir = entry.relative_path.substr(0, entry.relative_path.find_last_of(DIR_SEPARATOR)); + if (pal::strcmp(entry.asset_type.c_str(), _X("native")) == 0 && items.find(dir) == items.end()) + { + // Resolve the full path + for (auto search_path : m_package_search_paths) + { + pal::string_t candidate; + candidate.reserve(search_path.length() + + entry.library_name.length() + + entry.library_version.length() + + dir.length() + 3); + candidate.append(search_path); - append_path(candidate, entry.library_name.c_str()); - append_path(candidate, entry.library_version.c_str()); - append_path(candidate, get_directory(entry.relative_path).c_str()); + append_path(candidate, entry.library_name.c_str()); + append_path(candidate, entry.library_version.c_str()); + append_path(candidate, get_directory(entry.relative_path).c_str()); - if (pal::file_exists(candidate)) - { - trace::verbose(_X("adding native search path: %s"), candidate.c_str()); - output.append(candidate); - output.push_back(PATH_SEPARATOR); - items.insert(dir); - break; - } - } - } - } + if (pal::file_exists(candidate)) + { + trace::verbose(_X("adding native search path: %s"), candidate.c_str()); + output.append(candidate); + output.push_back(PATH_SEPARATOR); + items.insert(dir); + break; + } + } + } + } } void tpafile::add_package_dir(pal::string_t dir) { - m_package_search_paths.push_back(dir); + m_package_search_paths.push_back(dir); } void tpafile::add_native_search_path(pal::string_t dir) { - m_native_search_paths.push_back(dir); + m_native_search_paths.push_back(dir); } diff --git a/src/corehost/src/trace.cpp b/src/corehost/src/trace.cpp index 87d2ecc96..4d4be2e80 100644 --- a/src/corehost/src/trace.cpp +++ b/src/corehost/src/trace.cpp @@ -4,54 +4,54 @@ static trace::level_t g_level = trace::level_t::Error; void trace::set_level(trace::level_t new_level) { - g_level = new_level; + g_level = new_level; } bool trace::is_enabled(trace::level_t level) { - return level <= g_level; + return level <= g_level; } void trace::verbose(const pal::char_t* format, ...) { - if (trace::is_enabled(trace::level_t::Verbose)) - { - va_list args; - va_start(args, format); - pal::err_vprintf(format, args); - va_end(args); - } + if (trace::is_enabled(trace::level_t::Verbose)) + { + va_list args; + va_start(args, format); + pal::err_vprintf(format, args); + va_end(args); + } } void trace::info(const pal::char_t* format, ...) { - if (trace::is_enabled(trace::level_t::Info)) - { - va_list args; - va_start(args, format); - pal::err_vprintf(format, args); - va_end(args); - } + if (trace::is_enabled(trace::level_t::Info)) + { + va_list args; + va_start(args, format); + pal::err_vprintf(format, args); + va_end(args); + } } void trace::error(const pal::char_t* format, ...) { - if (trace::is_enabled(trace::level_t::Error)) - { - va_list args; - va_start(args, format); - pal::err_vprintf(format, args); - va_end(args); - } + if (trace::is_enabled(trace::level_t::Error)) + { + va_list args; + va_start(args, format); + pal::err_vprintf(format, args); + va_end(args); + } } void trace::warning(const pal::char_t* format, ...) { - if (trace::is_enabled(trace::level_t::Warning)) - { - va_list args; - va_start(args, format); - pal::err_vprintf(format, args); - va_end(args); - } + if (trace::is_enabled(trace::level_t::Warning)) + { + va_list args; + va_start(args, format); + pal::err_vprintf(format, args); + va_end(args); + } } diff --git a/src/corehost/src/utils.cpp b/src/corehost/src/utils.cpp index 80b9a0f60..4f3499ffc 100644 --- a/src/corehost/src/utils.cpp +++ b/src/corehost/src/utils.cpp @@ -1,59 +1,93 @@ #include "utils.h" +bool ends_with(const pal::string_t& value, const pal::string_t& suffix) +{ + return (0 == value.compare(value.length() - suffix.length(), suffix.length(), suffix)); +} + +bool find_coreclr(const pal::string_t& appbase, pal::string_t& recv) +{ + pal::string_t candidate; + // Check if it exists in the appbase + candidate.assign(appbase); + append_path(candidate, LIBCORECLR_NAME); + if (pal::file_exists(candidate)) + { + recv.assign(appbase); + return true; + } + + // TODO: Have a cleaner search strategy that supports multiple versions + // Search the PATH + pal::string_t path; + if (!pal::getenv(_X("PATH"), path)) + { + return false; + } + pal::stringstream_t path_stream(path); + pal::string_t entry; + while (std::getline(path_stream, entry, PATH_SEPARATOR)) + { + candidate.assign(entry); + append_path(candidate, LIBCORECLR_NAME); + if (pal::file_exists(candidate)) + { + recv.assign(entry); + return true; + } + } + return false; +} + void append_path(pal::string_t& path1, const pal::char_t* path2) { - if (pal::is_path_rooted(path2)) - { - path1.assign(path2); - } - else - { - if (path1.back() != DIR_SEPARATOR) - { - path1.push_back(DIR_SEPARATOR); - } - path1.append(path2); - } + if (pal::is_path_rooted(path2)) + { + path1.assign(path2); + } + else + { + if (path1.back() != DIR_SEPARATOR) + { + path1.push_back(DIR_SEPARATOR); + } + path1.append(path2); + } } pal::string_t get_executable(const pal::string_t& filename) { - pal::string_t result(filename); + pal::string_t result(filename); - if (ends_with(result, _X(".exe"))) - { - // We need to strip off the old extension - result.erase(result.length() - 4); - } - - return result; -} + if (ends_with(result, _X(".exe"))) + { + // We need to strip off the old extension + result.erase(result.length() - 4); + } -bool ends_with(const pal::string_t& value, const pal::string_t& suffix) -{ - return (0 == value.compare(value.length() - suffix.length(), suffix.length(), suffix)); + return result; } pal::string_t get_filename(const pal::string_t& path) { - // Find the last dir separator - auto path_sep = path.find_last_of(DIR_SEPARATOR); - if (path_sep == pal::string_t::npos) - { - return pal::string_t(path); - } + // Find the last dir separator + auto path_sep = path.find_last_of(DIR_SEPARATOR); + if (path_sep == pal::string_t::npos) + { + return pal::string_t(path); + } - return path.substr(path_sep + 1); + return path.substr(path_sep + 1); } pal::string_t get_directory(const pal::string_t& path) { - // Find the last dir separator - auto path_sep = path.find_last_of(DIR_SEPARATOR); - if (path_sep == pal::string_t::npos) - { - return pal::string_t(path); - } + // Find the last dir separator + auto path_sep = path.find_last_of(DIR_SEPARATOR); + if (path_sep == pal::string_t::npos) + { + return pal::string_t(path); + } - return path.substr(0, path_sep); + return path.substr(0, path_sep); } diff --git a/test/TestApp/Program.cs b/test/TestApp/Program.cs index 90141574a..adc6169e0 100644 --- a/test/TestApp/Program.cs +++ b/test/TestApp/Program.cs @@ -7,7 +7,7 @@ namespace TestApp { public static void Main(string[] args) { - Console.WriteLine("This is a test app"); + Console.WriteLine(TestLibrary.Helper.GetMessage()); } } } diff --git a/test/TestApp/project.json b/test/TestApp/project.json index d81c0116a..a42b70193 100644 --- a/test/TestApp/project.json +++ b/test/TestApp/project.json @@ -5,9 +5,10 @@ }, "dependencies": { - "System.IO": "4.0.10-beta-23420", + "TestLibrary": { "target": "project" }, + "System.IO": "4.0.11-beta-23420", "System.Console": "4.0.0-beta-23420", - "System.Runtime": "4.0.20-beta-23420", + "System.Runtime": "4.0.21-beta-23420", "System.Diagnostics.Process": "4.1.0-beta-23420", "Microsoft.NETCore.Runtime": "1.0.1-beta-23428" }, diff --git a/test/TestLibrary/Helper.cs b/test/TestLibrary/Helper.cs new file mode 100644 index 000000000..4c52ddfc6 --- /dev/null +++ b/test/TestLibrary/Helper.cs @@ -0,0 +1,12 @@ +using System; + +namespace TestLibrary +{ + public static class Helper + { + public static string GetMessage() + { + return "This string came from the test library!"; + } + } +} diff --git a/test/TestLibrary/TestLibrary.xproj b/test/TestLibrary/TestLibrary.xproj new file mode 100644 index 000000000..eb9f8bc2d --- /dev/null +++ b/test/TestLibrary/TestLibrary.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 947dd232-8d9b-4b78-9c6a-94f807d2dd58 + TestLibrary + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/test/TestLibrary/project.json b/test/TestLibrary/project.json new file mode 100644 index 000000000..1206d0a9c --- /dev/null +++ b/test/TestLibrary/project.json @@ -0,0 +1,11 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "System.Runtime": "4.0.21-beta-23420", + "Microsoft.NETCore.Runtime": "1.0.1-beta-23428" + }, + + "frameworks": { + "dnxcore50": { } + } +}