From b96039637a991771636b56b85d4d0a4919f8874f Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 10 May 2021 16:36:30 -0700 Subject: [PATCH 01/18] Added command line project --- Simulation.sln | 21 ++- .../CommandLineCompiler.csproj | 13 ++ .../Execution/CommandLineCompiler/Program.cs | 146 ++++++++++++++++++ src/Qir/Execution/Tools/QirTools.cs | 62 +++++--- 4 files changed, 221 insertions(+), 21 deletions(-) create mode 100644 src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj create mode 100644 src/Qir/Execution/CommandLineCompiler/Program.cs diff --git a/Simulation.sln b/Simulation.sln index 1a4a4abbd59..e644f1ebc3a 100644 --- a/Simulation.sln +++ b/Simulation.sln @@ -121,7 +121,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Execution", "Execution", "{ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.Qir.Tools", "src\Qir\Execution\Tools\Microsoft.Quantum.Qir.Tools.csproj", "{C60226E3-98DE-4E92-AED4-B4A93D4CA063}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Microsoft.Quantum.Qir.Tools", "src\Qir\Execution\Tests.Microsoft.Quantum.Qir.Tools\Tests.Microsoft.Quantum.Qir.Tools.csproj", "{4794FC80-4594-403F-AFEC-4889EFE87EA0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Microsoft.Quantum.Qir.Tools", "src\Qir\Execution\Tests.Microsoft.Quantum.Qir.Tools\Tests.Microsoft.Quantum.Qir.Tools.csproj", "{4794FC80-4594-403F-AFEC-4889EFE87EA0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLineCompiler", "src\Qir\Execution\CommandLineCompiler\CommandLineCompiler.csproj", "{F90D680A-376D-439B-99B4-A725A8BDD020}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -807,6 +809,22 @@ Global {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|x64.ActiveCfg = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|x64.Build.0 = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|Any CPU.Build.0 = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|x64.ActiveCfg = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|x64.Build.0 = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -865,6 +883,7 @@ Global {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} = {F6C2D4C0-12DC-40E3-9C86-FA5308D9B567} {C60226E3-98DE-4E92-AED4-B4A93D4CA063} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} {4794FC80-4594-403F-AFEC-4889EFE87EA0} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} + {F90D680A-376D-439B-99B4-A725A8BDD020} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {929C0464-86D8-4F70-8835-0A5EAF930821} diff --git a/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj b/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj new file mode 100644 index 00000000000..eedf09ba173 --- /dev/null +++ b/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + diff --git a/src/Qir/Execution/CommandLineCompiler/Program.cs b/src/Qir/Execution/CommandLineCompiler/Program.cs new file mode 100644 index 00000000000..d349ed94d67 --- /dev/null +++ b/src/Qir/Execution/CommandLineCompiler/Program.cs @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.CommandLine; +using System.CommandLine.Builder; +using System.CommandLine.Help; +using System.CommandLine.Invocation; +using System.CommandLine.Parsing; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Quantum.Qir.Tools; + +namespace CommandLineCompiler +{ + class Program + { + private static async Task Main(string[] args) + { + var buildCommand = CreateBuildCommand(); + + var root = new RootCommand() { buildCommand }; + SetSubCommandAsDefault(root, buildCommand); + root.Description = "Command-line tool for processing QIR DLL files."; + root.TreatUnmatchedTokensAsErrors = true; + + Console.OutputEncoding = Encoding.UTF8; + return await new CommandLineBuilder(root) + .UseDefaults() + .UseHelpBuilder(context => new QsHelpBuilder(context.Console)) + .Build() + .InvokeAsync(args); + } + + /// + /// Creates the Build command for the command line compiler, which is used to + /// compile the executables from a given QIR DLL. + /// + /// The Build command. + private static Command CreateBuildCommand() + { + var buildCommand = new Command("build", "(default) Build the executables from a QIR DLL.") + { + Handler = CommandHandler.Create((BuildOptions settings) => + QirTools.BuildFromQSharpDll(settings.QsharpDll, settings.LibraryDirectory, settings.IncludeDirectory, settings.ExecutablesDirectory)) + }; + buildCommand.TreatUnmatchedTokensAsErrors = true; + + Option qsharpDllOption = new Option( + aliases: new string[] { "--qsharpDll", "--dll" }, + description: "The path to the QIR DLL file that is to be compiled.") + { + Required = true + }; + buildCommand.AddOption(qsharpDllOption); + + Option libraryDirectory = new Option( + aliases: new string[] { "--libraryDirectory", "--lib" }, + description: "The path to the directory containing the required libraries.") + { + Required = true + }; + buildCommand.AddOption(libraryDirectory); + + Option includeDirectory = new Option( + aliases: new string[] { "--includeDirectory", "--include" }, + description: "The path to the directory containing the required resources to be included.") + { + Required = true + }; + buildCommand.AddOption(includeDirectory); + + Option executablesDirectory = new Option( + aliases: new string[] { "--executablesDirectory", "--exe" }, + description: "The path to the output directory where the created executables will be placed.") + { + Required = true + }; + buildCommand.AddOption(executablesDirectory); + + return buildCommand; + } + + /// + /// Copies the handle and options from the given sub command to the given command. + /// + /// The command whose handle and options will be set. + /// The sub command that will be copied from. + private static void SetSubCommandAsDefault(Command root, Command subCommand) + { + root.Handler = subCommand.Handler; + foreach (var option in subCommand.Options) + { + root.AddOption(option); + } + } + + /// + /// A modification of the command-line class. + /// + private sealed class QsHelpBuilder : HelpBuilder + { + /// + /// Creates a new help builder using the given console. + /// + /// The console to use. + internal QsHelpBuilder(IConsole console) : base(console) + { + } + + protected override string ArgumentDescriptor(IArgument argument) + { + // Hide long argument descriptors. + var descriptor = base.ArgumentDescriptor(argument); + return descriptor.Length > 30 ? argument.Name : descriptor; + } + } + + /// + /// A class for encapsulating the different options for the build command. + /// + public sealed class BuildOptions + { + /// + /// The path to the QIR DLL file that is to be compiled. + /// + public FileInfo QsharpDll { get; set; } + + /// + /// The path to the directory containing the required libraries. + /// + public DirectoryInfo LibraryDirectory { get; set; } + + /// + /// The path to the directory containing the required resources to be included. + /// + public DirectoryInfo IncludeDirectory { get; set; } + + /// + /// The path to the output directory where the created executables will be placed. + /// + public DirectoryInfo ExecutablesDirectory { get; set; } + } + } +} diff --git a/src/Qir/Execution/Tools/QirTools.cs b/src/Qir/Execution/Tools/QirTools.cs index e430ce5501b..542cb6053ce 100644 --- a/src/Qir/Execution/Tools/QirTools.cs +++ b/src/Qir/Execution/Tools/QirTools.cs @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Microsoft.Quantum.Qir.Tools.Executable; -using Microsoft.Quantum.QsCompiler; -using Microsoft.Quantum.QsCompiler.QIR; using System; using System.IO; using System.Linq; using System.Threading.Tasks; +using Microsoft.Quantum.Qir.Tools.Executable; +using Microsoft.Quantum.QsCompiler; +using Microsoft.Quantum.QsCompiler.QIR; namespace Microsoft.Quantum.Qir.Tools { @@ -29,27 +29,49 @@ public static async Task BuildFromQSharpDll( DirectoryInfo includeDirectory, DirectoryInfo executablesDirectory) { - using var qirContentStream = new MemoryStream(); - if (!AssemblyLoader.LoadQirByteCode(qsharpDll, qirContentStream)) - { - throw new ArgumentException("The given DLL does not contain QIR byte code."); - } + await Foo(qsharpDll, libraryDirectory, includeDirectory, executablesDirectory); - if (!executablesDirectory.Exists) - { - executablesDirectory.Create(); - } + //using var qirContentStream = new MemoryStream(); + //if (!AssemblyLoader.LoadQirByteCode(qsharpDll, qirContentStream)) + //{ + // throw new ArgumentException("The given DLL does not contain QIR byte code."); + //} + // + //if (!executablesDirectory.Exists) + //{ + // executablesDirectory.Create(); + //} + // + //var tasks = EntryPointOperationLoader.LoadEntryPointOperations(qsharpDll).Select(entryPointOp => + //{ + // var exeFileInfo = new FileInfo(Path.Combine(executablesDirectory.FullName, entryPointOp.Name)); + // var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray()); + // return exe.BuildAsync(entryPointOp, libraryDirectory, includeDirectory); + //}); + // + //await Task.WhenAll(tasks); - var tasks = EntryPointOperationLoader.LoadEntryPointOperations(qsharpDll).Select(entryPointOp => - { - var exeFileInfo = new FileInfo(Path.Combine(executablesDirectory.FullName, entryPointOp.Name)); - var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray()); - return exe.BuildAsync(entryPointOp, libraryDirectory, includeDirectory); - }); + // ToDo: Return list of created file names + } - await Task.WhenAll(tasks); + private static async Task Foo( + FileInfo qsharpDll, + DirectoryInfo libraryDirectory, + DirectoryInfo includeDirectory, + DirectoryInfo executablesDirectory) + { + Console.WriteLine("From BuildFromQSharpDll!"); - // ToDo: Return list of created file names + Console.WriteLine("QsharpDll:"); + Console.WriteLine($"\t{qsharpDll}"); + Console.WriteLine("LibraryDirectory:"); + Console.WriteLine($"\t{libraryDirectory}"); + Console.WriteLine("IncludeDirectory:"); + Console.WriteLine($"\t{includeDirectory}"); + Console.WriteLine("ExecutablesDirectory:"); + Console.WriteLine($"\t{executablesDirectory}"); + + return 0; } } } From daf34782628e929f89b724010dd428b74ebdc5f7 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 11 May 2021 12:24:16 -0700 Subject: [PATCH 02/18] Updates to the project file --- .../Execution/CommandLineCompiler/CommandLineCompiler.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj b/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj index eedf09ba173..fac2a521144 100644 --- a/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj +++ b/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj @@ -3,10 +3,13 @@ Exe netcoreapp3.1 + true + + From f0da336d851c756da673760f36160da4bda8560b Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 11 May 2021 16:16:35 -0700 Subject: [PATCH 03/18] Updated option descriptions, changed includeLibrary to includeLibraries. --- .../Execution/CommandLineCompiler/Program.cs | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Qir/Execution/CommandLineCompiler/Program.cs b/src/Qir/Execution/CommandLineCompiler/Program.cs index d349ed94d67..63e21d73814 100644 --- a/src/Qir/Execution/CommandLineCompiler/Program.cs +++ b/src/Qir/Execution/CommandLineCompiler/Program.cs @@ -43,29 +43,35 @@ private static Command CreateBuildCommand() var buildCommand = new Command("build", "(default) Build the executables from a QIR DLL.") { Handler = CommandHandler.Create((BuildOptions settings) => - QirTools.BuildFromQSharpDll(settings.QsharpDll, settings.LibraryDirectory, settings.IncludeDirectory, settings.ExecutablesDirectory)) + { + if (settings.LibraryDirectories.Length < 1) + { + throw new ArgumentException("The '--libraryDirectories' option requires at least one argument."); + } + return QirTools.BuildFromQSharpDll(settings.QsharpDll, settings.LibraryDirectories[0], settings.IncludeDirectory, settings.ExecutablesDirectory); + }) }; buildCommand.TreatUnmatchedTokensAsErrors = true; Option qsharpDllOption = new Option( aliases: new string[] { "--qsharpDll", "--dll" }, - description: "The path to the QIR DLL file that is to be compiled.") + description: "The path to the .NET DLL file generated by the Q# compiler.") { Required = true }; buildCommand.AddOption(qsharpDllOption); - Option libraryDirectory = new Option( - aliases: new string[] { "--libraryDirectory", "--lib" }, - description: "The path to the directory containing the required libraries.") + Option libraryDirectories = new Option( + aliases: new string[] { "--libraryDirectories", "--lib" }, + description: "One or more paths to the directories containing the libraries to be linked.") { Required = true }; - buildCommand.AddOption(libraryDirectory); + buildCommand.AddOption(libraryDirectories); Option includeDirectory = new Option( aliases: new string[] { "--includeDirectory", "--include" }, - description: "The path to the directory containing the required resources to be included.") + description: "The path to the directory containing the headers required for compilation.") { Required = true }; @@ -123,17 +129,17 @@ protected override string ArgumentDescriptor(IArgument argument) public sealed class BuildOptions { /// - /// The path to the QIR DLL file that is to be compiled. + /// The path to the .NET DLL file generated by the Q# compiler. /// public FileInfo QsharpDll { get; set; } /// - /// The path to the directory containing the required libraries. + /// One or more paths to the directories containing the libraries to be linked. /// - public DirectoryInfo LibraryDirectory { get; set; } + public DirectoryInfo[] LibraryDirectories { get; set; } /// - /// The path to the directory containing the required resources to be included. + /// The path to the directory containing the headers required for compilation. /// public DirectoryInfo IncludeDirectory { get; set; } From 0f96f959fd3742f868e9f1c53b1fb1991adba64d Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 11 May 2021 16:29:25 -0700 Subject: [PATCH 04/18] Package reference instead of project reference --- .../Execution/CommandLineCompiler/CommandLineCompiler.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj b/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj index fac2a521144..9390be958fb 100644 --- a/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj +++ b/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj @@ -10,7 +10,7 @@ - + From 8e6cf604f974e3bbc03a634bfe4c9b9e6f93d089 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 12 May 2021 13:37:16 -0700 Subject: [PATCH 05/18] Changed name and updated version --- Simulation.sln | 36 +++++++++---------- .../Program.cs | 0 .../QirCommandLineTool.csproj} | 6 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) rename src/Qir/Execution/{CommandLineCompiler => QirCommandLineTool}/Program.cs (100%) rename src/Qir/Execution/{CommandLineCompiler/CommandLineCompiler.csproj => QirCommandLineTool/QirCommandLineTool.csproj} (85%) diff --git a/Simulation.sln b/Simulation.sln index e644f1ebc3a..ccb3d0ad3ee 100644 --- a/Simulation.sln +++ b/Simulation.sln @@ -123,7 +123,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Quantum.Qir.Tools EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Microsoft.Quantum.Qir.Tools", "src\Qir\Execution\Tests.Microsoft.Quantum.Qir.Tools\Tests.Microsoft.Quantum.Qir.Tools.csproj", "{4794FC80-4594-403F-AFEC-4889EFE87EA0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLineCompiler", "src\Qir\Execution\CommandLineCompiler\CommandLineCompiler.csproj", "{F90D680A-376D-439B-99B4-A725A8BDD020}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QirCommandLineTool", "src\Qir\Execution\QirCommandLineTool\QirCommandLineTool.csproj", "{039D2649-20F6-46C7-8599-C44F3AA2CD4C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -809,22 +809,22 @@ Global {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {4794FC80-4594-403F-AFEC-4889EFE87EA0}.RelWithDebInfo|x64.Build.0 = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|x64.ActiveCfg = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Debug|x64.Build.0 = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.MinSizeRel|x64.Build.0 = Debug|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|Any CPU.Build.0 = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|x64.ActiveCfg = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.Release|x64.Build.0 = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU - {F90D680A-376D-439B-99B4-A725A8BDD020}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Debug|x64.ActiveCfg = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Debug|x64.Build.0 = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Release|Any CPU.Build.0 = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Release|x64.ActiveCfg = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.Release|x64.Build.0 = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {039D2649-20F6-46C7-8599-C44F3AA2CD4C}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -883,7 +883,7 @@ Global {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} = {F6C2D4C0-12DC-40E3-9C86-FA5308D9B567} {C60226E3-98DE-4E92-AED4-B4A93D4CA063} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} {4794FC80-4594-403F-AFEC-4889EFE87EA0} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} - {F90D680A-376D-439B-99B4-A725A8BDD020} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} + {039D2649-20F6-46C7-8599-C44F3AA2CD4C} = {442E66C8-F69F-44E9-9CD9-1F52C37EA41B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {929C0464-86D8-4F70-8835-0A5EAF930821} diff --git a/src/Qir/Execution/CommandLineCompiler/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs similarity index 100% rename from src/Qir/Execution/CommandLineCompiler/Program.cs rename to src/Qir/Execution/QirCommandLineTool/Program.cs diff --git a/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj similarity index 85% rename from src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj rename to src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj index 9390be958fb..1ddf9a1bf35 100644 --- a/src/Qir/Execution/CommandLineCompiler/CommandLineCompiler.csproj +++ b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj @@ -8,9 +8,9 @@ - - - + + + From 8f4b59645fdb2cb9d4b67d25ca68dff3c83909b6 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 13 May 2021 10:24:36 -0700 Subject: [PATCH 06/18] changes to project file --- .../Execution/QirCommandLineTool/QirCommandLineTool.csproj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj index 1ddf9a1bf35..4d31ebdb94a 100644 --- a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj +++ b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj @@ -3,14 +3,13 @@ Exe netcoreapp3.1 - true - + - + From 42128a7d6d0a0d99a4ed0ccfc24116b8417bedae Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 13 May 2021 12:05:14 -0700 Subject: [PATCH 07/18] made includeDirectories accept multiple arguments --- src/Qir/Execution/QirCommandLineTool/Program.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Qir/Execution/QirCommandLineTool/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs index 63e21d73814..75674d0b807 100644 --- a/src/Qir/Execution/QirCommandLineTool/Program.cs +++ b/src/Qir/Execution/QirCommandLineTool/Program.cs @@ -48,7 +48,11 @@ private static Command CreateBuildCommand() { throw new ArgumentException("The '--libraryDirectories' option requires at least one argument."); } - return QirTools.BuildFromQSharpDll(settings.QsharpDll, settings.LibraryDirectories[0], settings.IncludeDirectory, settings.ExecutablesDirectory); + if (settings.IncludeDirectories.Length < 1) + { + throw new ArgumentException("The '--includeDirectories' option requires at least one argument."); + } + return QirTools.BuildFromQSharpDll(settings.QsharpDll, settings.LibraryDirectories[0], settings.IncludeDirectories[0], settings.ExecutablesDirectory); }) }; buildCommand.TreatUnmatchedTokensAsErrors = true; @@ -69,13 +73,13 @@ private static Command CreateBuildCommand() }; buildCommand.AddOption(libraryDirectories); - Option includeDirectory = new Option( - aliases: new string[] { "--includeDirectory", "--include" }, + Option includeDirectories = new Option( + aliases: new string[] { "--includeDirectories", "--include" }, description: "The path to the directory containing the headers required for compilation.") { Required = true }; - buildCommand.AddOption(includeDirectory); + buildCommand.AddOption(includeDirectories); Option executablesDirectory = new Option( aliases: new string[] { "--executablesDirectory", "--exe" }, @@ -139,9 +143,9 @@ public sealed class BuildOptions public DirectoryInfo[] LibraryDirectories { get; set; } /// - /// The path to the directory containing the headers required for compilation. + /// One or more paths to the directories containing the headers required for compilation. /// - public DirectoryInfo IncludeDirectory { get; set; } + public DirectoryInfo[] IncludeDirectories { get; set; } /// /// The path to the output directory where the created executables will be placed. From eec547b9c8bed76bc66f31cdb6346ebccd185024 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 13 May 2021 14:26:51 -0700 Subject: [PATCH 08/18] minor changes --- .../Execution/QirCommandLineTool/Program.cs | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/Qir/Execution/QirCommandLineTool/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs index 75674d0b807..9edffef231a 100644 --- a/src/Qir/Execution/QirCommandLineTool/Program.cs +++ b/src/Qir/Execution/QirCommandLineTool/Program.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; using Microsoft.Quantum.Qir.Tools; -namespace CommandLineCompiler +namespace Microsoft.Quantum.CommandLineCompiler { class Program { @@ -46,48 +46,44 @@ private static Command CreateBuildCommand() { if (settings.LibraryDirectories.Length < 1) { - throw new ArgumentException("The '--libraryDirectories' option requires at least one argument."); + throw new ArgumentException("The '--library-directories' option requires at least one argument."); } if (settings.IncludeDirectories.Length < 1) { - throw new ArgumentException("The '--includeDirectories' option requires at least one argument."); + throw new ArgumentException("The '--include-directories' option requires at least one argument."); } - return QirTools.BuildFromQSharpDll(settings.QsharpDll, settings.LibraryDirectories[0], settings.IncludeDirectories[0], settings.ExecutablesDirectory); + return QirTools.BuildFromQSharpDll(settings.QSharpDll, settings.LibraryDirectories[0], settings.IncludeDirectories[0], settings.ExecutablesDirectory); }) }; buildCommand.TreatUnmatchedTokensAsErrors = true; - Option qsharpDllOption = new Option( - aliases: new string[] { "--qsharpDll", "--dll" }, + buildCommand.AddOption(new Option( + aliases: new string[] { "--qsharp-dll", "--dll" }, description: "The path to the .NET DLL file generated by the Q# compiler.") { Required = true - }; - buildCommand.AddOption(qsharpDllOption); + }); - Option libraryDirectories = new Option( - aliases: new string[] { "--libraryDirectories", "--lib" }, + buildCommand.AddOption(new Option( + aliases: new string[] { "--library-directories", "--lib" }, description: "One or more paths to the directories containing the libraries to be linked.") { Required = true - }; - buildCommand.AddOption(libraryDirectories); + }); - Option includeDirectories = new Option( - aliases: new string[] { "--includeDirectories", "--include" }, + buildCommand.AddOption(new Option( + aliases: new string[] { "--include-directories", "--include" }, description: "The path to the directory containing the headers required for compilation.") { Required = true - }; - buildCommand.AddOption(includeDirectories); + }); - Option executablesDirectory = new Option( - aliases: new string[] { "--executablesDirectory", "--exe" }, + buildCommand.AddOption(new Option( + aliases: new string[] { "--executables-directory", "--exe" }, description: "The path to the output directory where the created executables will be placed.") { Required = true - }; - buildCommand.AddOption(executablesDirectory); + }); return buildCommand; } @@ -135,7 +131,7 @@ public sealed class BuildOptions /// /// The path to the .NET DLL file generated by the Q# compiler. /// - public FileInfo QsharpDll { get; set; } + public FileInfo QSharpDll { get; set; } /// /// One or more paths to the directories containing the libraries to be linked. From cf0db65bcb3a0f1b35f1e9adfef237b354c43b30 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 17 May 2021 10:07:44 -0700 Subject: [PATCH 09/18] Fixed help for include-directories --- src/Qir/Execution/QirCommandLineTool/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/Execution/QirCommandLineTool/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs index 9edffef231a..f1cd00a415b 100644 --- a/src/Qir/Execution/QirCommandLineTool/Program.cs +++ b/src/Qir/Execution/QirCommandLineTool/Program.cs @@ -73,7 +73,7 @@ private static Command CreateBuildCommand() buildCommand.AddOption(new Option( aliases: new string[] { "--include-directories", "--include" }, - description: "The path to the directory containing the headers required for compilation.") + description: "One or more paths to the directories containing the headers required for compilation.") { Required = true }); From 66f4df393f2d30d28a73ddbb2048c95065459198 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 19 May 2021 12:09:52 -0700 Subject: [PATCH 10/18] updated version, added null checks for logger --- .../QirCommandLineTool.csproj | 2 +- .../Execution/Tools/Executable/ClangClient.cs | 2 +- .../Executable/QirExecutableGenerator.cs | 6 +- src/Qir/Execution/Tools/QirTools.cs | 60 ++++++------------- 4 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj index 4d31ebdb94a..378b1ad4891 100644 --- a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj +++ b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Qir/Execution/Tools/Executable/ClangClient.cs b/src/Qir/Execution/Tools/Executable/ClangClient.cs index 0279e8cdf53..e299a034731 100644 --- a/src/Qir/Execution/Tools/Executable/ClangClient.cs +++ b/src/Qir/Execution/Tools/Executable/ClangClient.cs @@ -25,7 +25,7 @@ public async Task CreateExecutableAsync(string[] inputFiles, string[] libraries, // string.Join does not automatically prepend the delimiter, so it is included again in the string here. var librariesArg = $"{LinkFlag} {string.Join(LinkFlag, libraries)}"; var arguments = $"{inputsArg} -I {includePath} -L {libraryPath} {librariesArg} -o {outputPath} -std=c++17 -v"; - logger.LogInfo($"Invoking clang with the following arguments: {arguments}"); + logger?.LogInfo($"Invoking clang with the following arguments: {arguments}"); var taskCompletionSource = new TaskCompletionSource(); using var process = new Process(); Environment.SetEnvironmentVariable("DYLD_LIBRARY_PATH", libraryPath); diff --git a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs index 80eaf8a768a..342679f739c 100644 --- a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs +++ b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs @@ -26,11 +26,11 @@ public async Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo await Task.Run(async () => { var binDirectory = executableFile.Directory; - logger.LogInfo($"Creating binary directory at {binDirectory.FullName}."); + logger?.LogInfo($"Creating binary directory at {binDirectory.FullName}."); executableFile.Directory.Create(); // Copy all library contents to bin. - logger.LogInfo("Copying library directory contents into the executable's folder."); + logger?.LogInfo("Copying library directory contents into the executable's folder."); var libraryFiles = libraryDirectory.GetFiles(); foreach (var file in libraryFiles) { @@ -48,7 +48,7 @@ private void CopyFileIfNotExists(FileInfo fileToCopy, DirectoryInfo destinationD if (!File.Exists(newPath)) { var newFile = fileToCopy.CopyTo(newPath); - logger.LogInfo($"Copied file {fileToCopy.FullName} to {newFile.FullName}"); + logger?.LogInfo($"Copied file {fileToCopy.FullName} to {newFile.FullName}"); } } } diff --git a/src/Qir/Execution/Tools/QirTools.cs b/src/Qir/Execution/Tools/QirTools.cs index 542cb6053ce..1aaf8860070 100644 --- a/src/Qir/Execution/Tools/QirTools.cs +++ b/src/Qir/Execution/Tools/QirTools.cs @@ -29,49 +29,27 @@ public static async Task BuildFromQSharpDll( DirectoryInfo includeDirectory, DirectoryInfo executablesDirectory) { - await Foo(qsharpDll, libraryDirectory, includeDirectory, executablesDirectory); - - //using var qirContentStream = new MemoryStream(); - //if (!AssemblyLoader.LoadQirByteCode(qsharpDll, qirContentStream)) - //{ - // throw new ArgumentException("The given DLL does not contain QIR byte code."); - //} - // - //if (!executablesDirectory.Exists) - //{ - // executablesDirectory.Create(); - //} - // - //var tasks = EntryPointOperationLoader.LoadEntryPointOperations(qsharpDll).Select(entryPointOp => - //{ - // var exeFileInfo = new FileInfo(Path.Combine(executablesDirectory.FullName, entryPointOp.Name)); - // var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray()); - // return exe.BuildAsync(entryPointOp, libraryDirectory, includeDirectory); - //}); - // - //await Task.WhenAll(tasks); + using var qirContentStream = new MemoryStream(); + if (!AssemblyLoader.LoadQirByteCode(qsharpDll, qirContentStream)) + { + throw new ArgumentException("The given DLL does not contain QIR byte code."); + } + + if (!executablesDirectory.Exists) + { + executablesDirectory.Create(); + } + + var tasks = EntryPointOperationLoader.LoadEntryPointOperations(qsharpDll).Select(entryPointOp => + { + var exeFileInfo = new FileInfo(Path.Combine(executablesDirectory.FullName, $"{entryPointOp.Name}.exe")); + var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray()); + return exe.BuildAsync(entryPointOp, libraryDirectory, includeDirectory); + }); + + await Task.WhenAll(tasks); // ToDo: Return list of created file names } - - private static async Task Foo( - FileInfo qsharpDll, - DirectoryInfo libraryDirectory, - DirectoryInfo includeDirectory, - DirectoryInfo executablesDirectory) - { - Console.WriteLine("From BuildFromQSharpDll!"); - - Console.WriteLine("QsharpDll:"); - Console.WriteLine($"\t{qsharpDll}"); - Console.WriteLine("LibraryDirectory:"); - Console.WriteLine($"\t{libraryDirectory}"); - Console.WriteLine("IncludeDirectory:"); - Console.WriteLine($"\t{includeDirectory}"); - Console.WriteLine("ExecutablesDirectory:"); - Console.WriteLine($"\t{executablesDirectory}"); - - return 0; - } } } From 5c1158af16929476007d63b7603392665be64ce3 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Mon, 24 May 2021 12:41:49 -0700 Subject: [PATCH 11/18] remove package reference to runtime --- src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj index 378b1ad4891..c66190b50aa 100644 --- a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj +++ b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj @@ -8,7 +8,6 @@ - From c35834dd8aebd9572d8b1fb1ad789e43932d7211 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Tue, 25 May 2021 11:32:13 -0700 Subject: [PATCH 12/18] Added PackAsTool --- src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj index c66190b50aa..868df199d12 100644 --- a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj +++ b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj @@ -3,6 +3,7 @@ Exe netcoreapp3.1 + true From 2dda01541f0b4f014accc515d5e290682fd59519 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 26 May 2021 16:23:02 -0700 Subject: [PATCH 13/18] Allow for multiple library and include paths --- .../Execution/QirCommandLineTool/Program.cs | 2 +- .../Execution/Tools/Executable/ClangClient.cs | 26 +++++++++++++++---- .../Tools/Executable/IClangClient.cs | 2 +- .../Tools/Executable/IQirExecutable.cs | 7 ++--- .../Executable/IQirExecutableGenerator.cs | 6 ++--- .../Tools/Executable/QirExecutable.cs | 4 +-- .../Executable/QirExecutableGenerator.cs | 24 ++++++++++++----- src/Qir/Execution/Tools/QirTools.cs | 11 ++++---- 8 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/Qir/Execution/QirCommandLineTool/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs index f1cd00a415b..10e4ce9ce1c 100644 --- a/src/Qir/Execution/QirCommandLineTool/Program.cs +++ b/src/Qir/Execution/QirCommandLineTool/Program.cs @@ -52,7 +52,7 @@ private static Command CreateBuildCommand() { throw new ArgumentException("The '--include-directories' option requires at least one argument."); } - return QirTools.BuildFromQSharpDll(settings.QSharpDll, settings.LibraryDirectories[0], settings.IncludeDirectories[0], settings.ExecutablesDirectory); + return QirTools.BuildFromQSharpDll(settings.QSharpDll, settings.LibraryDirectories, settings.IncludeDirectories, settings.ExecutablesDirectory); }) }; buildCommand.TreatUnmatchedTokensAsErrors = true; diff --git a/src/Qir/Execution/Tools/Executable/ClangClient.cs b/src/Qir/Execution/Tools/Executable/ClangClient.cs index e299a034731..a8e74f2a404 100644 --- a/src/Qir/Execution/Tools/Executable/ClangClient.cs +++ b/src/Qir/Execution/Tools/Executable/ClangClient.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.IO; using System.Threading.Tasks; using Microsoft.Quantum.Qir.Utility; @@ -11,6 +12,8 @@ namespace Microsoft.Quantum.Qir.Tools.Executable internal class ClangClient : IClangClient { private const string LinkFlag = " -l "; + private const string LibraryPathFlag = " -L "; + private const string IncludePathFlag = " -I "; private readonly ILogger logger; public ClangClient(ILogger logger) @@ -18,18 +21,20 @@ public ClangClient(ILogger logger) this.logger = logger; } - public async Task CreateExecutableAsync(string[] inputFiles, string[] libraries, string libraryPath, string includePath, string outputPath) + public async Task CreateExecutableAsync(string[] inputFiles, string[] linkedLibraries, string[] libraryPaths, string[] includePaths, string outputPath) { var inputsArg = string.Join(' ', inputFiles); // string.Join does not automatically prepend the delimiter, so it is included again in the string here. - var librariesArg = $"{LinkFlag} {string.Join(LinkFlag, libraries)}"; - var arguments = $"{inputsArg} -I {includePath} -L {libraryPath} {librariesArg} -o {outputPath} -std=c++17 -v"; + var linkedLibrariesArg = $"{LinkFlag} {string.Join(LinkFlag, linkedLibraries)}"; + var libraryPathsArg = $"{LibraryPathFlag} {string.Join(LibraryPathFlag, libraryPaths)}"; + var includePathsArg = $"{IncludePathFlag} {string.Join(IncludePathFlag, includePaths)}"; + var arguments = $"{inputsArg} {includePathsArg} {libraryPathsArg} {linkedLibrariesArg} -o {outputPath} -std=c++17 -v"; logger?.LogInfo($"Invoking clang with the following arguments: {arguments}"); var taskCompletionSource = new TaskCompletionSource(); using var process = new Process(); - Environment.SetEnvironmentVariable("DYLD_LIBRARY_PATH", libraryPath); - Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", libraryPath); + AddPathsToEnvironmentVariable("DYLD_LIBRARY_PATH", libraryPaths); + AddPathsToEnvironmentVariable("LD_LIBRARY_PATH", libraryPaths); process.StartInfo = new ProcessStartInfo { FileName = "clang++", @@ -40,5 +45,16 @@ public async Task CreateExecutableAsync(string[] inputFiles, string[] libraries, process.Start(); await taskCompletionSource.Task; } + + private static void AddPathsToEnvironmentVariable(string variable, string[] values) + { + var newValue = string.Join(Path.PathSeparator, values); + var oldValue = Environment.GetEnvironmentVariable(variable); + if (oldValue != null) + { + newValue = oldValue + $"{Path.PathSeparator}{newValue}"; + } + Environment.SetEnvironmentVariable(variable, newValue); + } } } diff --git a/src/Qir/Execution/Tools/Executable/IClangClient.cs b/src/Qir/Execution/Tools/Executable/IClangClient.cs index f5a1bb38135..87423492187 100644 --- a/src/Qir/Execution/Tools/Executable/IClangClient.cs +++ b/src/Qir/Execution/Tools/Executable/IClangClient.cs @@ -10,6 +10,6 @@ namespace Microsoft.Quantum.Qir.Tools.Executable /// internal interface IClangClient { - Task CreateExecutableAsync(string[] inputFiles, string[] libraries, string libraryPath, string includePath, string outputPath); + Task CreateExecutableAsync(string[] inputFiles, string[] linkedLibraries, string[] libraryPaths, string[] includePaths, string outputPath); } } diff --git a/src/Qir/Execution/Tools/Executable/IQirExecutable.cs b/src/Qir/Execution/Tools/Executable/IQirExecutable.cs index 477dd2cfe2a..e3ad50a6fcb 100644 --- a/src/Qir/Execution/Tools/Executable/IQirExecutable.cs +++ b/src/Qir/Execution/Tools/Executable/IQirExecutable.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.Quantum.Qir.Serialization; @@ -13,10 +14,10 @@ public interface IQirExecutable /// Builds the executable. /// /// Entry point operation. - /// Directory containing libraries to link. - /// Directory containing files to include. + /// Directories containing libraries to link. + /// Directories containing files to include. /// - Task BuildAsync(EntryPointOperation entryPoint, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory); + Task BuildAsync(EntryPointOperation entryPoint, IList libraryDirectories, IList includeDirectories); /// /// Runs the executable. diff --git a/src/Qir/Execution/Tools/Executable/IQirExecutableGenerator.cs b/src/Qir/Execution/Tools/Executable/IQirExecutableGenerator.cs index 3ddb310f98e..3715a8fed2e 100644 --- a/src/Qir/Execution/Tools/Executable/IQirExecutableGenerator.cs +++ b/src/Qir/Execution/Tools/Executable/IQirExecutableGenerator.cs @@ -14,10 +14,10 @@ internal interface IQirExecutableGenerator /// /// File path to create the executable at. Dependencies will be copied to its directory. /// Location of the source files. - /// Location of the libraries that must be linked. - /// Location of the headers that must be included. + /// Locations of the libraries that must be linked. + /// Locations of the headers that must be included. /// Libraries to link. /// - public Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory, IList linkLibraries); + public Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, IList libraryDirectories, IList includeDirectories, IList linkLibraries); } } diff --git a/src/Qir/Execution/Tools/Executable/QirExecutable.cs b/src/Qir/Execution/Tools/Executable/QirExecutable.cs index 4c6f73c7d2d..9aa7d671b8a 100644 --- a/src/Qir/Execution/Tools/Executable/QirExecutable.cs +++ b/src/Qir/Execution/Tools/Executable/QirExecutable.cs @@ -49,7 +49,7 @@ internal QirExecutable(FileInfo executableFile, byte[] qirBytecode, ILogger logg this.executableGenerator = executableGenerator; } - public async Task BuildAsync(EntryPointOperation entryPoint, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory) + public async Task BuildAsync(EntryPointOperation entryPoint, IList libraryDirectories, IList includeDirectories) { var sourceDirectory = new DirectoryInfo(SourceDirectoryPath); if (sourceDirectory.Exists) @@ -77,7 +77,7 @@ public async Task BuildAsync(EntryPointOperation entryPoint, DirectoryInfo libra } logger.LogInfo($"Created bytecode file at {bytecodeFile.FullName}."); - await executableGenerator.GenerateExecutableAsync(ExecutableFile, sourceDirectory, libraryDirectory, includeDirectory, LinkLibraries); + await executableGenerator.GenerateExecutableAsync(ExecutableFile, sourceDirectory, libraryDirectories, includeDirectories, LinkLibraries); } public async Task RunAsync(ExecutionInformation executionInformation, Stream output) diff --git a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs index 342679f739c..adde46e33d4 100644 --- a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs +++ b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs @@ -20,7 +20,7 @@ public QirExecutableGenerator(IClangClient clangClient, ILogger logger) this.logger = logger; } - public async Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory, IList linkLibraries) + public async Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, IList libraryDirectories, IList includeDirectories, IList linkLibraries) { // Wrap in a Task.Run because FileInfo methods are not asynchronous. await Task.Run(async () => @@ -30,15 +30,15 @@ await Task.Run(async () => executableFile.Directory.Create(); // Copy all library contents to bin. - logger?.LogInfo("Copying library directory contents into the executable's folder."); - var libraryFiles = libraryDirectory.GetFiles(); - foreach (var file in libraryFiles) + logger?.LogInfo("Copying library directories into the executable's folder."); + + foreach (var dir in libraryDirectories) { - CopyFileIfNotExists(file, binDirectory); + CopyDirectoryIfNotExists(dir, binDirectory); } var inputFiles = sourceDirectory.GetFiles().Select(fileInfo => fileInfo.FullName).ToArray(); - await clangClient.CreateExecutableAsync(inputFiles, linkLibraries.ToArray(), libraryDirectory.FullName, includeDirectory.FullName, executableFile.FullName); + await clangClient.CreateExecutableAsync(inputFiles, linkLibraries.ToArray(), libraryDirectories.Select(dir => dir.FullName).ToArray(), includeDirectories.Select(dir => dir.FullName).ToArray(), executableFile.FullName); }); } @@ -51,5 +51,17 @@ private void CopyFileIfNotExists(FileInfo fileToCopy, DirectoryInfo destinationD logger?.LogInfo($"Copied file {fileToCopy.FullName} to {newFile.FullName}"); } } + + private void CopyDirectoryIfNotExists(DirectoryInfo directoryToCopy, DirectoryInfo destinationDirectory) + { + var newPath = Path.Combine(destinationDirectory.FullName, directoryToCopy.Name); + var newDir = Directory.CreateDirectory(newPath); + + FileInfo[] files = directoryToCopy.GetFiles(); + foreach (var file in files) + { + CopyFileIfNotExists(file, newDir); + } + } } } diff --git a/src/Qir/Execution/Tools/QirTools.cs b/src/Qir/Execution/Tools/QirTools.cs index 1aaf8860070..b79c73072bb 100644 --- a/src/Qir/Execution/Tools/QirTools.cs +++ b/src/Qir/Execution/Tools/QirTools.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -20,13 +21,13 @@ public static class QirTools /// Creates a QIR-based executable from a .NET DLL generated by the Q# compiler. /// /// .NET DLL generated by the Q# compiler. - /// Directory where the libraries to link to are located. - /// Directory where the headers needed for compilation are located. + /// Directory where the libraries to link to are located. + /// Directory where the headers needed for compilation are located. /// Directory where the created executables are placed. public static async Task BuildFromQSharpDll( FileInfo qsharpDll, - DirectoryInfo libraryDirectory, - DirectoryInfo includeDirectory, + IList libraryDirectories, + IList includeDirectories, DirectoryInfo executablesDirectory) { using var qirContentStream = new MemoryStream(); @@ -44,7 +45,7 @@ public static async Task BuildFromQSharpDll( { var exeFileInfo = new FileInfo(Path.Combine(executablesDirectory.FullName, $"{entryPointOp.Name}.exe")); var exe = new QirFullStateExecutable(exeFileInfo, qirContentStream.ToArray()); - return exe.BuildAsync(entryPointOp, libraryDirectory, includeDirectory); + return exe.BuildAsync(entryPointOp, libraryDirectories, includeDirectories); }); await Task.WhenAll(tasks); From b30a174483fe4ba217043b8e327f59d15d1eae6e Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Wed, 26 May 2021 17:10:16 -0700 Subject: [PATCH 14/18] Make headers and libraries arguments optional --- src/Qir/Execution/QirCommandLineTool/Program.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Qir/Execution/QirCommandLineTool/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs index 10e4ce9ce1c..a2735863351 100644 --- a/src/Qir/Execution/QirCommandLineTool/Program.cs +++ b/src/Qir/Execution/QirCommandLineTool/Program.cs @@ -68,14 +68,22 @@ private static Command CreateBuildCommand() aliases: new string[] { "--library-directories", "--lib" }, description: "One or more paths to the directories containing the libraries to be linked.") { - Required = true + Required = false, + Argument = new Argument(() => new DirectoryInfo[] { }) + { + Arity = ArgumentArity.OneOrMore + } }); buildCommand.AddOption(new Option( aliases: new string[] { "--include-directories", "--include" }, description: "One or more paths to the directories containing the headers required for compilation.") { - Required = true + Required = false, + Argument = new Argument(() => new DirectoryInfo[] { }) + { + Arity = ArgumentArity.OneOrMore + } }); buildCommand.AddOption(new Option( From 589d268857ff42cb569a7c5570812d72b6ecde0e Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 27 May 2021 11:00:57 -0700 Subject: [PATCH 15/18] fixed tests --- .../QirExecutableGeneratorTests.cs | 6 +++--- .../Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableGeneratorTests.cs b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableGeneratorTests.cs index b110c59df65..fd88b7550f6 100644 --- a/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableGeneratorTests.cs +++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableGeneratorTests.cs @@ -65,14 +65,14 @@ public void Dispose() public async Task TestGenerateExecutable() { var executableFile = new FileInfo(Path.Combine(binDirectory.FullName, "executableFile")); - await executableGenerator.GenerateExecutableAsync(executableFile, sourceDirectory, libraryDirectory, includeDirectory, linkLibraries); + await executableGenerator.GenerateExecutableAsync(executableFile, sourceDirectory, new[] { libraryDirectory }, new[] { includeDirectory }, linkLibraries); // Verify invocation of clang. clangClientMock.Verify(obj => obj.CreateExecutableAsync( It.Is(s => s.OrderBy(val => val).SequenceEqual(sourceFiles.OrderBy(val => val.FullName).Select(fileInfo => fileInfo.FullName))), It.Is(s => s.OrderBy(val => val).SequenceEqual(linkLibraries.OrderBy(val => val))), - libraryDirectory.FullName, - includeDirectory.FullName, + new[] { libraryDirectory.FullName }, + new[] { includeDirectory.FullName }, executableFile.FullName)); // Verify files were copied. diff --git a/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs index 8c3b469c2a5..61750a83d5c 100644 --- a/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs +++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs @@ -72,7 +72,7 @@ public async Task TestBuild() }); // Build the executable. - await qirExecutable.Object.BuildAsync(entryPoint, libraryDirectory, includeDirectory); + await qirExecutable.Object.BuildAsync(entryPoint, new[] { libraryDirectory }, new[] { includeDirectory }); // Verify that the "bytecode" file was created correctly. var bytecodeFilePath = new FileInfo(Path.Combine(sourceDirectory.FullName, "qir.bc")); @@ -90,7 +90,7 @@ public async Task TestBuild() Assert.Equal(driverFileContents, actualDriverContents); // Verify that the executable was generated. - executableGeneratorMock.Verify(obj => obj.GenerateExecutableAsync(executableFile, It.Is(arg => arg.FullName == sourceDirectory.FullName), libraryDirectory, includeDirectory, linkLibraries)); + executableGeneratorMock.Verify(obj => obj.GenerateExecutableAsync(executableFile, It.Is(arg => arg.FullName == sourceDirectory.FullName), new[] { libraryDirectory }, new[] { includeDirectory }, linkLibraries)); } [Fact] From 0f37043f036d7b24aa3b1de58f6b379775d72bdb Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 27 May 2021 13:25:40 -0700 Subject: [PATCH 16/18] fixed API call in controller --- src/Qir/Controller/Controller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/Controller/Controller.cs b/src/Qir/Controller/Controller.cs index 1ae7e6a747c..93b8b38a8bd 100644 --- a/src/Qir/Controller/Controller.cs +++ b/src/Qir/Controller/Controller.cs @@ -41,7 +41,7 @@ public static async Task ExecuteAsync( var bytecodeArray = input.QirBytecode.Array.Skip(input.QirBytecode.Offset).Take(input.QirBytecode.Count).ToList().ToArray(); var executableFile = new FileInfo(Path.Combine(BinaryDirectoryPath, ExecutableName)); var executable = new QirFullStateExecutable(executableFile, bytecodeArray, logger); - await executable.BuildAsync(executionInfo.EntryPoint, libraryDirectory, includeDirectory); + await executable.BuildAsync(executionInfo.EntryPoint, new[] { libraryDirectory }, new[] { includeDirectory }); // Step 3: Run executable. if (outputFile.Exists) From 18ca27e36e04549bbd8c76dc781c17507de3fbf7 Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 27 May 2021 13:26:47 -0700 Subject: [PATCH 17/18] removed unnecessary checks --- src/Qir/Execution/QirCommandLineTool/Program.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Qir/Execution/QirCommandLineTool/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs index a2735863351..760788508e7 100644 --- a/src/Qir/Execution/QirCommandLineTool/Program.cs +++ b/src/Qir/Execution/QirCommandLineTool/Program.cs @@ -44,14 +44,6 @@ private static Command CreateBuildCommand() { Handler = CommandHandler.Create((BuildOptions settings) => { - if (settings.LibraryDirectories.Length < 1) - { - throw new ArgumentException("The '--library-directories' option requires at least one argument."); - } - if (settings.IncludeDirectories.Length < 1) - { - throw new ArgumentException("The '--include-directories' option requires at least one argument."); - } return QirTools.BuildFromQSharpDll(settings.QSharpDll, settings.LibraryDirectories, settings.IncludeDirectories, settings.ExecutablesDirectory); }) }; From 9d7fbb6af87ff6d0078f68cc9c1f4543d1f6690c Mon Sep 17 00:00:00 2001 From: Scott Carda Date: Thu, 27 May 2021 13:49:06 -0700 Subject: [PATCH 18/18] make output folder flat --- .../Execution/Tools/Executable/QirExecutableGenerator.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs index adde46e33d4..3201adeebe1 100644 --- a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs +++ b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs @@ -34,7 +34,7 @@ await Task.Run(async () => foreach (var dir in libraryDirectories) { - CopyDirectoryIfNotExists(dir, binDirectory); + CopyDirectoryContents(dir, binDirectory); } var inputFiles = sourceDirectory.GetFiles().Select(fileInfo => fileInfo.FullName).ToArray(); @@ -52,15 +52,12 @@ private void CopyFileIfNotExists(FileInfo fileToCopy, DirectoryInfo destinationD } } - private void CopyDirectoryIfNotExists(DirectoryInfo directoryToCopy, DirectoryInfo destinationDirectory) + private void CopyDirectoryContents(DirectoryInfo directoryToCopy, DirectoryInfo destinationDirectory) { - var newPath = Path.Combine(destinationDirectory.FullName, directoryToCopy.Name); - var newDir = Directory.CreateDirectory(newPath); - FileInfo[] files = directoryToCopy.GetFiles(); foreach (var file in files) { - CopyFileIfNotExists(file, newDir); + CopyFileIfNotExists(file, destinationDirectory); } } }