Augmenting Cling with Custom Functions

I had asked about building a custom interpreter using root in this post .

I was pointed to this cling-demo as a possible solution.

I downloaded and built cling and built the cling-demo. However, what it does is not what I am looking for. The cling-demo is an executable that uses the interpreter functionality but cannot interpret a script file that is passed to it as an argument.

I am trying to build an ‘enhanced’ interpreter that integrates additional proprietary functionality into cling which can then be used to interpret a source file which does not need to be compiled.

I’m starting this new thread to see if I can explain better and build what I need using Cling (or Root).

I hope that someone familiar with both Cint and Cling/Root can tell me if what I am looking for is possible in Cling/Root (and how). Cint worked great for us and we wouldn’t be looking for another solution had support for Cint not ceased for recent releases of linux.

To reiterate, I just need an augmented C++ interpreter which can also execute some other proprietary instrumentation functions that I have.

More given below with a very trivial code example.

Thank you.

_ROOT Version: v6.26.10
_Platform: Ubuntu 22.04
_Compiler: g++ 11.3.0

I have a source file mysrc.c which implements this function myfunc1() that returns the product of the two input parameters:

int myfunc1(int x, int y)
{
   return (x * y);
}

I’d like to integrate myfunc1() into cling/root so that the new cling/root can interpret a script file myscript.c which calls myfunc1(). The aim is to not need any compilation for myscript.c to be able to use the functions that it invokes.

/* File myscript.c  */

#include <stdio.h>

main()
{
  int x = myfunc1(3, 4);
  printf("%d\n", x);
}

To put it in Cint perspective, I could accomplish the above as follows with Cint:

  1. Declare the function prototype of myfunc1() in myhdrs.h
  2. Compile mysrc.c to get mysrc.o
  3. Define a makecint makefile with the following command -
makecint  -mk  mkfile_mylib  -o  mycint  -H  myhdrs.h  -l mysrc.o

The above creates a makefile called mkfile_mylib

When ‘make -f mkfile_mylib’ is executed, it creates the augmented/custom Cint mycint.

Then, mycint can be used by itself (no arguments) and it starts the augmented
interpreter which can also execute myfunc1() as follows (“$>” is the shell prompt):

$> 
$> mycint
mycint>
mycint> {myfunc1(2, 3);}
(int)6
mycint>
mycint> q
$>

or I could pass the script file myscript.c to mycint as follows:

$> 
$> mycint myscript.c
$> 12
$>

Is it possible to accomplish this with Cling (or root)? If so, how?

I guess @vvassilev and @Axel can help you.

Yes, I hope one of the experts gives me some pointers. Axel N, Daniel B and Philippe C had provided invaluable guidance and workarounds when I built the custom cint many years back.

Vassil Vasisilev @vvassilev is the author of the cling demo you pointed out in your first post. I am sure he can help you.

Hi @salz-root, apologies for the delay. Have you tried to build cling standalone from GitHub - root-project/cling: The cling C++ interpreter ?

Then, instead of building a .o file you could build a .so file. Then from the cling prompt you can do:

cling> #include "myhdrs.h"
cling> .L myLib.so
cling> myfunc1(2, 3);

Is that the use case you had in mind or I am misinterpreting your project requirements?

Thank you @vvassilev for responding.

I have not built cling from the URL you have provided but I built it using the following directives from the cling_build_instructions page :

git clone http://root.cern/git/llvm.git src
cd src
git checkout cling-patches
cd tools
git clone http://root.cern/git/cling.git
git clone http://root.cern/git/clang.git
cd clang
git checkout cling-patches
cd ../..

mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=[Install Path] -DCMAKE_BUILD_TYPE=Release  ../../src
cmake --build .
cmake --build . --target install

My questions -

  1. Do I need to discard the cling I have built and rebuild it from the root-project/cling page that you’ve referred to?

  2. What is the command syntax to build the shared library mylib.so from mysrc.c?

Currently, I can load the source file into the cling that I have built and do the following:

[cling]$ #include "myhdrs.h"
[cling]$ .L mysrc.c
[cling]$ myfunc1(2, 3)
(int) 6
[cling]$

But we won’t be sharing the source files such as mysrc.c with anyone since they contain proprietary code. So we need to create libraries from our source and integrate them into cling beforehand. The end user just has to write a source script (myscript.c) which would invoke functions that are listed in myhdrs.h and pass the script file to the modified cling that already has the library of our proprietary functions built in. The end user would not be loading any libraries (e.g., with a “.L mylib.so” command in cling) to be able to execute/interpret their scripts that call our proprietary functions.

Please see my earlier post where I described how we achieved our project goals with cint.

As long as you can run cling then it does not matter where it came from.

gcc -o mylib.so -shared mysrc.c?

You just need to do .L mylib.so.

Thank you again @vvassilev.

I am finally able to build a shared library both with source code files and pre-compiled object files and load it into cling. This is a library built with multiple files calling functions defined in different places. So I am happy to have made it thus far. I can execute some simple functions that are built into the shared library.

However, I get segmentation fault the moment I try “anything of value”, i.e., anything that involves port initialization etc., which are essential for our tools. I cannot see anything in the stack dump that would point me in a helpful direction. The source code I am using is time tested and should not have segfaults. So, I am probably missing some vital piece of information.

What is PIC? And what does “-fPIC” do? While trying to build my library, I once got an error message that suggested I recompile with “-fPIC”. I have been unable to find what that is. But the error went away after I compiled as suggested.

Can you provide a minimal (obfuscated if you are more comfortable that way) reproducer where I can take a look?

Position independent code: Position-independent code - Wikipedia

I realized later that since the PIC error was seen while building my library, it had nothing to do with cling and was from g++. Sorry about that. But thanks for the Wiki pointer. The error was in relation to some open source AES encryption code we incorporate with the code we have written. I had not seen this error before while compiling with previous versions of g++. So I am not sure what causes the error now as the source code hasn’t changed (but I’ll leave it for now since I could build the library).

Regarding the segfault, I will see if I can reproduce it with something that I can share.
Meanwhile, I noticed something and wonder if that could be a cause.

If I have a file like mytest.c

/* File mytest.c  */

#include <stdio.h>

main()
{
  printf("\nHello from main()\n");
}

cint could execute it without any error/warning because it looks for main(). In other words, the following

cint  mytest.c

prints “Hello from main()”. The return type of main() can be omitted where main() is defined.

g++ only gives a warning but also compiles the above mytest.c and produces the same output as cint.

$>
$>  g++   -o  mytest   mytest.c
$>  ./mytest
$>
$>  Hello from main()
$>

With cling (and root), main() seems to have no significance and the function in mytest.c must be renamed to mytest() and explicitly defined to be of type void as follows:

void mytest()

so that

cling  mytest.c

works (i.e., prints “Hello from main()”).

But the more serious problem is that functions of implicit return type int like this:

mytest()
{
  printf("\nHello from main()\n");
  return 0;
}

or a function where the return type int is specified but which has no return statement like this

int mytest()
{
  printf("\nHello from main()\n");
  // return 0;
}

both result in a core dump when invoked with cling.

cling mytest.c

We probably have several functions of type int that may not have a return statement or have an implicit return type of int.

Could this be causing the segfault?