From 29983aaf1e71ae9a3903a443bb7e5578c8d0ca88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Kvalsvik?= Date: Sun, 2 Jun 2019 18:31:12 +0200 Subject: [PATCH] Replace setuptools with skbuild Replace setuptools with scikit-build [1] Scikit-build is a nice alternatives to raw setuptools when building native-extensions, and a perfect fit for a project with segyio's structure. There is a minor breaking change for some build routines - the python setup script is moved the the python/ directory. This does not come without benefits: 1. The python project can now be completely oblivious, save the root cmake file, to the fact that it's a part of a larger repository, and behaves like most python projects 2. cmake is used to build the extension, which means compiler options and configs can be set in a more ergonomic manner 3. Because cmake and scikit now manages the compiler setup and binary compatibility, compiler support might just be extended, even for Windows. segyio no longer has to maintain or deal with these details, and can leave it to scikit-build [1] https://github.com/scikit-build/scikit-build --- .travis.yml | 16 +- appveyor.yml | 30 ++-- config.sh | 24 ++- lib/CMakeLists.txt | 2 + python/CMakeLists.txt | 220 +++++++++++++------------ python/examples/__init__.py | 6 + python/examples/make-rotated-copies.py | 27 +-- python/segyio/segyio.cpp | 2 +- python/setup-CMakeLists.txt | 21 +++ setup.cfg => python/setup.cfg | 2 +- setup.py => python/setup.py | 102 ++++++------ python/test/__init__.py | 2 +- 12 files changed, 262 insertions(+), 192 deletions(-) create mode 100644 python/examples/__init__.py create mode 100644 python/setup-CMakeLists.txt rename setup.cfg => python/setup.cfg (53%) rename setup.py => python/setup.py (59%) diff --git a/.travis.yml b/.travis.yml index dbce7187e..380f30282 100644 --- a/.travis.yml +++ b/.travis.yml @@ -73,7 +73,8 @@ install: brew update && brew install cppcheck; fi - pip install -r requirements.txt - - pip install bandit setuptools setuptools-scm pytest pytest-runner sphinx + - pip install setuptools setuptools-scm scikit-build + - pip install bandit pytest pytest-runner sphinx before_script: - enabled="-DBUILD_PYTHON=OFF -DBUILD_MEX=OFF" @@ -111,9 +112,12 @@ script: - $SCAN make && ctest --output-on-failure - sudo make install - popd - - build_wheel . $PLAT + # install works, so remove the _skbuild because it having root permissions + # from make install breaks build_wheel + - sudo rm -rf python/_skbuild + - build_wheel python $PLAT - install_run $PLAT - - mv wheelhouse dist + - mv wheelhouse python/dist before_deploy: # OS X ships with a tar that doesn't support --exclude-vcs, which is @@ -128,10 +132,14 @@ before_deploy: tar --exclude-vcs -C $TRAVIS_BUILD_DIR -czvf segyio-$VERSION.tar.gz segyio-$VERSION; zip --exclude *.git -r segyio-$VERSION.zip $TRAVIS_BUILD_DIR/segyio-$VERSION/*; fi + - pushd python - if [[ $SOURCEDEPLOY ]]; then rm -rf dist; fi +after_deploy: + - popd + deploy: - provider: pypi # source distribution (done from linux python 3.6 only) skip_cleanup: true @@ -147,7 +155,7 @@ deploy: skip_cleanup: true skip_upload_docs: true user: statoil-travis - distributions: build + distributions: --skip-cmake build password: secure: BaPED+fUXxmk61N/RtrEWtlRKinc2d+VodwKxwlq/74n8Z6RfJKp/ZzlinbjtnpLB/1kPphxwCYLuG2N2nU2kttNJCQEw9AlPL1gnDxDVUz83KuxSsqLPj9VOdj9MI3xyUs+LC3PW2N4kw2dB+/n2pB7BIwvA+Ykx6+Z2eD2vyEV8WqndP6+vApracCbE8huNfsnbxMqr188qzXbTRnzR1pwVFYBTNJ5vfRf0z/NmHXFpRhKEUaaqazJaax1xp5FGVFg2Wy4GQVDvtn6bVpu/rV5wyWXXdXSqqAQmrwv10OZt5ROfb88yfx+ZilpYDeiHmH8YLj4BjcLpdNeNW0c/irgtejLpnd7+XTUKl2QJzDr2l2ShhuaT+ZN7W8iXXZ4xPPvgcudF9fELZXMy6sKXLPE9qhL1yo/1x2eQ662PgusyegoBcQxtJvc0I0ct7jpWUMU0YQhu6VQUDTaxluSw7kxmQ2WYIW0UJIMkn+AkPw8t/ZYa83RbteRM3I7bAthzNl0IF/t5rDUt8itb6f4eTxjP1+5QdlNkSTNG9KXIxP8wX843PtFKA1i8gcqCIppgoQAnEHHcTJ+nX/ilqXHBWIDiYX6k79B3Hflqj1IcBZjwbUdojLRsHuNb8JN0y8aNsrWyYKhV09+AmvFwo3pY543HOHq/Fuux9ZCUCTeLbo= on: diff --git a/appveyor.yml b/appveyor.yml index 7d6b6cea6..3f07f8969 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -39,38 +39,40 @@ install: - IF DEFINED PYTHON (IF "%platform%" == "x64" SET PYTHON=%PYTHON%-x64) - IF DEFINED PYTHON SET PATH=%PYTHON%;%PYTHON%\Scripts;%PATH% - IF DEFINED PYTHON pip install -r requirements.txt - - IF DEFINED PYTHON pip install twine wheel pytest pytest-runner + - IF DEFINED PYTHON pip install + twine + wheel + setuptools + setuptools-scm + pytest + pytest-runner + scikit-build before_build: - IF DEFINED PYTHON SET LANG=%LANG% -DPYTHON_EXECUTABLE=%PYTHON%\python + - set generator="Visual Studio 14 2015" + - IF "%platform%" == "x64" set generator="Visual Studio 14 2015 Win64" - git fetch --tags -# python extensions with setup.py typically requires building with the same -# compiler as python itself, but it seems that the extern C does a reasonable -# job of keeping it binary compatible. For python < 3.0, copy the shared lib -# into the build directory (because otherwise visual c++ 9.0 is invoked, and it -# supports no C99. For newer pythons, setup.py is capable of building segyio build_script: - - cmake --version - - IF "%platform%" == "x64" set W64="-GVisual Studio 14 2015 Win64" - mkdir build - ps: pushd build - cmake %APPVEYOR_BUILD_FOLDER% - %W64% + -G %generator% %MEX% %LANG% -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% - -DBUILD_SHARED_LIBS=ON + -DCMAKE_CXX_FLAGS="/D_CRT_SECURE_NO_WARNINGS /EHsc" - cmake --build . --config "%configuration%" --target install - ctest -C "%configuration%" --output-on-failure - ps: popd - - ps: pushd build/python - - IF DEFINED PYTHON python %APPVEYOR_BUILD_FOLDER%/setup.py bdist_wheel + - ps: pushd python + - IF DEFINED PYTHON python setup.py bdist_wheel -G %generator% - ps: popd test_script: - set PATH=%INSTALL_DIR%\bin;%PATH% - - ps: pushd build/python + - ps: pushd python - IF DEFINED PYTHON FOR /F "tokens=*" %%G IN ('dir /b dist\*.whl') DO pip install dist/%%G - ps: popd @@ -79,7 +81,7 @@ test_script: - IF DEFINED PYTHON python python/examples/scan_min_max.py test-data/small.sgy before_deploy: - - ps: pushd build/python + - ps: pushd python after_deploy: - ps: popd diff --git a/config.sh b/config.sh index 2d45c0f58..aebbe7d9b 100644 --- a/config.sh +++ b/config.sh @@ -14,13 +14,31 @@ function pre_build { # the cmakes available in yum for centos5 are too old (latest 2.11.x), so # fetch a newer version pypi - python -m pip install cmake + python -m pip install cmake scikit-build mkdir build-centos5 pushd build-centos5 cmake --version - cmake .. -DBUILD_PYTHON=OFF -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON - make install + cmake -DBUILD_PYTHON=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_INSTALL_NAME_DIR=/usr/local/lib \ + .. + + if [ -n "$IS_OSX" ]; then + sudo make install; + else + make install; + fi + popd + + # clean dirty files from python/, otherwise it picks up the one built + # outside docker and symbols will be too recent for auditwheel. + # setuptools_scm really *really* expects a .git-directory. As the wheel + # building process does its work in /tmp, setuptools_scm crashes because it + # cannot find the .git dir. Leave version.py so that setuptools can obtain + # the version from it + git clean -dxf python --exclude python/segyio/version.py } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e6338584d..2db509ee0 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.5) project(libsegyio C CXX) +set(SEGYIO_LIB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "") + set(CMAKE_CXX_STANDARD 11) add_library(segyio src/segy.c) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 2e2b42b9c..6b0c1f497 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,3 +1,12 @@ +if (SKBUILD) + # invoked as a part of scikit-build, so this is just a proxy for the python + # extension cmake. this works around the fundamental limitation in cmake + # that it looks only for directories with a CMakeLists.txt in it, not for a + # named file + include(setup-CMakeLists.txt) + return () +endif () + cmake_minimum_required(VERSION 3.5) project(segyio-python) @@ -17,7 +26,9 @@ if (NOT PYTHON_EXECUTABLE AND REQUIRE_PYTHON) endif() if (NOT PYTHON_EXECUTABLE) - message(WARNING "Could not find python - skipping python bindings") + message(WARNING "Could not find python - skipping python bindings. " + "Select specific python distribution with " + "-DPYTHON_EXECUTABLE=bin/python") return() endif() @@ -25,100 +36,65 @@ if (PYTHON_INSTALL_LAYOUT) set(setup-install-layout --install-layout ${PYTHON_INSTALL_LAYOUT}) endif() -set(python ${PYTHON_EXECUTABLE}) - -if (NOT WIN32) - # setuptools on microsoft compilers doesn't support the --library-dir or - # --build-dir flag and crashes, so only pass it on non-microsoft platforms - set(setup-py-libdir build_ext - --rpath $ - --library-dirs $) - - set(install-no-rpath install_lib --build-dir build/install) - set(build-no-rpath --library-dirs $ - build --build-lib build/install) -else () - set(copy-dll-to-src ${CMAKE_COMMAND} -E - copy $ - ${CMAKE_CURRENT_SOURCE_DIR}/segyio/$) +set(setup.py ${CMAKE_CURRENT_SOURCE_DIR}/setup.py) +if (CMAKE_BUILD_TYPE) + # use the cmake_build_type of the source project, unless it has been + # specifically overriden + set(SEGYIO_PYTHON_BUILD_TYPE + --build-type=${CMAKE_BUILD_TYPE} + CACHE STRING "override CMAKE_BUILD_TYPE in python extension" + ) endif () - -set(setup-py ${CMAKE_SOURCE_DIR}/setup.py) add_custom_target( segyio-python ALL COMMENT "Building python library with setup.py" - SOURCES ${setup-py} - DEPENDS ${setup-py} + SOURCES ${setup.py} + DEPENDS ${setup.py} VERBATIM - - # copy the examples to have them runnable from a relative directory, so - # that a locally-installed segyio can be imported - COMMAND ${CMAKE_COMMAND} -E - copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/examples . - - # do the same to tests. running through setup.py test is *very* slow, so - # invoke unittest manually from the build directory. more importantly, - # setup.py test will pollute the source directory with egg info and - # extensions, which is unacceptable in a cmake world - COMMAND ${CMAKE_COMMAND} -E - copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/test test - - # setuptools on windows breaks spectacularly when the library isn't - # available in the same directory, and build_ext --library-dirs is not - # support on msvc is not supported, so we must copy out the libsegyio core - # object and put it here - COMMAND ${CMAKE_COMMAND} -E copy $ - $ - - COMMAND ${CMAKE_COMMAND} -E copy $ - $ - - # on windows, copy the freshly-built dll to the source directory. this - # voilates the cmake spirit (as does the version.py writing from - # setuptools-scm), but there's no auditwheel like tool to help fix the - # wheel, and the dll must still be bundled in order to make the package - # work. it's paired with package_data in setup.py. this is necessary - # because setup.py assumes all files to bundled with the package are - # relative downwards and in the package itself, with poor support for - # grabbing other files and adding to it later. - COMMAND ${copy-dll-to-src} - - # install the lib in the build-dir so that the examples can load that from - # current working dir - COMMAND ${python} ${setup-py} ${setup-py-libdir} install_lib -d . - - # to maintain good make && make install behaviour, the extension is built - # twice, one with rpath (for testing and build-dir-local) and one for - # installation - COMMAND ${python} ${setup-py} build_ext ${build-no-rpath} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + + COMMAND ${PYTHON_EXECUTABLE} ${setup.py} + # build the extension inplace (really, once its built, copy it to the + # source tree) so that post-build, the directory can be used to run + # tests against + build_ext --inplace + build # setup.py build args + --cmake-executable ${CMAKE_COMMAND} + --generator ${CMAKE_GENERATOR} + ${SEGYIO_PYTHON_BUILD_TYPE} + -- # cmake to the extension + -Dsegyio_DIR=${SEGYIO_LIB_BINARY_DIR} + # "install" to the python/dlisio dir with rpath, so there's no need + # to fiddle with environment in ctest to load the core library from + # the build tree + -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON + -DCMAKE_INSTALL_RPATH=$ + -DCMAKE_INSTALL_NAME_DIR=$ ) add_dependencies(segyio-python segyio) -# write egg_info to the build dir in order not to pollute the source directory -# and install as if it was through some other distro by using single-version, -# so that install won't die on possibly missing pythonpath -# setup.py install doesn't respect DESTDIR, so "force" it by changing the -# --root if DESTDIR is passed install(CODE " -if (DEFINED ENV{DESTDIR}) - get_filename_component(abs-destdir \"\$ENV{DESTDIR}\" ABSOLUTE) - set(root_destdir --root=\${abs-destdir}) -endif() + if (DEFINED ENV{DESTDIR}) + get_filename_component(abs-destdir \"\$ENV{DESTDIR}\" ABSOLUTE) + set(root_destdir --root \${abs-destdir}) + endif() -execute_process(COMMAND -${python} ${setup-py} - install_egg_info --install-dir . - egg_info --egg-base . - ${install-no-rpath} - install --prefix=${CMAKE_INSTALL_PREFIX} - --single-version-externally-managed - --record installed-files - ${setup-install-layout} - \${root_destdir} -WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} -)") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} ${setup.py} + install + \${root_destdir} + --single-version-externally-managed + --record record.txt + --cmake-executable \"${CMAKE_COMMAND}\" + --generator \"${CMAKE_GENERATOR}\" + ${SEGYIO_PYTHON_BUILD_TYPE} + -- + -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=OFF + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + )" +) option(BUILD_PYDOC "Build python documentation" OFF) @@ -162,25 +138,59 @@ if(NOT BUILD_TESTING) return() endif() -file(GLOB sgys ${testdata}/*.sgy ${testdata}/*.su) -foreach (sgy ${sgys}) - get_filename_component(fl ${sgy} NAME) - configure_file(${sgy} test-data/${fl} COPYONLY) -endforeach () - -set(pytest ${python} -m pytest) -add_test(NAME python.unit COMMAND ${pytest} test/) - -configure_file(${testdata}/small.sgy - test-data/write.sgy - COPYONLY) - -add_test(NAME python.example.about COMMAND ${python} about.py test-data/small.sgy INLINE_3D CROSSLINE_3D) -add_test(NAME python.example.write COMMAND ${python} write.py test-data/write.sgy) -add_test(NAME python.example.makefile COMMAND ${python} make-file.py test-data/large-file.sgy 20 1 20 1 20) -add_test(NAME python.example.makepsfile COMMAND ${python} make-ps-file.py test-data/small-prestack.sgy 10 1 5 1 4 1 3) -add_test(NAME python.example.subcube COMMAND ${python} copy-sub-cube.py test-data/small.sgy test-data/copy.sgy) -add_test(NAME python.example.rotate COMMAND ${python} make-rotated-copies.py test-data/small.sgy ex-rotate.sgy) -add_test(NAME python.example.scan_min_max COMMAND ${python} scan_min_max.py test-data/small.sgy) -add_test(NAME python.example.multi-text COMMAND ${python} make-multiple-text.py test-data/multi-text.sgy) -add_test(NAME python.example.shot-gather COMMAND ${python} make-shot-gather.py test-data/shot-gather.py) +add_test( + NAME python.unit + COMMAND ${PYTHON_EXECUTABLE} -m pytest test/ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +configure_file(../test-data/small.sgy write.sgy COPYONLY) + +add_test( + NAME python.example.about + COMMAND ${PYTHON_EXECUTABLE} -m examples.about + ../test-data/small.sgy INLINE_3D CROSSLINE_3D + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_test( + NAME python.example.write + COMMAND ${PYTHON_EXECUTABLE} -m examples.write + ${CMAKE_CURRENT_BINARY_DIR}/write.sgy + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_test( + NAME python.example.makefile + COMMAND ${PYTHON_EXECUTABLE} -m examples.make-file + ../test-data/large-file.sgy 20 1 20 1 20 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_test( + NAME python.example.makepsfile + COMMAND ${PYTHON_EXECUTABLE} -m examples.make-ps-file + ../test-data/small-prestack.sgy 10 1 5 1 4 1 3 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_test( + NAME python.example.subcube + COMMAND ${PYTHON_EXECUTABLE} -m examples.copy-sub-cube + ../test-data/small.sgy ${CMAKE_CURRENT_BINARY_DIR}/copy.sgy + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_test( + NAME python.example.rotate + COMMAND ${PYTHON_EXECUTABLE} -m examples.make-rotated-copies + ../test-data/small.sgy ex-rotate.sgy ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_test( + NAME python.example.scan_min_max + COMMAND ${PYTHON_EXECUTABLE} -m examples.scan_min_max + ../test-data/small.sgy + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +add_test( + NAME python.example.multi-text + COMMAND ${PYTHON_EXECUTABLE} -m examples.make-multiple-text + _skbuild/multi-text.sgy + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/python/examples/__init__.py b/python/examples/__init__.py new file mode 100644 index 000000000..3a35b0a44 --- /dev/null +++ b/python/examples/__init__.py @@ -0,0 +1,6 @@ +# make the examples directory a module +# +# all the scripts in this directory are meant to be run as scripts, and just to +# demonstrate how to write certain programs. By adding __init__ and making this +# dir a module, cmake can run them as a part of the test step, without +# modification of the PYTHONPATH variable diff --git a/python/examples/make-rotated-copies.py b/python/examples/make-rotated-copies.py index 18a93268b..6dd482e5c 100644 --- a/python/examples/make-rotated-copies.py +++ b/python/examples/make-rotated-copies.py @@ -8,22 +8,23 @@ def product(f): return itr.product(range(len(f.ilines)), range(len(f.xlines))) -def pathjoin(prefix, path): - dir, base = os.path.split(path) - return os.path.join(dir, '-'.join((prefix, base))) +def pathjoin(prefix, path, directory): + _, base = os.path.split(path) + return os.path.join(directory, '-'.join((prefix, base))) # this program copies the source-file and creates eight copies, each with a # modified set of CDP-X and CDP-Y coordinates, rotating the field around the # north (increasing CDP-Y) axis. def main(): if len(sys.argv) < 2: - sys.exit("Usage: {} [source-file] [destination-file]".format(sys.argv[0])) + sys.exit("Usage: {} [source-file] [destination-file] [prefix]".format(sys.argv[0])) srcfile = sys.argv[1] dstfile = sys.argv[2] if len(sys.argv) > 2 else srcfile + prefix = sys.argv[3] if len(sys.argv) > 3 else os.path.split(dstfile) for pre in ['normal', 'acute', 'right', 'obtuse', 'straight', 'reflex', 'left', 'inv-acute']: - fname = pathjoin(pre, dstfile) + fname = pathjoin(pre, dstfile, prefix) shutil.copyfile(srcfile, fname) with segyio.open(srcfile) as src, segyio.open(fname, 'r+') as dst: @@ -34,56 +35,56 @@ def main(): dst.trace = src.trace dst.header = src.header - with segyio.open(pathjoin('normal', dstfile), 'r+') as dst: + with segyio.open(pathjoin('normal', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = x trh[su.cdpy] = y trh[su.scalco] = 10 - with segyio.open(pathjoin('acute', dstfile), 'r+') as dst: + with segyio.open(pathjoin('acute', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[y + x * len(src.ilines)] trh[su.cdpx] = x + y trh[su.cdpy] = (100 - x) + y trh[su.scalco] = -10 - with segyio.open(pathjoin('right', dstfile), 'r+') as dst: + with segyio.open(pathjoin('right', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = y trh[su.cdpy] = 100 - x trh[su.scalco] = 1 - with segyio.open(pathjoin('obtuse', dstfile), 'r+') as dst: + with segyio.open(pathjoin('obtuse', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = (100 - x) + y trh[su.cdpy] = (100 - x) - y trh[su.scalco] = 2 - with segyio.open(pathjoin('straight', dstfile), 'r+') as dst: + with segyio.open(pathjoin('straight', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 - x trh[su.cdpy] = 100 - y trh[su.scalco] = -7 - with segyio.open(pathjoin('reflex', dstfile), 'r+') as dst: + with segyio.open(pathjoin('reflex', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 - (x + y) trh[su.cdpy] = 100 + (x - y) trh[su.scalco] = 7 - with segyio.open(pathjoin('left', dstfile), 'r+') as dst: + with segyio.open(pathjoin('left', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 - y trh[su.cdpy] = x trh[su.scalco] = 21 - with segyio.open(pathjoin('inv-acute', dstfile), 'r+') as dst: + with segyio.open(pathjoin('inv-acute', dstfile, prefix), 'r+') as dst: for i, (x, y) in enumerate(product(src)): trh = dst.header[i] trh[su.cdpx] = 100 + x - y diff --git a/python/segyio/segyio.cpp b/python/segyio/segyio.cpp index 144c400da..f51f43c98 100644 --- a/python/segyio/segyio.cpp +++ b/python/segyio/segyio.cpp @@ -9,7 +9,7 @@ # include #endif -#include "segyio/segy.h" +#include #include #include diff --git a/python/setup-CMakeLists.txt b/python/setup-CMakeLists.txt new file mode 100644 index 000000000..cc14b6321 --- /dev/null +++ b/python/setup-CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.5.0) +project(segyio-python-extension LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 11) + +find_package(PythonExtensions REQUIRED) +find_package(segyio REQUIRED) + +add_library(_segyio MODULE segyio/segyio.cpp) +python_extension_module(_segyio) +target_link_libraries(_segyio segyio::segyio) + +if (MSVC) + target_compile_options(_segyio + BEFORE + PRIVATE + /EHsc + ) +endif () + +install(TARGETS _segyio LIBRARY DESTINATION segyio) diff --git a/setup.cfg b/python/setup.cfg similarity index 53% rename from setup.cfg rename to python/setup.cfg index 2c137bb51..7a7ede494 100644 --- a/setup.cfg +++ b/python/setup.cfg @@ -2,4 +2,4 @@ test=pytest [tool:pytest] -python_files = python/test/*.py +python_files = test/*.py diff --git a/setup.py b/python/setup.py similarity index 59% rename from setup.py rename to python/setup.py index 8c8246a54..85144f688 100644 --- a/setup.py +++ b/python/setup.py @@ -1,8 +1,7 @@ -#!/usr/bin/env python - import os import sys -from setuptools import setup, Extension +import skbuild +import setuptools long_description = """ ======= @@ -53,11 +52,6 @@ def src(x): root = os.path.dirname( __file__ ) return os.path.abspath(os.path.join(root, x)) -if 'win' in sys.platform: - extra_libs = [] -else: - extra_libs = ['m'] - def getversion(): # if this is a tarball distribution, the .git-directory won't be avilable # and setuptools_scm will crash hard. good tarballs are built with a @@ -65,18 +59,19 @@ def getversion(): # # set the SEGYIO_NO_GIT_VER environment variable to ignore a version from # git (useful when building for debian or other distributions) + pkgversion = { 'version': '0.0.0' } + versionfile = 'segyio/version.py' + if not 'SEGYIO_NO_GIT_VER' in os.environ and os.path.isdir(src('.git')): return { 'use_scm_version': { - 'root': src(''), - 'write_to': src('python/segyio/version.py') + 'relative_to' : src(''), + # write to ./python + 'write_to' : os.path.join(src(''), versionfile), } } - pkgversion = { 'version': '0.0.0' } - versionfile = src('python/segyio/version.py') - if not os.path.exists(versionfile): return pkgversion @@ -91,40 +86,47 @@ def getversion(): return pkgversion -setup(name='segyio', - description='Simple & fast IO for SEG-Y files', - long_description=long_description, - author='Statoil ASA', - author_email='fg_gpl@statoil.com', - url='https://github.com/Statoil/segyio', - package_dir={'' : src('python')}, - packages=['segyio', 'segyio.su'], - package_data={ 'segyio': ['segyio.dll'], }, - license='LGPL-3.0', - ext_modules=[Extension('segyio._segyio', - sources=[src('python/segyio/segyio.cpp')], - include_dirs=[src('lib/include')], - libraries=['segyio'] + extra_libs - )], - platforms='any', - install_requires=['numpy >=1.10'], - setup_requires=['setuptools >=28', 'setuptools_scm', 'pytest-runner'], - tests_require=['pytest'], - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Other Environment', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)', - 'Natural Language :: English', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Physics', - 'Topic :: Software Development :: Libraries', - 'Topic :: Utilities' - ], - **getversion() - ) +skbuild.setup( + name = 'segyio', + description = 'Simple & fast IO for SEG-Y files', + long_description = long_description, + author = 'Equinor ASA', + author_email = 'jokva@equinor.com', + url = 'https://github.com/equinor/segyio', + packages = ['segyio', 'segyio.su'], + package_data = { 'segyio': ['segyio.dll'], }, + license = 'LGPL-3.0', + platforms = 'any', + install_requires = ['numpy >= 1.10'], + setup_requires = [ + 'setuptools >= 28', + 'setuptools_scm', + 'pytest-runner', + 'scikit-build', + ], + tests_require = ['pytest'], + cmake_args = [ + # we can safely pass OSX_DEPLOYMENT_TARGET as it's ignored on + # everything not OS X. We depend on C++11, which makes our minimum + # supported OS X release 10.9 + '-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9', + ], + cmdclass = { 'test': setuptools.command.test.test }, + classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Other Environment', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)', + 'Natural Language :: English', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Physics', + 'Topic :: Software Development :: Libraries', + 'Topic :: Utilities' + ], + **getversion() + ) diff --git a/python/test/__init__.py b/python/test/__init__.py index f52567472..206e753ef 100644 --- a/python/test/__init__.py +++ b/python/test/__init__.py @@ -5,7 +5,7 @@ import py import os -testdata = py.path.local(os.path.abspath('test-data/')) +testdata = py.path.local(os.path.abspath('../test-data/')) def tmpfiles(*files): def tmpfiles_decorator(func):