From 8f9716bfb60ff203faec32f6c28d13d57fa62148 Mon Sep 17 00:00:00 2001 From: "M. Amin Safavi" Date: Sat, 14 Sep 2024 12:37:11 +0900 Subject: [PATCH] Reverting all the adventures into working --- .github/workflows/ci.yaml | 5 ++-- CMakeLists.txt | 22 ++++------------ setup.py | 33 ++++++++++++++++++++++-- src/drake_extension.cpp | 51 ++++++++++++++++++++++++++++++++++++++ tests/test_simple_adder.py | 2 +- 5 files changed, 91 insertions(+), 22 deletions(-) create mode 100644 src/drake_extension.cpp diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ba891a1..bf2a158 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,12 +20,13 @@ jobs: python-version: '3.10' - name: Build and Install run: | - python3 -m pip install pybind11 + python3 -m pip install pybind11[global] python3 -m pip install pytest python3 -m pip install --verbose . - name: Test run: | - source .venv/bin/activate + export PATH="/opt/drake/bin${PATH:+:${PATH}}" + export PYTHONPATH="/opt/drake/lib/python$(python3 -c 'import sys; print("{0}.{1}".format(*sys.version_info))')/site-packages${PYTHONPATH:+:${PYTHONPATH}}" export LD_LIBRARY_PATH="/opt/drake/lib:$LD_LIBRARY_PATH" python3 -m pytest diff --git a/CMakeLists.txt b/CMakeLists.txt index 09aba60..b25db1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,17 +6,11 @@ cmake_minimum_required(VERSION 3.16...3.27) # Scikit-build-core sets these values for you, or you can just hard-code the # name and version. -project( - ${SKBUILD_PROJECT_NAME} - VERSION ${SKBUILD_PROJECT_VERSION} - LANGUAGES CXX) +project(drake_extension LANGUAGES CXX) include(CTest) - +option(RUN_X11_TESTS "Run tests that require X11" OFF) find_package(drake CONFIG REQUIRED) - -# Try to import all Python components potentially needed by nanobind -find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module) find_package(pybind11 CONFIG REQUIRED) execute_process(COMMAND ${Python3_EXECUTABLE}-config --exec-prefix @@ -38,12 +32,6 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Add a library using FindPython's tooling (pybind11 also provides a helper like # this) -pybind11_add_module(drake_extension_ext MODULE src/drake_extension_ext.cpp) -target_link_libraries(drake_extension_ext PUBLIC drake::drake) -set_target_properties(drake_extension_ext PROPERTIES CXX_VISIBILITY_PRESET default) - -# This is passing in the version as a define just as an example -target_compile_definitions(drake_extension_ext PRIVATE VERSION_INFO=${PROJECT_VERSION}) - -# Install directive for scikit-build-core -install(TARGETS drake_extension_ext LIBRARY DESTINATION drake_extension) +pybind11_add_module(drake_extension MODULE src/drake_extension.cpp) +target_link_libraries(drake_extension PUBLIC drake::drake) +set_target_properties(drake_extension PROPERTIES CXX_VISIBILITY_PRESET default) diff --git a/setup.py b/setup.py index a4caa98..5a528a0 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,14 @@ from setuptools import Extension, setup from setuptools.command.build_ext import build_ext +# Convert distutils Windows platform specifiers to CMake -A arguments +PLAT_TO_CMAKE = { + "win32": "Win32", + "win-amd64": "x64", + "win-arm32": "ARM", + "win-arm64": "ARM64", +} + # A CMakeExtension needs a sourcedir instead of a file list. # The name must be the _single_ output extension from the CMake build. @@ -68,6 +76,26 @@ def build_extension(self, ext: CMakeExtension) -> None: except ImportError: pass + else: + # Single config generators are handled "normally" + single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) + + # CMake allows an arch-in-generator style for backward compatibility + contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) + + # Specify the arch if using MSVC generator, but only if it doesn't + # contain a backward-compatibility arch spec already in the + # generator name. + if not single_config and not contains_arch: + cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] + + # Multi-config generators have a different way to specify configs + if not single_config: + cmake_args += [ + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}" + ] + build_args += ["--config", cfg] + if sys.platform.startswith("darwin"): # Cross-compile support for macOS - respect ARCHFLAGS if set archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) @@ -102,11 +130,12 @@ def build_extension(self, ext: CMakeExtension) -> None: version="0.0.1", author="M. Amin Safavi", author_email="safavi.m.amin@gmail.com", - description="A test project using pybind11 and Drake", + description="A template project to extend Drake using pybind11 and CMake", long_description="", ext_modules=[CMakeExtension("drake_extension")], cmdclass={"build_ext": CMakeBuild}, zip_safe=False, - extras_require={"test": ["pytest>=6.0"]}, + extras_require={"test": ["pytest>=6.0"], + "pydrake": ["pydrake>=1.20"]}, python_requires=">=3.10", ) diff --git a/src/drake_extension.cpp b/src/drake_extension.cpp new file mode 100644 index 0000000..141aa57 --- /dev/null +++ b/src/drake_extension.cpp @@ -0,0 +1,51 @@ +/** + * @file + * Provides an example of creating a simple Drake C++ system and binding it in + * pybind11, to be used with pydrake. + */ +#include +#include + +namespace py = pybind11; + +using drake::systems::BasicVector; +using drake::systems::Context; +using drake::systems::LeafSystem; +using drake::systems::kVectorValued; + +namespace drake_extension { + +/// Adds a constant to an input. +template +class SimpleAdder : public LeafSystem { + public: + explicit SimpleAdder(T add) + : add_(add) { + this->DeclareInputPort("in", kVectorValued, 1); + this->DeclareVectorOutputPort( + "out", BasicVector(1), &SimpleAdder::CalcOutput); + } + + private: + void CalcOutput(const Context& context, BasicVector* output) const { + auto u = this->get_input_port(0).Eval(context); + auto&& y = output->get_mutable_value(); + y.array() = u.array() + add_; + } + + const T add_{}; +}; + + +PYBIND11_MODULE(drake_extension , m) { + m.doc() = "Example module interfacing with pydrake and Drake C++"; + + py::module::import("pydrake.systems.framework"); + + using T = double; + + py::class_, LeafSystem>(m, "SimpleAdder") + .def(py::init(), py::arg("add")); +} + +} // namespace drake_extension diff --git a/tests/test_simple_adder.py b/tests/test_simple_adder.py index cbaf730..cdd43a8 100644 --- a/tests/test_simple_adder.py +++ b/tests/test_simple_adder.py @@ -1,4 +1,4 @@ -#import numpy as np +import numpy as np from drake_extension import SimpleAdder from pydrake.systems.analysis import Simulator