Skip to content

Commit

Permalink
Build cuspatial with scikit-build (#524)
Browse files Browse the repository at this point in the history
This PR switches cuspatial's Python build system to use scikit-build and CMake.

Authors:
  - Vyas Ramasubramani (https://github.com/vyasr)

Approvers:
  - AJ Schmidt (https://github.com/ajschmidt8)
  - Mark Harris (https://github.com/harrism)

URL: #524
  • Loading branch information
vyasr authored May 20, 2022
1 parent 8738223 commit 47ba833
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 93 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ DartConfiguration.tcl
dist/
cuspatial.egg-info/
python/build
_skbuild
python/*/build
python/cuspatial/*/_lib/**/*.cpp
python/cuspatial/*/_lib/**/*.h
Expand Down
56 changes: 39 additions & 17 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@ ARGS=$*
REPODIR=$(cd $(dirname $0); pwd)

VALIDARGS="clean libcuspatial cuspatial tests -v -g -n -h --allgpuarch --show_depr_warn"
HELP="$0 [clean] [libcuspatial] [cuspatial] [tests] [-v] [-g] [-n] [-h] [-l] [--show_depr_warn]
clean - remove all existing build artifacts and configuration (start
over)
libcuspatial - build the libcuspatial C++ code only
cuspatial - build the cuspatial Python package
tests - build tests
-v - verbose build mode
-g - build for debug
-n - no install step
-h - print this text
--allgpuarch - build for all supported GPU architectures
--show_depr_warn - show cmake deprecation warnings
HELP="$0 [clean] [libcuspatial] [cuspatial] [tests] [-v] [-g] [-n] [-h] [-l] [--show_depr_warn] [--cmake-args=\"<args>\"]
clean - remove all existing build artifacts and configuration (start over)
libcuspatial - build the libcuspatial C++ code only
cuspatial - build the cuspatial Python package
tests - build tests
-v - verbose build mode
-g - build for debug
-n - no install step
-h - print this text
--allgpuarch - build for all supported GPU architectures
--show_depr_warn - show cmake deprecation warnings
--cmake-args=\\\"<args>\\\" - pass arbitrary list of CMake configuration options (escape all quotes in argument)
default action (no args) is to build and install 'libcuspatial' then
'cuspatial' targets
"
LIBCUSPATIAL_BUILD_DIR=${REPODIR}/cpp/build
CUSPATIAL_BUILD_DIR=${REPODIR}/python/cuspatial/build
CUSPATIAL_BUILD_DIR=${REPODIR}/python/cuspatial/_skbuild
BUILD_DIRS="${LIBCUSPATIAL_BUILD_DIR} ${CUSPATIAL_BUILD_DIR}"

# Set defaults for vars modified by flags to this script
Expand All @@ -56,13 +56,36 @@ function hasArg {
(( ${NUMARGS} != 0 )) && (echo " ${ARGS} " | grep -q " $1 ")
}

function cmakeArgs {
# Check for multiple cmake args options
if [[ $(echo $ARGS | { grep -Eo "\-\-cmake\-args" || true; } | wc -l ) -gt 1 ]]; then
echo "Multiple --cmake-args options were provided, please provide only one: ${ARGS}"
exit 1
fi

# Check for cmake args option
if [[ -n $(echo $ARGS | { grep -E "\-\-cmake\-args" || true; } ) ]]; then
# There are possible weird edge cases that may cause this regex filter to output nothing and fail silently
# the true pipe will catch any weird edge cases that may happen and will cause the program to fall back
# on the invalid option error
CMAKE_ARGS=$(echo $ARGS | { grep -Eo "\-\-cmake\-args=\".+\"" || true; })
if [[ -n ${CMAKE_ARGS} ]]; then
# Remove the full CMAKE_ARGS argument from list of args so that it passes validArgs function
ARGS=${ARGS//$CMAKE_ARGS/}
# Filter the full argument down to just the extra string that will be added to cmake call
CMAKE_ARGS=$(echo $CMAKE_ARGS | grep -Eo "\".+\"" | sed -e 's/^"//' -e 's/"$//')
fi
fi
}

if hasArg -h; then
echo "${HELP}"
exit 0
fi

# Check for valid usage
if (( ${NUMARGS} != 0 )); then
cmakeArgs
for a in ${ARGS}; do
if ! (echo " ${VALIDARGS} " | grep -q " ${a} "); then
echo "Invalid option: ${a}"
Expand Down Expand Up @@ -125,6 +148,7 @@ if (( ${NUMARGS} == 0 )) || hasArg libcuspatial; then
-DBUILD_TESTS=${BUILD_TESTS} \
-DDISABLE_DEPRECATION_WARNING=${BUILD_DISABLE_DEPRECATION_WARNING} \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
${CMAKE_ARGS} \
..

cmake --build . -j ${PARALLEL_LEVEL} ${VERBOSE_FLAG}
Expand All @@ -138,10 +162,8 @@ fi
if (( ${NUMARGS} == 0 )) || hasArg cuspatial; then

cd ${REPODIR}/python/cuspatial
python setup.py build_ext -j${PARALLEL_LEVEL:-1} --inplace -- -DCMAKE_PREFIX_PATH=${INSTALL_PREFIX} -DCMAKE_LIBRARY_PATH=${LIBCUSPATIAL_BUILD_DIR} ${CMAKE_ARGS}
if [[ ${INSTALL_TARGET} != "" ]]; then
PARALLEL_LEVEL=${PARALLEL_LEVEL} python setup.py build_ext --inplace
python setup.py install --single-version-externally-managed --record=record.txt
else
PARALLEL_LEVEL=${PARALLEL_LEVEL} python setup.py build_ext --inplace --library-dir=${LIBCUSPATIAL_BUILD_DIR}
python setup.py install --single-version-externally-managed --record=record.txt -- ${CMAKE_ARGS}
fi
fi
2 changes: 1 addition & 1 deletion ci/gpu/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ if [[ -z "$PROJECT_FLASH" || "$PROJECT_FLASH" == "0" ]]; then

gpuci_logger "Build cuSpatial"
cd "$WORKSPACE"
./build.sh clean libcuspatial cuspatial tests
./build.sh clean libcuspatial cuspatial tests --cmake-args=\"-DFIND_CUSPATIAL_CPP=ON\"

###############################################################################
# TEST - Run libcuspatial and cuSpatial Unit Tests
Expand Down
4 changes: 3 additions & 1 deletion ci/release/update-version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ function sed_runner() {
sed -i.bak ''"$1"'' $2 && rm -f ${2}.bak
}

# cpp update
# python/cpp update
sed_runner 's/'"CUSPATIAL VERSION .* LANGUAGES"'/'"CUSPATIAL VERSION ${NEXT_FULL_TAG} LANGUAGES"'/g' cpp/CMakeLists.txt
sed_runner 's/'"cuspatial_version .*)"'/'"cuspatial_version ${NEXT_FULL_TAG})"'/g' python/cuspatial/CMakeLists.txt

# RTD update
sed_runner 's/version = .*/version = '"'${NEXT_SHORT_TAG}'"'/g' docs/source/conf.py
sed_runner 's/release = .*/release = '"'${NEXT_FULL_TAG}'"'/g' docs/source/conf.py

# rapids-cmake version
sed_runner 's/'"branch-.*\/RAPIDS.cmake"'/'"branch-${NEXT_SHORT_TAG}\/RAPIDS.cmake"'/g' fetch_rapids.cmake
sed_runner 's/'"branch-.*\/RAPIDS.cmake"'/'"branch-${NEXT_SHORT_TAG}\/RAPIDS.cmake"'/g' python/cuspatial/CMakeLists.txt

# bump cudf
for FILE in conda/environments/*.yml; do
Expand Down
3 changes: 2 additions & 1 deletion conda/environments/cuspatial_dev_cuda11.0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ dependencies:
- cudatoolkit=11.0
- gdal>=3.0.2
- geopandas>=0.9.0,<0.10.0a0
- cmake>=3.20.1
- cmake>=3.20.1,!=3.23.0
- cython>=0.29,<0.30
- scikit-build>=0.13.1
- gtest=1.10.0
- gmock=1.10.0
3 changes: 2 additions & 1 deletion conda/environments/cuspatial_dev_cuda11.1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ dependencies:
- cudatoolkit=11.1
- gdal>=3.0.2
- geopandas>=0.9.0,<0.10.0a0
- cmake>=3.20.1
- cmake>=3.20.1,!=3.23.0
- cython>=0.29,<0.30
- scikit-build>=0.13.1
- gtest=1.10.0
- gmock=1.10.0
3 changes: 2 additions & 1 deletion conda/environments/cuspatial_dev_cuda11.2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ dependencies:
- cudatoolkit=11.2
- gdal>=3.0.2
- geopandas>=0.9.0,<0.10.0a0
- cmake>=3.20.1
- cmake>=3.20.1,!=3.23.0
- cython>=0.29,<0.30
- scikit-build>=0.13.1
- gtest=1.10.0
- gmock=1.10.0
2 changes: 1 addition & 1 deletion conda/recipes/cuspatial/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# Copyright (c) 2018-2019, NVIDIA CORPORATION.

# This assumes the script is executed from the root of the repo directory
./build.sh cuspatial
./build.sh cuspatial --cmake-args=\"-DFIND_CUSPATIAL_CPP=ON\"
2 changes: 2 additions & 0 deletions conda/recipes/cuspatial/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ requirements:
host:
- python
- cython >=0.29,<0.30
- cmake>=3.20.1,!=3.23.0
- scikit-build>=0.13.1
- setuptools
- cudf {{ minor_version }}.*
- rmm {{ minor_version }}.*
Expand Down
1 change: 1 addition & 0 deletions conda/recipes/libcuspatial/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ outputs:
- cudatoolkit {{ cuda_spec }}
- libcudf {{ minor_version }}.*
- librmm {{ minor_version }}.*
- gdal {{ gdal_version }}
test:
commands:
- test -f $PREFIX/lib/libcuspatial.so
Expand Down
61 changes: 61 additions & 0 deletions python/cuspatial/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# =============================================================================
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions and limitations under
# the License.
# =============================================================================

cmake_minimum_required(VERSION 3.20.1 FATAL_ERROR)

set(cuspatial_version 22.06.00)

file(DOWNLOAD https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-22.06/RAPIDS.cmake
${CMAKE_BINARY_DIR}/RAPIDS.cmake)
include(${CMAKE_BINARY_DIR}/RAPIDS.cmake)

project(
cuspatial-python
VERSION ${cuspatial_version}
LANGUAGES # TODO: Building Python extension modules via the python_extension_module requires the C
# language to be enabled here. The test project that is built in scikit-build to verify
# various linking options for the python library is hardcoded to build with C, so until
# that is fixed we need to keep C.
C CXX)

option(FIND_CUSPATIAL_CPP "Search for existing cuspatial C++ installations before defaulting to local files"
OFF)

# If the user requested it we attempt to find cuspatial.
if(FIND_CUSPATIAL_CPP)
find_package(cuspatial ${cuspatial_version})
else()
set(cuspatial_FOUND OFF)
endif()

if(NOT cuspatial_FOUND)
# TODO: This will not be necessary once we upgrade to CMake 3.22, which will
# pull in the required languages for the C++ project even if this project
# does not require those languges.
include(rapids-cuda)
rapids_cuda_init_architectures(cuspatial)
enable_language(CUDA)
# Since cuspatial only enables CUDA optionally we need to manually include the file that
# rapids_cuda_init_architectures relies on `project` including.
include("${CMAKE_PROJECT_cuspatial_INCLUDE}")

add_subdirectory(../../cpp cuspatial-cpp)

install(TARGETS cuspatial DESTINATION cuspatial/_lib)
endif()

include(rapids-cython)
rapids_cython_init()

add_subdirectory(cuspatial/_lib)
31 changes: 31 additions & 0 deletions python/cuspatial/cuspatial/_lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# =============================================================================
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions and limitations under
# the License.
# =============================================================================

set(cython_sources
hausdorff.pyx
interpolate.pyx
point_in_polygon.pyx
polygon_bounding_boxes.pyx
polyline_bounding_boxes.pyx
quadtree.pyx
shapefile_reader.pyx
spatial.pyx
spatial_join.pyx
spatial_window.pyx
trajectory.pyx
)
set(linked_libraries cuspatial::cuspatial)

rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}"
CXX)
24 changes: 24 additions & 0 deletions python/cuspatial/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

[build-system]

requires = [
"wheel",
"setuptools",
"cython>=0.29,<0.30",
"scikit-build>=0.13.1",
"cmake>=3.20.1,!=3.23.0",
"ninja",
]
74 changes: 4 additions & 70 deletions python/cuspatial/setup.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,9 @@
# Copyright (c) 2018, NVIDIA CORPORATION.
import os
import shutil
import sysconfig
from distutils.sysconfig import get_python_lib

import numpy as np
from Cython.Build import cythonize
from setuptools import find_packages, setup
from setuptools.extension import Extension
# Copyright (c) 2018-2022, NVIDIA CORPORATION.
from setuptools import find_packages
from skbuild import setup

import versioneer

install_requires = ["numba", "cython"]
cython_files = ["cuspatial/_lib/**/*.pyx"]

CUDA_HOME = os.environ.get("CUDA_HOME", False)
if not CUDA_HOME:
path_to_cuda_gdb = shutil.which("cuda-gdb")
if path_to_cuda_gdb is None:
raise OSError(
"Could not locate CUDA. "
"Please set the environment variable "
"CUDA_HOME to the path to the CUDA installation "
"and try again."
)
CUDA_HOME = os.path.dirname(os.path.dirname(path_to_cuda_gdb))

if not os.path.isdir(CUDA_HOME):
raise OSError(f"Invalid CUDA_HOME: directory does not exist: {CUDA_HOME}")

cuda_include_dir = os.path.join(CUDA_HOME, "include")

CUSPATIAL_ROOT = os.environ.get("CUSPATIAL_ROOT", "../../cpp/build/")

try:
nthreads = int(os.environ.get("PARALLEL_LEVEL", "0") or "0")
except Exception:
nthreads = 0

extensions = [
Extension(
"*",
sources=cython_files,
include_dirs=[
"../../cpp/include",
os.path.join(CUSPATIAL_ROOT, "include"),
os.path.join(CUSPATIAL_ROOT, "_deps/libcudacxx-src/include"),
os.path.join(
os.path.dirname(sysconfig.get_path("include")),
"rapids/libcudacxx",
),
os.path.dirname(sysconfig.get_path("include")),
np.get_include(),
cuda_include_dir,
],
library_dirs=[get_python_lib()],
libraries=["cudf", "cuspatial"],
language="c++",
extra_compile_args=["-std=c++17"],
)
]

setup(
name="cuspatial",
version=versioneer.get_version(),
Expand All @@ -80,18 +23,9 @@
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
],
# Include the separately-compiled shared library
setup_requires=["cython"],
ext_modules=cythonize(
extensions,
nthreads=nthreads,
compiler_directives=dict(
profile=False, language_level=3, embedsignature=True
),
),
packages=find_packages(include=["cuspatial", "cuspatial.*"]),
package_data={"cuspatial._lib": ["*.pxd"]},
cmdclass=versioneer.get_cmdclass(),
install_requires=install_requires,
install_requires=["numba"],
zip_safe=False,
)

0 comments on commit 47ba833

Please sign in to comment.