diff --git a/src/ProjectTemplates/Quantum.App1/Driver.cs b/src/ProjectTemplates/Quantum.App1/Driver.cs index 5ab9441939..20a7ecae50 100644 --- a/src/ProjectTemplates/Quantum.App1/Driver.cs +++ b/src/ProjectTemplates/Quantum.App1/Driver.cs @@ -1,7 +1,4 @@ -using System; -using System.Threading.Tasks; - -using Microsoft.Quantum.Simulation.Core; +using System.Threading.Tasks; using Microsoft.Quantum.Simulation.Simulators; namespace Quantum.App1 @@ -10,10 +7,8 @@ class Driver { static async Task Main(string[] args) { - using (var qsim = new QuantumSimulator()) - { - await HelloQ.Run(qsim); - } + using var qsim = new QuantumSimulator(); + await HelloQ.Run(qsim); } } } \ No newline at end of file diff --git a/src/QsCompiler/CommandLineTool/Commands/Build.cs b/src/QsCompiler/CommandLineTool/Commands/Build.cs index ba1a7965fd..b9a7ac8356 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Build.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Build.cs @@ -16,7 +16,7 @@ namespace Microsoft.Quantum.QsCompiler.CommandLineCompiler public static class BuildCompilation { [Verb("build", HelpText = "Builds a compilation unit to run on the Q# quantum simulation framework.")] - public class BuildOptions : Options + public class BuildOptions : CompilationOptions { [Usage(ApplicationAlias = "qsCompiler")] public static IEnumerable UsageExamples @@ -35,7 +35,7 @@ public static IEnumerable UsageExamples } [Option("response-files", Required = true, SetName = RESPONSE_FILES, - HelpText = "Response file(s) providing the command arguments. Required only if no other arguments are specified. This option replaces all other arguments.")] + HelpText = "Response file(s) providing command arguments. Required only if no other arguments are specified. Non-default values for options specified via command line take precedence.")] public IEnumerable ResponseFiles { get; set; } [Option('o', "output", Required = false, SetName = CODE_MODE, @@ -50,14 +50,6 @@ public static IEnumerable UsageExamples HelpText = "Name of the project (needs to be usable as file name).")] public string ProjectName { get; set; } - [Option("load", Required = false, SetName = CODE_MODE, - HelpText = "[Experimental feature] Path to the .NET Core dll(s) defining additional transformations to include in the compilation process.")] - public IEnumerable Plugins { get; set; } - - [Option("trim", Required = false, Default = 1, - HelpText = "[Experimental feature] Integer indicating how much to simplify the syntax tree by eliminating selective abstractions.")] - public int TrimLevel { get; set; } - [Option("emit-dll", Required = false, Default = false, SetName = CODE_MODE, HelpText = "Specifies whether the compiler should emit a .NET Core dll containing the compiled Q# code.")] public bool EmitDll { get; set; } @@ -65,8 +57,30 @@ public static IEnumerable UsageExamples [Option('p', "perf", Required = false, SetName = CODE_MODE, HelpText = "Destination folder where the output of the performance assessment will be generated.")] public string PerfFolder { get; set; } + + + /// + /// Reads the content of all specified response files and processes it using FromResponseFiles. + /// Updates the settings accordingly, prioritizing already specified non-default values over the values from response-files. + /// Returns true and a new BuildOptions object as out parameter with all the settings from response files incorporated. + /// Returns false if the content of the specified response-files could not be processed. + /// + internal static bool IncorporateResponseFiles(BuildOptions options, out BuildOptions incorporated) + { + incorporated = null; + while (options.ResponseFiles != null && options.ResponseFiles.Any()) + { + var fromResponseFiles = FromResponseFiles(options.ResponseFiles); + if (fromResponseFiles == null) return false; + fromResponseFiles.UpdateSetIndependentSettings(options); + options = fromResponseFiles; + } + incorporated = options; + return true; + } } + /// /// Given a string representing the command line arguments, splits them into a suitable string array. /// @@ -120,15 +134,19 @@ public static int Run(BuildOptions options, ConsoleLogger logger) { if (options == null) throw new ArgumentNullException(nameof(options)); if (logger == null) throw new ArgumentNullException(nameof(logger)); - - if (options?.ResponseFiles != null && options.ResponseFiles.Any()) - { options = FromResponseFiles(options.ResponseFiles); } - if (options == null) return ReturnCode.INVALID_ARGUMENTS; + if (!BuildOptions.IncorporateResponseFiles(options, out options)) return ReturnCode.INVALID_ARGUMENTS; var usesPlugins = options.Plugins != null && options.Plugins.Any(); + if (!options.ParseAssemblyProperties(out var assemblyConstants)) + { + logger.Log(WarningCode.InvalidAssemblyProperties, new string[0]); + } + var loadOptions = new CompilationLoader.Configuration { ProjectName = options.ProjectName, + AssemblyConstants = assemblyConstants, + TargetPackageAssembly = options.GetTargetPackageAssemblyPath(logger), GenerateFunctorSupport = true, SkipSyntaxTreeTrimming = options.TrimLevel == 0, ConvertClassicalControl = options.TrimLevel >= 2, @@ -154,7 +172,7 @@ public static int Run(BuildOptions options, ConsoleLogger logger) } catch (Exception ex) { - logger.Log(ErrorCode.PublishingPerfResultsFailed, new string[]{options.PerfFolder}); + logger.Log(ErrorCode.PublishingPerfResultsFailed, new string[]{ options.PerfFolder }); logger.Log(ex); } } diff --git a/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs b/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs index 8692affa79..d11755ff9a 100644 --- a/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs +++ b/src/QsCompiler/CommandLineTool/Commands/Diagnose.cs @@ -23,7 +23,7 @@ namespace Microsoft.Quantum.QsCompiler.CommandLineCompiler public static class DiagnoseCompilation { [Verb("diagnose", HelpText = "Generates intermediate representations of the code to help diagnose issues.")] - public class DiagnoseOptions : Options + public class DiagnoseOptions : CompilationOptions { [Usage(ApplicationAlias = "qsCompiler")] public static IEnumerable UsageExamples @@ -56,14 +56,6 @@ public static IEnumerable UsageExamples [Option("code", Required = false, Default = false, HelpText = "Specifies whether to print the Q# code generated based on the built syntax tree.")] public bool PrintCompiledCode { get; set; } - - [Option("trim", Required = false, Default = 1, - HelpText = "[Experimental feature] Integer indicating how much to simplify the syntax tree by eliminating selective abstractions.")] - public int TrimLevel { get; set; } - - [Option("load", Required = false, SetName = CODE_MODE, - HelpText = "[Experimental feature] Path to the .NET Core dll(s) defining additional transformations to include in the compilation process.")] - public IEnumerable Plugins { get; set; } } /// @@ -136,7 +128,7 @@ private static void PrintContentTokenization(Compilation compilation, ILogger lo private static void PrintSyntaxTree(IEnumerable evaluatedTree, Compilation compilation, ILogger logger) { if (compilation == null) throw new ArgumentNullException(nameof(compilation)); - evaluatedTree = evaluatedTree ?? compilation.SyntaxTree.Values; + evaluatedTree ??= compilation.SyntaxTree.Values; foreach (var file in compilation.SourceFiles) { @@ -166,7 +158,7 @@ void PrintTree(string serialization) => logger.Log( private static void PrintGeneratedQs(IEnumerable evaluatedTree, Compilation compilation, ILogger logger) { if (compilation == null) throw new ArgumentNullException(nameof(compilation)); - evaluatedTree = evaluatedTree ?? compilation.SyntaxTree.Values; + evaluatedTree ??= compilation.SyntaxTree.Values; foreach (var file in compilation.SourceFiles) { @@ -217,8 +209,15 @@ public static int Run(DiagnoseOptions options, ConsoleLogger logger) if (options == null) throw new ArgumentNullException(nameof(options)); if (logger == null) throw new ArgumentNullException(nameof(logger)); + if (!options.ParseAssemblyProperties(out var assemblyConstants)) + { + logger.Log(WarningCode.InvalidAssemblyProperties, new string[0]); + } + var loadOptions = new CompilationLoader.Configuration { + AssemblyConstants = assemblyConstants, + TargetPackageAssembly = options.GetTargetPackageAssemblyPath(logger), GenerateFunctorSupport = true, SkipSyntaxTreeTrimming = options.TrimLevel == 0, ConvertClassicalControl = options.TrimLevel >= 2, diff --git a/src/QsCompiler/CommandLineTool/Options.cs b/src/QsCompiler/CommandLineTool/Options.cs index ddc0afe413..124893dadd 100644 --- a/src/QsCompiler/CommandLineTool/Options.cs +++ b/src/QsCompiler/CommandLineTool/Options.cs @@ -17,6 +17,81 @@ namespace Microsoft.Quantum.QsCompiler.CommandLineCompiler { + /// + /// Default values for command line options if nothing is specified. + /// + internal static class DefaultOptions + { + public const string Verbosity = "normal"; + public const Options.LogFormat OutputFormat = Options.LogFormat.Default; + public const int TrimLevel = 1; + } + + + public class CompilationOptions : Options + { + [Option("trim", Required = false, Default = DefaultOptions.TrimLevel, SetName = CODE_MODE, + HelpText = "[Experimental feature] Integer indicating how much to simplify the syntax tree by eliminating selective abstractions.")] + public int TrimLevel { get; set; } + + [Option("load", Required = false, SetName = CODE_MODE, + HelpText = "[Experimental feature] Path to the .NET Core dll(s) defining additional transformations to include in the compilation process.")] + public IEnumerable Plugins { get; set; } + + [Option("target-package", Required = false, SetName = CODE_MODE, + HelpText = "Path to the NuGet package containing target specific information and implementations.")] + public string TargetPackage { get; set; } + + [Option('p', "assembly-properties", Required = false, SetName = CODE_MODE, + HelpText = "Additional properties to populate the AssemblyConstants dictionary with. Each item is expected to be of the form \"key=value\".")] + public IEnumerable AdditionalAssemblyProperties { get; set; } + + /// + /// Returns a dictionary with the specified assembly properties as out parameter. + /// Returns a boolean indicating whether all specified properties were successfully added. + /// + internal bool ParseAssemblyProperties(out Dictionary parsed) + { + var success = true; + parsed = new Dictionary(); + foreach (var keyValue in this.AdditionalAssemblyProperties ?? new string[0]) + { + var pieces = keyValue?.Split("="); + var valid = pieces != null && pieces.Length == 2; + success = valid && parsed.TryAdd(pieces[0].Trim().Trim('"'), pieces[1].Trim().Trim('"')) && success; + } + return success; + } + + /// + /// Returns null if TargetPackage is null or empty, and + /// returns the path to the assembly containing target specific implementations otherwise. + /// If a logger is specified, logs suitable diagnostics if a TargetPackages is not null or empty, + /// but no path to the target package assembly could be determined. + /// This may be the case if no directory at the TargetPackage location exists, or if its files can't be accessed, + /// or more than one dll matches the pattern by which the target package assembly is identified. + /// + public string GetTargetPackageAssemblyPath(ILogger logger = null) + { + if (String.IsNullOrEmpty(this.TargetPackage)) return null; + try + { + // Disclaimer: we may revise that in the future. + var targetPackageAssembly = Directory.GetFiles(this.TargetPackage, "*Intrinsics.dll", SearchOption.AllDirectories).SingleOrDefault(); + if (targetPackageAssembly != null) return targetPackageAssembly; + } + catch (Exception ex) + { + if (Directory.Exists(this.TargetPackage)) logger?.Log(ex); + else logger?.Log(ErrorCode.CouldNotFindTargetPackage, new[] { this.TargetPackage }); + } + + logger?.Log(ErrorCode.CouldNotFindTargetPackageAssembly, new[] { this.TargetPackage }); + return null; + } + } + + public class Options { public enum LogFormat @@ -30,10 +105,14 @@ public enum LogFormat protected const string SNIPPET_MODE = "snippetMode"; protected const string RESPONSE_FILES = "responseFiles"; - [Option('v', "verbosity", Required = false, Default = "normal", + [Option('v', "verbosity", Required = false, Default = DefaultOptions.Verbosity, HelpText = "Specifies the verbosity of the logged output. Valid values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].")] public string Verbosity { get; set; } + [Option("format", Required = false, Default = DefaultOptions.OutputFormat, + HelpText = "Specifies the output format of the command line compiler.")] + public LogFormat OutputFormat { get; set; } + [Option('i', "input", Required = true, SetName = CODE_MODE, HelpText = "Q# code or name of the Q# file to compile.")] public IEnumerable Input { get; set; } @@ -54,15 +133,25 @@ public enum LogFormat HelpText = "Warnings with the given code(s) will be ignored.")] public IEnumerable NoWarn { get; set; } - [Option("format", Required = false, Default = LogFormat.Default, - HelpText = "Specifies the output format of the command line compiler.")] - public LogFormat OutputFormat { get; set; } - [Option("package-load-fallback-folders", Required = false, SetName = CODE_MODE, - HelpText = "Specifies the directories the compiler will search when a rewrite step dependency could not be found.")] + HelpText = "Specifies the directories the compiler will search when a compiler dependency could not be found.")] public IEnumerable PackageLoadFallbackFolders { get; set; } + /// + /// Updates the settings that can be used independent on the other arguments according to the setting in the given options. + /// Already specified non-default values are prioritized over the values in the given options, + /// unless overwriteNonDefaultValues is set to true. Sequences are merged. + /// + internal void UpdateSetIndependentSettings(Options updates, bool overwriteNonDefaultValues = false) + { + this.Verbosity = overwriteNonDefaultValues || this.Verbosity == DefaultOptions.Verbosity ? updates.Verbosity : this.Verbosity; + this.OutputFormat = overwriteNonDefaultValues || this.OutputFormat == DefaultOptions.OutputFormat ? updates.OutputFormat : this.OutputFormat; + this.NoWarn = (this.NoWarn ?? new int[0]).Concat(updates.NoWarn ?? new int[0]); + this.References = (this.References ?? new string[0]).Concat(updates.References ?? new string[0]); + } + + // routines related to logging /// @@ -87,15 +176,13 @@ string value(PropertyInfo p) /// /// Given a LogFormat, returns a suitable routing for formatting diagnostics. /// - internal static Func LoggingFormat(LogFormat format) - { - switch (format) + internal static Func LoggingFormat(LogFormat format) => + format switch { - case LogFormat.MsBuild: return Formatting.MsBuildFormat; - case LogFormat.Default: return Formatting.HumanReadableFormat; - default: throw new NotImplementedException("unknown output format for logger"); - } - } + LogFormat.MsBuild => Formatting.MsBuildFormat, + LogFormat.Default => Formatting.HumanReadableFormat, + _ => throw new NotImplementedException("unknown output format for logger"), + }; /// /// Creates a suitable logger for the given command line options, diff --git a/src/QsCompiler/CompilationManager/AssemblyLoader.cs b/src/QsCompiler/CompilationManager/AssemblyLoader.cs index d3b41243a2..7c4937112d 100644 --- a/src/QsCompiler/CompilationManager/AssemblyLoader.cs +++ b/src/QsCompiler/CompilationManager/AssemblyLoader.cs @@ -30,44 +30,82 @@ public static class AssemblyLoader /// and returns the loaded content as out parameter. /// Returns false if some of the content could not be loaded successfully, /// possibly because the referenced assembly has been compiled with an older compiler version. + /// If onDeserializationException is specified, invokes the given action on any exception thrown during deserialization. /// Throws an ArgumentNullException if the given uri is null. /// Throws a FileNotFoundException if no file with the given name exists. /// Throws the corresponding exceptions if the information cannot be extracted. /// - public static bool LoadReferencedAssembly(Uri asm, out References.Headers headers, bool ignoreDllResources = false) + public static bool LoadReferencedAssembly(Uri asm, out References.Headers headers, bool ignoreDllResources = false, Action onDeserializationException = null) { if (asm == null) throw new ArgumentNullException(nameof(asm)); if (!CompilationUnitManager.TryGetFileId(asm, out var id) || !File.Exists(asm.LocalPath)) - { throw new FileNotFoundException($"the uri '{asm}' given to the assembly loader is invalid or the file does not exist"); } + { throw new FileNotFoundException($"The uri '{asm}' given to the assembly loader is invalid or the file does not exist."); } using var stream = File.OpenRead(asm.LocalPath); using var assemblyFile = new PEReader(stream); - if (ignoreDllResources || !FromResource(assemblyFile, out var syntaxTree)) + if (ignoreDllResources || !FromResource(assemblyFile, out var compilation, onDeserializationException)) { var attributes = LoadHeaderAttributes(assemblyFile); headers = new References.Headers(id, attributes); return ignoreDllResources || !attributes.Any(); // just means we have no references } - headers = new References.Headers(id, syntaxTree?.Namespaces ?? ImmutableArray.Empty); + headers = new References.Headers(id, compilation?.Namespaces ?? ImmutableArray.Empty); return true; } + /// + /// Loads the Q# data structures in a referenced assembly given the Uri to that assembly, + /// and returns the loaded content as out parameter. + /// Returns false if some of the content could not be loaded successfully, + /// possibly because the referenced assembly has been compiled with an older compiler version. + /// Catches any exception throw upon loading the compilation, and invokes onException with it if such an action has been specified. + /// Sets the out parameter to null if an exception occurred during loading. + /// Throws an ArgumentNullException if the given uri is null. + /// Throws a FileNotFoundException if no file with the given name exists. + /// + public static bool LoadReferencedAssembly(string asmPath, out QsCompilation compilation, Action onException = null) + { + if (asmPath == null) throw new ArgumentNullException(nameof(asmPath)); + if (!File.Exists(asmPath)) throw new FileNotFoundException($"The file '{asmPath}' does not exist."); + + using var stream = File.OpenRead(asmPath); + using var assemblyFile = new PEReader(stream); + try + { + return FromResource(assemblyFile, out compilation, onException); + } + catch (Exception ex) + { + onException?.Invoke(ex); + compilation = null; + return false; + } + } + // tools for loading the compiled syntax tree from the dll resource (later setup for shipping Q# libraries) /// /// Given a stream containing the binary representation of compiled Q# code, returns the corresponding Q# compilation. /// Returns true if the compilation could be deserialized without throwing an exception, and false otherwise. + /// If onDeserializationException is specified, invokes the given action on any exception thrown during deserialization. /// Throws an ArgumentNullException if the given stream is null, but ignores exceptions thrown during deserialization. /// - public static bool LoadSyntaxTree(Stream stream, out QsCompilation compilation) + public static bool LoadSyntaxTree(Stream stream, out QsCompilation compilation, Action onDeserializationException = null) { if (stream == null) throw new ArgumentNullException(nameof(stream)); using var reader = new BsonDataReader(stream); (compilation, reader.ReadRootValueAsArray) = (null, false); - try { compilation = Json.Serializer.Deserialize(reader); } - catch { return false; } - return compilation != null && !compilation.Namespaces.IsDefault && !compilation.EntryPoints.IsDefault; + try + { + compilation = Json.Serializer.Deserialize(reader); + return compilation != null && !compilation.Namespaces.IsDefault && !compilation.EntryPoints.IsDefault; + } + catch (Exception ex) + { + onDeserializationException?.Invoke(ex); + return false; + } } /// @@ -85,10 +123,11 @@ private static ImmutableDictionary Resources(this Meta /// /// Given a reader for the byte stream of a dotnet dll, loads any Q# compilation included as a resource. /// Returns true as well as the loaded compilation if the given dll includes a suitable resource, and returns false otherwise. + /// If onDeserializationException is specified, invokes the given action on any exception thrown during deserialization. /// Throws an ArgumentNullException if any of the given readers is null. /// May throw an exception if the given binary file has been compiled with a different compiler version. /// - private static bool FromResource(PEReader assemblyFile, out QsCompilation compilation) + private static bool FromResource(PEReader assemblyFile, out QsCompilation compilation, Action onDeserializationException = null) { if (assemblyFile == null) throw new ArgumentNullException(nameof(assemblyFile)); var metadataReader = assemblyFile.GetMetadataReader(); @@ -112,7 +151,7 @@ private static bool FromResource(PEReader assemblyFile, out QsCompilation compil // the first four bytes of the resource denote how long the resource is, and are followed by the actual resource data var resourceLength = BitConverter.ToInt32(image.GetContent(absResourceOffset, sizeof(Int32)).ToArray(), 0); var resourceData = image.GetContent(absResourceOffset + sizeof(Int32), resourceLength).ToArray(); - return LoadSyntaxTree(new MemoryStream(resourceData), out compilation); + return LoadSyntaxTree(new MemoryStream(resourceData), out compilation, onDeserializationException); } diff --git a/src/QsCompiler/CompilationManager/ProjectManager.cs b/src/QsCompiler/CompilationManager/ProjectManager.cs index 339c48ed51..f73fed31d1 100644 --- a/src/QsCompiler/CompilationManager/ProjectManager.cs +++ b/src/QsCompiler/CompilationManager/ProjectManager.cs @@ -470,7 +470,7 @@ public Task ReloadProjectReferenceAsync(IDictionary projectOutputPaths public Task ReloadSourceFileAsync(Uri sourceFile, Func openInEditor = null) { if (sourceFile == null) throw new ArgumentNullException(nameof(sourceFile)); - openInEditor = openInEditor ?? (_ => null); + openInEditor ??= (_ => null); return this.Processing.QueueForExecutionAsync(() => { @@ -589,7 +589,7 @@ private Func, Uri, IEnumerable> Migrat if (openInEditor == null) throw new ArgumentNullException(nameof(openInEditor)); return (filesAddedToProject, projFile) => { - filesAddedToProject = filesAddedToProject ?? ImmutableHashSet.Empty; + filesAddedToProject ??= ImmutableHashSet.Empty; var openFiles = filesAddedToProject.Select(openInEditor).Where(m => m != null).ToImmutableArray(); var removals = openFiles.Select(file => { @@ -618,7 +618,7 @@ private Action, Task> MigrateToDefaultManager(Func { if (removal.IsCanceled) return; - filesRemovedFromProject = filesRemovedFromProject ?? ImmutableHashSet.Empty; + filesRemovedFromProject ??= ImmutableHashSet.Empty; Task.WaitAll(removal); // we *need* to wait here in order to make sure that change notifications are processed in order!! var openFiles = filesRemovedFromProject.Select(openInEditor).Where(m => m != null).ToImmutableHashSet(); foreach (var file in openFiles) @@ -642,7 +642,7 @@ public Task LoadProjectsAsync(IEnumerable projectFiles, ProjectInformation. { if (projectFiles == null || projectFiles.Contains(null)) throw new ArgumentNullException(nameof(projectFiles)); if (projectLoader == null) throw new ArgumentNullException(nameof(projectLoader)); - openInEditor = openInEditor ?? (_ => null); + openInEditor ??= (_ => null); return this.Load.QueueForExecutionAsync(() => { @@ -672,7 +672,7 @@ public Task ProjectChangedOnDiskAsync(Uri projectFile, ProjectInformation.Loader { if (projectFile == null) throw new ArgumentNullException(nameof(projectFile)); if (projectLoader == null) throw new ArgumentNullException(nameof(projectLoader)); - openInEditor = openInEditor ?? (_ => null); + openInEditor ??= (_ => null); // TODO: allow to cancel this task via cancellation token? return this.Load.QueueForExecutionAsync(() => diff --git a/src/QsCompiler/Compiler/CompilationLoader.cs b/src/QsCompiler/Compiler/CompilationLoader.cs index 5bd3c0e3fa..425844ffff 100644 --- a/src/QsCompiler/Compiler/CompilationLoader.cs +++ b/src/QsCompiler/Compiler/CompilationLoader.cs @@ -151,7 +151,13 @@ public struct Configuration /// However, the compiler may overwrite the assembly constants defined for the Q# compilation unit in the dictionary of the loaded step. /// The given dictionary in this configuration is left unchanged in any case. /// - public IReadOnlyDictionary AssemblyConstants; + public IReadOnlyDictionary AssemblyConstants; + /// + /// Path to the assembly that contains a syntax tree with target specific implementations for certain functions and operations. + /// The functions and operations defined in that assembly replace the ones declarated within the compilation unit. + /// If no path is specified here or the specified path is null then this compilation step is omitted. + /// + public string TargetPackageAssembly; /// /// Indicates whether a serialization of the syntax tree needs to be generated. @@ -190,6 +196,7 @@ private class ExecutionStatus internal Status ReferenceLoading = Status.NotRun; internal Status PluginLoading = Status.NotRun; internal Status Validation = Status.NotRun; + internal Status TargetSpecificReplacements = Status.NotRun; internal Status FunctorSupport = Status.NotRun; internal Status PreEvaluation = Status.NotRun; internal Status TreeTrimming = Status.NotRun; @@ -212,6 +219,7 @@ internal bool Success(Configuration options, bool isExe) => this.ReferenceLoading <= 0 && WasSuccessful(true, this.Validation) && WasSuccessful(true, this.PluginLoading) && + WasSuccessful(!String.IsNullOrWhiteSpace(options.TargetPackageAssembly), this.TargetSpecificReplacements) && WasSuccessful(options.GenerateFunctorSupport, this.FunctorSupport) && WasSuccessful(options.AttemptFullPreEvaluation, this.PreEvaluation) && WasSuccessful(!options.SkipSyntaxTreeTrimming, this.TreeTrimming) && @@ -247,6 +255,12 @@ internal bool Success(Configuration options, bool isExe) => /// public Status Validation => this.CompilationStatus.Validation; /// + /// Indicates whether target specific implementations for functions and operations + /// have been used to replace the ones declarated within the compilation unit. + /// This step is only executed if the specified configuration contains the path to the target package. + /// + public Status TargetSpecificReplacements => this.CompilationStatus.TargetSpecificReplacements; + /// /// Indicates whether all specializations were generated successfully. /// This rewrite step is only executed if the corresponding configuration is specified. /// @@ -414,10 +428,9 @@ public CompilationLoader(SourceLoader loadSources, ReferenceLoader loadReference if (!Uri.TryCreate(Assembly.GetExecutingAssembly().CodeBase, UriKind.Absolute, out Uri thisDllUri)) { thisDllUri = new Uri(Path.GetFullPath(".", "CompilationLoader.cs")); } - QsCompilation ExecuteAsAtomicTransformation(RewriteSteps.LoadedStep rewriteStep, ref Status status) + if (!String.IsNullOrWhiteSpace(this.Config.TargetPackageAssembly)) { - status = this.ExecuteRewriteStep(rewriteStep, this.CompilationOutput, out var transformed); - return status == Status.Succeeded ? transformed : this.CompilationOutput; + this.ReplaceTargetSpecificImplementations(thisDllUri, out this.CompilationOutput); } if (this.Config.ConvertClassicalControl) @@ -508,66 +521,6 @@ QsCompilation ExecuteAsAtomicTransformation(RewriteSteps.LoadedStep rewriteStep, RaiseCompilationTaskEnd(null, "OverallCompilation"); } - /// - /// Executes the given rewrite step on the given compilation, returning a transformed compilation as an out parameter. - /// Catches and logs any thrown exception. Returns the status of the rewrite step. - /// Throws an ArgumentNullException if the rewrite step to execute or the given compilation is null. - /// - private Status ExecuteRewriteStep(RewriteSteps.LoadedStep rewriteStep, QsCompilation compilation, out QsCompilation transformed) - { - if (rewriteStep == null) throw new ArgumentNullException(nameof(rewriteStep)); - if (compilation == null) throw new ArgumentNullException(nameof(compilation)); - - string GetDiagnosticsCode(DiagnosticSeverity severity) => - rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Error ? Errors.Code(ErrorCode.CsharpGenerationGeneratedError) : - rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Warning ? Warnings.Code(WarningCode.CsharpGenerationGeneratedWarning) : - rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Information ? Informations.Code(InformationCode.CsharpGenerationGeneratedInfo) : - null; - - Status LogDiagnostics(Status status = Status.Succeeded) - { - try - { - foreach (var diagnostic in rewriteStep.GeneratedDiagnostics ?? ImmutableArray.Empty) - { this.LogAndUpdate(ref status, RewriteSteps.LoadedStep.ConvertDiagnostic(diagnostic, GetDiagnosticsCode)); } - } - catch { this.LogAndUpdate(ref status, Warning(WarningCode.RewriteStepDiagnosticsGenerationFailed, new[] { rewriteStep.Name })); } - return status; - } - - var status = Status.Succeeded; - var messageSource = ProjectManager.MessageSource(rewriteStep.Origin); - Diagnostic Warning(WarningCode code, params string[] args) => Warnings.LoadWarning(code, args, messageSource); - try - { - transformed = compilation; - var preconditionFailed = rewriteStep.ImplementsPreconditionVerification && !rewriteStep.PreconditionVerification(compilation); - if (preconditionFailed) - { - LogDiagnostics(); - this.LogAndUpdate(ref status, Warning(WarningCode.PreconditionVerificationFailed, new[] { rewriteStep.Name, messageSource })); - return status; - } - - var transformationFailed = rewriteStep.ImplementsTransformation && !rewriteStep.Transformation(compilation, out transformed); - var postconditionFailed = this.Config.EnableAdditionalChecks && rewriteStep.ImplementsPostconditionVerification && !rewriteStep.PostconditionVerification(transformed); - LogDiagnostics(); - - if (transformationFailed) this.LogAndUpdate(ref status, ErrorCode.RewriteStepExecutionFailed, new[] { rewriteStep.Name, messageSource }); - if (postconditionFailed) this.LogAndUpdate(ref status, ErrorCode.PostconditionVerificationFailed, new[] { rewriteStep.Name, messageSource }); - return status; - } - catch (Exception ex) - { - this.LogAndUpdate(ref status, ex); - var isLoadException = ex is FileLoadException || ex.InnerException is FileLoadException; - if (isLoadException) this.LogAndUpdate(ref status, ErrorCode.FileNotFoundDuringPluginExecution, new[] { rewriteStep.Name, messageSource }); - else this.LogAndUpdate(ref status, ErrorCode.PluginExecutionFailed, new[] { rewriteStep.Name, messageSource }); - transformed = null; - } - return status; - } - /// /// Builds the compilation of the specified source files and references, /// executing the compilation steps specified by the given options. @@ -685,6 +638,130 @@ private void PrintLoadedRewriteSteps(IEnumerable rewrit } + // private helper methods used during construction + + /// + /// Raises a compilation task start event. + /// + private void RaiseCompilationTaskStart(string parentTaskName, string taskName) => + CompilationTaskEvent?.Invoke(this, new CompilationTaskEventArgs(CompilationTaskEventType.Start, parentTaskName, taskName)); + + /// + /// Raises a compilation task end event. + /// + private void RaiseCompilationTaskEnd(string parentTaskName, string taskName) => + CompilationTaskEvent?.Invoke(this, new CompilationTaskEventArgs(CompilationTaskEventType.End, parentTaskName, taskName)); + + /// + /// Executes the given rewrite step on the current CompilationOutput, and updates the given status accordingly. + /// Sets the CompilationOutput to the transformed compilation if the status indicates success. + /// + private QsCompilation ExecuteAsAtomicTransformation(RewriteSteps.LoadedStep rewriteStep, ref Status status) + { + status = this.ExecuteRewriteStep(rewriteStep, this.CompilationOutput, out var transformed); + return status == Status.Succeeded ? transformed : this.CompilationOutput; + } + + /// + /// Attempts to load the target package assembly specified in the configuration, + /// logging diagnostics when the loading fails or the corresponding configuration is not specified. + /// Updates the compilation status accordingly. + /// Executes the transformation to replace target specific implementations as atomic rewrite step, + /// returning the transformed compilation as out parameter. + /// Sets the out parameter to the unmodified CompilationOutput if the replacement fails. + /// Returns a boolean value indicating whether the returned compilation has been modified. + /// + private bool ReplaceTargetSpecificImplementations(Uri rewriteStepOrigin, out QsCompilation transformed) + { + try + { + var targetDll = Path.GetFullPath(this.Config.TargetPackageAssembly); + var loaded = AssemblyLoader.LoadReferencedAssembly( + targetDll, + out var targetIntrinsics, + ex => this.LogAndUpdate(ref this.CompilationStatus.TargetSpecificReplacements, ex)); + + if (loaded) + { + var rewriteStep = new RewriteSteps.LoadedStep(new IntrinsicResolution(targetIntrinsics), typeof(IRewriteStep), rewriteStepOrigin); + transformed = ExecuteAsAtomicTransformation(rewriteStep, ref this.CompilationStatus.TargetSpecificReplacements); + return true; + } + else + { + this.LogAndUpdate(ref this.CompilationStatus.TargetSpecificReplacements, ErrorCode.FailedToLoadTargetPackageAssembly, new[] { targetDll }); + } + } + catch (Exception ex) + { + this.LogAndUpdate(ref this.CompilationStatus.TargetSpecificReplacements, ErrorCode.InvalidTargetPackageAssemblyPath, new[] { this.Config.TargetPackageAssembly }); + this.LogAndUpdate(ref this.CompilationStatus.TargetSpecificReplacements, ex); + } + transformed = this.CompilationOutput; + return false; + } + + /// + /// Executes the given rewrite step on the given compilation, returning a transformed compilation as an out parameter. + /// Catches and logs any thrown exception. Returns the status of the rewrite step. + /// Throws an ArgumentNullException if the rewrite step to execute or the given compilation is null. + /// + private Status ExecuteRewriteStep(RewriteSteps.LoadedStep rewriteStep, QsCompilation compilation, out QsCompilation transformed) + { + if (rewriteStep == null) throw new ArgumentNullException(nameof(rewriteStep)); + if (compilation == null) throw new ArgumentNullException(nameof(compilation)); + + string GetDiagnosticsCode(DiagnosticSeverity severity) => + rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Error ? Errors.Code(ErrorCode.CsharpGenerationGeneratedError) : + rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Warning ? Warnings.Code(WarningCode.CsharpGenerationGeneratedWarning) : + rewriteStep.Name == "CsharpGeneration" && severity == DiagnosticSeverity.Information ? Informations.Code(InformationCode.CsharpGenerationGeneratedInfo) : + null; + + Status LogDiagnostics(Status status = Status.Succeeded) + { + try + { + foreach (var diagnostic in rewriteStep.GeneratedDiagnostics ?? ImmutableArray.Empty) + { this.LogAndUpdate(ref status, RewriteSteps.LoadedStep.ConvertDiagnostic(diagnostic, GetDiagnosticsCode)); } + } + catch { this.LogAndUpdate(ref status, Warning(WarningCode.RewriteStepDiagnosticsGenerationFailed, new[] { rewriteStep.Name })); } + return status; + } + + var status = Status.Succeeded; + var messageSource = ProjectManager.MessageSource(rewriteStep.Origin); + Diagnostic Warning(WarningCode code, params string[] args) => Warnings.LoadWarning(code, args, messageSource); + try + { + transformed = compilation; + var preconditionFailed = rewriteStep.ImplementsPreconditionVerification && !rewriteStep.PreconditionVerification(compilation); + if (preconditionFailed) + { + LogDiagnostics(); + this.LogAndUpdate(ref status, Warning(WarningCode.PreconditionVerificationFailed, new[] { rewriteStep.Name, messageSource })); + return status; + } + + var transformationFailed = rewriteStep.ImplementsTransformation && !rewriteStep.Transformation(compilation, out transformed); + var postconditionFailed = this.Config.EnableAdditionalChecks && rewriteStep.ImplementsPostconditionVerification && !rewriteStep.PostconditionVerification(transformed); + LogDiagnostics(); + + if (transformationFailed) this.LogAndUpdate(ref status, ErrorCode.RewriteStepExecutionFailed, new[] { rewriteStep.Name, messageSource }); + if (postconditionFailed) this.LogAndUpdate(ref status, ErrorCode.PostconditionVerificationFailed, new[] { rewriteStep.Name, messageSource }); + return status; + } + catch (Exception ex) + { + this.LogAndUpdate(ref status, ex); + var isLoadException = ex is FileLoadException || ex.InnerException is FileLoadException; + if (isLoadException) this.LogAndUpdate(ref status, ErrorCode.FileNotFoundDuringPluginExecution, new[] { rewriteStep.Name, messageSource }); + else this.LogAndUpdate(ref status, ErrorCode.PluginExecutionFailed, new[] { rewriteStep.Name, messageSource }); + transformed = null; + } + return status; + } + + // routines for loading from and dumping to files /// @@ -909,17 +986,5 @@ string FullDirectoryName(string dir) => File.WriteAllText(targetFile, content); return targetFile; } - - /// - /// Raises a compilation task start event. - /// - private void RaiseCompilationTaskStart (string parentTaskName, string taskName) => - CompilationTaskEvent?.Invoke(this, new CompilationTaskEventArgs(CompilationTaskEventType.Start, parentTaskName, taskName)); - - /// - /// Raises a compilation task end event. - /// - private void RaiseCompilationTaskEnd(string parentTaskName, string taskName) => - CompilationTaskEvent?.Invoke(this, new CompilationTaskEventArgs(CompilationTaskEventType.End, parentTaskName, taskName)); } } diff --git a/src/QsCompiler/Compiler/ExternalRewriteSteps.cs b/src/QsCompiler/Compiler/ExternalRewriteSteps.cs index 07531a5aef..fbbd3925a9 100644 --- a/src/QsCompiler/Compiler/ExternalRewriteSteps.cs +++ b/src/QsCompiler/Compiler/ExternalRewriteSteps.cs @@ -285,9 +285,10 @@ Uri WithFullPath(string file) foreach (var kvPair in config.AssemblyConstants ?? Enumerable.Empty>()) { assemblyConstants[kvPair.Key] = kvPair.Value; } - var defaultOutput = assemblyConstants.TryGetValue(AssemblyConstants.OutputPath, out var path) ? path : null; - assemblyConstants[AssemblyConstants.OutputPath] = outputFolder ?? defaultOutput ?? config.BuildOutputFolder; - assemblyConstants[AssemblyConstants.AssemblyName] = config.ProjectNameWithoutExtension; + // We don't overwrite assembly properties specified by configuration. + var defaultOutput = assemblyConstants.TryGetValue(AssemblyConstants.OutputPath, out var path) ? path : null; + assemblyConstants.TryAdd(AssemblyConstants.OutputPath, outputFolder ?? defaultOutput ?? config.BuildOutputFolder); + assemblyConstants.TryAdd(AssemblyConstants.AssemblyName, config.ProjectNameWithoutExtension); } loadedSteps.Sort((fst, snd) => snd.Priority - fst.Priority); diff --git a/src/QsCompiler/DataStructures/Diagnostics.fs b/src/QsCompiler/DataStructures/Diagnostics.fs index 92bd670a0d..95802c8c8f 100644 --- a/src/QsCompiler/DataStructures/Diagnostics.fs +++ b/src/QsCompiler/DataStructures/Diagnostics.fs @@ -273,7 +273,11 @@ type ErrorCode = | UnknownCompilerPlugin = 7015 | CouldNotLoadCompilerPlugin = 7016 | CouldNotInstantiateRewriteStep = 7017 - | UnexpectedCompilerException = 7018 + | CouldNotFindTargetPackage = 7018 + | CouldNotFindTargetPackageAssembly = 7019 + | InvalidTargetPackageAssemblyPath = 7020 + | FailedToLoadTargetPackageAssembly = 7021 + | UnexpectedCompilerException = 7022 | FunctorGenerationFailed = 7101 | TreeTrimmingFailed = 7102 @@ -289,8 +293,7 @@ type ErrorCode = | PostconditionVerificationFailed = 7113 | CsharpGenerationGeneratedError = 8001 - - | PublishingPerfResultsFailed = 9001 + | PublishingPerfResultsFailed = 8101 type WarningCode = @@ -334,6 +337,7 @@ type WarningCode = | FailedToLoadRewriteStepViaReflection = 7204 | CsharpGenerationGeneratedWarning = 8001 + | InvalidAssemblyProperties = 8101 type InformationCode = @@ -631,7 +635,11 @@ type DiagnosticItem = | ErrorCode.SourceFilesMissing -> "No source files have been specified." | ErrorCode.UnknownCompilerPlugin -> "Could not find the .NET Core library \"{0}\" specifying transformations to perform as part of the compilation process." | ErrorCode.CouldNotLoadCompilerPlugin -> "Unable to load the file \"{0}\" specifying transformations to perform as part of the compilation process. The file needs to be a suitable .NET Core library." - | ErrorCode.CouldNotInstantiateRewriteStep -> "Could not instantiate the type {0} in \"{1}\" specifying a rewrite step. The type may not have a parameterless constructor. " + | ErrorCode.CouldNotInstantiateRewriteStep -> "Could not instantiate the type {0} in \"{1}\" specifying a rewrite step. The type may not have a parameterless constructor." + | ErrorCode.CouldNotFindTargetPackage -> "Could not find the directory \"{0}\" containing target specific information." + | ErrorCode.CouldNotFindTargetPackageAssembly -> "Could not find the assembly specifying target specific implementations within the target package \"{0}\"." + | ErrorCode.InvalidTargetPackageAssemblyPath -> "Could not find the file \"{0}\" that specifies target specific implementations." + | ErrorCode.FailedToLoadTargetPackageAssembly -> "Unable to load target specific implementations from \"{0}\"." | ErrorCode.UnexpectedCompilerException -> "The compiler threw an exception." | ErrorCode.FunctorGenerationFailed -> "Auto-generation of functor specialization(s) failed." @@ -648,8 +656,8 @@ type DiagnosticItem = | ErrorCode.PostconditionVerificationFailed -> "The postcondition for the compilation step \"{0}\" loaded from \"{1}\" was not satisfied. The transformation has produced incorrect output and should be excluded from the compilation process." | ErrorCode.CsharpGenerationGeneratedError -> "" - | ErrorCode.PublishingPerfResultsFailed -> "Performance results failed to be published at \"{0}\"." + | _ -> "" code |> ApplyArguments @@ -695,6 +703,7 @@ type DiagnosticItem = | WarningCode.FailedToLoadRewriteStepViaReflection -> "A possible rewrite step has been detected in \"{0}\". The step could not be loaded and will be ignored." | WarningCode.CsharpGenerationGeneratedWarning -> "" + | WarningCode.InvalidAssemblyProperties -> "Some of the specified assembly properties could not be processed. Either they did not match the expected format, or they duplicate existing ones." | _ -> "" code |> ApplyArguments diff --git a/src/QsCompiler/DocumentationParser/DocComment.cs b/src/QsCompiler/DocumentationParser/DocComment.cs index 0c501cb27b..527ee9a4df 100644 --- a/src/QsCompiler/DocumentationParser/DocComment.cs +++ b/src/QsCompiler/DocumentationParser/DocComment.cs @@ -101,7 +101,7 @@ public class DocComment /// The name of the replacement element for deprecated elements, if given public DocComment(IEnumerable docComments, string name, bool deprecated, string replacement) { - string GetHeadingText(HeadingBlock heading) + static string GetHeadingText(HeadingBlock heading) { var sb = new StringBuilder(); foreach (var item in heading.Inline) @@ -111,7 +111,7 @@ string GetHeadingText(HeadingBlock heading) return sb.ToString(); } - string GetParagraphText(LeafBlock leaf) + static string GetParagraphText(LeafBlock leaf) { var sb = new StringBuilder(); foreach (var item in leaf.Inline) @@ -121,7 +121,7 @@ string GetParagraphText(LeafBlock leaf) return sb.ToString(); } - string ToMarkdown(IEnumerable blocks) + static string ToMarkdown(IEnumerable blocks) { var writer = new StringWriter(); var renderer = new NormalizeRenderer(writer); @@ -136,7 +136,7 @@ string ToMarkdown(IEnumerable blocks) return writer.ToString().TrimEnd().Replace('\n', '\r'); } - List>> BreakIntoSections(IEnumerable blocks, int level) + static List>> BreakIntoSections(IEnumerable blocks, int level) { var key = ""; var accum = new List(); @@ -174,7 +174,7 @@ List>> BreakIntoSections(IEnumerable block return result; } - void ParseListSection(IEnumerable blocks, List accum, bool lowerCase) + static void ParseListSection(IEnumerable blocks, List accum, bool lowerCase) { foreach (var block in blocks) { @@ -202,7 +202,7 @@ void ParseListSection(IEnumerable blocks, List accum, bool lowerC } } - void ParseMapSection(IEnumerable blocks, Dictionary accum) + static void ParseMapSection(IEnumerable blocks, Dictionary accum) { var subsections = BreakIntoSections(blocks, 2); foreach ((var key, var subs) in subsections) @@ -214,7 +214,7 @@ void ParseMapSection(IEnumerable blocks, Dictionary accum } // First element is not matching, second is matching - (List, List) PartitionNestedSection(IEnumerable blocks, int level, string name) + static (List, List) PartitionNestedSection(IEnumerable blocks, int level, string name) { var inMatch = false; var result = (new List(), new List()); diff --git a/src/QsCompiler/Tests.Compiler/CommandLineTests.fs b/src/QsCompiler/Tests.Compiler/CommandLineTests.fs index a880acafb0..4a13ca8592 100644 --- a/src/QsCompiler/Tests.Compiler/CommandLineTests.fs +++ b/src/QsCompiler/Tests.Compiler/CommandLineTests.fs @@ -155,6 +155,31 @@ let ``diagnose outputs`` () = Assert.Equal(ReturnCode.INVALID_ARGUMENTS, result) +[] +let ``options from response files`` () = + let configFile = ("TestCases", "qsc-config.txt") |> Path.Combine + let configArgs = + [| + "-i" + ("TestCases","LinkingTests","Core.qs") |> Path.Combine + ("TestCases","LinkingTests","Diagnostics.qs") |> Path.Combine + |] + File.WriteAllText(configFile, String.Join (" ", configArgs)) + let commandLineArgs = + [| + "build" + "-v" + "Detailed" + "--format" + "MsBuild" + "--response-files" + configFile + |] + + let result = Program.Main commandLineArgs + Assert.Equal(ReturnCode.SUCCESS, result) + + [] let ``generate docs`` () = let docsFolder = ("TestCases", "docs.Out") |> Path.Combine diff --git a/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs b/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs index f4854547f2..1d68db9683 100644 --- a/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs +++ b/src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs @@ -14,7 +14,11 @@ open Xunit.Abstractions type LocalVerificationTests (output:ITestOutputHelper) = - inherit CompilerTests(CompilerTests.Compile "TestCases" ["General.qs"; "LocalVerification.qs"; "Types.qs"; Path.Combine ("LinkingTests", "Core.qs")] [], output) + inherit CompilerTests( + CompilerTests.Compile "TestCases" [ + "General.qs"; "LocalVerification.qs"; "Types.qs"; + Path.Combine ("LinkingTests", "Core.qs"); Path.Combine ("LinkingTests", "Diagnostics.qs") + ] [], output) member private this.Expect name (diag : IEnumerable) = let ns = "Microsoft.Quantum.Testing.LocalVerification" |> NonNullable<_>.New diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/Core.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/Core.qs index 66fe60a6f3..64005ce6d0 100644 --- a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/Core.qs +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/Core.qs @@ -19,9 +19,3 @@ namespace Microsoft.Quantum.Core { } } -namespace Microsoft.Quantum.Diagnostics { - - // needs to be available for testing - @ Attribute() - newtype Test = String; -} \ No newline at end of file diff --git a/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/Diagnostics.qs b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/Diagnostics.qs new file mode 100644 index 0000000000..6a691e0946 --- /dev/null +++ b/src/QsCompiler/Tests.Compiler/TestCases/LinkingTests/Diagnostics.qs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Diagnostics { + + // needs to be available for testing + @ Attribute() + newtype Test = String; +} + diff --git a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj index 4f9d319cbb..879f089a5d 100644 --- a/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj +++ b/src/QsCompiler/Tests.Compiler/Tests.Compiler.fsproj @@ -23,6 +23,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/QuantumSdk/DefaultItems/DefaultItems.targets b/src/QuantumSdk/DefaultItems/DefaultItems.targets index 764107d873..4ba548dd5d 100644 --- a/src/QuantumSdk/DefaultItems/DefaultItems.targets +++ b/src/QuantumSdk/DefaultItems/DefaultItems.targets @@ -9,15 +9,15 @@ - - + + - + QsharpLibrary QsharpExe @@ -25,18 +25,34 @@ Possible values are 'Exe', or 'Library'. - + - QuantumProcessorBackend - SimulatorBackend + HoneywellProcessor + IonQProcessor + QCIProcessor Unspecified - - Possible values are 'QuantumSimulator', 'ToffoliSimulator', 'ResourcesEstimator', or 'QuantumProcessor'. - The execution target for a Q# library needs to be 'Any'. - true + + Possible values are 'Honeywell', 'IonQ', 'QCI', or 'Any'. + The execution target for a Q# library needs to be 'Any'. - + + + OpenQASM + ExtendedQASM + OpenQASM + Default + + + + + QPGen1 + QPGen0 + QPGen1 + Unknown + + + $([System.String]::Copy('$(AssemblyName)').Replace(' ','')) @@ -55,7 +71,28 @@ - + + + + <_TargetPackageReference Include="@(PackageReference)" Condition="@(PackageReference->Count()) > 0 And %(PackageReference.IsTargetPackage)" /> + <_TargetPackageReferencePathProperty Include="@(_TargetPackageReference->'Pkg$([System.String]::Copy('%(_TargetPackageReference.Identity)').Replace('.','_'))')" /> + <_ResolvedTargetPackageReferences Include="$(%(_TargetPackageReferencePathProperty.Identity))" /> + + + + + %(_ResolvedTargetPackageReferences.Identity) + + + + + diff --git a/src/QuantumSdk/Sdk/Sdk.props b/src/QuantumSdk/Sdk/Sdk.props index ba31d6536e..7f9bd490b9 100644 --- a/src/QuantumSdk/Sdk/Sdk.props +++ b/src/QuantumSdk/Sdk/Sdk.props @@ -31,11 +31,14 @@ - + + - + + @@ -64,7 +64,7 @@ - + @@ -73,9 +73,11 @@ <_QscCommandInputFlag Condition="@(QsharpCompile->Count()) > 0">--input "@(QsharpCompile,'" "')" <_QscCommandReferencesFlag Condition="@(ResolvedQsharpReferences->Count()) > 0">--references "@(ResolvedQsharpReferences,'" "')" <_QscCommandLoadFlag Condition="@(_PrioritizedResolvedQscReferences->Count()) > 0">--load "@(_PrioritizedResolvedQscReferences,'" "')" - <_QscCommandTrimFlag Condition="'$(ResolvedQsharpExecutionTarget)' == 'QuantumProcessorBackend'">--trim 2 + <_QscCommandTrimFlag Condition="'$(ResolvedQuantumProcessor)' == 'QPGen1'">--trim 2 + <_QscCommandTargetPackageFlag Condition="'$(ResolvedTargetPackage)' != ''">--target-package "$(ResolvedTargetPackage)" + <_QscCommandAssemblyPropertiesFlag>-p ResolvedExecutionTarget=$(ResolvedQsharpExecutionTarget) $(QscCommandAssemblyProperties) <_QscPackageLoadFallbackFoldersFlag Condition="@(ResolvedPackageLoadFallbackFolders->Count()) > 0">--package-load-fallback-folders "@(ResolvedPackageLoadFallbackFolders,'" "')" - <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandDocsFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandTrimFlag) $(_QscPackageLoadFallbackFoldersFlag) $(AdditionalQscArguments) + <_QscCommandArgs>--proj "$(PathCompatibleAssemblyName)" $(_QscCommandDocsFlag) $(_QscCommandInputFlag) $(_QscCommandOutputFlag) $(_QscCommandReferencesFlag) $(_QscCommandLoadFlag) $(_QscCommandTrimFlag) $(_QscCommandTargetPackageFlag) $(_QscPackageLoadFallbackFoldersFlag) $(_QscCommandAssemblyPropertiesFlag) $(AdditionalQscArguments) <_QscCommandArgsFile>$(QscBuildConfigOutputPath)qsc.rsp $(QscExe) build --format MsBuild $(_VerbosityFlag) --response-files $(_QscCommandArgsFile)