Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CMake build flag for generating Python bindings #1

Merged
merged 18 commits into from
May 14, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
## Release 0.1.0
## Release 0.2.0 (development release)

### New features since last release

* Running CMake with `-DBUILD_PYTHON=ON` now generates Python bindings within a `jet` package. [(#1)](https://github.com/XanaduAI/jet/pull/1)

### Improvements

### Breaking Changes

### Bug Fixes

### Documentation

### Contributors

This release contains contributions from (in alphabetical order):

[Mikhail Andrenkov](https://github.com/Mandrenkov).

Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved
## Release 0.1.0 (current release)

### New features since last release

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- main
paths:
- "include/**"
- "python/**"
- "test/**"

jobs:
Expand All @@ -26,4 +27,4 @@ jobs:
uses: actions/checkout@v2

- name: Run formatter
run: ./bin/format --check include test
run: ./bin/format --check include python test
Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved
85 changes: 85 additions & 0 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Python
on:
pull_request:
push:
branches:
- main
paths-ignore:
- ".github/**"
- "docs/**"
- "README.rst"

jobs:
test-ubuntu:
name: Build (Ubuntu)
runs-on: ubuntu-20.04

steps:
- name: Cancel previous runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Install dependencies
run: sudo apt install -y libopenblas-dev python3.8-dev

- name: Checkout code
uses: actions/checkout@v2

- name: Initialize build directory
run: |
mkdir build
cd build
cmake -DBUILD_PYTHON=ON ../

- name: Generate Python bindings
run: |
cd build
make -j`nproc`

- name: Create virtual environment
run: |
cd python
make setup

- name: Run tests
run: |
cd python
make test

test-macos:
name: Build (MacOS)
runs-on: macos-10.15

steps:
- name: Cancel previous runs
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}

- name: Install dependencies
run: brew install libomp

- name: Checkout code
uses: actions/checkout@v2

- name: Initialize build directory
run: |
mkdir build
cd build
cmake -DBUILD_PYTHON=ON ../

- name: Generate Python bindings
run: |
cd build
make -j`sysctl -n hw.physicalcpu`

- name: Create virtual environment
run: |
cd python
make setup

- name: Run tests
run: |
cd python
make test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ build
# CMake build artifacts
include/jet/CmakeMacros.hpp

# Python virtualenv
# Python
.venv
__pycache__

# Sphinx documentation
docs/__pycache__/*
Expand Down
61 changes: 42 additions & 19 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
##########################
## Set Project version
##########################
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.14)
Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved
set(JET_LOGO "
▄▄ ▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄
██ ██▀▀▀▀▀▀ ▀▀▀██▀▀▀
Expand Down Expand Up @@ -30,11 +30,12 @@ option(ENABLE_NATIVE "Enable native build tuning" OFF)
option(ENABLE_IPO "Enable interprocedural/link-time optimisation" OFF)

# Build options
option(BUILD_PYTHON "Generate Python bindings" OFF)
option(BUILD_TESTS "Build tests" OFF)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Default build type: Release" FORCE)
endif()
option(BUILD_TESTS "Build tests" OFF)

##########################
## Enfore Compiler Support
Expand Down Expand Up @@ -88,7 +89,7 @@ endif()


##########################
## Fetch Taskflow
## Fetch dependencies
##########################
Include(FetchContent)

Expand All @@ -97,31 +98,30 @@ FetchContent_Declare(
GIT_REPOSITORY https://github.com/taskflow/taskflow.git
GIT_TAG v3.1.0
)
FetchContent_Declare(
Pybind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v2.6.2
)

# FetchContent_MakeAvailable() requires CMake 3.14 or newer.
FetchContent_GetProperties(Taskflow)
if(NOT Taskflow_POPULATED)
FetchContent_Populate(Taskflow)
# Don't build the Taskflow tests or examples.
set(TF_BUILD_EXAMPLES OFF CACHE INTERNAL "Build Taskflow examples")
set(TF_BUILD_TESTS OFF CACHE INTERNAL "Build Taskflow tests")
add_subdirectory(${taskflow_SOURCE_DIR} ${taskflow_BINARY_DIR})
# Don't build the Taskflow tests or examples.
set(TF_BUILD_EXAMPLES OFF CACHE INTERNAL "Build Taskflow examples")
set(TF_BUILD_TESTS OFF CACHE INTERNAL "Build Taskflow tests")

if(BUILD_PYTHON)
FetchContent_MakeAvailable(Taskflow Pybind11)
else()
FetchContent_MakeAvailable(Taskflow)
endif()
Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved

find_package(OpenMP QUIET)

message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(STATUS "BLAS_LIBRARIES: ${BLAS_LIBRARIES}")
message(STATUS "BLAS_INCLUDE_DIRS: ${BLAS_INCLUDE_DIRS}")
message(STATUS "ENABLE_NATIVE: ${ENABLE_NATIVE}")
message(STATUS "ENABLE_IPO: ${ENABLE_IPO}")

##########################
## Create Jet target
##########################

add_library(Jet INTERFACE)
target_include_directories(Jet INTERFACE
target_include_directories(Jet INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
${BLAS_INCLUDE_DIRS}
)
Expand All @@ -137,24 +137,47 @@ if (ENABLE_OPENMP AND OPENMP_FOUND)
elseif (ENABLE_OPENMP AND NOT OPENMP_FOUND)
message(FATAL_ERROR "\nOpenMP is enabled but could not be found")
endif()

if(ENABLE_SANITIZERS)
target_compile_options(Jet INTERFACE -g -fsanitize=address,undefined)
target_link_options(Jet INTERFACE -fsanitize=address,undefined)
endif()

if(ENABLE_WARNINGS)
target_compile_options(Jet INTERFACE -Wall -Wextra -Werror)
endif()

if(ENABLE_NATIVE)
target_compile_options(Jet INTERFACE -march=native)
endif()

if(ENABLE_IPO)
target_compile_options(Jet INTERFACE -flto)
endif()

##########################
## Build tests
## Report
##########################

message(STATUS "BLAS_INCLUDE_DIRS: ${BLAS_INCLUDE_DIRS}")
message(STATUS "BLAS_LIBRARIES: ${BLAS_LIBRARIES}")
message(STATUS "BUILD_PYTHON: ${BUILD_PYTHON}")
message(STATUS "BUILD_TESTS: ${BUILD_TESTS}")
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(STATUS "ENABLE_IPO: ${ENABLE_IPO}")
message(STATUS "ENABLE_NATIVE: ${ENABLE_NATIVE}")
message(STATUS "ENABLE_SANITIZERS: ${ENABLE_SANITIZERS}")
message(STATUS "ENABLE_WARNINGS: ${ENABLE_WARNINGS}")

##########################
## Build targets
##########################

if(BUILD_PYTHON)
pybind11_add_module(jet python/src/Python.cpp)
target_link_libraries(jet PRIVATE Jet)
endif()

if(BUILD_TESTS)
enable_testing()
add_subdirectory(test)
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ help:
.PHONY: format
format:
ifdef check
./bin/format --check include test
./bin/format --check include python test
Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved
else
./bin/format include test
./bin/format include python test
Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved
endif


Expand Down
50 changes: 50 additions & 0 deletions python/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.VENV_DIR=.venv
.VENV_BIN=$(.VENV_DIR)/bin

python=python3

define HELP_BODY
Please use 'make [target]'.

TARGETS

setup [python=<path>] Set up virtualenv using the Python interpreter at <path>, defaults to $(python)
Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved

test [args=<pytest args>] Run tests; use with 'args=<pytest args>' to pass test arguments

format [check=1] Apply formatters; use with 'check=1' to check instead of modify

clean Remove all build artifacts

endef

.PHONY: help
help:
@: $(info $(HELP_BODY))

.PHONY: setup
setup: $(.VENV_DIR)/requirements_test.txt.touch

.PHONY: format
format:
ifdef check
$(.VENV_BIN)/black --check tests && $(.VENV_BIN)/isort --profile black --check-only tests
else
$(.VENV_BIN)/black tests && $(.VENV_BIN)/isort --profile black tests
endif

.PHONY: test
test: $(.VENV_DIR)/requirements_test.txt.touch
PYTHONPATH="../build" $(.VENV_BIN)/python -m pytest ./tests $(args)

.PHONY: clean
clean:
rm -rf $(.VENV_DIR)

$(.VENV_DIR)/requirements_test.txt.touch: $(.VENV_DIR)/touch requirements_test.txt
$(.VENV_DIR)/bin/pip install -r requirements_test.txt
@touch $@

$(.VENV_DIR)/touch:
$(python) -m venv ${.VENV_DIR}
@touch $@
3 changes: 3 additions & 0 deletions python/requirements_test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
black
isort>5
pytest>=5,<6
11 changes: 11 additions & 0 deletions python/src/Python.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <pybind11/pybind11.h>

#include "Version.hpp"

PYBIND11_MODULE(jet, m)
{
m.doc() = "Jet is a library for simulating quantum circuits using tensor "
"network contractions.";

AddBindingsForVersion(m);
}
22 changes: 22 additions & 0 deletions python/src/Version.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <pybind11/pybind11.h>

#include <Jet.hpp>

namespace py = pybind11;

/**
* @brief Adds Python bindings for the include/jet/Version.hpp file.
*
* @param m Jet pybind11 module.
*/
void AddBindingsForVersion(py::module_ &m)
{
m.attr("__version__") = Jet::Version();

m.def("version", Jet::Version, R"(
Returns the current Jet version.

Returns:
String representation of the current Jet version.
)");
}
14 changes: 14 additions & 0 deletions python/tests/test_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import re

import jet


class TestVersion:
def test_attribute(self):
"""Tests that the version attribute has the correct form."""
semver_pattern = re.compile(r"^\d+\.\d+\.\d+$")
assert semver_pattern.match(jet.__version__)

def test_function(self):
"""Tests that the version attribute matches the version function."""
assert jet.__version__ == jet.version()