From 7220b48ca061734619559936dd4bcfd8817cc157 Mon Sep 17 00:00:00 2001 From: jake-arkinstall-quantinuum <111498186+jake-arkinstall-quantinuum@users.noreply.github.com> Date: Fri, 20 Oct 2023 11:30:56 +0100 Subject: [PATCH] [infra] Add nix support (#918) --- .github/workflows/build-with-nix.yml | 20 ++++ .gitignore | 1 + README.md | 6 ++ flake.lock | 60 ++++++++++++ flake.nix | 31 ++++++ libs/tkassert/CMakeLists.txt | 7 +- libs/tklog/CMakeLists.txt | 8 +- libs/tkrng/CMakeLists.txt | 7 +- libs/tktokenswap/CMakeLists.txt | 8 +- libs/tkwsm/CMakeLists.txt | 8 +- nix-support/README.md | 33 +++++++ nix-support/example-flake-project/README.md | 18 ++++ nix-support/example-flake-project/flake.nix | 45 +++++++++ .../example-flake-project/pyproject.toml | 9 ++ .../src/examples/__init__.py | 0 .../src/examples/basic_circuits.py | 22 +++++ nix-support/includes-fixup.nix | 7 ++ nix-support/libs.nix | 45 +++++++++ nix-support/pytket.nix | 94 +++++++++++++++++++ nix-support/symengine.nix | 14 +++ nix-support/symengine.patch | 21 +++++ nix-support/third-party-python-packages.nix | 44 +++++++++ nix-support/tket.nix | 44 +++++++++ pytket/CMakeLists.txt | 3 + pytket/conanfile.py | 2 +- pytket/setup.py | 32 ++++++- tket/CMakeLists.txt | 8 +- tket/conanfile.py | 2 +- tket/test/src/test_PhasePolynomials.cpp | 2 +- 29 files changed, 591 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/build-with-nix.yml create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix-support/README.md create mode 100644 nix-support/example-flake-project/README.md create mode 100644 nix-support/example-flake-project/flake.nix create mode 100644 nix-support/example-flake-project/pyproject.toml create mode 100644 nix-support/example-flake-project/src/examples/__init__.py create mode 100644 nix-support/example-flake-project/src/examples/basic_circuits.py create mode 100644 nix-support/includes-fixup.nix create mode 100644 nix-support/libs.nix create mode 100644 nix-support/pytket.nix create mode 100644 nix-support/symengine.nix create mode 100644 nix-support/symengine.patch create mode 100644 nix-support/third-party-python-packages.nix create mode 100644 nix-support/tket.nix diff --git a/.github/workflows/build-with-nix.yml b/.github/workflows/build-with-nix.yml new file mode 100644 index 0000000000..091f2a9671 --- /dev/null +++ b/.github/workflows/build-with-nix.yml @@ -0,0 +1,20 @@ +name: build with nix +on: + schedule: + # 01:00 every Sunday morning + - cron: '0 1 * * 0' + workflow_dispatch: {} +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + build_and_test: + strategy: + matrix: + os: ['ubuntu-22.04', 'macos-12'] + runs-on: ${{matrix.os}} + steps: + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v20 + - name: Build and test tket + run: nix flake check diff --git a/.gitignore b/.gitignore index e3a61997e0..90eb7af76d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.egg-info *.o *.so +*.swp .cache .eggs .hypothesis diff --git a/README.md b/README.md index 14e928a27c..e3facaa256 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,12 @@ building and testing tket as a standalone C++ library. See the [README](pytket/README.md) in the `pytket` directory for instructions on building and testing pytket. +### Nix Support + +Tket and pytket are available as a Nix flake. See the [README](nix-support/README.md) +in the `nix-support` directory for instructions on building and testing tket and pytket +through Nix, and on how to use it within a Nix project. + ## API documentation The `tket` (C++) API documentation (generated with `doxygen`, and still rather diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..4ba12b3083 --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1697158538, + "narHash": "sha256-TR02XPre2EcwU1kT4WXZWJOBi/B8C7P1xoywOUGkdDk=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "ee176b5fbb680864dcf80f9ca3f6f134d81331d8", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000..a82c8cf73d --- /dev/null +++ b/flake.nix @@ -0,0 +1,31 @@ +{ + description = "Tket Quantum SDK"; + inputs.nixpkgs.url = "github:nixos/nixpkgs"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ + (import ./nix-support/libs.nix) + (import ./nix-support/symengine.nix) + (import ./nix-support/tket.nix) + (import ./nix-support/third-party-python-packages.nix) + (import ./nix-support/pytket.nix) + ]; + }; + in { + packages = { + tket = pkgs.tket; + pytket = pkgs.pytket; + }; + devShells = { + default = pkgs.mkShell { buildInputs = [ pkgs.tket pkgs.pytket ]; }; + }; + checks = { + tket-tests = pkgs.run-tket-tests; + pytket-tests = pkgs.pytket; + }; + }); +} diff --git a/libs/tkassert/CMakeLists.txt b/libs/tkassert/CMakeLists.txt index cd38a7f271..b65ef57dd5 100644 --- a/libs/tkassert/CMakeLists.txt +++ b/libs/tkassert/CMakeLists.txt @@ -22,6 +22,8 @@ find_package(tklog CONFIG REQUIRED) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) +option(INSTALL_NAME_DIR "Set the install name dir for the library to @loader_path for Apple targets" ON) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() @@ -35,7 +37,7 @@ if(WIN32) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS yes) endif() -if(APPLE) +if(APPLE AND INSTALL_NAME_DIR) set(CMAKE_INSTALL_NAME_DIR "@loader_path") set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) endif() @@ -64,6 +66,9 @@ target_include_directories(tkassert PUBLIC $ $) target_link_libraries(tkassert PRIVATE tklog::tklog) +IF(APPLE) + target_link_libraries(tkassert PRIVATE "-flat_namespace") +ENDIF() target_sources(tkassert PRIVATE src/AssertMessage.cpp diff --git a/libs/tklog/CMakeLists.txt b/libs/tklog/CMakeLists.txt index 8b570edce7..2366c0f895 100644 --- a/libs/tklog/CMakeLists.txt +++ b/libs/tklog/CMakeLists.txt @@ -20,6 +20,8 @@ list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) +option(INSTALL_NAME_DIR "Set the install name dir for the library to @loader_path for Apple targets" ON) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() @@ -33,7 +35,7 @@ if(WIN32) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS yes) endif() -if(APPLE) +if(APPLE AND INSTALL_NAME_DIR) set(CMAKE_INSTALL_NAME_DIR "@loader_path") set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) endif() @@ -62,6 +64,10 @@ target_include_directories(tklog PUBLIC $ $) +IF(APPLE) + target_link_libraries(tklog PRIVATE "-flat_namespace") +ENDIF() + target_sources(tklog PRIVATE src/TketLog.cpp PUBLIC FILE_SET HEADERS diff --git a/libs/tkrng/CMakeLists.txt b/libs/tkrng/CMakeLists.txt index d7de653944..9f81d6a90f 100644 --- a/libs/tkrng/CMakeLists.txt +++ b/libs/tkrng/CMakeLists.txt @@ -20,6 +20,8 @@ list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) +option(INSTALL_NAME_DIR "Set the install name dir for the library to @loader_path for Apple targets" ON) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() @@ -33,7 +35,7 @@ if(WIN32) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS yes) endif() -if(APPLE) +if(APPLE AND INSTALL_NAME_DIR) set(CMAKE_INSTALL_NAME_DIR "@loader_path") set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) endif() @@ -62,6 +64,9 @@ target_include_directories(tkrng PUBLIC $ $) +IF(APPLE) + target_link_libraries(tkrng PRIVATE "-flat_namespace") +ENDIF() target_sources(tkrng PRIVATE src/RNG.cpp PUBLIC FILE_SET HEADERS diff --git a/libs/tktokenswap/CMakeLists.txt b/libs/tktokenswap/CMakeLists.txt index fa9a8a21b9..e9e50624ed 100644 --- a/libs/tktokenswap/CMakeLists.txt +++ b/libs/tktokenswap/CMakeLists.txt @@ -25,6 +25,8 @@ find_package(Boost CONFIG REQUIRED) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) +option(INSTALL_NAME_DIR "Set the install name dir for the library to @loader_path for Apple targets" ON) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() @@ -38,7 +40,7 @@ if(WIN32) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS yes) endif() -if(APPLE) +if(APPLE AND INSTALL_NAME_DIR) set(CMAKE_INSTALL_NAME_DIR "@loader_path") set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) endif() @@ -71,6 +73,10 @@ target_link_libraries(tktokenswap PRIVATE tkassert::tkassert) target_link_libraries(tktokenswap PRIVATE tkrng::tkrng) target_link_libraries(tktokenswap PRIVATE Boost::headers) +IF(APPLE) + target_link_libraries(tktokenswap PRIVATE "-flat_namespace") +ENDIF() + target_sources(tktokenswap PRIVATE src/BestFullTsa.cpp diff --git a/libs/tkwsm/CMakeLists.txt b/libs/tkwsm/CMakeLists.txt index e37c1ff6cf..d889aa887b 100644 --- a/libs/tkwsm/CMakeLists.txt +++ b/libs/tkwsm/CMakeLists.txt @@ -25,6 +25,8 @@ find_package(Boost CONFIG REQUIRED) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) +option(INSTALL_NAME_DIR "Set the install name dir for the library to @loader_path for Apple targets" ON) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() @@ -38,7 +40,7 @@ if(WIN32) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS yes) endif() -if(APPLE) +if(APPLE AND INSTALL_NAME_DIR) set(CMAKE_INSTALL_NAME_DIR "@loader_path") set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) endif() @@ -69,6 +71,9 @@ target_include_directories(tkwsm PUBLIC target_link_libraries(tkwsm PRIVATE tkassert::tkassert) target_link_libraries(tkwsm PRIVATE tkrng::tkrng) target_link_libraries(tkwsm PRIVATE Boost::headers) +IF(APPLE) + target_link_libraries(tkwsm PRIVATE "-flat_namespace") +ENDIF() target_sources(tkwsm PRIVATE @@ -157,6 +162,7 @@ target_sources(tkwsm include/tkwsm/WeightPruning/WeightNogoodDetectorManager.hpp ) + include(GNUInstallDirs) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/tkwsm) diff --git a/nix-support/README.md b/nix-support/README.md new file mode 100644 index 0000000000..0721a5e8ff --- /dev/null +++ b/nix-support/README.md @@ -0,0 +1,33 @@ +# Nix support for tket and pytket + +Tket exposes a Nix flake that you can build, test and use within a Nix environment. +To build and test tket and pytket on your local system, you can run + +``` +$ nix flake check github:CQCL/tket +``` + +This will take some time, as it requires the building of a patched symengine, +the compilation of tket and tket tests, and the compilation of pytket's dependencies, +before testing. + +You can enter a development environment with tket and pytket available +with use of `nix develop`. For example, + +``` +$ nix develop github:CQCL/tket + +$ python3 +Python 3.10.12 (main, Jun 6 2023, 22:43:10) [GCC 12.2.0] on linux +Type "help", "copyright", "credits" or "license" for more information. +>>> from pytket import Circuit +>>> circuit = Circuit(5) +>>> circuit.X(1) +[X q[1]; ] +>>> circuit.X(2) +[X q[1]; X q[2]; ] +``` + +You can also use tket and pytket within your own flake project. +An example of such a project is given in the [example-flake-project](example-flake-project) +directory. diff --git a/nix-support/example-flake-project/README.md b/nix-support/example-flake-project/README.md new file mode 100644 index 0000000000..d0c3737043 --- /dev/null +++ b/nix-support/example-flake-project/README.md @@ -0,0 +1,18 @@ +# Example flake project + +In this example, we create a [flake.nix](flake.nix) file that tells Nix +where to fetch nixpkgs, flake-utils and tket. It also builds an example +application, using [pyproject.toml](pyproject.toml) and the +[src](src) directory. This application [exposes](src/examples/basic_circuits.py) +two scripts: `entanglement` and `teleport`, that set up trivial circuits +and display them in your browser. + +To run these scripts, simply run the following commands from within this directory: + +``` +nix run .#entanglement +``` +and +``` +nix run .#teleport +``` diff --git a/nix-support/example-flake-project/flake.nix b/nix-support/example-flake-project/flake.nix new file mode 100644 index 0000000000..747f4d462e --- /dev/null +++ b/nix-support/example-flake-project/flake.nix @@ -0,0 +1,45 @@ +{ + inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + # fetch tket from github + inputs.tket.url = "github:CQCL/tket"; + + outputs = { self, nixpkgs, flake-utils, tket }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ + (self: super: { + # add tket and pytket to pkgs for later use + tket = tket.packages.${system}.tket; + pytket = tket.packages.${system}.pytket; + }) + ]; + }; + examples = pkgs.python3Packages.buildPythonApplication { + pname = "examples"; + version = "0.0.1"; + format = "pyproject"; + # copy pyproject.toml and src to the build directory + unpackPhase = '' + cp ${./pyproject.toml} pyproject.toml + cp -r ${./src} src + chmod 700 src; + ''; + # provide pytket as a dependency + propagatedBuildInputs = [ pkgs.pytket ]; + }; + in { + apps = { + entanglement = { + type = "app"; + program = "${examples}/bin/entanglement"; + }; + teleport = { + type = "app"; + program = "${examples}/bin/teleport"; + }; + }; + }); +} diff --git a/nix-support/example-flake-project/pyproject.toml b/nix-support/example-flake-project/pyproject.toml new file mode 100644 index 0000000000..c5b56a7063 --- /dev/null +++ b/nix-support/example-flake-project/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "examples" +version = "0.0.1" +dependencies = ["pytket"] + +[project.scripts] +entanglement = "examples.basic_circuits:entanglement_circuit" +teleport = "examples.basic_circuits:teleport_circuit" + diff --git a/nix-support/example-flake-project/src/examples/__init__.py b/nix-support/example-flake-project/src/examples/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/nix-support/example-flake-project/src/examples/basic_circuits.py b/nix-support/example-flake-project/src/examples/basic_circuits.py new file mode 100644 index 0000000000..9d2ddd3cb1 --- /dev/null +++ b/nix-support/example-flake-project/src/examples/basic_circuits.py @@ -0,0 +1,22 @@ +from pytket import Circuit +from pytket.circuit.display import get_circuit_renderer + + +def entanglement_circuit(): + circuit = Circuit(2) + circuit.H(0) + circuit.CX(0, 1) + circuit.measure_all() + renderer = get_circuit_renderer() + renderer.view_browser(circuit) + + +def teleport_circuit(): + circuit = Circuit(3) + circuit.H(0) + circuit.CX(0, 1) + circuit.CX(1, 2) + circuit.H(0) + circuit.measure_all() + renderer = get_circuit_renderer() + renderer.view_browser(circuit) diff --git a/nix-support/includes-fixup.nix b/nix-support/includes-fixup.nix new file mode 100644 index 0000000000..b9a1fa43d2 --- /dev/null +++ b/nix-support/includes-fixup.nix @@ -0,0 +1,7 @@ +'' + # fix bogus include paths + # trick found here: https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/crc32c/default.nix + for f in $(find $out/lib/cmake -name '*.cmake'); do + substituteInPlace "$f" --replace "\''${_IMPORT_PREFIX}/$out/include" "\''${_IMPORT_PREFIX}/include" + done +'' diff --git a/nix-support/libs.nix b/nix-support/libs.nix new file mode 100644 index 0000000000..59f1f65524 --- /dev/null +++ b/nix-support/libs.nix @@ -0,0 +1,45 @@ +self: super: +let + default-flags = [ "-DBUILD_SHARED_LIBS=ON" "-DINSTALL_NAME_DIR=OFF" ]; + postFixup = import ./includes-fixup.nix; +in { + tklog = super.stdenv.mkDerivation { + name = "tklog"; + src = ../libs/tklog; + nativeBuildInputs = [ super.cmake ]; + cmakeFlags = default-flags; + inherit postFixup; + }; + tkrng = super.stdenv.mkDerivation { + name = "tkrng"; + src = ../libs/tkrng; + nativeBuildInputs = [ super.cmake ]; + cmakeFlags = default-flags; + inherit postFixup; + }; + tkassert = super.stdenv.mkDerivation { + name = "tkassert"; + src = ../libs/tkassert; + nativeBuildInputs = [ super.cmake ]; + buildInputs = [ self.tklog ]; + cmakeFlags = default-flags; + inherit postFixup; + }; + tktokenswap = super.stdenv.mkDerivation { + name = "tktokenswap"; + src = ../libs/tktokenswap; + nativeBuildInputs = [ super.cmake super.boost ]; + buildInputs = [ self.tklog self.tkassert self.tkrng ]; + cmakeFlags = default-flags; + inherit postFixup; + }; + tkwsm = super.stdenv.mkDerivation { + name = "tkwsm"; + src = ../libs/tkwsm; + nativeBuildInputs = [ super.cmake super.boost ]; + buildInputs = [ self.tklog self.tkassert self.tkrng ]; + cmakeFlags = default-flags; + inherit postFixup; + }; + tklibs = [ self.tklog self.tkrng self.tkassert self.tktokenswap self.tkwsm ]; +} diff --git a/nix-support/pytket.nix b/nix-support/pytket.nix new file mode 100644 index 0000000000..d99d90b98f --- /dev/null +++ b/nix-support/pytket.nix @@ -0,0 +1,94 @@ +self: super: +let + config_contents = builtins.readFile ../pytket/docs/conf.py; + versions = + builtins.match ''.*release *= *["']([^"']+)["'].*'' config_contents; + version = if builtins.length versions > 0 then + builtins.elemAt versions 0 + else + "0.0.0"; + + jsonschema-4180 = super.python3Packages.jsonschema.overrideAttrs (_: rec { + version = "4.18.0"; + src = super.fetchPypi { + pname = "jsonschema"; + version = "4.18.0"; + hash = sha256:jK9bV6mQqY6bOYMu88s1wXb+MxQUJStuGyb9WGb4kaQ=; + }; + }); +in { + binders = super.stdenv.mkDerivation { + name = "binders"; + nativeBuildInputs = [ + super.cmake + super.pkg-config + super.python3Packages.pybind11 + super.pybind11_json + ]; + cmakeFlags = [ "-DBUILD_SHARED_LIBS=ON" ]; + propagatedBuildInputs = [ + super.tket + ]; + unpackPhase = '' + cp -r ${../pytket/binders} binders; + cp ${../pytket/CMakeLists.txt} CMakeLists.txt; + ''; + }; + pytket = super.python3.pkgs.buildPythonPackage { + name = "pytket"; + inherit version; + propagatedBuildInputs = with super.python3.pkgs; [ + self.binders + super.lark-parser + super.types-pkg_resources + super.qwasm + graphviz + networkx + jinja2 + sympy + scipy + numpy + typing-extensions + ]; + + unpackPhase = '' + cp -r ${../pytket/pytket} pytket; + cp -r ${../pytket/setup.py} setup.py; + cp -r ${../pytket/package.md} package.md; + cp -r ${../schemas} schemas; + mkdir test_root; + cp -r ${../pytket/tests} test_root/tests; + ''; + preBuild = '' + export USE_NIX=1; + ''; + postFixup = '' + # hardcode the version extracted from docs/conf.py. + echo '__version__ = "${version}"' > $out/lib/python3.10/site-packages/pytket/_version.py; + + # these directories aren't copied by setup.py, so we do it manually + cp -r ${ + ../pytket/pytket/circuit/display/js + } $out/lib/python3.10/site-packages/pytket/circuit/display/js; + cp -r ${ + ../pytket/pytket/circuit/display/static + } $out/lib/python3.10/site-packages/pytket/circuit/display/static; + ''; + checkInputs = with super.python3.pkgs; [ + pytest + pytest-cov + pytest-benchmark + py + hypothesis + docker + opt-einsum + ] ++ [jsonschema-4180]; + checkPhase = '' + export HOME=$TMPDIR; + chmod 700 $TMPDIR/test_root/tests/qasm_test_files; + cd test_root/tests; + python -m pytest -s . + ''; + doCheck = true; + }; +} diff --git a/nix-support/symengine.nix b/nix-support/symengine.nix new file mode 100644 index 0000000000..7b74768a47 --- /dev/null +++ b/nix-support/symengine.nix @@ -0,0 +1,14 @@ +self: super: { + # symengine in nixpkgs is built as a static library, and doesn't expose + # propagated inputs in its pkgconfig file. This is a workaround to build + # it as a shared library, and to expose the propagated inputs. + symengine = super.symengine.overrideAttrs (old: { + patches = [ ./symengine.patch ]; + cmakeFlags = old.cmakeFlags ++ [ + "-DBUILD_TESTS=OFF" + "-DBUILD_BENCHMARKS=OFF" + "-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=yes" + ]; + propagatedBuildInputs = [ super.flint super.gmp super.libmpc super.mpfr ]; + }); +} diff --git a/nix-support/symengine.patch b/nix-support/symengine.patch new file mode 100644 index 0000000000..b6e130f0f2 --- /dev/null +++ b/nix-support/symengine.patch @@ -0,0 +1,21 @@ +diff --git a/cmake/SymEngineConfig.cmake.in b/cmake/SymEngineConfig.cmake.in +index dbfc80ba..d3a390b8 100644 +--- a/cmake/SymEngineConfig.cmake.in ++++ b/cmake/SymEngineConfig.cmake.in +@@ -107,11 +107,11 @@ endif() + + list(REMOVE_DUPLICATES SYMENGINE_INCLUDE_DIRS) + +-foreach(LIB "@SYMENGINE_TARGETS@") +- # Remove linking of dependencies to later add them as targets +- set_target_properties(${LIB} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE "") +- set_target_properties(${LIB} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG "") +-endforeach() ++#foreach(LIB "@SYMENGINE_TARGETS@") ++# set_target_properties(${LIB} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE "") ++# set_target_properties(${LIB} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG "") ++#endforeach() ++set_target_properties(symengine PROPERTIES INTERFACE_LINK_LIBRARIES "${SYMENGINE_LIBRARIES}") + + set(SYMENGINE_LIBRARIES @SYMENGINE_TARGETS@ ${SYMENGINE_LIBRARIES}) + set(SYMENGINE_BUILD_TYPE "@CMAKE_BUILD_TYPE@") diff --git a/nix-support/third-party-python-packages.nix b/nix-support/third-party-python-packages.nix new file mode 100644 index 0000000000..b462a4c0b7 --- /dev/null +++ b/nix-support/third-party-python-packages.nix @@ -0,0 +1,44 @@ +self: super: { + pybind11_json = super.stdenv.mkDerivation { + name = "pybind11_json"; + src = super.fetchFromGitHub { + owner = "pybind"; + repo = "pybind11_json"; + rev = "0.2.13"; + sha256 = "sha256:Kl/QflV2bBoH72/LW03K8JDlhBF+DYYXL47A5s1nmTw="; + }; + nativeBuildInputs = [ super.cmake ]; + buildInputs = [ super.python3Packages.pybind11 super.nlohmann_json ]; + }; + qwasm = super.python3.pkgs.buildPythonPackage { + name = "qwasm"; + src = super.fetchFromGitHub { + owner = "CQCL"; + repo = "qwasm"; + rev = "35ebe1e2551449d97b9948a600f8d2e4d7474df6"; + sha256 = "sha256:g/QA5CpAR3exRDgVQMnXGIH8bEGtwGFBjjSblbdXRkU="; + }; + }; + lark-parser = super.python3.pkgs.buildPythonPackage { + pname = "lark-parser"; + version = "0.12.0"; + src = super.fetchFromGitHub { + owner = "lark-parser"; + repo = "lark"; + rev = "refs/tags/0.12.0"; + hash = "sha256-zcMGCn3ixD3dJg3GlC/ijs+U1JN1BodHLTXZc/5UR7Y="; + }; + doCheck = false; + }; + types-pkg_resources = let + pname = "types-pkg_resources"; + version = "0.1.3"; + in super.python3.pkgs.buildPythonPackage { + inherit pname version; + src = super.fetchPypi { + inherit pname version; + sha256 = "sha256:g0qbjT2+o0NWL9mdXTNZpyb2v503M7zNK08wlvurna4="; + }; + doCheck = false; + }; +} diff --git a/nix-support/tket.nix b/nix-support/tket.nix new file mode 100644 index 0000000000..5dc0fa43a2 --- /dev/null +++ b/nix-support/tket.nix @@ -0,0 +1,44 @@ +self: super: +let + postFixup = import ./includes-fixup.nix; + # only import necessary directories so that changes to unrelated + # files inside of ../tket won't trigger a rebuild + tket-without-tests = super.stdenv.mkDerivation { + name = "tket-sources"; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out; + cp -r ${../tket/cmake} $out/cmake; + cp -r ${../tket/include} $out/include; + cp -r ${../tket/src} $out/src; + cp -r ${../tket/CMakeLists.txt} $out/CMakeLists.txt; + ''; + }; +in { + tket = super.stdenv.mkDerivation { + name = "tket"; + src = tket-without-tests; + nativeBuildInputs = [ super.cmake ]; + propagatedBuildInputs = super.tklibs + ++ [ super.boost super.symengine super.eigen super.nlohmann_json ]; + cmakeFlags = [ "-DBUILD_SHARED_LIBS=ON" "-DINSTALL_NAME_DIR=OFF" ]; + inherit postFixup; + }; + + tket-tests = super.stdenv.mkDerivation { + name = "tket-tests"; + src = ../tket/test; + nativeBuildInputs = [ super.cmake super.pkg-config ]; + buildInputs = [ self.tket super.catch2_3 ]; + }; + run-tket-tests = super.stdenv.mkDerivation { + name = "run-tket-tests"; + stages = [ "build" ]; + buildCommand = '' + pushd ${self.tket-tests}/bin; + mkdir -p $out; + ./test-tket > $out/test_result.txt; + popd; + ''; + }; +} diff --git a/pytket/CMakeLists.txt b/pytket/CMakeLists.txt index 3042b08f6e..a5f46ca430 100644 --- a/pytket/CMakeLists.txt +++ b/pytket/CMakeLists.txt @@ -92,6 +92,9 @@ list(APPEND lib_deps if (WIN32) list(APPEND lib_deps bcrypt) # For boost::uuid endif() +if (APPLE) + list(APPEND lib_deps "-flat_namespace") +endif() set(HEADER_FILES binders/include/add_gate.hpp diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 71b0000b0b..2fdd615d19 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -32,7 +32,7 @@ def package(self): cmake.install() def requirements(self): - self.requires("tket/1.2.59@tket/stable") + self.requires("tket/1.2.60@tket/stable") self.requires("tklog/0.3.3@tket/stable") self.requires("tkrng/0.3.3@tket/stable") self.requires("tkassert/0.3.3@tket/stable") diff --git a/pytket/setup.py b/pytket/setup.py index c16bd7fd21..b26819b448 100755 --- a/pytket/setup.py +++ b/pytket/setup.py @@ -123,9 +123,39 @@ def run(self): shutil.copy(libpath, extdir) +class NixBuild(build_ext): + def run(self): + self.check_extensions_list(self.extensions) + extdir = os.path.abspath( + os.path.dirname(self.get_ext_fullpath(self.extensions[0].name)) + ) + if os.path.exists(extdir): + shutil.rmtree(extdir) + os.makedirs(extdir) + + nix_ldflags = os.environ["NIX_LDFLAGS"].split() + build_inputs = os.environ["propagatedBuildInputs"].split() + + binders = [f"{l}/lib" for l in build_inputs if "-binders" in l] + for binder in binders: + for lib in os.listdir(binder): + libpath = os.path.join(binder, lib) + if not os.path.isdir(libpath): + shutil.copy(libpath, extdir) + + plat_name = os.getenv("WHEEL_PLAT_NAME") +def get_build_ext(): + if os.getenv("USE_NIX"): + return NixBuild + elif os.getenv("NO_CONAN"): + return CMakeBuild + else: + return ConanBuild + + class bdist_wheel(_bdist_wheel): def finalize_options(self): _bdist_wheel.finalize_options(self) @@ -173,7 +203,7 @@ def finalize_options(self): CMakeExtension("pytket._tket.{}".format(binder)) for binder in binders ], cmdclass={ - "build_ext": CMakeBuild if os.getenv("NO_CONAN") else ConanBuild, + "build_ext": get_build_ext(), "bdist_wheel": bdist_wheel, }, classifiers=[ diff --git a/tket/CMakeLists.txt b/tket/CMakeLists.txt index 947ec51d23..69d9cee448 100644 --- a/tket/CMakeLists.txt +++ b/tket/CMakeLists.txt @@ -30,6 +30,8 @@ find_package(tkwsm CONFIG REQUIRED) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) +option(INSTALL_NAME_DIR "Set the install name dir for the library to @loader_path for Apple targets" ON) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() @@ -62,7 +64,7 @@ endif() if(WIN32) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS yes) -elseif(APPLE) +elseif(APPLE AND INSTALL_NAME_DIR) # set correct install_name set(CMAKE_INSTALL_NAME_DIR "@loader_path") set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) @@ -84,6 +86,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=maybe-uninitialized") endif() + add_library(tket) set(PROFILE_COVERAGE no CACHE BOOL "Build library with profiling for test coverage") @@ -114,6 +117,9 @@ target_link_libraries(tket PRIVATE tkassert::tkassert) target_link_libraries(tket PRIVATE tkrng::tkrng) target_link_libraries(tket PRIVATE tktokenswap::tktokenswap) target_link_libraries(tket PRIVATE tkwsm::tkwsm) +IF(APPLE) + target_link_libraries(tket PRIVATE "-flat_namespace") +ENDIF() target_sources(tket PRIVATE diff --git a/tket/conanfile.py b/tket/conanfile.py index 12a1adb205..6811687523 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.2.59" + version = "1.2.60" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" diff --git a/tket/test/src/test_PhasePolynomials.cpp b/tket/test/src/test_PhasePolynomials.cpp index e4d4e3cd35..0247e43cc9 100644 --- a/tket/test/src/test_PhasePolynomials.cpp +++ b/tket/test/src/test_PhasePolynomials.cpp @@ -15,12 +15,12 @@ #include #include "CircuitsForTesting.hpp" -#include "Predicates/PassLibrary.hpp" #include "testutil.hpp" #include "tket/Circuit/Boxes.hpp" #include "tket/Circuit/CircUtils.hpp" #include "tket/Converters/PhasePoly.hpp" #include "tket/Predicates/CompilerPass.hpp" +#include "tket/Predicates/PassLibrary.hpp" #include "tket/Transformations/Decomposition.hpp" #include "tket/Transformations/Rebase.hpp" #include "tket/Transformations/Transform.hpp"