Pybind11: Possible to use mpi4py? - boost

Is it possible in Pybind11 to use mpi4py on the Python side and then to hand over the communicator to the C++ side?
If so, how would it work?
If not, is it possible for example with Boost? And if so, how would it be done?
I searched the web literally for hours but didn't find anything.

Passing an mpi4py communicator to C++
using pybind11 can be done using the
mpi4py C-API. The corresponding header files can be located using the
following Python code:
import mpi4py
print(mpi4py.get_include())
To convenietly pass communicators between Python and C++, a custom pybind11
type caster
can be implemented. For this purpose, we start with the typical preamble.
// native.cpp
#include <pybind11/pybind11.h>
#include <mpi.h>
#include <mpi4py/mpi4py.h>
namespace py = pybind11;
In order for pybind11 to automatically convert a Python type to a C++ type,
we need a distinct type that the C++ compiler can recognise. Unfortunately,
the MPI standard does not specify the type for MPI_comm. Worse, in
common MPI implementations MPI_comm can be defined as int or void*
which the C++ compiler cannot distinguish from regular use of these types.
To create a distinct type, we define a wrapper class for MPI_Comm which
implicitly converts to and from MPI_Comm.
struct mpi4py_comm {
mpi4py_comm() = default;
mpi4py_comm(MPI_Comm value) : value(value) {}
operator MPI_Comm () { return value; }
MPI_Comm value;
};
The type caster is then implemented as follows:
namespace pybind11 { namespace detail {
template <> struct type_caster<mpi4py_comm> {
public:
PYBIND11_TYPE_CASTER(mpi4py_comm, _("mpi4py_comm"));
// Python -> C++
bool load(handle src, bool) {
PyObject *py_src = src.ptr();
// Check that we have been passed an mpi4py communicator
if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) {
// Convert to regular MPI communicator
value.value = *PyMPIComm_Get(py_src);
} else {
return false;
}
return !PyErr_Occurred();
}
// C++ -> Python
static handle cast(mpi4py_comm src,
return_value_policy /* policy */,
handle /* parent */)
{
// Create an mpi4py handle
return PyMPIComm_New(src.value);
}
};
}} // namespace pybind11::detail
Below is the code of an example module which uses the type caster. Note, that
we use mpi4py_comm instead of MPI_Comm in the function definitions
exposed to pybind11. However, due to the implicit conversion, we can use
these variables as regular MPI_Comm variables. Especially, they can be
passed to any function expecting an argument of type MPI_Comm.
// recieve a communicator and check if it equals MPI_COMM_WORLD
void print_comm(mpi4py_comm comm)
{
if (comm == MPI_COMM_WORLD) {
std::cout << "Received the world." << std::endl;
} else {
std::cout << "Received something else." << std::endl;
}
}
mpi4py_comm get_comm()
{
return MPI_COMM_WORLD; // Just return MPI_COMM_WORLD for demonstration
}
PYBIND11_MODULE(native, m)
{
// import the mpi4py API
if (import_mpi4py() < 0) {
throw std::runtime_error("Could not load mpi4py API.");
}
// register the test functions
m.def("print_comm", &print_comm, "Do something with the mpi4py communicator.");
m.def("get_comm", &get_comm, "Return some communicator.");
}
The module can be compiled, e.g., using
mpicxx -O3 -Wall -shared -std=c++14 -fPIC \
$(python3 -m pybind11 --includes) \
-I$(python3 -c 'import mpi4py; print(mpi4py.get_include())') \
native.cpp -o native$(python3-config --extension-suffix)
and tested using
import native
from mpi4py import MPI
import math
native.print_comm(MPI.COMM_WORLD)
# Create a cart communicator for testing
# (MPI_COMM_WORLD.size has to be a square number)
d = math.sqrt(MPI.COMM_WORLD.size)
cart_comm = MPI.COMM_WORLD.Create_cart([d,d], [1,1], False)
native.print_comm(cart_comm)
print(f'native.get_comm() == MPI.COMM_WORLD '
f'-> {native.get_comm() == MPI.COMM_WORLD}')
The output should be:
Received the world.
Received something else.
native.get_comm() == MPI.COMM_WORLD -> True

This is indeed possible. As was pointed out in the comments by John Zwinck, MPI_COMM_WORLD will automatically point to the correct communicator, so nothing has to be passed from python to the C++ side.
Example
First we have a simple pybind11 module that does expose a single function which simple prints some MPI information (taken from one of the many online tutorials). To compile the module see here pybind11 cmake example.
#include <pybind11/pybind11.h>
#include <mpi.h>
#include <stdio.h>
void say_hi()
{
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
char processor_name[MPI_MAX_PROCESSOR_NAME];
int name_len;
MPI_Get_processor_name(processor_name, &name_len);
printf("Hello world from processor %s, rank %d out of %d processors\n",
processor_name,
world_rank,
world_size);
}
PYBIND11_MODULE(mpi_lib, pybind_module)
{
constexpr auto MODULE_DESCRIPTION = "Just testing out mpi with python.";
pybind_module.doc() = MODULE_DESCRIPTION;
pybind_module.def("say_hi", &say_hi, "Each process is allowed to say hi");
}
Next the python side. Here I reuse the example from this post: Hiding MPI in Python and simply put in the pybind11 library. So first the python script that will call the MPI python script:
import sys
import numpy as np
from mpi4py import MPI
def parallel_fun():
comm = MPI.COMM_SELF.Spawn(
sys.executable,
args = ['child.py'],
maxprocs=4)
N = np.array(0, dtype='i')
comm.Reduce(None, [N, MPI.INT], op=MPI.SUM, root=MPI.ROOT)
print(f'We got the magic number {N}')
And the child process file. Here we simply call the library function and it just works.
from mpi4py import MPI
import numpy as np
from mpi_lib import say_hi
comm = MPI.Comm.Get_parent()
N = np.array(comm.Get_rank(), dtype='i')
say_hi()
comm.Reduce([N, MPI.INT], None, op=MPI.SUM, root=0)
The end result is:
from prog import parallel_fun
parallel_fun()
# Hello world from processor arch_zero, rank 1 out of 4 processors
# Hello world from processor arch_zero, rank 2 out of 4 processors
# Hello world from processor arch_zero, rank 0 out of 4 processors
# Hello world from processor arch_zero, rank 3 out of 4 processors
# We got the magic number 6

Related

Error access violation reading 0x0000000a when call fortran dll made by gfortran

1.FORTRAN source (main.for)
integer function mysum(a, b)
!DEC$ATTRIBUTES DLLEXPORT,STDCALL :: mysum
!DEC$ATTRIBUTES VALUE :: a, b
integer a,b
mysum = a + b
return
end function mysum
make dll
gfortran main.for -shared -o fordll.dll
call dll
#include <stdio.h>
#include <iostream>
#include <windows.h>
using namespace std;
typedef int(_stdcall * MYSUM)(int a, int b);
int main()
{
int a=10,b=20;
HINSTANCE hLibrary = LoadLibrary("fordll.dll");
if (hLibrary == NULL)
{
cout << "can't find the dll file" << endl;
return -1;
}
MYSUM fact = (MYSUM)GetProcAddress(hLibrary, "mysum");
if (fact == NULL)
{
cout << "can't find the function file." << endl;
return -2;
}
try
{
cout << fact(a,b);
}
catch(...)
{ }
FreeLibrary(hLibrary);
return 0;
}
ERROR
Exception Access Violation reading 0x0000000A
why? if the fortran source file is comppiled by Compad Visual fortran or Inter fortran, it works well. However, it doesn't work with gcc or gfortran. What's wrong?
You are using special directives to alter the calling conventions
!DEC$ATTRIBUTES DLLEXPORT,STDCALL :: mysum
!DEC$ATTRIBUTES VALUE :: a, b
However, these are only valid for the DEC compiler sand its descendant Intel Fortran.
GCC use !GCC$ directives instead. Use them, they are pretty much the same as the DEC ones. See https://gcc.gnu.org/onlinedocs/gfortran/ATTRIBUTES-directive.html#ATTRIBUTES-directive Just change coppy and paste the DEC directives and change DEC to GCC.
Alternatively, change the code to pass-by-reference and ditch the VALUE attribute. The STDCALL attribute is relevant for 32-bit Windows only.
In modern Fortran it is much better to use
integer function mysum(a, b) bind(C,name="mysum")
integer, value :: a, b
(ignoring the stdcall issue, which can be just deleted in the C++ code).

How to access data when calling python function from c++ which return numpy array

I'm calling the python function from c++ by pybind 11. the python function return a numpy array, I want to analyze the data in numpy array in c++
//the code for testing
#include <pybind11/embed.h> // everything needed for embedding
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
int main()
{
py::scoped_interpreter guard{};
py::print("test python interpreter");
auto sys = py::module::import("sys");
sys.attr("path").attr("append")(
"<path for python module>");
auto hdf5 = py::module::import("reader_hdf5");
auto rdata = hdf5.attr("load_next_chunk")(0, 1);
// how to access the data from the return value ?
py::array_t<int16_t> array(331776);
array = rdata.cast<py::array_t<int16_t>>();
}
There is error for the code here:
terminate called after throwing an instance of 'pybind11::error_already_set'
what(): TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
A call to mutable_data() works
py::array_t<int>rdata= hdf5.attr("load_next_chunk")(0, 1);
int *carray = rdata.mutable_data();
The contents should then exist in carray. I am not a pybind expert, but this solution was provided by pybind github forum

Swig: how to write wrapper code for Tcl to map member of enum type as string constants

I have read here that "C/C++ constants are installed as global Tcl variables containing the appropriate value", which applies to enum as well. I am trying to build a Tcl wrapper using swig for an enum class (called "Statement") that will result into the corresponding Tcl variables to be stored as string objects. The C++ code provides some ostream conversion facilities that I thought I could use to perform the conversion, but I cannot find a recipe that will work. I have tried the following:
//%typemap(argout) Statement *out {
// ostringstream oss;
// oss << $1;
// $result = Tcl_NewStringObj(oss.str()->c_str(), oss.str().size());
//}
//%typemap(constcode) Statement {
// ostringstream oss;
// oss << $1;
// $result = Tcl_NewStringObj(oss.str()->c_str(), oss.str().size());
//}
//%typemap(out) Statement {
// ostringstream oss;
// oss << $1;
// $result = Tcl_NewStringObj(oss.str()->c_str(), oss.str().size());
//}
Another (maybe related issue) is that no Tcl variables are created at all from the enums in my wrapper. I read from this follow up link that when you use static linking, the Tcl variables used to store constants will be put in the ::swig namespace. But this is not my problem here: I do not have a ::swig namespace, and info vars does not list any variables in the top namespace either.
I have found the answer for the second issue. My wrapper SWIG code uses the %init directive which uses some magic to make use of the readline library. It was evaluating a Tcl script that starts the readline command processing loop before the rest of the application initialization got a chance to complete. The constant initialization code was generated after the block of code provided to the %init SWIG block, so it never got executed. By moving the SWIG declaration of the enum above the %init section, the relative order of inserted constant initialization code and %init segment was changed, and the issue was solved.
Bottom-line: the relative order of declaration and %init segment in your SWIG wrapper code matters.
I was able to resolve this using a typemap of the form:
%typemap(out) enum NS::Statement {
ostringstream oss;
oss << "NS_Statement(" << $1 << ")";
Tcl_SetObjResult(interp,Tcl_NewStringObj(oss.str().c_str(), oss.str().size()));
}
The reason it was not working previously is that the enum is defined within a namespace statement. Even though I had 'using namespace NS;' statement before the typemap declaration, it was not being applied until I provided the full namespace qualifier of the enum. Also, both typemap statements had to be provided before the wrapper code declaring the enum constants.
As you can see, the variable name that is returned is a Tcl array variable name. In order for things to be consistent, the global variables set by the generated code that contain the actual values of the enum need also be changed. I was able to achieve that using another typemap like so:
%typemap(constcode,noblock=1) int {
%set_constant("NS_Statement($symname)", SWIG_From_long(static_cast< int >($1)));
}
In the case where you need to wrap multiple enum type, just insert a similar set of typemaps for each enum before its SWIG declaration, matching the Tcl array name part with the enum type being mapped. In case where there are non-enum constants to be declared in your SWIG code, or other enum types that you do not want to wrap in that way, add a last typemap(constcode) to reset to default behavior before you add the SWIG code declaring these other constants.
I have created a small example that illustrates that approach:
// file example.h
enum TOPETYPE {BI, DUL, BUC};
class MyClass {
public:
enum ETYPE {ONE,TWO, THREE};
static void Foo(ETYPE);
static ETYPE Bar(int);
};
namespace NS {
enum LIBENUM {LIB1, LIB2, LIB3};
}
extern const char * ETYPE2Str(MyClass::ETYPE);
extern const char * TOPETYPE2Str(TOPETYPE);
extern const char * LIBENUM2Str(NS::LIBENUM);
/* File : example.i */
%module example
%{
#include "example.h"
#include <sstream>
using namespace std;
%}
#define XX 0
%typemap(out) enum TOPETYPE {
#include <iostream>
std::ostringstream oss;
oss << "TOPETYPE(" << TOPETYPE2Str($1) << ")";
Tcl_SetObjResult(interp,Tcl_NewStringObj(oss.str().c_str(), -1));
}
%typemap(constcode,noblock=1) int {
%set_constant("TOPETYPE($symname)", SWIG_From_long(static_cast< int >($1)));
}
enum TOPETYPE {BI, DUL, BUC};
%typemap(out) enum MyClass::ETYPE {
#include <iostream>
std::ostringstream oss;
oss << "MyClass_ETYPE(MyClass_" << ETYPE2Str($1) << ")";
Tcl_SetObjResult(interp,Tcl_NewStringObj(oss.str().c_str(), -1));
}
%typemap(constcode,noblock=1) int {
%set_constant("MyClass_ETYPE($symname)", SWIG_From_long(static_cast< int >($1)));
}
class MyClass {
public:
enum ETYPE {ONE,TWO, THREE};
static void Foo(ETYPE);
static ETYPE Bar(int);
};
%typemap(out) enum NS::LIBENUM {
#include <iostream>
std::ostringstream oss;
oss << "NS_LIBENUM(" << LIBENUM2Str($1) << ")";
Tcl_SetObjResult(interp,Tcl_NewStringObj(oss.str().c_str(), -1));
}
%typemap(constcode,noblock=1) int {
%set_constant("NS_LIBENUM($symname)", SWIG_From_long(static_cast< int >($1)));
}
namespace NS {
enum LIBENUM {LIB1, LIB2, LIB3};
}
// file example.cpp
#include "example.h"
#include <iostream>
using namespace std;
void MyClass::Foo(MyClass::ETYPE typ)
{
cout << "Enum value = " << typ << endl;
}
MyClass::ETYPE MyClass::Bar(int val)
{
switch (static_cast<MyClass::ETYPE>(val)) {
case MyClass::ETYPE::ONE: {return MyClass::ETYPE::ONE;}
case MyClass::ETYPE::TWO: {return MyClass::ETYPE::TWO;}
case MyClass::ETYPE::THREE: {return MyClass::ETYPE::THREE;}
default: {return MyClass::ETYPE::THREE;}
}
}
const char * ETYPE2Str(MyClass::ETYPE val) {
switch (val) {
case MyClass::ETYPE::ONE: {return "ONE";}
case MyClass::ETYPE::TWO: {return "TWO";}
case MyClass::ETYPE::THREE: {return "THREE";}
default: {return "unknown";}
}
}
const char * TOPETYPE2Str(TOPETYPE val) {
switch (val) {
case TOPETYPE::BI: {return "BI";}
case TOPETYPE::DUL: {return "DUL";}
case TOPETYPE::BUC: {return "BUC";}
default: {return "unknown";}
}
}
const char * LIBENUM2Str(NS::LIBENUM val) {
switch (val) {
case NS::LIB1: {return "LIB1";}
case NS::LIB2: {return "LIB2";}
case NS::LIB3: {return "LIB3";}
default: {return "unknown";}
}
}
You can try this out with:
swig -c++ -tcl8 example.i
g++ -c -fpic example_wrap.cxx example.cpp -I/usr/local/include
g++ -shared example.o example_wrap.o -o example.so
And then, inside tclsh:
% load example4.so
% info vars
XX tcl_rcFileName tcl_version argv0 argv tcl_interactive auto_path errorCode NS_LIBENUM errorInfo auto_execs auto_index env tcl_pkgPath MyClass_ETYPE TOPETYPE tcl_patchLevel swig_runtime_data_type_pointer4 argc tcl_library tcl_platform
% info commands
MyClass_Bar tell socket subst open eof pwd glob list pid exec auto_load_index time unknown eval lassign lrange fblocked lsearch auto_import gets case lappend proc break variable llength auto_execok return linsert error catch clock info split array if fconfigure concat join lreplace source fcopy global switch auto_qualify update close cd for auto_load file append lreverse format unload read package set binary namespace scan delete_MyClass apply trace seek while chan flush after vwait dict continue uplevel foreach lset rename fileevent regexp new_MyClass lrepeat upvar encoding expr unset load regsub history interp exit MyClass puts incr lindex lsort tclLog MyClass_Foo string
% array names NS_LIBENUM
LIB1 LIB2 LIB3
% array names MyClass_ETYPE
MyClass_TWO MyClass_ONE MyClass_THREE
% array names TOPETYPE
DUL BUC BI
% puts $XX
0
% MyClass_Bar $MyClass_ETYPE(MyClass_ONE)
MyClass_ETYPE(MyClass_ONE)
% MyClass_Foo $MyClass_ETYPE(MyClass_ONE)
Enum value = 0
% exit

Does MSP430 GCC support newer C++ standards? (like 11, 14, 17)

I'm writing some code that would greatly benefit from the concise syntax of lambdas, which were introduced with C++ 11. Is this supported by the compiler?
How do I specify the compiler flags when compiling using Energia or embedXcode?
As of February 2018, up to C++14 is supported with some limitations:
http://processors.wiki.ti.com/index.php/C%2B%2B_Support_in_TI_Compilers
There isn't much about this topic on the TI site, or, at least, I don't know enough C++ to give you a detailed and precise response.
The implementation of the embedded ABI is described in this document that is mainly a derivation of the Itanium C++ ABI. It explains nothing about the implementation of lambdas nor the auto, keyword (or probably I'm not able to derive this information from the documentation).
Thus I decided to directly test in Energia. Apparently the g++ version is 4.6.3, thus it should support both.
And in fact (from a compilation point of view, I don't have my MSP here to test the code) it can compile something like:
// In template.hpp
#ifndef TEMPLATE_HPP_
#define TEMPLATE_HPP_
template<class T>
T func(T a) {
auto c = [&](int n) { return n + a; };
return c(0);
}
#endif /* TEMPLATE_HPP_ */
// in the sketch main
#include "template.hpp"
void setup() { int b = func<int>(0); }
void loop() { }
(the template works only if in an header, in the main sketch raises an error). To compile this sketch I had to modify one internal file of the editor. The maximum supported standard seems to be -std=c++0x, and the compilation flags are in the file:
$ENERGIA_ROOT/hardware/energia/msp430/platform.txt
in my setup the root is in /opt/energia. Inside that file I modified line 32 (compiler.cpp.flags) and added the option. Notice that -std=c++11 is not supported (raises an error).
compiler.cpp.flags=-std=c++0x -c -g -O2 {compiler.mlarge_flag} {compiler.warning_flags} -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD
Unfortunately I have zero experience with embedXcode :\
Mimic std::function
std::function is not provided, thus you have to write some sort of class that mimics it. Something like:
// callback.hpp
#ifndef CALLBACK_HPP_
#define CALLBACK_HPP_
template <class RET, class ARG>
class Callback {
RET (*_f)(ARG);
public:
Callback() : _f(0) { };
Callback(RET (*f)(ARG)) : _f(f) { };
bool is_set() const { return (_f) ? true : false; }
RET operator()(ARG a) const { return is_set() ? _f(a) : 0; }
};
#endif /* CALLBACK_HPP_ */
// sketch
#include "callback.hpp"
// | !! empty capture!
void setup() { // V
auto clb = Callback<int, char>([](char c) { return (int)c; });
if (clb.is_set())
auto b = clb('a');
}
void loop() {}
may do the work, and it uses a simple trick:
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. [C++11 standard 5.1.2]
As soon as you leave the capture empty, you are assured to have a "conversion" to a function pointer, thus you can store it without issues. The code I have written:
requires a first template RET that is the returned type
requires a second template ARG that is one argument for the callback. In the majority of the case you may consider to use void* as common argument (cast a struct pointer in a void pointer and use it as argument, to counter-cast in the function, the operation costs nothing)
implements two constructors: the empty constructor initialize the function pointer to NULL, while the second directly assigns the callback. Notice that the copy constructor is missing, you need to implement it.
implements a method to call the function (overloading the operator ()) and to check if the callback actually exists.
Again: this stuff compiles with no warnings, but I don't know if it works on the MSP430, since I cannot test it (it works on a common amd64 linux system).

Runtime error : Segmentation fault with libtommath and libtomcrypt

I am trying to run sample rsa/dsa code using libtomcrypt.
I have installed LibTomMath first as make install, as a result following files are created.
/usr/lib/libtommath.a
/usr/include/tommath.h
After that I installed libtomcrypt with LibTomMath as external library
CFLAGS="-DLTM_DESC -DUSE_LTM -I/usr/include" EXTRALIBS="/usr/lib/libtommath.a " make install
As a result following file is created
/usr/lib/libtomcrypt.a
I am not getting any error while running following command
CFLAGS="-DLTM_DESC -DUSE_LTM -I/usr/include" EXTRALIBS="/usr/lib/libtommath.a " make test
I have gone through this document libtomcrypt_installation and libtomcrypt_resolved to successfully compile using
gcc -DLTM_DESC rsa_make_key_example.c -o rsa -ltomcrypt
or
gcc rsa_make_key_example.c -o rsa -ltomcrypt
no compile error. However when I try to run, I got following error.
./rsa
LTC_ARGCHK 'ltc_mp.name != NULL' failure on line 34 of file src/pk/rsa/rsa_make_key.c
Aborted
Here is my sample rsa code
#include <tomcrypt.h>
#include <stdio.h>
int main(void) {
# ifdef USE_LTM
ltc_mp = ltm_desc;
# elif defined (USE_TFM)
ltc_mp = tfm_desc;
# endif
rsa_key key;
int err;
register_prng(&sprng_desc);
if ((err = rsa_make_key(NULL, find_prng("sprng"), 1024/8, 65537,&key)) != CRYPT_OK) {
printf("make_key error: %s\n", error_to_string(err));
return -1;
}
/* use the key ... */
return 0;
}
Here is my sample dsa code
#include <tomcrypt.h>
#include <stdio.h>
int main(void) {
# ifdef USE_LTM
ltc_mp = ltm_desc;
# elif defined (USE_TFM)
ltc_mp = tfm_desc;
# endif
int err;
register_prng(&sprng_desc);
dsa_key key;
if ((err = dsa_make_key(NULL, find_prng("sprng"), 20, 128,&key)) != CRYPT_OK) {
printf("make_key error: %s\n", error_to_string(err));
return -1;
}
/* use the key ... */
return 0;
}
Here is how I have compiled it successfully,
gcc dsa_make_key_example.c -o dsa -ltomcrypt
When I try to run the code , I am getting following error .
./dsa
segmentation fault
EDIT 1:
I investigated further and found the reason for segmentation fault
#ifdef LTC_MPI
#include <stdarg.h>
int ltc_init_multi(void **a, ...)
{
...
...
if (mp_init(cur) != CRYPT_OK) ---> This line causes segmentation fault
Where am I making mistakes ? How to resolve this problem to run these programs successfully?
I am using linux , gcc. Any help/link will be highly appreciated. Thanks in advance.
It's been a year or so since this was asked, but I have some component of an answer, and a workaround.
The reason mp_init fails is that the "math_descriptor" is uninitialized. mp_init is a defined as
#define mp_init(a) ltc_mp.init(a)
where ltc_mp is a global struct (of type ltc_math_descriptor) that holds pointers to the math routines.
There are several implementations of the math routines available, and a user can choose which they want. For whatever reason, there does not seem to be a default math implementation chosen for certain builds of libtomcrypt. Thus, the init member of ltc_mp is null, and we get the SIGSEGV.
Here is a manual workaround:
You can make your desired ltc_math_descriptor struct available to your main() routine by #defineing one of
LTM_DESC -- built-in math lib
TFM_DESC -- an external fast math package
GMP_DESC -- presumably a GNU MultiPrecision implementation?
Before #include <tomcrypt.h> (or by using -D on the command-line).
Whichever you choose, a corresponding object will be declared:
extern const ltc_math_descriptor ltm_desc;
extern const ltc_math_descriptor tfm_desc;
extern const ltc_math_descriptor gmp_desc;
To use it, manually copy it to the global math descriptor:
E.g., in my case, for the local math imlpementation,
ltc_mp = ltm_desc;
Now libtomcrypt works.

Resources