From e124c40d0b07a509a379e80c58ea7b2b64a107b9 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 20 Feb 2018 14:04:05 -0600 Subject: [PATCH 1/6] setup: switch to scikit-build --- setup.py | 230 +++++-------------------------------------------------- 1 file changed, 20 insertions(+), 210 deletions(-) diff --git a/setup.py b/setup.py index f8cfd5859..04cca9696 100644 --- a/setup.py +++ b/setup.py @@ -1,217 +1,28 @@ from __future__ import print_function -from os import getenv, path, makedirs + import os -import subprocess +import shlex import sys -from distutils.command.build_ext import build_ext as _build_ext -from distutils.command.build import build as _build - -# Make sure the system has the right Python version. -if sys.version_info[:2] < (2, 7): - print("SymEngine requires Python 2.7 or newer. " - "Python %d.%d detected" % sys.version_info[:2]) - sys.exit(-1) - -# use setuptools by default as per the official advice at: -# packaging.python.org/en/latest/current.html#packaging-tool-recommendations -use_setuptools = True -# set the environment variable USE_DISTUTILS=True to force the use of distutils -use_distutils = getenv('USE_DISTUTILS') -if use_distutils is not None: - if use_distutils.lower() == 'true': - use_setuptools = False - else: - print("Value {} for USE_DISTUTILS treated as False". - format(use_distutils)) - -if use_setuptools: - try: - from setuptools import setup - from setuptools.command.install import install as _install - except ImportError: - use_setuptools = False - -if not use_setuptools: - from distutils.core import setup - from distutils.command.install import install as _install - -cmake_opts = [("PYTHON_BIN", sys.executable), - ("CMAKE_INSTALL_RPATH_USE_LINK_PATH", "yes")] -cmake_generator = [None] -cmake_build_type = ["Release"] - - -def process_opts(opts): - return ['-D'+'='.join(o) for o in opts] - - -def get_build_dir(dist): - source_dir = path.dirname(path.realpath(__file__)) - build = dist.get_command_obj('build') - build_ext = dist.get_command_obj('build_ext') - return source_dir if build_ext.inplace else build.build_platlib - - -global_user_options = [ - ('symengine-dir=', None, - 'path to symengine installation or build directory'), - ('generator=', None, 'cmake build generator'), - ('build-type=', None, 'build type: Release or Debug'), - ('define=', 'D', - 'options to cmake :='), -] - -def _process_define(arg): - (defs, one), = getattr(arg, 'define', None) or [('', '1')] - assert one == '1' - defs = [df for df in defs.split(';') if df != ''] - return [(s.strip(), None) if '=' not in s else - tuple(ss.strip() for ss in s.split('=')) - for s in defs] - - -class BuildWithCmake(_build): - sub_commands = [('build_ext', None)] - - -class BuildExtWithCmake(_build_ext): - _build_opts = _build_ext.user_options - user_options = list(global_user_options) - user_options.extend(_build_opts) - - def initialize_options(self): - _build_ext.initialize_options(self) - self.define = None - self.symengine_dir = None - self.generator = None - self.build_type = "Release" - - def finalize_options(self): - _build_ext.finalize_options(self) - # The argument parsing will result in self.define being a string, but - # it has to be a list of 2-tuples. - # Multiple symbols can be separated with semi-colons. - self.define = _process_define(self) - cmake_opts.extend(self.define) - if self.symengine_dir: - cmake_opts.extend([('SymEngine_DIR', self.symengine_dir)]) - - if self.generator: - cmake_generator[0] = self.generator - - cmake_build_type[0] = self.build_type - - def cmake_build(self): - source_dir = path.dirname(path.realpath(__file__)) - build_dir = get_build_dir(self.distribution) - if not path.exists(build_dir): - makedirs(build_dir) - if build_dir != source_dir and path.exists("CMakeCache.txt"): - os.remove("CMakeCache.txt") - - cmake_cmd = ["cmake", source_dir, - "-DCMAKE_BUILD_TYPE=" + cmake_build_type[0]] - cmake_cmd.extend(process_opts(cmake_opts)) - if not path.exists(path.join(build_dir, "CMakeCache.txt")): - cmake_cmd.extend(self.get_generator()) - if subprocess.call(cmake_cmd, cwd=build_dir) != 0: - raise EnvironmentError("error calling cmake") - - if subprocess.call(["cmake", "--build", ".", - "--config", cmake_build_type[0]], - cwd=build_dir) != 0: - raise EnvironmentError("error building project") - - def get_generator(self): - if cmake_generator[0]: - return ["-G", cmake_generator[0]] - else: - import platform - import sys - if (platform.system() == "Windows"): - compiler = str(self.compiler).lower() - if ("msys" in compiler): - return ["-G", "MSYS Makefiles"] - elif ("mingw" in compiler): - return ["-G", "MinGW Makefiles"] - elif sys.maxsize > 2**32: - return ["-G", "Visual Studio 14 2015 Win64"] - else: - return ["-G", "Visual Studio 14 2015"] - return [] - - def run(self): - self.cmake_build() - # can't use super() here because - # _build_ext is an old style class in 2.7 - _build_ext.run(self) - - -class InstallWithCmake(_install): - _install_opts = _install.user_options - user_options = list(global_user_options) - user_options.extend(_install_opts) - - def initialize_options(self): - _install.initialize_options(self) - self.define = None - self.symengine_dir = None - self.generator = None - self.build_type = "Release" - - def finalize_options(self): - _install.finalize_options(self) - # The argument parsing will result in self.define being a string, but - # it has to be a list of 2-tuples. - # Multiple symbols can be separated with semi-colons. - self.define = _process_define(self) - cmake_opts.extend(self.define) - cmake_build_type[0] = self.build_type - cmake_opts.extend([('PYTHON_INSTALL_PATH', path.join(os.getcwd(), self.install_platlib))]) - #cmake_opts.extend([('PYTHON_INSTALL_HEADER_PATH', - # path.join(os.getcwd(), self.install_headers))]) - - def cmake_install(self): - source_dir = path.dirname(path.realpath(__file__)) - build_dir = get_build_dir(self.distribution) - cmake_cmd = ["cmake", source_dir] - cmake_cmd.extend(process_opts(cmake_opts)) - - # CMake has to be called here to update PYTHON_INSTALL_PATH - # if build and install were called separately by the user - if subprocess.call(cmake_cmd, cwd=build_dir) != 0: - raise EnvironmentError("error calling cmake") - - if subprocess.call(["cmake", "--build", ".", - "--config", cmake_build_type[0], - "--target", "install"], - cwd=build_dir) != 0: - raise EnvironmentError("error installing") - - import compileall - compileall.compile_dir(path.join(self.install_platlib, "symengine")) - - def run(self): - # can't use super() here because _install is an old style class in 2.7 - _install.run(self) - self.cmake_install() - -cmdclass={ - 'build': BuildWithCmake, - 'build_ext': BuildExtWithCmake, - 'install': InstallWithCmake, - } try: - from wheel.bdist_wheel import bdist_wheel - class BdistWheelWithCmake(bdist_wheel): - def finalize_options(self): - bdist_wheel.finalize_options(self) - self.root_is_pure = False - cmdclass["bdist_wheel"] = BdistWheelWithCmake + from skbuild import setup except ImportError: - pass - + print('scikit-build is required to build from source.', file=sys.stderr) + print('Please run:', file=sys.stderr) + print('', file=sys.stderr) + print(' python -m pip install scikit-build') + sys.exit(1) + +from setuptools import find_packages + +# BEGIN +# TODO: remove hack when py27 is dropped +from skbuild.platform_specifics import windows + +if sys.version_info < (3, 0): + windows._get_msvc_compiler_env = lambda _ : {} +# END + long_description = ''' SymEngine is a standalone fast C++ symbolic manipulation library. Optional thin Python wrappers (SymEngine) allow easy usage from Python and @@ -225,13 +36,12 @@ def finalize_options(self): setup(name="symengine", version="0.3.0", description="Python library providing wrappers to SymEngine", - setup_requires=['cython>=0.19.1'], long_description=long_description, + packages=find_packages(), author="SymEngine development team", author_email="symengine@googlegroups.com", license="MIT", url="https://github.com/symengine/symengine.py", - cmdclass = cmdclass, classifiers=[ 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', From 59e7249b69e277906858474170bbd96b5eba686b Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 20 Feb 2018 14:04:13 -0600 Subject: [PATCH 2/6] gitignore: add _skbuild --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5596947ed..cd0a08bd9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ symengine.egg-info/ # Temp files *~ .eggs/ + +_skbuild \ No newline at end of file From 42e936bcbfe6489b312c81b8b2c578530f62d4a8 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 20 Feb 2018 14:05:14 -0600 Subject: [PATCH 3/6] appveyor: remove mingw configuration from tests The MinGW configuration is removed completely to ease maintenance, and MSVC 2015 is used to compile on Python 2.7. --- appveyor.yml | 60 ++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index b0ddc7f3f..21d4c6c7a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,13 +9,6 @@ environment: PLATFORMTOOLSET: "v140" matrix: - - BUILD_TYPE: "Release" - COMPILER: MSVC15 - PLATFORM: "Win32" - PYTHON_VERSION: 27 - CONDA_INSTALL_LOCN: C:\\Miniconda35 - WITH_MPFR: yes - WITH_MPC: yes - BUILD_TYPE: "Release" COMPILER: MSVC15 PLATFORM: "x64" @@ -36,33 +29,39 @@ environment: # COMPILER: MinGW # PYTHON_VERSION: 35 - BUILD_TYPE: "Release" - COMPILER: MinGW-w64 - PYTHON_VERSION: 27-x64 - - BUILD_TYPE: "Debug" - COMPILER: MinGW-w64 - PYTHON_VERSION: 35-x64 - WITH_NUMPY: no - - BUILD_TYPE: "Debug" - COMPILER: MinGW-w64 - PYTHON_VERSION: 36-x64 - WITH_SYMPY: no + COMPILER: MSVC15 + PLATFORM: "Win32" + PYTHON_VERSION: 27 + CONDA_INSTALL_LOCN: C:\\Miniconda35 + WITH_MPFR: yes + WITH_MPC: yes +# - BUILD_TYPE: "Debug" +# COMPILER: MinGW-w64 +# PYTHON_VERSION: 35-x64 +# WITH_NUMPY: no +# - BUILD_TYPE: "Debug" +# COMPILER: MinGW-w64 +# PYTHON_VERSION: 36-x64 +# WITH_SYMPY: no install: - set PYTHON_SOURCE_DIR=%CD% - git clone https://github.com/sympy/symengine symengine-cpp - if [%COMPILER%]==[MSVC15] call %CONDA_INSTALL_LOCN%\Scripts\activate.bat -- if [%COMPILER%]==[MSVC15] conda update --yes --quiet conda + - if [%COMPILER%]==[MSVC15] conda config --add channels conda-forge - if [%COMPILER%]==[MSVC15] if [%BUILD_TYPE%]==[Debug] conda config --add channels symengine/label/debug -- if [%COMPILER%]==[MSVC15] conda create -n test --yes mpir=3.0.0 vc=14 -- if [%COMPILER%]==[MSVC15] call activate test -- if [%COMPILER%]==[MSVC15] if [%WITH_MPFR%]==[yes] conda install --yes mpfr=3.1.5 -- if [%COMPILER%]==[MSVC15] if [%WITH_MPC%]==[yes] conda install --yes mpc=1.0.3 -- if [%COMPILER%]==[MSVC15] if [%WITH_LLVM%]==[yes] conda install --yes llvmdev=3.9 + +- if [%COMPILER%]==[MSVC15] if [%WITH_MPFR%]==[yes] set MPFR_SPEC="mpfr=3.1.5" +- if [%COMPILER%]==[MSVC15] if [%WITH_MPC%]==[yes] set MPC_SPEC="mpc=1.0.3" +- if [%COMPILER%]==[MSVC15] if [%WITH_LLVM%]==[yes] set LLVM_SPEC="llvmdev=3.9" + +- if [%COMPILER%]==[MSVC15] conda install --yes mpir=3.0.0 vc=14 ninja %MPFR_SPEC% %MPC_SPEC% %LLVM_SPEC% - if [%COMPILER%]==[MinGW] set PATH=C:\MinGW\bin;%PATH% - if [%COMPILER%]==[MinGW] mingw-get update + # workaround for https://github.com/appveyor/ci/issues/996 - if [%COMPILER%]==[MinGW] mingw-get upgrade mingw32-libstdc++ - if [%COMPILER%]==[MinGW] mingw-get install mingw32-gmp @@ -92,8 +91,11 @@ install: - mkdir build - cd build -- if [%COMPILER%]==[MSVC15] if [%PLATFORM%]==[Win32] cmake -G "Visual Studio 14 2015" -DCMAKE_PREFIX_PATH=%CONDA_PREFIX%\Library .. -- if [%COMPILER%]==[MSVC15] if [%PLATFORM%]==[x64] cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_PREFIX_PATH=%CONDA_PREFIX%\Library .. +- if [%COMPILER%]==[MSVC15] if [%PLATFORM%]==[Win32] call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 +- if [%COMPILER%]==[MSVC15] if [%PLATFORM%]==[x64] call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 + +- if [%COMPILER%]==[MSVC15] cmake -G "Ninja" -DCMAKE_PREFIX_PATH=%CONDA_PREFIX%\Library -DCMAKE_BUILD_TYPE=%BUILD_TYPE% .. + - if [%COMPILER%]==[MinGW] cmake -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=C:\MinGW -DCMAKE_BUILD_TYPE=%BUILD_TYPE% .. - if [%COMPILER%]==[MinGW-w64] cmake -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=C:\mingw64 -DCMAKE_BUILD_TYPE=%BUILD_TYPE% .. @@ -101,14 +103,16 @@ install: - if [%WITH_MPC%]==[yes] cmake -DWITH_MPC=yes .. - if [%WITH_LLVM%]==[yes] cmake -DWITH_LLVM=yes -DMSVC_USE_MT=no .. -- cmake -DBUILD_SHARED_LIBS=yes -DBUILD_TESTS=no -DBUILD_BENCHMARKS=no -DCMAKE_INSTALL_PREFIX=C:\symengine .. +- cmake -DBUILD_SHARED_LIBS=yes -DBUILD_TESTS=no -DBUILD_BENCHMARKS=no -DCMAKE_INSTALL_PREFIX=C:\symengine .. -- cmake --build . --config %BUILD_TYPE% --target install +- cmake --build . --target install - cd ../../ +- python -m pip install scikit-build + build_script: - set PATH=C:\symengine\bin\;%PATH% -- if [%COMPILER%]==[MSVC15] python setup.py install build_ext --compiler=msvc --build-type=%BUILD_TYPE% +- if [%COMPILER%]==[MSVC15] python -m pip install -vvv . - if [%COMPILER%]==[MinGW] python setup.py install build_ext --compiler=mingw --inplace - if [%COMPILER%]==[MinGW-w64] python setup.py install build_ext --compiler=mingw --inplace From ae598cb8c892f1cdb7a99d79075c1aa059afc5fc Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 20 Feb 2018 14:05:28 -0600 Subject: [PATCH 4/6] Travis: remove 3.3 tests, as it's EOL --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0fe382d3d..6336789cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,6 @@ env: # Release builds: - PYTHON_VERSION="2.7" BUILD_SHARED_LIBS="yes" - PYTHON_VERSION="2.7" WITH_MPFR="yes" INTEGER_CLASS="gmpxx" WITH_NUMPY="no" - - PYTHON_VERSION="3.3" WITH_MPC="yes" - PYTHON_VERSION="3.4" WITH_MPFR="yes" - PYTHON_VERSION="3.5" WITH_MPC="yes" - PYTHON_VERSION="3.6" WITH_MPC="yes" INTEGER_CLASS="flint" WITH_FLINT="yes" From 641c8d0efc26982d3bf1cad7d08fa3f1133ae0b4 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 20 Feb 2018 14:05:44 -0600 Subject: [PATCH 5/6] Install build requirements and use pip --- bin/test_travis.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/test_travis.sh b/bin/test_travis.sh index 7dd176455..ffab0dcd3 100755 --- a/bin/test_travis.sh +++ b/bin/test_travis.sh @@ -6,7 +6,9 @@ set -e set -x # Build inplace so that nosetests can be run inside source directory -python setup.py install build_ext --inplace --symengine-dir=$our_install_dir +pip install -U pip +pip install -U cython scikit-build +pip install -vvv -e . # Test python wrappers nosetests -v From eb1eb447ecd40def582c02ac1661245754f22b16 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 20 Feb 2018 14:05:53 -0600 Subject: [PATCH 6/6] CMake: Install to correct directory --- symengine/CMakeLists.txt | 2 +- symengine/lib/CMakeLists.txt | 4 ++-- symengine/tests/CMakeLists.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/symengine/CMakeLists.txt b/symengine/CMakeLists.txt index 224d1c99e..637e73758 100644 --- a/symengine/CMakeLists.txt +++ b/symengine/CMakeLists.txt @@ -1,7 +1,7 @@ add_subdirectory(lib) add_subdirectory(tests) -set(PY_PATH ${PYTHON_INSTALL_PATH}/symengine) +set(PY_PATH symengine) install(FILES __init__.py utilities.py compatibility.py sympy_compat.py functions.py printing.py DESTINATION ${PY_PATH} ) diff --git a/symengine/lib/CMakeLists.txt b/symengine/lib/CMakeLists.txt index 86a5060ce..60181cb2b 100644 --- a/symengine/lib/CMakeLists.txt +++ b/symengine/lib/CMakeLists.txt @@ -22,7 +22,7 @@ add_custom_target(cython COMMAND cython symengine_wrapper.pyx ) -set(PY_PATH ${PYTHON_INSTALL_PATH}/symengine/lib) +set(PY_PATH symengine/lib) install(TARGETS symengine_wrapper RUNTIME DESTINATION ${PY_PATH} ARCHIVE DESTINATION ${PY_PATH} @@ -37,5 +37,5 @@ install(FILES __init__.py install(FILES pywrapper.h - DESTINATION ${PYTHON_INSTALL_PATH}/symengine/lib + DESTINATION symengine/lib ) diff --git a/symengine/tests/CMakeLists.txt b/symengine/tests/CMakeLists.txt index ebd4dfaa2..5a2009988 100644 --- a/symengine/tests/CMakeLists.txt +++ b/symengine/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -set(PY_PATH ${PYTHON_INSTALL_PATH}/symengine/tests) +set(PY_PATH symengine/tests) install(FILES __init__.py test_arit.py test_dict_basic.py