Skip to content

Commit

Permalink
GEM-3491 - CFFI Compile Split
Browse files Browse the repository at this point in the history
  • Loading branch information
HarryMills-UL committed Oct 20, 2023
1 parent 213ac2c commit 33dcf1d
Show file tree
Hide file tree
Showing 30 changed files with 294 additions and 167 deletions.
22 changes: 16 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
.idea/
dist/
venv/
build/
src/leap.egg-info
src/leap/leapc/*.h
src/leap/leapc/*.dll
src/leap/leapc/*.lib
src/leap/leapc/*.dylib
src/leap/leapc/*.so

leapc-python-api/build
leapc-python-api/dist
leapc-python-api/src/leap.egg-info

leapc-cffi/build
leapc-cffi/dist
leapc-cffi/src/leapc_cffi.egg-info
leapc-cffi/src/leapc_cffi/*.h
leapc-cffi/src/leapc_cffi/*.dll
leapc-cffi/src/leapc_cffi/*.pyd
leapc-cffi/src/leapc_cffi/*.lib
leapc-cffi/src/leapc_cffi/*.dylib
leapc-cffi/src/leapc_cffi/*.so

*.pyc
*.pyd
27 changes: 14 additions & 13 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ stages:
.common:
variables:
LIBTRACK_PROJECT_REF: leap-v5-platform/libtrack
LIBTRACK_REF: v5.13.2
LIBTRACK_REF: develop # Use develop until we have a tagged release including the leapc_cffi module

python-black:
stage: analysis
Expand All @@ -19,7 +19,7 @@ python-black:
script:
- python3 -m venv python_env --system-site-packages
- python_env/bin/python -m pip install black==22.3.0
- python_env/bin/python -m black --diff --check examples src
- python_env/bin/python -m black --diff --check examples leapc-cffi leapc-python-api

Linux-Build:
extends: .common
Expand All @@ -37,11 +37,11 @@ Linux-Build:
- mkdir build
- python3 -m venv build/venv --system-site-packages
- build/venv/bin/python -m pip install -r requirements.txt
- build/venv/bin/python -m build -o build/dist
- build/venv/bin/python -m build leapc-cffi -o build/dist
needs:
- project: $LIBTRACK_PROJECT_REF
job: X64LinuxRelProd
ref: develop # This has to be develop as we don't build tagged linux
ref: $LIBTRACK_REF
artifacts: true

Windows-Build:
Expand All @@ -62,10 +62,10 @@ Windows-Build:
- mkdir build
- python -m venv build/venv --system-site-packages
- build/venv/Scripts/python.exe -m pip install -r requirements.txt
- build/venv/Scripts/python.exe -m build -o build/dist
- build/venv/Scripts/python.exe -m build leapc-cffi -o build/dist
needs:
- project: $LIBTRACK_PROJECT_REF
job: WinRelDebProdLTS
job: WinRelDebProd
ref: $LIBTRACK_REF
artifacts: true

Expand All @@ -80,14 +80,14 @@ MacOS-Build:
- export EXTRACTED_INSTALLER_PATH="${PWD}"
- cd $CI_PROJECT_DIR
script:
- export LEAPSDK_INSTALL_LOCATION="$EXTRACTED_INSTALLER_PATH/LeapSDK"
- export LEAPSDK_INSTALL_LOCATION="$EXTRACTED_INSTALLER_PATH/Ultraleap Hand Tracking.app/Contents/LeapSDK"
- mkdir build
- python3 -m venv build/venv --system-site-packages
- build/venv/bin/python -m pip install -r requirements.txt
- build/venv/bin/python -m build -o build/dist
- build/venv/bin/python -m build leapc-cffi -o build/dist
needs:
- project: $LIBTRACK_PROJECT_REF
job: MacOSArm64RelDebProd-LTS
job: MacOSArm64RelDebProd
ref: $LIBTRACK_REF
artifacts: true

Expand All @@ -102,13 +102,14 @@ MacOS-Test:
- export EXTRACTED_INSTALLER_PATH="${PWD}"
- cd $CI_PROJECT_DIR
script:
- export LEAPSDK_INSTALL_LOCATION="$EXTRACTED_INSTALLER_PATH/LeapSDK"
- export LEAPSDK_INSTALL_LOCATION="$EXTRACTED_INSTALLER_PATH/Ultraleap Hand Tracking.app/Contents/LeapSDK"
- mkdir build
- python3 -m venv build/venv --system-site-packages
- build/venv/bin/python -m pip install .
- build/venv/bin/python -m pip install cffi
- build/venv/bin/python -m pip install -e leapc-python-api
- build/venv/bin/python examples/print_current_time.py
needs:
- project: $LIBTRACK_PROJECT_REF
job: MacOSArm64RelDebProd-LTS
job: MacOSArm64RelDebProd
ref: $LIBTRACK_REF
artifacts: true
artifacts: true
2 changes: 0 additions & 2 deletions MANIFEST.in

This file was deleted.

58 changes: 37 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,54 @@ Gemini LeapC Python Bindings
============================

Open-source Python bindings to the Gemini LeapC API. Including build instructions and some simple
examples. It does not include a pre-compiled python module; the bindings will have to be built
from source with Gemini already installed.
examples to get started with. We include some pre-compiled python objects with our Gemini installation from
5.17 onwards. To use these bindings you will require an installation of Gemini Hand Tracking.

The latest version of Gemini Hand Tracking can be found here:

https://www.ultraleap.com/tracking/gemini-hand-tracking-platform/


Install Instructions:
---------------------

```
# Create and activate a virtual environment
pip install -r requirements.txt
pip install -e leapc-python-api
python examples/tracking_event_example.py
```

Custom Install
--------------

The module assumes that you have the Leap SDK installed in the default location. If this is not
the case for you, you can use an environment variable to define the installation location. Define
`LEAPSDK_INSTALL_LOCATION` to the path of the `LeapSDK` folder if you have installed to a custom
location.
This module assumes that you have the Leap SDK installed in the default location. If this is not the case
for you, you can use an environment variable for define the installation location. Define the environment variable
`LEAPSDK_INSTALL_LOCATION` to the path of the `LeapSDK` folder, if you have installed to a custom location or moved it
somewhere else.

Example:
`export LEAPSDK_INSTALL_LOCATION="C:\Program Files\CustomDir\Ultraleap\LeapSDK"`

By default, this path is the following for each operating system:

- Windows: `C:\Program Files\Ultraleap\LeapSDK`
- MacOS: `/Library/Application Support/Ultraleap/LeapSDK`
- Linux: `TODO`

How to install:
---------------

1. `git clone [insert link here]`
2. Create and activate a virtual environment
3. `pip install -r requirements.txt`
4. `python -m build`
5. `pip install dist/leap-0.0.1.tar.gz`
6. `python examples/image_sample.py`

- Windows: `C:/Program Files/Ultraleap/LeapSDK`
- Linux: `/usr/lib/ultraleap-hand-tracking-service`
- Darwin: `/Applications/Ultraleap Hand Tracking.app/Contents/LeapSDK`


Missing Compiled Module?
------------------------

You might not have the correct matching compiled leapc_cffi module for your system, this can cause issues when importing
leap, such as: `ModuleNotFoundError: No module named 'leapc_cffi._leapc_cffi'`
If you'd like to build your own compiled module, you will still require a Gemini install and a C compiler of your
choice. Follow the steps below:

```
# Create and activate a virtual environment
pip install -r requirements.txt
python -m build leapc-cffi
pip install leapc-cffi/dist/leapc_cffi-0.0.1.tar.gz
pip install leapc-python-api
python examples/tracking_event_example.py
```
4 changes: 1 addition & 3 deletions examples/interpolation_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
from leap.datatypes import FrameData


def wait_until(
condition: Callable[[], bool], timeout: float = 5, poll_delay: float = 0.01
):
def wait_until(condition: Callable[[], bool], timeout: float = 5, poll_delay: float = 0.01):
start_time = timer()
while timer() - start_time < timeout:
if condition():
Expand Down
4 changes: 1 addition & 3 deletions examples/multi_device_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ def on_event(self, event):
self.n_events += 1


def wait_until(
condition: Callable[[], bool], timeout: float = 5, poll_delay: float = 0.01
):
def wait_until(condition: Callable[[], bool], timeout: float = 5, poll_delay: float = 0.01):
start_time = timer()
while timer() - start_time < timeout:
if condition():
Expand Down
7 changes: 7 additions & 0 deletions examples/print_current_time.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""
This is a simple example that prints the time according to the LeapC library.
It does not require a tracking camera or the Ultraleap Tracking service to be running.
This can be used to check if the python module has built successfully.
"""
import leap


Expand Down
2 changes: 2 additions & 0 deletions leapc-cffi/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include src/leapc_cffi/*
include src/scripts/*
34 changes: 34 additions & 0 deletions leapc-cffi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
CFFI Python Binds For LeapC
===========================

Low-level Python bindings for LeapC. These bindings are used by the leap module to interface with the LeapC API.

A built shared object of this is included in the Gemini Hand Tracking install from v5.17 onwards. However, you can
manually build this if it does not include a shared object for your python version or architecture.

Below are the instructions on how to compile manually (requiring a C compiler):

```
# Create and activate a virtual environment
pip install -r requirements.txt
python -m build leapc-cffi
pip install leapc-cffi/dist/leapc_cffi-0.0.1.tar.gz
pip install -e leapc-python-api
python examples/tracking_event_example.py
```

Building Errors
---------------

This will try to use the LeapC shared object from your install of Gemini Hand Tracking. This module assumes that you
have the Leap SDK installed in the default location. If this is not the case for you, you can use an environment
variable for define the installation location. Define the environment variable `LEAPSDK_INSTALL_LOCATION` to the path of
the `LeapSDK` folder, if you have installed to a custom location or moved it somewhere else.

Example:
`export LEAPSDK_INSTALL_LOCATION="C:\Program Files\CustomDir\Ultraleap\LeapSDK"`

By default, this path is the following for each operating system:
- Windows: `C:/Program Files/Ultraleap/LeapSDK`
- Linux: `/usr/lib/ultraleap-hand-tracking-service`
- Darwin: `/Applications/Ultraleap Hand Tracking.app/Contents/LeapSDK`
53 changes: 23 additions & 30 deletions setup.py → leapc-cffi/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
long_description = fh.read()

# The resource directory needs to contain the LeapC headers and libraries
_RESOURCE_DIRECTORY = os.path.join(_HERE, "src/leap/leapc")
_RESOURCE_DIRECTORY = os.path.join(_HERE, "src/leapc_cffi")

_OS_DEFAULT_HEADER_INSTALL_LOCATION = {
"Windows": "C:/Program Files/Ultraleap/LeapSDK",
"Linux": "/usr/include",
"Darwin": "/Applications/Ultraleap Hand Tracking Service.app/Contents/LeapSDK",
"Darwin": "/Applications/Ultraleap Hand Tracking.app/Contents/LeapSDK",
}

_OS_DEFAULT_LIB_INSTALL_LOCATION = {
Expand All @@ -23,11 +23,7 @@
"Darwin": _OS_DEFAULT_HEADER_INSTALL_LOCATION[platform.system()],
}

_OS_SHARED_OBJECT = {
"Windows": "LeapC.dll",
"Linux": "libLeapC.so",
"Darwin": "libLeapC.5.dylib",
}
_OS_SHARED_OBJECT = {"Windows": "LeapC.dll", "Linux": "libLeapC.so", "Darwin": "libLeapC.5.dylib"}


def setup_symlink(file_path, destination_path):
Expand All @@ -39,20 +35,24 @@ def setup_symlink(file_path, destination_path):

if os.path.exists(file_path):
try:
os.symlink(file_path, destination_path)
if platform.system() != "Windows":
os.symlink(file_path, destination_path)
else:
# Just copy it for windows, so we don't need administrator privileges
shutil.copy(file_path, destination_path)
except OSError as error:
print(error)
raise Exception(
"Error creating symlink to "
error_msg = (
"Error "
+ ("creating symlink to " if platform.system() != "Windows" else "copying file ")
+ file_path
+ ". You may need to run as administrator for the module build."
+ "."
)
raise Exception(error_msg)
else:
print("Looking for LeapC library at: " + file_path)
raise Exception(
"No "
+ str(_OS_SHARED_OBJECT[platform.system()])
+ " found, please ensure you "
"No " + str(_OS_SHARED_OBJECT[platform.system()]) + " found, please ensure you "
"have Ultraleap Gemini Hand Tracking installed, or define LEAPSDK_INSTALL_LOCATION environment "
"variable to point to a LeapSDK directory."
)
Expand Down Expand Up @@ -102,9 +102,7 @@ def gather_leap_sdk():

# Override
if _OVERRIDE_HEADER_LOCATION is not None:
print(
"Header override location given, using: " + str(_OVERRIDE_HEADER_LOCATION)
)
print("Header override location given, using: " + str(_OVERRIDE_HEADER_LOCATION))
leapc_header_path = _OVERRIDE_HEADER_LOCATION

if _OVERRIDE_LIB_LOCATION is not None:
Expand All @@ -113,17 +111,15 @@ def gather_leap_sdk():

# Copy the found header
if os.path.exists(leapc_header_path):
shutil.copy(leapc_header_path, _RESOURCE_DIRECTORY)
shutil.copy(leapc_header_path, os.path.join(_RESOURCE_DIRECTORY, "LeapC.h"))
else:
raise Exception(
"No LeapC.h found, please ensure you have Ultraleap Gemini Hand Tracking installed, or define "
"LEAPSDK_INSTALL_LOCATION environment variable to point to a LeapSDK directory."
)

# Create a symlink for the shared object
symlink_path = os.path.join(
_RESOURCE_DIRECTORY, _OS_SHARED_OBJECT[platform.system()]
)
symlink_path = os.path.join(_RESOURCE_DIRECTORY, _OS_SHARED_OBJECT[platform.system()])
setup_symlink(libleapc_path, symlink_path)

# On windows we also need to manage the LeapC.lib file
Expand All @@ -134,10 +130,7 @@ def gather_leap_sdk():
)
else:
windows_lib_path = os.path.join(
_OS_DEFAULT_LIB_INSTALL_LOCATION[platform.system()],
"lib",
"x64",
"LeapC.lib",
_OS_DEFAULT_LIB_INSTALL_LOCATION[platform.system()], "lib", "x64", "LeapC.lib"
)
symlink_lib_path = os.path.join(_RESOURCE_DIRECTORY, "LeapC.lib")
setup_symlink(windows_lib_path, symlink_lib_path)
Expand All @@ -146,10 +139,10 @@ def gather_leap_sdk():
gather_leap_sdk()

setuptools.setup(
name="leap",
name="leapc_cffi",
version="0.0.1",
author="Ultraleap",
description="Python wrappers around LeapC bindings",
description="Python CFFI bindings for LeapC",
long_description=long_description,
long_description_content_type="text/markdown",
package_dir={"": "src"},
Expand All @@ -160,7 +153,7 @@ def gather_leap_sdk():
}, # Excluded from the installed package
python_requires=">=3.6",
setup_requires=["cffi"],
install_requires=["cffi", "numpy", "websocket-client"],
ext_package="leap/leapc", # The location that the CFFI module will be built
cffi_modules=["src/leap/scripts/cffi_build.py:ffibuilder"],
install_requires=["cffi"],
ext_package="leapc_cffi", # The location that the CFFI module will be built
cffi_modules=["src/scripts/cffi_build.py:ffibuilder"],
)
File renamed without changes.
Loading

0 comments on commit 33dcf1d

Please sign in to comment.