Embedding cling in a compiled C++ program

Hello folks,

I am writing a rules engine for an AI module. The module will store and retrieve rule sets from a database. The intention is for the module to edit/enhance/correct rule sets which will then be executed by the engine. The engine would launch a thread which in turn would create a cling interpreter instance to execute the rule set. In order for it to work correctly, the C++ module needs to pass a context object instance to the cling script and the script needs to return a result object back to the C++ module.

As I said, the cling script (a c++ object and associated methods constituting the rule engine) would receive the rule set and the context object, execute the rules, and then return a result object back to the compiled caller.

Can this be done? I’m looking for the proper set and sequence of API calls to accomplish this objective.

Thanks,

Arthur Sera

2 Likes

Hi Arthur,

Cling sounds like a perfect match here, this is exactly what it was designed to do.

Code is passed to cling as a string. You can use Interpreter::evaluate to receive the object back as a Value, or even simpler, you use the same approach you could use for passing values into cling: passing the address of a variable, that the code run inside cling will access, eg using Interpreter:: process. Example code snippet:

int out = 42;
int in = 17;
stringstream sscode;
sscode << "*((int*)" << &out << ") = *((int*)" << &in << ") * 2";
interp.process(sscode.str());

Now, out is 34.

We’ll be happy to provide more detailed answers should you have specific questions!

Axel

1 Like

Hello Axel,

As it happens, I have run into what I believe are documentation obstacles. By that I mean that I cannot find something similar to we used to call a programmers guide. This was a document that laid out both the concepts of the language,utility or whatever it was, and the gross implementation details.

If there were such a beast for ‘Cling’, I would expect to be able to find a section called something like ‘Embedding Cling into your program’. In that section would be found a simple explanation of what header files to use, the principal functions to be called to instantiate the interpreter, and what libraries to link with for static or dynamic linking of the user’s program.

I hate wasting the time of busy gurus but I would greatly appreciate it if you could point me to a source for answering the following questions for my intended use cases:

  1. What header files do I need to include in my C++ compiled program to access the Cling interpreter’s needed data structures?

  2. What libraries and in what order will I need to link the Cling interpreter to my C++ compiled program?

  3. My C++ program will make extensive use of the Posix thread facilities. I intend to manage a pool of worker threads that will each independently utilize the Cling interpreter to run C++ scripts. The worker thread pools will be managed by schedulers whose services are enlisted by creating requests that are appended to the schedulers request queues. To facilitate inter-thread communications, the interpreter threads will lock a schedulers mutex, add to their request queue, and then wakeup the scheduler thread my signaling with its condition variable. Therefore, the interpreter scripts will need:

    3.1 Interpreter needs to receive a pointer to a mutex belonging to the C++ code.
    3.2 Interpreter needs to be able to load ‘libpthread.so’ to enable the calling of pthread_mutex_init, pthread_mutex_trylock, pthread_mutex_lock and pthread_mutex_unlock
    3.3 Interpreter needs to receive a pointer to a condition variable belonging to the C++ code.
    3.4 Interpreter needs to be able to call pthread_cond_init, pthread_cond_wait, pthread_cond_signal with the passed pointer to the condition variable.

Finally, it would be very nice if I were able to reset the interpreter instance back to its initial state after successfully completing the primary script so I did not have to fully construct a new instance of the interpreter before returning the work thread back to the available list in the worker thread pool.

Thanks for your good works and your assistance,

Arthur Sera

1 Like

Hi Arthur,

Fair enough, I see your point.

Would a sample program suffice? We had another request for a CMakeFile.txt that shows how to build a project using cling as a library; this could take care of both.

Would that be an acceptable solution?

The problems I have with documents is that they are even more annoying to write than code :wink: and they are more ambiguous to read than code and they are less maintainable (because no compiler ever complains).

Cheers, Axel.

Thanks Axel,

I’m always happy to have a good example. I agree with your comments about the fact that writing documentation tends to be an annoyance. I have always tried to get management to budget for a good technical writer to assist with these burdensome tasks. Still, I know it can still be painful to have to slow down and explain things to the tech writer so he/she can write meaningful prose that embraces the meaning and elegance of the artworks that have been produced.

Cheers & Glass Clinks,

Arthur

Axel,

You know that while I can enjoy a good read about theory and operations, I could get by with just a brief answer to 2 questions:

  1. What header files do I need for embedding and what libraries need to be linked with my C++ complied code?
  2. How do I get cling to load ‘libpthread.so’ or any other external shared lib?

Thanks again,

Arthur

Hi,

Look at cling/tools/driver/cling.cpp; it shows what a binary using cling can look like: how to create an Interpreter, which headers to #include.

Its CMakeLists.txt shows what to link against. But most of the clang and llvm libraries are pulled in as dependencies of libclingInterpreter, libclingUtils etc - depending on what you use (MetaProcessor? Or just the Interpreter?) you might need different libraries.

Have a look at cling/lib/Interpreter/CMakeLists.txt which enumerates these libraries. It’s a bit involved, because this uses the llvm machinery for translating functionality (“native”) into library names. If you use CMake you should be able to use the same approach given their FindLLVM or whatever it’s called. I’ve never done this myself - so it’s not a question of me not sharing knowledge but of me now knowing :slight_smile: If you have a CMake “recipe” I’d appreciate if you can share it.

Regarding the second part: you can link your binary against libpthread and cling will be able to resolve symbols (specially if you build your binary as -rdynamic, on Linux). You can then simply interpret #include <pthread.h> and use its functionality in the interpreter.

You can communicate with the interpreter world either through cling::Value or through the address passing I explained above.

Cheers, Axel.

I’ve been messing with cling/tools/driver/cling.cpp like you suggested. I’ve been programming since the 70’s and I’ve used make since the late 80’s. However, I’ve never been real attracted to cmake. I guess I should probably see if O’Reilly has a cmake book, but at the moment the CMakeLists.txt file does not enlighten me with regards to what libraries I should use to embed cling in my program.

Even after running cmake for that part of the source tree, I can’t seem to end up with a Makefile that has a clearly defined $(LIBS) variable much less an actual link to an executable statement. Come on. Someone has to have done this.

Sigh!

Ok, I found an old posting by Axel that helped lead the way. There’s a thread that is called:

How to properly link cling into my executable with cmake

The first post is Oct '15, the last one is Sep '16. The last post says that there is now a “libcling.so”. So the solution to compiling and linking the program cling/tools/driver/cling.cpp is as follows for me based upon my copying the cling.cpp program to my root build directory (i.e. /src/root-6.08.06/build - the directory where I ran cmake …) and having run “make install” after the 7 day creation exercise (well not really 7 days, but lengthy). Therefore the following was required to build it:

g++ -c -o clingI.o -std=c++11 -Iinclude cling.cpp
g++ -o clingI cling.o -lclingUserInterface -lcling

Aparently, most everything was stuffed into the libcling.so library. The library libclingUserInterface.a was necessary because the source file ‘cling.cpp’ instantiates UserInterface (cling::UserInterface ui(interp):wink: to accommodate interactive code entry/execution. I don’t believe I’ll need that for my program but it’s nice to have it available for some other purposes.

If anyone has any questions about this please feel free to ask: artsera@yahoo.com

Good Luck,

Arthur Sera

Hi,

Indeed, that’s the easiest approach. If you want to avoid the runtime mess of finding the shared library then take the static libraries (.a files), else libcling.so is the way to go.

Axel.

…and I have just pushed cling/tools/demo: a CMake project that shows how to code, compile and link a binary that uses cling. I hope you like it :slight_smile:

Cheers, Axel.

Hello Axel,

Thanks for posting the demo. Is there any way for me to call a Compiled function/method from the cling interpreter script?

Thanks,

Arthur Sera

Hi Arthur,

Isn’t get / setAnotherGlobal() just that?

Axel

Hmmm,

I can’t find any method name within the Interpreter class. There’s a getAddressOfGlobal method, but I can’t find a method to set one.

?

Arthur

Hi Arthur,

I was talking about the example in cling/tools/demo which defines this function to demonstrate exactly what you are looking for.

Axel

Because trying to compile cling exhausted my disk space, I only installed the binaries, hence there is no ‘/cling-source-dir/tools/cling/tools/demo’ directory on my machine… What should I do instead to compile this on ubuntu 18.04 ?

It’s not a makefile I need; without the sources it’s not much use. & I’ve got cling up & running fine.

Given that, does anyone know which libraries & headers are needed to compile cling-demo.cpp on Linux?

trying to use cmake I try:

cmake -Dcling_DIR=ci/inst/lib/cmake/cling ci/src/tools/cling/tools/demo

and get:
– Configuring done
CMake Error: CMake can not determine linker language for target: cling-demo
CMake Error: Cannot determine link language for target “cling-demo”.
– Generating done
CMake Warning:
Manually-specified variables were not used by the project:

cling_DIR

– Build files have been written to: /home/forrest

Suggestions?

Hi
I played with the cling-demo sample found in https://github.com/elix22/cling/tree/master/tools/demo

Works great .
I am curious if it’s possible to do the same with C++ Classes.
Specifically instantiate a native class from the interpreter side and call some of its methods and vice versa .

I am aware of the C++ name mangling issues .
I am aware that it’s possible to create some extern “C” wrapper functions that will do the job , but I consider it to be an workaround .
Is there another way ?

Hi Eli,

Welcome to the ROOT forum!

Sure, that’s the whole beauty of cling: just #include a header in cling, and use the same header in your compiled code, and if the flags are all lined up then you can pass objects from compiled code into the interpreter and back! That’s what ROOT does, in production, 24/7, on 100’000s cores world-wise: it works!

Cheers, Axel.