Merging 'master' into 'wrap'
commit
4945642481
|
@ -1,2 +1,5 @@
|
|||
__pycache__/
|
||||
.vscode/
|
||||
*build*
|
||||
*dist*
|
||||
*.egg-info
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
cmake_minimum_required(VERSION 3.9)
|
||||
|
||||
# Set the project name and version
|
||||
project(GTwrap VERSION 1.0)
|
||||
|
||||
# ##############################################################################
|
||||
# General configuration
|
||||
|
||||
set(WRAP_PYTHON_VERSION
|
||||
"Default"
|
||||
CACHE STRING "The Python version to use for wrapping")
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GtwrapUtils.cmake)
|
||||
gtwrap_get_python_version(${WRAP_PYTHON_VERSION})
|
||||
|
||||
# ##############################################################################
|
||||
# Install the CMake file to be used by other projects
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/CMake")
|
||||
else()
|
||||
set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/cmake")
|
||||
endif()
|
||||
|
||||
# Install scripts to the standard CMake script directory.
|
||||
install(FILES cmake/gtwrapConfig.cmake cmake/PybindWrap.cmake
|
||||
cmake/GtwrapUtils.cmake
|
||||
DESTINATION "${SCRIPT_INSTALL_DIR}/gtwrap")
|
||||
|
||||
# Install wrapping scripts as binaries to `CMAKE_INSTALL_PREFIX/bin` so they can
|
||||
# be invoked for wrapping.
|
||||
install(PROGRAMS scripts/pybind_wrap.py scripts/matlab_wrap.py TYPE BIN)
|
||||
|
||||
# Install pybind11 directory to `CMAKE_INSTALL_PREFIX/lib/pybind11` This will
|
||||
# allow the gtwrapConfig.cmake file to load it later.
|
||||
install(DIRECTORY pybind11 TYPE LIB)
|
||||
|
||||
# ##############################################################################
|
||||
# Install the Python package
|
||||
find_package(
|
||||
Python ${WRAP_PYTHON_VERSION}
|
||||
COMPONENTS Interpreter
|
||||
REQUIRED)
|
||||
|
||||
# Detect virtualenv and set Pip args accordingly
|
||||
# https://www.scivision.dev/cmake-install-python-package/
|
||||
if(DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX})
|
||||
set(_pip_args)
|
||||
else()
|
||||
set(_pip_args "--user")
|
||||
endif()
|
||||
#TODO add correct flags for virtualenv
|
||||
|
||||
# Finally install the gtwrap python package.
|
||||
execute_process(COMMAND ${Python_EXECUTABLE} -m pip install . ${_pip_args}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) 2010, Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332-0415
|
||||
All Rights Reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -8,9 +8,40 @@ It was designed to be more general than just wrapping GTSAM. For notes on creati
|
|||
|
||||
1. This library uses `pybind11`, which is included as a subdirectory in GTSAM.
|
||||
2. The `interface_parser.py` in this library uses `pyparsing` to parse the interface file `gtsam.h`. Please install it first in your current Python environment before attempting the build.
|
||||
```
|
||||
python3 -m pip install pyparsing
|
||||
```
|
||||
|
||||
```
|
||||
python3 -m pip install pyparsing
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
Clone this repository to your local machine and perform the standard CMake install:
|
||||
|
||||
```sh
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make install # use sudo if needed
|
||||
```
|
||||
|
||||
Using `wrap` in your project is straightforward from here. In you `CMakeLists.txt` file, you just need to add the following:
|
||||
|
||||
```cmake
|
||||
include(PybindWrap)
|
||||
|
||||
pybind_wrap(${PROJECT_NAME}_py # target
|
||||
${PROJECT_SOURCE_DIR}/cpp/${PROJECT_NAME}.h # interface header file
|
||||
"${PROJECT_NAME}.cpp" # the generated cpp
|
||||
"${PROJECT_NAME}" # module_name
|
||||
"gtsam" # top namespace in the cpp file
|
||||
"${ignore}" # ignore classes
|
||||
${PROJECT_BINARY_DIR}/${PROJECT_NAME}.tpl
|
||||
${PROJECT_NAME} # libs
|
||||
"${PROJECT_NAME}" # dependencies
|
||||
ON # use boost
|
||||
)
|
||||
```
|
||||
|
||||
For more information, please follow our [tutorial](https://github.com/borglab/gtsam-project-python).
|
||||
|
||||
## GTSAM Python wrapper
|
||||
|
||||
|
@ -45,32 +76,3 @@ It was designed to be more general than just wrapping GTSAM. For notes on creati
|
|||
python setup.py install
|
||||
```
|
||||
- NOTE: It's a good idea to create a virtual environment otherwise it will be installed in your system Python's site-packages.
|
||||
|
||||
|
||||
## Old GTSAM Wrapper
|
||||
|
||||
*Outdated note from the original wrap.*
|
||||
|
||||
TODO: Update this.
|
||||
|
||||
It was designed to be more general than just wrapping GTSAM, but a small amount of GTSAM specific code exists in `matlab.h`, the include file that is included by the `mex` files. The GTSAM-specific functionality consists primarily of handling of Eigen Matrix and Vector classes.
|
||||
|
||||
For notes on creating a wrap interface, see `gtsam.h` for what features can be wrapped into a toolbox, as well as the current state of the toolbox for GTSAM. For more technical details on the interface, please read comments in `matlab.h`
|
||||
|
||||
Some good things to know:
|
||||
|
||||
OBJECT CREATION
|
||||
|
||||
- Classes are created by special constructors, e.g., `new_GaussianFactorGraph_.cpp`.
|
||||
These constructors are called from the MATLAB class `@GaussianFactorGraph`.
|
||||
`new_GaussianFactorGraph_` calls wrap_constructed in `matlab.h`, see documentation there
|
||||
|
||||
METHOD (AND CONSTRUCTOR) ARGUMENTS
|
||||
|
||||
- Simple argument types of methods, such as "double", will be converted in the
|
||||
`mex` wrappers by calling unwrap<double>, defined in matlab.h
|
||||
- Vector and Matrix arguments are normally passed by reference in GTSAM, but
|
||||
in `gtsam.h` you need to pretend they are passed by value, to trigger the
|
||||
generation of the correct conversion routines `unwrap<Vector>` and `unwrap<Matrix>`
|
||||
- passing classes as arguments works, provided they are passed by reference.
|
||||
This triggers a call to unwrap_shared_ptr
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# Utilities to help with wrapping.
|
||||
|
||||
macro(get_python_version)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
|
||||
# Use older version of cmake's find_python
|
||||
find_package(PythonInterp)
|
||||
|
||||
if(NOT ${PYTHONINTERP_FOUND})
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Cannot find Python interpreter. Please install Python >= 3.6.")
|
||||
endif()
|
||||
|
||||
find_package(PythonLibs ${PYTHON_VERSION_STRING})
|
||||
|
||||
set(Python_VERSION_MAJOR
|
||||
${PYTHON_VERSION_MAJOR}
|
||||
PARENT_SCOPE)
|
||||
set(Python_VERSION_MINOR
|
||||
${PYTHON_VERSION_MINOR}
|
||||
PARENT_SCOPE)
|
||||
set(Python_VERSION_PATCH
|
||||
${PYTHON_VERSION_PATCH}
|
||||
PARENT_SCOPE)
|
||||
set(Python_EXECUTABLE
|
||||
${PYTHON_EXECUTABLE}
|
||||
PARENT_SCOPE)
|
||||
|
||||
else()
|
||||
# Get info about the Python interpreter
|
||||
# https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
|
||||
find_package(Python COMPONENTS Interpreter Development)
|
||||
|
||||
if(NOT ${Python_FOUND})
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Cannot find Python interpreter. Please install Python>=3.6.")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Set the Python version for the wrapper and set the paths to the executable and
|
||||
# include/library directories. WRAP_PYTHON_VERSION can be "Default" or a
|
||||
# specific major.minor version.
|
||||
macro(gtwrap_get_python_version WRAP_PYTHON_VERSION)
|
||||
# Unset these cached variables to avoid surprises when the python in the
|
||||
# current environment are different from the cached!
|
||||
unset(Python_EXECUTABLE CACHE)
|
||||
unset(Python_INCLUDE_DIRS CACHE)
|
||||
unset(Python_VERSION_MAJOR CACHE)
|
||||
unset(Python_VERSION_MINOR CACHE)
|
||||
unset(Python_VERSION_PATCH CACHE)
|
||||
|
||||
# Allow override
|
||||
if(${WRAP_PYTHON_VERSION} STREQUAL "Default")
|
||||
# Check for Python3 or Python2 in order
|
||||
get_python_version()
|
||||
|
||||
# Set the wrapper python version
|
||||
set(WRAP_PYTHON_VERSION
|
||||
"${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}.${Python_VERSION_PATCH}"
|
||||
CACHE STRING "The version of Python to build the wrappers against."
|
||||
FORCE)
|
||||
|
||||
else()
|
||||
# Find the Python that best matches the python version specified.
|
||||
find_package(
|
||||
Python ${WRAP_PYTHON_VERSION}
|
||||
COMPONENTS Interpreter Development
|
||||
EXACT REQUIRED)
|
||||
endif()
|
||||
|
||||
endmacro()
|
|
@ -1,32 +1,5 @@
|
|||
# Unset these cached variables to avoid surprises when the python in the current
|
||||
# environment are different from the cached!
|
||||
unset(PYTHON_EXECUTABLE CACHE)
|
||||
unset(PYTHON_INCLUDE_DIR CACHE)
|
||||
unset(PYTHON_MAJOR_VERSION CACHE)
|
||||
|
||||
# Allow override from command line
|
||||
if(NOT DEFINED WRAP_USE_CUSTOM_PYTHON_LIBRARY)
|
||||
if(WRAP_PYTHON_VERSION STREQUAL "Default")
|
||||
find_package(PythonInterp REQUIRED)
|
||||
find_package(PythonLibs REQUIRED)
|
||||
else()
|
||||
find_package(PythonInterp
|
||||
${WRAP_PYTHON_VERSION}
|
||||
EXACT
|
||||
REQUIRED)
|
||||
find_package(PythonLibs
|
||||
${WRAP_PYTHON_VERSION}
|
||||
EXACT
|
||||
REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(DIR_OF_WRAP_PYBIND_CMAKE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
set(PYBIND11_PYTHON_VERSION ${WRAP_PYTHON_VERSION})
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../pybind11 pybind11)
|
||||
|
||||
# User-friendly Pybind11 wrapping and installing function.
|
||||
# Builds a Pybind11 module from the provided interface_header.
|
||||
# For example, for the interface header gtsam.h, this will
|
||||
|
@ -65,7 +38,7 @@ function(pybind_wrap
|
|||
|
||||
add_custom_command(OUTPUT ${generated_cpp}
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
${CMAKE_SOURCE_DIR}/wrap/pybind_wrapper.py
|
||||
${PYBIND_WRAP_SCRIPT}
|
||||
--src
|
||||
${interface_header}
|
||||
--out
|
||||
|
@ -89,9 +62,9 @@ function(pybind_wrap
|
|||
# ~~~
|
||||
add_custom_command(OUTPUT ${generated_cpp}
|
||||
DEPENDS ${interface_header}
|
||||
${CMAKE_SOURCE_DIR}/wrap/interface_parser.py
|
||||
${CMAKE_SOURCE_DIR}/wrap/pybind_wrapper.py
|
||||
${CMAKE_SOURCE_DIR}/wrap/template_instantiator.py
|
||||
# @GTWRAP_SOURCE_DIR@/gtwrap/interface_parser.py
|
||||
# @GTWRAP_SOURCE_DIR@/gtwrap/pybind_wrapper.py
|
||||
# @GTWRAP_SOURCE_DIR@/gtwrap/template_instantiator.py
|
||||
APPEND)
|
||||
|
||||
pybind11_add_module(${target} ${generated_cpp})
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# This config file modifies CMAKE_MODULE_PATH so that the wrap cmake files may
|
||||
# be included This file also allows the use of `find_package(gtwrap)` in CMake.
|
||||
|
||||
set(GTWRAP_DIR "${CMAKE_CURRENT_LIST_DIR}")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/CMake")
|
||||
else()
|
||||
set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/cmake")
|
||||
endif()
|
||||
|
||||
# Standard includes
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
# Load all the CMake scripts from the standard location
|
||||
include(${SCRIPT_INSTALL_DIR}/gtwrap/PybindWrap.cmake)
|
||||
include(${SCRIPT_INSTALL_DIR}/gtwrap/GtwrapUtils.cmake)
|
||||
|
||||
# Set the variables for the wrapping scripts to be used in the build.
|
||||
set(PYBIND_WRAP_SCRIPT "${CMAKE_INSTALL_FULL_BINDIR}/pybind_wrap.py")
|
||||
set(MATLAB_WRAP_SCRIPT "${CMAKE_INSTALL_FULL_BINDIR}/matlab_wrap.py")
|
||||
|
||||
# Load the pybind11 code from the library installation path
|
||||
add_subdirectory(${CMAKE_INSTALL_FULL_LIBDIR}/pybind11 pybind11)
|
|
@ -2,8 +2,8 @@ import os
|
|||
import argparse
|
||||
import textwrap
|
||||
|
||||
import interface_parser as parser
|
||||
import template_instantiator as instantiator
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
|
||||
from functools import reduce
|
||||
from functools import partial
|
||||
|
@ -1666,7 +1666,7 @@ class MatlabWrapper(object):
|
|||
return self.content
|
||||
|
||||
|
||||
def _generate_content(cc_content, path, verbose=False):
|
||||
def generate_content(cc_content, path, verbose=False):
|
||||
"""Generate files and folders from matlab wrapper content.
|
||||
|
||||
Keyword arguments:
|
||||
|
@ -1698,7 +1698,7 @@ def _generate_content(cc_content, path, verbose=False):
|
|||
for sub_content in c:
|
||||
import sys
|
||||
_debug("sub object: {}".format(sub_content[1][0][0]))
|
||||
_generate_content(sub_content[1], path_to_folder)
|
||||
generate_content(sub_content[1], path_to_folder)
|
||||
elif type(c[1]) == list:
|
||||
path_to_folder = path + '/' + c[0]
|
||||
|
||||
|
@ -1726,53 +1726,3 @@ def _generate_content(cc_content, path, verbose=False):
|
|||
|
||||
with open(path_to_file, 'w') as f:
|
||||
f.write(c[1])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
arg_parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
arg_parser.add_argument("--src", type=str, required=True, help="Input interface .h file.")
|
||||
arg_parser.add_argument("--module_name", type=str, required=True, help="Name of the C++ class being wrapped.")
|
||||
arg_parser.add_argument("--out", type=str, required=True, help="Name of the output folder.")
|
||||
arg_parser.add_argument("--top_module_namespaces",
|
||||
type=str,
|
||||
default="",
|
||||
help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. "
|
||||
"Only the content within this namespace and its sub-namespaces "
|
||||
"will be wrapped. The content of this namespace will be available at "
|
||||
"the top module level, and its sub-namespaces' in the submodules.\n"
|
||||
"For example, `import <module_name>` gives you access to a Python "
|
||||
"`<module_name>.Class` of the corresponding C++ `ns1::ns2::ns3::Class`"
|
||||
", and `from <module_name> import ns4` gives you access to a Python "
|
||||
"`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ")
|
||||
arg_parser.add_argument("--ignore",
|
||||
nargs='*',
|
||||
type=str,
|
||||
help="A space-separated list of classes to ignore. "
|
||||
"Class names must include their full namespaces.")
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
top_module_namespaces = args.top_module_namespaces.split("::")
|
||||
if top_module_namespaces[0]:
|
||||
top_module_namespaces = [''] + top_module_namespaces
|
||||
|
||||
with open(args.src, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
if not os.path.exists(args.src):
|
||||
os.mkdir(args.src)
|
||||
|
||||
module = parser.Module.parseString(content)
|
||||
|
||||
instantiator.instantiate_namespace_inplace(module)
|
||||
|
||||
import sys
|
||||
|
||||
print("Ignoring classes: {}".format(args.ignore), file=sys.stderr)
|
||||
wrapper = MatlabWrapper(module=module,
|
||||
module_name=args.module_name,
|
||||
top_module_namespace=top_module_namespaces,
|
||||
ignore_classes=args.ignore)
|
||||
|
||||
cc_content = wrapper.wrap()
|
||||
|
||||
_generate_content(cc_content, args.out)
|
|
@ -9,12 +9,11 @@ See LICENSE for the license information
|
|||
Code generator for wrapping a C++ module with Pybind11
|
||||
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar and Frank Dellaert
|
||||
"""
|
||||
import argparse
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
import interface_parser as parser
|
||||
import template_instantiator as instantiator
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
|
||||
|
||||
class PybindWrapper(object):
|
||||
|
@ -319,76 +318,3 @@ class PybindWrapper(object):
|
|||
wrapped_namespace=wrapped_namespace,
|
||||
boost_class_export=boost_class_export,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
arg_parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
arg_parser.add_argument("--src", type=str, required=True, help="Input interface .h file")
|
||||
arg_parser.add_argument(
|
||||
"--module_name",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Name of the Python module to be generated and "
|
||||
"used in the Python `import` statement.",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--out",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Name of the output pybind .cc file",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--use-boost",
|
||||
action="store_true",
|
||||
help="using boost's shared_ptr instead of std's",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--top_module_namespaces",
|
||||
type=str,
|
||||
default="",
|
||||
help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. "
|
||||
"Only the content within this namespace and its sub-namespaces "
|
||||
"will be wrapped. The content of this namespace will be available at "
|
||||
"the top module level, and its sub-namespaces' in the submodules.\n"
|
||||
"For example, `import <module_name>` gives you access to a Python "
|
||||
"`<module_name>.Class` of the corresponding C++ `ns1::ns2::ns3::Class`"
|
||||
"and `from <module_name> import ns4` gives you access to a Python "
|
||||
"`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--ignore",
|
||||
nargs='*',
|
||||
type=str,
|
||||
help="A space-separated list of classes to ignore. "
|
||||
"Class names must include their full namespaces.",
|
||||
)
|
||||
arg_parser.add_argument("--template", type=str, help="The module template file")
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
top_module_namespaces = args.top_module_namespaces.split("::")
|
||||
if top_module_namespaces[0]:
|
||||
top_module_namespaces = [''] + top_module_namespaces
|
||||
|
||||
with open(args.src, "r") as f:
|
||||
content = f.read()
|
||||
module = parser.Module.parseString(content)
|
||||
instantiator.instantiate_namespace_inplace(module)
|
||||
|
||||
with open(args.template, "r") as f:
|
||||
template_content = f.read()
|
||||
wrapper = PybindWrapper(
|
||||
module=module,
|
||||
module_name=args.module_name,
|
||||
use_boost=args.use_boost,
|
||||
top_module_namespaces=top_module_namespaces,
|
||||
ignore_classes=args.ignore,
|
||||
module_template=template_content,
|
||||
)
|
||||
|
||||
cc_content = wrapper.wrap()
|
||||
with open(args.out, "w") as f:
|
||||
f.write(cc_content)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,4 +1,4 @@
|
|||
import interface_parser as parser
|
||||
import gtwrap.interface_parser as parser
|
||||
|
||||
|
||||
def instantiate_type(ctype, template_typenames, instantiations, cpp_typename, instantiated_class=None):
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Helper script to wrap C++ to Matlab.
|
||||
This script is installed via CMake to the user's binary directory
|
||||
and invoked during the wrapping by CMake.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
from gtwrap.matlab_wrapper import MatlabWrapper, generate_content
|
||||
|
||||
if __name__ == "__main__":
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
arg_parser.add_argument("--src", type=str, required=True,
|
||||
help="Input interface .h file.")
|
||||
arg_parser.add_argument("--module_name", type=str, required=True,
|
||||
help="Name of the C++ class being wrapped.")
|
||||
arg_parser.add_argument("--out", type=str, required=True,
|
||||
help="Name of the output folder.")
|
||||
arg_parser.add_argument(
|
||||
"--top_module_namespaces",
|
||||
type=str,
|
||||
default="",
|
||||
help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. "
|
||||
"Only the content within this namespace and its sub-namespaces "
|
||||
"will be wrapped. The content of this namespace will be available at "
|
||||
"the top module level, and its sub-namespaces' in the submodules.\n"
|
||||
"For example, `import <module_name>` gives you access to a Python "
|
||||
"`<module_name>.Class` of the corresponding C++ `ns1::ns2::ns3::Class`"
|
||||
", and `from <module_name> import ns4` gives you access to a Python "
|
||||
"`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ")
|
||||
arg_parser.add_argument("--ignore",
|
||||
nargs='*',
|
||||
type=str,
|
||||
help="A space-separated list of classes to ignore. "
|
||||
"Class names must include their full namespaces.")
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
top_module_namespaces = args.top_module_namespaces.split("::")
|
||||
if top_module_namespaces[0]:
|
||||
top_module_namespaces = [''] + top_module_namespaces
|
||||
|
||||
with open(args.src, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
if not os.path.exists(args.src):
|
||||
os.mkdir(args.src)
|
||||
|
||||
module = parser.Module.parseString(content)
|
||||
|
||||
instantiator.instantiate_namespace_inplace(module)
|
||||
|
||||
import sys
|
||||
|
||||
print("Ignoring classes: {}".format(args.ignore), file=sys.stderr)
|
||||
wrapper = MatlabWrapper(module=module,
|
||||
module_name=args.module_name,
|
||||
top_module_namespace=top_module_namespaces,
|
||||
ignore_classes=args.ignore)
|
||||
|
||||
cc_content = wrapper.wrap()
|
||||
|
||||
generate_content(cc_content, args.out)
|
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Helper script to wrap C++ to Python with Pybind.
|
||||
This script is installed via CMake to the user's binary directory
|
||||
and invoked during the wrapping by CMake.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
from gtwrap.pybind_wrapper import PybindWrapper
|
||||
|
||||
|
||||
def main():
|
||||
"""Main runner."""
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
arg_parser.add_argument(
|
||||
"--src",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Input interface .i/.h file")
|
||||
arg_parser.add_argument(
|
||||
"--module_name",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Name of the Python module to be generated and "
|
||||
"used in the Python `import` statement.",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--out",
|
||||
type=str,
|
||||
required=True,
|
||||
help="Name of the output pybind .cc file",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--use-boost",
|
||||
action="store_true",
|
||||
help="using boost's shared_ptr instead of std's",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--top_module_namespaces",
|
||||
type=str,
|
||||
default="",
|
||||
help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. "
|
||||
"Only the content within this namespace and its sub-namespaces "
|
||||
"will be wrapped. The content of this namespace will be available at "
|
||||
"the top module level, and its sub-namespaces' in the submodules.\n"
|
||||
"For example, `import <module_name>` gives you access to a Python "
|
||||
"`<module_name>.Class` of the corresponding C++ `ns1::ns2::ns3::Class`"
|
||||
"and `from <module_name> import ns4` gives you access to a Python "
|
||||
"`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--ignore",
|
||||
nargs='*',
|
||||
type=str,
|
||||
help="A space-separated list of classes to ignore. "
|
||||
"Class names must include their full namespaces.",
|
||||
)
|
||||
arg_parser.add_argument("--template", type=str,
|
||||
help="The module template file")
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
top_module_namespaces = args.top_module_namespaces.split("::")
|
||||
if top_module_namespaces[0]:
|
||||
top_module_namespaces = [''] + top_module_namespaces
|
||||
|
||||
with open(args.src, "r") as f:
|
||||
content = f.read()
|
||||
module = parser.Module.parseString(content)
|
||||
instantiator.instantiate_namespace_inplace(module)
|
||||
|
||||
with open(args.template, "r") as f:
|
||||
template_content = f.read()
|
||||
wrapper = PybindWrapper(
|
||||
module=module,
|
||||
module_name=args.module_name,
|
||||
use_boost=args.use_boost,
|
||||
top_module_namespaces=top_module_namespaces,
|
||||
ignore_classes=args.ignore,
|
||||
module_template=template_content,
|
||||
)
|
||||
|
||||
cc_content = wrapper.wrap()
|
||||
with open(args.out, "w") as f:
|
||||
f.write(cc_content)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,36 @@
|
|||
"""Setup file for the GTwrap package"""
|
||||
|
||||
try:
|
||||
from setuptools import find_packages, setup
|
||||
except ImportError:
|
||||
from distutils.core import find_packages, setup
|
||||
|
||||
packages = find_packages()
|
||||
|
||||
setup(
|
||||
name='gtwrap',
|
||||
description='Library to wrap C++ with Python and Matlab',
|
||||
version='1.1.0',
|
||||
author="Frank Dellaert et. al.",
|
||||
author_email="dellaert@gatech.edu",
|
||||
license='BSD',
|
||||
keywords="wrap, bindings, cpp, python",
|
||||
long_description=open("README.md").read(),
|
||||
long_description_content_type="text/markdown",
|
||||
python_requires=">=3.6",
|
||||
# https://pypi.org/classifiers
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Education',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Science/Research',
|
||||
'Operating System :: MacOS',
|
||||
'Operating System :: Microsoft :: Windows',
|
||||
'Operating System :: POSIX',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Topic :: Software Development :: Libraries'
|
||||
],
|
||||
packages=packages,
|
||||
platforms="any",
|
||||
install_requires=open("requirements.txt").readlines(),
|
||||
)
|
|
@ -4,7 +4,7 @@ import unittest
|
|||
import sys, os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from interface_parser import *
|
||||
from gtwrap.interface_parser import *
|
||||
|
||||
|
||||
class TestPyparsing(unittest.TestCase):
|
||||
|
|
|
@ -10,9 +10,9 @@ import filecmp
|
|||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import template_instantiator as instantiator
|
||||
import interface_parser as parser
|
||||
from matlab_wrapper import MatlabWrapper
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
import gtwrap.interface_parser as parser
|
||||
from gtwrap.matlab_wrapper import MatlabWrapper
|
||||
|
||||
|
||||
class TestWrap(unittest.TestCase):
|
||||
|
@ -20,7 +20,7 @@ class TestWrap(unittest.TestCase):
|
|||
MATLAB_TEST_DIR = TEST_DIR + "expected-matlab/"
|
||||
MATLAB_ACTUAL_DIR = TEST_DIR + "actual-matlab/"
|
||||
|
||||
def _generate_content(self, cc_content, path=''):
|
||||
def generate_content(self, cc_content, path=''):
|
||||
"""Generate files and folders from matlab wrapper content.
|
||||
|
||||
Keyword arguments:
|
||||
|
@ -48,7 +48,7 @@ class TestWrap(unittest.TestCase):
|
|||
for sub_content in c:
|
||||
import sys
|
||||
print("sub object: {}".format(sub_content[1][0][0]), file=sys.stderr)
|
||||
self._generate_content(sub_content[1], path_to_folder)
|
||||
self.generate_content(sub_content[1], path_to_folder)
|
||||
elif type(c[1]) == list:
|
||||
path_to_folder = path + '/' + c[0]
|
||||
|
||||
|
@ -104,7 +104,7 @@ class TestWrap(unittest.TestCase):
|
|||
|
||||
cc_content = wrapper.wrap()
|
||||
|
||||
self._generate_content(cc_content)
|
||||
self.generate_content(cc_content)
|
||||
|
||||
def compare_and_diff(file):
|
||||
output = self.MATLAB_ACTUAL_DIR + file
|
||||
|
|
|
@ -14,9 +14,9 @@ import os.path as path
|
|||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.path.append(os.path.normpath(os.path.abspath(os.path.join(__file__, '../../../build/wrap'))))
|
||||
|
||||
from pybind_wrapper import PybindWrapper
|
||||
import interface_parser as parser
|
||||
import template_instantiator as instantiator
|
||||
from gtwrap.pybind_wrapper import PybindWrapper
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
|
Loading…
Reference in New Issue