From 1e1f34fbdc6c13825b860cde2750b012bb1144ac Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Mon, 13 Jan 2020 13:31:36 -0500 Subject: [PATCH 01/10] added disclaimer --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7f1a776..9122580 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # gtsam-project-python Project template using GTSAM + python wrapping + +# DISCLAIMER +Under construction, doesn't work yet!! :( From 5bfadff30b114220d3e4fa4cd906c4a814b5c4d5 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 22 Jun 2020 16:23:04 -0500 Subject: [PATCH 02/10] basic python setup files --- example/__init__.py | 0 example/__init__.py.in | 1 + example/setup.py | 46 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) delete mode 100644 example/__init__.py create mode 100644 example/__init__.py.in create mode 100644 example/setup.py diff --git a/example/__init__.py b/example/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/example/__init__.py.in b/example/__init__.py.in new file mode 100644 index 0000000..0762a15 --- /dev/null +++ b/example/__init__.py.in @@ -0,0 +1 @@ +from .${PROJECT_NAME} import * diff --git a/example/setup.py b/example/setup.py new file mode 100644 index 0000000..daadd0f --- /dev/null +++ b/example/setup.py @@ -0,0 +1,46 @@ +import os +import sys +try: + from setuptools import setup, find_packages +except ImportError: + from distutils.core import setup, find_packages + +packages = find_packages() + +setup( + name='varun_example', + description='Simple example of wrapping projects with Python and GTSAM', + url='https://gtsam.org/', + version='1.0.0', + author='Varun Agrawak', + author_email='varunagrawal@gatech.edu', + license='Simplified BSD license', + keywords='wrapper tutorial example', + long_description="", + long_description_content_type='text/markdown', + python_requires='>=3.6', + # https://pypi.org/pypi?%3Aaction=list_classifiers + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Education', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Operating System :: MacOS', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX', + 'License :: OSI Approved :: BSD License', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + ], + + packages=packages, + package_data={package: + [f for f in os.listdir(package.replace('.', os.path.sep)) if os.path.splitext(f)[1] in ('.so', '.pyd')] + for package in packages + }, + install_requires=[line.strip() for line in ''' + Cython>=0.25.2 + backports_abc>=0.5 + numpy>=1.12.0 +'''.splitlines() if len(line.strip()) > 0 and not line.strip().startswith('#')] +) From 69557b7ee0a941c4ec7ab064150d720b0a6efcef Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 22 Jun 2020 16:23:39 -0500 Subject: [PATCH 03/10] all the C++ code and wrapper header --- example/example.h | 31 +++++++++++++++++++++++++++++++ example/src/greeting.cpp | 15 +++++++++++++++ example/src/greeting.h | 15 +++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 example/example.h create mode 100644 example/src/greeting.cpp create mode 100644 example/src/greeting.h diff --git a/example/example.h b/example/example.h new file mode 100644 index 0000000..e070084 --- /dev/null +++ b/example/example.h @@ -0,0 +1,31 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file example.h + * @brief Example wrapper interface file for Python + * @author Varun Agrawal + */ + +// This is an interface file for automatic Python wrapper generation. See +// gtsam.h for full documentation and more examples. + +#include + +namespace example { + +class Greeting { + Greeting(); + void sayHello() const; + void sayGoodbye() const; +}; + +} diff --git a/example/src/greeting.cpp b/example/src/greeting.cpp new file mode 100644 index 0000000..e1ce198 --- /dev/null +++ b/example/src/greeting.cpp @@ -0,0 +1,15 @@ +#include "greeting.h" + +namespace example { + +/// Print a greeting +void Greeting::sayHello() const { + std::cout << "Hello from GTSAM" << std::endl; +} + +/// Print a farewell +void Greeting::sayGoodbye() const { + std::cout << "Goodbye, robot" << std::endl; +} + +}; diff --git a/example/src/greeting.h b/example/src/greeting.h new file mode 100644 index 0000000..8bdecb6 --- /dev/null +++ b/example/src/greeting.h @@ -0,0 +1,15 @@ +#include +#include + +namespace example { + +class Greeting { + public: + /// Print a greeting + void sayHello() const; + + /// Print a farewell + void sayGoodbye() const; +}; + +} // namespace example From 94f01d2a02049d6fcf5856ab9ff5ad71153c73a9 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 22 Jun 2020 16:24:31 -0500 Subject: [PATCH 04/10] fully working CMake file --- example/CMakeLists.txt | 71 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 example/CMakeLists.txt diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..f294dc9 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,71 @@ +# This file should be used as a template for creating new projects with Python wrapping using the CMake tools + +################################################################################### +# 1. To create your own project, replace "example" with the actual name of your project +cmake_minimum_required(VERSION 3.0) +project(example CXX C) + +################################################################################### +# 2. Set the python version +set(GTSAM_PYTHON_VERSION "3.6") + +################################################################################### +# 3. Find GTSAM components so we have access to the GTSAM Cython install path +find_package(GTSAM REQUIRED) # Uses installed package +# Note: Since Jan-2019, GTSAMConfig.cmake defines exported CMake targets +# that automatically do include the include_directories() without the need +# to call include_directories(), just target_link_libraries(NAME gtsam) +#include_directories(${GTSAM_INCLUDE_DIR}) + +# Include the required GTSAM Cython libraries +include_directories(${GTSAM_CYTHON_INSTALL_PATH}) +include_directories(${GTSAM_EIGENCY_INSTALL_PATH}) + +################################################################################### +# 4. Get the wrapping functions +# Include GTSAM CMake tools +find_package(GTSAMCMakeTools CONFIG) +#include(GtsamBuildTypes) # Load build type flags and default to Debug mode +#include(GtsamTesting) # Easy functions for creating unit tests and scripts +include(GtsamCythonWrap) # Automatic Cython wrapper generation + +################################################################################### +# 5. Add the local source directory for CMake +# Ensure that local folder is searched before library folders +include_directories(BEFORE "${PROJECT_SOURCE_DIR}") + + +################################################################################### +# 6. Build static library from common sources +add_library(${PROJECT_NAME} SHARED src/greeting.h src/greeting.cpp) +target_link_libraries(${PROJECT_NAME} gtsam) + +################################################################################### +# 7. Install library +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) + +################################################################################### +# # Build tests (CMake tracks the dependecy to link with GTSAM through our project's static library) +# gtsamAddTestsGlob("${PROJECT_NAME}" "tests/test*.cpp" "" "${PROJECT_NAME}") + +################################################################################### +# # Build scripts (CMake tracks the dependecy to link with GTSAM through our project's static library) +# gtsamAddExamplesGlob("*.cpp" "" "${PROJECT_NAME}") + +################################################################################### +# 8. Copy the __init__.py file so Cython recognizes this as a package. +# This function also updates the contents to use the correct package name. +configure_file(${PROJECT_SOURCE_DIR}/__init__.py.in ${PROJECT_BINARY_DIR}/cython/${PROJECT_NAME}/__init__.py) + +################################################################################### +# 9. (Strict) Copy over the setup.py file so we can build and install the package. +configure_file(${PROJECT_SOURCE_DIR}/setup.py ${PROJECT_BINARY_DIR}/cython/setup.py COPYONLY) + +################################################################################### +# 10. Build Cython wrapper (CMake tracks the dependecy to link with GTSAM through our project's static library) +wrap_and_install_library_cython("example.h" # interface_header + "" # extra imports + "./${PROJECT_NAME}" # install path + "gtsam;${PROJECT_NAME}" # library to link with + "wrap;gtsam" # dependencies which need to be built before wrapping + ) From 0a6f1dbd3269d06649a43dae1591aabcc1b4140f Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 22 Jun 2020 16:24:56 -0500 Subject: [PATCH 05/10] update .gitignore to ignore all build directories --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 67456eb..fb27ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -33,5 +33,5 @@ # Directories .ipynb_checkpoints/* -build/* +**/build/* example/__pycache__ \ No newline at end of file From 68130232b4fe88a864e3e456258283d40e9aa712 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 22 Jun 2020 16:25:26 -0500 Subject: [PATCH 06/10] added tutorial detailing all the steps necessary to perform python wrapping --- README.md | 3 +- TUTORIAL.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 TUTORIAL.md diff --git a/README.md b/README.md index 9122580..29a1fc2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # gtsam-project-python Project template using GTSAM + python wrapping -# DISCLAIMER -Under construction, doesn't work yet!! :( +Please refer to the [tutorial](TUTORIAL.md) to get started. \ No newline at end of file diff --git a/TUTORIAL.md b/TUTORIAL.md new file mode 100644 index 0000000..15b8cc6 --- /dev/null +++ b/TUTORIAL.md @@ -0,0 +1,121 @@ +# Tutorial + +This is a tutorial on how to wrap your own C++ projects using GTSAM's python wrapper. + +# Prerequisites + +We assume you have Python 3 installed. We support Python 3.6 and up. + +We also assume some knowledge of how Python packaging and setup works. If you understand how to write your own basic `setup.py` file, you should be fine. + +As a bonus, if you understand Cython's build process, this tutorial should be fairly intuitive. + +# Project Setup + +As a set of minimal requirements, the project should be set up as follows: + +``` +top-level-directory +| +|- CMakeLists.txt +|- .h +|- __init__.py.in +|- setup.py +|- src/ + +``` + +The files are + +1. `CMakeLists.txt`: The cmake definition file. +2. `.h`: The header file which specifies all the code components to be wrapped. +3. `__init__.py.in`: Template __init__.py file used by cmake. +4. `setup.py`: The file used by setuptools to generate the egg/wheel. +5. `src/`: All your C++ source code goes here. + + +# CMake Configuration + +In this section, we will go through a step-by-step process of defining the `CMakeLists.txt` file which will generated our wrapped code. + +An illustrative example is provided in the `src` directory of this repository. + +1. Define project name. +2. Optionally, set the Python version you'd like to target. This should ideally be the same as the version you used to build the wrapper. +3. Include `GTSAM` package. This allows use to use the cython install path automatically. CMake will take care of the rest. + + ```cmake + find_package(GTSAM REQUIRED) + include_directories(${GTSAM_CYTHON_INSTALL_PATH}) + include_directories(${GTSAM_EIGENCY_INSTALL_PATH}) + ``` + + 4. The second package is `GTSAMCMakeTools`. This gives us access to the wrapping functions which we will use later on. + + ```cmake + find_package(GTSAMCMakeTools CONFIG) + include(GtsamCythonWrap) # Automatic Cython wrapper generation + ``` + +5. These next few steps should be familiar for CMake users. We first include the project source directory. + + ```cmake + include_directories(BEFORE "${PROJECT_SOURCE_DIR}") + ``` + +6. Now we can specify the building and linking of our project code as a shared library. + + ```cmake + add_library(${PROJECT_NAME} SHARED src/greeting.h src/greeting.cpp) + target_link_libraries(${PROJECT_NAME} gtsam) + ``` + +7. And finally, we can install the shared library. + + ```cmake + install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) + ``` + +8. Now we get to the wrapping part. To specify our project as a package we need to include an `__init__.py` file at the top level. This will allow python imports to work correctly. We can use the basic `__init__.py.in` template in this repo since it is pretty generic. + + ```cmake + configure_file(${PROJECT_SOURCE_DIR}/__init__.py.in ${PROJECT_BINARY_DIR}/cython/${PROJECT_NAME}/__init__.py) + ``` + +9. To help build and install the wrapped project, we make use of a `setup.py` file. This file can be customized as per your requirements. **NOTE** This command only copies over the `setup.py` file, so make sure you make any updates **BEFORE** you run `cmake`. + + ```cmake + configure_file(${PROJECT_SOURCE_DIR}/setup.py ${PROJECT_BINARY_DIR}/cython/setup.py COPYONLY) + ``` + +10. Finally, we specify the wrapping function so that the GTSAM wrapper can do its job. We require only one function `wrap_and_install_library_cython` which takes the following 5 arguments: + + 1. Interface Header: A `.h` file which defines what classes, functions, etc., are to be wrapped. + 2. Extra Imports: This is a set of `cython` imports included in the generated Cython files. You can use this to specify any additional imports your project may be dependent on. + 3. Install Path: This is the location where the wrapped package will be installed on running `make install`. + 4. Libraries: A semi-colon separated list of libraries which the project will be linked against. At the very least, you should link against `gtsam` and the generated shared object file. + 5. Dependencies: This is a semi-colon separated list of dependency targets that need to be built before the code can be compiled and wrapped. This is nothing but a list of CMake targets. + + ```cmake + wrap_and_install_library_cython("example.h" # interface_header + "" # extra imports + "./${PROJECT_NAME}" # install path + "gtsam;${PROJECT_NAME}" # library to link with + "wrap;gtsam" # dependencies which need to be built before wrapping + ) + ``` + +# Compiling + +To compile and wrap the code, the familiar CMake process is followed. We create a build directory and run `cmake` and `make` + +```sh +mkdir build && cd build +cmake .. && make +``` + +Finally, we go into the generated `cython` directory where the `setup.py` file is present, and run `python setup.py build` to generate the final package. + +# Installing + +To install the package, in the `cython` directory we can run `python setup.py build`. From 2b3e94a317b18e3ddb1d4b5366b3961bf7470eb1 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 22 Jun 2020 16:28:20 -0500 Subject: [PATCH 07/10] minor fixes to setup.py --- example/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/setup.py b/example/setup.py index daadd0f..75f8b3c 100644 --- a/example/setup.py +++ b/example/setup.py @@ -8,11 +8,11 @@ packages = find_packages() setup( - name='varun_example', + name='example', description='Simple example of wrapping projects with Python and GTSAM', url='https://gtsam.org/', version='1.0.0', - author='Varun Agrawak', + author='Varun Agrawal', author_email='varunagrawal@gatech.edu', license='Simplified BSD license', keywords='wrapper tutorial example', From 0db685edf59a59936baca621faff3f3d50ad36d5 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 23 Jun 2020 10:19:24 -0500 Subject: [PATCH 08/10] additional, disambiguating comments --- TUTORIAL.md | 3 ++- example/setup.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/TUTORIAL.md b/TUTORIAL.md index 15b8cc6..88c71f6 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -7,6 +7,7 @@ This is a tutorial on how to wrap your own C++ projects using GTSAM's python wra We assume you have Python 3 installed. We support Python 3.6 and up. We also assume some knowledge of how Python packaging and setup works. If you understand how to write your own basic `setup.py` file, you should be fine. +Using this template project, you should only need to update the metadata information about your project. Check out the [python packaging website](https://packaging.python.org/tutorials/packaging-projects/) to learn more. As a bonus, if you understand Cython's build process, this tutorial should be fairly intuitive. @@ -107,7 +108,7 @@ An illustrative example is provided in the `src` directory of this repository. # Compiling -To compile and wrap the code, the familiar CMake process is followed. We create a build directory and run `cmake` and `make` +To compile and wrap the code, the familiar CMake process is followed. Starting from the directory where the `setup.py` file is located, we create a build directory and run `cmake` and `make`. ```sh mkdir build && cd build diff --git a/example/setup.py b/example/setup.py index 75f8b3c..7bf5693 100644 --- a/example/setup.py +++ b/example/setup.py @@ -34,6 +34,7 @@ ], packages=packages, + # Load the built shared object files package_data={package: [f for f in os.listdir(package.replace('.', os.path.sep)) if os.path.splitext(f)[1] in ('.so', '.pyd')] for package in packages From 4aec7ff286f5418c4539084b97f7ca1102274043 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 23 Jun 2020 10:41:21 -0500 Subject: [PATCH 09/10] add GTSAM Rot3 code for completion purposes --- example/src/greeting.cpp | 3 ++- example/src/greeting.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/example/src/greeting.cpp b/example/src/greeting.cpp index e1ce198..f8a5f0e 100644 --- a/example/src/greeting.cpp +++ b/example/src/greeting.cpp @@ -4,7 +4,8 @@ namespace example { /// Print a greeting void Greeting::sayHello() const { - std::cout << "Hello from GTSAM" << std::endl; + std::cout << "Hello from GTSAM!" << std::endl; + std::cout << "Here's a Rot3 for you " << gtsam::Rot3() << std::endl; } /// Print a farewell diff --git a/example/src/greeting.h b/example/src/greeting.h index 8bdecb6..671cb5a 100644 --- a/example/src/greeting.h +++ b/example/src/greeting.h @@ -1,3 +1,4 @@ +#include #include #include From b4904bfe90af81f8b05b168db381d029434fa278 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 30 Jun 2020 21:05:56 -0500 Subject: [PATCH 10/10] added note about GTSAM version against which tutorial was tested --- TUTORIAL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TUTORIAL.md b/TUTORIAL.md index 88c71f6..adf43df 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -11,6 +11,8 @@ Using this template project, you should only need to update the metadata informa As a bonus, if you understand Cython's build process, this tutorial should be fairly intuitive. +**NOTE** This tutorial has been tested using GTSAM version 4.0.x and above. + # Project Setup As a set of minimal requirements, the project should be set up as follows: