diff --git a/sys-utils/libcmt/Makefile b/sys-utils/libcmt/Makefile index c5b92952..2c5b1c26 100644 --- a/sys-utils/libcmt/Makefile +++ b/sys-utils/libcmt/Makefile @@ -81,11 +81,12 @@ $(libcmt_SO): $(libcmt_OBJ) $(TARGET_CC) -shared -o $@ $^ libcmt: $(libcmt_LIB) $(libcmt_SO) -install: $(libcmt_LIB) $(libcmt_SO) +install: $(libcmt_LIB) $(libcmt_SO) build/ffi.h mkdir -p $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib cp -f $^ $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib mkdir -p $(TARGET_DESTDIR)$(TARGET_PREFIX)/include/libcmt/ cp -f src/*.h $(TARGET_DESTDIR)$(TARGET_PREFIX)/include/libcmt/ + cp -f build/ffi.h $(TARGET_DESTDIR)$(TARGET_PREFIX)/include/libcmt/ mkdir -p $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib/pkgconfig sed -e 's|@ARG_PREFIX@|$(TARGET_PREFIX)|g' src/libcmt.pc > $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib/pkgconfig/libcmt.pc @@ -121,11 +122,12 @@ $(mock_SO): $(mock_OBJ) mock: $(mock_LIB) $(mock_SO) -install-mock: $(mock_LIB) $(mock_SO) +install-mock: $(mock_LIB) $(mock_SO) build/ffi.h mkdir -p $(DESTDIR)$(PREFIX)/lib cp -f $^ $(DESTDIR)$(PREFIX)/lib mkdir -p $(DESTDIR)$(PREFIX)/include/libcmt/ cp -f src/*.h $(DESTDIR)$(PREFIX)/include/libcmt/ + cp -f build/ffi.h $(DESTDIR)$(PREFIX)/include/libcmt/ mkdir -p $(DESTDIR)$(PREFIX)/lib/pkgconfig sed -e 's|@ARG_PREFIX@|$(PREFIX)|g' src/libcmt_mock.pc > $(DESTDIR)$(PREFIX)/lib/pkgconfig/libcmt.pc @@ -181,6 +183,8 @@ $(tools_OBJDIR)/funsel: tools/funsel.c $(mock_LIB) tools: $(tools_BINS) +build/ffi.h: src/buf.h src/abi.h src/keccak.h src/merkle.h src/io.h src/rollup.h + cat $^ | sh tools/prepare-ffi.sh > $@ #------------------------------------------------------------------------------- LINTER_IGNORE_SOURCES=src/io.c LINTER_IGNORE_HEADERS= diff --git a/sys-utils/libcmt/README.md b/sys-utils/libcmt/README.md index 8a9d66a0..389ba8ec 100644 --- a/sys-utils/libcmt/README.md +++ b/sys-utils/libcmt/README.md @@ -134,6 +134,79 @@ cast calldata-decode "Notice(bytes)" 0x`xxd -p -c0 "$1"` | ( This library is intented to be used with programming languages other than C. They acheive this by different means. +## Python + +Python has multiple Foreign Function Interface (FFI) options for interoperability with C. +This example uses CFFI and the `libcmt` mock. Which is assumed to be installed at `./libcmt-0.1.0`. + +This document uses the [main mode](https://cffi.readthedocs.io/en/latest/overview.html#main-mode-of-usage) of CFFI and works in two steps: `build`, then `use`. + +### Build + +The `build` step has the objective of creating a python module for libcmt. +To acheive this we'll use `libcmt/ffi.h` and the script below. +Paths may need adjustments. + +``` +import os +from cffi import FFI + +ffi = FFI() +with open(os.path.join(os.path.dirname(__file__), "../libcmt-0.1.0/usr/include/libcmt/ffi.h")) as f: + ffi.cdef(f.read()) +ffi.set_source("pycmt", +""" +#include "libcmt/rollup.h" +""", + include_dirs=["libcmt-0.1.0/usr/include"], + library_dirs=["libcmt-0.1.0/usr/lib"], + libraries=['cmt']) + +if __name__ == "__main__": + ffi.compile(verbose=True) +``` + +### Use + +With the module built, we can import it with python and use its functions. +This example uses the raw bindings and just serves to ilustrate the process. +Better yet would be to wrap these functions into a more "pythonic" API. + +`LD_LIBRARY_PATH=libcmt-0.1.0/lib/ python` + +``` +#!/usr/bin/env python + +# run this file only after building pycmt! +import os +from pycmt.lib import ffi, lib + +r = ffi.new("cmt_rollup_t[1]") +assert(lib.cmt_rollup_init(r) == 0) + +address = ffi.new("uint8_t[20]", b"1000000000000") +value = ffi.new("uint8_t[32]", b"0000000000001") +data = b"hello world" +index = ffi.new("uint64_t *") +print(os.strerror(-lib.cmt_rollup_emit_voucher(r, + 20, address, + 32, value, + len(data), data, index))) + +ffi.gc(r, lib.cmt_rollup_fini) +``` + +Common errors such as the one below indicate that python couldn't find libcmt, +make sure `LD_LIBRARY_PATH` points to the correct directory, or better yet, link +against the static library. + +``` +>>> import pycmt +Traceback (most recent call last): + File "", line 1, in +ImportError: libcmt.so: cannot open shared object file: No such file or directory +``` + ## Go Go is able to include C headers directly with cgo. diff --git a/sys-utils/libcmt/tools/prepare-ffi.sh b/sys-utils/libcmt/tools/prepare-ffi.sh new file mode 100644 index 00000000..42aaadf8 --- /dev/null +++ b/sys-utils/libcmt/tools/prepare-ffi.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +sed \ + -e '/\/\*/,/\*\//d' \ + -e '/#if\s/,/#endif/d' \ + -e '/#define/d' \ + -e '/#endif/d' \ + -e '/#ifndef/d' \ + -e '/#include/d' \