From 92c4b8c1b6a2f32cbb9b0ba55b9a6b55fe2c92d3 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 6 May 2020 13:02:46 -0700 Subject: [PATCH 1/3] Exclude EntryPointDriver.dll from QSC references --- .../Tools/BuildConfiguration/Generate.cs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs b/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs index d4ab25b086..725cc5d974 100644 --- a/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs +++ b/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs @@ -2,15 +2,27 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; namespace Microsoft.Quantum.Sdk.Tools { public static partial class BuildConfiguration { + /// + /// Assembly names that are not compatible with the Q# compiler when loaded as a plugin. + /// + private static readonly IReadOnlyCollection IncompatibleQscReferences = new[] + { + // TODO: This is to work around an assembly that is included with the C# generation package, but which + // shouldn't be loaded as a compiler reference. If the Quantum SDK allows packages to explicitly specify + // which assemblies should be loaded for rewrite steps, instead of loading all of the assemblies in the + // package, then this can be removed. + "Microsoft.Quantum.CsharpGeneration.EntryPointDriver.dll" + }; + /// /// Generates a suitable configuration file for the Q# compiler based on the given options. /// Encountered exceptions are logged to the console, and indicated by the returned status. @@ -31,14 +43,14 @@ public static ReturnCode Generate(Options options) return (path, Int32.TryParse(pieces.Skip(1).SingleOrDefault(), out var priority) ? priority : 0); } - var qscReferences = options.QscReferences?.ToArray() ?? new string[0]; - var orderedQscReferences = new string[0]; + ILookup qscReferences; try { - orderedQscReferences = qscReferences + qscReferences = (options.QscReferences ?? Array.Empty()) .Select(ParseQscReference) .OrderByDescending(qscRef => qscRef.Item2) - .Select(qscRef => qscRef.Item1).ToArray(); + .Select(qscRef => qscRef.Item1) + .ToLookup(qscRef => IncompatibleQscReferences.Contains(Path.GetFileName(qscRef))); } catch (Exception ex) { @@ -49,7 +61,14 @@ public static ReturnCode Generate(Options options) return ReturnCode.INVALID_ARGUMENTS; } - return BuildConfiguration.WriteConfigFile(options.OutputFile, orderedQscReferences, verbose) + var incompatible = qscReferences[true]; + foreach (var reference in incompatible) + { + Console.Error.WriteLine($"Ignored incompatible reference {reference}."); + } + + var compatible = qscReferences[false]; + return WriteConfigFile(options.OutputFile, compatible, verbose) ? ReturnCode.SUCCESS : ReturnCode.IO_EXCEPTION; } @@ -58,7 +77,7 @@ public static ReturnCode Generate(Options options) /// Work in progress: /// The signature and output of this method will change in the future. /// - private static bool WriteConfigFile(string configFile, string[] qscReferences, bool verbose = false) + private static bool WriteConfigFile(string configFile, IEnumerable qscReferences, bool verbose = false) { try { From ba47cbdb8c835cbef9802ad8161959672499e1cf Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 6 May 2020 14:37:14 -0700 Subject: [PATCH 2/3] Show incompatible message only in verbose mode --- .../Tools/BuildConfiguration/Generate.cs | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs b/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs index 725cc5d974..d75671c5ed 100644 --- a/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs +++ b/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs @@ -36,21 +36,12 @@ public static ReturnCode Generate(Options options) "diagnostic".Equals(options.Verbosity, StringComparison.InvariantCultureIgnoreCase) || "diag".Equals(options.Verbosity, StringComparison.InvariantCultureIgnoreCase); - static (string, int) ParseQscReference(string qscRef) - { - var pieces = qscRef.Trim().TrimStart('(').TrimEnd(')').Split(','); - var path = pieces.First().Trim(); - return (path, Int32.TryParse(pieces.Skip(1).SingleOrDefault(), out var priority) ? priority : 0); - } - - ILookup qscReferences; + IEnumerable compatibleQscReferences; + IEnumerable incompatibleQscReferences; try { - qscReferences = (options.QscReferences ?? Array.Empty()) - .Select(ParseQscReference) - .OrderByDescending(qscRef => qscRef.Item2) - .Select(qscRef => qscRef.Item1) - .ToLookup(qscRef => IncompatibleQscReferences.Contains(Path.GetFileName(qscRef))); + (compatibleQscReferences, incompatibleQscReferences) = + ParseQscReferences(options.QscReferences ?? Array.Empty()); } catch (Exception ex) { @@ -61,18 +52,40 @@ public static ReturnCode Generate(Options options) return ReturnCode.INVALID_ARGUMENTS; } - var incompatible = qscReferences[true]; - foreach (var reference in incompatible) + if (verbose) { - Console.Error.WriteLine($"Ignored incompatible reference {reference}."); + foreach (var reference in incompatibleQscReferences) + { + Console.Error.WriteLine($"Skipped incompatible QSC reference: {reference}"); + } } - - var compatible = qscReferences[false]; - return WriteConfigFile(options.OutputFile, compatible, verbose) + return WriteConfigFile(options.OutputFile, compatibleQscReferences, verbose) ? ReturnCode.SUCCESS : ReturnCode.IO_EXCEPTION; } + /// + /// Parses the QSC reference strings in the format "(path, priority)" and partitions them into compatible and + /// incompatible references. + /// + /// The QSC reference strings to parse. + /// A tuple of compatible and incompatible QSC references. + private static (IEnumerable, IEnumerable) ParseQscReferences(IEnumerable qscReferences) + { + static (string, int) ParseQscReference(string qscRef) + { + var pieces = qscRef.Trim().TrimStart('(').TrimEnd(')').Split(','); + var path = pieces.First().Trim(); + return (path, int.TryParse(pieces.Skip(1).SingleOrDefault(), out var priority) ? priority : 0); + } + var compatible = qscReferences + .Select(ParseQscReference) + .OrderByDescending(qscRef => qscRef.Item2) + .Select(qscRef => qscRef.Item1) + .ToLookup(qscRef => !IncompatibleQscReferences.Contains(Path.GetFileName(qscRef))); + return (compatible[true], compatible[false]); + } + /// /// Work in progress: /// The signature and output of this method will change in the future. From dd79b892421b39c225cb104a6d7198b8079d97d0 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 19 May 2020 12:10:53 -0700 Subject: [PATCH 3/3] Update TODO comment with link to issue --- src/QuantumSdk/Tools/BuildConfiguration/Generate.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs b/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs index d75671c5ed..ceec4a43f3 100644 --- a/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs +++ b/src/QuantumSdk/Tools/BuildConfiguration/Generate.cs @@ -17,9 +17,10 @@ public static partial class BuildConfiguration private static readonly IReadOnlyCollection IncompatibleQscReferences = new[] { // TODO: This is to work around an assembly that is included with the C# generation package, but which - // shouldn't be loaded as a compiler reference. If the Quantum SDK allows packages to explicitly specify - // which assemblies should be loaded for rewrite steps, instead of loading all of the assemblies in the - // package, then this can be removed. + // can't be loaded as a compiler reference. If the SDK gains support for packages containing a combination + // of assemblies that can be loaded as rewrite steps and those that can't, this should be removed. + // + // See: https://github.com/microsoft/qsharp-compiler/issues/435 "Microsoft.Quantum.CsharpGeneration.EntryPointDriver.dll" };