|
| 1 | +# Tutorial |
| 2 | + |
| 3 | +This is a tutorial on how to wrap your own C++ projects using GTSAM's python wrapper. |
| 4 | + |
| 5 | +# Prerequisites |
| 6 | + |
| 7 | +We assume you have Python 3 installed. We support Python 3.6 and up. |
| 8 | + |
| 9 | +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. |
| 10 | +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. |
| 11 | + |
| 12 | +As a bonus, if you understand Cython's build process, this tutorial should be fairly intuitive. |
| 13 | + |
| 14 | +**NOTE** This tutorial has been tested using GTSAM version 4.0.x and above. |
| 15 | + |
| 16 | +# Project Setup |
| 17 | + |
| 18 | +As a set of minimal requirements, the project should be set up as follows: |
| 19 | + |
| 20 | +``` |
| 21 | +top-level-directory |
| 22 | +| |
| 23 | +|- CMakeLists.txt |
| 24 | +|- <project>.h |
| 25 | +|- __init__.py.in |
| 26 | +|- setup.py |
| 27 | +|- src/ |
| 28 | +
|
| 29 | +``` |
| 30 | + |
| 31 | +The files are |
| 32 | + |
| 33 | +1. `CMakeLists.txt`: The cmake definition file. |
| 34 | +2. `<project>.h`: The header file which specifies all the code components to be wrapped. |
| 35 | +3. `__init__.py.in`: Template __init__.py file used by cmake. |
| 36 | +4. `setup.py`: The file used by setuptools to generate the egg/wheel. |
| 37 | +5. `src/`: All your C++ source code goes here. |
| 38 | + |
| 39 | + |
| 40 | +# CMake Configuration |
| 41 | + |
| 42 | +In this section, we will go through a step-by-step process of defining the `CMakeLists.txt` file which will generated our wrapped code. |
| 43 | + |
| 44 | +An illustrative example is provided in the `src` directory of this repository. |
| 45 | + |
| 46 | +1. Define project name. |
| 47 | +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. |
| 48 | +3. Include `GTSAM` package. This allows use to use the cython install path automatically. CMake will take care of the rest. |
| 49 | + |
| 50 | + ```cmake |
| 51 | + find_package(GTSAM REQUIRED) |
| 52 | + include_directories(${GTSAM_CYTHON_INSTALL_PATH}) |
| 53 | + include_directories(${GTSAM_EIGENCY_INSTALL_PATH}) |
| 54 | + ``` |
| 55 | +
|
| 56 | + 4. The second package is `GTSAMCMakeTools`. This gives us access to the wrapping functions which we will use later on. |
| 57 | +
|
| 58 | + ```cmake |
| 59 | + find_package(GTSAMCMakeTools CONFIG) |
| 60 | + include(GtsamCythonWrap) # Automatic Cython wrapper generation |
| 61 | + ``` |
| 62 | +
|
| 63 | +5. These next few steps should be familiar for CMake users. We first include the project source directory. |
| 64 | +
|
| 65 | + ```cmake |
| 66 | + include_directories(BEFORE "${PROJECT_SOURCE_DIR}") |
| 67 | + ``` |
| 68 | +
|
| 69 | +6. Now we can specify the building and linking of our project code as a shared library. |
| 70 | +
|
| 71 | + ```cmake |
| 72 | + add_library(${PROJECT_NAME} SHARED src/greeting.h src/greeting.cpp) |
| 73 | + target_link_libraries(${PROJECT_NAME} gtsam) |
| 74 | + ``` |
| 75 | +
|
| 76 | +7. And finally, we can install the shared library. |
| 77 | +
|
| 78 | + ```cmake |
| 79 | + install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) |
| 80 | + ``` |
| 81 | +
|
| 82 | +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. |
| 83 | +
|
| 84 | + ```cmake |
| 85 | + configure_file(${PROJECT_SOURCE_DIR}/__init__.py.in ${PROJECT_BINARY_DIR}/cython/${PROJECT_NAME}/__init__.py) |
| 86 | + ``` |
| 87 | +
|
| 88 | +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`. |
| 89 | +
|
| 90 | + ```cmake |
| 91 | + configure_file(${PROJECT_SOURCE_DIR}/setup.py ${PROJECT_BINARY_DIR}/cython/setup.py COPYONLY) |
| 92 | + ``` |
| 93 | +
|
| 94 | +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: |
| 95 | +
|
| 96 | + 1. Interface Header: A `.h` file which defines what classes, functions, etc., are to be wrapped. |
| 97 | + 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. |
| 98 | + 3. Install Path: This is the location where the wrapped package will be installed on running `make install`. |
| 99 | + 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. |
| 100 | + 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. |
| 101 | +
|
| 102 | + ```cmake |
| 103 | + wrap_and_install_library_cython("example.h" # interface_header |
| 104 | + "" # extra imports |
| 105 | + "./${PROJECT_NAME}" # install path |
| 106 | + "gtsam;${PROJECT_NAME}" # library to link with |
| 107 | + "wrap;gtsam" # dependencies which need to be built before wrapping |
| 108 | + ) |
| 109 | + ``` |
| 110 | +
|
| 111 | +# Compiling |
| 112 | +
|
| 113 | +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`. |
| 114 | +
|
| 115 | +```sh |
| 116 | +mkdir build && cd build |
| 117 | +cmake .. && make |
| 118 | +``` |
| 119 | + |
| 120 | +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. |
| 121 | + |
| 122 | +# Installing |
| 123 | + |
| 124 | +To install the package, in the `cython` directory we can run `python setup.py build`. |
0 commit comments