mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
With Boost 1.64 to 1.65 (which, of course, Ubuntu LTS ships), the `PyInit_Libraryname` are invisible when one sets the default visibility to "hidden" (which is reasonable, and which we do).
202 lines
5.7 KiB
C++
202 lines
5.7 KiB
C++
//
|
|
// Copyright 2017-2018 Ettus Research, a National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
//
|
|
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <boost/python.hpp>
|
|
#include <boost/python/stl_iterator.hpp>
|
|
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
|
|
|
|
/*
|
|
This solution was adapted from an Issue posted to the Boost.Python Github.
|
|
https://github.com/boostorg/python/pull/159/files
|
|
*/
|
|
#if (BOOST_VERSION >= 106400) && (BOOST_VERSION < 106600)
|
|
#warning overriding broken boost python implementation of BOOST_PYTHON_MODULE_INIT
|
|
# define BOOST_PYTHON_MODULE_INIT(name) \
|
|
void BOOST_PP_CAT(init_module_,name)(); \
|
|
extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name)
|
|
#endif
|
|
|
|
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
|
#include <numpy/arrayobject.h>
|
|
|
|
namespace bp = boost::python;
|
|
|
|
#include "stream_python.hpp"
|
|
|
|
#include "types/types_python.hpp"
|
|
#include "types/serial_python.hpp"
|
|
#include "types/time_spec_python.hpp"
|
|
#include "types/metadata_python.hpp"
|
|
#include "types/sensors_python.hpp"
|
|
#include "types/filters_python.hpp"
|
|
#include "types/tune_python.hpp"
|
|
|
|
#include "usrp/fe_connection_python.hpp"
|
|
#include "usrp/dboard_iface_python.hpp"
|
|
#include "usrp/subdev_spec_python.hpp"
|
|
#include "usrp/multi_usrp_python.hpp"
|
|
|
|
// Converter for std::vector / std::list arguments from python iterables
|
|
struct iterable_converter
|
|
{
|
|
template <typename Container>
|
|
iterable_converter& from_python()
|
|
{
|
|
bp::converter::registry::push_back(
|
|
&iterable_converter::convertible,
|
|
&iterable_converter::construct<Container>,
|
|
bp::type_id<Container>()
|
|
);
|
|
return *this;
|
|
}
|
|
|
|
static void* convertible(PyObject* object)
|
|
{
|
|
return PyObject_GetIter(object) ? object : NULL;
|
|
}
|
|
|
|
template <typename Container>
|
|
static void construct(
|
|
PyObject* object,
|
|
bp::converter::rvalue_from_python_stage1_data* data)
|
|
{
|
|
// Object is a borrowed reference, so create a handle indicting it is
|
|
// borrowed for proper reference counting.
|
|
bp::handle<> handle(bp::borrowed(object));
|
|
|
|
// Obtain a handle to the memory block that the converter has
|
|
// allocated for the C++ type.
|
|
typedef bp::converter::rvalue_from_python_storage<Container> storage_type;
|
|
|
|
void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
|
|
typedef bp::stl_input_iterator<typename Container::value_type> iterator;
|
|
|
|
// Allocate the C++ type into the converter's memory block, and assign
|
|
// its handle to the converter's convertible variable. The C++
|
|
// container is populated by passing the begin and end iterators of
|
|
// the python object to the container's constructor.
|
|
new (storage) Container(
|
|
iterator(bp::object(handle)), // begin
|
|
iterator() // end
|
|
);
|
|
|
|
data->convertible = storage;
|
|
}
|
|
};
|
|
|
|
template<typename Dtype1, typename Dtype2>
|
|
struct uhd_to_python_dict
|
|
{
|
|
static PyObject* convert(uhd::dict<Dtype1, Dtype2> const& input_dict)
|
|
{
|
|
bp::dict py_dict;
|
|
for (const auto& key: input_dict.keys()){
|
|
py_dict[key] = input_dict[key];
|
|
}
|
|
return bp::incref(py_dict.ptr());
|
|
}
|
|
|
|
};
|
|
|
|
template<typename Container>
|
|
struct iterable_to_python_list
|
|
{
|
|
static PyObject* convert(Container const& input)
|
|
{
|
|
bp::list py_list;
|
|
for (const auto& element: input){
|
|
py_list.append(element);
|
|
}
|
|
return bp::incref(py_list.ptr());
|
|
}
|
|
};
|
|
|
|
// We need this hack because import_array() returns NULL
|
|
// for newer Python versions.
|
|
// This function is also necessary because it ensures access to the C API
|
|
// and removes a warning.
|
|
#if PY_MAJOR_VERSION >= 3
|
|
void* init_numpy()
|
|
{
|
|
import_array();
|
|
return NULL;
|
|
}
|
|
#else
|
|
void init_numpy()
|
|
{
|
|
import_array();
|
|
}
|
|
#endif
|
|
|
|
BOOST_PYTHON_MODULE(libpyuhd)
|
|
{
|
|
// Initialize the numpy C API
|
|
// (otherwise we will see segmentation faults)
|
|
init_numpy();
|
|
|
|
bp::object package = bp::scope();
|
|
package.attr("__path__") = "libpyuhd";
|
|
|
|
// Declare converters
|
|
iterable_converter()
|
|
.from_python<std::vector<double> >()
|
|
.from_python<std::vector<int> >()
|
|
.from_python<std::vector<size_t> >()
|
|
;
|
|
|
|
bp::to_python_converter<
|
|
uhd::dict<std::string, std::string>,
|
|
uhd_to_python_dict<std::string, std::string>, false >();
|
|
bp::to_python_converter<
|
|
std::vector<std::string>,
|
|
iterable_to_python_list<std::vector<std::string> >, false >();
|
|
|
|
// Register types submodule
|
|
{
|
|
bp::object types_module(
|
|
bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.types")))
|
|
);
|
|
bp::scope().attr("types") = types_module;
|
|
bp::scope io_scope = types_module;
|
|
|
|
bp::implicitly_convertible<std::string, uhd::device_addr_t>();
|
|
|
|
export_types();
|
|
export_time_spec();
|
|
export_spi_config();
|
|
export_metadata();
|
|
export_sensors();
|
|
export_tune();
|
|
}
|
|
|
|
// Register usrp submodule
|
|
{
|
|
bp::object usrp_module(
|
|
bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.usrp")))
|
|
);
|
|
bp::scope().attr("usrp") = usrp_module;
|
|
bp::scope io_scope = usrp_module;
|
|
|
|
export_multi_usrp();
|
|
export_subdev_spec();
|
|
export_dboard_iface();
|
|
export_fe_connection();
|
|
export_stream();
|
|
}
|
|
|
|
// Register filters submodule
|
|
{
|
|
bp::object filters_module(
|
|
bp::handle<>(bp::borrowed(PyImport_AddModule("libpyuhd.filters")))
|
|
);
|
|
bp::scope().attr("filters") = filters_module;
|
|
bp::scope io_scope = filters_module;
|
|
|
|
export_filters();
|
|
}
|
|
}
|
|
|