JIT and libraries

How do i link JIT-ed code with libraries (static or dynamic)?

As far as i can tell -rpath cannot be passed to the interpreter (warning ‘linker’ input unused), so it is not possible to add new shared objects when JIT-ing code.

I also couldn’t find a way to add static libraries – cling does not complain about -L/-l when creating the interpreter instance, and it compiles the code, but i end up with an error message when invoking the compiled code (IncrementalExecutor: calling unresolved symbol, see previous error message!).

Hi,
I am not sure I understand what you mean correctly. If you want to use a library you could do:

  [cling] .L myLib
  [cling]  #include "myLibHeader.h"
  [cling] myLibHeaderClass c = new...

– Vassil

I am not using cling as an interpreter (from a command prompt), but as a JIT compiler, so the equivalent of your example for the static lib case is something like:

  ...
  argv[] = { ... "-static", "-L.", "-lmylib", ... };
  dc = new cling::Interpreter(argv, ...)
  ...
  dc->declare("#include \"mylib.h\"\n int f() { return mylibfunc(); }\n", ...);
  ...
  typedef int ft(void);
  ft* f = reinterpret_cast<ft*>(dc->getAddressOfGlobal(...));
  ...

but code();[/code] results in “IncrementalExecutor: calling unresolved symbol, see previous error message!”

Try:

  dc->loadFile("mylib", /*sharedLib*/ true);

cling.web.cern.ch/cling/doxygen/ … 0a87eed947

The documentation of loadFile() says:

    ///\brief Loads header file or shared library.

Indeed auto const cr = dc->loadFile("libsc.a", false); results in

/a/lnn51f2/vol/lnn51f2v7/u_t1402742371/andrase/jit/libsc.a:1:1: error: expected unqualified-id
!
^
/a/lnn51f2/vol/lnn51f2v7/u_t1402742371/andrase/jit/libsc.a:3:1: warning: null character ignored [-Wnull-character]
^

/a/lnn51f2/vol/lnn51f2v7/u_t1402742371/andrase/jit/libsc.a:7:664: error: source file is not valid UTF-8
…<U+000F>
^

which suggests that cling is trying to load the file as source code instead of as a static library. I think Fail to load shared library in Cling<Windows> is about the same problem (although on windows).

Yes, the library should be a shared object. We don’t support loading static libs, because what does loading of a static library mean :slight_smile:
One way to make it work is to link against mylib during cling build phase.

To resolve symbols using the lib (link JIT-ed code against the lib).

I am actually also linking against “mylib” when building the binary containing cling (and calling into mylib from the offline compiled code)

g++ ... -L. -lmylib 

but i don’t see how that could help with resolving symbols in the JIT-ed part – i guess you are referring to dynamic libs again (that for dynamic libs i can use loadFile() at JIT time, or -rpath during offline building).

Is the symbol that you are looking for present in the cling binary. The linker optimizes out the non used symbols. We request those explicitly in lib/Interpreter/RequiredSymbols.cpp Try to add the symbols there if it gets optimized away.

It is still not clear to me whether you are talking about the statically linked lib or the shared object case here.

Yes, the symbol is present in (the function is called from) the offline compiled part, but as it is a statically linked lib, i do not see how that can help the JIT-ed part to find the symbol. To make the example more concrete:

sc.hint inc();

sc.cc[code]
static int i = 0;

int inc()
{
return ++i;
}[/code]

main.cc[code]#include “sc.h”
#include “cling.h”
#include <stdio.h>

int main()
{
printf(“static inc %d\n”, inc());
char const src =
#include "sc.h"\n”
“int dinc() { return inc(); }\n”;
typedef int dinc(void);
jit::DynamicCompiler* dc = jit::new_compiler(“libtest”); // pass -L. and -lsc to cling::Interpreter
dinc* dip = reinterpret_cast<dinc*>(jit::compile(*dc, src, “dinc”));
printf(“compiled\n”);
if (dip) {
printf(“dynamic inc %d\n”, (*dip)());
printf(“static inc %d\n”, inc());
printf(“dynamic inc %d\n”, (*dip)());
}
delete dc;
}
[/code]

$ gcc -c -o sc.o sc.cc
$ ar rcs libsc.a sc.o
$ g++ ... main.cc cling.cc ... -L. -lsc && ./a.out

static inc 1
compiled
IncrementalExecutor: calling unresolved symbol, see previous error message!
dynamic inc 47754048
static inc 2
IncrementalExecutor: calling unresolved symbol, see previous error message!
dynamic inc 47754048

Previously i had a problem for which this might be the solution: Missing std::string::operator=(std::string&&) – do you mean that referencing e.g. the the std::string move constructor in symbol_requester() would make it available for the JIT-ed code? I’d try it myself, but i can’t wrap my head around what’s going on in that function.

I am talking about static libs.

If you want to use static libs, cling has to know how to get the symbol. Definitely dlopen won’t work (this is what loadFile uses). Currently, we use things from just one statically linked lib: libc++. This is why this code works:

[cling] #include <iostream>
[cling] printf(...) // here we need to load libc++ because the binary (libCling) is linked against it.

The reason this works is because during cling’s build time we link against libc++. In your example sc has to be linked against libCling, not against your third-party code.

The second option would be to teach cling what to do on a missing symbol. I am not sure whether that is possible. There are callbacks (eg. HandleMissingFunction) in the IncrementalExecutor.cpp, where you could provide a callback and point the JIT to try to find the symbol from your lib and give it to the “JIT” for execution.

I hope this makes it clearer…

I still don’t see why don’t you put sc in a shared library and load it via the designed interface?

–Vassil

PS: I am not sure whether this would fix the other issue you have with std::string move constructor.

ATM I am just exploring what is and what isn’t possible with cling, and in the long run it is not going to be up to me to decide between using shared/static libs in the JIT-ed code, but by the concrete use-cases (the final clients may only have static libs); and the outcome of the investigation can be that “you can only use shared libs in JIT-ed code” (or “you need a custom built cling to use your static libs”).

What i was after with this simple example is figuring out whether i’ll end up with

static inc 1 dynamic inc 2 static inc 3 dynamic inc 4
or

static inc 1 dynamic inc 1 static inc 2 dynamic inc 2
if i can make it work – my suspicion was the latter (both the offline compiled and the JIT-ed code has its own copy of the static lib), but if i do it the way you are suggesting most likely i’ll end up with the former output (there’ll be a single copy of the static lib).

I’ll look into HandleMissingFunction, but i suspect that’d require too much support (and sophistication) from the final users, and custom built cling instances don’t look like a good choice either, so the outcome will likely be “only shared libs are supported for JIT, sorry”.

Hi,

Your static libraries will be mostly ignored by the linker when linking it against cling, because cling doesn’t resolve any symbols from it.

You should create a shared library and then load it, either through cling or simply by calling dlopen.

In principle the JIT is able to link against static libraries; we have not implemented it because we don’t have a use case. You are welcome to submit a patch is you have a need for supporting static libraries!

Cheers, Axel.