diff --git a/.gitignore b/.gitignore index f93c02277..97c741ae7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ cython_test.cpp symengine/lib/symengine_wrapper.cpp symengine/lib/symengine_wrapper.pyx symengine/lib/symengine_wrapper.pxd +symengine/_version.py # Config Files symengine/lib/config.pxi @@ -33,6 +34,12 @@ MANIFEST dist/ .*cache/ symengine.egg-info/ +.cmake/ +.ninja_deps +.ninja_log +.skbuild-info.json +CMakeInit.txt +symengine/lib/symengine_wrapper.cpp.dep # Temp files *~ diff --git a/CMakeLists.txt b/CMakeLists.txt index cc990c4ee..7e3dd896d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.12...4.0.0) +cmake_minimum_required(VERSION 3.21...4.0.0) if (POLICY CMP0057) cmake_policy(SET CMP0057 NEW) # needed for llvm >= 16 @@ -7,7 +7,7 @@ if (POLICY CMP0074) cmake_policy(SET CMP0074 NEW) # allow user to set *_ROOT variables endif() -project(python_wrapper) +project(${SKBUILD_PROJECT_NAME} LANGUAGES C CXX) set(CMAKE_PREFIX_PATH ${SymEngine_DIR} ${CMAKE_PREFIX_PATH}) @@ -21,13 +21,28 @@ set(CMAKE_BUILD_TYPE ${SYMENGINE_BUILD_TYPE}) set(CMAKE_CXX_FLAGS_RELEASE ${SYMENGINE_CXX_FLAGS_RELEASE}) set(CMAKE_CXX_FLAGS_DEBUG ${SYMENGINE_CXX_FLAGS_DEBUG}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SYMENGINE_CXX_FLAGS}") -include_directories(${SYMENGINE_INCLUDE_DIRS}) -set(WITH_PY_LIMITED_API OFF CACHE STRING "Use CPython's limited API") -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") -find_package(Python REQUIRED) -find_package(Cython REQUIRED) -include_directories(${PYTHON_INCLUDE_PATH}) +find_package( + Python + COMPONENTS + Interpreter + Development.Module + ${SKBUILD_SABI_COMPONENT} + REQUIRED +) + +if ("${SKBUILD_SABI_VERSION}" STREQUAL "") + set(CYTHON_MIN "0.29") +else() + set(CYTHON_MIN "3.1") +endif() + +find_package(Cython ${CYTHON_MIN} MODULE REQUIRED) +include(UseCython) + +if ("${CYTHON_VERSION}" VERSION_LESS "${CYTHON_MIN}") + message(FATAL_ERROR "Cython version found: ${CYTHON_VERSION}. Minimum required: ${CYTHON_MIN}") +endif() if (MINGW AND ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DMS_WIN64") @@ -56,7 +71,6 @@ foreach (PKG MPC MPFR PIRANHA FLINT LLVM) set(HAVE_SYMENGINE_${PKG} False) endif() endforeach() -option(SYMENGINE_INSTALL_PY_FILES "Install python files" ON) message("CMAKE_SYSTEM_PROCESSOR : ${CMAKE_SYSTEM_PROCESSOR}") message("CMAKE_BUILD_TYPE : ${CMAKE_BUILD_TYPE}") @@ -69,9 +83,5 @@ message("HAVE_SYMENGINE_PIRANHA : ${HAVE_SYMENGINE_PIRANHA}") message("HAVE_SYMENGINE_FLINT : ${HAVE_SYMENGINE_FLINT}") message("HAVE_SYMENGINE_LLVM : ${HAVE_SYMENGINE_LLVM}") message("HAVE_SYMENGINE_LLVM_LONG_DOUBLE : ${HAVE_SYMENGINE_LLVM_LONG_DOUBLE}") -message("SYMENGINE_COPY_EXTENSION : ${SYMENGINE_COPY_EXTENSION}") - -message("Copying source of python wrappers into: ${CMAKE_CURRENT_BINARY_DIR}") -file(COPY symengine/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/symengine) add_subdirectory(symengine) diff --git a/README.md b/README.md index e13eb7272..39d5b7886 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,14 @@ conda install python-symengine -c conda-forge Install prerequisites. ```bash -CMake >= 2.8.12 -Python3 >= 3.8 -Cython >= 0.29.24 -SymEngine >= 0.7.0 +CMake >= 3.21 +Python3 >= 3.9 +SymEngine >= 0.14.0 +pip +setuptools_scm # will be automatically downloaded by pip +scikit-build-core # will be automatically downloaded by pip +cython >= 0.29.24 # will be automatically downloaded by pip +cython-cmake # will be automatically downloaded by pip ``` For **SymEngine**, only a specific commit/tag (see `symengine_version.txt`) is @@ -40,25 +44,22 @@ changes in **SymEngine**. Python wrappers can be installed by, ```bash -python setup.py install +pip install . -vv ``` -Additional options to `setup.py` are: - +If you are building SymEngine for development, you should implement +the dependencies automatically installed by pip and do, ```bash -python setup.py install build_ext - --symengine-dir=/path/to/symengine/install/dir # Path to SymEngine install directory or build directory - --compiler=mingw32|msvc|cygwin # Select the compiler for Windows - --generator=cmake-generator # CMake Generator - --build-type=Release|Debug # Set build-type for multi-configuration generators like MSVC - --define="var1=value1;var2=value2" # Give options to CMake - --inplace # Build the extension in source tree +pip install -e . -vv --no-build-isolation ``` -Standard options to `setup.py` like `--user`, `--prefix` can be used to -configure install location. NumPy is used if found by default, if you wish -to make your choice of NumPy use explicit: then add -e.g. `WITH_NUMPY=False` to `--define`. +A few additional options to scikit-build-core are mentioned here: + +```bash +pip install -e . -vv --no-build-isolation + -Ccmake.build-type=Release|Debug # Set build-type for multi-configuration generators like MSVC + -Ccmake.define.SymEngine_DIR=/path/to/symengine/install/dir # Path to SymEngine install directory or build directory +``` ### Notes on Dependencies diff --git a/appveyor.yml b/appveyor.yml index 52e44eb57..cdf0ee1b1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,17 +38,6 @@ environment: PYTHON_VERSION: 311-x64 WITH_NUMPY: no CONDA_INSTALL_LOCN: C:\\Miniconda38-x64 - #- BUILD_TYPE: "Debug" - # COMPILER: MinGW-w64 - # PYTHON_VERSION: 39-x64 - # WITH_NUMPY: no - #- BUILD_TYPE: "Release" - # COMPILER: MinGW-w64 - # PYTHON_VERSION: 39-x64 - #- BUILD_TYPE: "Debug" - # COMPILER: MinGW-w64 - # PYTHON_VERSION: 39-x64 - # WITH_SYMPY: no - BUILD_TYPE: "Release" COMPILER: MSVC15 PLATFORM: "x64" @@ -63,41 +52,23 @@ install: - git clone https://github.com/sympy/symengine symengine-cpp - if [%PLATFORM%]==[Win32] set "CONDA_SUBDIR=win-32" -- if [%COMPILER%]==[MSVC15] call %CONDA_INSTALL_LOCN%\Scripts\activate.bat -- if [%COMPILER%]==[MSVC15] set "CONDA_DEPS=mpir=3.0.0 vc=14" -- if [%COMPILER%]==[MSVC15] if [%WITH_MPFR%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% mpfr=3.1.5" -- if [%COMPILER%]==[MSVC15] if [%WITH_MPC%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% mpc=1.0.3" -- if [%COMPILER%]==[MSVC15] if [%WITH_LLVM%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% llvmdev=4.0" -- if [%COMPILER%]==[MSVC15] set "CONDA_DEPS=%CONDA_DEPS% -c conda-forge" -- if [%COMPILER%]==[MSVC15] if [%BUILD_TYPE%]==[Debug] set "CONDA_DEPS=%CONDA_DEPS% -c symengine/label/debug" -- if [%COMPILER%]==[MSVC15] conda create -n deps --yes %CONDA_DEPS% -- if [%COMPILER%]==[MSVC15] call conda activate deps -- if [%COMPILER%]==[MSVC15] echo %CONDA_PREFIX% -- if [%COMPILER%]==[MSVC15] echo %PATH% -- if [%COMPILER%]==[MSVC15] set "PATH=%PATH%;%CONDA_PREFIX%\\Library\\bin;%CONDA_PREFIX%" -- if [%COMPILER%]==[MSVC15] echo %PATH% - -- 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 - -- if [%COMPILER%]==[MinGW-w64] set "PATH=C:\mingw64\bin;%PATH%" - -- rename "C:\Program Files\Git\usr\bin\sh.exe" "sh2.exe" - -- if [%COMPILER%]==[MinGW-w64] call symengine-cpp\bin\appveyor-download.cmd "https://raw.githubusercontent.com/symengine/dependencies/5cff7d1736877336cf9fb58267111beea4fa152f/x86_64-4.9.1-release-posix-seh-rt_v3-rev1.7z" -FileName mw64.7z -- if [%COMPILER%]==[MinGW-w64] 7z x -oC:\ mw64.7z > NUL -- if [%COMPILER%]==[MinGW-w64] call symengine-cpp\bin\appveyor-download.cmd "https://raw.githubusercontent.com/symengine/dependencies/5cff7d1736877336cf9fb58267111beea4fa152f/gmp-6.0.0-x86_64-w64-mingw32.7z" -FileName gmp.7z -- if [%COMPILER%]==[MinGW-w64] 7z x -oC:\mingw64 gmp.7z > NUL - -- if NOT [%COMPILER%]==[MSVC15] call symengine-cpp\bin\appveyor-download.cmd "https://raw.githubusercontent.com/symengine/dependencies/dcc10cce2133e2b57e61c5ced6120139bbcdfa20/python-libs-mingw32.7z" -FileName pylibs.7z -- if NOT [%COMPILER%]==[MSVC15] 7z x -aoa -oC:\ pylibs.7z > NUL +- call %CONDA_INSTALL_LOCN%\Scripts\activate.bat +- set "CONDA_DEPS=mpir=3.0.0 vc=14" +- if [%WITH_MPFR%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% mpfr=3.1.5" +- if [%WITH_MPC%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% mpc=1.0.3" +- if [%WITH_LLVM%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% llvmdev=4.0" +- set "CONDA_DEPS=%CONDA_DEPS% -c conda-forge" +- if [%BUILD_TYPE%]==[Debug] set "CONDA_DEPS=%CONDA_DEPS% -c symengine/label/debug" +- conda create -n deps --yes %CONDA_DEPS% +- call conda activate deps +- echo %CONDA_PREFIX% +- echo %PATH% +- set "PATH=%PATH%;%CONDA_PREFIX%\\Library\\bin;%CONDA_PREFIX%" +- echo %PATH% - set "PATH=C:\Python%PYTHON_VERSION%;C:\Python%PYTHON_VERSION%\Scripts;%PATH%" - echo %PATH% -- pip install nose pytest cython setuptools +- pip install pytest cython scikit-build-core cython-cmake setuptools_scm - if NOT [%WITH_NUMPY%]==[no] pip install numpy - if NOT [%WITH_SYMPY%]==[no] pip install sympy @@ -107,14 +78,10 @@ install: - mkdir build - cd build -- if [%COMPILER%]==[MSVC15] set "CMAKE_GENERATOR=Visual Studio 16 2019" -- if [%COMPILER%]==[MSVC15] set "CMAKE_GENERATOR_PLATFORM=%PLATFORM%" -- if [%COMPILER%]==[MinGW] set "CMAKE_GENERATOR=MinGW Makefiles" -- if [%COMPILER%]==[MinGW-w64] set "CMAKE_GENERATOR=MinGW Makefiles" +- set "CMAKE_GENERATOR=Visual Studio 16 2019" +- set "CMAKE_GENERATOR_PLATFORM=%PLATFORM%" -- if [%COMPILER%]==[MSVC15] set "CMAKE_ARGS=-DCMAKE_PREFIX_PATH=%CONDA_PREFIX%\\Library" -- if [%COMPILER%]==[MinGW] set "CMAKE_ARGS=-DCMAKE_PREFIX_PATH=C:\MinGW -DCMAKE_BUILD_TYPE=%BUILD_TYPE%" -- if [%COMPILER%]==[MinGW-w64] set "CMAKE_ARGS=-DCMAKE_PREFIX_PATH=C:\mingw64 -DCMAKE_BUILD_TYPE=%BUILD_TYPE%" +- set "CMAKE_ARGS=-DCMAKE_PREFIX_PATH=%CONDA_PREFIX%\\Library" - if [%WITH_MPFR%]==[yes] set "CMAKE_ARGS=%CMAKE_ARGS% -DWITH_MPFR=yes" - if [%WITH_MPC%]==[yes] set "CMAKE_ARGS=%CMAKE_ARGS% -DWITH_MPC=yes" @@ -130,12 +97,10 @@ build_script: - set "PATH=C:\symengine\bin\;%PATH%" - set "SYMENGINE_PY_ADD_PATH_TO_SEARCH_DIRS=1" - echo %PATH% -- if [%COMPILER%]==[MSVC15] python setup.py install build_ext --compiler=msvc --build-type=%BUILD_TYPE% -- 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 +- set "CMAKE_ARGS=" +- python -m pip install -e . --no-build-isolation -Ccmake.build-type=%BUILD_TYPE% -vv test_script: -- if not [%COMPILER%]==[MSVC15] nosetests - mkdir empty && cd empty - python %PYTHON_SOURCE_DIR%\bin\test_python.py diff --git a/bin/install_travis.sh b/bin/install_travis.sh index c9199843d..0b09ffc02 100644 --- a/bin/install_travis.sh +++ b/bin/install_travis.sh @@ -2,7 +2,7 @@ # symengine's bin/install_travis.sh will install miniconda -export conda_pkgs="python=${PYTHON_VERSION} pip pytest setuptools gmp mpfr" +export conda_pkgs="python=${PYTHON_VERSION} pip pytest python-build scikit-build-core ninja cython-cmake cython setuptools-scm gmp mpfr" if [[ "${WITH_NUMPY}" != "no" ]]; then export conda_pkgs="${conda_pkgs} numpy"; @@ -31,7 +31,7 @@ if [[ "${WITH_SAGE}" == "yes" ]]; then export conda_pkgs="${conda_pkgs} sage=8.1"; fi -conda install -q ${conda_pkgs} "cython>=0.29.24" +conda install -q ${conda_pkgs} if [[ "${WITH_SYMPY}" != "no" ]]; then pip install sympy; diff --git a/bin/test_travis.sh b/bin/test_travis.sh index fe579cdc7..c3301df17 100755 --- a/bin/test_travis.sh +++ b/bin/test_travis.sh @@ -5,16 +5,17 @@ set -e # Echo each command set -x -python setup.py sdist +python -m build . --sdist mkdir dist-extract cd dist-extract tar -xvf ../dist/symengine-*.tar.gz cd symengine-* -# Build inplace so that nosetests can be run inside source directory -python3 setup.py install build_ext --inplace --symengine-dir=$our_install_dir - -if [[ "${SYMENGINE_PY_LIMITED_API:-}" != "" ]]; then +# Build inplace +if [[ "${SYMENGINE_PY_LIMITED_API:-}" == "" ]]; then + python3 -m pip install -e . -vv -Ccmake.define.SymEngine_DIR=$our_install_dir +else + python3 -m pip install -e . -vv -Ccmake.define.SymEngine_DIR=$our_install_dir -Cwheel.py-api="cp${SYMENGINE_PY_LIMITED_API/./}" python3 -m abi3audit --assume-minimum-abi3 ${SYMENGINE_PY_LIMITED_API} symengine/lib/symengine_wrapper.abi3.so -v fi diff --git a/cmake/FindCython.cmake b/cmake/FindCython.cmake deleted file mode 100644 index e35d44ba6..000000000 --- a/cmake/FindCython.cmake +++ /dev/null @@ -1,93 +0,0 @@ -# -# Cython -# - -# This finds the "cython" executable in your PATH, and then in some standard -# paths: - -find_program(CYTHON_BIN NAMES cython cython3 cython2) -SET(CYTHON_FLAGS --cplus --fast-fail -3) - -SET(Cython_FOUND FALSE) -IF (CYTHON_BIN) - # Try to run Cython, to make sure it works: - execute_process( - COMMAND ${CYTHON_BIN} ${CYTHON_FLAGS} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cython_test.pyx - RESULT_VARIABLE CYTHON_RESULT - OUTPUT_VARIABLE CYTHON_OUTPUT - ERROR_VARIABLE CYTHON_ERROR - ) - if (CYTHON_RESULT EQUAL 0) - # Only if cython exits with the return code 0, we know that all is ok: - SET(Cython_FOUND TRUE) - SET(Cython_Compilation_Failed FALSE) - else (CYTHON_RESULT EQUAL 0) - SET(Cython_Compilation_Failed TRUE) - endif (CYTHON_RESULT EQUAL 0) - execute_process( - COMMAND ${CYTHON_BIN} --version - RESULT_VARIABLE CYTHON_VERSION_RESULT - OUTPUT_VARIABLE CYTHON_VERSION_OUTPUT - ERROR_VARIABLE CYTHON_VERSION_ERROR - ) - if (CYTHON_VERSION_RESULT EQUAL 0) - string(STRIP ${CYTHON_VERSION_OUTPUT} CYTHON_VERSION_OUTPUT) - if ("${CYTHON_VERSION_OUTPUT}" MATCHES "Cython version") - string(SUBSTRING "${CYTHON_VERSION_OUTPUT}" 15 -1 CYTHON_VERSION) - endif () - endif () - message(STATUS "Cython version: ${CYTHON_VERSION}") -ENDIF (CYTHON_BIN) - - -IF (Cython_FOUND) - IF (NOT Cython_FIND_QUIETLY) - MESSAGE(STATUS "Found CYTHON: ${CYTHON_BIN}") - ENDIF (NOT Cython_FIND_QUIETLY) - IF (WITH_PY_LIMITED_API AND "${CYTHON_VERSION}" VERSION_LESS "3.1") - MESSAGE(FATAL_ERROR - "Your Cython version (${CYTHON_VERSION}) is too old. Please upgrade Cython to 3.1 or newer." - ) - ENDIF () -ELSE (Cython_FOUND) - IF (Cython_FIND_REQUIRED) - if(Cython_Compilation_Failed) - MESSAGE(STATUS "Found CYTHON: ${CYTHON_BIN}") - # On Win the testing of Cython does not return any accessible value, so the test is not carried out. - # Fresh Cython install was tested and works. - IF(NOT MSVC) - MESSAGE(FATAL_ERROR - "Your Cython version is too old. Please upgrade Cython." - "STDOUT: ${CYTHON_OUTPUT}" - "STDERROR: ${CYTHON_ERROR}" - ) - ENDIF(NOT MSVC) - else(Cython_Compilation_Failed) - MESSAGE(FATAL_ERROR "Could not find Cython. Please install Cython.") - endif(Cython_Compilation_Failed) - ENDIF (Cython_FIND_REQUIRED) -ENDIF (Cython_FOUND) - - -# This allows to link Cython files -# Examples: -# 1) to compile assembly.pyx to assembly.so: -# CYTHON_ADD_MODULE(assembly) -# 2) to compile assembly.pyx and something.cpp to assembly.so: -# CYTHON_ADD_MODULE(assembly something.cpp) - -if(NOT CYTHON_INCLUDE_DIRECTORIES) - set(CYTHON_INCLUDE_DIRECTORIES .) -endif(NOT CYTHON_INCLUDE_DIRECTORIES) - -# Cythonizes the .pyx files into .cpp file (but doesn't compile it) -macro(CYTHON_ADD_MODULE_PYX cpp_name pyx_name) - # Allow the user to specify dependencies as optional arguments - set(DEPENDS ${DEPENDS} ${ARGN}) - add_custom_command( - OUTPUT ${cpp_name} - COMMAND ${CYTHON_BIN} - ARGS ${CYTHON_FLAGS} -I ${CYTHON_INCLUDE_DIRECTORIES} -o ${cpp_name} ${pyx_name} - DEPENDS ${DEPENDS} ${pyx_name} - COMMENT "Cythonizing ${pyx_name}") -endmacro(CYTHON_ADD_MODULE_PYX) diff --git a/cmake/FindNumPy.cmake b/cmake/FindNumPy.cmake deleted file mode 100644 index 66bf7bf41..000000000 --- a/cmake/FindNumPy.cmake +++ /dev/null @@ -1,19 +0,0 @@ -execute_process( - COMMAND ${PYTHON_BIN} -c "import numpy; print(numpy.get_include())" - RESULT_VARIABLE NUMPY_FIND_RESULT - OUTPUT_VARIABLE NUMPY_FIND_OUTPUT - ERROR_VARIABLE NUMPY_FIND_ERROR - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -if(NOT NUMPY_FIND_RESULT MATCHES 0) - set(NUMPY_FOUND FALSE) - message(STATUS "NumPy import failure:\n${NUMPY_FIND_ERROR}") -else() - find_path(NUMPY_INCLUDE_PATH numpy/arrayobject.h - HINTS "${NUMPY_FIND_OUTPUT}" NO_DEFAULT_PATH) - if(NUMPY_INCLUDE_PATH) - set(NUMPY_FOUND TRUE CACHE BOOL INTERNAL "NumPy found") - INCLUDE(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(NUMPY DEFAULT_MSG NUMPY_INCLUDE_PATH) - endif() -endif() diff --git a/cmake/FindPython.cmake b/cmake/FindPython.cmake deleted file mode 100644 index 7ed8287f8..000000000 --- a/cmake/FindPython.cmake +++ /dev/null @@ -1,164 +0,0 @@ -set(PYTHON_BIN python CACHE STRING "Python executable name") - -execute_process( - COMMAND ${PYTHON_BIN} -c "from sysconfig import get_paths; print(get_paths()['include'])" - OUTPUT_VARIABLE PYTHON_SYS_PATH - ) -string(STRIP ${PYTHON_SYS_PATH} PYTHON_SYS_PATH) -FIND_PATH(PYTHON_INCLUDE_PATH Python.h - PATHS ${PYTHON_SYS_PATH} - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - ) -message(STATUS "Python include path: ${PYTHON_INCLUDE_PATH}") - -set(PYTHON_INSTALL_HEADER_PATH ${PYTHON_INCLUDE_PATH}/symengine - CACHE BOOL "Python install headers path") - -execute_process( - COMMAND ${PYTHON_BIN} -c "from sysconfig import get_config_var; print(get_config_var('LIBDIR'))" - OUTPUT_VARIABLE PYTHON_LIB_PATH - ) -string(STRIP ${PYTHON_LIB_PATH} PYTHON_LIB_PATH) - -execute_process( - COMMAND ${PYTHON_BIN} -c "import sys; print(sys.prefix)" - OUTPUT_VARIABLE PYTHON_PREFIX_PATH -) - -string(STRIP ${PYTHON_PREFIX_PATH} PYTHON_PREFIX_PATH) - -execute_process( - COMMAND ${PYTHON_BIN} -c "import sys; print('%s.%s' % sys.version_info[:2])" - OUTPUT_VARIABLE PYTHON_VERSION -) -string(STRIP ${PYTHON_VERSION} PYTHON_VERSION) -message(STATUS "Python version: ${PYTHON_VERSION}") - -string(REPLACE "." "" PYTHON_VERSION_WITHOUT_DOTS ${PYTHON_VERSION}) - -execute_process( - COMMAND ${PYTHON_BIN} -c "import sysconfig;print(bool(sysconfig.get_config_var('Py_GIL_DISABLED')))" - OUTPUT_VARIABLE PY_GIL_DISABLED -) -string(STRIP ${PY_GIL_DISABLED} PY_GIL_DISABLED) - -if ("${PY_GIL_DISABLED}" STREQUAL "True") - set (PY_THREAD "t") -endif() - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if (WITH_PY_LIMITED_API) - set(PYTHON_LIBRARY_NAMES python3) - else() - set(PYTHON_LIBRARY_NAMES python${PYTHON_VERSION}${PY_THREAD} python${PYTHON_VERSION}m python${PYTHON_VERSION_WITHOUT_DOTS}${PY_THREAD}) - endif() - FIND_LIBRARY(PYTHON_LIBRARY NAMES ${PYTHON_LIBRARY_NAMES} - PATHS ${PYTHON_LIB_PATH} ${PYTHON_PREFIX_PATH}/lib ${PYTHON_PREFIX_PATH}/libs - PATH_SUFFIXES ${CMAKE_LIBRARY_ARCHITECTURE} - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - ) -endif() - -execute_process( - COMMAND ${PYTHON_BIN} -c "from sysconfig import get_paths; print(get_paths()['platlib'])" - OUTPUT_VARIABLE PYTHON_INSTALL_PATH_tmp -) -string(STRIP ${PYTHON_INSTALL_PATH_tmp} PYTHON_INSTALL_PATH_tmp) -set(PYTHON_INSTALL_PATH ${PYTHON_INSTALL_PATH_tmp} - CACHE BOOL "Python install path") -message(STATUS "Python install path: ${PYTHON_INSTALL_PATH}") - -execute_process( - COMMAND ${PYTHON_BIN} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/get_suffix.py - OUTPUT_VARIABLE PYTHON_EXTENSION_SOABI_tmp -) -string(STRIP ${PYTHON_EXTENSION_SOABI_tmp} PYTHON_EXTENSION_SOABI_tmp) - -if (WITH_PY_LIMITED_API) - if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - set(PYTHON_EXTENSION_SOABI_tmp "") - else() - set(PYTHON_EXTENSION_SOABI_tmp ".abi3") - endif() -endif() - -set(PYTHON_EXTENSION_SOABI ${PYTHON_EXTENSION_SOABI_tmp} - CACHE STRING "Suffix for python extensions") - -INCLUDE(FindPackageHandleStandardArgs) - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - FIND_PACKAGE_HANDLE_STANDARD_ARGS(Python DEFAULT_MSG PYTHON_LIBRARY PYTHON_INCLUDE_PATH PYTHON_INSTALL_PATH) -else () - FIND_PACKAGE_HANDLE_STANDARD_ARGS(Python DEFAULT_MSG PYTHON_INCLUDE_PATH PYTHON_INSTALL_PATH) -endif () - - -# Links a Python extension module. -# -# The exact link flags are platform dependent and this macro makes it possible -# to write platform independent cmakefiles. All you have to do is to change -# this: -# -# add_library(simple_wrapper SHARED ${SRC}) # Linux only -# set_target_properties(simple_wrapper PROPERTIES PREFIX "") -# -# to this: -# -# add_python_library(simple_wrapper ${SRC}) # Platform independent -# -# Full example: -# -# set(SRC -# iso_c_utilities.f90 -# pde_pointers.f90 -# example1.f90 -# example2.f90 -# example_eigen.f90 -# simple.f90 -# simple_wrapper.c -# ) -# add_python_library(simple_wrapper ${SRC}) - -macro(ADD_PYTHON_LIBRARY name) - # When linking Python extension modules, a special care must be taken about - # the link flags, which are platform dependent: - IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - # on Mac, we need to use the "-bundle" gcc flag, which is what MODULE - # does: - add_library(${name} MODULE ${ARGN}) - # and "-undefined dynamic_lookup" link flags, that we need to add by hand: - set_property(TARGET ${name} APPEND_STRING PROPERTY - LINK_FLAGS " -undefined dynamic_lookup -Wl,-exported_symbol,_PyInit_${name}") - ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - # on Linux, we need to use the "-shared" gcc flag, which is what SHARED - # does: - set(PYTHON_EXTENSION_NAME ${name}) - add_library(${name} SHARED ${ARGN}) - configure_file(${CMAKE_SOURCE_DIR}/cmake/version_script.txt - ${CMAKE_CURRENT_BINARY_DIR}/version_script_${name}.txt @ONLY) - set_property(TARGET ${name} APPEND_STRING PROPERTY - LINK_FLAGS " \"-Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/version_script_${name}.txt\"") - ELSE() - add_library(${name} SHARED ${ARGN}) - ENDIF() - set_target_properties(${name} PROPERTIES PREFIX "") - set_target_properties(${name} PROPERTIES OUTPUT_NAME "${name}${PYTHON_EXTENSION_SOABI}") - IF(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_link_libraries(${name} ${PYTHON_LIBRARY}) - set_target_properties(${name} PROPERTIES SUFFIX ".pyd") - IF("${PY_GIL_DISABLED}" STREQUAL "True") - target_compile_definitions(${name} PRIVATE Py_GIL_DISABLED=1) - ENDIF() - ENDIF() - IF(WITH_PY_LIMITED_API) - target_compile_definitions( - ${name} - PRIVATE - Py_LIMITED_API=${WITH_PY_LIMITED_API} - CYTHON_LIMITED_API=1 - ) - ENDIF() -endmacro(ADD_PYTHON_LIBRARY) diff --git a/cmake/cython_test.pyx b/cmake/cython_test.pyx deleted file mode 100644 index e97be0b43..000000000 --- a/cmake/cython_test.pyx +++ /dev/null @@ -1,82 +0,0 @@ -# Test that libcpp module is present: -from libcpp.vector cimport vector -from libcpp.string cimport string - -# Test the math library: -from libc.math cimport sin, cos, atan2 - -# Test that templates work: -cdef vector[int] array2vector_int(a): - cdef vector[int] v - for i in range(len(a)): - v.push_back(a[i]) - return v - -# Test that bool support works -from libcpp cimport bool - -# Test that C++ support works - -cdef extern from "electrostatics.h": - - ctypedef double scalar - - cdef cppclass Function: - pass - - cdef cppclass MeshFunction(Function): - scalar get_pt_value(double x, double y) - - cdef cppclass Solution(MeshFunction): - void copy(Solution *s) - - cdef cppclass Electrostatics: - void set_mesh_str(char *mesh) - void set_initial_mesh_refinement(int init_ref_num) - void set_initial_poly_degree(int p) - void set_material_markers(vector[int] &mat_markers) - void set_permittivity_array(vector[double] &p_array) - void set_charge_density_array(vector[double] &cd_array) - void set_boundary_markers_value(vector[int] &bdy_markers_val) - void set_boundary_values(vector[double] &bc_val) - void set_boundary_markers_derivative(vector[int] &bdy_markers_der) - void set_boundary_derivatives(vector[double] &bc_der) - bool calculate(Solution* phi) - -cdef extern from "" namespace "SymEngine": - cdef enum ENull: - null - - cdef cppclass RCP[T]: - T& operator*() nogil except + - void reset() nogil except + - - cdef cppclass Ptr[T]: - T& operator*() nogil except + - - RCP[Symbol] rcp_static_cast_Symbol "SymEngine::rcp_static_cast"(const RCP[Basic] &b) nogil - RCP[Add] rcp_static_cast_Add "SymEngine::rcp_static_cast"(const RCP[Basic] &b) nogil - - -cdef extern from "" namespace "SymEngine": - cdef cppclass Basic: - string __str__() nogil except + - RCP[Basic] diff(const RCP[Symbol] &x) nogil except + - - bool eq(RCP[Basic] &a, RCP[Basic] &b) nogil except + - bool neq(RCP[Basic] &a, RCP[Basic] &b) nogil except + - - bool is_a_Add "SymEngine::is_a"(const Basic &b) nogil - bool is_a_Mul "SymEngine::is_a"(const Basic &b) nogil - -cdef extern from "" namespace "SymEngine": - cdef cppclass Symbol(Basic): - Symbol(string name) nogil - string get_name() nogil - -cdef extern from "" namespace "SymEngine": - cdef RCP[Basic] add(RCP[Basic] &a, RCP[Basic] &b) nogil except + - cdef RCP[Basic] sub(RCP[Basic] &a, RCP[Basic] &b) nogil except + - - cdef cppclass Add(Basic): - void as_two_terms(const Ptr[RCP[Basic]] &a, const Ptr[RCP[Basic]] &b) diff --git a/cmake/get_suffix.py b/cmake/get_suffix.py deleted file mode 100644 index 42470fce5..000000000 --- a/cmake/get_suffix.py +++ /dev/null @@ -1,6 +0,0 @@ -from sysconfig import get_config_var -extsuffix = get_config_var('EXT_SUFFIX') -if extsuffix is None: - print("") -else: - print(extsuffix[0:].rsplit(".", 1)[0]) diff --git a/cmake/version_script.txt b/cmake/version_script.txt deleted file mode 100644 index 0b24ad9fa..000000000 --- a/cmake/version_script.txt +++ /dev/null @@ -1,4 +0,0 @@ -{ - global: PyInit_@PYTHON_EXTENSION_NAME@; - local: *; -}; diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..fcea2b6a0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,41 @@ +[project] +name = "symengine" +dynamic = ["version"] +description = "Python library providing wrappers to SymEngine" +authors = [ + {name = "SymEngine development team", email="symengine@googlegroups.com"}, +] +readme = "README.md" +license = "MIT" +license-files = ["LICENSE"] +requires-python = ">=3.8" +classifiers = [ + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Mathematics', + 'Topic :: Scientific/Engineering :: Physics', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', +] + +[project.urls] +Homepage = "https://symengine.org" +Documentation = "https://symengine.org/symengine.py" +Repository = "https://github.com/symengine/symengine.py" +Issues = "https://github.com/symengine/symengine.py/issues" + +[build-system] +requires = ["scikit-build-core", "cython>=0.29.14", "setuptools-scm", "cython-cmake"] +build-backend = "scikit_build_core.build" + +[tool.scikit-build] +metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" +sdist.include = ["symengine/_version.py"] +editable.mode = "inplace" + +[tool.setuptools_scm] # Section required +write_to = "symengine/_version.py" diff --git a/setup.py b/setup.py deleted file mode 100644 index b0eb0206c..000000000 --- a/setup.py +++ /dev/null @@ -1,274 +0,0 @@ -from os import getenv, path, makedirs -import os -import subprocess -import sys -import platform - -# Make sure the system has the right Python version. -if sys.version_info[:2] < (3, 9): - print("SymEngine requires Python 3.9 or newer. " - "Python %d.%d detected" % sys.version_info[:2]) - sys.exit(-1) - -def _get_limited_api(): - value = os.environ.get("SYMENGINE_PY_LIMITED_API") - if not value: - return None - else: - version = tuple(map(int, value.split("."))) - if version < (3, 11): - raise ValueError(f"symengine needs at least python 3.11 limited API support. Got {value}") - return version - -limited_api = _get_limited_api() - -# 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 - from setuptools.command.build_ext import build_ext as _build_ext - except ImportError: - use_setuptools = False - else: - try: - from setuptools.command.build import build as _build - except ImportError: - from distutils.command.build import build as _build - -if not use_setuptools: - from distutils.core import setup - from distutils.command.install import install as _install - from distutils.command.build_ext import build_ext as _build_ext - from distutils.command.build import build as _build - -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 :='), - ('py-limited-api=', None, 'Use Py_LIMITED_API with given version.'), -] - -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], - "-DSYMENGINE_INSTALL_PY_FILES=ON", - ] - cmake_cmd.extend(process_opts(cmake_opts)) - if not path.exists(path.join(build_dir, "CMakeCache.txt")): - cmake_cmd.extend(self.get_generator()) - - if limited_api: - h = limited_api[0] * 16**6 + limited_api[1] * 16**4 - cmake_cmd.append(f"-DWITH_PY_LIMITED_API={h}") - - if subprocess.call(cmake_cmd, cwd=build_dir) != 0: - raise OSError("error calling cmake") - - if subprocess.call(["cmake", "--build", ".", - "--config", cmake_build_type[0]], - cwd=build_dir) != 0: - raise OSError("error building project") - - def get_generator(self): - if cmake_generator[0]: - return ["-G", cmake_generator[0]] - elif "CMAKE_GENERATOR" not in os.environ and platform.system() == "Windows": - compiler = str(self.compiler).lower() - if ("msys" in compiler): - return ["-G", "MSYS Makefiles"] - elif ("mingw" in compiler): - return ["-G", "MinGW Makefiles"] - else: - return ["-G", "NMake Makefiles"] - else: - return [] - - def run(self): - self.cmake_build() - _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))]) - - 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 OSError("error calling cmake") - - if subprocess.call(["cmake", "--build", ".", - "--config", cmake_build_type[0], - "--target", "install"], - cwd=build_dir) != 0: - raise OSError("error installing") - - import compileall - compileall.compile_dir(path.join(self.install_platlib, "symengine")) - - def run(self): - _install.run(self) - self.cmake_install() - -cmdclass={ - 'build': BuildWithCmake, - 'build_ext': BuildExtWithCmake, - 'install': InstallWithCmake, - } - -try: - try: - from setuptools.command.bdist_wheel import bdist_wheel - except ImportError: - 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 - if limited_api: - self.py_limited_api = "cp" + "".join(str(c) for c in limited_api) - cmdclass["bdist_wheel"] = BdistWheelWithCmake -except ImportError: - pass - -long_description = ''' -SymEngine is a standalone fast C++ symbolic manipulation library. -Optional thin Python wrappers (SymEngine) allow easy usage from Python and -integration with SymPy and Sage. - -See https://github.com/symengine/symengine.py for information about License -and dependencies of wheels - -''' - -setup(name="symengine", - version="0.14.1", - description="Python library providing wrappers to SymEngine", - setup_requires=['cython>=0.29.24', 'setuptools'], - long_description=long_description, - author="SymEngine development team", - author_email="symengine@googlegroups.com", - license="MIT", - url="https://github.com/symengine/symengine.py", - python_requires='>=3.9,<4', - zip_safe=False, - packages=[], - cmdclass = cmdclass, - classifiers=[ - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Mathematics', - 'Topic :: Scientific/Engineering :: Physics', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: 3.13', - ] - ) diff --git a/symengine/CMakeLists.txt b/symengine/CMakeLists.txt index bedec397d..2f849a70d 100644 --- a/symengine/CMakeLists.txt +++ b/symengine/CMakeLists.txt @@ -1,17 +1,13 @@ add_subdirectory(lib) - -if (SYMENGINE_INSTALL_PY_FILES) - add_subdirectory(tests) - set(PY_PATH ${PYTHON_INSTALL_PATH}/symengine) - install( - FILES - __init__.py - functions.py - printing.py - sympy_compat.py - test_utilities.py - utilities.py - DESTINATION - ${PY_PATH} +add_subdirectory(tests) +install( + FILES + __init__.py + functions.py + printing.py + sympy_compat.py + test_utilities.py + utilities.py + DESTINATION + symengine ) -endif () diff --git a/symengine/__init__.py b/symengine/__init__.py index e9545baf6..07e2b31fa 100644 --- a/symengine/__init__.py +++ b/symengine/__init__.py @@ -1,4 +1,5 @@ import os + import sys if sys.platform == 'win32' \ @@ -63,7 +64,7 @@ def __getattr__(name): raise AttributeError(f"module 'symengine' has no attribute '{name}'") -__version__ = "0.14.1" +from ._version import __version__ # To not expose internals diff --git a/symengine/lib/CMakeLists.txt b/symengine/lib/CMakeLists.txt index 7683d4aa8..ef494ecaa 100644 --- a/symengine/lib/CMakeLists.txt +++ b/symengine/lib/CMakeLists.txt @@ -1,15 +1,8 @@ -set(SRC - ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.cpp - pywrapper.cpp - ) - -include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pxd DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/symengine_wrapper.in.pxd ${PROJECT_SOURCE_DIR}/cmake/preprocess.py - COMMAND ${PYTHON_BIN} ${PROJECT_SOURCE_DIR}/cmake/preprocess.py + COMMAND Python::Interpreter ${PROJECT_SOURCE_DIR}/cmake/preprocess.py ${CMAKE_CURRENT_SOURCE_DIR}/symengine_wrapper.in.pxd ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pxd HAVE_SYMENGINE_MPFR=${HAVE_SYMENGINE_MPFR} @@ -26,7 +19,7 @@ add_custom_command( ${CMAKE_CURRENT_SOURCE_DIR}/symengine_wrapper.in.pxd ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pxd ${PROJECT_SOURCE_DIR}/cmake/preprocess.py - COMMAND ${PYTHON_BIN} ${PROJECT_SOURCE_DIR}/cmake/preprocess.py + COMMAND Python::Interpreter ${PROJECT_SOURCE_DIR}/cmake/preprocess.py ${CMAKE_CURRENT_SOURCE_DIR}/symengine_wrapper.in.pyx ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pyx HAVE_SYMENGINE_MPFR=${HAVE_SYMENGINE_MPFR} @@ -38,46 +31,77 @@ add_custom_command( COMMENT "Preprocessing symengine_wrapper.in.pyx" ) -cython_add_module_pyx(symengine_wrapper.cpp - ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pyx - ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pxd - ${CMAKE_CURRENT_SOURCE_DIR}/symengine.pxd) -add_python_library(symengine_wrapper ${SRC}) -target_link_libraries(symengine_wrapper ${SYMENGINE_LIBRARIES}) +cython_transpile( + ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pyx + LANGUAGE CXX + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.cpp + CYTHON_ARGS + -I ${CMAKE_CURRENT_BINARY_DIR} + -I ${CMAKE_CURRENT_SOURCE_DIR} +) + +if (NOT "${SKBUILD_SABI_VERSION}" STREQUAL "") + if ("${SKBUILD_SABI_VERSION}" VERSION_LESS "3.11") + message(FATAL_ERROR "symengine.py with ABI3 requires python>=3.11") + endif() + set(USE_SABI USE_SABI ${SKBUILD_SABI_VERSION}) +endif() + +Python_add_library( + symengine_wrapper + MODULE + WITH_SOABI + ${USE_SABI} + ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.cpp + pywrapper.cpp +) +target_link_libraries( + symengine_wrapper + PRIVATE + ${SYMENGINE_LIBRARIES} +) +target_include_directories( + symengine_wrapper + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${SYMENGINE_INCLUDE_DIRS} +) + if (CMAKE_CXX_COMPILER_ID MATCHES GNU|Clang) # Must suppress strict aliasing for this file set_source_files_properties( symengine_wrapper.cpp - PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -Wno-unused-function" - ) + PROPERTIES + COMPILE_FLAGS "-fno-strict-aliasing -Wno-unused-function" + ) endif() -set(PY_PATH ${PYTHON_INSTALL_PATH}/symengine/lib) -install(TARGETS symengine_wrapper - RUNTIME DESTINATION ${PY_PATH} - ARCHIVE DESTINATION ${PY_PATH} - LIBRARY DESTINATION ${PY_PATH} - ) -install(FILES - symengine.pxd - ${CMAKE_CURRENT_BINARY_DIR}/symengine_wrapper.pxd - pywrapper.h - DESTINATION ${PY_PATH} - ) +if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" + AND DEFINED SKBUILD) + # Editable in-place builds. THe empty generator expression ensures + # multi-config enerators keeps us from having to set + # LIBRARY_OUTPUT_DIRECTORY_ too. + set_target_properties( + symengine_wrapper + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}$<0:>" + ) +endif() -if (SYMENGINE_INSTALL_PY_FILES) - install(FILES __init__.py DESTINATION ${PY_PATH}) -endif () +install( + TARGETS + symengine_wrapper + RUNTIME DESTINATION symengine/lib + ARCHIVE DESTINATION symengine/lib + LIBRARY DESTINATION symengine/lib +) -if (${SYMENGINE_COPY_EXTENSION}) - if ("${PYTHON_EXTENSION_SOABI}" MATCHES "ppc64le") - string(REPLACE "ppc64le" "powerpc64le" COPY_PYTHON_EXTENSION_SOABI "${PYTHON_EXTENSION_SOABI}") - endif () - if ("${PYTHON_EXTENSION_SOABI}" MATCHES "powerpc64le") - string(REPLACE "powerpc64le" "ppc64le" COPY_PYTHON_EXTENSION_SOABI "${PYTHON_EXTENSION_SOABI}") - endif () - message("${PYTHON_EXTENSION_SOABI} ${COPY_PYTHON_EXTENSION_SOABI}") - set(SOURCE_NAME "${PY_PATH}/symengine_wrapper${PYTHON_EXTENSION_SOABI}.so") - set(DEST_NAME "${PY_PATH}/symengine_wrapper${COPY_PYTHON_EXTENSION_SOABI}.so") - install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${SOURCE_NAME} ${DEST_NAME})") -endif () +install( + FILES + __init__.py + symengine.pxd + symengine_wrapper.pxd + pywrapper.h + DESTINATION symengine/lib +) diff --git a/symengine/tests/CMakeLists.txt b/symengine/tests/CMakeLists.txt index 4f19093b7..64804dec6 100644 --- a/symengine/tests/CMakeLists.txt +++ b/symengine/tests/CMakeLists.txt @@ -1,4 +1,3 @@ -set(PY_PATH ${PYTHON_INSTALL_PATH}/symengine/tests) install( FILES __init__.py @@ -26,5 +25,5 @@ install( test_sympy_conv.py test_var.py DESTINATION - ${PY_PATH} + symengine/tests )