diff --git a/README.md b/README.md index 072e3f98d2d..2f3c4a10b6b 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,28 @@ To build on other platforms: 1. Install the pre-reqs: * Install [CMake](https://cmake.org/install/) * Install [.NET Core 3 SDK](https://dotnet.microsoft.com/download) + * On [WSL](https://docs.microsoft.com/en-us/windows/wsl/)/Linux: + * Install `g++` (e.g. in Ubuntu 20.04 `sudo apt-get install g++`). + * The build does not accept `dotnet-*-5.0` packages, install `dotnet-*-3.1` + (`sudo apt-get install dotnet-sdk-3.1`). The possible result can be: + +```sh +qsharp-runtime$ dpkg -l *dotnet* +Desired=Unknown/Install/Remove/Purge/Hold +| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend +|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) +||/ Name Version Architecture Description ++++-=========================-============-============-================================================================= +un dotnet (no description available) +ii dotnet-apphost-pack-3.1 3.1.13-1 amd64 Microsoft.NETCore.App.Host 3.1.13 +ii dotnet-host 5.0.4-1 amd64 Microsoft .NET Host - 5.0.4 +ii dotnet-hostfxr-3.1 3.1.13-1 amd64 Microsoft .NET Core Host FX Resolver - 3.1.13 3.1.13 +un dotnet-nightly (no description available) +ii dotnet-runtime-3.1 3.1.13-1 amd64 Microsoft .NET Core Runtime - 3.1.13 Microsoft.NETCore.App 3.1.13 +ii dotnet-runtime-deps-3.1 3.1.13-1 amd64 dotnet-runtime-deps-3.1 3.1.13 +ii dotnet-sdk-3.1 3.1.407-1 amd64 Microsoft .NET Core SDK 3.1.407 +ii dotnet-targeting-pack-3.1 3.1.0-1 amd64 Microsoft.NETCore.App.Ref 3.1.0 +``` 2. Run [bootstrap.ps1](./bootstrap.ps1) * The script might install additional tools (a specific compiler, build tools, etc) * Then it builds release flavor of the native (C++) full-state simulator and debug flavor of the Simulation solution. diff --git a/src/QirRuntime/README.md b/src/QirRuntime/README.md index 3a7f2e4b69b..b1145ad2432 100644 --- a/src/QirRuntime/README.md +++ b/src/QirRuntime/README.md @@ -1,8 +1,9 @@ # The Native QIR Runtime -This folder contains QIR runtime project, which includes implementation of the +This folder contains the Quantum Intermediate Representation (QIR) Runtime project. The QIR is a subset of the [LLVM](https://llvm.org/) Intermediate Representation. +The QIR runtime includes an implementation of the [QIR specification](https://github.com/microsoft/qsharp-language/tree/main/Specifications/QIR) and the bridge to - compile QIR to be run against the native full state simulator. + run QIR against the native full state simulator. - `public` folder contains the public headers - `lib` folder contains the implementation of the runtime and the simulators. @@ -11,24 +12,19 @@ This folder contains QIR runtime project, which includes implementation of the ## Build -The QirRuntime project is using CMake (3.17) + Ninja(1.10.0) + Clang++(11.0.0). Other versions of the tools might work - but haven't been tested. Only x64 architecture is supported. - -You can use CMake directly. For example, to produce a release build: - -1. navigate into QirRuntime folder -2. mkdir build -3. cd build -4. cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. -5. cmake --build . - -Or you can run `build-qir-runtime.ps1` script from QirRuntime folder. The script will place the build artifacts into `build/[Debug|Release]` folder. We strongly recommend doing local builds using the build script because it also runs clang-tidy if it is installed. +### Prerequisites -CI builds and tests are enabled for this project. The build for `test/QIR-static/qsharp/qir-gen.csproj` has project dependencies on other parts of the runtime and may trigger a build for those components, while some of the tests depend on `Microsoft.Quantum.Simulator.Runtime` dynamic library built from. +The QirRuntime project is using CMake (3.17) + Ninja(1.10.0) + Clang++(11.0.0). Other versions of the tools might work + but haven't been tested. Only x64 architecture is supported. +For running the PowerShell scripts below use +[PowerShell Core or PowerShell 7+ (`pwsh`)](https://github.com/PowerShell/PowerShell), not the inbox PowerShell. -To install prerequisite tools for building the QIR runtime, you can set the `ENABLE_QIRRUNTIME` environment variable to the string `"true"` and run `prerequisites.ps1` or manually install pre-reqs with the steps listed below (Windows script relies on [Chocolatey](https://chocolatey.org/) for installation). +To install prerequisite tools for building the QIR runtime, you can set the `ENABLE_QIRRUNTIME` environment variable to the string `"true"` +and run [`prerequisites.ps1`](prerequisites.ps1), or manually install pre-reqs with the steps listed below. +Note that on Windows, this script relies on the [Chocolatey package manager](https://chocolatey.org/), +while on macOS, `prerequisites.ps1` relies on the [`brew` package manager](https://brew.sh). -### Windows pre-reqs +#### Windows pre-reqs 1. Install Clang 11, Ninja and CMake from the public distros. 1. Add all three to your/system `%PATH%`. @@ -39,7 +35,7 @@ To install prerequisite tools for building the QIR runtime, you can set the `ENA *Building from Visual Studio and VS Code is **not** supported. Running cmake from the editors will likely default to MSVC or clang-cl and fail.* -### Linux via WSL pre-reqs +#### Linux via WSL pre-reqs 1. On the host Windows machine [enable WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10) and install Ubuntu 20.04 LTS. @@ -55,35 +51,35 @@ Running cmake from the editors will likely default to MSVC or clang-cl and fail. See [https://code.visualstudio.com/docs/remote/wsl] on how to use VS Code with WSL. -## Test +#### Other Prerequisites -Some of the tests depend on Microsoft.Quantum.Simulator.Runtime library. To run them make sure to build Native simulator - from this repository or provide your own version of the library in a folder the OS would search during dynamic library - lookup. +The build depends on `Microsoft.Quantum.Simulator.Runtime` dynamic library built at a higher level of the directory tree. +To build that library follow the instructions in [`qsharp-runtime/README.md`](../../README.md#building-from-source) +(up to and including the step `Simulation.sln`). -Some of the tests use generated QIR (*.ll) files as build input. Currently the files are checked-in as part of the project - but in the future they will be replaced by automatic generation during build. To regenerate the files, run generateqir.py - or build/test scripts without specifying `noqirgen`. To use the checked-in files without regenerating them, run build/test - scripts with `noqirgen` argument. -### Running tests with test.py +### Build Commands -To execute all tests locally run `test.py` from the project's root folder: +To build QirRuntime you can run [`build-qir-runtime.ps1`](build-qir-runtime.ps1) script from QirRuntime folder: +```batch +pwsh build-qir-runtime.ps1 +``` + +The script will create the `build/{Debug|Release}` folder and place the build artifacts in it. The configuration `Debug|Release` +is specified with the `BUILD_CONFIGURATION` environment variable. +If the variable is not set then the default is specified in [`set-env.ps1`](../../build/set-env.ps1). -- (Windows) `python test.py [nobuild] [debug/release]` -- (Linux) `python3 test.py [nobuild] [debug/release]` +## Tests -The script will trigger an incremental build unless `nobuild` options is specified. Tests from the "[skip]" category - won't be run. +### Running All Tests -### Running tests with CTest +```powershell +# Navigate to QirRuntime folder. -All native tests, including QIR, use catch2 and are fully integrated with CTest. Navigate into - `build/[Windows|Linux]/[Debug|Release]` folder and run `ctest`. No configuration options required. The results will be - logged into the corresponding `build/[Windows|Linux]/[Debug|Release]//_results.xml` file. - Tests from the "[skip]" category won't be run. +pwsh test-qir-runtime.ps1 +``` -### Running test binaries individually +### Running Test Binaries Individually ` -help` provides details on how to run a subset of the tests and other options. For example, you can filter tests from the "[skip]" category out by ` ~[skip]`. diff --git a/src/QirRuntime/build.py b/src/QirRuntime/build.py deleted file mode 100644 index 5b6c1646a19..00000000000 --- a/src/QirRuntime/build.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import sys, os, platform, subprocess, datetime, shutil -import generateqir - -# ============================================================================= -# The script will create [root]\build\[OS]\[Debug|Release] folder for the output. -# -# Accepts arguments: -# make/nomake -# 'make' will limit action to producing make files only -# 'nomake' will skip make step and build using the current cmake cache -# if omitted will make and then build the project -# debug/release -# default: debug -# -# For example: "build.py nomake debug ir" or "build.py release" -# ============================================================================= - -# ============================================================================= -def log(message): - now = datetime.datetime.now() - current_time = now.strftime("%H:%M:%S") - print(current_time + ": " + message) -# ============================================================================= - -# ============================================================================= -def create_if_doesnot_exist(dir): - if not os.path.isdir(dir): - os.mkdir(dir) - -def create_folder_structure(start_dir, dirs): - new_dir = start_dir - for dir in dirs: - new_dir = os.path.join(new_dir, dir) - create_if_doesnot_exist(new_dir) - return new_dir -# ============================================================================= - -# ============================================================================= -def do_build(root_dir, should_make, should_build, flavor): - build_dir = create_folder_structure(root_dir, ["build", platform.system(), flavor]) - os.chdir(build_dir) - - flavorWithDebInfo = flavor - if flavor == "Release" : - flavorWithDebInfo = "RelWithDebInfo" - - clangTidy = "clang-tidy" - if platform.system() == "Linux" : - clangTidy = "clang-tidy-11" - - if should_make: - cmd = "cmake -G Ninja -DCMAKE_CXX_CLANG_TIDY=" + clangTidy + " -DCMAKE_BUILD_TYPE=" + flavorWithDebInfo + " ../../.." - log("running: " + cmd) - result = subprocess.run(cmd, shell = True) - if result.returncode != 0: - return result - - if should_build: - cmd = "cmake --build . --target install --config " + flavorWithDebInfo - log("running: " + cmd) - result = subprocess.run(cmd, shell = True) - - return result -# ============================================================================= - -if __name__ == '__main__': - # this script is executed as script - # parameters - flavor = "Debug" - should_make = True - should_build = True - noqirgen = False - - for arg in sys.argv: - arg = arg.lower() - if "build.py" in arg: - continue - elif arg == "debug": - flavor = "Debug" - elif arg == "release": - flavor = "Release" - elif arg == "nomake": - should_make = False - elif arg == "make": - should_build = False - elif arg == "noqirgen": - noqirgen = True - else: - log("unrecognized argument: " + arg) - sys.exit() - - root_dir = os.path.dirname(os.path.abspath(__file__)) - - if not noqirgen: - if generateqir.do_generate_all(root_dir) != 0: - log("Aborting build due to failures in QIR generation") - sys.exit() - - do_build(root_dir, should_make, should_build, flavor) \ No newline at end of file diff --git a/src/QirRuntime/generateqir.py b/src/QirRuntime/generateqir.py deleted file mode 100644 index af013f67cb9..00000000000 --- a/src/QirRuntime/generateqir.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import os, sys, subprocess, datetime, shutil, pathlib - -# ============================================================================= -def log(message): - now = datetime.datetime.now() - current_time = now.strftime("%H:%M:%S") - print(current_time + ": " + message) -# ============================================================================= - -# ============================================================================= -# The Q# project should be located in a subfolder under test_dir, named "qsharp" -def do_generate_qir(test_dir): - qsharp_project_path = os.path.join(test_dir, "qsharp") - qirgencmd = "dotnet build " + qsharp_project_path - log("running: " + qirgencmd) - result = subprocess.run(qirgencmd, shell = True) - if result.returncode != 0: - return result - - # really, expect to have only one file - for generated_qir_file in os.listdir(os.path.join(qsharp_project_path, "qir")): - shutil.copyfile( - os.path.join(os.path.join(qsharp_project_path, "qir", generated_qir_file)), - os.path.join(test_dir, generated_qir_file)) - - return result -# ============================================================================= - -# ============================================================================= -def do_generate_all(root_dir): - test_projects = [ - os.path.join(root_dir, "test", "QIR-static"), - os.path.join(root_dir, "samples", "StandaloneInputReference") - # add other test folders here - ] - - for test_dir in test_projects: - log("generating QIR for: " + test_dir) - result = do_generate_qir(test_dir) - if result.returncode != 0: - log("Failed to generate QIR for: " + test_dir) - return result.returncode - - return 0 -# ============================================================================= - -if __name__ == '__main__': - root_dir = os.path.dirname(os.path.abspath(__file__)) - do_generate_all(root_dir) - - diff --git a/src/QirRuntime/test.py b/src/QirRuntime/test.py deleted file mode 100644 index 4e62ea33be7..00000000000 --- a/src/QirRuntime/test.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import sys, os, platform, subprocess, datetime, shutil -import build, generateqir - -# ============================================================================= -# Accepts arguments: -# nobuild [if omitted, will attempt to build the project] -# noqirgen [if omitted, will attempt to generate qir from Q# projects] -# debug/release -# -# For example: "test.py nobuild debug" -# ============================================================================= - -# ============================================================================= -def log(message): - now = datetime.datetime.now() - current_time = now.strftime("%H:%M:%S") - print(current_time + ": " + message) -# ============================================================================= - -if __name__ == '__main__': - # this script is executed as script - root_dir = os.path.dirname(os.path.abspath(__file__)) - - # parameters - flavor = "Debug" - nobuild = False - noqirgen = False - for arg in sys.argv: - arg = arg.lower() - if arg == "test.py": - continue - elif arg == "debug": - flavor = "Debug" - elif arg == "release": - flavor = "Release" - elif arg == "nobuild": - nobuild = True - noqirgen = True - elif arg == "noqirgen": - noqirgen = True - else: - log("unrecognized argument: " + arg) - sys.exit() - - if not noqirgen: - if generateqir.do_generate_all(root_dir) != 0: - log("build failed to generate QIR => won't execute the tests") - log("to execute the tests from the last successful build run `test.py nobuild`") - sys.exit() - - if not nobuild: - result = build.do_build(root_dir, True, True, flavor) # should_make, should_build - if result.returncode != 0: - log("build failed with exit code {0} => won't execute the tests".format(result.returncode)) - log("to execute the tests from the last successful build run `test.py nobuild`") - sys.exit() - - install_dir = os.path.join(root_dir, "build", platform.system(), flavor, "bin") - if not os.path.isdir(install_dir): - log("please build first: 'build.py [debug|release] [ir]'") - sys.exit() - - print("\n") - - # Configure DLL lookup locations to include full state simulator and qdk - exe_ext = "" - fullstate_sim_dir = os.path.join(root_dir, "..", "Simulation", "Native", "build", flavor) - if platform.system() == "Windows": - exe_ext = ".exe" - os.environ['PATH'] = os.environ['PATH'] + ";" + fullstate_sim_dir + ";" + install_dir - else: - # add the folder to the list of locations to load libraries from - old = os.environ.get("LD_LIBRARY_PATH") - if old: - os.environ["LD_LIBRARY_PATH"] = old + ":" + fullstate_sim_dir + ":" + install_dir - else: - os.environ["LD_LIBRARY_PATH"] = fullstate_sim_dir + ":" + install_dir - - old = os.environ.get("DYLD_LIBRARY_PATH") - if old: - os.environ["DYLD_LIBRARY_PATH"] = old + ":" + fullstate_sim_dir + ":" + install_dir - else: - os.environ["DYLD_LIBRARY_PATH"] = fullstate_sim_dir + ":" + install_dir - - log("========= Running native tests =========") - test_binaries = [ - "fullstate-simulator-tests", - "qir-runtime-unittests", - "qir-static-tests", - "qir-dynamic-tests", - "qir-tracer-tests" - ] - - for name in test_binaries: - test_binary = os.path.join(install_dir, name + exe_ext) - log(test_binary) - subprocess.run(test_binary + " ~[skip]", shell = True) - - log("========= Running samples =========") - sample_binary = os.path.join(install_dir, "qir-input-reference-standalone" + exe_ext) - log(sample_binary) - subprocess.run( - sample_binary +\ - " --int-value 1" +\ - " --integer-array 1 2 3 4 5" +\ - " --double-value 0.5" +\ - " --double-array 0.1 0.2 0.3 0.4 0.5" +\ - " --bool-value true" +\ - " --bool-array true TRUE false fALSe 0" +\ - " --pauli-value PauliX" +\ - " --pauli-array PauliI paulix PAULIY PAulIZ" +\ - " --range-value 1 2 10" +\ - " --range-array 1 2 10 5 5 50 10 1 20" +\ - " --string-value ASampleString" +\ - " --result-value one" +\ - " --result-array one ONE 1 zero ZERO 0" +\ - " --string-array StringA StringB StringC") - - print("\n")