command line interface clean-up
This commit is contained in:
parent
d39f492300
commit
b35fba863b
33 changed files with 1113 additions and 815 deletions
|
@ -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"
|
dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE1_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Publish"
|
||||||
if errorlevel 1 goto fail
|
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"
|
dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE1_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Resgen"
|
||||||
if errorlevel 1 goto fail
|
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"
|
dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE2_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Publish"
|
||||||
if errorlevel 1 goto fail
|
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"
|
dotnet publish --framework "%TFM%" --runtime "%RID%" --output "%STAGE2_DIR%" --configuration "%CONFIGURATION%" "%REPOROOT%\src\Microsoft.DotNet.Tools.Resgen"
|
||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ REM Smoke-test the output
|
||||||
set PATH=%STAGE2_DIR%;%START_PATH%
|
set PATH=%STAGE2_DIR%;%START_PATH%
|
||||||
|
|
||||||
del "%REPOROOT%\test\TestApp\project.lock.json"
|
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"
|
dotnet compile "%REPOROOT%\test\TestApp" --output "%REPOROOT%\artifacts\%RID%\smoketest"
|
||||||
|
|
||||||
set CLRHOST_CLR_PATH=%STAGE2_DIR%
|
set CLRHOST_CLR_PATH=%STAGE2_DIR%
|
||||||
|
|
|
@ -108,8 +108,8 @@ dotnet compile "$REPOROOT/test/TestApp" --output "$REPOROOT/artifacts/$RID/smoke
|
||||||
|
|
||||||
export CLRHOST_CLR_PATH=$STAGE2_DIR
|
export CLRHOST_CLR_PATH=$STAGE2_DIR
|
||||||
|
|
||||||
OUTPUT=$($REPOROOT/artifacts/$RID/smoketest/TestApp)
|
# set -e will abort if the exit code of this is non-zero
|
||||||
[ "$OUTPUT" == "This is a test app" ] || (error "Smoke test failed!" && exit 1)
|
$REPOROOT/artifacts/$RID/smoketest/TestApp
|
||||||
|
|
||||||
# Check that a compiler error is reported
|
# Check that a compiler error is reported
|
||||||
set +e
|
set +e
|
||||||
|
|
19
scripts/dev-install.cmd
Normal file
19
scripts/dev-install.cmd
Normal file
|
@ -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%
|
|
@ -2,7 +2,7 @@
|
||||||
SETLOCAL
|
SETLOCAL
|
||||||
SET ERRORLEVEL=
|
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%
|
exit /b %ERRORLEVEL%
|
||||||
ENDLOCAL
|
ENDLOCAL
|
||||||
|
|
|
@ -16,12 +16,16 @@ if(![string]::IsNullOrEmpty($env:DOTNET_BUILD_VERSION)) {
|
||||||
|
|
||||||
$PackageName = Join-Path $PackageDir "dotnet-win-x64.$PackageVersion.zip"
|
$PackageName = Join-Path $PackageDir "dotnet-win-x64.$PackageVersion.zip"
|
||||||
|
|
||||||
|
if (Test-Path $PackageName)
|
||||||
|
{
|
||||||
|
del $PackageName
|
||||||
|
}
|
||||||
|
|
||||||
Add-Type -Assembly System.IO.Compression.FileSystem
|
Add-Type -Assembly System.IO.Compression.FileSystem
|
||||||
[System.IO.Compression.ZipFile]::CreateFromDirectory($Stage2Dir, $PackageName, "Optimal", $false)
|
[System.IO.Compression.ZipFile]::CreateFromDirectory($Stage2Dir, $PackageName, "Optimal", $false)
|
||||||
|
|
||||||
Write-Host "Packaged stage2 to $PackageName"
|
Write-Host "Packaged stage2 to $PackageName"
|
||||||
|
|
||||||
|
|
||||||
$PublishScript = Join-Path $PSScriptRoot "publish.ps1"
|
$PublishScript = Join-Path $PSScriptRoot "publish.ps1"
|
||||||
& $PublishScript -file $PackageName
|
& $PublishScript -file $PackageName
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Cli.Utils
|
namespace Microsoft.DotNet.Cli.Utils
|
||||||
{
|
{
|
||||||
|
@ -16,8 +17,8 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
private StringWriter _stdOutCapture;
|
private StringWriter _stdOutCapture;
|
||||||
private StringWriter _stdErrCapture;
|
private StringWriter _stdErrCapture;
|
||||||
|
|
||||||
private TextWriter _stdOutForward;
|
private Action<string> _stdOutForward;
|
||||||
private TextWriter _stdErrForward;
|
private Action<string> _stdErrForward;
|
||||||
|
|
||||||
private Action<string> _stdOutHandler;
|
private Action<string> _stdOutHandler;
|
||||||
private Action<string> _stdErrHandler;
|
private Action<string> _stdErrHandler;
|
||||||
|
@ -128,7 +129,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
Reporter.Output.WriteLine($"> {FormatProcessInfo(_process.StartInfo)}".White());
|
Reporter.Verbose.WriteLine($"> {FormatProcessInfo(_process.StartInfo)}".White());
|
||||||
#endif
|
#endif
|
||||||
_process.Start();
|
_process.Start();
|
||||||
_process.BeginOutputReadLine();
|
_process.BeginOutputReadLine();
|
||||||
|
@ -142,11 +143,11 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
var message = $"< {FormatProcessInfo(_process.StartInfo)} exited with {exitCode} in {sw.ElapsedMilliseconds} ms.";
|
var message = $"< {FormatProcessInfo(_process.StartInfo)} exited with {exitCode} in {sw.ElapsedMilliseconds} ms.";
|
||||||
if (exitCode == 0)
|
if (exitCode == 0)
|
||||||
{
|
{
|
||||||
Reporter.Output.WriteLine(message.Green());
|
Reporter.Verbose.WriteLine(message.Green());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Reporter.Output.WriteLine(message.Red().Bold());
|
Reporter.Verbose.WriteLine(message.Red().Bold());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -176,17 +177,37 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command ForwardStdOut(TextWriter to = null)
|
public Command ForwardStdOut(TextWriter to = null, bool onlyIfVerbose = false)
|
||||||
{
|
{
|
||||||
ThrowIfRunning();
|
ThrowIfRunning();
|
||||||
_stdOutForward = to ?? Console.Out;
|
if (!onlyIfVerbose || CommandContext.IsVerbose())
|
||||||
|
{
|
||||||
|
if (to == null)
|
||||||
|
{
|
||||||
|
_stdOutForward = Reporter.Output.WriteLine;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stdOutForward = to.WriteLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command ForwardStdErr(TextWriter to = null)
|
public Command ForwardStdErr(TextWriter to = null, bool onlyIfVerbose = false)
|
||||||
{
|
{
|
||||||
ThrowIfRunning();
|
ThrowIfRunning();
|
||||||
_stdErrForward = to ?? Console.Error;
|
if (!onlyIfVerbose || CommandContext.IsVerbose())
|
||||||
|
{
|
||||||
|
if (to == null)
|
||||||
|
{
|
||||||
|
_stdErrForward = Reporter.Error.WriteLine;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stdErrForward = to.WriteLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +251,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessData(string data, StringWriter capture, TextWriter forward, Action<string> handler)
|
private void ProcessData(string data, StringWriter capture, Action<string> forward, Action<string> handler)
|
||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
|
@ -244,7 +265,7 @@ namespace Microsoft.DotNet.Cli.Utils
|
||||||
|
|
||||||
if (forward != null)
|
if (forward != null)
|
||||||
{
|
{
|
||||||
forward.WriteLine(data);
|
forward(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handler != null)
|
if (handler != null)
|
||||||
|
|
41
src/Microsoft.DotNet.Cli.Utils/CommandContext.cs
Normal file
41
src/Microsoft.DotNet.Cli.Utils/CommandContext.cs
Normal file
|
@ -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<bool> _verbose = new Lazy<bool>(() => GetBool(Variables.Verbose));
|
||||||
|
private static Lazy<bool> _ansiPassThru = new Lazy<bool>(() => 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Cli.Utils
|
namespace Microsoft.DotNet.Cli.Utils
|
||||||
{
|
{
|
||||||
// Stupid-simple console manager
|
// Stupid-simple console manager
|
||||||
internal static class Reporter
|
internal class Reporter
|
||||||
{
|
{
|
||||||
public static AnsiConsole Output { get; } = AnsiConsole.GetOutput(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
|
private static readonly Reporter Null = new Reporter(console: null);
|
||||||
public static AnsiConsole Error { get; } = AnsiConsole.GetError(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
|
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<bool, AnsiConsole> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,101 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
||||||
using Microsoft.DotNet.Cli.Utils;
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Cli
|
namespace Microsoft.DotNet.Cli
|
||||||
{
|
{
|
||||||
public class Program
|
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)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length < 1)
|
// CommandLineApplication is a bit restrictive, so we parse things ourselves here. Individual apps should use CLA.
|
||||||
{
|
var verbose = false;
|
||||||
// Handle missing args
|
var command = string.Empty;
|
||||||
PrintCommandList();
|
var lastArg = 0;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
verbose = true;
|
||||||
.ForwardStdErr()
|
}
|
||||||
.ForwardStdOut()
|
else if (args[lastArg].StartsWith("-"))
|
||||||
.Execute()
|
{
|
||||||
.ExitCode;
|
PrintHelp($"Unknown option: ${args[lastArg]}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PrintCommandList();
|
// It's the command, and we're done!
|
||||||
return 0;
|
command = args[lastArg];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
var appArgs = (lastArg + 1) >= args.Length ? Enumerable.Empty<string>() : 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<string> appArgs)
|
||||||
|
{
|
||||||
|
if (appArgs.Any())
|
||||||
|
{
|
||||||
|
return Command.Create("dotnet-" + appArgs.First(), "--help")
|
||||||
.ForwardStdErr()
|
.ForwardStdErr()
|
||||||
.ForwardStdOut()
|
.ForwardStdOut()
|
||||||
.Execute()
|
.Execute()
|
||||||
.ExitCode;
|
.ExitCode;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintHelp();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintCommandList()
|
private static void PrintHelp(string errorMessage = null)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Some dotnet Commands (use 'dotnet help <command>' to get help):");
|
if(!string.IsNullOrEmpty(errorMessage))
|
||||||
Console.WriteLine("* compile - Compiles code");
|
{
|
||||||
Console.WriteLine("* publish - Publishes a project to a self-contained application");
|
Reporter.Error.WriteLine(errorMessage.Red());
|
||||||
Console.WriteLine("* run - Publishes and immediately runs a project");
|
}
|
||||||
|
Reporter.Output.WriteLine(HelpText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsArg(string candidate, string shortName, string longName)
|
||||||
|
{
|
||||||
|
return candidate.Equals("-" + shortName) || candidate.Equals("--" + longName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.ProjectModel.Compilation
|
namespace Microsoft.Extensions.ProjectModel.Compilation
|
||||||
{
|
{
|
||||||
|
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
||||||
public class LibraryExport
|
public class LibraryExport
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -39,5 +41,13 @@ namespace Microsoft.Extensions.ProjectModel.Compilation
|
||||||
RuntimeAssemblies = runtimeAssemblies;
|
RuntimeAssemblies = runtimeAssemblies;
|
||||||
NativeLibraries = nativeLibraries;
|
NativeLibraries = nativeLibraries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string DebuggerDisplay
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Library.Identity.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,33 @@ namespace Microsoft.Extensions.ProjectModel.Compilation
|
||||||
|
|
||||||
public LibraryManager LibraryManager { get; }
|
public LibraryManager LibraryManager { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all the exports specified by this project, including the root project itself
|
||||||
|
/// </summary>
|
||||||
public IEnumerable<LibraryExport> GetAllExports()
|
public IEnumerable<LibraryExport> GetAllExports()
|
||||||
{
|
{
|
||||||
// Export all but the main project
|
|
||||||
return ExportLibraries(_ => true);
|
return ExportLibraries(_ => true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<LibraryExport> GetCompilationDependencies()
|
/// <summary>
|
||||||
|
/// Gets all exports required by the project, NOT including the project itself
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IEnumerable<LibraryExport> GetDependencies()
|
||||||
|
{
|
||||||
|
return GetDependencies(LibraryType.Unspecified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all exports required by the project, of the specified <see cref="LibraryType"/>, NOT including the project itself
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IEnumerable<LibraryExport> GetDependencies(LibraryType type)
|
||||||
{
|
{
|
||||||
// Export all but the main project
|
// Export all but the main project
|
||||||
return ExportLibraries(library => library != _rootProject);
|
return ExportLibraries(library =>
|
||||||
|
library != _rootProject &&
|
||||||
|
LibraryIsOfType(type, library));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -214,5 +231,11 @@ namespace Microsoft.Extensions.ProjectModel.Compilation
|
||||||
Path.Combine(package.Path, assemblyPath)));
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Microsoft.DotNet.Cli.Utils;
|
||||||
using Microsoft.DotNet.Tools.Common;
|
using Microsoft.DotNet.Tools.Common;
|
||||||
using Microsoft.Extensions.ProjectModel;
|
using Microsoft.Extensions.ProjectModel;
|
||||||
using Microsoft.Extensions.ProjectModel.Compilation;
|
using Microsoft.Extensions.ProjectModel.Compilation;
|
||||||
|
using Microsoft.Extensions.ProjectModel.Graph;
|
||||||
using NuGet.Frameworks;
|
using NuGet.Frameworks;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Tools.Compiler
|
namespace Microsoft.DotNet.Tools.Compiler
|
||||||
|
@ -106,8 +107,6 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
|
|
||||||
private static bool Compile(ProjectContext context, string configuration, string outputOptionValue, string intermediateOutputValue, bool buildProjectReferences)
|
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
|
// Set up Output Paths
|
||||||
string outputPath = GetOutputPath(context, configuration, outputOptionValue);
|
string outputPath = GetOutputPath(context, configuration, outputOptionValue);
|
||||||
string intermediateOutputPath = GetIntermediateOutputPath(context, configuration, intermediateOutputValue, outputOptionValue);
|
string intermediateOutputPath = GetIntermediateOutputPath(context, configuration, intermediateOutputValue, outputOptionValue);
|
||||||
|
@ -124,7 +123,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
diagnostics.AddRange(context.LibraryManager.GetAllDiagnostics());
|
diagnostics.AddRange(context.LibraryManager.GetAllDiagnostics());
|
||||||
|
|
||||||
// Gather exports for the project
|
// Gather exports for the project
|
||||||
var dependencies = exporter.GetCompilationDependencies().ToList();
|
var dependencies = exporter.GetDependencies().ToList();
|
||||||
|
|
||||||
if (buildProjectReferences)
|
if (buildProjectReferences)
|
||||||
{
|
{
|
||||||
|
@ -158,6 +157,8 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
projects.Clear();
|
projects.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}");
|
||||||
|
|
||||||
// Dump dependency data
|
// Dump dependency data
|
||||||
// TODO: Turn on only if verbose, we can look at the response
|
// TODO: Turn on only if verbose, we can look at the response
|
||||||
// file anyways
|
// file anyways
|
||||||
|
@ -228,7 +229,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(line);
|
Reporter.Error.WriteLine(line);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.OnOutputLine(line =>
|
.OnOutputLine(line =>
|
||||||
|
@ -241,7 +242,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Out.WriteLine(line);
|
Reporter.Output.WriteLine(line);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.Execute();
|
.Execute();
|
||||||
|
@ -325,7 +326,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(outputOptionValue))
|
if (string.IsNullOrEmpty(outputOptionValue))
|
||||||
{
|
{
|
||||||
rootOutputPath = context.ProjectFile.ProjectDirectory;
|
rootOutputPath = context.ProjectFile.ProjectDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootOutputPath;
|
return rootOutputPath;
|
||||||
|
@ -339,7 +340,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
{
|
{
|
||||||
Directory.Delete(path, recursive: true);
|
Directory.Delete(path, recursive: true);
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Unable to remove directory: " + path);
|
Console.WriteLine("Unable to remove directory: " + path);
|
||||||
Console.WriteLine(e.Message);
|
Console.WriteLine(e.Message);
|
||||||
|
@ -354,15 +355,9 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
if (runtimeContext.TargetFramework.IsDesktop())
|
if (runtimeContext.TargetFramework.IsDesktop())
|
||||||
{
|
{
|
||||||
// On desktop we need to copy dependencies since we don't own the host
|
// 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)
|
CopyExport(outputPath, export);
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyFiles(export.RuntimeAssemblies, outputPath);
|
|
||||||
CopyFiles(export.NativeLibraries, outputPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -371,16 +366,29 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
private static void EmitHost(ProjectContext runtimeContext, string outputPath, LibraryExporter exporter)
|
||||||
{
|
{
|
||||||
// Write the Host information file (basically a simplified form of the lock file)
|
// Write the Host information file (basically a simplified form of the lock file)
|
||||||
var lines = new List<string>();
|
var lines = new List<string>();
|
||||||
foreach(var export in exporter.GetAllExports())
|
foreach (var export in exporter.GetAllExports())
|
||||||
{
|
{
|
||||||
if (export.Library is ProjectDescription)
|
if (export.Library == runtimeContext.RootProject)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (export.Library is ProjectDescription)
|
||||||
|
{
|
||||||
|
// Copy project dependencies to the output folder
|
||||||
|
CopyFiles(export.RuntimeAssemblies, outputPath);
|
||||||
|
CopyFiles(export.NativeLibraries, outputPath);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lines.AddRange(GenerateLines(export, export.RuntimeAssemblies, "runtime"));
|
lines.AddRange(GenerateLines(export, export.RuntimeAssemblies, "runtime"));
|
||||||
|
@ -419,7 +427,7 @@ namespace Microsoft.DotNet.Tools.Compiler
|
||||||
|
|
||||||
private static void PrintSummary(bool success, List<DiagnosticMessage> diagnostics)
|
private static void PrintSummary(bool success, List<DiagnosticMessage> diagnostics)
|
||||||
{
|
{
|
||||||
Reporter.Output.Writer.WriteLine();
|
Reporter.Output.WriteLine();
|
||||||
|
|
||||||
var errorCount = diagnostics.Count(d => d.Severity == DiagnosticMessageSeverity.Error);
|
var errorCount = diagnostics.Count(d => d.Severity == DiagnosticMessageSeverity.Error);
|
||||||
var warningCount = diagnostics.Count(d => d.Severity == DiagnosticMessageSeverity.Warning);
|
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($" {warningCount} Warning(s)");
|
||||||
Reporter.Output.WriteLine($" {errorCount} Error(s)");
|
Reporter.Output.WriteLine($" {errorCount} Error(s)");
|
||||||
|
|
||||||
Reporter.Output.Writer.WriteLine();
|
Reporter.Output.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool AddResources(Project project, List<string> compilerArgs, string intermediateOutputPath)
|
private static bool AddResources(Project project, List<string> compilerArgs, string intermediateOutputPath)
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace Microsoft.DotNet.Tools.Publish
|
||||||
|
|
||||||
private static int Publish(ProjectContext context, string outputPath, string configuration)
|
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);
|
var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration);
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ namespace Microsoft.DotNet.Tools.Publish
|
||||||
continue;
|
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.RuntimeAssemblies, outputPath);
|
||||||
PublishFiles(export.NativeLibraries, outputPath);
|
PublishFiles(export.NativeLibraries, outputPath);
|
||||||
|
|
|
@ -4,11 +4,10 @@
|
||||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>0a309227-a9d8-4ddf-88dd-326b57b04378</ProjectGuid>
|
<ProjectGuid>1c16108c-c786-482d-bb0a-36bdafe109ed</ProjectGuid>
|
||||||
<RootNamespace>Microsoft.DotNet.Tools.Compiler</RootNamespace>
|
<RootNamespace>Microsoft.DotNet.Tools.Run</RootNamespace>
|
||||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
|
@ -24,16 +24,16 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
|
|
||||||
var framework = app.Option("-f|--framework <FRAMEWORK>", "Compile a specific framework", CommandOptionType.MultipleValue);
|
var framework = app.Option("-f|--framework <FRAMEWORK>", "Compile a specific framework", CommandOptionType.MultipleValue);
|
||||||
var configuration = app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
|
var configuration = app.Option("-c|--configuration <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 preserveTemporaryOutput = app.Option("-t|--preserve-temporary", "Keep the output's temporary directory around", CommandOptionType.NoValue);
|
||||||
var project = app.Argument("<PROJECT>", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory");
|
var project = app.Option("-p|--project <PROJECT_PATH>", "The path to the project to run (defaults to the current directory)", CommandOptionType.SingleValue);
|
||||||
|
|
||||||
app.OnExecute(() =>
|
app.OnExecute(() =>
|
||||||
{
|
{
|
||||||
// Locate the project and get the name and full path
|
// Locate the project and get the name and full path
|
||||||
var path = project.Value;
|
var path = Directory.GetCurrentDirectory();
|
||||||
if (string.IsNullOrEmpty(path))
|
if(project.HasValue())
|
||||||
{
|
{
|
||||||
path = Directory.GetCurrentDirectory();
|
path = project.Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
var contexts = ProjectContext.CreateContextForEachFramework(path);
|
var contexts = ProjectContext.CreateContextForEachFramework(path);
|
||||||
|
@ -69,8 +69,8 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
|
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
|
||||||
|
|
||||||
// Compile to that directory
|
// Compile to that directory
|
||||||
var result = Command.Create($"dotnet-compile", $"--output \"{tempDir}\" --framework \"{context.TargetFramework}\" --configuration \"{configuration}\"")
|
var result = Command.Create($"dotnet-compile", $"--output \"{tempDir}\" --framework \"{context.TargetFramework}\" --configuration \"{configuration}\" {context.ProjectFile.ProjectDirectory}")
|
||||||
.ForwardStdOut()
|
.ForwardStdOut(onlyIfVerbose: true)
|
||||||
.ForwardStdErr()
|
.ForwardStdErr()
|
||||||
.Execute();
|
.Execute();
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
|
|
||||||
struct arguments_t
|
struct arguments_t
|
||||||
{
|
{
|
||||||
trace::level_t trace_level;
|
trace::level_t trace_level;
|
||||||
pal::string_t own_path;
|
pal::string_t own_path;
|
||||||
pal::string_t managed_application;
|
pal::string_t managed_application;
|
||||||
pal::string_t clr_path;
|
pal::string_t clr_path;
|
||||||
|
|
||||||
int app_argc;
|
int app_argc;
|
||||||
const pal::char_t** app_argv;
|
const pal::char_t** app_argv;
|
||||||
|
|
||||||
arguments_t();
|
arguments_t();
|
||||||
};
|
};
|
||||||
|
|
||||||
bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args);
|
bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args);
|
||||||
|
|
|
@ -6,31 +6,31 @@
|
||||||
|
|
||||||
namespace coreclr
|
namespace coreclr
|
||||||
{
|
{
|
||||||
typedef void* host_handle_t;
|
typedef void* host_handle_t;
|
||||||
typedef unsigned int domain_id_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(
|
pal::hresult_t initialize(
|
||||||
const char* exe_path,
|
const char* exe_path,
|
||||||
const char* app_domain_friendly_name,
|
const char* app_domain_friendly_name,
|
||||||
const char** property_keys,
|
const char** property_keys,
|
||||||
const char** property_values,
|
const char** property_values,
|
||||||
int property_count,
|
int property_count,
|
||||||
host_handle_t* host_handle,
|
host_handle_t* host_handle,
|
||||||
domain_id_t* domain_id);
|
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(
|
pal::hresult_t execute_assembly(
|
||||||
host_handle_t host_handle,
|
host_handle_t host_handle,
|
||||||
domain_id_t domain_id,
|
domain_id_t domain_id,
|
||||||
int argc,
|
int argc,
|
||||||
const char** argv,
|
const char** argv,
|
||||||
const char* managed_assembly_path,
|
const char* managed_assembly_path,
|
||||||
unsigned int* exit_code);
|
unsigned int* exit_code);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
@ -58,50 +59,52 @@ namespace pal
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
typedef wchar_t char_t;
|
typedef wchar_t char_t;
|
||||||
typedef std::wstring string_t;
|
typedef std::wstring string_t;
|
||||||
typedef std::ifstream ifstream_t;
|
typedef std::wstringstream stringstream_t;
|
||||||
typedef HRESULT hresult_t;
|
typedef std::ifstream ifstream_t;
|
||||||
typedef HMODULE dll_t;
|
typedef HRESULT hresult_t;
|
||||||
typedef FARPROC proc_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 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 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 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 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);
|
pal::string_t to_palstring(const std::string& str);
|
||||||
std::string to_stdstring(const pal::string_t& str);
|
std::string to_stdstring(const pal::string_t& str);
|
||||||
#else
|
#else
|
||||||
typedef char char_t;
|
typedef char char_t;
|
||||||
typedef std::string string_t;
|
typedef std::string string_t;
|
||||||
typedef std::ifstream ifstream_t;
|
typedef std::stringstream stringstream_t;
|
||||||
typedef long hresult_t;
|
typedef std::ifstream ifstream_t;
|
||||||
typedef void* dll_t;
|
typedef long hresult_t;
|
||||||
typedef void* proc_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 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 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 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 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 pal::string_t to_palstring(const std::string& str) { return str; }
|
||||||
inline std::string to_stdstring(const pal::string_t& str) { return str; }
|
inline std::string to_stdstring(const pal::string_t& str) { return str; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool realpath(string_t& path);
|
bool realpath(string_t& path);
|
||||||
bool file_exists(const string_t& path);
|
bool file_exists(const string_t& path);
|
||||||
std::vector<pal::string_t> readdir(const string_t& path);
|
std::vector<pal::string_t> readdir(const string_t& path);
|
||||||
|
|
||||||
bool get_own_executable_path(string_t& recv);
|
bool get_own_executable_path(string_t& recv);
|
||||||
bool getenv(const char_t* name, string_t& recv);
|
bool getenv(const char_t* name, string_t& recv);
|
||||||
bool get_default_packages_directory(string_t& recv);
|
bool get_default_packages_directory(string_t& recv);
|
||||||
bool is_path_rooted(const string_t& path);
|
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);
|
bool load_library(const char_t* path, dll_t& dll);
|
||||||
proc_t get_symbol(dll_t library, const char* name);
|
proc_t get_symbol(dll_t library, const char* name);
|
||||||
void unload_library(dll_t library);
|
void unload_library(dll_t library);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // PAL_H
|
#endif // PAL_H
|
||||||
|
|
|
@ -8,31 +8,31 @@
|
||||||
|
|
||||||
struct tpaentry_t
|
struct tpaentry_t
|
||||||
{
|
{
|
||||||
pal::string_t library_type;
|
pal::string_t library_type;
|
||||||
pal::string_t library_name;
|
pal::string_t library_name;
|
||||||
pal::string_t library_version;
|
pal::string_t library_version;
|
||||||
pal::string_t library_hash;
|
pal::string_t library_hash;
|
||||||
pal::string_t asset_type;
|
pal::string_t asset_type;
|
||||||
pal::string_t asset_name;
|
pal::string_t asset_name;
|
||||||
pal::string_t relative_path;
|
pal::string_t relative_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
class tpafile
|
class tpafile
|
||||||
{
|
{
|
||||||
public:
|
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_from_local_dir(const pal::string_t& dir);
|
||||||
void add_package_dir(pal::string_t dir);
|
void add_package_dir(pal::string_t dir);
|
||||||
void add_native_search_path(pal::string_t dir);
|
void add_native_search_path(pal::string_t dir);
|
||||||
|
|
||||||
void write_tpa_list(pal::string_t& output);
|
void write_tpa_list(pal::string_t& output);
|
||||||
void write_native_paths(pal::string_t& output);
|
void write_native_paths(pal::string_t& output);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<tpaentry_t> m_entries;
|
std::vector<tpaentry_t> m_entries;
|
||||||
std::vector<pal::string_t> m_native_search_paths;
|
std::vector<pal::string_t> m_native_search_paths;
|
||||||
std::vector<pal::string_t> m_package_search_paths;
|
std::vector<pal::string_t> m_package_search_paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TPAFILE_H
|
#endif // TPAFILE_H
|
||||||
|
|
|
@ -5,20 +5,20 @@
|
||||||
|
|
||||||
namespace trace
|
namespace trace
|
||||||
{
|
{
|
||||||
enum class level_t
|
enum class level_t
|
||||||
{
|
{
|
||||||
Error = 0,
|
Error = 0,
|
||||||
Warning = 1,
|
Warning = 1,
|
||||||
Info = 2,
|
Info = 2,
|
||||||
Verbose = 3
|
Verbose = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_level(level_t level);
|
void set_level(level_t level);
|
||||||
bool is_enabled(level_t level);
|
bool is_enabled(level_t level);
|
||||||
void verbose(const pal::char_t* format, ...);
|
void verbose(const pal::char_t* format, ...);
|
||||||
void info(const pal::char_t* format, ...);
|
void info(const pal::char_t* format, ...);
|
||||||
void warning(const pal::char_t* format, ...);
|
void warning(const pal::char_t* format, ...);
|
||||||
void error(const pal::char_t* format, ...);
|
void error(const pal::char_t* format, ...);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRACE_H
|
#endif // TRACE_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_executable(const pal::string_t& filename);
|
||||||
pal::string_t get_directory(const pal::string_t& path);
|
pal::string_t get_directory(const pal::string_t& path);
|
||||||
pal::string_t get_filename(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);
|
void append_path(pal::string_t& path1, const pal::char_t* path2);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,73 +2,73 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
arguments_t::arguments_t() :
|
arguments_t::arguments_t() :
|
||||||
trace_level(trace::level_t::Error),
|
trace_level(trace::level_t::Error),
|
||||||
managed_application(_X("")),
|
managed_application(_X("")),
|
||||||
clr_path(_X("")),
|
clr_path(_X("")),
|
||||||
app_argc(0),
|
app_argc(0),
|
||||||
app_argv(nullptr)
|
app_argv(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_help()
|
void display_help()
|
||||||
{
|
{
|
||||||
xerr <<
|
xerr <<
|
||||||
_X("Usage: " HOST_EXE_NAME " [ASSEMBLY] [ARGUMENTS]\n")
|
_X("Usage: " HOST_EXE_NAME " [ASSEMBLY] [ARGUMENTS]\n")
|
||||||
_X("Execute the specified managed assembly with the passed in arguments\n\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("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_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");
|
_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)
|
bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args)
|
||||||
{
|
{
|
||||||
// Get the full name of the application
|
// Get the full name of the application
|
||||||
if (!pal::get_own_executable_path(args.own_path) || !pal::realpath(args.own_path))
|
if (!pal::get_own_executable_path(args.own_path) || !pal::realpath(args.own_path))
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to locate current executable"));
|
trace::error(_X("failed to locate current executable"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto own_name = get_filename(args.own_path);
|
auto own_name = get_filename(args.own_path);
|
||||||
auto own_dir = get_directory(args.own_path);
|
auto own_dir = get_directory(args.own_path);
|
||||||
|
|
||||||
if (own_name.compare(HOST_EXE_NAME) == 0)
|
if (own_name.compare(HOST_EXE_NAME) == 0)
|
||||||
{
|
{
|
||||||
// corerun mode. First argument is managed app
|
// corerun mode. First argument is managed app
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
{
|
{
|
||||||
display_help();
|
display_help();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
args.managed_application = pal::string_t(argv[1]);
|
args.managed_application = pal::string_t(argv[1]);
|
||||||
args.app_argc = argc - 2;
|
args.app_argc = argc - 2;
|
||||||
args.app_argv = &argv[2];
|
args.app_argv = &argv[2];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// coreconsole mode. Find the managed app in the same directory
|
// coreconsole mode. Find the managed app in the same directory
|
||||||
pal::string_t managed_app(own_dir);
|
pal::string_t managed_app(own_dir);
|
||||||
managed_app.push_back(DIR_SEPARATOR);
|
managed_app.push_back(DIR_SEPARATOR);
|
||||||
managed_app.append(get_executable(own_name));
|
managed_app.append(get_executable(own_name));
|
||||||
managed_app.append(_X(".dll"));
|
managed_app.append(_X(".dll"));
|
||||||
args.managed_application = managed_app;
|
args.managed_application = managed_app;
|
||||||
args.app_argv = &argv[1];
|
args.app_argv = &argv[1];
|
||||||
args.app_argc = argc - 1;
|
args.app_argc = argc - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read trace environment variable
|
// Read trace environment variable
|
||||||
pal::string_t trace_str;
|
pal::string_t trace_str;
|
||||||
if (pal::getenv(_X("CLRHOST_TRACE"), trace_str))
|
if (pal::getenv(_X("CLRHOST_TRACE"), trace_str))
|
||||||
{
|
{
|
||||||
auto trace_val = pal::xtoi(trace_str.c_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)
|
if (trace_val >= (int)trace::level_t::Error && trace_val <= (int)trace::level_t::Verbose)
|
||||||
{
|
{
|
||||||
args.trace_level = (trace::level_t)trace_val;
|
args.trace_level = (trace::level_t)trace_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read CLR path from environment variable
|
// Read CLR path from environment variable
|
||||||
pal::getenv(_X("CLRHOST_CLR_PATH"), args.clr_path);
|
pal::getenv(_X("CLRHOST_CLR_PATH"), args.clr_path);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,28 +6,28 @@
|
||||||
static pal::dll_t g_coreclr = nullptr;
|
static pal::dll_t g_coreclr = nullptr;
|
||||||
|
|
||||||
// Prototype of the coreclr_initialize function from coreclr.dll
|
// Prototype of the coreclr_initialize function from coreclr.dll
|
||||||
typedef pal::hresult_t (*coreclr_initialize_fn)(
|
typedef pal::hresult_t(*coreclr_initialize_fn)(
|
||||||
const char* exePath,
|
const char* exePath,
|
||||||
const char* appDomainFriendlyName,
|
const char* appDomainFriendlyName,
|
||||||
int propertyCount,
|
int propertyCount,
|
||||||
const char** propertyKeys,
|
const char** propertyKeys,
|
||||||
const char** propertyValues,
|
const char** propertyValues,
|
||||||
coreclr::host_handle_t* hostHandle,
|
coreclr::host_handle_t* hostHandle,
|
||||||
unsigned int* domainId);
|
unsigned int* domainId);
|
||||||
|
|
||||||
// Prototype of the coreclr_shutdown function from coreclr.dll
|
// Prototype of the coreclr_shutdown function from coreclr.dll
|
||||||
typedef pal::hresult_t (*coreclr_shutdown_fn)(
|
typedef pal::hresult_t(*coreclr_shutdown_fn)(
|
||||||
coreclr::host_handle_t hostHandle,
|
coreclr::host_handle_t hostHandle,
|
||||||
unsigned int domainId);
|
unsigned int domainId);
|
||||||
|
|
||||||
// Prototype of the coreclr_execute_assembly function from coreclr.dll
|
// Prototype of the coreclr_execute_assembly function from coreclr.dll
|
||||||
typedef pal::hresult_t (*coreclr_execute_assembly_fn)(
|
typedef pal::hresult_t(*coreclr_execute_assembly_fn)(
|
||||||
coreclr::host_handle_t hostHandle,
|
coreclr::host_handle_t hostHandle,
|
||||||
unsigned int domainId,
|
unsigned int domainId,
|
||||||
int argc,
|
int argc,
|
||||||
const char** argv,
|
const char** argv,
|
||||||
const char* managedAssemblyPath,
|
const char* managedAssemblyPath,
|
||||||
unsigned int* exitCode);
|
unsigned int* exitCode);
|
||||||
|
|
||||||
static coreclr_shutdown_fn coreclr_shutdown = nullptr;
|
static coreclr_shutdown_fn coreclr_shutdown = nullptr;
|
||||||
static coreclr_initialize_fn coreclr_initialize = 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)
|
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);
|
pal::string_t coreclr_dll_path(libcoreclr_path);
|
||||||
append_path(coreclr_dll_path, LIBCORECLR_NAME);
|
append_path(coreclr_dll_path, LIBCORECLR_NAME);
|
||||||
|
|
||||||
if(!pal::load_library(coreclr_dll_path.c_str(), g_coreclr))
|
if (!pal::load_library(coreclr_dll_path.c_str(), g_coreclr))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
coreclr_initialize = (coreclr_initialize_fn)pal::get_symbol(g_coreclr, "coreclr_initialize");
|
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_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_execute_assembly = (coreclr_execute_assembly_fn)pal::get_symbol(g_coreclr, "coreclr_execute_assembly");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void coreclr::unload()
|
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(
|
pal::hresult_t coreclr::initialize(
|
||||||
const char* exe_path,
|
const char* exe_path,
|
||||||
const char* app_domain_friendly_name,
|
const char* app_domain_friendly_name,
|
||||||
const char** property_keys,
|
const char** property_keys,
|
||||||
const char** property_values,
|
const char** property_values,
|
||||||
int property_count,
|
int property_count,
|
||||||
host_handle_t* host_handle,
|
host_handle_t* host_handle,
|
||||||
domain_id_t* domain_id)
|
domain_id_t* domain_id)
|
||||||
{
|
{
|
||||||
assert(g_coreclr != nullptr && coreclr_initialize != nullptr);
|
assert(g_coreclr != nullptr && coreclr_initialize != nullptr);
|
||||||
|
|
||||||
return coreclr_initialize(
|
return coreclr_initialize(
|
||||||
exe_path,
|
exe_path,
|
||||||
app_domain_friendly_name,
|
app_domain_friendly_name,
|
||||||
property_count,
|
property_count,
|
||||||
property_keys,
|
property_keys,
|
||||||
property_values,
|
property_values,
|
||||||
host_handle,
|
host_handle,
|
||||||
domain_id);
|
domain_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pal::hresult_t coreclr::shutdown(host_handle_t host_handle, domain_id_t 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(
|
pal::hresult_t coreclr::execute_assembly(
|
||||||
host_handle_t host_handle,
|
host_handle_t host_handle,
|
||||||
domain_id_t domain_id,
|
domain_id_t domain_id,
|
||||||
int argc,
|
int argc,
|
||||||
const char** argv,
|
const char** argv,
|
||||||
const char* managed_assembly_path,
|
const char* managed_assembly_path,
|
||||||
unsigned int* exit_code)
|
unsigned int* exit_code)
|
||||||
{
|
{
|
||||||
assert(g_coreclr != nullptr && coreclr_execute_assembly != nullptr);
|
assert(g_coreclr != nullptr && coreclr_execute_assembly != nullptr);
|
||||||
|
|
||||||
return coreclr_execute_assembly(
|
return coreclr_execute_assembly(
|
||||||
host_handle,
|
host_handle,
|
||||||
domain_id,
|
domain_id,
|
||||||
argc,
|
argc,
|
||||||
argv,
|
argv,
|
||||||
managed_assembly_path,
|
managed_assembly_path,
|
||||||
exit_code);
|
exit_code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,143 +7,143 @@
|
||||||
|
|
||||||
void get_tpafile_path(const pal::string_t& app_base, const pal::string_t& app_name, pal::string_t& tpapath)
|
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.append(app_base);
|
||||||
tpapath.push_back(DIR_SEPARATOR);
|
tpapath.push_back(DIR_SEPARATOR);
|
||||||
|
|
||||||
// Remove the extension from the app_name
|
// Remove the extension from the app_name
|
||||||
auto ext_location = app_name.find_last_of('.');
|
auto ext_location = app_name.find_last_of('.');
|
||||||
if (ext_location != std::string::npos)
|
if (ext_location != std::string::npos)
|
||||||
{
|
{
|
||||||
tpapath.append(app_name.substr(0, ext_location));
|
tpapath.append(app_name.substr(0, ext_location));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tpapath.append(app_name);
|
tpapath.append(app_name);
|
||||||
}
|
}
|
||||||
tpapath.append(_X(".deps"));
|
tpapath.append(_X(".deps"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int run(arguments_t args, pal::string_t app_base, tpafile tpa)
|
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
|
// Add packages directory
|
||||||
pal::string_t packages_dir;
|
pal::string_t packages_dir;
|
||||||
if (!pal::get_default_packages_directory(packages_dir))
|
if (!pal::get_default_packages_directory(packages_dir))
|
||||||
{
|
{
|
||||||
trace::info(_X("did not find local packages directory"));
|
trace::info(_X("did not find local packages directory"));
|
||||||
|
|
||||||
// We can continue, the app may have it's dependencies locally
|
// We can continue, the app may have it's dependencies locally
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trace::info(_X("using packages directory: %s"), packages_dir.c_str());
|
trace::info(_X("using packages directory: %s"), packages_dir.c_str());
|
||||||
tpa.add_package_dir(packages_dir);
|
tpa.add_package_dir(packages_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add native search path
|
// Add native search path
|
||||||
trace::info(_X("using native search path: %s"), packages_dir.c_str());
|
trace::info(_X("using native search path: %s"), packages_dir.c_str());
|
||||||
tpa.add_native_search_path(args.clr_path);
|
tpa.add_native_search_path(args.clr_path);
|
||||||
|
|
||||||
// Build TPA list and search paths
|
// Build TPA list and search paths
|
||||||
pal::string_t tpalist;
|
pal::string_t tpalist;
|
||||||
tpa.write_tpa_list(tpalist);
|
tpa.write_tpa_list(tpalist);
|
||||||
|
|
||||||
pal::string_t search_paths;
|
pal::string_t search_paths;
|
||||||
tpa.write_native_paths(search_paths);
|
tpa.write_native_paths(search_paths);
|
||||||
|
|
||||||
// Build CoreCLR properties
|
// Build CoreCLR properties
|
||||||
const char* property_keys[] = {
|
const char* property_keys[] = {
|
||||||
"TRUSTED_PLATFORM_ASSEMBLIES",
|
"TRUSTED_PLATFORM_ASSEMBLIES",
|
||||||
"APP_PATHS",
|
"APP_PATHS",
|
||||||
"APP_NI_PATHS",
|
"APP_NI_PATHS",
|
||||||
"NATIVE_DLL_SEARCH_DIRECTORIES",
|
"NATIVE_DLL_SEARCH_DIRECTORIES",
|
||||||
"AppDomainCompatSwitch"
|
"AppDomainCompatSwitch"
|
||||||
};
|
};
|
||||||
|
|
||||||
auto tpa_cstr = pal::to_stdstring(tpalist);
|
auto tpa_cstr = pal::to_stdstring(tpalist);
|
||||||
auto app_base_cstr = pal::to_stdstring(app_base);
|
auto app_base_cstr = pal::to_stdstring(app_base);
|
||||||
auto search_paths_cstr = pal::to_stdstring(search_paths);
|
auto search_paths_cstr = pal::to_stdstring(search_paths);
|
||||||
|
|
||||||
const char* property_values[] = {
|
const char* property_values[] = {
|
||||||
// TRUSTED_PLATFORM_ASSEMBLIES
|
// TRUSTED_PLATFORM_ASSEMBLIES
|
||||||
tpa_cstr.c_str(),
|
tpa_cstr.c_str(),
|
||||||
// APP_PATHS
|
// APP_PATHS
|
||||||
app_base_cstr.c_str(),
|
app_base_cstr.c_str(),
|
||||||
// APP_NI_PATHS
|
// APP_NI_PATHS
|
||||||
app_base_cstr.c_str(),
|
app_base_cstr.c_str(),
|
||||||
// NATIVE_DLL_SEARCH_DIRECTORIES
|
// NATIVE_DLL_SEARCH_DIRECTORIES
|
||||||
search_paths_cstr.c_str(),
|
search_paths_cstr.c_str(),
|
||||||
// AppDomainCompatSwitch
|
// AppDomainCompatSwitch
|
||||||
"UseLatestBehaviorWhenTFMNotSpecified"
|
"UseLatestBehaviorWhenTFMNotSpecified"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Dump TPA list
|
// Dump TPA list
|
||||||
trace::verbose(_X("TPA List: %s"), tpalist.c_str());
|
trace::verbose(_X("TPA List: %s"), tpalist.c_str());
|
||||||
|
|
||||||
// Dump native search paths
|
// Dump native search paths
|
||||||
trace::verbose(_X("Native Paths: %s"), search_paths.c_str());
|
trace::verbose(_X("Native Paths: %s"), search_paths.c_str());
|
||||||
|
|
||||||
// Bind CoreCLR
|
// Bind CoreCLR
|
||||||
if (!coreclr::bind(args.clr_path))
|
if (!coreclr::bind(args.clr_path))
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to bind to coreclr"));
|
trace::error(_X("failed to bind to coreclr"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize CoreCLR
|
// Initialize CoreCLR
|
||||||
coreclr::host_handle_t host_handle;
|
coreclr::host_handle_t host_handle;
|
||||||
coreclr::domain_id_t domain_id;
|
coreclr::domain_id_t domain_id;
|
||||||
auto hr = coreclr::initialize(
|
auto hr = coreclr::initialize(
|
||||||
pal::to_stdstring(args.own_path).c_str(),
|
pal::to_stdstring(args.own_path).c_str(),
|
||||||
"clrhost",
|
"clrhost",
|
||||||
property_keys,
|
property_keys,
|
||||||
property_values,
|
property_values,
|
||||||
sizeof(property_keys) / sizeof(property_keys[0]),
|
sizeof(property_keys) / sizeof(property_keys[0]),
|
||||||
&host_handle,
|
&host_handle,
|
||||||
&domain_id);
|
&domain_id);
|
||||||
if (!SUCCEEDED(hr))
|
if (!SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to initialize CoreCLR, HRESULT: 0x%X"), hr);
|
trace::error(_X("failed to initialize CoreCLR, HRESULT: 0x%X"), hr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the args (probably not the most performant way to do this...)
|
// Convert the args (probably not the most performant way to do this...)
|
||||||
auto argv_strs = new std::string[args.app_argc];
|
auto argv_strs = new std::string[args.app_argc];
|
||||||
auto argv = new const char*[args.app_argc];
|
auto argv = new const char*[args.app_argc];
|
||||||
for (int i = 0; i < args.app_argc; i++)
|
for (int i = 0; i < args.app_argc; i++)
|
||||||
{
|
{
|
||||||
argv_strs[i] = pal::to_stdstring(pal::string_t(args.app_argv[i]));
|
argv_strs[i] = pal::to_stdstring(pal::string_t(args.app_argv[i]));
|
||||||
argv[i] = argv_strs[i].c_str();
|
argv[i] = argv_strs[i].c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the application
|
// Execute the application
|
||||||
unsigned int exit_code = 1;
|
unsigned int exit_code = 1;
|
||||||
hr = coreclr::execute_assembly(
|
hr = coreclr::execute_assembly(
|
||||||
host_handle,
|
host_handle,
|
||||||
domain_id,
|
domain_id,
|
||||||
args.app_argc,
|
args.app_argc,
|
||||||
argv,
|
argv,
|
||||||
pal::to_stdstring(args.managed_application).c_str(),
|
pal::to_stdstring(args.managed_application).c_str(),
|
||||||
&exit_code);
|
&exit_code);
|
||||||
if (!SUCCEEDED(hr))
|
if (!SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to execute managed app, HRESULT: 0x%X"), hr);
|
trace::error(_X("failed to execute managed app, HRESULT: 0x%X"), hr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shut down the CoreCLR
|
// Shut down the CoreCLR
|
||||||
hr = coreclr::shutdown(host_handle, domain_id);
|
hr = coreclr::shutdown(host_handle, domain_id);
|
||||||
if (!SUCCEEDED(hr))
|
if (!SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
trace::warning(_X("failed to shut down CoreCLR, HRESULT: 0x%X"), 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)
|
#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[])
|
int main(const int argc, const pal::char_t* argv[])
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
arguments_t args;
|
arguments_t args;
|
||||||
if (!parse_arguments(argc, argv, args))
|
if (!parse_arguments(argc, argv, args))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure tracing
|
// Configure tracing
|
||||||
trace::set_level(args.trace_level);
|
trace::set_level(args.trace_level);
|
||||||
trace::info(_X("tracing enabled"));
|
trace::info(_X("tracing enabled"));
|
||||||
|
|
||||||
// Resolve paths
|
// Resolve paths
|
||||||
if (!pal::realpath(args.managed_application))
|
if (!pal::realpath(args.managed_application))
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to locate managed application: %s"), args.managed_application.c_str());
|
trace::error(_X("failed to locate managed application: %s"), args.managed_application.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
trace::info(_X("preparing to launch managed application: %s"), args.managed_application.c_str());
|
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());
|
trace::info(_X("host path: %s"), args.own_path.c_str());
|
||||||
|
|
||||||
pal::string_t argstr;
|
pal::string_t argstr;
|
||||||
for (int i = 0; i < args.app_argc; i++)
|
for (int i = 0; i < args.app_argc; i++)
|
||||||
{
|
{
|
||||||
argstr.append(args.app_argv[i]);
|
argstr.append(args.app_argv[i]);
|
||||||
argstr.append(_X(","));
|
argstr.append(_X(","));
|
||||||
}
|
}
|
||||||
trace::info(_X("App argc: %d"), args.app_argc);
|
trace::info(_X("App argc: %d"), args.app_argc);
|
||||||
trace::info(_X("App argv: %s"), argstr.c_str());
|
trace::info(_X("App argv: %s"), argstr.c_str());
|
||||||
|
|
||||||
auto app_base = get_directory(args.managed_application);
|
auto app_base = get_directory(args.managed_application);
|
||||||
auto app_name = get_filename(args.managed_application);
|
auto app_name = get_filename(args.managed_application);
|
||||||
|
|
||||||
if (args.clr_path.empty())
|
if (args.clr_path.empty())
|
||||||
{
|
{
|
||||||
// Use the directory containing the managed assembly
|
// Use the directory containing the managed assembly
|
||||||
args.clr_path = app_base;
|
if (!find_coreclr(app_base, args.clr_path))
|
||||||
}
|
{
|
||||||
|
trace::error(_X("failed to locate CLR files"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!pal::realpath(args.clr_path))
|
if (!pal::realpath(args.clr_path))
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to locate CLR files at %s"), args.clr_path.c_str());
|
trace::error(_X("failed to locate CLR files at %s"), args.clr_path.c_str());
|
||||||
return 1;
|
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());
|
// Check for and load tpa file
|
||||||
trace::info(_X("using app base: %s"), app_base.c_str());
|
pal::string_t tpafile_path;
|
||||||
|
get_tpafile_path(app_base, app_name, tpafile_path);
|
||||||
// Check for and load tpa file
|
trace::info(_X("checking for TPA File at: %s"), tpafile_path.c_str());
|
||||||
pal::string_t tpafile_path;
|
tpafile tpa;
|
||||||
get_tpafile_path(app_base, app_name, tpafile_path);
|
if (!tpa.load(tpafile_path))
|
||||||
trace::info(_X("checking for TPA File at: %s"), tpafile_path.c_str());
|
{
|
||||||
tpafile tpa;
|
trace::error(_X("invalid TPA file"));
|
||||||
if (!tpa.load(tpafile_path))
|
return 1;
|
||||||
{
|
}
|
||||||
trace::error(_X("invalid TPA file"));
|
return run(args, app_base, tpa);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return run(args, app_base, tpa);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,148 +9,148 @@ static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> g_converter;
|
||||||
|
|
||||||
bool pal::load_library(const char_t* path, dll_t& dll)
|
bool pal::load_library(const char_t* path, dll_t& dll)
|
||||||
{
|
{
|
||||||
dll = ::LoadLibraryW(path);
|
dll = ::LoadLibraryW(path);
|
||||||
if (dll == nullptr)
|
if (dll == nullptr)
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to load coreclr.dll from %s, HRESULT: 0x%X"), path, HRESULT_FROM_WIN32(GetLastError()));
|
trace::error(_X("failed to load coreclr.dll from %s, HRESULT: 0x%X"), path, HRESULT_FROM_WIN32(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pin the module
|
// Pin the module
|
||||||
HMODULE dummy_module;
|
HMODULE dummy_module;
|
||||||
if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, path, &dummy_module))
|
if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, path, &dummy_module))
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to pin library: %s"));
|
trace::error(_X("failed to pin library: %s"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trace::is_enabled(trace::level_t::Info))
|
if (trace::is_enabled(trace::level_t::Info))
|
||||||
{
|
{
|
||||||
pal::char_t buf[PATH_MAX];
|
pal::char_t buf[PATH_MAX];
|
||||||
::GetModuleFileNameW(dll, buf, PATH_MAX);
|
::GetModuleFileNameW(dll, buf, PATH_MAX);
|
||||||
trace::info(_X("loaded library from %s"), buf);
|
trace::info(_X("loaded library from %s"), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pal::proc_t pal::get_symbol(dll_t library, const char* name)
|
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)
|
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)
|
bool pal::get_default_packages_directory(string_t& recv)
|
||||||
{
|
{
|
||||||
if (!pal::getenv(_X("USERPROFILE"), recv))
|
if (!pal::getenv(_X("USERPROFILE"), recv))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
append_path(recv, _X(".dnx"));
|
append_path(recv, _X(".dnx"));
|
||||||
append_path(recv, _X("packages"));
|
append_path(recv, _X("packages"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pal::is_path_rooted(const string_t& path)
|
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)
|
bool pal::getenv(const char_t* name, string_t& recv)
|
||||||
{
|
{
|
||||||
auto length = ::GetEnvironmentVariableW(name, nullptr, 0);
|
auto length = ::GetEnvironmentVariableW(name, nullptr, 0);
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
{
|
{
|
||||||
auto err = GetLastError();
|
auto err = GetLastError();
|
||||||
if (err == ERROR_ENVVAR_NOT_FOUND)
|
if (err == ERROR_ENVVAR_NOT_FOUND)
|
||||||
{
|
{
|
||||||
// Leave the receiver empty and return success
|
// Leave the receiver empty and return success
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError()));
|
trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto buf = new char_t[length];
|
auto buf = new char_t[length];
|
||||||
if (::GetEnvironmentVariableW(name, buf, length) == 0)
|
if (::GetEnvironmentVariableW(name, buf, length) == 0)
|
||||||
{
|
{
|
||||||
trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError()));
|
trace::error(_X("failed to read enviroment variable '%s', HRESULT: 0x%X"), name, HRESULT_FROM_WIN32(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
recv.assign(buf);
|
recv.assign(buf);
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pal::xtoi(const char_t* input)
|
int pal::xtoi(const char_t* input)
|
||||||
{
|
{
|
||||||
return ::_wtoi(input);
|
return ::_wtoi(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pal::get_own_executable_path(string_t& recv)
|
bool pal::get_own_executable_path(string_t& recv)
|
||||||
{
|
{
|
||||||
char_t program_path[MAX_PATH];
|
char_t program_path[MAX_PATH];
|
||||||
DWORD dwModuleFileName = ::GetModuleFileNameW(NULL, program_path, MAX_PATH);
|
DWORD dwModuleFileName = ::GetModuleFileNameW(NULL, program_path, MAX_PATH);
|
||||||
if (dwModuleFileName == 0 || dwModuleFileName >= MAX_PATH) {
|
if (dwModuleFileName == 0 || dwModuleFileName >= MAX_PATH) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
recv.assign(program_path);
|
recv.assign(program_path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pal::to_stdstring(const string_t& str)
|
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)
|
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)
|
bool pal::realpath(string_t& path)
|
||||||
{
|
{
|
||||||
char_t buf[MAX_PATH];
|
char_t buf[MAX_PATH];
|
||||||
auto res = ::GetFullPathNameW(path.c_str(), MAX_PATH, buf, nullptr);
|
auto res = ::GetFullPathNameW(path.c_str(), MAX_PATH, buf, nullptr);
|
||||||
if (res == 0 || res > MAX_PATH)
|
if (res == 0 || res > MAX_PATH)
|
||||||
{
|
{
|
||||||
trace::error(_X("error resolving path: %s"), path.c_str());
|
trace::error(_X("error resolving path: %s"), path.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
path.assign(buf);
|
path.assign(buf);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pal::file_exists(const string_t& path)
|
bool pal::file_exists(const string_t& path)
|
||||||
{
|
{
|
||||||
WIN32_FIND_DATAW data;
|
WIN32_FIND_DATAW data;
|
||||||
auto find_handle = ::FindFirstFileW(path.c_str(), &data);
|
auto find_handle = ::FindFirstFileW(path.c_str(), &data);
|
||||||
bool found = find_handle != INVALID_HANDLE_VALUE;
|
bool found = find_handle != INVALID_HANDLE_VALUE;
|
||||||
::FindClose(find_handle);
|
::FindClose(find_handle);
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<pal::string_t> pal::readdir(const string_t& path)
|
std::vector<pal::string_t> pal::readdir(const string_t& path)
|
||||||
{
|
{
|
||||||
std::vector<string_t> files;
|
std::vector<string_t> files;
|
||||||
|
|
||||||
string_t search_string(path);
|
string_t search_string(path);
|
||||||
search_string.push_back(DIR_SEPARATOR);
|
search_string.push_back(DIR_SEPARATOR);
|
||||||
search_string.push_back(L'*');
|
search_string.push_back(L'*');
|
||||||
|
|
||||||
WIN32_FIND_DATAW data;
|
WIN32_FIND_DATAW data;
|
||||||
auto handle = ::FindFirstFileW(search_string.c_str(), &data);
|
auto handle = ::FindFirstFileW(search_string.c_str(), &data);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
string_t filepath(data.cFileName);
|
string_t filepath(data.cFileName);
|
||||||
files.push_back(filepath);
|
files.push_back(filepath);
|
||||||
} while (::FindNextFileW(handle, &data));
|
} while (::FindNextFileW(handle, &data));
|
||||||
::FindClose(handle);
|
::FindClose(handle);
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,242 +7,242 @@
|
||||||
|
|
||||||
bool read_field(pal::string_t line, int& offset, pal::string_t& value_recv)
|
bool read_field(pal::string_t line, int& offset, pal::string_t& value_recv)
|
||||||
{
|
{
|
||||||
// The first character should be a '"'
|
// The first character should be a '"'
|
||||||
if (line[offset] != '"')
|
if (line[offset] != '"')
|
||||||
{
|
{
|
||||||
trace::error(_X("error reading TPA file"));
|
trace::error(_X("error reading TPA file"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
offset++;
|
offset++;
|
||||||
|
|
||||||
// Set up destination buffer (it can't be bigger than the original line)
|
// Set up destination buffer (it can't be bigger than the original line)
|
||||||
pal::char_t buf[PATH_MAX];
|
pal::char_t buf[PATH_MAX];
|
||||||
auto buf_offset = 0;
|
auto buf_offset = 0;
|
||||||
|
|
||||||
// Iterate through characters in the string
|
// Iterate through characters in the string
|
||||||
for (; offset < line.length(); offset++)
|
for (; offset < line.length(); offset++)
|
||||||
{
|
{
|
||||||
// Is this a '\'?
|
// Is this a '\'?
|
||||||
if (line[offset] == '\\')
|
if (line[offset] == '\\')
|
||||||
{
|
{
|
||||||
// Skip this character and read the next character into the buffer
|
// Skip this character and read the next character into the buffer
|
||||||
offset++;
|
offset++;
|
||||||
buf[buf_offset] = line[offset];
|
buf[buf_offset] = line[offset];
|
||||||
}
|
}
|
||||||
// Is this a '"'?
|
// Is this a '"'?
|
||||||
else if (line[offset] == '\"')
|
else if (line[offset] == '\"')
|
||||||
{
|
{
|
||||||
// Done! Advance to the pointer after the input
|
// Done! Advance to the pointer after the input
|
||||||
offset++;
|
offset++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Take the character
|
// Take the character
|
||||||
buf[buf_offset] = line[offset];
|
buf[buf_offset] = line[offset];
|
||||||
}
|
}
|
||||||
buf_offset++;
|
buf_offset++;
|
||||||
}
|
}
|
||||||
buf[buf_offset] = '\0';
|
buf[buf_offset] = '\0';
|
||||||
value_recv.assign(buf);
|
value_recv.assign(buf);
|
||||||
|
|
||||||
// Consume the ',' if we have one
|
// Consume the ',' if we have one
|
||||||
if (line[offset] == ',')
|
if (line[offset] == ',')
|
||||||
{
|
{
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tpafile::load(pal::string_t path)
|
bool tpafile::load(pal::string_t path)
|
||||||
{
|
{
|
||||||
// Check if the file exists, if not, there is nothing to add
|
// Check if the file exists, if not, there is nothing to add
|
||||||
if (!pal::file_exists(path))
|
if (!pal::file_exists(path))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the file
|
// Open the file
|
||||||
pal::ifstream_t file(path);
|
pal::ifstream_t file(path);
|
||||||
if (!file.good())
|
if (!file.good())
|
||||||
{
|
{
|
||||||
// Failed to open the file!
|
// Failed to open the file!
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read lines from the file
|
// Read lines from the file
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
std::getline(file, line);
|
std::getline(file, line);
|
||||||
auto line_palstr = pal::to_palstring(line);
|
auto line_palstr = pal::to_palstring(line);
|
||||||
if (file.eof())
|
if (file.eof())
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offset = 0;
|
auto offset = 0;
|
||||||
|
|
||||||
tpaentry_t entry;
|
tpaentry_t entry;
|
||||||
|
|
||||||
// Read fields
|
// Read fields
|
||||||
if (!(read_field(line_palstr, offset, entry.library_type))) return false;
|
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_name))) return false;
|
||||||
if (!(read_field(line_palstr, offset, entry.library_version))) 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.library_hash))) return false;
|
||||||
if (!(read_field(line_palstr, offset, entry.asset_type))) 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.asset_name))) return false;
|
||||||
if (!(read_field(line_palstr, offset, entry.relative_path))) 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)
|
void tpafile::add_from_local_dir(const pal::string_t& dir)
|
||||||
{
|
{
|
||||||
trace::verbose(_X("adding files from %s to TPA"), dir.c_str());
|
trace::verbose(_X("adding files from %s to TPA"), dir.c_str());
|
||||||
const pal::char_t * const tpa_extensions[] = {
|
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(".ni.dll"), // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
|
||||||
_X(".dll"),
|
_X(".dll"),
|
||||||
_X(".ni.exe"),
|
_X(".ni.exe"),
|
||||||
_X(".exe"),
|
_X(".exe"),
|
||||||
};
|
};
|
||||||
|
|
||||||
std::set<pal::string_t> added_assemblies;
|
std::set<pal::string_t> added_assemblies;
|
||||||
|
|
||||||
// Get directory entries
|
// Get directory entries
|
||||||
auto files = pal::readdir(dir);
|
auto files = pal::readdir(dir);
|
||||||
for (auto ext : tpa_extensions)
|
for (auto ext : tpa_extensions)
|
||||||
{
|
{
|
||||||
auto len = pal::strlen(ext);
|
auto len = pal::strlen(ext);
|
||||||
for (auto file : files)
|
for (auto file : files)
|
||||||
{
|
{
|
||||||
// Can't be a match if it's the same length as the extension :)
|
// Can't be a match if it's the same length as the extension :)
|
||||||
if (file.length() > len)
|
if (file.length() > len)
|
||||||
{
|
{
|
||||||
// Extract the same amount of text from the end of file name
|
// Extract the same amount of text from the end of file name
|
||||||
auto file_ext = file.substr(file.length() - len, len);
|
auto file_ext = file.substr(file.length() - len, len);
|
||||||
|
|
||||||
// Check if this file name matches
|
// Check if this file name matches
|
||||||
if (pal::strcasecmp(ext, file_ext.c_str()) == 0)
|
if (pal::strcasecmp(ext, file_ext.c_str()) == 0)
|
||||||
{
|
{
|
||||||
// Get the assembly name by stripping the extension
|
// Get the assembly name by stripping the extension
|
||||||
// and add it to the set so we can de-dupe
|
// and add it to the set so we can de-dupe
|
||||||
auto asm_name = file.substr(0, file.length() - len);
|
auto asm_name = file.substr(0, file.length() - len);
|
||||||
|
|
||||||
// TODO(anurse): Also check if already in TPA file
|
// TODO(anurse): Also check if already in TPA file
|
||||||
if (added_assemblies.find(asm_name) == added_assemblies.end())
|
if (added_assemblies.find(asm_name) == added_assemblies.end())
|
||||||
{
|
{
|
||||||
added_assemblies.insert(asm_name);
|
added_assemblies.insert(asm_name);
|
||||||
|
|
||||||
tpaentry_t entry;
|
tpaentry_t entry;
|
||||||
entry.asset_type = pal::string_t(_X("runtime"));
|
entry.asset_type = pal::string_t(_X("runtime"));
|
||||||
entry.library_name = pal::string_t(asm_name);
|
entry.library_name = pal::string_t(asm_name);
|
||||||
entry.library_version = pal::string_t(_X(""));
|
entry.library_version = pal::string_t(_X(""));
|
||||||
|
|
||||||
pal::string_t relpath(dir);
|
pal::string_t relpath(dir);
|
||||||
relpath.push_back(DIR_SEPARATOR);
|
relpath.push_back(DIR_SEPARATOR);
|
||||||
relpath.append(file);
|
relpath.append(file);
|
||||||
entry.relative_path = relpath;
|
entry.relative_path = relpath;
|
||||||
entry.asset_name = asm_name;
|
entry.asset_name = asm_name;
|
||||||
|
|
||||||
trace::verbose(_X("adding %s to TPA list from %s"), asm_name.c_str(), relpath.c_str());
|
trace::verbose(_X("adding %s to TPA list from %s"), asm_name.c_str(), relpath.c_str());
|
||||||
m_entries.push_back(entry);
|
m_entries.push_back(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tpafile::write_tpa_list(pal::string_t& output)
|
void tpafile::write_tpa_list(pal::string_t& output)
|
||||||
{
|
{
|
||||||
std::set<pal::string_t> items;
|
std::set<pal::string_t> items;
|
||||||
for (auto entry : m_entries)
|
for (auto entry : m_entries)
|
||||||
{
|
{
|
||||||
if (pal::strcmp(entry.asset_type.c_str(), _X("runtime")) == 0 && items.find(entry.asset_name) == items.end())
|
if (pal::strcmp(entry.asset_type.c_str(), _X("runtime")) == 0 && items.find(entry.asset_name) == items.end())
|
||||||
{
|
{
|
||||||
// Resolve the full path
|
// Resolve the full path
|
||||||
for (auto search_path : m_package_search_paths)
|
for (auto search_path : m_package_search_paths)
|
||||||
{
|
{
|
||||||
pal::string_t candidate;
|
pal::string_t candidate;
|
||||||
candidate.reserve(search_path.length() +
|
candidate.reserve(search_path.length() +
|
||||||
entry.library_name.length() +
|
entry.library_name.length() +
|
||||||
entry.library_version.length() +
|
entry.library_version.length() +
|
||||||
entry.relative_path.length() + 3);
|
entry.relative_path.length() + 3);
|
||||||
candidate.append(search_path);
|
candidate.append(search_path);
|
||||||
|
|
||||||
append_path(candidate, entry.library_name.c_str());
|
append_path(candidate, entry.library_name.c_str());
|
||||||
append_path(candidate, entry.library_version.c_str());
|
append_path(candidate, entry.library_version.c_str());
|
||||||
append_path(candidate, entry.relative_path.c_str());
|
append_path(candidate, entry.relative_path.c_str());
|
||||||
if (pal::file_exists(candidate))
|
if (pal::file_exists(candidate))
|
||||||
{
|
{
|
||||||
trace::verbose(_X("adding tpa entry: %s"), candidate.c_str());
|
trace::verbose(_X("adding tpa entry: %s"), candidate.c_str());
|
||||||
|
|
||||||
output.append(candidate);
|
output.append(candidate);
|
||||||
output.push_back(PATH_SEPARATOR);
|
output.push_back(PATH_SEPARATOR);
|
||||||
items.insert(entry.asset_name);
|
items.insert(entry.asset_name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tpafile::write_native_paths(pal::string_t& output)
|
void tpafile::write_native_paths(pal::string_t& output)
|
||||||
{
|
{
|
||||||
std::set<pal::string_t> items;
|
std::set<pal::string_t> items;
|
||||||
for (auto search_path : m_native_search_paths)
|
for (auto search_path : m_native_search_paths)
|
||||||
{
|
{
|
||||||
if (items.find(search_path) == items.end())
|
if (items.find(search_path) == items.end())
|
||||||
{
|
{
|
||||||
trace::verbose(_X("adding native search path: %s"), search_path.c_str());
|
trace::verbose(_X("adding native search path: %s"), search_path.c_str());
|
||||||
output.append(search_path);
|
output.append(search_path);
|
||||||
output.push_back(PATH_SEPARATOR);
|
output.push_back(PATH_SEPARATOR);
|
||||||
items.insert(search_path);
|
items.insert(search_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto entry : m_entries)
|
for (auto entry : m_entries)
|
||||||
{
|
{
|
||||||
auto dir = entry.relative_path.substr(0, entry.relative_path.find_last_of(DIR_SEPARATOR));
|
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())
|
if (pal::strcmp(entry.asset_type.c_str(), _X("native")) == 0 && items.find(dir) == items.end())
|
||||||
{
|
{
|
||||||
// Resolve the full path
|
// Resolve the full path
|
||||||
for (auto search_path : m_package_search_paths)
|
for (auto search_path : m_package_search_paths)
|
||||||
{
|
{
|
||||||
pal::string_t candidate;
|
pal::string_t candidate;
|
||||||
candidate.reserve(search_path.length() +
|
candidate.reserve(search_path.length() +
|
||||||
entry.library_name.length() +
|
entry.library_name.length() +
|
||||||
entry.library_version.length() +
|
entry.library_version.length() +
|
||||||
dir.length() + 3);
|
dir.length() + 3);
|
||||||
candidate.append(search_path);
|
candidate.append(search_path);
|
||||||
|
|
||||||
append_path(candidate, entry.library_name.c_str());
|
append_path(candidate, entry.library_name.c_str());
|
||||||
append_path(candidate, entry.library_version.c_str());
|
append_path(candidate, entry.library_version.c_str());
|
||||||
append_path(candidate, get_directory(entry.relative_path).c_str());
|
append_path(candidate, get_directory(entry.relative_path).c_str());
|
||||||
|
|
||||||
if (pal::file_exists(candidate))
|
if (pal::file_exists(candidate))
|
||||||
{
|
{
|
||||||
trace::verbose(_X("adding native search path: %s"), candidate.c_str());
|
trace::verbose(_X("adding native search path: %s"), candidate.c_str());
|
||||||
output.append(candidate);
|
output.append(candidate);
|
||||||
output.push_back(PATH_SEPARATOR);
|
output.push_back(PATH_SEPARATOR);
|
||||||
items.insert(dir);
|
items.insert(dir);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tpafile::add_package_dir(pal::string_t dir)
|
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)
|
void tpafile::add_native_search_path(pal::string_t dir)
|
||||||
{
|
{
|
||||||
m_native_search_paths.push_back(dir);
|
m_native_search_paths.push_back(dir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,54 +4,54 @@ static trace::level_t g_level = trace::level_t::Error;
|
||||||
|
|
||||||
void trace::set_level(trace::level_t new_level)
|
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)
|
bool trace::is_enabled(trace::level_t level)
|
||||||
{
|
{
|
||||||
return level <= g_level;
|
return level <= g_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace::verbose(const pal::char_t* format, ...)
|
void trace::verbose(const pal::char_t* format, ...)
|
||||||
{
|
{
|
||||||
if (trace::is_enabled(trace::level_t::Verbose))
|
if (trace::is_enabled(trace::level_t::Verbose))
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
pal::err_vprintf(format, args);
|
pal::err_vprintf(format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace::info(const pal::char_t* format, ...)
|
void trace::info(const pal::char_t* format, ...)
|
||||||
{
|
{
|
||||||
if (trace::is_enabled(trace::level_t::Info))
|
if (trace::is_enabled(trace::level_t::Info))
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
pal::err_vprintf(format, args);
|
pal::err_vprintf(format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace::error(const pal::char_t* format, ...)
|
void trace::error(const pal::char_t* format, ...)
|
||||||
{
|
{
|
||||||
if (trace::is_enabled(trace::level_t::Error))
|
if (trace::is_enabled(trace::level_t::Error))
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
pal::err_vprintf(format, args);
|
pal::err_vprintf(format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace::warning(const pal::char_t* format, ...)
|
void trace::warning(const pal::char_t* format, ...)
|
||||||
{
|
{
|
||||||
if (trace::is_enabled(trace::level_t::Warning))
|
if (trace::is_enabled(trace::level_t::Warning))
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
pal::err_vprintf(format, args);
|
pal::err_vprintf(format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +1,93 @@
|
||||||
#include "utils.h"
|
#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)
|
void append_path(pal::string_t& path1, const pal::char_t* path2)
|
||||||
{
|
{
|
||||||
if (pal::is_path_rooted(path2))
|
if (pal::is_path_rooted(path2))
|
||||||
{
|
{
|
||||||
path1.assign(path2);
|
path1.assign(path2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (path1.back() != DIR_SEPARATOR)
|
if (path1.back() != DIR_SEPARATOR)
|
||||||
{
|
{
|
||||||
path1.push_back(DIR_SEPARATOR);
|
path1.push_back(DIR_SEPARATOR);
|
||||||
}
|
}
|
||||||
path1.append(path2);
|
path1.append(path2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pal::string_t get_executable(const pal::string_t& filename)
|
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")))
|
if (ends_with(result, _X(".exe")))
|
||||||
{
|
{
|
||||||
// We need to strip off the old extension
|
// We need to strip off the old extension
|
||||||
result.erase(result.length() - 4);
|
result.erase(result.length() - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
bool ends_with(const pal::string_t& value, const pal::string_t& suffix)
|
|
||||||
{
|
|
||||||
return (0 == value.compare(value.length() - suffix.length(), suffix.length(), suffix));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pal::string_t get_filename(const pal::string_t& path)
|
pal::string_t get_filename(const pal::string_t& path)
|
||||||
{
|
{
|
||||||
// Find the last dir separator
|
// Find the last dir separator
|
||||||
auto path_sep = path.find_last_of(DIR_SEPARATOR);
|
auto path_sep = path.find_last_of(DIR_SEPARATOR);
|
||||||
if (path_sep == pal::string_t::npos)
|
if (path_sep == pal::string_t::npos)
|
||||||
{
|
{
|
||||||
return pal::string_t(path);
|
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)
|
pal::string_t get_directory(const pal::string_t& path)
|
||||||
{
|
{
|
||||||
// Find the last dir separator
|
// Find the last dir separator
|
||||||
auto path_sep = path.find_last_of(DIR_SEPARATOR);
|
auto path_sep = path.find_last_of(DIR_SEPARATOR);
|
||||||
if (path_sep == pal::string_t::npos)
|
if (path_sep == pal::string_t::npos)
|
||||||
{
|
{
|
||||||
return pal::string_t(path);
|
return pal::string_t(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.substr(0, path_sep);
|
return path.substr(0, path_sep);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace TestApp
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Console.WriteLine("This is a test app");
|
Console.WriteLine(TestLibrary.Helper.GetMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"dependencies": {
|
"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.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",
|
"System.Diagnostics.Process": "4.1.0-beta-23420",
|
||||||
"Microsoft.NETCore.Runtime": "1.0.1-beta-23428"
|
"Microsoft.NETCore.Runtime": "1.0.1-beta-23428"
|
||||||
},
|
},
|
||||||
|
|
12
test/TestLibrary/Helper.cs
Normal file
12
test/TestLibrary/Helper.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TestLibrary
|
||||||
|
{
|
||||||
|
public static class Helper
|
||||||
|
{
|
||||||
|
public static string GetMessage()
|
||||||
|
{
|
||||||
|
return "This string came from the test library!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
test/TestLibrary/TestLibrary.xproj
Normal file
19
test/TestLibrary/TestLibrary.xproj
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>947dd232-8d9b-4b78-9c6a-94f807d2dd58</ProjectGuid>
|
||||||
|
<RootNamespace>TestLibrary</RootNamespace>
|
||||||
|
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||||
|
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
</Project>
|
11
test/TestLibrary/project.json
Normal file
11
test/TestLibrary/project.json
Normal file
|
@ -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": { }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue