diff --git a/src/Qir/Execution/QirCommandLineTool/Program.cs b/src/Qir/Execution/QirCommandLineTool/Program.cs index 760788508e7..6bdeb704674 100644 --- a/src/Qir/Execution/QirCommandLineTool/Program.cs +++ b/src/Qir/Execution/QirCommandLineTool/Program.cs @@ -43,9 +43,7 @@ private static Command CreateBuildCommand() var buildCommand = new Command("build", "(default) Build the executables from a QIR DLL.") { Handler = CommandHandler.Create((BuildOptions settings) => - { - return QirTools.BuildFromQSharpDll(settings.QSharpDll, settings.LibraryDirectories, settings.IncludeDirectories, settings.ExecutablesDirectory); - }) + QirTools.BuildFromQSharpDll(settings.QSharpDll, settings.LibraryDirectories, settings.IncludeDirectories, settings.ExecutablesDirectory)) }; buildCommand.TreatUnmatchedTokensAsErrors = true; diff --git a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj index 868df199d12..bbbd132751f 100644 --- a/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj +++ b/src/Qir/Execution/QirCommandLineTool/QirCommandLineTool.csproj @@ -1,5 +1,5 @@ - - + + Exe netcoreapp3.1 @@ -7,9 +7,8 @@ - - - + + 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 61750a83d5c..292f1e7d3d9 100644 --- a/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs +++ b/src/Qir/Execution/Tests.Microsoft.Quantum.Qir.Tools/QirExecutableTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using Microsoft.Quantum.Qir.Serialization; using Microsoft.Quantum.Qir.Tools.Driver; @@ -27,6 +28,8 @@ public class QirExecutableTests : IDisposable private readonly FileInfo executableFile; private readonly byte[] qirBytecode = { 1, 2, 3, 4, 5 }; private readonly IList linkLibraries; + private readonly IList headerDirectories; + private readonly IList libraryDirectories; public QirExecutableTests() { @@ -46,9 +49,13 @@ public QirExecutableTests() runnerMock = new Mock(); qirExecutable = new Mock(executableFile, qirBytecode, Mock.Of(), driverGeneratorMock.Object, executableGeneratorMock.Object, runnerMock.Object) { CallBase = true }; linkLibraries = new List { "lib1", "lib2" }; + headerDirectories = new List(); + libraryDirectories = new List(); qirExecutable.SetupGet(obj => obj.LinkLibraries).Returns(linkLibraries); qirExecutable.SetupGet(obj => obj.SourceDirectoryPath).Returns(sourceDirectory.FullName); qirExecutable.SetupGet(obj => obj.DriverFileExtension).Returns(".cpp"); + qirExecutable.SetupGet(obj => obj.HeaderDirectories).Returns(headerDirectories); + qirExecutable.SetupGet(obj => obj.LibraryDirectories).Returns(libraryDirectories); } public void Dispose() diff --git a/src/Qir/Execution/Tools/Executable/QirExecutable.cs b/src/Qir/Execution/Tools/Executable/QirExecutable.cs index 9aa7d671b8a..a962aa46a76 100644 --- a/src/Qir/Execution/Tools/Executable/QirExecutable.cs +++ b/src/Qir/Execution/Tools/Executable/QirExecutable.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using Microsoft.Quantum.Qir.Serialization; using Microsoft.Quantum.Qir.Tools.Driver; @@ -20,6 +21,9 @@ public abstract class QirExecutable : IQirExecutable public virtual string SourceDirectoryPath => "src"; public abstract string DriverFileExtension { get; } + public abstract IList LinkLibraries { get; } + public abstract IList HeaderDirectories { get; } + public abstract IList LibraryDirectories { get; } protected FileInfo ExecutableFile { get; } @@ -76,8 +80,7 @@ public async Task BuildAsync(EntryPointOperation entryPoint, IList LinkLibraries { get; } } } diff --git a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs index 3201adeebe1..d95b80cafe5 100644 --- a/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs +++ b/src/Qir/Execution/Tools/Executable/QirExecutableGenerator.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -32,13 +33,40 @@ await Task.Run(async () => // Copy all library contents to bin. logger?.LogInfo("Copying library directories into the executable's folder."); + if (!sourceDirectory.Exists) + { + logger?.LogWarning($"Cannot find source directory: {sourceDirectory.FullName}"); + } + + var libDirs = new List(); foreach (var dir in libraryDirectories) { - CopyDirectoryContents(dir, binDirectory); + if (!dir.Exists) + { + logger?.LogWarning($"Cannot find given directory: {dir.FullName}"); + } + else + { + CopyDirectoryContents(dir, binDirectory); + libDirs.Add(dir.FullName); + } + } + + var includeDirs = new List(); + foreach (var dir in includeDirectories) + { + if (!dir.Exists) + { + logger?.LogWarning($"Could not find given directory: {dir.FullName}"); + } + else + { + includeDirs.Add(dir.FullName); + } } var inputFiles = sourceDirectory.GetFiles().Select(fileInfo => fileInfo.FullName).ToArray(); - await clangClient.CreateExecutableAsync(inputFiles, linkLibraries.ToArray(), libraryDirectories.Select(dir => dir.FullName).ToArray(), includeDirectories.Select(dir => dir.FullName).ToArray(), executableFile.FullName); + await clangClient.CreateExecutableAsync(inputFiles, linkLibraries.ToArray(), libDirs.ToArray(), includeDirs.ToArray(), executableFile.FullName); }); } diff --git a/src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs b/src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs index 03362d370a6..de394c70e0f 100644 --- a/src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs +++ b/src/Qir/Execution/Tools/Executable/QirFullStateExecutable.cs @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; using Microsoft.Quantum.Qir.Tools.Driver; using Microsoft.Quantum.Qir.Utility; @@ -13,20 +16,40 @@ namespace Microsoft.Quantum.Qir.Tools.Executable /// public class QirFullStateExecutable : QirExecutable { + public override string DriverFileExtension => "cpp"; + + public override IList LinkLibraries => new List { + "Microsoft.Quantum.Qir.Runtime", + "Microsoft.Quantum.Qir.QSharp.Foundation", + "Microsoft.Quantum.Qir.QSharp.Core" + }; + + public override IList HeaderDirectories { get; } = new List(); + + public override IList LibraryDirectories { get; } = new List(); + public QirFullStateExecutable(FileInfo executableFile, byte[] qirBytecode, ILogger logger = null) : base(executableFile, qirBytecode, new QirFullStateDriverGenerator(), logger) { - } + var thisModulePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + if (string.IsNullOrWhiteSpace(thisModulePath)) + { + throw new InvalidOperationException("Could not get a path for the current assembly location."); + } + HeaderDirectories.Add(new DirectoryInfo(Path.Combine(thisModulePath, "runtimes", "any", "native", "include"))); + HeaderDirectories.Add(new DirectoryInfo(Path.Combine(thisModulePath, "Externals", "CLI11"))); - public override IList LinkLibraries => new List { - "Microsoft.Quantum.Qir.Runtime", - "Microsoft.Quantum.Qir.QSharp.Foundation", - "Microsoft.Quantum.Qir.QSharp.Core" - }; + var osID = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win-x64" + : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux-x64" + : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx-x64" + : throw new ArgumentException("Unsupported operating system architecture."); - public override string DriverFileExtension => "cpp"; + LibraryDirectories.Add(new DirectoryInfo(Path.Combine(thisModulePath, "runtimes", osID, "native"))); + LibraryDirectories.Add(new DirectoryInfo(Path.Combine(thisModulePath, "Libraries", osID))); + LibraryDirectories.Add(new DirectoryInfo(Path.Combine(thisModulePath, "Libraries"))); + } } } diff --git a/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj b/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj index 8917f61f09e..dad660fc9f0 100644 --- a/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj +++ b/src/Qir/Execution/Tools/Microsoft.Quantum.Qir.Tools.csproj @@ -1,5 +1,7 @@  + + netstandard2.1 x64 @@ -50,4 +52,43 @@ + + + runtimes\%(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + false + + + runtimes\any\native\include\%(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + false + + + + + + Libraries\%(FileName)%(Extension) + PreserveNewest + false + + + + + + Libraries\win-x64\%(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + false + + + Libraries\osx-x64\%(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + false + + + Libraries\linux-x64\%(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + false + + + diff --git a/src/Qir/Execution/Tools/Utility/ILogger.cs b/src/Qir/Execution/Tools/Utility/ILogger.cs index 7049bee9582..075fc708947 100644 --- a/src/Qir/Execution/Tools/Utility/ILogger.cs +++ b/src/Qir/Execution/Tools/Utility/ILogger.cs @@ -17,6 +17,12 @@ public interface ILogger /// Message to log. void LogInfo(string message); + /// + /// Logs a message at the "warning" level. + /// + /// Message to log. + void LogWarning(string message); + /// /// Logs a message at the "error" level. /// diff --git a/src/Qir/Execution/Tools/Utility/Logger.cs b/src/Qir/Execution/Tools/Utility/Logger.cs index 4aa2074a760..e5f2fe5b107 100644 --- a/src/Qir/Execution/Tools/Utility/Logger.cs +++ b/src/Qir/Execution/Tools/Utility/Logger.cs @@ -20,6 +20,7 @@ public Logger(IClock clock) // ...{exception type}: {exception message}{Environment.NewLine}{stack trace}. private const string ExceptionMessageFormat = "Exception encountered: {0}: {1}{2}{3}"; private const string InfoLevel = "INFO"; + private const string WarningLevel = "WARNING"; private const string ErrorLevel = "ERROR"; public void LogInfo(string message) @@ -27,6 +28,11 @@ public void LogInfo(string message) Console.WriteLine(LogFormat, clock.Now, InfoLevel, message); } + public void LogWarning(string message) + { + Console.WriteLine(LogFormat, clock.Now, WarningLevel, message); + } + public void LogError(string message) { Console.WriteLine(LogFormat, clock.Now, ErrorLevel, message);