Skip to content

Commit 331f390

Browse files
committed
Export grid type with pybind
Add some python setuptools packaging.
1 parent 80888b3 commit 331f390

11 files changed

+384
-4
lines changed

Diff for: .gitignore

+105
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,108 @@ fabric.properties
7575

7676
# Android studio 3.1+ serialized cache file
7777
.idea/caches/build_file_checksums.ser
78+
79+
# Byte-compiled / optimized / DLL files
80+
__pycache__/
81+
*.py[cod]
82+
*$py.class
83+
84+
# C extensions
85+
*.so
86+
87+
# Distribution / packaging
88+
.Python
89+
build/
90+
develop-eggs/
91+
dist/
92+
downloads/
93+
eggs/
94+
.eggs/
95+
lib/
96+
lib64/
97+
parts/
98+
sdist/
99+
var/
100+
wheels/
101+
*.egg-info/
102+
.installed.cfg
103+
*.egg
104+
MANIFEST
105+
106+
# PyInstaller
107+
# Usually these files are written by a python script from a template
108+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
109+
*.manifest
110+
*.spec
111+
112+
# Installer logs
113+
pip-log.txt
114+
pip-delete-this-directory.txt
115+
116+
# Unit test / coverage reports
117+
htmlcov/
118+
.tox/
119+
.coverage
120+
.coverage.*
121+
.cache
122+
nosetests.xml
123+
coverage.xml
124+
*.cover
125+
.hypothesis/
126+
.pytest_cache/
127+
128+
# Translations
129+
*.mo
130+
*.pot
131+
132+
# Django stuff:
133+
*.log
134+
local_settings.py
135+
db.sqlite3
136+
137+
# Flask stuff:
138+
instance/
139+
.webassets-cache
140+
141+
# Scrapy stuff:
142+
.scrapy
143+
144+
# Sphinx documentation
145+
docs/_build/
146+
147+
# PyBuilder
148+
target/
149+
150+
# Jupyter Notebook
151+
.ipynb_checkpoints
152+
153+
# pyenv
154+
.python-version
155+
156+
# celery beat schedule file
157+
celerybeat-schedule
158+
159+
# SageMath parsed files
160+
*.sage.py
161+
162+
# Environments
163+
.env
164+
.venv
165+
env/
166+
venv/
167+
ENV/
168+
env.bak/
169+
venv.bak/
170+
171+
# Spyder project settings
172+
.spyderproject
173+
.spyproject
174+
175+
# Rope project settings
176+
.ropeproject
177+
178+
# mkdocs documentation
179+
/site
180+
181+
# mypy
182+
.mypy_cache/

Diff for: CMakeLists.txt

+18-4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ FetchContent_Declare(
7878
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
7979
FetchContent_MakeAvailable(googletest)
8080

81+
# ------------------- FETCH PYBIND11 ------------------
82+
FetchContent_Declare(
83+
pybind11
84+
GIT_REPOSITORY https://github.com/pybind/pybind11
85+
GIT_TAG v2.9.2
86+
)
87+
FetchContent_MakeAvailable(pybind11)
88+
8189
# ------------- VOXEL TRAVERSAL LIBRARY -----------------
8290
add_library(voxel_traversal SHARED src/voxel_traversal.cpp)
8391

@@ -115,12 +123,18 @@ install(TARGETS voxel_traversal EXPORT voxelTraversalTargets
115123
# Other CMake targets can refer to it using VoxelTraversal::<lib>.
116124
export(TARGETS voxel_traversal NAMESPACE VoxelTraversal:: FILE VoxelTraversalTargets.cmake)
117125

126+
# ---------------- python bindings --------------------
127+
# TODO(risteon): make all python bindings optional
128+
pybind11_add_module(pytraversal SHARED src/python_bindings.cpp)
129+
target_link_libraries(pytraversal PRIVATE voxel_traversal Eigen3::Eigen)
130+
131+
118132
# ------------------- TESTS -------------------
119133
enable_testing()
120134
##################################
121135
add_executable(
122136
test_voxel_traversal
123-
test/test_voxel_traversal.cpp
137+
tests/test_voxel_traversal.cpp
124138
)
125139
target_include_directories(test_voxel_traversal PUBLIC
126140
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
@@ -135,7 +149,7 @@ target_link_libraries(
135149
##################################
136150
add_executable(
137151
test_voxel_counter
138-
test/test_voxel_counter.cpp
152+
tests/test_voxel_counter.cpp
139153
)
140154
target_include_directories(test_voxel_counter PUBLIC
141155
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/src
@@ -150,7 +164,7 @@ target_link_libraries(
150164
##################################
151165
add_executable(
152166
test_voxel_intersect
153-
test/test_voxel_intersect.cpp
167+
tests/test_voxel_intersect.cpp
154168
)
155169
target_include_directories(test_voxel_intersect PUBLIC
156170
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/src
@@ -165,7 +179,7 @@ target_link_libraries(
165179
##################################
166180
add_executable(
167181
test_on_data
168-
test/test_on_data.cpp
182+
tests/test_on_data.cpp
169183
)
170184
target_include_directories(test_on_data PUBLIC
171185
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/src

Diff for: README.md

+12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ It is based on the code prototype of Chris Gyurgyik
1313

1414
The contributions of this repository are:
1515
* **Tests!**
16+
* Python bindings (in progress...)
1617
* Installation and cmake packaging
1718
* Use Eigen for readability, vectorization, and grid counting.
1819
* Execution and timing on real LiDAR data from the [nuScenes dataset](https://www.nuscenes.org/). The demonstration data files are bundled with git lfs.
@@ -21,11 +22,22 @@ The contributions of this repository are:
2122
* Eigen3
2223
* C++17 compiler
2324

25+
## Python bindings
26+
27+
```bash
28+
# setup python environment, make cmake >= 3.21 available, e.g. with conda install cmake=3.22
29+
$ python setup.py install
30+
# or
31+
$ python setup.py develop
32+
$ pytest tests
33+
```
34+
2435
## Run the Tests and Install
2536
```bash
2637
$ git clone https://github.com/risteon/voxel-traversal.git
2738
$ mkdir build && cd build
2839
# set CMAKE_INSTALL_PREFIX to your liking
40+
# specify python version with -DPYTHON_EXECUTABLE=<path/to/python> or -DPYBIND11_PYTHON_VERSION=3.XX
2941
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../install ..
3042
# build and install
3143
$ cmake --build . --target install -- -j 4

Diff for: setup.py

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Copyright (c) 2016 The Pybind Development Team, All rights reserved.
2+
#
3+
# Redistribution and use in source and binary forms, with or without
4+
# modification, are permitted provided that the following conditions are met:
5+
#
6+
# 1. Redistributions of source code must retain the above copyright notice, this
7+
# list of conditions and the following disclaimer.
8+
#
9+
# 2. Redistributions in binary form must reproduce the above copyright notice,
10+
# this list of conditions and the following disclaimer in the documentation
11+
# and/or other materials provided with the distribution.
12+
#
13+
# 3. Neither the name of the copyright holder nor the names of its contributors
14+
# may be used to endorse or promote products derived from this software
15+
# without specific prior written permission.
16+
#
17+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
#
28+
# You are under no obligation whatsoever to provide any bug fixes, patches, or
29+
# upgrades to the features, functionality or performance of the source code
30+
# ("Enhancements") to anyone; however, if you choose to make your Enhancements
31+
# available either publicly, or directly to the author of this software, without
32+
# imposing a separate written license agreement for such Enhancements, then you
33+
# hereby grant the following license: a non-exclusive, royalty-free perpetual
34+
# license to install, use, modify, prepare derivative works, incorporate into
35+
# other computer software, distribute, and sublicense such enhancements or
36+
# derivative works thereof, in binary and source code form.
37+
38+
import os
39+
import re
40+
import subprocess
41+
import sys
42+
43+
from setuptools import Extension, setup
44+
from setuptools.command.build_ext import build_ext
45+
46+
# Convert distutils Windows platform specifiers to CMake -A arguments
47+
PLAT_TO_CMAKE = {
48+
"win32": "Win32",
49+
"win-amd64": "x64",
50+
"win-arm32": "ARM",
51+
"win-arm64": "ARM64",
52+
}
53+
54+
55+
# A CMakeExtension needs a sourcedir instead of a file list.
56+
# The name must be the _single_ output extension from the CMake build.
57+
# If you need multiple extensions, see scikit-build.
58+
class CMakeExtension(Extension):
59+
def __init__(self, name, sourcedir=""):
60+
Extension.__init__(self, name, sources=[])
61+
self.sourcedir = os.path.abspath(sourcedir)
62+
63+
64+
class CMakeBuild(build_ext):
65+
def build_extension(self, ext):
66+
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
67+
68+
# required for auto-detection & inclusion of auxiliary "native" libs
69+
if not extdir.endswith(os.path.sep):
70+
extdir += os.path.sep
71+
72+
debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug
73+
cfg = "Debug" if debug else "Release"
74+
75+
# CMake lets you override the generator - we need to check this.
76+
# Can be set with Conda-Build, for example.
77+
cmake_generator = os.environ.get("CMAKE_GENERATOR", "")
78+
79+
# Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON
80+
# EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code
81+
# from Python.
82+
cmake_args = [
83+
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
84+
f"-DPYTHON_EXECUTABLE={sys.executable}",
85+
f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm
86+
]
87+
build_args = []
88+
# Adding CMake arguments set as environment variable
89+
# (needed e.g. to build for ARM OSx on conda-forge)
90+
if "CMAKE_ARGS" in os.environ:
91+
cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item]
92+
93+
# In this example, we pass in the version to C++. You might not need to.
94+
cmake_args += [f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}"]
95+
96+
if self.compiler.compiler_type != "msvc":
97+
# Using Ninja-build since it a) is available as a wheel and b)
98+
# multithreads automatically. MSVC would require all variables be
99+
# exported for Ninja to pick it up, which is a little tricky to do.
100+
# Users can override the generator with CMAKE_GENERATOR in CMake
101+
# 3.15+.
102+
if not cmake_generator or cmake_generator == "Ninja":
103+
try:
104+
import ninja # noqa: F401
105+
106+
ninja_executable_path = os.path.join(ninja.BIN_DIR, "ninja")
107+
cmake_args += [
108+
"-GNinja",
109+
f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}",
110+
]
111+
except ImportError:
112+
pass
113+
114+
else:
115+
116+
# Single config generators are handled "normally"
117+
single_config = any(x in cmake_generator for x in {"NMake", "Ninja"})
118+
119+
# CMake allows an arch-in-generator style for backward compatibility
120+
contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"})
121+
122+
# Specify the arch if using MSVC generator, but only if it doesn't
123+
# contain a backward-compatibility arch spec already in the
124+
# generator name.
125+
if not single_config and not contains_arch:
126+
cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]]
127+
128+
# Multi-config generators have a different way to specify configs
129+
if not single_config:
130+
cmake_args += [
131+
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}"
132+
]
133+
build_args += ["--config", cfg]
134+
135+
if sys.platform.startswith("darwin"):
136+
# Cross-compile support for macOS - respect ARCHFLAGS if set
137+
archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", ""))
138+
if archs:
139+
cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))]
140+
141+
# Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level
142+
# across all generators.
143+
if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ:
144+
# self.parallel is a Python 3 only way to set parallel jobs by hand
145+
# using -j in the build_ext call, not supported by pip or PyPA-build.
146+
if hasattr(self, "parallel") and self.parallel:
147+
# CMake 3.12+ only.
148+
build_args += [f"-j{self.parallel}"]
149+
150+
build_temp = os.path.join(self.build_temp, ext.name)
151+
if not os.path.exists(build_temp):
152+
os.makedirs(build_temp)
153+
154+
subprocess.check_call(["cmake", ext.sourcedir] + cmake_args, cwd=build_temp)
155+
subprocess.check_call(["cmake", "--build", "."] + build_args, cwd=build_temp)
156+
157+
158+
# The information here can also be placed in setup.cfg - better separation of
159+
# logic and declaration, and simpler if you include description/version in a file.
160+
setup(
161+
name="pytraversal",
162+
version="1.1",
163+
author="Christoph Rist",
164+
author_email="[email protected]",
165+
description="python bindings for voxel traversal",
166+
long_description="",
167+
ext_modules=[CMakeExtension("pytraversal")],
168+
cmdclass={"build_ext": CMakeBuild},
169+
zip_safe=False,
170+
extras_require={"test": ["pytest>=6.0"]},
171+
python_requires=">=3.6",
172+
)

0 commit comments

Comments
 (0)