Skip to content

Commit

Permalink
Merge pull request #749 from borglab/feature/wrap-update
Browse files Browse the repository at this point in the history
  • Loading branch information
dellaert authored Apr 20, 2021
2 parents e9202b8 + 31635be commit dbefd75
Show file tree
Hide file tree
Showing 21 changed files with 399 additions and 109 deletions.
38 changes: 21 additions & 17 deletions wrap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ configure_package_config_file(
INSTALL_INCLUDE_DIR
INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})

message(STATUS "Package config : ${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}")
# Set all the install paths
set(GTWRAP_CMAKE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR})
set(GTWRAP_LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR})
set(GTWRAP_BIN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${INSTALL_BIN_DIR})
set(GTWRAP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR})

# ##############################################################################
# Install the package

message(STATUS "CMake : ${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}")
# Install CMake scripts to the standard CMake script directory.
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/gtwrapConfig.cmake
cmake/MatlabWrap.cmake cmake/PybindWrap.cmake cmake/GtwrapUtils.cmake
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/gtwrapConfig.cmake
cmake/MatlabWrap.cmake cmake/PybindWrap.cmake
cmake/GtwrapUtils.cmake DESTINATION "${GTWRAP_CMAKE_INSTALL_DIR}")

# Configure the include directory for matlab.h This allows the #include to be
# either gtwrap/matlab.h, wrap/matlab.h or something custom.
Expand All @@ -60,24 +62,26 @@ configure_file(${PROJECT_SOURCE_DIR}/templates/matlab_wrapper.tpl.in

# Install the gtwrap python package as a directory so it can be found by CMake
# for wrapping.
message(STATUS "Lib path : ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}")
install(DIRECTORY gtwrap
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}")
install(DIRECTORY gtwrap DESTINATION "${GTWRAP_LIB_INSTALL_DIR}")

# Install pybind11 directory to `CMAKE_INSTALL_PREFIX/lib/gtwrap/pybind11` This
# will allow the gtwrapConfig.cmake file to load it later.
install(DIRECTORY pybind11
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}")
install(DIRECTORY pybind11 DESTINATION "${GTWRAP_LIB_INSTALL_DIR}")

# Install wrapping scripts as binaries to `CMAKE_INSTALL_PREFIX/bin` so they can
# be invoked for wrapping. We use DESTINATION (instead of TYPE) so we can
# support older CMake versions.
message(STATUS "Bin path : ${CMAKE_INSTALL_PREFIX}/${INSTALL_BIN_DIR}")
install(PROGRAMS scripts/pybind_wrap.py scripts/matlab_wrap.py
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INSTALL_BIN_DIR}")
DESTINATION "${GTWRAP_BIN_INSTALL_DIR}")

# Install the matlab.h file to `CMAKE_INSTALL_PREFIX/lib/gtwrap/matlab.h`.
message(
STATUS "Header path : ${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}")
install(FILES matlab.h
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}")
install(FILES matlab.h DESTINATION "${GTWRAP_INCLUDE_INSTALL_DIR}")

string(ASCII 27 Esc)
set(gtwrap "${Esc}[1;36mgtwrap${Esc}[m")
message(STATUS "${gtwrap} Package config : ${GTWRAP_CMAKE_INSTALL_DIR}")
message(STATUS "${gtwrap} version : ${PROJECT_VERSION}")
message(STATUS "${gtwrap} CMake path : ${GTWRAP_CMAKE_INSTALL_DIR}")
message(STATUS "${gtwrap} library path : ${GTWRAP_LIB_INSTALL_DIR}")
message(STATUS "${gtwrap} binary path : ${GTWRAP_BIN_INSTALL_DIR}")
message(STATUS "${gtwrap} header path : ${GTWRAP_INCLUDE_INSTALL_DIR}")
2 changes: 2 additions & 0 deletions wrap/gtwrap/interface_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
"""

import sys

import pyparsing

from .classes import *
from .declaration import *
from .enum import *
from .function import *
from .module import *
from .namespace import *
Expand Down
42 changes: 20 additions & 22 deletions wrap/gtwrap/interface_parser/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@

from typing import Iterable, List, Union

from pyparsing import Optional, ZeroOrMore, Literal
from pyparsing import Literal, Optional, ZeroOrMore

from .enum import Enum
from .function import ArgumentList, ReturnType
from .template import Template
from .tokens import (CLASS, COLON, CONST, IDENT, LBRACE, LPAREN, RBRACE,
RPAREN, SEMI_COLON, STATIC, VIRTUAL, OPERATOR)
from .type import TemplatedType, Type, Typename
from .tokens import (CLASS, COLON, CONST, IDENT, LBRACE, LPAREN, OPERATOR,
RBRACE, RPAREN, SEMI_COLON, STATIC, VIRTUAL)
from .type import TemplatedType, Typename
from .utils import collect_namespaces
from .variable import Variable


Expand Down Expand Up @@ -200,21 +202,6 @@ def __repr__(self) -> str:
)


def collect_namespaces(obj):
"""
Get the chain of namespaces from the lowest to highest for the given object.
Args:
obj: Object of type Namespace, Class or InstantiatedClass.
"""
namespaces = []
ancestor = obj.parent
while ancestor and ancestor.name:
namespaces = [ancestor.name] + namespaces
ancestor = ancestor.parent
return [''] + namespaces


class Class:
"""
Rule to parse a class defined in the interface file.
Expand All @@ -230,9 +217,13 @@ class Members:
"""
Rule for all the members within a class.
"""
rule = ZeroOrMore(Constructor.rule ^ StaticMethod.rule ^ Method.rule
^ Variable.rule ^ Operator.rule).setParseAction(
lambda t: Class.Members(t.asList()))
rule = ZeroOrMore(Constructor.rule #
^ StaticMethod.rule #
^ Method.rule #
^ Variable.rule #
^ Operator.rule #
^ Enum.rule #
).setParseAction(lambda t: Class.Members(t.asList()))

def __init__(self,
members: List[Union[Constructor, Method, StaticMethod,
Expand All @@ -242,6 +233,7 @@ def __init__(self,
self.static_methods = []
self.properties = []
self.operators = []
self.enums = []
for m in members:
if isinstance(m, Constructor):
self.ctors.append(m)
Expand All @@ -253,6 +245,8 @@ def __init__(self,
self.properties.append(m)
elif isinstance(m, Operator):
self.operators.append(m)
elif isinstance(m, Enum):
self.enums.append(m)

_parent = COLON + (TemplatedType.rule ^ Typename.rule)("parent_class")
rule = (
Expand All @@ -275,6 +269,7 @@ def __init__(self,
t.members.static_methods,
t.members.properties,
t.members.operators,
t.members.enums
))

def __init__(
Expand All @@ -288,6 +283,7 @@ def __init__(
static_methods: List[StaticMethod],
properties: List[Variable],
operators: List[Operator],
enums: List[Enum],
parent: str = '',
):
self.template = template
Expand All @@ -312,6 +308,8 @@ def __init__(
self.static_methods = static_methods
self.properties = properties
self.operators = operators
self.enums = enums

self.parent = parent

# Make sure ctors' names and class name are the same.
Expand Down
70 changes: 70 additions & 0 deletions wrap/gtwrap/interface_parser/enum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
Atlanta, Georgia 30332-0415
All Rights Reserved
See LICENSE for the license information
Parser class and rules for parsing C++ enums.
Author: Varun Agrawal
"""

from pyparsing import delimitedList

from .tokens import ENUM, IDENT, LBRACE, RBRACE, SEMI_COLON
from .type import Typename
from .utils import collect_namespaces


class Enumerator:
"""
Rule to parse an enumerator inside an enum.
"""
rule = (
IDENT("enumerator")).setParseAction(lambda t: Enumerator(t.enumerator))

def __init__(self, name):
self.name = name

def __repr__(self):
return "Enumerator: ({0})".format(self.name)


class Enum:
"""
Rule to parse enums defined in the interface file.
E.g.
```
enum Kind {
Dog,
Cat
};
```
"""

rule = (ENUM + IDENT("name") + LBRACE +
delimitedList(Enumerator.rule)("enumerators") + RBRACE +
SEMI_COLON).setParseAction(lambda t: Enum(t.name, t.enumerators))

def __init__(self, name, enumerators, parent=''):
self.name = name
self.enumerators = enumerators
self.parent = parent

def namespaces(self) -> list:
"""Get the namespaces which this class is nested under as a list."""
return collect_namespaces(self)

def cpp_typename(self):
"""
Return a Typename with the namespaces and cpp name of this
class.
"""
namespaces_name = self.namespaces()
namespaces_name.append(self.name)
return Typename(namespaces_name)

def __repr__(self):
return "Enum: {0}".format(self.name)
3 changes: 3 additions & 0 deletions wrap/gtwrap/interface_parser/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def __init__(self,
# This means a tuple has been passed so we convert accordingly
elif len(default) > 1:
default = tuple(default.asList())
else:
# set to None explicitly so we can support empty strings
default = None
self.default = default

self.parent: Union[ArgumentList, None] = None
Expand Down
10 changes: 4 additions & 6 deletions wrap/gtwrap/interface_parser/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@

# pylint: disable=unnecessary-lambda, unused-import, expression-not-assigned, no-else-return, protected-access, too-few-public-methods, too-many-arguments

import sys

import pyparsing # type: ignore
from pyparsing import (ParserElement, ParseResults, ZeroOrMore,
cppStyleComment, stringEnd)
from pyparsing import ParseResults, ZeroOrMore, cppStyleComment, stringEnd

from .classes import Class
from .declaration import ForwardDeclaration, Include
from .enum import Enum
from .function import GlobalFunction
from .namespace import Namespace
from .template import TypedefTemplateInstantiation
Expand All @@ -44,7 +41,8 @@ class Module:
^ Class.rule #
^ TypedefTemplateInstantiation.rule #
^ GlobalFunction.rule #
^ Variable.rule #
^ Enum.rule #
^ Variable.rule #
^ Namespace.rule #
).setParseAction(lambda t: Namespace('', t.asList())) +
stringEnd)
Expand Down
4 changes: 3 additions & 1 deletion wrap/gtwrap/interface_parser/namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from .classes import Class, collect_namespaces
from .declaration import ForwardDeclaration, Include
from .enum import Enum
from .function import GlobalFunction
from .template import TypedefTemplateInstantiation
from .tokens import IDENT, LBRACE, NAMESPACE, RBRACE
Expand Down Expand Up @@ -68,7 +69,8 @@ class Namespace:
^ Class.rule #
^ TypedefTemplateInstantiation.rule #
^ GlobalFunction.rule #
^ Variable.rule #
^ Enum.rule #
^ Variable.rule #
^ rule #
)("content") # BR
+ RBRACE #
Expand Down
1 change: 1 addition & 0 deletions wrap/gtwrap/interface_parser/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"#include",
],
)
ENUM = Keyword("enum") ^ Keyword("enum class") ^ Keyword("enum struct")
NAMESPACE = Keyword("namespace")
BASIS_TYPES = map(
Keyword,
Expand Down
26 changes: 26 additions & 0 deletions wrap/gtwrap/interface_parser/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
Atlanta, Georgia 30332-0415
All Rights Reserved
See LICENSE for the license information
Various common utilities.
Author: Varun Agrawal
"""


def collect_namespaces(obj):
"""
Get the chain of namespaces from the lowest to highest for the given object.
Args:
obj: Object of type Namespace, Class, InstantiatedClass, or Enum.
"""
namespaces = []
ancestor = obj.parent
while ancestor and ancestor.name:
namespaces = [ancestor.name] + namespaces
ancestor = ancestor.parent
return [''] + namespaces
2 changes: 2 additions & 0 deletions wrap/gtwrap/interface_parser/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ def __init__(self,
self.name = name
if default:
self.default = default[0]
else:
self.default = None

self.parent = parent

Expand Down
Loading

0 comments on commit dbefd75

Please sign in to comment.