From f889d7d1510ac9d4948c0d70a8bc3f16ad6582bb Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 4 Jun 2016 16:03:23 +0200 Subject: [PATCH 1/3] Update readme and remove old license --- .gitignore | 1 + CMakeLists.txt | 3 +-- README.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ license.md | 24 ----------------- pybind11 | 2 +- readme.md | 17 ------------ 6 files changed, 74 insertions(+), 44 deletions(-) create mode 100644 README.md delete mode 100644 license.md delete mode 100644 readme.md diff --git a/.gitignore b/.gitignore index 5eb1135..c3ae3cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +dist/ *.so *.py[cod] *.egg-info diff --git a/CMakeLists.txt b/CMakeLists.txt index 0763a57..31449ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 2.8.12) -project(pybind11_cmake_example) +project(cmake_example) add_subdirectory(pybind11) - pybind11_add_module(cmake_example src/main.cpp) diff --git a/README.md b/README.md new file mode 100644 index 0000000..6493c4d --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# cmake_example for pybind11 + +[![Build Status](https://travis-ci.org/pybind/cmake_example.svg?branch=master)](https://travis-ci.org/pybind/cmake_example) +[![Build status](https://ci.appveyor.com/api/projects/status/8gtjyogdmy9amqm1/branch/master?svg=true)](https://ci.appveyor.com/project/dean0x7d/cmake-example/branch/master) + +An example [pybind11](https://github.com/pybind/pybind11) module built with a +CMake-based build system. This is useful for C++ codebases that have an existing +CMake project structure. + + +## Prerequisites + +**On Unix (Linux, OS X)** + +* A compiler with C++11 support +* CMake >= 2.8.12 + +**On Windows** + +* Visual Studio 2015 (required for all Python versions, see notes below) +* CMake >= 3.1 + + +## Installation + +Just clone this repository and pip install. Note the `--recursive` option which is +needed for the pybind11 submodule: + +```bash +git clone --recursive https://github.com/pybind/cmake_example.git +pip install ./cmake_example +``` + +With the `setup.py` file included in this example, the `pip install` command will +invoke CMake and build the pybind11 module as specified in `CMakeLists.txt`. + + +## Special notes for Windows + +**Compiler requirements** + +Pybind11 requires a C++11 compliant compiler, i.e Visual Studio 2015 on Windows. +This applies to all Python versions, including 2.7. Unlike regular C extension +modules, it's perfectly fine to compile a pybind11 module with a VS version newer +than the target Python's VS version. See the [FAQ] for more details. + +**Runtime requirements** + +The Visual C++ 2015 redistributable packages are a runtime requirement for this +project. It can be found [here][vs2015_runtime]. If you use the Anaconda Python +distribution, you can add `vs2015_runtime` as a platform-dependent runtime +requirement for you package: see the `conda.recipe/meta.yaml` file in this example. + + +## License + +Pybind11 is provided under a BSD-style license that can be found in the LICENSE +file. By using, distributing, or contributing to this project, you agree to the +terms and conditions of this license. + + +## Test call + +```python +import cmake_example +cmake_example.add(1, 2) +``` + + +[FAQ]: http://pybind11.rtfd.io/en/latest/faq.html#working-with-ancient-visual-studio-2009-builds-on-windows +[vs2015_runtime]: https://www.microsoft.com/en-us/download/details.aspx?id=48145 diff --git a/license.md b/license.md deleted file mode 100644 index 42a65e4..0000000 --- a/license.md +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2016, Dean Moldovan - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pybind11 b/pybind11 index 0a07805..19d95ef 160000 --- a/pybind11 +++ b/pybind11 @@ -1 +1 @@ -Subproject commit 0a07805ab663b981d72bbe2663b946f8c18e67cf +Subproject commit 19d95ef09a384d6631308161ead24e5a230c9bf8 diff --git a/readme.md b/readme.md deleted file mode 100644 index 4e69340..0000000 --- a/readme.md +++ /dev/null @@ -1,17 +0,0 @@ -## Building pybind11 modules with CMake - -An example of building a Python extension using [pybind11](https://github.com/pybind/pybind11) and CMake. -This is useful for C++ codebases that already have an existing CMake-based build system. - -### Install - -1. Make sure CMake >= 2.8.12 is installed on your system -2. Clone this repository -3. `pip install ./pybind11_cmake_example` - -### Test - -```python -import cmake_example -cmake_example.add(1, 2) -``` From 0a8d583cd02550c08a2f0bd87eeb6af2254d73ab Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 4 Jun 2016 16:23:04 +0200 Subject: [PATCH 2/3] Improve CI tests - Test sdist package on all platforms - Include Python 2.7 and 32-bit versions on Windows --- .appveyor.yml | 9 ++++++--- .travis.yml | 5 +++-- MANIFEST.in | 4 ++++ test.py | 3 --- tests/test.py | 3 +++ 5 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 MANIFEST.in delete mode 100644 test.py create mode 100644 tests/test.py diff --git a/.appveyor.yml b/.appveyor.yml index 5c1d56e..0c6d117 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,11 +2,14 @@ version: 1.0.{build} image: Visual Studio 2015 environment: matrix: + - PATH: C:\Python27\;C:\Python27\Scripts\;%PATH% + - PATH: C:\Python27-x64\;C:\Python27-x64\Scripts\;%PATH% + - PATH: C:\Python35\;C:\Python35\Scripts\;%PATH% - PATH: C:\Python35-x64\;C:\Python35-x64\Scripts\;%PATH% - - PATH: C:\Miniconda35-x64\;C:\Miniconda35-x64\Scripts\;%PATH% install: - cmd: git submodule update -q --init --recursive build_script: -- cmd: pip install . +- cmd: python setup.py sdist +- cmd: pip install dist\cmake_example-0.0.1.zip test_script: -- cmd: python test.py +- cmd: python tests\test.py diff --git a/.travis.yml b/.travis.yml index b2bd571..943df2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ before_install: - virtualenv -p python$PYTHON venv - source venv/bin/activate install: -- pip install . +- python setup.py sdist +- pip install dist/*.tar.gz script: -- python test.py +- python tests/test.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..99c01b3 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +include README.md LICENSE +global-include CMakeLists.txt *.cmake +recursive-include src * +recursive-include pybind11/include *.h diff --git a/test.py b/test.py deleted file mode 100644 index dbdedcc..0000000 --- a/test.py +++ /dev/null @@ -1,3 +0,0 @@ -import cmake_example - -print(cmake_example.add(1, 2)) diff --git a/tests/test.py b/tests/test.py new file mode 100644 index 0000000..4d11657 --- /dev/null +++ b/tests/test.py @@ -0,0 +1,3 @@ +from cmake_example import add + +assert add(1, 2) == 3 From 1b978218566d0ce45b1c28b248acbdd039076854 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 4 Jun 2016 18:31:09 +0200 Subject: [PATCH 3/3] Improve CMake extension builder in setup.py - Better conform to build_ext directory structure - Select build type according to build_ext '-g' flag - Check for CMake >= 3.1 on Windows --- .appveyor.yml | 2 +- .travis.yml | 2 +- setup.py | 56 ++++++++++++++++++++++++++++++--------------------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 0c6d117..76c61b8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,6 +10,6 @@ install: - cmd: git submodule update -q --init --recursive build_script: - cmd: python setup.py sdist -- cmd: pip install dist\cmake_example-0.0.1.zip +- cmd: pip install --verbose dist\cmake_example-0.0.1.zip test_script: - cmd: python tests\test.py diff --git a/.travis.yml b/.travis.yml index 943df2c..f6d7d44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,6 @@ before_install: - source venv/bin/activate install: - python setup.py sdist -- pip install dist/*.tar.gz +- pip install --verbose dist/*.tar.gz script: - python tests/test.py diff --git a/setup.py b/setup.py index bd6d642..73ae4a6 100644 --- a/setup.py +++ b/setup.py @@ -1,47 +1,57 @@ import os +import re import sys import platform import subprocess from setuptools import setup, Extension from setuptools.command.build_ext import build_ext -from distutils.spawn import find_executable +from distutils.version import LooseVersion class CMakeExtension(Extension): def __init__(self, name, sourcedir=''): Extension.__init__(self, name, sources=[]) - self.sourcedir = sourcedir + self.sourcedir = os.path.abspath(sourcedir) class CMakeBuild(build_ext): def run(self): - if find_executable('cmake') is None: - print("CMake must be installed to build this extension") - sys.exit(-1) + try: + out = subprocess.check_output(['cmake', '--version']) + except OSError: + raise RuntimeError("CMake must be installed to build the following extensions: " + + ", ".join(e.name for e in self.extensions)) + + if platform.system() == "Windows": + cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) + if cmake_version < '3.1.0': + raise RuntimeError("CMake >= 3.1.0 is required on Windows") for ext in self.extensions: - build_dir = os.path.join(os.path.dirname(__file__), 'build', 'cmake') - if not os.path.exists(build_dir): - os.makedirs(build_dir) - cmake_dir = os.path.abspath(ext.sourcedir) + self.build_extension(ext) - extpath = self.get_ext_fullpath(ext.name) - extfulldir = os.path.abspath(os.path.dirname(extpath)) - cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extfulldir, - '-DPYTHON_EXECUTABLE=' + sys.executable] - build_args = ['--config', 'Release'] + def build_extension(self, ext): + extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) + cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, + '-DPYTHON_EXECUTABLE=' + sys.executable] - if platform.system() == "Windows": - cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE=' + extfulldir] - if sys.maxsize > 2**32: - cmake_args += ['-A', 'x64'] - build_args += ['--', '/m'] - else: - build_args += ['--', '-j2'] + cfg = 'Debug' if self.debug else 'Release' + build_args = ['--config', cfg] - subprocess.check_call(['cmake', cmake_dir] + cmake_args, cwd=build_dir) - subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=build_dir) + if platform.system() == "Windows": + cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] + if sys.maxsize > 2**32: + cmake_args += ['-A', 'x64'] + build_args += ['--', '/m'] + else: + cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] + build_args += ['--', '-j2'] + + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp) + subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp) setup( name='cmake_example',