Squashed 'wrap/' changes from dfa624e77..09f8bbf71

09f8bbf71 Merge pull request #25 from borglab/fix/function-name
0dbfb6c13 fix function name to be the correct one
f69f8b01f Merge pull request #24 from borglab/fix/pip
6519a6627 use pip install to overcome superuser issues
b11ecf4e8 Merge pull request #23 from borglab/fix/remove-pip-args
813030108 remove pip-args since we are using setup.py
498d233e0 Merge pull request #22 from borglab/fix/package-install
846212ac3 set correct flags for installing gtwrap package
62161cd20 Merge pull request #21 from borglab/feature/script-vars
93be1d9f8 set script variables and move pybind11 loading so gtwrap can be used under gtsam
8770e3c7e Merge pull request #20 from borglab/fix/pybind-include
8c3c83618 proper placement of pybind11 include
a9ad4f504 Merge pull request #19 from borglab/feature/package
99d8a12c7 added more documentation
4cbec1579 change to macro so we don't have to deal with function scopes
b83e405b8 updates to completely install the package
38a64b3de new scripts which will be installed to bin directory
bf9646235 Merge pull request #18 from borglab/fix/cmake-min
c7c280099 Consistent cmake minimum required
42df58f62 Merge pull request #17 from borglab/fix/cleanup
e580b282d version bump
4ccd66fa5 More finegrained handling of Python version
6476fd710 Merge pull request #16 from borglab/feature/better-find-python
8ac1296a0 use setup.py to install dependencies
e9ac473be install dependencies and support versions of CMake<3.12
cf272dbd2 Merge pull request #15 from borglab/feature/utils
ffc9cc4f7 new utils to reduce boilerplate
20e8e8b7a Merge pull request #11 from borglab/feature/package
04b844bd6 use new version of FindPython and be consistent
3f9d7a32a Merge pull request #13 from borglab/add_license
c791075a6 Add LICENSE
517b67c46 correct working directory for setup.py
1b22b47ae move matlab.h to root directory
37b407214 Proper source directory path for use in other projects
61696dd5d configure PybindWrap within the cmake directory
1b91fc9af add config file so we can use find_package
a1e6f4f53 small typo
da9f351be updated README and housekeeping
64b8f78d5 files needed to allow for packaging
bddda7f54 package structure

git-subtree-dir: wrap
git-subtree-split: 09f8bbf7172ba8b1bd3d2484795743f16e1a5893
release/4.3a0
Varun Agrawal 2021-01-04 13:11:36 -05:00
parent 16418e2fa6
commit 7cc7232a99
18 changed files with 424 additions and 204 deletions

3
.gitignore vendored
View File

@ -1,2 +1,5 @@
__pycache__/
.vscode/
*build*
*dist*
*.egg-info

55
CMakeLists.txt Normal file
View File

@ -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})

13
LICENSE Normal file
View File

@ -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.

View File

@ -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

74
cmake/GtwrapUtils.cmake Normal file
View File

@ -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()

View File

@ -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})

27
cmake/gtwrapConfig.cmake Normal file
View File

@ -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)

0
gtwrap/__init__.py Normal file
View File

View File

@ -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)

View File

@ -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()

View File

@ -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):

68
scripts/matlab_wrap.py Normal file
View File

@ -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)

93
scripts/pybind_wrap.py Normal file
View File

@ -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()

36
setup.py Normal file
View File

@ -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(),
)

View File

@ -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):

View File

@ -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

View 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__))))