[segyio] 164/376: Reorganise makefiles and CI

Jørgen Kvalsvik jokva-guest at moszumanska.debian.org
Wed Sep 20 08:04:26 UTC 2017


This is an automated email from the git hooks/post-receive script.

jokva-guest pushed a commit to branch debian
in repository segyio.

commit 7a50932d3b7f83373b6a1734243ccbd9348da302
Author: Jørgen Kvalsvik <jokva at statoil.com>
Date:   Mon Feb 6 14:47:48 2017 +0100

    Reorganise makefiles and CI
    
    Synopsis:
    * New directory layout.
    * Makefiles rewritten, export and install added
    * Tests moved to language directory
    * Windows DLLs expose symbols (with .def file)
    * cmake module paths no longer absolute
    * CI (appveyor.yml and .travis.yml) are more language agnostic
    * segyio-config.cmake created
    * Embeddable in other projects
    
    The top level directory now contains language-specific sub directories
    and global files such as changelog, licence, and readme.
    
    Tests and example programs are moved to their language directory, rather
    than being bundled together in tests/. This is largely to help keeping
    makefiles very language or sub-project specific, so minimal information
    need to be shared between sibling directories.
    
    Test data is still global, and is moved to /test-data. Every language's
    makefile is responsible for copying the test files it needs to the place
    it needs them.
    
    The python.cmake file has been heavily updated and generalised, and
    makes fewer assumptions about directory layout. It is also aware of
    potential C/C++ targets and handles all python-specific things, meaning
    the makefile for the python support can be very segyio oriented.
    
    The segyspec C functions are now considered an internal matlab detail
    and are moved into the mex directory.
    
    The C core layout has changed slightly. It is organised under lib/, and
    public headers are in the include/segyio directory. This separation is
    useful, since the segyio-* targets export their public headers
    (include/segyio), and not its private headers. This allows easier
    inclusion of segyio in other cmake based projects, and creates a clear
    separation of public and private interface.
    
    Ultimately, this means that projects can depend on segyio by either
    using segyio-config.cmake or source-wise by doing add_subdirectory. This
    was tested by writing a tiny program that depended on segyio with
    add_subdirectory(segyio) in the makefile, where segyio was a fresh
    checkout of this commit.
    
    Finally, The CI files no longer assume python is the only language to
    ever be supported.
---
 .travis.yml                                        |  22 +-
 CMakeLists.txt                                     |  51 ++--
 README.md                                          |  13 +-
 applications/CMakeLists.txt                        |   8 +-
 appveyor.yml                                       |  27 +-
 cmake/matlab.cmake                                 |   4 +-
 cmake/python.cmake                                 | 148 +++++++++--
 cmake/test_runner.py                               |  48 ----
 examples/CMakeLists.txt                            |   9 -
 lib/CMakeLists.txt                                 |  74 ++++++
 {src => lib/include}/segyio/segy.h                 |  23 ++
 {src/segyio => lib/src}/segy.c                     |  35 +++
 lib/src/segy.def                                   |  49 ++++
 {src => lib/src}/segyio/util.h                     |   8 +
 tests/test_segy.c => lib/test/segy.c               |   7 +
 tests/test_segyspec.c => lib/test/spec.c           |   0
 lib/test/unittest.h                                |  43 ++++
 tests/test_utils.c => lib/test/utils.c             |   0
 mex/CMakeLists.txt                                 |  10 +
 mex/segyspec_mex.c                                 |   2 +-
 mex/segyutil.c                                     | 127 +++++++++-
 mex/segyutil.h                                     |  26 +-
 python/CMakeLists.txt                              |  63 +++--
 {examples => python/examples}/about.py             |   0
 {examples => python/examples}/copy-sub-cube.py     |   0
 {examples => python/examples}/make-file.py         |   0
 {examples => python/examples}/make-ps-file.py      |   0
 {examples => python/examples}/scan_min_max.py      |   0
 {examples => python/examples}/write.py             |   0
 python/segyio/CMakeLists.txt                       |  17 --
 .../test_test_context.py => python/test/context.py |   0
 tests/test_segy.py => python/test/segy.py          |   0
 tests/test_segyio_c.py => python/test/segyio_c.py  |   0
 tests/test_enum.py => python/test/segyioenum.py    |   0
 {tests => python/test}/test_context.py             |   0
 tests/test_tools.py => python/test/tools.py        |   0
 setup.py                                           |   7 +-
 src/spec/segyspec.c                                | 129 ----------
 src/spec/segyspec.h                                |  33 ---
 {tests/test-data => test-data}/1x1.sgy             | Bin
 {tests/test-data => test-data}/1xN.sgy             | Bin
 {tests/test-data => test-data}/Mx1.sgy             | Bin
 {tests/test-data => test-data}/small-ps.sgy        | Bin
 {tests/test-data => test-data}/small.sgy           | Bin
 {tests/test-data => test-data}/text.sgy            | Bin
 tests/CMakeLists.txt                               |  28 --
 tests/test_segy_mex.m                              | 281 ---------------------
 tests/test_segyspec_mex.m                          |  88 -------
 48 files changed, 637 insertions(+), 743 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index b60a216..671fec1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,10 @@
 language: generic
 
 env:
-  - BUILD_TYPE=RELEASE;PYTHON=2.7
-  - BUILD_TYPE=RELEASE;PYTHON=3.5
-  - BUILD_TYPE=DEBUG;PYTHON=2.7
-  - BUILD_TYPE=DEBUG;PYTHON=3.5
+  - BUILD_TYPE=RELEASE; PYTHON=2.7;
+  - BUILD_TYPE=RELEASE; PYTHON=3.5;
+  - BUILD_TYPE=DEBUG; PYTHON=2.7;
+  - BUILD_TYPE=DEBUG; PYTHON=3.5;
 
 os:
   - linux
@@ -26,7 +26,7 @@ addons:
       packages:
         - valgrind
 
-before_script:
+install:
   # Valgrind is experimental(ish) on MacOS with false positives on among others printf
   #- if [[ "$TRAVIS_OS_NAME" == "osx" && "$BUILD_TYPE" == "DEBUG" ]]; then
   #    brew update;
@@ -51,11 +51,15 @@ before_script:
 
   - conda install numpy cmake
 
+before_script:
+  - enabled="-DBUILD_PYTHON=OFF -DBUILD_MEX=OFF"
+  - if [[ -n "${PYTHON+1}" ]]; then enabled="$enabled -DBUILD_PYTHON=ON"; fi
   - cmake --version
+
+script:
   - mkdir build
-  - cd build
-  - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
+  - pushd build
+  - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE $enabled  ..
   - make
   - export LD_LIBRARY_PATH=$PWD
-
-script: make && ctest --output-on-failure
+  - ctest --output-on-failure
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 324b3f2..8cd8a9f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,62 +1,43 @@
-cmake_minimum_required(VERSION 2.8.8)
+cmake_minimum_required(VERSION 2.8.11)
 project(segyio)
 
 if (POLICY CMP0042)
     cmake_policy(SET CMP0042 NEW)
 endif ()
 
+option(BUILD_PYTHON "Build Python wrappers"     ON)
+option(BUILD_MEX    "Build Matlab mex files"    OFF)
+
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
     set(MAC_OS TRUE)
 elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
     set(LINUX TRUE)
-    set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
 elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
     set(WINDOWS TRUE)
 endif ()
 
-option(BUILD_MEX    "Build Matlab mex files"    OFF)
-option(BUILD_PYTHON "Build Python wrappers"     ON)
-
-include(cmake/check_includes.cmake)
-include(cmake/default_warnings.cmake)
-include(cmake/segyio_testing.cmake)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+include(check_includes)
+include(default_warnings)
+include(segyio_testing)
 enable_testing()
 
-if (NOT MSVC)
-    set(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
-endif()
-
 if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
-    set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Default install path" FORCE)
+    set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install"
+        CACHE PATH "Default install path" FORCE)
 endif ()
 
-if(NOT CMAKE_BUILD_TYPE)
-    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+if (NOT CMAKE_BUILD_TYPE)
+    set(CMAKE_BUILD_TYPE "Release"
+        CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
+        FORCE)
 endif(NOT CMAKE_BUILD_TYPE)
 
-include_directories(src)
-set(SOURCE_FILES src/segyio/segy.c src/spec/segyspec.c)
-
-# The object library type is a reusable component for later builds: shared, static and python
-add_library(segyio-object OBJECT ${SOURCE_FILES})
-
-add_library(segyio-static STATIC $<TARGET_OBJECTS:segyio-object>)
-target_link_libraries(segyio-static ${SEGYIO_LIBRARIES})
-set_target_properties(segyio-static PROPERTIES OUTPUT_NAME segyio CLEAN_DIRECT_OUTPUT 1)
-set_target_properties(segyio-static PROPERTIES COMPILE_FLAGS "-fPIC")
-
-add_library(segyio-shared SHARED $<TARGET_OBJECTS:segyio-object>)
-target_link_libraries(segyio-shared ${SEGYIO_LIBRARIES} ${SEGYIO_LIBRARIES})
-set_target_properties(segyio-shared PROPERTIES OUTPUT_NAME segyio CLEAN_DIRECT_OUTPUT 1)
+set(testdata ${CMAKE_CURRENT_SOURCE_DIR}/test-data)
 
+add_subdirectory(lib)
 # language bindings
 add_subdirectory(mex)
 add_subdirectory(python)
 
 add_subdirectory(applications)
-add_subdirectory(examples)
-add_subdirectory(tests)
-
-# install the library
-install(FILES src/segyio/segy.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/segyio)
-install(TARGETS segyio-static segyio-shared DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
diff --git a/README.md b/README.md
index 9109874..7db28d3 100644
--- a/README.md
+++ b/README.md
@@ -36,9 +36,9 @@ written according to specification, but segyio does not mandate this.
 ## Getting started ##
 
 When Segyio is built and installed, you're ready to start programming! For
-examples and documentation, check out the examples in the examples directory.
-If you're using python, pydoc is used, so fire up your favourite python
-interpreter and type `help(segyio)` to get started.
+examples and documentation, check out the examples in the python/examples
+directory.  If you're using python, pydoc is used, so fire up your favourite
+python interpreter and type `help(segyio)` to get started.
 
 ### Requirements ###
 
@@ -80,9 +80,10 @@ It's recommended to build in debug mode to get more warnings and to embed debug
 symbols in the objects. Substituting `Debug` for `Release` in the
 `CMAKE_BUILD_TYPE` is plenty.
 
-Tests are located in the tests directory, and it's highly recommended that new
-features added are demonstrated for correctness and contract by adding a test.
-Feel free to use the tests already written as a guide.
+Tests are located in the language/tests directories, and it's highly
+recommended that new features added are demonstrated for correctness and
+contract by adding a test. Feel free to use the tests already written as a
+guide.
 
 After building Segyio you can run the tests with `ctest`, executed from the
 build directory.
diff --git a/applications/CMakeLists.txt b/applications/CMakeLists.txt
index e67bff1..9cd3741 100644
--- a/applications/CMakeLists.txt
+++ b/applications/CMakeLists.txt
@@ -1,10 +1,14 @@
+project(segyio-apps)
+
+if (NOT MSVC)
+    set(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+endif()
+
 add_executable(segyinfo segyinfo.c)
 target_link_libraries(segyinfo segyio-static)
-add_dependencies(segyinfo segyio-static)
 
 add_executable(segyinspect segyinspect.c)
 target_link_libraries(segyinspect segyio-static)
-add_dependencies(segyinspect segyio-static)
 
 install(TARGETS segyinfo DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
 install(TARGETS segyinspect DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
diff --git a/appveyor.yml b/appveyor.yml
index 2e103a7..932c9f8 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -14,15 +14,34 @@ platform:
     - x64
 
 environment:
+    OFF: -DBUILD_PYTHON=OFF -DBUILD_MEX=OFF
     matrix:
         - PYTHON: C:\Python27
+          LANG: -DBUILD_PYTHON=ON
         - PYTHON: C:\Python35
+          LANG: -DBUILD_PYTHON=ON
+
+matrix:
+    fast_finish: true
+
+init:
+    - INSTALL_DIR: C:\projects\segyio-install
+
+install:
+  - IF DEFINED PYTHON (IF "%platform%" == "x64" SET PYTHON=%PYTHON%-x64)
+  - IF DEFINED PYTHON %PYTHON%\python -m pip install --user numpy
+
+before_build:
+    - IF DEFINED PYTHON SET LANG=%LANG% -DPYTHON_EXECUTABLE=%PYTHON%\python.exe
 
 build_script:
-    - "%PYTHON%\\python -m pip install --user numpy"
     - cmake --version
+    - IF "%platform%" == "x64" set W64="-GVisual Studio 14 2015 Win64"
     - mkdir build
     - pushd build
-    - cmake C:\projects\SegyIO -DBUILD_MEX=OFF -DBUILD_PYTHON=ON -DCMAKE_BUILD_TYPE=%configuration% -DPYTHON_EXECUTABLE="%PYTHON%\\python.exe"
-    - cmake --build . --config %configuration%
-    - ctest -C %configuration% --output-on-failure -V
+    - cmake C:\projects\SegyIO %W64% %OFF% %LANG% -DCMAKE_BUILD_TYPE=%configuration% -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR%
+    - cmake --build . --config %configuration% --target install
+
+test_script:
+    - set PATH=%INSTALL_DIR%\bin;%PATH%
+    - ctest -C %configuration% --output-on-failure
diff --git a/cmake/matlab.cmake b/cmake/matlab.cmake
index f2454c7..2e9e69a 100644
--- a/cmake/matlab.cmake
+++ b/cmake/matlab.cmake
@@ -201,12 +201,12 @@ macro(mex MEX_NAME )
             CFLAGS="${MEX_CFLAGS}"
             LDFLAGS="${MEX_LDFLAGS}"
             ${OBJECT}
-            $<TARGET_FILE:segyio-static>
+            $<TARGET_FILE:segyio-shared>
             -outdir ${CMAKE_CURRENT_BINARY_DIR}
             ${MEX_SOURCE_FILE}
             DEPENDS
             ${MEX_SOURCE_FILE}
-            segyio-static
+            segyio-shared
             segyutil.o
             )
 
diff --git a/cmake/python.cmake b/cmake/python.cmake
index 1cd497b..ca61b25 100644
--- a/cmake/python.cmake
+++ b/cmake/python.cmake
@@ -1,11 +1,10 @@
-include(${CMAKE_SOURCE_DIR}/cmake/find_python_module.cmake)
-include(${CMAKE_SOURCE_DIR}/cmake/python_module_version.cmake)
+include(find_python_module)
+include(python_module_version)
+include(CMakeParseArguments)
 
 find_package(PythonInterp)
 find_package(PythonLibs REQUIRED)
 
-configure_file(${CMAKE_SOURCE_DIR}/cmake/test_runner.py ${CMAKE_BINARY_DIR}/tests/test_runner.py COPYONLY)
-
 if (EXISTS "/etc/debian_version")
     set( PYTHON_PACKAGE_PATH "dist-packages")
 else()
@@ -13,38 +12,141 @@ else()
 endif()
 set(PYTHON_INSTALL_PREFIX "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/${PYTHON_PACKAGE_PATH}" CACHE STRING "Subdirectory to install Python modules in")
 
-function(add_python_package PACKAGE_NAME PACKAGE_PATH PYTHON_FILES)
-    add_custom_target(package_${PACKAGE_NAME} ALL)
+# 
+# usage: add_python_package(<target> <name>
+#                           [APPEND]
+#                           [SUBDIR <dir>] [PATH <path>]
+#                           [TARGETS <tgt>...] [SOURCES <src>...]
+#
+# Create a new target <target>, analogous to add_library. Creates a python
+# package <name>, optionally at the path specified with PATH. If SUBDIR <dir>
+# is used, then the files will be copied to $root/dir/*, in order to create
+# python sub namespaces - if subdir is not used then all files will be put in
+# $root/*. SOURCES <src> is the python files to be copied to the directory in
+# question, and <tgt> are regular cmake libraries (targets created by
+# add_library).
+#
+# Wuen the APPEND option is used, the files and targets given will be added
+# onto the same target package - it is necessary to use APPEND when you want
+# sub modules. Consider the package foo, with the sub module bar. In python,
+# you'd do: `from foo.bar import baz`. This means the directory structure is
+# `foo/bar/baz.py` in the package. This is accomplished with:
+# add_python_package(mypackage mypackage SOURCES __init__.py)
+# add_python_package(mypackage mypackage APPEND SOURCES baz.py)
+#
+# This command provides install targets, but no exports.
+function(add_python_package pkg NAME)
+    set(options APPEND)
+    set(unary PATH SUBDIR)
+    set(nary  TARGETS SOURCES)
+    cmake_parse_arguments(PP "${options}" "${unary}" "${nary}" "${ARGN}")
+
+    set(installpath ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX}/${NAME})
+
+    if (PP_PATH)
+        # obey an optional path to install into - but prefer the reasonable
+        # default of currentdir/name
+        set(dstpath ${PP_PATH})
+    else ()
+        set(dstpath ${NAME})
+    endif()
+
+    # if APPEND is passed, we *add* files/directories instead of creating it.
+    # this can be used to add sub directories to a package. If append is passed
+    # and the target does not exist - create it
+    if (TARGET ${pkg} AND NOT PP_APPEND)
+        set(problem "Target '${pkg}' already exists")
+        set(descr "To add more files to this package")
+        set(solution "${descr}, use add_python_package(<target> <name> APPEND)")
+        message(FATAL_ERROR "${problem}. ${solution}.")
+
+    elseif (NOT TARGET ${pkg})
+        add_custom_target(${pkg} ALL)
 
-    foreach (file ${PYTHON_FILES})
-        add_custom_command(TARGET package_${PACKAGE_NAME}
-                COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/python/${PACKAGE_PATH}
-                COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${CMAKE_BINARY_DIR}/python/${PACKAGE_PATH}
+        get_filename_component(abspath ${CMAKE_CURRENT_BINARY_DIR} ABSOLUTE)
+        set_target_properties(${pkg} PROPERTIES PACKAGE_INSTALL_PATH ${installpath})
+        set_target_properties(${pkg} PROPERTIES PACKAGE_BUILD_PATH ${abspath})
+    endif ()
+    # append subdir if requested
+    if (PP_SUBDIR)
+        set(dstpath ${dstpath}/${PP_SUBDIR})
+        set(installpath ${installpath}/${PP_SUBDIR})
+    endif ()
+
+    # copy all .py files into
+    foreach (file ${PP_SOURCES})
+        get_filename_component(absfile ${file} ABSOLUTE)
+        add_custom_command(TARGET ${pkg}
+            COMMAND ${CMAKE_COMMAND} -E make_directory ${dstpath}
+            COMMAND ${CMAKE_COMMAND} -E copy ${absfile} ${dstpath}/
                 )
     endforeach ()
-    set_target_properties(package_${PACKAGE_NAME} PROPERTIES PACKAGE_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX}/${PACKAGE_PATH})
-    install(FILES ${PYTHON_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX}/${PACKAGE_PATH})
+
+    # targets are compiled as regular C/C++ libraries (via add_library), before
+    # we add some python specific stuff for the linker here.
+    if (MSVC)
+        # on windows, .pyd is used as extension instead of DLL
+        set(SUFFIX ".pyd")
+    elseif (APPLE)
+        # regular shared libraries on OS X are .dylib, but python wants .so
+        set(SUFFIX ".so")
+        # the spaces in LINK_FLAGS are important; otherwise APPEND_STRING to
+        # set_property seem to combine it with previously-set options or
+        # mangles it in some other way
+        set(LINK_FLAGS " -undefined dynamic_lookup ")
+    else()
+        set(LINK_FLAGS " -Xlinker -export-dynamic ")
+    endif()
+
+    # register all targets as python extensions
+    foreach (tgt ${PP_TARGETS})
+        set_target_properties(${tgt} PROPERTIES PREFIX "")
+        if (LINK_FLAGS)
+            set_property(TARGET ${tgt} APPEND_STRING PROPERTY LINK_FLAGS ${LINK_FLAGS})
+        endif()
+        if (SUFFIX)
+            set_property(TARGET ${tgt} APPEND_STRING PROPERTY SUFFIX ${SUFFIX})
+        endif()
+
+        # copy all targets into the package directory
+        add_custom_command(TARGET ${tgt} POST_BUILD
+            COMMAND ${CMAKE_COMMAND} -E make_directory ${dstpath}
+            COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${tgt}> ${dstpath}/
+        )
+    endforeach ()
+
+    if (NOT PP_SOURCES AND NOT PP_TARGETS AND NOT PP_APPEND)
+        message(FATAL_ERROR
+            "add_python_package called without .py files or C/C++ targets.")
+    endif()
+
+    if (PP_SOURCES)
+        install(FILES ${PP_SOURCES} DESTINATION ${installpath})
+    endif()
+
+    if (PP_TARGETS)
+        install(TARGETS ${PP_TARGETS} EXPORT ${pkg} DESTINATION ${installpath})
+    endif()
 endfunction()
 
 function(add_python_test TESTNAME PYTHON_TEST_FILE)
     configure_file(${PYTHON_TEST_FILE} ${PYTHON_TEST_FILE} COPYONLY)
-        
+    get_filename_component(name ${PYTHON_TEST_FILE} NAME)
+    get_filename_component(dir  ${PYTHON_TEST_FILE} DIRECTORY)
+
     add_test(NAME ${TESTNAME}
-            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests
-            COMMAND ${PYTHON_EXECUTABLE} test_runner.py ${PYTHON_TEST_FILE}
+            COMMAND ${PYTHON_EXECUTABLE} -m unittest discover -vs ${dir} -p ${name}
             )
-
-    to_path_list(pythonpath "${CMAKE_BINARY_DIR}/python" "$ENV{PYTHONPATH}")
-    set_tests_properties(${TESTNAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${pythonpath}")
 endfunction()
 
-function(add_python_example TESTNAME PYTHON_TEST_FILE)
+function(add_python_example pkg TESTNAME PYTHON_TEST_FILE)
     configure_file(${PYTHON_TEST_FILE} ${PYTHON_TEST_FILE} COPYONLY)
 
     add_test(NAME ${TESTNAME}
-            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples
-            COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_TEST_FILE} ${ARGN}
-            )
-    to_path_list(pythonpath "${CMAKE_BINARY_DIR}/python" "$ENV{PYTHONPATH}")
+            WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+            COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_TEST_FILE} ${ARGN})
+
+    get_target_property(buildpath ${pkg} PACKAGE_BUILD_PATH)
+    to_path_list(pythonpath "$ENV{PYTHONPATH}" ${buildpath})
     set_tests_properties(${TESTNAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${pythonpath}")
 endfunction()
diff --git a/cmake/test_runner.py b/cmake/test_runner.py
deleted file mode 100755
index 31e6fb9..0000000
--- a/cmake/test_runner.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-import inspect
-import os
-import sys
-
-import imp
-
-try:
-    from unittest2 import TextTestRunner, TestLoader, TestCase
-except ImportError:
-    from unittest import TextTestRunner, TestLoader, TestCase
-
-
-def runTestCase(tests, verbosity=0):
-    test_result = TextTestRunner(verbosity=verbosity).run(tests)
-
-    if len(test_result.errors) or len(test_result.failures):
-        test_result.printErrors()
-        return False
-    else:
-        return True
-
-def getTestClassFromModule(module_path):
-    test_module = imp.load_source('test', module_path)
-    for name, obj in inspect.getmembers(test_module):
-        if inspect.isclass(obj) and issubclass(obj, TestCase) and not obj == TestCase:
-            return obj
-
-def getTestsFromModule(module_path):
-    klass = getTestClassFromModule(module_path)
-    if klass is None:
-        raise UserWarning("No tests classes found in: '%s'" % module_path)
-    
-    loader = TestLoader()
-    return loader.loadTestsFromTestCase(klass)
-            
-
-if __name__ == '__main__':
-    test_module = sys.argv[1]
-    argv = []
-
-    tests = getTestsFromModule(test_module)
-
-    # Set verbosity to 2 to see which test method in a class that fails.
-    if runTestCase(tests, verbosity=0):
-        sys.exit(0)
-    else:
-        sys.exit(1)
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
deleted file mode 100644
index a48d185..0000000
--- a/examples/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-configure_file(../tests/test-data/small.sgy test-data/small.sgy COPYONLY)
-
-
-add_python_example(python.examples.about about.py test-data/small.sgy INLINE_3D CROSSLINE_3D)
-add_python_example(python.examples.write write.py test-data/small.sgy)
-add_python_example(python.examples.makefile make-file.py test-data/large-file.sgy 20 1 20 1 20)
-add_python_example(python.examples.makepsfile make-ps-file.py test-data/small-prestack.sgy 10 1 5 1 4 1 3)
-add_python_example(python.examples.subcube copy-sub-cube.py test-data/small.sgy test-data/copy.sgy)
-add_python_example(python.examples.scan_min_max scan_min_max.py test-data/small.sgy)
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644
index 0000000..2dc9e91
--- /dev/null
+++ b/lib/CMakeLists.txt
@@ -0,0 +1,74 @@
+project(libsegyio)
+
+if (NOT MSVC)
+    set(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+endif()
+
+set(SOURCE_FILES src/segy.c)
+
+set(STATIC_NAME segyio)
+if(WINDOWS)
+    # MSVC outputs the same name for static and shared libraries (with the same
+    # extension), so we need to differentiate between the two somehow.
+    set(STATIC_NAME "${STATIC_NAME}-static")
+    set(DLL_EXPORT_FILES src/segy.def)
+endif()
+
+#
+# static build
+#
+add_library(segyio-static STATIC ${SOURCE_FILES})
+target_link_libraries(segyio-static ${SEGYIO_LIBRARIES})
+set_target_properties(segyio-static PROPERTIES
+                      OUTPUT_NAME ${STATIC_NAME}
+                      CLEAN_DIRECT_OUTPUT 1)
+target_include_directories(
+    segyio-static PUBLIC
+    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+    $<INSTALL_INTERFACE:include>
+    PRIVATE src)
+
+#
+# dynamic build
+#
+add_library(segyio-shared SHARED ${SOURCE_FILES} ${DLL_EXPORT_FILES})
+target_link_libraries(segyio-shared ${SEGYIO_LIBRARIES})
+set_target_properties(segyio-shared PROPERTIES
+                      OUTPUT_NAME segyio
+                      CLEAN_DIRECT_OUTPUT 1)
+target_include_directories(
+    segyio-shared PUBLIC
+    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+    $<INSTALL_INTERFACE:include>
+    PRIVATE src)
+
+#
+# install & export
+#
+install(TARGETS segyio-static segyio-shared
+        EXPORT segyio
+        ARCHIVE DESTINATION lib
+        LIBRARY DESTINATION lib
+        RUNTIME DESTINATION bin)
+install(DIRECTORY include/ DESTINATION include)
+install(EXPORT segyio DESTINATION share/segyio/cmake)
+export(TARGETS segyio-static segyio-shared FILE segyio-config.cmake)
+
+#
+# tests
+#
+configure_file(${testdata}/small.sgy test-data/small.sgy             COPYONLY)
+configure_file(${testdata}/small.sgy test-data/small-traceheader.sgy COPYONLY)
+configure_file(${testdata}/text.sgy  test-data/text.sgy              COPYONLY)
+
+if(NOT MSVC)
+    set(math "m")
+endif()
+
+foreach (src segy utils)
+    add_executable(test${src} test/${src}.c)
+    target_link_libraries(test${src} segyio-shared ${math})
+    target_include_directories(test${src} PRIVATE src)
+    add_test(c.${src} test${src})
+    add_memcheck_test(test${src} test${src})
+endforeach()
diff --git a/src/segyio/segy.h b/lib/include/segyio/segy.h
similarity index 95%
rename from src/segyio/segy.h
rename to lib/include/segyio/segy.h
index 32e7494..3d2a576 100644
--- a/src/segyio/segy.h
+++ b/lib/include/segyio/segy.h
@@ -1,6 +1,10 @@
 #ifndef SEGYIO_SEGY_H
 #define SEGYIO_SEGY_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -178,6 +182,22 @@ int segy_count_lines( segy_file*,
                       unsigned int* l2out,
                       long trace0,
                       unsigned int trace_bsize );
+
+/*
+ * Alternative interface for segy_count_lines. If you have information about
+ * sorting this is easier to use, but requires both the inline and crossline
+ * header field positions. Does the argument shuffling needed to call
+ * segy_count_lines.
+ */
+int segy_lines_count( segy_file*,
+                      int il,
+                      int xl,
+                      int sorting,
+                      int offsets,
+                      int* il_count,
+                      int* xl_count,
+                      long trace0,
+                      unsigned int trace_bsize );
 /*
  * Find the `line_length` for the inlines. Assumes all inlines, crosslines and
  * traces don't vary in length.
@@ -408,5 +428,8 @@ typedef enum {
     SEGY_MMAP_INVALID,
 } SEGY_ERROR;
 
+#ifdef __cplusplus
+}
+#endif // __cplusplus
 
 #endif //SEGYIO_SEGY_H
diff --git a/src/segyio/segy.c b/lib/src/segy.c
similarity index 97%
rename from src/segyio/segy.c
rename to lib/src/segy.c
index 8b14ed9..b33c950 100644
--- a/src/segyio/segy.c
+++ b/lib/src/segy.c
@@ -937,6 +937,41 @@ int segy_count_lines( segy_file* fp,
     return SEGY_OK;
 }
 
+int segy_lines_count( segy_file* fp,
+                      int il,
+                      int xl,
+                      int sorting,
+                      int offsets,
+                      int* il_count,
+                      int* xl_count,
+                      long trace0,
+                      unsigned int trace_bsize ) {
+
+    if( sorting == UNKNOWN_SORTING ) return SEGY_INVALID_SORTING;
+
+    int field;
+    unsigned int l1out, l2out;
+
+    if( sorting == INLINE_SORTING ) field = xl;
+    else field = il;
+
+    int err = segy_count_lines( fp, field, offsets,
+                                &l1out, &l2out,
+                                trace0, trace_bsize );
+
+    if( err != SEGY_OK ) return err;
+
+    if( sorting == INLINE_SORTING ) {
+        *il_count = l1out;
+        *xl_count = l2out;
+    } else {
+        *il_count = l2out;
+        *xl_count = l1out;
+    }
+
+    return SEGY_OK;
+}
+
 unsigned int segy_inline_length(unsigned int crossline_count) {
     return crossline_count;
 }
diff --git a/lib/src/segy.def b/lib/src/segy.def
new file mode 100644
index 0000000..58b6e5e
--- /dev/null
+++ b/lib/src/segy.def
@@ -0,0 +1,49 @@
+LIBRARY segyio
+EXPORTS
+segy_open
+segy_mmap
+segy_flush
+segy_close
+segy_binheader_size
+segy_binheader
+segy_write_binheader
+segy_samples
+segy_sample_interval
+segy_format
+segy_get_field
+segy_get_bfield
+segy_set_field
+segy_set_bfield
+segy_trace_bsize
+segy_trace0
+segy_traces
+segy_sample_indexes
+segy_read_textheader
+segy_textheader_size
+segy_write_textheader
+segy_traceheader
+segy_write_traceheader
+segy_sorting
+segy_offsets
+segy_offset_indices
+segy_readtrace
+segy_writetrace
+segy_to_native
+segy_from_native
+segy_read_line
+segy_write_line
+segy_count_lines
+segy_lines_count
+segy_inline_length
+segy_crossline_length
+segy_inline_indices
+segy_crossline_indices
+segy_line_trace0
+segy_inline_stride
+segy_crossline_stride
+segy_seek
+segy_ftell
+ebcdic2ascii
+ascii2ebcdic
+ieee2ibm
+ibm2ieee
diff --git a/src/segyio/util.h b/lib/src/segyio/util.h
similarity index 85%
rename from src/segyio/util.h
rename to lib/src/segyio/util.h
index fa122ad..7582f09 100644
--- a/src/segyio/util.h
+++ b/lib/src/segyio/util.h
@@ -8,6 +8,10 @@
  * testing utilities. These functions won't show up in the installed headers.
  */
 
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
 struct segy_file_handle;
 
 void ebcdic2ascii( const char* ebcdic, char* ascii );
@@ -17,4 +21,8 @@ void ieee2ibm(void* to, const void* from);
 int segy_seek( struct segy_file_handle*, unsigned int, long, unsigned int );
 long segy_ftell( struct segy_file_handle* );
 
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
 #endif //SEGYIO_UTILS_H
diff --git a/tests/test_segy.c b/lib/test/segy.c
similarity index 99%
rename from tests/test_segy.c
rename to lib/test/segy.c
index 84551b8..f4f053e 100644
--- a/tests/test_segy.c
+++ b/lib/test/segy.c
@@ -585,12 +585,19 @@ static void test_file_size_above_4GB(){
 }
 
 int main() {
+    puts("starting");
+    puts("interpret file");
     test_interpret_file();
     /* test_interpret_file_prestack(); */
+    puts("read inline 4");
     testReadInLine_4();
+    puts("read inline 22");
     testReadCrossLine_22();
+    puts("mod traceh");
     test_modify_trace_header();
+    puts("mod texth");
     test_text_header();
+    puts("test traceh");
     test_trace_header_errors();
     /*
      * due to its barely-defined behavorial nature, this test is commented out
diff --git a/tests/test_segyspec.c b/lib/test/spec.c
similarity index 100%
rename from tests/test_segyspec.c
rename to lib/test/spec.c
diff --git a/lib/test/unittest.h b/lib/test/unittest.h
new file mode 100644
index 0000000..1ee1745
--- /dev/null
+++ b/lib/test/unittest.h
@@ -0,0 +1,43 @@
+#ifndef SEGYIO_UNITTEST_H
+#define SEGYIO_UNITTEST_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <math.h>
+
+static void testAssertionFailed(const char *message, const char *file, int line) {
+    fprintf(stderr, "Assertion failed in file: %s on line: %d\n", file, line);
+    if (strlen(message) > 0) {
+        fprintf(stderr, "%s", message);
+    }
+    exit(1);
+}
+
+#define assertTrue(value, message) testAssertTrue((value), (message), __FILE__, __LINE__)
+
+static void testAssertTrue(bool value, const char *message, const char *file, int line) {
+    if (!value) {
+        if (message && strlen(message) == 0) {
+            message = "The expression did not evaluate to true!";
+        }
+        testAssertionFailed(message, file, line);
+    }
+}
+
+#define assertClose(expected, actual, eps) testAssertClose((expected), (actual), (eps), __FILE__, __LINE__)
+
+static void testAssertClose(double expected, double actual, double eps, const char *file, int line) {
+    double diff = fabs(expected-actual);
+    if (diff > eps) {
+        char message[1000];
+        sprintf(message, "Expected: %f, Actual: %f, diff: %f, eps: %f\n", expected, actual, diff, eps);
+        testAssertionFailed(message, file, line);
+    }
+}
+
+
+
+#endif //SEGYIO_UNITTEST_H
diff --git a/tests/test_utils.c b/lib/test/utils.c
similarity index 100%
rename from tests/test_utils.c
rename to lib/test/utils.c
diff --git a/mex/CMakeLists.txt b/mex/CMakeLists.txt
index 44fe589..6a90949 100644
--- a/mex/CMakeLists.txt
+++ b/mex/CMakeLists.txt
@@ -1,3 +1,5 @@
+project(segyio-mex)
+
 if (NOT BUILD_MEX)
     unset(MATLAB_MCC CACHE)
     unset(MATLAB_MEX CACHE)
@@ -17,6 +19,8 @@ configure_file(SegySampleFormat.m SegySampleFormat.m)
 configure_file(TraceSortingFormat.m TraceSortingFormat.m)
 configure_file(TraceField.m TraceField.m)
 
+get_property(dirs TARGET segyio-shared PROPERTY INCLUDE_DIRECTORIES)
+include_directories(${dirs})
 
 mexo(segyutil)
 mex(segyspec_mex)
@@ -33,6 +37,7 @@ mex(segy_get_field_mex segyutil)
 mex(segy_put_headers_mex segyutil)
 mex(segy_get_offsets_mex segyutil)
 
+
 install(FILES
         ${CMAKE_CURRENT_BINARY_DIR}/segyspec_mex.mexa64
         ${CMAKE_CURRENT_BINARY_DIR}/segy_read_write_line_mex.mexa64
@@ -54,3 +59,8 @@ install(FILES
         TraceField.m
         DESTINATION
         ${CMAKE_INSTALL_PREFIX}/matlab)
+
+if(BUILD_MEX_TESTS)
+    add_matlab_test(matlab.segyspec test/spec.m test_segyspec_mex)
+    add_matlab_test(matlab.segy     test/segy.m test_segy_mex)
+endif()
diff --git a/mex/segyspec_mex.c b/mex/segyspec_mex.c
index e318fae..7f47bca 100644
--- a/mex/segyspec_mex.c
+++ b/mex/segyspec_mex.c
@@ -1,7 +1,7 @@
 #include <string.h>
 #include "mex.h"
 
-#include <../src/segyio/segy.h>
+#include <segyio/segy.h>
 #include "segyutil.h"
 
 mxArray *createPLHSStruct() {
diff --git a/mex/segyutil.c b/mex/segyutil.c
index 64abd25..4feaca7 100644
--- a/mex/segyutil.c
+++ b/mex/segyutil.c
@@ -2,9 +2,134 @@
 #include <malloc.h>
 #include <string.h>
 
-#include "segyio/segy.h"
+#include <segyio/segy.h>
 #include "segyutil.h"
 
+static char* copyString(const char* path) {
+    size_t size = strlen(path) + 1;
+    char* path_copy = malloc(size);
+    memcpy(path_copy, path, size);
+    return path_copy;
+}
+
+
+int segyCreateSpec(SegySpec* spec, const char* file, unsigned int inline_field, unsigned int crossline_field, double t0, double dt) {
+
+    int errc = 0;
+
+    segy_file* fp = segy_open( file, "rb" );
+    if (fp == NULL) {
+        fprintf(stderr, "Unable to open file: '%s'\n", file);
+        return -1;
+    }
+
+    spec->sample_indexes = NULL;
+    spec->inline_indexes = NULL;
+    spec->crossline_indexes = NULL;
+
+    char header[ SEGY_BINARY_HEADER_SIZE ];
+    errc = segy_binheader( fp, header );
+    if (errc!=0) {
+        goto CLEANUP;
+    }
+
+    spec->filename = copyString(file);
+    spec->sample_format = segy_format( header );
+    spec->sample_count = segy_samples( header );
+
+    spec->sample_indexes = malloc(sizeof(double) * spec->sample_count);
+    errc = segy_sample_indexes(fp, spec->sample_indexes, t0, dt, spec->sample_count);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    const long trace0 = segy_trace0( header );
+
+    spec->trace_bsize = segy_trace_bsize( segy_samples( header ) );
+    size_t traces;
+    errc = segy_traces(fp, &traces, trace0, spec->trace_bsize);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    errc = segy_offsets(fp, inline_field, crossline_field, traces, &spec->offset_count, trace0, spec->trace_bsize);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    errc = segy_sorting(fp, inline_field, crossline_field, &spec->trace_sorting_format, trace0, spec->trace_bsize);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    unsigned int* l1;
+    unsigned int* l2;
+    unsigned int field;
+    if (spec->trace_sorting_format == INLINE_SORTING) {
+        field = crossline_field;
+        l1 = &spec->inline_count;
+        l2 = &spec->crossline_count;
+    } else if (spec->trace_sorting_format == CROSSLINE_SORTING) {
+        field = inline_field;
+        l2 = &spec->inline_count;
+        l1 = &spec->crossline_count;
+    } else {
+        fprintf(stderr, "Unknown sorting\n");
+        goto CLEANUP;
+    }
+
+    errc = segy_count_lines(fp, field, spec->offset_count, l1, l2, trace0, spec->trace_bsize);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    spec->inline_indexes = malloc(sizeof(unsigned int) * spec->inline_count);
+    spec->crossline_indexes = malloc(sizeof(unsigned int) * spec->crossline_count);
+
+    errc = segy_inline_indices(fp, inline_field, spec->trace_sorting_format,
+                        spec->inline_count, spec->crossline_count, spec->offset_count, spec->inline_indexes,
+                        trace0, spec->trace_bsize);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    errc = segy_crossline_indices(fp, crossline_field, spec->trace_sorting_format,
+                        spec->inline_count, spec->crossline_count, spec->offset_count, spec->crossline_indexes,
+                        trace0, spec->trace_bsize);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    spec->first_trace_pos = segy_trace0( header );
+
+    errc = segy_inline_stride(spec->trace_sorting_format, spec->inline_count, &spec->il_stride);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    errc = segy_crossline_stride(spec->trace_sorting_format, spec->crossline_count, &spec->xl_stride);
+    if (errc != 0) {
+        goto CLEANUP;
+    }
+
+    segy_close(fp);
+
+    return 0;
+
+    CLEANUP:
+    if (spec->crossline_indexes != NULL)
+        free(spec->crossline_indexes);
+    if (spec->inline_indexes != NULL)
+        free(spec->inline_indexes);
+    if (spec->sample_indexes != NULL)
+        free(spec->sample_indexes);
+    free(spec->filename);
+
+    segy_close(fp);
+
+    return errc;
+}
+
 static int getMaxDim(mxArray* arr){
     int n = mxGetN(arr);
     int m = mxGetM(arr);
diff --git a/mex/segyutil.h b/mex/segyutil.h
index c9fe634..4f498d7 100644
--- a/mex/segyutil.h
+++ b/mex/segyutil.h
@@ -8,8 +8,32 @@
 
 #include <segyio/segy.h>
 
-#include "spec/segyspec.h"
+typedef struct {
+    char* filename;
 
+    unsigned int sample_format;
+
+    unsigned int* crossline_indexes;
+    unsigned int crossline_count;
+
+    unsigned int* inline_indexes;
+    unsigned int inline_count;
+
+    unsigned int offset_count;
+
+    double* sample_indexes;
+    unsigned int sample_count;
+
+    int trace_sorting_format;
+
+    unsigned int il_stride;
+    unsigned int xl_stride;
+    unsigned int first_trace_pos;
+    unsigned int trace_bsize;
+
+} SegySpec;
+
+int segyCreateSpec(SegySpec* spec, const char* file, unsigned int inline_field, unsigned int crossline_field, double t0, double dt);
 
 void recreateSpec(SegySpec* spec, const mxArray* mex_spec);
 
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 7523ec4..2fcb51b 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -1,8 +1,10 @@
+project(segyio-python)
+
 if (NOT BUILD_PYTHON)
     return()
 endif()
 
-include(${CMAKE_SOURCE_DIR}/cmake/python.cmake)
+include(python)
 
 if (NOT DEFINED PYTHON_EXECUTABLE)
     message("Python interpreter not found - Python wrappers not enabled")
@@ -24,29 +26,44 @@ if (NOT PYTHONLIBS_FOUND)
     return()
 endif()
 
-include_directories(${PYTHON_INCLUDE_DIRS})
-add_library(_segyio SHARED segyio/_segyio.c $<TARGET_OBJECTS:segyio-object>)
-
-if (MSVC)
-    set(LIB_SUFFIX "pyd")
-    set(LINK_FLAGS "/DLL ${PYTHON_LIBRARY}")
-elseif (MAC_OS)
-    set(LIB_SUFFIX "so")
-    set(LINK_FLAGS "-undefined dynamic_lookup")
-else()
-    set(LIB_SUFFIX "so")
-    set(LINK_FLAGS "-Xlinker -export-dynamic")
-endif()
+add_library(_segyio MODULE segyio/_segyio.c)
+target_include_directories(_segyio PRIVATE ${PYTHON_INCLUDE_DIRS})
+target_link_libraries(_segyio segyio-shared ${PYTHON_LIBRARIES})
+export(TARGETS _segyio segyio-shared FILE segyio-config.cmake)
 
-set_target_properties(_segyio PROPERTIES PREFIX "" SUFFIX ".${LIB_SUFFIX}")
-set_target_properties(_segyio PROPERTIES LINK_FLAGS ${LINK_FLAGS})
-target_link_libraries(_segyio ${SEGYIO_LIBRARIES})
+add_python_package(pysegyio segyio
+                    TARGETS _segyio
+                    SOURCES segyio/__init__.py
+                            segyio/_header.py
+                            segyio/_line.py
+                            segyio/_field.py
+                            segyio/_trace.py
+                            segyio/_raw_trace.py
+                            segyio/segy.py
+                            segyio/tracefield.py
+                            segyio/binfield.py
+                            segyio/open.py
+                            segyio/tools.py
+                            segyio/create.py
+                            segyio/segysampleformat.py
+                            segyio/tracesortingformat.py)
 
-install(TARGETS _segyio DESTINATION ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX}/segyio)
+file(GLOB sgys "${CMAKE_SOURCE_DIR}/test-data/*.sgy")
+foreach (sgy ${sgys})
+    get_filename_component(fl ${sgy} NAME)
+    configure_file(${sgy} test-data/${fl} COPYONLY)
+endforeach ()
 
-add_custom_command(TARGET _segyio POST_BUILD
-        COMMAND ${CMAKE_COMMAND} -E copy
-        $<TARGET_FILE:_segyio>
-        ${CMAKE_BINARY_DIR}/python/segyio/_segyio.${LIB_SUFFIX})
+configure_file(test/test_context.py test/test_context.py COPYONLY)
+add_python_test(python.segy         test/segy.py)
+add_python_test(python.h.segy       test/segyio_c.py)
+add_python_test(python.enum.segy    test/segyioenum.py)
+add_python_test(python.tools        test/tools.py)
+add_python_test(python.context      test/context.py)
 
-add_subdirectory(segyio)
+add_python_example(pysegyio python.example.about         examples/about.py test-data/small.sgy INLINE_3D CROSSLINE_3D)
+add_python_example(pysegyio python.example.write         examples/write.py test-data/small.sgy)
+add_python_example(pysegyio python.example.makefile      examples/make-file.py test-data/large-file.sgy 20 1 20 1 20)
+add_python_example(pysegyio python.example.makepsfile    examples/make-ps-file.py test-data/small-prestack.sgy 10 1 5 1 4 1 3)
+add_python_example(pysegyio python.example.subcube       examples/copy-sub-cube.py test-data/small.sgy test-data/copy.sgy)
+add_python_example(pysegyio python.example.scan_min_max  examples/scan_min_max.py test-data/small.sgy)
diff --git a/examples/about.py b/python/examples/about.py
similarity index 100%
rename from examples/about.py
rename to python/examples/about.py
diff --git a/examples/copy-sub-cube.py b/python/examples/copy-sub-cube.py
similarity index 100%
rename from examples/copy-sub-cube.py
rename to python/examples/copy-sub-cube.py
diff --git a/examples/make-file.py b/python/examples/make-file.py
similarity index 100%
rename from examples/make-file.py
rename to python/examples/make-file.py
diff --git a/examples/make-ps-file.py b/python/examples/make-ps-file.py
similarity index 100%
rename from examples/make-ps-file.py
rename to python/examples/make-ps-file.py
diff --git a/examples/scan_min_max.py b/python/examples/scan_min_max.py
similarity index 100%
rename from examples/scan_min_max.py
rename to python/examples/scan_min_max.py
diff --git a/examples/write.py b/python/examples/write.py
similarity index 100%
rename from examples/write.py
rename to python/examples/write.py
diff --git a/python/segyio/CMakeLists.txt b/python/segyio/CMakeLists.txt
deleted file mode 100644
index 32621d8..0000000
--- a/python/segyio/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-set(PYTHON_SOURCES
-        __init__.py
-        _header.py
-        _line.py
-        _field.py
-        _trace.py
-        _raw_trace.py
-        segy.py
-        tracefield.py
-        binfield.py
-        open.py
-        tools.py
-        create.py
-        segysampleformat.py
-        tracesortingformat.py)
-
-add_python_package(segyio segyio "${PYTHON_SOURCES}")
diff --git a/tests/test_test_context.py b/python/test/context.py
similarity index 100%
rename from tests/test_test_context.py
rename to python/test/context.py
diff --git a/tests/test_segy.py b/python/test/segy.py
similarity index 100%
rename from tests/test_segy.py
rename to python/test/segy.py
diff --git a/tests/test_segyio_c.py b/python/test/segyio_c.py
similarity index 100%
rename from tests/test_segyio_c.py
rename to python/test/segyio_c.py
diff --git a/tests/test_enum.py b/python/test/segyioenum.py
similarity index 100%
rename from tests/test_enum.py
rename to python/test/segyioenum.py
diff --git a/tests/test_context.py b/python/test/test_context.py
similarity index 100%
rename from tests/test_context.py
rename to python/test/test_context.py
diff --git a/tests/test_tools.py b/python/test/tools.py
similarity index 100%
rename from tests/test_tools.py
rename to python/test/tools.py
diff --git a/setup.py b/setup.py
index 470aba5..82542f2 100644
--- a/setup.py
+++ b/setup.py
@@ -3,9 +3,10 @@
 from distutils.core import setup, Extension
 
 _segyio = Extension('segyio._segyio',
-                    sources=['python/segyio/_segyio.c', 'src/segyio/segy.c', 'src/spec/segyspec.c'],
-                    include_dirs=['src'],
-                    extra_compile_args=["-std=c99"])
+                    sources=['python/segyio/_segyio.c', 'lib/src/segy.c'],
+                    include_dirs=['lib/src', 'lib/include'],
+                    define_macros=[('HAVE_MMAP', 1), ('HAVE_NETINET_IN_H', 1)],
+                    extra_compile_args=['-std=c99'])
 
 long_description = """
 =======
diff --git a/src/spec/segyspec.c b/src/spec/segyspec.c
deleted file mode 100644
index f3e08e5..0000000
--- a/src/spec/segyspec.c
+++ /dev/null
@@ -1,129 +0,0 @@
-#include <stdlib.h>
-
-#include "segyio/segy.h"
-#include "segyspec.h"
-
-static char* copyString(const char* path) {
-    size_t size = strlen(path) + 1;
-    char* path_copy = malloc(size);
-    memcpy(path_copy, path, size);
-    return path_copy;
-}
-
-
-int segyCreateSpec(SegySpec* spec, const char* file, unsigned int inline_field, unsigned int crossline_field, double t0, double dt) {
-
-    int errc = 0;
-
-    segy_file* fp = segy_open( file, "rb" );
-    if (fp == NULL) {
-        fprintf(stderr, "Unable to open file: '%s'\n", file);
-        return -1;
-    }
-
-    spec->sample_indexes = NULL;
-    spec->inline_indexes = NULL;
-    spec->crossline_indexes = NULL;
-
-    char header[ SEGY_BINARY_HEADER_SIZE ];
-    errc = segy_binheader( fp, header );
-    if (errc!=0) {
-        goto CLEANUP;
-    }
-
-    spec->filename = copyString(file);
-    spec->sample_format = segy_format( header );
-    spec->sample_count = segy_samples( header );
-
-    spec->sample_indexes = malloc(sizeof(double) * spec->sample_count);
-    errc = segy_sample_indexes(fp, spec->sample_indexes, t0, dt, spec->sample_count);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    const long trace0 = segy_trace0( header );
-
-    spec->trace_bsize = segy_trace_bsize( segy_samples( header ) );
-    size_t traces;
-    errc = segy_traces(fp, &traces, trace0, spec->trace_bsize);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    errc = segy_offsets(fp, inline_field, crossline_field, traces, &spec->offset_count, trace0, spec->trace_bsize);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    errc = segy_sorting(fp, inline_field, crossline_field, &spec->trace_sorting_format, trace0, spec->trace_bsize);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    unsigned int* l1;
-    unsigned int* l2;
-    unsigned int field;
-    if (spec->trace_sorting_format == INLINE_SORTING) {
-        field = crossline_field;
-        l1 = &spec->inline_count;
-        l2 = &spec->crossline_count;
-    } else if (spec->trace_sorting_format == CROSSLINE_SORTING) {
-        field = inline_field;
-        l2 = &spec->inline_count;
-        l1 = &spec->crossline_count;
-    } else {
-        fprintf(stderr, "Unknown sorting\n");
-        goto CLEANUP;
-    }
-
-    errc = segy_count_lines(fp, field, spec->offset_count, l1, l2, trace0, spec->trace_bsize);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    spec->inline_indexes = malloc(sizeof(unsigned int) * spec->inline_count);
-    spec->crossline_indexes = malloc(sizeof(unsigned int) * spec->crossline_count);
-
-    errc = segy_inline_indices(fp, inline_field, spec->trace_sorting_format,
-                        spec->inline_count, spec->crossline_count, spec->offset_count, spec->inline_indexes,
-                        trace0, spec->trace_bsize);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    errc = segy_crossline_indices(fp, crossline_field, spec->trace_sorting_format,
-                        spec->inline_count, spec->crossline_count, spec->offset_count, spec->crossline_indexes,
-                        trace0, spec->trace_bsize);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    spec->first_trace_pos = segy_trace0( header );
-
-    errc = segy_inline_stride(spec->trace_sorting_format, spec->inline_count, &spec->il_stride);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    errc = segy_crossline_stride(spec->trace_sorting_format, spec->crossline_count, &spec->xl_stride);
-    if (errc != 0) {
-        goto CLEANUP;
-    }
-
-    segy_close(fp);
-
-    return 0;
-
-    CLEANUP:
-    if (spec->crossline_indexes != NULL)
-        free(spec->crossline_indexes);
-    if (spec->inline_indexes != NULL)
-        free(spec->inline_indexes);
-    if (spec->sample_indexes != NULL)
-        free(spec->sample_indexes);
-    free(spec->filename);
-
-    segy_close(fp);
-
-    return errc;
-}
diff --git a/src/spec/segyspec.h b/src/spec/segyspec.h
deleted file mode 100644
index f23dd9f..0000000
--- a/src/spec/segyspec.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef SEGYIO_SEGYSPEC_H
-#define SEGYIO_SEGYSPEC_H
-
-#include <string.h>
-
-typedef struct {
-    char* filename;
-
-    unsigned int sample_format;
-
-    unsigned int* crossline_indexes;
-    unsigned int crossline_count;
-
-    unsigned int* inline_indexes;
-    unsigned int inline_count;
-
-    unsigned int offset_count;
-
-    double* sample_indexes;
-    unsigned int sample_count;
-
-    int trace_sorting_format;
-
-    unsigned int il_stride;
-    unsigned int xl_stride;
-    unsigned int first_trace_pos;
-    unsigned int trace_bsize;
-
-} SegySpec;
-
-int segyCreateSpec(SegySpec* spec, const char* file, unsigned int inline_field, unsigned int crossline_field, double t0, double dt);
-
-#endif //SEGYIO_SEGYSPEC_H
diff --git a/tests/test-data/1x1.sgy b/test-data/1x1.sgy
similarity index 100%
rename from tests/test-data/1x1.sgy
rename to test-data/1x1.sgy
diff --git a/tests/test-data/1xN.sgy b/test-data/1xN.sgy
similarity index 100%
rename from tests/test-data/1xN.sgy
rename to test-data/1xN.sgy
diff --git a/tests/test-data/Mx1.sgy b/test-data/Mx1.sgy
similarity index 100%
rename from tests/test-data/Mx1.sgy
rename to test-data/Mx1.sgy
diff --git a/tests/test-data/small-ps.sgy b/test-data/small-ps.sgy
similarity index 100%
rename from tests/test-data/small-ps.sgy
rename to test-data/small-ps.sgy
diff --git a/tests/test-data/small.sgy b/test-data/small.sgy
similarity index 100%
rename from tests/test-data/small.sgy
rename to test-data/small.sgy
diff --git a/tests/test-data/text.sgy b/test-data/text.sgy
similarity index 100%
rename from tests/test-data/text.sgy
rename to test-data/text.sgy
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
deleted file mode 100644
index c2ba75c..0000000
--- a/tests/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-configure_file(test-data/small.sgy      test-data/small.sgy COPYONLY)
-configure_file(test-data/small-ps.sgy   test-data/small-ps.sgy COPYONLY)
-configure_file(test-data/text.sgy       test-data/text.sgy COPYONLY)
-configure_file(test-data/small.sgy      test-data/small-traceheader.sgy COPYONLY)
-configure_file(test-data/Mx1.sgy        test-data/Mx1.sgy COPYONLY)
-configure_file(test-data/1xN.sgy        test-data/1xN.sgy COPYONLY)
-configure_file(test-data/1x1.sgy        test-data/1x1.sgy COPYONLY)
-
-add_segyio_test(utils test_utils.c)
-add_segyio_test(segy test_segy.c)
-add_segyio_test(segyspec test_segyspec.c)
-
-if(BUILD_MEX)
-    if(BUILD_MEX_TESTS)
-        add_matlab_test(matlab.segyspec test_segyspec_mex.m test_segyspec_mex)
-        add_matlab_test(matlab.segy test_segy_mex.m test_segy_mex)
-    endif()
-endif()
-
-
-if(BUILD_PYTHON)
-    configure_file(test_context.py test_context.py COPYONLY)
-    add_python_test(python.segy test_segy.py)
-    add_python_test(python.h.segy test_segyio_c.py)
-    add_python_test(python.enum.segy test_enum.py)
-    add_python_test(python.tools test_tools.py)
-    add_python_test(python.test_context test_test_context.py)
-endif()
diff --git a/tests/test_segy_mex.m b/tests/test_segy_mex.m
deleted file mode 100644
index 2e2f5b5..0000000
--- a/tests/test_segy_mex.m
+++ /dev/null
@@ -1,281 +0,0 @@
-% test segyline
-
-% preconditions
-filename = 'test-data/small.sgy';
-assert(exist(filename,'file')==2);
-t0 = 1111.0;
-
-%% Spec is created
-try
-    spec = Segy.interpret_segycube(filename, 'Inline3D', 'Crossline3D', t0);
-    spec = Segy.interpret_segycube(filename, TraceField.Inline3D, 'Crossline3D', t0);
-    spec = Segy.interpret_segycube(filename, TraceField.Inline3D, 193, t0);
-    data = Segy.get_cube( spec );
-
-    assert(all(size(data) == [50, 5, 5]));
-catch
-    %nothing should be caught
-    assert(false);
-end
-
-% fail when file doesn't exist
-
-try
-    Segy.get_header('does-not-exist', 193);
-    assert(false);
-catch
-    assert(true);
-end
-
-try
-    Segy.get_traces('does-not-exist', 189, 193 );
-    assert(false);
-catch
-    assert(true);
-end
-
-try
-    Segy.get_ntraces('does-not-exist');
-    assert(false);
-catch
-    assert(true);
-end
-
-try
-    Segy.interpret_segycube('does-not-exist');
-    assert(false);
-catch
-    assert(true);
-end
-
-%% Segy.readInLine 4
-
-spec = Segy.interpret_segycube(filename, 'Inline3D', 'Crossline3D', t0);
-data = Segy.get_line(spec, 'iline', 4);
-sample_count = length(spec.sample_indexes);
-
-eps = 1e-6;
-% first trace along xline
-% first sample
-assert(abs(data(1, 1) - 4.2)<eps);
-% middle sample
-assert(abs(data(sample_count/2,1)-4.20024)<eps);
-% last sample
-assert(abs(data(sample_count,1)-4.20049)<eps);
-
-% middle trace along xline
-middle = 3;
-% first sample
-assert(abs(data(1, middle) - 4.22) < eps);
-% middle sample
-assert(abs(data(sample_count/2,middle)-4.22024)<eps);
-% last sample
-assert(abs(data(sample_count,middle)-4.22049)<eps);
-
-% middle trace along xline
-last = length(spec.crossline_indexes);
-% first sample
-assert(abs(data(1, last) - 4.24) < eps);
-% middle sample
-assert(abs(data(sample_count/2,last)-4.24024)<eps);
-% last sample
-assert(abs(data(sample_count,last)-4.24049)<eps);
-
-%% Segy.readCrossLine 1433
-
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-data = Segy.readCrossLine(spec, 20);
-data = Segy.readCrossLine(spec, 21);
-data = Segy.readCrossLine(spec, 22);
-data = Segy.readCrossLine(spec, 23);
-data = Segy.readCrossLine(spec, 24);
-data = Segy.readCrossLine(spec, 22);
-sample_count = length(spec.sample_indexes);
-
-eps = 1e-4;
-% first trace along iline
-% first sample
-assert(abs(data(1, 1) - 1.22) < eps);
-% middle sample
-assert(abs(data(sample_count/2,1)-1.22024)<eps);
-% last sample
-assert(abs(data(sample_count,1)-1.22049)<eps);
-
-% middle trace along iline
-middle = 3;
-% first sample
-assert(abs(data(1, middle) - 3.22) < eps);
-% middle sample
-assert(abs(data(sample_count/2,middle)-3.22029)<eps);
-% last sample
-assert(abs(data(sample_count,middle)-3.22049)<eps);
-
-% middle trace along iline
-last = length(spec.inline_indexes);
-% first sample
-assert(abs(data(1, last) - 5.22) < eps);
-% middle sample
-assert(abs(data(sample_count/2,last)-5.22029)<eps);
-% last sample
-assert(abs(data(sample_count,last)-5.22049)<eps);
-
-filename_write = 'test-data/SEGY-3D_write_mex.sgy';
-
-copyfile(filename, filename_write)
-
-spec = SegySpec(filename_write, TraceField.Inline3D, TraceField.Crossline3D, t0);
-data = Segy.get_line(spec, 'xline', 22);
-
-assert(abs(data(1, 1) - 1.22) < eps);
-
-data(1,1) = 100;
-
-Segy.writeCrossLine(spec, data, 22);
-
-data = Segy.readCrossLine(spec, 22);
-assert(data(1, 1) == 100);
-
-data = Segy.readInLine(spec, 4);
-
-assert(abs(data(1, 1) - 4.2) < eps);
-
-data(1,1) = 200;
-
-Segy.writeInLine(spec, data, 4);
-
-data = Segy.readInLine(spec, 4);
-assert(data(1, 1) == 200);
-
-[~, dt, nt] = Segy.get_traces(filename);
-assert(dt == 4000);
-assert(nt == 1);
-
-[headers, notraces] = Segy.get_header(filename, 'Inline3D');
-assert(isequal((1:5), unique(headers)));
-assert(notraces == 25)
-
-assert(Segy.get_ntraces(filename) == 25);
-
-
-% Goal:
-%   Fast writing of segy file
-%
-% Inputs:
-%   filename         Filename of segyfile to write
-%   filename_orig    Filename of segyfile to copy header
-%   data:            Data
-%   nt:              Number of time samples
-%   nxl:             Number of Xlines
-%   nil:             Number of Inlines
-%
-% function provided by Matteo Ravasi
-
-Segy_struct_orig = Segy.interpret_segycube(filename,'Inline3D','Crossline3D');
-data = Segy.get_traces(filename);
-data = data + 1000;
-
-nt = 50;
-nxl = 5;
-nil = 5;
-
-if( ( nt  == numel( Segy_struct_orig.t ) ) &&...
-    ( nxl == numel( Segy_struct_orig.xline ) ) &&...
-    ( nil == numel( Segy_struct_orig.iline ) ) )
-
-    data = reshape( data, [nt, nxl*nil] );
-
-    filename_copy = 'test-data/SEGY-3D_copy.sgy';
-    copyfile( filename, filename_copy );
-
-    Segy.put_traces( filename_copy, data, 1, nxl*nil );
-    spec = Segy.interpret_segycube( filename_copy );
-    data = Segy.get_line(spec, 'iline', 4);
-
-    assert(abs(data(1, 1) - 1004.2) < eps);
-    assert(abs(data(sample_count/2,1) - 1004.20024) < eps);
-    assert(abs(data(sample_count,1) - 1004.20049) < eps);
-
-    middle = 3;
-    assert(abs(data(1, middle) - 1004.22) < eps);
-    assert(abs(data(sample_count/2, middle) - 1004.22024) < eps);
-    assert(abs(data(sample_count, middle) - 1004.22049) < eps);
-
-    last = length(spec.crossline_indexes);
-    assert(abs(data(1, last) - 1004.24) < eps);
-    assert(abs(data(sample_count/2, last) - 1004.24024) < eps);
-    assert(abs(data(sample_count, last) - 1004.24049) < eps);
-else
-    assert(false);
-end
-
-% test put_line
-data = Segy.get_line(spec, 'iline', 4);
-data = data + 100;
-p1 = data(sample_count/2, 1);
-p2 = data(sample_count, 1);
-Segy.put_line(spec, data, 'iline', 4);
-data = Segy.get_line( spec, 'iline', 4);
-assert(all([p1, p2] == [data(sample_count/2, 1), data(sample_count, 1)]));
-
-% read trace headers and file headers
-dummy = Segy.get_segy_header( filename );
-dummy = Segy.get_trace_header( filename, 0 );
-dummy = Segy.get_trace_header( filename, 10 );
-
-Segy.put_headers( filename, 10, 'cdp' );
-Segy.get_header( filename, 'cdp' );
-
-increasing = linspace( 1, notraces, notraces );
-Segy.put_headers( filename_copy, increasing, 'offset' );
-assert( all(increasing == Segy.get_header( filename_copy, 'offset' )) );
-
-%% test_traces_offset
-prestack_filename = 'test-data/small-ps.sgy';
-cube_with_offsets = Segy.parse_ps_segycube(prestack_filename);
-assert(isequal(cube_with_offsets.offset, [1 2]));
-
-try
-    ps_line1 = Segy.get_ps_line(cube_with_offsets, 'iline', 22);
-    % reading a line that doesn't exist should throw
-    assert(false);
-end
-ps_line1 = Segy.get_ps_line(cube_with_offsets, 'iline', 1);
-ps_line2 = Segy.get_ps_line(cube_with_offsets, 'xline', 1);
-
-% offset 1
-assert(abs(ps_line1(1,1,1) - 101.01)    < eps);
-assert(abs(ps_line1(1,1,2) - 101.02)    < eps);
-assert(abs(ps_line1(1,1,3) - 101.03)    < eps);
-assert(abs(ps_line1(2,1,1) - 101.01001) < eps);
-assert(abs(ps_line1(3,1,1) - 101.01002) < eps);
-assert(abs(ps_line1(2,1,2) - 101.02001) < eps);
-
-% offset 2
-assert(abs(ps_line1(1,2,1) - 201.01)    < eps);
-assert(abs(ps_line1(1,2,2) - 201.02)    < eps);
-assert(abs(ps_line1(1,2,3) - 201.03)    < eps);
-assert(abs(ps_line1(2,2,1) - 201.01001) < eps);
-assert(abs(ps_line1(3,2,1) - 201.01002) < eps);
-assert(abs(ps_line1(2,2,2) - 201.02001) < eps);
-
-%%%%% test writing of prestack lines
-prestack_dest = 'test-data/mex-tmp-small-ps.sgy';
-assert(copyfile(prestack_filename, prestack_dest));
-ps_cube_w = Segy.parse_ps_segycube(prestack_dest);
-Segy.put_ps_line( ps_cube_w, ps_line1 - 100.00, 'iline', 1 );
-% offset 1
-wr_line1 = Segy.get_ps_line( ps_cube_w, 'iline', 1 );
-assert(abs(wr_line1(1,1,1) - 001.01)    < eps);
-assert(abs(wr_line1(1,1,2) - 001.02)    < eps);
-assert(abs(wr_line1(1,1,3) - 001.03)    < eps);
-assert(abs(wr_line1(2,1,1) - 001.01001) < eps);
-assert(abs(wr_line1(3,1,1) - 001.01002) < eps);
-assert(abs(wr_line1(2,1,2) - 001.02001) < eps);
-
-% offset 2
-assert(abs(wr_line1(1,2,1) - 101.01)    < eps);
-assert(abs(wr_line1(1,2,2) - 101.02)    < eps);
-assert(abs(wr_line1(1,2,3) - 101.03)    < eps);
-assert(abs(wr_line1(2,2,1) - 101.01001) < eps);
-assert(abs(wr_line1(3,2,1) - 101.01002) < eps);
-assert(abs(wr_line1(2,2,2) - 101.02001) < eps);
diff --git a/tests/test_segyspec_mex.m b/tests/test_segyspec_mex.m
deleted file mode 100644
index bb8669b..0000000
--- a/tests/test_segyspec_mex.m
+++ /dev/null
@@ -1,88 +0,0 @@
-% test segyspec
-
-% preconditions 
-filename = 'test-data/small.sgy';
-assert(exist(filename,'file')==2);
-t0 = 1111.0;
-
-%% no such file
-no_such_filename = 'no-such-dir/no-such-file.sgy';
-assert(exist(no_such_filename,'file')~=2);
-try
-    spec = SegySpec(no_such_filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-    %should not reach here
-    assert(false);
-catch
-    %not actually needed...
-    assert(true);
-end
-
-%% Spec is created
-try
-    spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-catch
-    %nothing should be caught
-    assert(false);
-end
-
-%% IBM_FLOAT_4_BYTE
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-assert(spec.sample_format == SegySampleFormat.IBM_FLOAT_4_BYTE);
-
-%% filename is set
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-assert(strcmp(spec.filename,filename));
-
-%% trace_sorting_format
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-assert(spec.trace_sorting_format == TraceSortingFormat.iline);
-
-%%offset_count
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-assert(length(spec.offset_count) == 1);
-
-%% sample_indexes
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-sample_indexes = spec.sample_indexes;
-assert(length(sample_indexes) == 50);
-
-for i = 1:length(sample_indexes)
-    t = t0 + (i-1) * 4;
-    assert(sample_indexes(i) == t);
-end
-
-
-%% first_trace_pos
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-first_trace_pos = spec.first_trace_pos;
-assert(first_trace_pos == 3600);
-
-%% il_stride
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-il_stride = spec.il_stride;
-assert(il_stride == 1);
-
-%% xl_stride
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-xl_stride = spec.xl_stride;
-assert(xl_stride == 5);
-
-%% xl_stride
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-trace_bsize = spec.trace_bsize;
-assert(trace_bsize == 50*4);
-
-%% xline
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-assert(length(spec.crossline_indexes)==5)
-for xl = spec.crossline_indexes'
-    assert(xl >= 20 && xl <= 24);
-end
-
-%% iline
-spec = SegySpec(filename, TraceField.Inline3D, TraceField.Crossline3D, t0);
-assert(length(spec.inline_indexes)==5)
-
-for il = spec.inline_indexes'
-    assert(il >= 1 && il <= 5);
-end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/segyio.git



More information about the debian-science-commits mailing list