Hi All,
TL;DR trying to figure out if its possible to registering std::functions (lambda) to the interpreter, and executing them at the same time all, while in a single scope, such that I can run the same script endlessly without worrying about cling complaining about re-declaring variables.
I’m using root 6.06.02 compiled with both gcc530 and gcc 4.9.3 on various flavors of linux (the gcc version doesn’t bother me at the moment)
Right now I’m tryting to register functions from my compiled (gcc) session into my interpreter in a very recyclable manner.
What I’m trying to do essentially is to run scripts that are all scoped. In other words, I want to only pass “{ [string_to_interpret] }” to the interpreter, such that all of the variables I tell cling to allocate get deallocated and/or forgotten.
There are issues with using unload() (sft.its.cern.ch/jira/browse/ROOT-7939)
and child interpreters aren’t supported yet (API: scopes and curley braces) (I promised Axel to help out but I never got up to it yet <img src="/uploads/default/original/2X/8/84c2fe9464a4066c00e1bd5978e913e7869cbb07.gif" width=“22” height=“16” alt=":-"" title=“Whistle”/> )
I also don’t know of any way of copying a cling::Interpreter instance.
DISCLAIMER: in this example, I’m using boost::optional.
#include <iostream>
#include <cstdio>
#include <boost/optional.hpp>
#include <cling/Interpreter/Interpreter.h>
#include <functional>
static const std::string PATH_TO_LLVM {"/home/d4nf/Custom_Libs/Root-CERN/root-6.06.00.gcc530/etc/cling"};
static const char * clingArgs[] = {"", "-std=c++11"};
struct Mobject
{
void set(double _d) {d = _d;}
double get() {return d.get();};
private:
boost::optional<double> d;
boost::optional<uint32_t> b;
boost::optional<int32_t> a;
};
int main()
{
Mobject foo, foo2, foo3;
foo2.set(33.334);
cling::Interpreter inter(2, clingArgs, PATH_TO_LLVM.c_str());
//inter.AddIncludePath("/usr/include");
inter.declare("#include <functional>\n #include <boost/optional.hpp>");
std::function<void(double)> fun_setter = [&foo] (double d_cpy) -> void { foo.set(d_cpy);};
std::function<double()> fun_getter = [&foo] () -> double {return foo.get();};
std::function<void()> printHello = []() {std::cout << "Hi Everyone!!!\n";};
uintptr_t setter_addr = reinterpret_cast<uintptr_t>(&fun_setter);
uintptr_t getter_addr = reinterpret_cast<uintptr_t>(&fun_getter);
uintptr_t hello_addr = reinterpret_cast<uintptr_t>(&printHello);
std::array<char, 4096> toExec;
int BytesWritten = 0;
BytesWritten = std::sprintf( &toExec[BytesWritten], "%s * fun_setter_mangle = reinterpret_cast<%s*>(%llu);",
"std::function<void(double)>", "std::function<void(double)>", setter_addr);
BytesWritten += std::sprintf( &toExec[BytesWritten], "%s & fun_setter = *fun_setter_mangle;",
"std::function<void(double)>");
BytesWritten += std::sprintf( &toExec[BytesWritten], "%s * fun_getter_mangle = reinterpret_cast<%s*>(%llu);",
"std::function<double()>", "std::function<double()>", getter_addr);
BytesWritten += std::sprintf( &toExec[BytesWritten], "%s & fun_getter = *fun_getter_mangle;",
"std::function<double()>");
inter.process(toExec.data());
BytesWritten = 0;
BytesWritten += std::sprintf( &toExec[BytesWritten], "%s * printHello_mangle = reinterpret_cast<%s*>(%llu);",
"std::function<void()>", "std::function<void()>", hello_addr);
BytesWritten += std::sprintf( &toExec[BytesWritten], "%s & printHello = *printHello_mangle;",
"std::function<void()>");
const char proxyStruct[] =
"struct MyProxy{"
"void set (double d) {fun_setter(d); }"
"double get () {return fun_getter(); }"
"}; MyProxy foo2;";
BytesWritten += std::sprintf( &toExec[BytesWritten], proxyStruct);
BytesWritten += std::sprintf( &toExec[BytesWritten], " printHello();");
foo.set(11234.22);
std::cout << "foo is: " << foo.get() << "\n";
inter.process(toExec.data());
inter.process("foo2.set(45.123);");
std::cout << "foo is: " << foo.get() << "\n";
}
The output here is exactly as I desire
[quote]./tcling
foo is: 11234.2
Hi Everyone!!!
foo is: 45.123
[/quote]
However, when I comment out lines 51,52[quote]
// inter.process(toExec.data());
// BytesWritten = 0;[/quote]
[quote]./tcling
foo is: 11234.2
input_line_4:2:536: error: reference to local variable ‘fun_setter’ declared in enclosing function ‘__cling_Un1Qu30’
…& printHello = printHello_mangle;struct MyProxy{void set (double d) {fun_setter(d); }double get () {return fun_getter(); }}; MyProxy foo2; printHello();
^
input_line_4:2:146: note: ‘fun_setter’ declared here
std::function<void(double)> * fun_setter_mangle = reinterpret_cast<std::function<void(double)>>(140737143517008);std::function<void(double)> & fun_setter = …
^
input_line_4:2:574: error: reference to local variable ‘fun_getter’ declared in enclosing function ‘__cling_Un1Qu30’
…& printHello = *printHello_mangle;struct MyProxy{void set (double d) {fun_setter(d); }double get () {return fun_getter(); }}; MyProxy foo2; printHello();
^
input_line_4:2:310: note: ‘fun_getter’ declared here
…fun_setter_mangle;std::function<double()> * fun_getter_mangle = reinterpret_cast<std::function<double()>>(140737143517040);std::function<double()> & fun_get…
^
input_line_5:2:2: error: use of undeclared identifier ‘foo2’
foo2.set(45.123);
^
foo is: 11234.2
[/quote]
This is what I want my whole execution string to look like (generated after one run (with above errors))
[quote]{ std::function<void(double)> * fun_setter_mangle = reinterpret_cast<std::function<void(double)>*>(140732576095296);
std::function<void(double)> & fun_setter = fun_setter_mangle;std::function<double()> * fun_getter_mangle = reinterpret_cast<std::function<double()>>(140732576095328);
std::function<double()> & fun_getter = fun_getter_mangle;std::function<void()> * printHello_mangle = reinterpret_cast<std::function<void()>>(140732576095360);
std::function<void()> & printHello = *printHello_mangle;
struct MyProxy{
void set (double d) {fun_setter(d); }
double get () {return fun_getter(); }
};
MyProxy foo2;
printHello();
foo2.set(45.123); }
[/quote]
I don’t claim that my way of doing things is right, and I clearly am having trouble with this. Could anyone recommend me a way of doing this right?
I need a mechanism where I can run toExec (the std::array) an unlimited amount of times without cling telling me that I’m trying to redeclare anything. (that’s why in my general use case, it’s surrounded by braces)
I was thinking of somehow copying cling::Interpreter (a full clone, not a child copy), however the copy constructor and assignment operator are deleted/removed, I didn’t notice any clone() or copy() functions in Interpreter.hpp either so I’m once again at a loss.
Any help would be appreciated
Thanks in advance.