I'm trying to get started using debug helpers in QtCreator.
But I can't even get anything simple to work.
I made this simple python file:
from dumper import *
def qdump_TestClass(d, value):
d.putNumChild(0)
d.putValue("hi")
Then add that file in here:
This is the C++ definition of the class:
struct TestClass {
int x, y;
};
I have been following the steps in this other question. But that didn't work for me.
Use double underscores in function name:
def qdump__TestClass(d, value):
^^
And, correct your path according to the documentation:
~/<Qt>/Tools/QtCreator/share/qtcreator/debugger/personaltypes.py
Use your Qt folder name (or path if it's not at ~).
The path showing in that dialog box is relative to your app.
Here's a complete working example:
main.cpp
struct TestClass
{
int x {12}, y {34};
};
int main()
{
TestClass t;
(void) t;
return 0;
}
personaltypes.py
from dumper import *
def qdump__TestClass(d, value):
d.putValue("TestClass")
d.putNumChild(2)
if d.isExpanded():
with Children(d):
d.putSubItem("x", value["x"])
d.putSubItem("y", value["y"])
Screenshot:
Related
I am trying to call a python function from a C++ code which contains main() function using Pybind11. But I found very few references are available. Most of existing documents talk about the reversed direction, i.e. calling C++ from Python.
Is there any complete example showing how to do that? The only reference I found is: https://github.com/pybind/pybind11/issues/30
But it has very little information.
The answer to your question really has two parts: one about calling a Python function from C++, the other about embedding the interpreter.
Calling a function in pybind11 is simply a matter of getting that function into a pybind11::object variable, on which you can invoke operator() to attempt to call the object. (It doesn't have to be a function, but just something callable: for example, it could also be an object with a __call__ method). For example, to call math.sqrt(2) from C++ code you'd use:
auto math = py::module::import("math");
auto resultobj = math.attr("sqrt")(2);
double result = resultobj.cast<double>();
or you could condense it all to just:
double result = py::module::import("math").attr("sqrt")(2).cast<double>();
The second part of the question involves how to do this from a C++ executable. When building an executable (i.e. when your C++ code contains main()) you have to embed the Python interpreter in your binary before you can do anything with Python (like calling a Python function).
Embedded support is a new feature added in the current pybind11 master branch (which will become the 2.2 release). Here's a basic example that starts an embedded Python interpreter and calls a Python function (math.sqrt):
#include <pybind11/embed.h>
#include <iostream>
namespace py = pybind11;
int main() {
py::scoped_interpreter python;
auto math = py::module::import("math");
double root_two = math.attr("sqrt")(2.0).cast<double>();
std::cout << "The square root of 2 is: " << root_two << "\n";
}
Outputs:
The square root of 2 is: 1.41421
More examples and documentation of calling functions and embedding are available at http://pybind11.readthedocs.io/en/master/advanced/pycpp/object.html and http://pybind11.readthedocs.io/en/master/advanced/embedding.html, respectively.
Jasons answer is pretty much on point, but I want to add a slightly more complex (and clean) example calling a python method with a numpy input.
I want to showcase two points:
We can cast a py::object to a py::function using py::reinterpret_borrow<py::function>
We can input a std::vector that automatically gets converted to a numpy.array
Note that the user is responsible for making sure that the PyModule.attr is actually a python function. Also note that the type conversion works for a wide variety of c++ types (see here for details).
In this example I want to use the method scipy.optimize.minimize with a starting point x0 that is provided from the c++ interface.
#include <iostream>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h> // python interpreter
#include <pybind11/stl.h> // type conversion
namespace py = pybind11;
int main() {
std::cout << "Starting pybind" << std::endl;
py::scoped_interpreter guard{}; // start interpreter, dies when out of scope
py::function min_rosen =
py::reinterpret_borrow<py::function>( // cast from 'object' to 'function - use `borrow` (copy) or `steal` (move)
py::module::import("py_src.exec_numpy").attr("min_rosen") // import method "min_rosen" from python "module"
);
py::object result = min_rosen(std::vector<double>{1,2,3,4,5}); // automatic conversion from `std::vector` to `numpy.array`, imported in `pybind11/stl.h`
bool success = result.attr("success").cast<bool>();
int num_iters = result.attr("nit").cast<int>();
double obj_value = result.attr("fun").cast<double>();
}
with the python script py_src/exec_numpy.py
import numpy as np
from scipy.optimize import minimize, rosen, rosen_der
def min_rosen(x0):
res = minimize(rosen, x0)
return res
Hope this helps someone!
project structure
CMakeLists.txt
calc.py
main.cpp
main.cpp
#include <pybind11/embed.h>
#include <iostream>
namespace py = pybind11;
using namespace py::literals;
int main() {
py::scoped_interpreter guard{};
// append source dir to sys.path, and python interpreter would find your custom python file
py::module_ sys = py::module_::import("sys");
py::list path = sys.attr("path");
path.attr("append")("..");
// import custom python class and call it
py::module_ tokenize = py::module_::import("calc");
py::type customTokenizerClass = tokenize.attr("CustomTokenizer");
py::object customTokenizer = customTokenizerClass("/Users/Caleb/Desktop/codes/ptms/bert-base");
py::object res = customTokenizer.attr("custom_tokenize")("good luck");
// show the result
py::list input_ids = res.attr("input_ids");
py::list token_type_ids = res.attr("token_type_ids");
py::list attention_mask = res.attr("attention_mask");
py::list offsets = res.attr("offset_mapping");
std::string message = "input ids is {},\noffsets is {}"_s.format(input_ids, offsets);
std::cout << message << std::endl;
}
calc.py
from transformers import BertTokenizerFast
class CustomTokenizer(object):
def __init__(self, vocab_dir):
self._tokenizer = BertTokenizerFast.from_pretrained(vocab_dir)
def custom_tokenize(self, text):
return self._tokenizer(text, return_offsets_mapping=True)
def build_tokenizer(vocab_dir: str) -> BertTokenizerFast:
tokenizer = BertTokenizerFast.from_pretrained(vocab_dir)
return tokenizer
def tokenize_text(tokenizer: BertTokenizerFast, text: str) -> dict:
res = tokenizer(text, return_offsets_mapping=True)
return dict(res)
CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
project(example)
set(CMAKE_CXX_STANDARD 11)
# set pybind11 dir
set(pybind11_DIR /Users/Caleb/Softwares/pybind11)
find_package(pybind11 REQUIRED)
# set custom python interpreter(under macos)
link_libraries(/Users/Caleb/miniforge3/envs/py38/lib/libpython3.8.dylib)
add_executable(example main.cpp)
target_link_libraries(example PRIVATE pybind11::embed)
I am no stranger to the python ctypes module, but this is my first attempt at combining C++, C and Python all in one code. My problem seems to be very similar to Seg fault when using ctypes with Python and C++, however I could not seem to solve the problem in the same way.
I have a simple C++ file called Header.cpp:
#include <iostream>
class Foo{
public:
int nbits;
Foo(int nb){nbits = nb;}
void bar(){ std::cout << nbits << std::endl; }
};
extern "C" {
Foo *Foo_new(int nbits){ return new Foo(nbits); }
void Foo_bar(Foo *foo){ foo->bar(); }
}
which I compile to a shared library using:
g++ -c Header.cpp -fPIC -o Header.o
g++ -shared -fPIC -o libHeader.so Header.o
and a simple Python wrapper called test.py:
import ctypes as C
lib = C.CDLL('./libHeader.so')
class Foo(object):
def __init__(self,nbits):
self.nbits = C.c_int(nbits)
self.obj = lib.Foo_new(self.nbits)
def bar(self):
lib.Foo_bar(self.obj)
def main():
f = Foo(32)
f.bar()
if __name__ == "__main__":
main()
I would expect that when I call test.py, I should get the number 32 printed to screen. However, all I get is a segmentation fault. If I change the constructor to return the class instance on the stack (i.e. without the new call) and then pass around the object, the program performs as expected. Also, if I change the bar method in the Foo class such that it does not use the nbits member, the program does not seg fault.
I have an limited understanding of C++, but the fact that I can make this function as expected in C and in C++ but not in Python is a little confusing. Any help would be greatly appreciated.
Update: Thanks to one of the comments below, the problem has been solved. In this case, an explicit declaration of both restype and argtypes for the C functions was required. i.e the following was added to the python code:
lib.Foo_new.restype = C.c_void_p
lib.Foo_new.argtypes = [C.c_int32]
lib.Foo_bar.restype = None
lib.Foo_bar.argtypes = [C.c_void_p]
I would try the following:
extern "C"
{
Foo *Foo_new(int nbits)
{
Foo *foo = new Foo(nbits);
printf("Foo_new(%d) => foo=%p\n", nbits, foo);
return foo;
}
void Foo_bar(Foo *foo)
{
printf("Foo_bar => foo=%p\n", foo);
foo->bar();
}
}
to see if the values of foo match.
Also, you might want to look at Boost.Python to simplify creating Python bindings of C++ objects.
I'm newbie working with a logging system, but it's something very useful to add to your programs.
Summarizing my problem. I use the logging library log4cplus
I doing and easy example with two simple classes and the main program.
That's my error log:
log4cplus:ERROR No appenders could be found for logger (main).
log4cplus:ERROR Please initialize the log4cplus system properly.
Segmentation fault: 11
The problem is i don't know how to solve the problem with the appender.
That's basic code of my example.
Class1.h
#include <iostream>
#include <log4cplus/configurator.h>
#include <log4cplus/logger.h>
using namespace std;
// Use the log4cplus namespace
using namespace log4cplus;
class one
{
private:
// Create the logger
Logger logger;
public:
bool flag;
int valor;
one();
int multiplica(int a);
};
Class1.cpp
one::one()
{
logger.getInstance(LOG4CPLUS_TEXT("Clase One - constructor."));
}
int one::multiplica(int a)
{
int sol = 0;
sol = valor * a;
// Imprimo un mesaje en el log.
LOG4CPLUS_INFO(logger, "El resultado de la multiplicación es: xx");
return sol;
}
Class2.h
#include <iostream>
#include <log4cplus/configurator.h>
#include <log4cplus/logger.h>
using namespace std;
// Use the log4cplus namespace
using namespace log4cplus;
class two
{
private:
// Create the logger
Logger logger;
public:
bool flag;
int valor;
two();
int suma(int a);
};
Class.cpp
two::two()
{
logger.getInstance(LOG4CPLUS_TEXT("Clase Two - DEconstructor."));
}
int two::suma(int a)
{
int sol = 0;
sol = valor + a;
// Imprimo un mesaje en el log.
LOG4CPLUS_INFO(logger, "El resultado de la suma es: YY ");
return sol;
}
main.cpp
int main(int argc, char** argv)
{
// Load the properties
PropertyConfigurator::doConfigure("logClase.properties");
Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main"));
// Log with INFO level
if (logger.isEnabledFor(INFO_LOG_LEVEL))
{
LOG4CPLUS_INFO(logger, "Application startup");
}
one uno;
two dos;
uno.valor = dos.valor = 4;
uno.multiplica(7);
dos.suma(7);
// Log with INFO level
if (logger.isEnabledFor(INFO_LOG_LEVEL))
{
LOG4CPLUS_INFO(logger, "Application shutdown");
}
return 0;
}
What i'm doing wrong ???
That's the correct way to work with the logging system ??
I use a simple properties file to save all the log messages in a file.
That's my logClase.properties file to configure de logger.
log4cplus.rootLogger=INFO, STDOUT, FILEAPPENDER
log4cplus.logger.main=INFO
log4cplus.logger.utils=FILEAPPENDER
log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
log4cplus.appender.STDOUT.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n
log4cplus.appender.FILEAPPENDER=log4cplus::RollingFileAppender
log4cplus.appender.FILEAPPENDER.File=KlasseEx.log
log4cplus.appender.FILEAPPENDER.MaxFileSize=5MB
#log4cplus.appender.FILEAPPENDER.MaxFileSize=500KB
log4cplus.appender.FILEAPPENDER.MaxBackupIndex=1
log4cplus.appender.FILEAPPENDER.layout=log4cplus::PatternLayout
log4cplus.appender.FILEAPPENDER.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n
I want to use FILEAPPENDER and the Console appender to throw messages in a file and into the console. I think that's not must be so difficult to do, it must be easy to do it.
See for appenders in log4cplus documentation. You probably missing some step of intialitation of this logger - I mean you did not add appenders.
See http://www.codeproject.com/Articles/15955/logging-made-easy-in-your-c-applications
After:
Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main"));
Missing:
SharedAppenderPtr consoleAppender(new ConsoleAppender());
consoleAppender->setName("myAppenderName");
consoleAppender->setLayout(new log4cplus::TTCCLayout());
logger.addAppender(consoleAppender);
PiotrNycz mentioned that you indeed needed to do more initialization steps for your log4cplus logging, particularly adding appenders. I want to elaborate more on that.
Documentation states that prior to version 2.0 initialization is to be done with:
log4cplus::initialize();
and deinitialization, by calling shutdown() on the Logger like so:
log4cplus::Logger::getRoot().shutdown();
, while after version 2.0, initialization is supposed to occur with instantiating the RAII class log4cplus::Initializer initializer; and deinitialization when that instance is destructed.
However I have version 2.0.0 and the prior method is what actually has worked for me. With the 2nd method I was getting the exact same error you did.
Then a minimal implementation of logging for a class could be like so:
const wchar_t* PATTERN = LOG_PATTERN; // optional - create an initial log status message
log4cplus::SharedAppenderPtr consoleApp(new log4cplus::ConsoleAppender()); // for console output
consoleApp->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::PatternLayout(PATTERN))); // again optional
log4cplus::Logger m_logger = log4cplus::Logger::getRoot(); // get root logger
m_logger.setLogLevel(log4cplus::ALL_LOG_LEVEL); // set root logger log level
// finally add appenders
this->m_logger.addAppender(consoleApp); // at least one appender must be set in order for you to be able to actually log to the console or file or to an output device (multiple appender types exist).
Now, a custom MyLogger class should minimally contain a log4cplus::Logger, logging functions - like the following logError - and the initialization steps mentioned above done in its constructor. Also, it needs a member function GetLogger defined as such: log4cplus::Logger* GetLogger(const char* logger = DEFAULT_LOGGER); to acquire a MyLogger instance and use it as a member of a class for which you want to provide the logging facilities.
To log a specific message you also need a function like this in MyLogger:
template<typename... Args>
inline void logError(const char* stringOptionallyFormatted, Args&&... args)
{
LOG4CPLUS_ERROR_FMT(m_logger, fmt, std::forward<Args>(args)...);
}
(Likewise for other log levels.)
Now instantiate a logger instance in some class's constructor (or in main):
MyLogger myLoggerInstance;
myLoggerInstance.GetLogger(L"File System Logger");
and log with:
myLoggerInstance.logError|Info|Debug("like today is %s No%d", "Sunday", 7 );
or:
logger.logDebug(L"no formatted string");
Additional notes:
I have found documenetation for log4cplus to be relatively poor. This (which is for log4j! - the java original) tutorial is the best one I have found. It explains the basics very well. Then the page I linked above as well.
Make sure you call log4cplus::initialize() first thing in main to prevent SIOF.
Typically you want one Logger member object per class you're interested in.
If you're working on a multithreaded application call log4cplus::threadCleanup(); as an additional de-initialization step after calling shutdown.
Only a trivial hello world app link wouldn't need an appender.
I have a class interface written in C++. I have a few classes that implement this interface also written in C++. These are called in the context of a larger C++ program, which essentially implements "main". I want to be able to write implementations of this interface in Python, and allow them to be used in the context of the larger C++ program, as if they had been just written in C++.
There's been a lot written about interfacing python and C++ but I cannot quite figure out how to do what I want. The closest I can find is here: http://www.cs.brown.edu/~jwicks/boost/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions, but this isn't quite right.
To be more concrete, suppose I have an existing C++ interface defined something like:
// myif.h
class myif {
public:
virtual float myfunc(float a);
};
What I want to be able to do is something like:
// mycl.py
... some magic python stuff ...
class MyCl(myif):
def myfunc(a):
return a*2
Then, back in my C++ code, I want to be able to say something like:
// mymain.cc
void main(...) {
... some magic c++ stuff ...
myif c = MyCl(); // get the python class
cout << c.myfunc(5) << endl; // should print 10
}
I hope this is sufficiently clear ;)
There's two parts to this answer. First you need to expose your interface in Python in a way which allows Python implementations to override parts of it at will. Then you need to show your C++ program (in main how to call Python.
Exposing the existing interface to Python:
The first part is pretty easy to do with SWIG. I modified your example scenario slightly to fix a few issues and added an extra function for testing:
// myif.h
class myif {
public:
virtual float myfunc(float a) = 0;
};
inline void runCode(myif *inst) {
std::cout << inst->myfunc(5) << std::endl;
}
For now I'll look at the problem without embedding Python in your application, i.e. you start excetion in Python, not in int main() in C++. It's fairly straightforward to add that later though.
First up is getting cross-language polymorphism working:
%module(directors="1") module
// We need to include myif.h in the SWIG generated C++ file
%{
#include <iostream>
#include "myif.h"
%}
// Enable cross-language polymorphism in the SWIG wrapper.
// It's pretty slow so not enable by default
%feature("director") myif;
// Tell swig to wrap everything in myif.h
%include "myif.h"
To do that we've enabled SWIG's director feature globally and specifically for our interface. The rest of it is pretty standard SWIG though.
I wrote a test Python implementation:
import module
class MyCl(module.myif):
def __init__(self):
module.myif.__init__(self)
def myfunc(self,a):
return a*2.0
cl = MyCl()
print cl.myfunc(100.0)
module.runCode(cl)
With that I was then able to compile and run this:
swig -python -c++ -Wall myif.i
g++ -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
python mycl.py
200.0
10
Exactly what you'd hope to see from that test.
Embedding the Python in the application:
Next up we need to implement a real version of your mymain.cc. I've put together a sketch of what it might look like:
#include <iostream>
#include "myif.h"
#include <Python.h>
int main()
{
Py_Initialize();
const double input = 5.0;
PyObject *main = PyImport_AddModule("__main__");
PyObject *dict = PyModule_GetDict(main);
PySys_SetPath(".");
PyObject *module = PyImport_Import(PyString_FromString("mycl"));
PyModule_AddObject(main, "mycl", module);
PyObject *instance = PyRun_String("mycl.MyCl()", Py_eval_input, dict, dict);
PyObject *result = PyObject_CallMethod(instance, "myfunc", (char *)"(O)" ,PyFloat_FromDouble(input));
PyObject *error = PyErr_Occurred();
if (error) {
std::cerr << "Error occured in PyRun_String" << std::endl;
PyErr_Print();
}
double ret = PyFloat_AsDouble(result);
std::cout << ret << std::endl;
Py_Finalize();
return 0;
}
It's basically just standard embedding Python in another application. It works and gives exactly what you'd hope to see also:
g++ -Wall -Wextra -I/usr/include/python2.7 main.cc -o main -lpython2.7
./main
200.0
10
10
The final piece of the puzzle is being able to convert the PyObject* that you get from creating the instance in Python into a myif *. SWIG again makes this reasonably straightforward.
First we need to ask SWIG to expose its runtime in a headerfile for us. We do this with an extra call to SWIG:
swig -Wall -c++ -python -external-runtime runtime.h
Next we need to re-compile our SWIG module, explicitly giving the table of types SWIG knows about a name so we can look it up from within our main.cc. We recompile the .so using:
g++ -DSWIG_TYPE_TABLE=myif -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
Then we add a helper function for converting the PyObject* to myif* in our main.cc:
#include "runtime.h"
// runtime.h was generated by SWIG for us with the second call we made
myif *python2interface(PyObject *obj) {
void *argp1 = 0;
swig_type_info * pTypeInfo = SWIG_TypeQuery("myif *");
const int res = SWIG_ConvertPtr(obj, &argp1,pTypeInfo, 0);
if (!SWIG_IsOK(res)) {
abort();
}
return reinterpret_cast<myif*>(argp1);
}
Now this is in place we can use it from within main():
int main()
{
Py_Initialize();
const double input = 5.5;
PySys_SetPath(".");
PyObject *module = PyImport_ImportModule("mycl");
PyObject *cls = PyObject_GetAttrString(module, "MyCl");
PyObject *instance = PyObject_CallFunctionObjArgs(cls, NULL);
myif *inst = python2interface(instance);
std::cout << inst->myfunc(input) << std::endl;
Py_XDECREF(instance);
Py_XDECREF(cls);
Py_Finalize();
return 0;
}
Finally we have to compile main.cc with -DSWIG_TYPE_TABLE=myif and this gives:
./main
11
Minimal example; note that it is complicated by the fact that Base is not pure virtual. There we go:
baz.cpp:
#include<string>
#include<boost/python.hpp>
using std::string;
namespace py=boost::python;
struct Base{
virtual string foo() const { return "Base.foo"; }
// fooBase is non-virtual, calling it from anywhere (c++ or python)
// will go through c++ dispatch
string fooBase() const { return foo(); }
};
struct BaseWrapper: Base, py::wrapper<Base>{
string foo() const{
// if Base were abstract (non-instantiable in python), then
// there would be only this->get_override("foo")() here
//
// if called on a class which overrides foo in python
if(this->get_override("foo")) return this->get_override("foo")();
// no override in python; happens if Base(Wrapper) is instantiated directly
else return Base::foo();
}
};
BOOST_PYTHON_MODULE(baz){
py::class_<BaseWrapper,boost::noncopyable>("Base")
.def("foo",&Base::foo)
.def("fooBase",&Base::fooBase)
;
}
bar.py
import sys
sys.path.append('.')
import baz
class PyDerived(baz.Base):
def foo(self): return 'PyDerived.foo'
base=baz.Base()
der=PyDerived()
print base.foo(), base.fooBase()
print der.foo(), der.fooBase()
Makefile
default:
g++ -shared -fPIC -o baz.so baz.cpp -lboost_python `pkg-config python --cflags`
And the result is:
Base.foo Base.foo
PyDerived.foo PyDerived.foo
where you can see how fooBase() (the non-virtual c++ function) calls virtual foo(), which resolves to the override regardless whether in c++ or python. You could derive a class from Base in c++ and it would work just the same.
EDIT (extracting c++ object):
PyObject* obj; // given
py::object pyObj(obj); // wrap as boost::python object (cheap)
py::extract<Base> ex(pyObj);
if(ex.check()){ // types are compatible
Base& b=ex(); // get the wrapped object
// ...
} else {
// error
}
// shorter, thrwos when conversion not possible
Base &b=py::extract<Base>(py::object(obj))();
Construct py::object from PyObject* and use py::extract to query whether the python object matches what you are trying to extract: PyObject* obj; py::extract<Base> extractor(py::object(obj)); if(!extractor.check()) /* error */; Base& b=extractor();
Quoting http://wiki.python.org/moin/boost.python/Inheritance
"Boost.Python also allows us to represent C++ inheritance relationships so that wrapped derived classes may be passed where values, pointers, or references to a base class are expected as arguments."
There are examples of virtual functions so that solves the first part (the one with class MyCl(myif))
For specific examples doing this, http://wiki.python.org/moin/boost.python/OverridableVirtualFunctions
For the line myif c = MyCl(); you need to expose your python (module) to C++. There are examples here http://wiki.python.org/moin/boost.python/EmbeddingPython
Based upon the (very helpful) answer by Eudoxos I've taken his code and extended it such that there is now an embedded interpreter, with a built-in module.
This answer is the Boost.Python equivalent of my SWIG based answer.
The headerfile myif.h:
class myif {
public:
virtual float myfunc(float a) const { return 0; }
virtual ~myif() {}
};
Is basically as in the question, but with a default implementation of myfunc and a virtual destructor.
For the Python implementation, MyCl.py I have basically the same as the question:
import myif
class MyCl(myif.myif):
def myfunc(self,a):
return a*2.0
This then leaves mymain.cc, most of which is based upon the answer from Eudoxos:
#include <boost/python.hpp>
#include <iostream>
#include "myif.h"
using namespace boost::python;
// This is basically Eudoxos's answer:
struct MyIfWrapper: myif, wrapper<myif>{
float myfunc(float a) const {
if(this->get_override("myfunc"))
return this->get_override("myfunc")(a);
else
return myif::myfunc(a);
}
};
BOOST_PYTHON_MODULE(myif){
class_<MyIfWrapper,boost::noncopyable>("myif")
.def("myfunc",&myif::myfunc)
;
}
// End answer by Eudoxos
int main( int argc, char ** argv ) {
try {
// Tell python that "myif" is a built-in module
PyImport_AppendInittab("myif", initmyif);
// Set up embedded Python interpreter:
Py_Initialize();
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
PySys_SetPath(".");
main_namespace["mycl"] = import("mycl");
// Create the Python object with an eval()
object obj = eval("mycl.MyCl()", main_namespace);
// Find the base C++ type for the Python object (from Eudoxos)
const myif &b=extract<myif>(obj)();
std::cout << b.myfunc(5) << std::endl;
} catch( error_already_set ) {
PyErr_Print();
}
}
The key part that I've added here, above and beyond the "how do I embed Python using Boost.Python?" and "how do I extend Python using Boost.python?" (which was answered by Eudoxos) is the answer to the question "How do I do both at once in the same program?". The solution to this lies with the PyImport_AppendInittab call, which takes the initialisation function that would normally be called when the module is loaded and registers it as a built-in module. Thus when mycl.py says import myif it ends up importing the built-in Boost.Python module.
Take a look at Boost Python, that is the most versatile and powerful tool to bridge between C++ and Python.
http://www.boost.org/doc/libs/1_48_0/libs/python/doc/
There's no real way to interface C++ code directly with Python.
SWIG does handle this, but it builds its own wrapper.
One alternative I prefer over SWIG is ctypes, but to use this you need to create a C wrapper.
For the example:
// myif.h
class myif {
public:
virtual float myfunc(float a);
};
Build a C wrapper like so:
extern "C" __declspec(dllexport) float myif_myfunc(myif* m, float a) {
return m->myfunc(a);
}
Since you are building using C++, the extern "C" allows for C linkage so you can call it easily from your dll, and __declspec(dllexport) allows the function to be called from the dll.
In Python:
from ctypes import *
from os.path import dirname
dlldir = dirname(__file__) # this strips it to the directory only
dlldir.replace( '\\', '\\\\' ) # Replaces \ with \\ in dlldir
lib = cdll.LoadLibrary(dlldir+'\\myif.dll') # Loads from the full path to your module.
# Just an alias for the void pointer for your class
c_myif = c_void_p
# This tells Python how to interpret the return type and arguments
lib.myif_myfunc.argtypes = [ c_myif, c_float ]
lib.myif_myfunc.restype = c_float
class MyCl(myif):
def __init__:
# Assume you wrapped a constructor for myif in C
self.obj = lib.myif_newmyif(None)
def myfunc(a):
return lib.myif_myfunc(self.obj, a)
While SWIG does all this for you, there's little room for you to modify things as you please without getting frustrated at all the changes you have to redo when you regenerate the SWIG wrapper.
One issue with ctypes is that it doesn't handle STL structures, since it's made for C. SWIG does handle this for you, but you may be able to wrap it yourself in the C. It's up to you.
Here's the Python doc for ctypes:
http://docs.python.org/library/ctypes.html
Also, the built dll should be in the same folder as your Python interface (why wouldn't it be?).
I am curious though, why would you want to call Python from inside C++ instead of calling the C++ implementation directly?
I'm going through exercises of a C++ book. For each exercise I want to minimize the boilerplate code I have to write. I've set up my project a certain way but it doesn't seem right, and requires too many changes.
Right now I have a single main.cpp file with the following:
#include "e0614.h"
int main()
{
E0614 ex;
ex.solve();
}
Each time I create a new class from an exercise, I have to come and modify this file to change the name of the included header as well as the class i'm instantiating.
So my questions are:
Can I include all headers in the directory so at least I don't have to change the #include line?
Better yet, can I rewrite my solution so that I don't even have to touch main.cpp, without having one file with all the code for every exercise in it?
Update:
I ended up following Poita_'s advice to generate main.cpp via a script.
Since I'm using an IDE (Visual Studio), I wanted this integrated with it, so did a bit of research on how. For those interested in how, read on (it was fairly, but not entirely, straightforward).
Visual Studio lets you use an external tool via the Tools -> External Tools menu, and contains a bunch of pre-defined variables, such as $(ItemFileName), which can be passed on to the tool. So in this instance I used a simple batch file, and it gets passed the name of the currently selected file in Visual Studio.
To add that tool to the toolbar, right click on the toolbar, select Customize -> Commands -> Tools, and select the "External Command X" and drag it to the toolbar. Substitute X with the number corresponding to the tool you created. My installation contained 5 default pre-existing tools listed in Tools -> External Tools, so the one I created was tool number 6. You have to figure out this number as it is not shown. You can then assign an icon to the shortcut (it's the BuildMain command shown below):
No. You have to include them all if that's what you want to do.
No. At least, not in a way that's actually going to save typing.
Of course, you could write a script to create main.cpp for you...
If you build your code using make, you should be able to do this.
Can I include all headers in the directory so at least I don't have to change the #include line?
Change your include line to something like #include <all_headers.h>. Now, you can let your Makefile auto-generate all_headers.h with a target like:
all_headers.h:
for i in `ls *.h`; do echo "#include <$i>" >>all_headers.h; done
Make sure that all_headers.h is getting deleted when you 'make clean'.
Better yet, can I rewrite my solution so that I don't even have to touch main.cpp,
without having one file with all the code for every exercise in it?
You can do this if you abstract away your class with a typedef. In your example, change your class name from E0614 to myClass (or something). Now, add a line to your Makefile underneath the for loop above that says echo "typedef "$MY_TYPE" myClass;" >>all_headers.h. When you build your program, invoke 'make' with something like make MY_TYPE=E0614 and your typedef will be automatically filled in with the class you are wanting to test.
If you're on Unix system, you can have a softlink that points to the latest excercise.
ln -s e0615.h latest.h
and name your class E instead of E0614, of course
P.S. To the best of my knowledge, you can't do #include xxx*
Don't use one main.cpp which you modify for each exercise. This solution makes use of make's builtin rules, so you only have to type make e0614 and it will generate e0614.cpp, compile, and link it. You can customize each .cpp file (they won't be regenerated as written below) and maintain all of that history to refer to as you complete exercises, rather than erasing it as you move from one to the next. (You should also use source control, such as Mercurial.)
Makefile
e%.cpp:
./gen_ex_cpp $# > $#
You can generate boilerplate code with scripts, because you don't want it to be tedious either. There are several options for these scripts—and I use a variety of languages including C++, Python, and shell—but the Python below is short and should be simple and clear enough here.
Sample generate script
#!/usr/bin/python
import sys
args = sys.argv[1:]
if not args:
sys.exit("expected filename")
name = args.pop(0).partition(".")[0]
if args:
sys.exit("unexpected args")
upper_name = name.upper()
print """
#include "%(name)s.hpp"
int main() {
%(upper_name)s ex;
ex.solve();
return 0;
}
""" % locals()
Make a master include file containing the names of all the headers you want.
It's a really bad idea to include *, even if you could.
You could use conditional compilation for the class name by using concatenation.
// Somewhere in your other files
define CLASS_NUMBER E0614
// in main.cpp
#define ENTERCLASSNUMBER(num) \
##num## ex;
// in main()
ENTERCLASSNUMBER(CLASS_NUMBER)
Don't know about the includes though. As suggested above, a script might be the best option.
writing a makefile rule to pass the name of the executable as a -DHEADERFILE=something parameter to the compiler shouldn't be difficult at all. Something like:
%.exe : %.h %.cpp main.cpp
gcc -o $< -DHEADER_FILE=$<F $>
OTOH, I don't know if #include does macro expansion on the filename.
sed -i 's/\<\\([eE]\\)[0-9]+\\>/\19999/' main.cpp
Replace 9999 with the required number. There might be better ways.
Why not using object mechanisms ?
You can use an Exemplar strategy for this.
class BaseExercise
{
public:
static bool Add(BaseExercise* b) { Collection().push_back(b); return true; }
static size_t Solve() {
size_t nbErrors = 0;
for(collections_type::const_iterator it = Collection().begin(), end = Collection().end(); it != end; ++it)
nbErrors += it->solve();
return nbErrors;
}
size_t solve() const
{
try {
this->solveImpl();
return 0;
} catch(std::exception& e) {
std::cout << mName << " - end - " << e.what() << std::endl;
return 1;
}
}
protected:
explicit BaseExercise(const char* name): mName(name)
{
}
private:
typedef std::vector<BaseExercise*> collection_type;
static collection_type& Collection() { collection_type MCollection; return MCollection; }
virtual void solveImpl() const = 0;
const char* mName;
}; // class BaseExercise
template <class T>
class BaseExerciseT: public BaseExercise
{
protected:
explicit BaseExerciseT(const char* b): BaseExercise(b) {
static bool MRegistered = BaseExercise::Add(this);
}
};
Okay, that's the base.
// Exercise007.h
#include "baseExercise.h"
class Exercise007: public BaseExerciseT<Exercise007>
{
public:
Exercise007(): BaseExerciseT<Exercise007>("Exercise007") {}
private:
virtual void solveImpl() const { ... }
};
// Exercise007.cpp
Exercise007 gExemplar007;
And for main
// main.cpp
#include "baseExercise.h"
int main(int argc, char* argv[])
{
size_t nbErrors = BaseExercise::Solve();
if (nbErrors) std::cout << nbErrors << " errors" << std::endl;
return nbErrors;
}
And here, you don't need any script ;)
try this:-
#ifndef a_h
#define a_h
#include <iostream>
#include <conio.h>
#incl....as many u like
class a{
f1();//leave it blank
int d;
}
#endif //save this as a.h
later
include this in ur main program that is cpp file
#include "a.h"
...your program