diff --git a/.gitlab-ci.astron.yml b/.gitlab-ci.astron.yml index 310737ce040b8141e41be3d78f17db68aaa94cb7..439879802e1ce70777178e2f6f0a6bde3fe8ce18 100644 --- a/.gitlab-ci.astron.yml +++ b/.gitlab-ci.astron.yml @@ -40,10 +40,13 @@ cibuild-python-wheels: - wget -qO - https://get.docker.com/ | sh - pip install cibuildwheel - cibuildwheel --output-dir wheelhouse - # rules: - # # Only run cibuildwheel when building the default branch or a tag. - # - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - # - if: '$CI_COMMIT_TAG' + rules: + # Run cibuildwheel for merge requests, or when building a tag or the default branch + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + tags: + - das6 artifacts: paths: - wheelhouse/*.whl diff --git a/.gitlab-ci.common.yml b/.gitlab-ci.common.yml index 79a8b15d6496c6512cb341f27591c81052be46aa..f2a5de0d8ed05d49a82a7620d4dcb38445e3405e 100644 --- a/.gitlab-ci.common.yml +++ b/.gitlab-ci.common.yml @@ -292,16 +292,6 @@ deploy-image-2204: # For testing this job on a branch, set the DEPLOY_IMAGE variable to true. - if: '$DEPLOY_IMAGE' -python-wheel-2204: - extends: .needs-base-2204 - stage: deploy - image: $BASE_IMAGE_2204 - variables: - GIT_SUBMODULE_STRATEGY: normal - script: - - python3 setup.py bdist_wheel - - pip install --user dist/*.whl - - python3 -c "import everybeam" artifacts: paths: - - dist/*.whl + - dist/everybeam*.whl diff --git a/CMake/PythonInstall.cmake b/CMake/PythonInstall.cmake deleted file mode 100644 index bdd6c6c3ca7d471ce0e38c9c4d4e49f96ed24fb6..0000000000000000000000000000000000000000 --- a/CMake/PythonInstall.cmake +++ /dev/null @@ -1,131 +0,0 @@ -# - Install Python source files. -# python_install(source1..sourceN DESTINATION install_dir) -# Install Python source files and byte-compile them in the directory -# ${PYTHON_INSTALL_DIR}/${install_dir}. - -# Copyright (C) 2020 ASTRON (Netherlands Institute for Radio Astronomy) -# SPDX-License-Identifier: GPL-3.0-or-later - -# Search for the Python interpreter. -find_package(PythonInterp) - -# Derive the Python site-packages installation directory and build directory. -if(PYTHON_EXECUTABLE) - set(_cmd - "from distutils.sysconfig import get_python_lib" - "from os.path import join" - "print(join( - get_python_lib(plat_specific=True, standard_lib=True, prefix=''), - 'site-packages'))" - ) - execute_process( - COMMAND "${PYTHON_EXECUTABLE}" "-c" "${_cmd}" - OUTPUT_VARIABLE _pydir - ERROR_VARIABLE _pyerr - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(_pyerr) - message(FATAL_ERROR "Python command failed:\n${_pyerr}") - endif(_pyerr) - - if(NOT DEFINED PYTHON_BUILD_DIR) - set(_PRINT_PYTHON_DIRS TRUE) - endif() - - set(PYTHON_BUILD_DIR "${CMAKE_BINARY_DIR}/${_pydir}" CACHE PATH - "Build directory for Python extensions" FORCE) - set(PYTHON_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${_pydir}" CACHE PATH - "Installation directory for Python extensions" FORCE) - - if(_PRINT_PYTHON_DIRS) - message(STATUS "Build directory for Python extensions: ${PYTHON_BUILD_DIR}") - message(STATUS "Installation directory for Python extensions: ${PYTHON_INSTALL_DIR}") - endif() -endif(PYTHON_EXECUTABLE) - - -# -# macro python_install -# -macro(python_install) - - # Precondition check. - if(NOT PYTHON_EXECUTABLE) - message(FATAL_ERROR "python_install: Python interpreter not available") - endif(NOT PYTHON_EXECUTABLE) - - # Parse arguments. - # apart from the python files list, there are two additional arguments - # DESTINATION (required), where to put the py files (relative to python lib dir) - # EXECUTABLE (optional), makes the py files executable - string(REGEX REPLACE ";?DESTINATION.*" "" _py_files "${ARGN}") - string(REGEX REPLACE ";?EXECUTABLE.*" "" _py_files "${_py_files}") - string(REGEX MATCH "DESTINATION;.*" _dest_dir "${ARGN}") - string(REGEX REPLACE "^DESTINATION;" "" _dest_dir "${_dest_dir}") - string(REGEX REPLACE ";?EXECUTABLE.*" "" _dest_dir "${_dest_dir}") - string(REGEX MATCH "EXECUTABLE;" _executable "${ARGN}") - - #check if optional argument EXECUTABLE is set - #if so, then install the _py_files as EXECUTABLE type (executable) - #else as normal files (not executable) - if("${_executable}" STRGREATER "") - set(INSTALL_TYPE PROGRAMS) - else() - set(INSTALL_TYPE FILES) - endif("${_executable}" STRGREATER "") - - if(_py_files MATCHES "^$") - message(FATAL_ERROR "python_install: no sources files specified") - endif(_py_files MATCHES "^$") - if(_dest_dir MATCHES "^$" OR _dest_dir MATCHES ";") - message(FATAL_ERROR "python_install: destination directory invalid") - endif(_dest_dir MATCHES "^$" OR _dest_dir MATCHES ";") - - # Set python package build/install directory. - set(_inst_dir "${PYTHON_INSTALL_DIR}/${_dest_dir}") - set(_build_dir "${PYTHON_BUILD_DIR}/${_dest_dir}") - - # Install and byte-compile each Python file. - foreach(_py ${_py_files}) - get_filename_component(_py_path ${_py} PATH) - get_filename_component(_py_abs ${_py} ABSOLUTE) - - # check if _py is a path in CMAKE_BINARY_DIR. If so, then it is most likely a configured_file. - # then strip the CMAKE_CURRENT_BINARY_DIR prefix. - if(${_py} MATCHES "^(${CMAKE_CURRENT_BINARY_DIR})") - string(REGEX REPLACE "^(${CMAKE_CURRENT_BINARY_DIR}/)" "" _py "${_py}") - get_filename_component(_py_path ${_py} PATH) - endif() - - # Create a symlink to each Python file; needed to mimic install tree. - file(MAKE_DIRECTORY ${_build_dir}/${_py_path}) - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink - ${_py_abs} ${_build_dir}/${_py}) - install(${INSTALL_TYPE} ${_py_abs} DESTINATION ${_inst_dir}/${_py_path}) - if(USE_PYTHON_COMPILATION) - set(_py_code - "import py_compile, os" - "destdir = os.environ.get('DESTDIR','')" - "print('-- Byte-compiling: %s${_inst_dir}/${_py}' % destdir)" - "py_compile.compile('%s${DESTDIR}${_inst_dir}/${_py}' % destdir, doraise=True)") - install(CODE - "execute_process(COMMAND ${PYTHON_EXECUTABLE} -c \"${_py_code}\" - RESULT_VARIABLE _result) - if(NOT _result EQUAL 0) - message(FATAL_ERROR \"Byte-compilation FAILED: \$ENV{DESTDIR}${_inst_dir}/${_py}\") - endif(NOT _result EQUAL 0)") - endif(USE_PYTHON_COMPILATION) - endforeach(_py ${_py_files}) - - # Make sure that there's a __init__.py file in each build/install directory. - string(REGEX REPLACE "/" ";" _dir_list ${_dest_dir}) - set(_init_dir) - foreach(_dir ${_dir_list}) - set(_init_dir "${_init_dir}/${_dir}") - execute_process(COMMAND ${CMAKE_COMMAND} -E touch - "${PYTHON_BUILD_DIR}${_init_dir}/__init__.py") - install(CODE - "execute_process(COMMAND ${CMAKE_COMMAND} -E touch - \"\$ENV{DESTDIR}${PYTHON_INSTALL_DIR}${_init_dir}/__init__.py\")") - endforeach(_dir ${_dir_list}) - -endmacro(python_install) diff --git a/CMake/config.h.in b/CMake/config.h.in index c128798ca6728c828bc5b1313593abaee0b8da3b..e2270e4ff5aabf245fde9cdd2c413e182ed4bcc8 100644 --- a/CMake/config.h.in +++ b/CMake/config.h.in @@ -5,7 +5,7 @@ #define EVERYBEAM_CONFIG_H_ #define EVERYBEAM_DATADIR "@EVERYBEAM_DATADIR@" -#define EVERYBEAM_FULL_DATADIR "@EVERYBEAM_FULL_DATADIR@" +#define EVERYBEAM_ABSOLUTE_DATADIR "@EVERYBEAM_ABSOLUTE_DATADIR@" #define TEST_MEASUREMENTSET "@TEST_MEASUREMENTSET@" #define LOFAR_HBA_MOCK_MS "@LOFAR_HBA_MOCK_MS@" #define LOFAR_LBA_MOCK_MS "@LOFAR_LBA_MOCK_MS@" diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e030aa5ff139cae88011425ebf9f72d358929b6..70d3dada4687d37765595a8b3c8ba0fe560302ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.15) #------------------------------------------------------------------------------ # Set version name and project number -set(EVERYBEAM_VERSION 0.5.3) +set(EVERYBEAM_VERSION 0.5.3) # Keep in sync with `pyproject.toml` file if(EVERYBEAM_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") set(EVERYBEAM_VERSION_MAJOR "${CMAKE_MATCH_1}") set(EVERYBEAM_VERSION_MINOR "${CMAKE_MATCH_2}") @@ -53,6 +53,16 @@ option(DOWNLOAD_LWA "Download and install OVRO-LWA coefficient file" OFF) string(TOLOWER ${CMAKE_PROJECT_NAME} projectname) +# When the software is built with, e.g., `pip` or `build`, `scikit-build-core` +# controls the build, and software will be installed in `site-packages`. In +# this case we do not want to install libraries in `lib`, but instead follow +# the convention of installing libraries in a directory `<package>.libs`. +if(SKBUILD) + set(INSTALL_LIBDIR everybeam.libs) +else() + set(INSTALL_LIBDIR lib) +endif() + # Set the path to CMake modules set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake) @@ -85,6 +95,9 @@ else() set(FIND_CUDA OFF CACHE INTERNAL "") + # Ensure that the ska-sdp-func library is installed in the same directory as + # the other everybeam libraries. + set(SDP_FUNC_LIB_INSTALL_DIR "${INSTALL_LIBDIR}") FetchContent_Declare( ska-sdp-func GIT_REPOSITORY ${ska-sdp-func_GIT_REPOSITORY} @@ -106,11 +119,23 @@ set(EVERYBEAM_DATADIR "share/${projectname}" CACHE STRING "EveryBeam data directory") if(IS_ABSOLUTE ${EVERYBEAM_DATADIR}) - set(EVERYBEAM_FULL_DATADIR "${EVERYBEAM_DATADIR}") + set(EVERYBEAM_ABSOLUTE_DATADIR "${EVERYBEAM_DATADIR}") else() - set(EVERYBEAM_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/${EVERYBEAM_DATADIR}") + set(EVERYBEAM_ABSOLUTE_DATADIR "${CMAKE_INSTALL_PREFIX}/${EVERYBEAM_DATADIR}") endif() -message("Storing data in: " ${EVERYBEAM_FULL_DATADIR}) + +# When the software is built with, e.g., `pip` or `build`, `scikit-build-core` +# controls the build. In this case we need to follow the naming convention in +# PEP-491 for the data directory, otherwise the data files will not be +# installed in the right directory when the python wheel is unpacked. +if(SKBUILD) + # Following naming convention of data directory in PEP 491 + set(EVERYBEAM_INSTALL_DATADIR + "${projectname}-${EVERYBEAM_VERSION}.data/data/share/${projectname}") +else() + set(EVERYBEAM_INSTALL_DATADIR ${EVERYBEAM_DATADIR}) +endif() +message("Installing data files in: ${EVERYBEAM_INSTALL_DATADIR}") # Find and include git submodules find_package(Git QUIET) @@ -234,16 +259,15 @@ set(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # the RPATH to be used when installing, but only if it's not a system directory list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES - "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) + "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") - set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -endif("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") +endif() #------------------------------------------------------------------------------ # Set up a test_data directory in the build directory. diff --git a/cibuildwheel/before_all.sh b/cibuildwheel/before_all.sh index 1372d9697c82621bb47aa58a7c68a7e06649680a..9d85f5e4e4f457f78d423699e7e0848cc6fa6204 100755 --- a/cibuildwheel/before_all.sh +++ b/cibuildwheel/before_all.sh @@ -26,11 +26,12 @@ function download_and_build_fftw /bin/echo -e "\n==> Building and installing FFTW ${FFTW_VERSION} ...\n" cd "${WORKDIR}/fftw-${FFTW_VERSION}" ./configure \ + --quiet \ --prefix /usr/local \ --enable-threads \ --enable-shared \ --enable-float - make -j"${nproc}" install + make --jobs="${nproc}" --quiet install } @@ -46,11 +47,12 @@ function download_and_build_hdf5 /bin/echo -e "\n==> Building and installing HDF5 ${HDF5_VERSION} ...\n" cd "${WORKDIR}/hdf5-${HDF5_VERSION}" ./configure \ + --quiet \ --prefix /usr/local \ --enable-build-mode=production \ --with-szlib \ --enable-cxx - make -j"${nproc}" install + make --jobs="${nproc}" --quiet install } diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index d7278c30e18f754bfe3d8284b9515a5be8235d14..66574d6e1699fc9556b01dc59f9489b09eb9a7b0 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -103,10 +103,15 @@ target_link_libraries( target_link_libraries(everybeam PRIVATE schaapcommon Threads::Threads xtensor ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES}) +if(SKBUILD) + set_target_properties(everybeam PROPERTIES INSTALL_RPATH "$ORIGIN") +endif() + install( TARGETS everybeam everybeam-core + COMPONENT libraries EXPORT EveryBeamTargets - DESTINATION lib) + DESTINATION ${INSTALL_LIBDIR}) install( FILES antenna.h diff --git a/cpp/hamaker/CMakeLists.txt b/cpp/hamaker/CMakeLists.txt index fe51c4b3840ef26b74f60c328c84c7bf08d5a041..0b1b919577771740b60e908b714682da4217869b 100644 --- a/cpp/hamaker/CMakeLists.txt +++ b/cpp/hamaker/CMakeLists.txt @@ -10,16 +10,21 @@ target_link_libraries(hamaker PUBLIC ${HDF5_CXX_LIBRARIES} everybeam-core) string(TOLOWER ${CMAKE_PROJECT_NAME} projectname) set_target_properties(hamaker PROPERTIES LIBRARY_OUTPUT_NAME "${projectname}-hamaker") +if(SKBUILD) + set_target_properties(hamaker PROPERTIES INSTALL_RPATH "$ORIGIN") +endif() # install libhamaker.so install( TARGETS hamaker + COMPONENT libraries EXPORT EveryBeamTargets - DESTINATION lib) + DESTINATION ${INSTALL_LIBDIR}) # install coefficients -message("install hamaker in: " ${EVERYBEAM_FULL_DATADIR}) -install(FILES "${CMAKE_SOURCE_DIR}/coeffs/HamakerHBACoeff.h5" - DESTINATION ${EVERYBEAM_DATADIR}) -install(FILES "${CMAKE_SOURCE_DIR}/coeffs/HamakerLBACoeff.h5" - DESTINATION ${EVERYBEAM_DATADIR}) +message("Install Hamaker coefficients in: ${EVERYBEAM_INSTALL_DATADIR}") +install( + FILES "${CMAKE_SOURCE_DIR}/coeffs/HamakerHBACoeff.h5" + "${CMAKE_SOURCE_DIR}/coeffs/HamakerLBACoeff.h5" + COMPONENT data-files + DESTINATION ${EVERYBEAM_INSTALL_DATADIR}) diff --git a/cpp/lobes/CMakeLists.txt b/cpp/lobes/CMakeLists.txt index cb0339c80318947ebfb81268e4471ffa0e75521f..68d5665b5c8bcec154717e6c118458ae546bbb10 100644 --- a/cpp/lobes/CMakeLists.txt +++ b/cpp/lobes/CMakeLists.txt @@ -17,10 +17,11 @@ if(DOWNLOAD_LOBES OR BUILD_TESTING) endif() # install coefficients -message("install lobes coefficients in: " ${EVERYBEAM_FULL_DATADIR}/lobes) +message("Install LOBES coefficients in: ${EVERYBEAM_INSTALL_DATADIR}/lobes") install( DIRECTORY "${CMAKE_BINARY_DIR}/coeffs/lobes" - DESTINATION ${EVERYBEAM_DATADIR} + COMPONENT data-files + DESTINATION ${EVERYBEAM_INSTALL_DATADIR} FILES_MATCHING PATTERN "LOBES_*") diff --git a/cpp/lwa/CMakeLists.txt b/cpp/lwa/CMakeLists.txt index 9ccf7f3587cf68bf3a718a20c6b64bd39149fcf1..c700974706d7dca3d68dbdda512add489c595be5 100644 --- a/cpp/lwa/CMakeLists.txt +++ b/cpp/lwa/CMakeLists.txt @@ -16,8 +16,8 @@ if(DOWNLOAD_LWA OR BUILD_TESTING) add_dependencies(everybeam download_lwa_coefficients) # install coefficients - message("install LWA coefficients in: " ${EVERYBEAM_FULL_DATADIR}/lwa) + message("Install LWA coefficients in: ${EVERYBEAM_INSTALL_DATADIR}/lwa") install(FILES "${CMAKE_BINARY_DIR}/coeffs/lwa/LWA_OVRO.h5" - DESTINATION "${EVERYBEAM_DATADIR}/lwa") + DESTINATION "${EVERYBEAM_INSTALL_DATADIR}/lwa") endif() diff --git a/cpp/options.cc b/cpp/options.cc index 6d7add45e8bcf2af65834af7430750f1fa2158dd..4dc2081bef114360a09ef32aabd6fb8dad2db77a 100644 --- a/cpp/options.cc +++ b/cpp/options.cc @@ -13,7 +13,7 @@ namespace everybeam { // TODO(RAP-260) Improve this path lookup. std::filesystem::path GetDataDirectory() { const char* envvar; - if (std::strcmp(EVERYBEAM_DATADIR, EVERYBEAM_FULL_DATADIR) == 0) + if (std::strcmp(EVERYBEAM_DATADIR, EVERYBEAM_ABSOLUTE_DATADIR) == 0) return std::filesystem::path(EVERYBEAM_DATADIR); if ((envvar = std::getenv("EVERYBEAM_DATADIR"))) return std::filesystem::path(envvar); @@ -21,6 +21,6 @@ std::filesystem::path GetDataDirectory() { return std::filesystem::path(envvar) / EVERYBEAM_DATADIR; if ((envvar = std::getenv("VIRTUAL_ENV"))) return std::filesystem::path(envvar) / EVERYBEAM_DATADIR; - return std::filesystem::path(EVERYBEAM_FULL_DATADIR); + return std::filesystem::path(EVERYBEAM_ABSOLUTE_DATADIR); } } // namespace everybeam diff --git a/cpp/oskar/CMakeLists.txt b/cpp/oskar/CMakeLists.txt index 47e0cd0de035ff4932e906dbe991a5f42820413f..af0499e8741c944f78d03b6eacf85e7c7aa747c9 100644 --- a/cpp/oskar/CMakeLists.txt +++ b/cpp/oskar/CMakeLists.txt @@ -13,7 +13,9 @@ add_library(oskar SHARED oskarelementresponse.cc oskardatafile.cc string(TOLOWER ${CMAKE_PROJECT_NAME} projectname) set_target_properties(oskar PROPERTIES LIBRARY_OUTPUT_NAME "${projectname}-oskar") - +if(SKBUILD) + set_target_properties(oskar PROPERTIES INSTALL_RPATH "$ORIGIN") +endif() # Make sure that when other targets within this project link against the oskar target, # they can find the include files. target_include_directories( @@ -29,9 +31,12 @@ target_link_libraries(oskar PRIVATE ska-sdp-func::ska-sdp-func) # install libeverybeam-oskar.so install( TARGETS oskar + COMPONENT libraries EXPORT EveryBeamTargets - DESTINATION lib) + DESTINATION ${INSTALL_LIBDIR}) #install oskar coefficients -install(FILES "${CMAKE_SOURCE_DIR}/coeffs/oskar.h5" - DESTINATION ${EVERYBEAM_DATADIR}) +install( + FILES "${CMAKE_SOURCE_DIR}/coeffs/oskar.h5" + COMPONENT data-files + DESTINATION ${EVERYBEAM_INSTALL_DATADIR}) diff --git a/cpp/skamidbeam/CMakeLists.txt b/cpp/skamidbeam/CMakeLists.txt index 217505fb1436ac2198aa90747d57d8a20d76276f..042b38979d214c83e181c55f1e39f22c0f999d7c 100644 --- a/cpp/skamidbeam/CMakeLists.txt +++ b/cpp/skamidbeam/CMakeLists.txt @@ -18,5 +18,6 @@ target_include_directories( # install libeverybeam-skamidbeam.so install( TARGETS skamidbeam + COMPONENT libraries EXPORT EveryBeamTargets - DESTINATION lib) + DESTINATION ${INSTALL_LIBDIR}) diff --git a/pyproject.toml b/pyproject.toml index 7bc4b61e99a3aacf0f215e49ade992f19ba43d49..577aaaa672309a79c721f7f21c32fd92def7c028 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,23 +1,76 @@ +######################### +# build-system settings # +######################### + [build-system] requires = [ - "build", - "cmake>=3.18", - "oldest-supported-numpy", - "setuptools", - "wheel", + "scikit-build-core", +] +build-backend = "scikit_build_core.build" + + +#################### +# project settings # +#################### + +[project] +name = "everybeam" +version = "0.5.3" # Keep in sync with top-level `CMakeLists.txt` file +description = "EveryBeam" +readme = {file = "README.md", content-type = "text/markdown"} +requires-python = ">=3.7" +license = {text = "GPLv3+"} +authors = [ + {name = "Bram Veenboer", email = "veenboer@astron.nl"}, + {name = "André Offringa", email = "offringa@astron.nl"}, + {name = "Sebastiaan van der Tol", email = "tol@astron.nl"}, + {name = "Tammo Jan Dijkema", email = "dijkema@astron.nl"}, + {name = "Jakob Maljaars", email = "jakob.maljaars@stcorp.nl"}, + {name = "Maik Nijhuis", email = "maik.nijhuis@triopsys.nl"}, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Programming Language :: C++", + "Programming Language :: Python :: 3", + "Topic :: Scientific/Engineering :: Astronomy", ] +dependencies = [ + "numpy", +] + +[project.urls] +Homepage = "https://git.astron.nl/RD/EveryBeam/" +Documentation = "https://everybeam.readthedocs.io/" +Repository = "https://git.astron.nl/RD/EveryBeam.git" + + +######################### +# cibuildwheel settings # +######################### [tool.cibuildwheel] +## Build before-all = "cibuildwheel/before_all.sh" before-build = "cibuildwheel/before_build.sh" build = "cp3{7,8,9,10,11}-*_x86_64" -build-verbosity = 1 environment = """ \ WORKDIR="/tmp" \ FFTW_VERSION="3.3.8" \ HDF5_VERSION="1.12.2" \ """ -# test-command = "cd {package}/python/test && pytest" +## Test +before-test = [ + "scripts/download_ms.sh lba.MS.tar.bz2 LOFAR_LBA_MOCK.ms", + "scripts/download_ms.sh L258627-one-timestep.tar.bz2 LOFAR_HBA_MOCK.ms", +] +test-command = [ + "export DATA_DIR={project}", + "export EVERYBEAM_DATADIR=$(dirname $(which python))/../share/everybeam", + "pytest -v {package}/python/test/test_pybindings.py" +] +test-requires = "pytest-lazy-fixture" [tool.cibuildwheel.macos] repair-wheel-command = """\ @@ -47,3 +100,17 @@ manylinux-x86_64-image = "quay.io/casacore/casacore:master_wheel310" [[tool.cibuildwheel.overrides]] select="cp311-*" manylinux-x86_64-image = "quay.io/casacore/casacore:master_wheel311" + + +######################### +# scikit-build settings # +######################### + +[tool.scikit-build] +cmake.minimum-version = "3.15" +ninja.minimum-version = "1.5" +install.components = ["data-files", "libraries"] +logging.level = "INFO" + +[tool.scikit-build.cmake.define] +BUILD_WITH_PYTHON = "ON" diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index bd98c17084918c17ed3555720aba85e07961bef7..7da84972ca8f7f96edf05a6f861e511a377f85de 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -36,27 +36,37 @@ target_include_directories(pyeverybeam PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/cpp>") target_link_libraries(pyeverybeam PUBLIC everybeam) set_target_properties(pyeverybeam PROPERTIES OUTPUT_NAME everybeam) +if(SKBUILD) + set_target_properties(pyeverybeam PROPERTIES INSTALL_RPATH + "$ORIGIN/${INSTALL_LIBDIR}") +endif() -# If the PYTHON_LIBRARY_DIR is not specified, install in lib dir -if(NOT DEFINED ${PYTHON_LIBRARY_DIR}) - execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c - "import site; print(site.getsitepackages()[0])" - OUTPUT_VARIABLE PYTHON_DIST_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if(PYTHON_DIST_PATH MATCHES - "\\/(lib.*\\/python${PYTHON_VERSION_MAJOR}\\.${PYTHON_VERSION_MINOR}\\/.*)" - ) - set(PYTHON_LIBRARY_DIR ${CMAKE_MATCH_1}) +# Define where the python module will be installed. When using scikit-build, +# it must be the current directory; otherwise, use site-packages directory. +if(NOT DEFINED PYTHON_LIBRARY_DIR) + if(DEFINED SKBUILD) + set(PYTHON_LIBRARY_DIR .) else() - message( - FATAL_ERROR "Failed to parse PYTHON_DIST_PATH='${PYTHON_DIST_PATH}'") + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c + "import site; print(site.getsitepackages()[0])" + OUTPUT_VARIABLE PYTHON_DIST_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(PYTHON_DIST_PATH + MATCHES + "\\/(lib.*\\/python${PYTHON_VERSION_MAJOR}\\.${PYTHON_VERSION_MINOR}\\/.*)" + ) + set(PYTHON_LIBRARY_DIR ${CMAKE_MATCH_1}) + else() + message( + FATAL_ERROR "Failed to parse PYTHON_DIST_PATH='${PYTHON_DIST_PATH}'") + endif() endif() endif() # Install pyeverybeam in site-packages directory install( TARGETS pyeverybeam - COMPONENT python + COMPONENT libraries LIBRARY DESTINATION ${PYTHON_LIBRARY_DIR}) diff --git a/setup.py b/setup.py deleted file mode 100644 index dcbd48e4520dd715ffb11ae29db2e329ac060038..0000000000000000000000000000000000000000 --- a/setup.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - -# Copyright (c) 2016 The Pybind Development Team, All rights reserved. - -# Setup.py that calls CMake. Largely taken from https://github.com/pybind/cmake_example/ - -import os -import re -import subprocess -import sys - -from setuptools import Extension, setup -from setuptools.command.build_ext import build_ext - - -# Set the location where data files are to be installed -EVERYBEAM_DATADIR = os.path.join("share", "everybeam") - - -# A CMakeExtension needs a sourcedir instead of a file list. -# The name must be the _single_ output extension from the CMake build. -# If you need multiple extensions, see scikit-build. -class CMakeExtension(Extension): - def __init__(self, name, sourcedir=""): - Extension.__init__(self, name, sources=[]) - self.sourcedir = os.path.abspath(sourcedir) - - -class CMakeBuild(build_ext): - def build_extension(self, ext): - extdir = os.path.abspath( - os.path.dirname(self.get_ext_fullpath(ext.name)) - ) - - # required for auto-detection & inclusion of auxiliary "native" libs - if not extdir.endswith(os.path.sep): - extdir += os.path.sep - - debug = ( - int(os.environ.get("DEBUG", 0)) - if self.debug is None - else self.debug - ) - cfg = "Debug" if debug else "Release" - - # CMake lets you override the generator - we need to check this. - # Can be set with Conda-Build, for example. - cmake_generator = os.environ.get("CMAKE_GENERATOR", "") - - # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON - cmake_args = [ - f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}", - f"-DPYTHON_EXECUTABLE={sys.executable}", - f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm - ] - build_args = [] - # Adding CMake arguments set as environment variable - # (needed e.g. to build for ARM OSx on conda-forge) - if "CMAKE_ARGS" in os.environ: - cmake_args += [ - item for item in os.environ["CMAKE_ARGS"].split(" ") if item - ] - - # Adding CMake arguments specific to building EveryBeam - cmake_args += [ - "-DBUILD_WITH_PYTHON=On", - f"-DEVERYBEAM_DATADIR={EVERYBEAM_DATADIR}", - ] - - # Using Ninja-build since it a) is available as a wheel and b) - # multithreads automatically. MSVC would require all variables be - # exported for Ninja to pick it up, which is a little tricky to do. - # Users can override the generator with CMAKE_GENERATOR in CMake - # 3.15+. - if not cmake_generator or cmake_generator == "Ninja": - try: - import ninja # noqa: F401 - - ninja_executable_path = os.path.join(ninja.BIN_DIR, "ninja") - cmake_args += [ - "-GNinja", - f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}", - ] - except ImportError: - pass - - if sys.platform.startswith("darwin"): - # Cross-compile support for macOS - respect ARCHFLAGS if set - archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) - if archs: - cmake_args += [ - "-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs)) - ] - - # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level - # across all generators. - if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: - # self.parallel is a Python 3 only way to set parallel jobs by hand - # using -j in the build_ext call, not supported by pip or PyPA-build. - if hasattr(self, "parallel") and self.parallel: - # CMake 3.12+ only. - build_args += [f"-j{self.parallel}"] - - build_temp = os.path.join(self.build_temp, ext.name) - if not os.path.exists(build_temp): - os.makedirs(build_temp) - - subprocess.check_call(["which", "g++"]) - subprocess.check_call( - ["cmake", ext.sourcedir] + cmake_args, cwd=build_temp - ) - subprocess.check_call( - ["cmake", "--build", "."] + build_args, cwd=build_temp - ) - - -# Install the coefficient files in a location outside the python package -- -# <prefix>/share/everbeam, where <prefix> is the python install prefix -- -# which makes them easier to find for other programs. -data_files = [] -for root, _, files in os.walk("coeffs"): - data_files.append( - ( - EVERYBEAM_DATADIR, - [os.path.join(root, f) for f in files], - ) - ) - -# The information here can also be placed in setup.cfg - better separation of -# logic and declaration, and simpler if you include description/version in a file. -setup( - name="everybeam", - version="0.5.1", - author="André Offringa", - author_email="offringa@astron.nl", - description="EveryBeam", - long_description=open("README.md", "rt").read(), - long_description_content_type="text/markdown", - ext_modules=[CMakeExtension("everybeam")], - cmdclass={"build_ext": CMakeBuild}, - zip_safe=False, - python_requires=">=3.6", - install_requires=["numpy"], - url="https://everybeam.readthedocs.io/", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", - "Programming Language :: C++", - "Programming Language :: Python :: 3", - "Topic :: Scientific/Engineering :: Astronomy", - ], - data_files=data_files, -)