I'm on Linux and trying to link an application that makes use of
LLVM's JIT execution engine statically.
(1) LLVM libs are compiled as static libraries.
(2) Called InitializeNativeTarget().
(3) Included llvm/ExecutionEngine/JIT.h.
It works if I build and link regularly.
However, if I add -static when linking, the execution engine
fails to initialize. Does anyone know why? LLVM libs are already
archives. Is that supported at all?
Thanks & ciao,
Yeah, this is a problem with the static constructor getting optimized out. Including "JIT.h" is supposed to fix that.
Is it possible that the file where you are including "JIT.h" doesn't have any required code in it?
If you send me details about how you're building this I'll look into it.
Thanks. I forgot to mention it's LLVM 3.2 on Ubuntu 12.10. The command line is:
$ g++-4.7 ExecutionEngineTest.cpp $(llvm-config --cxxflags --ldflags --libs) -lpthread -ldl
$ g++-4.7 -static ExecutionEngineTest.cpp $(llvm-config --cxxflags --ldflags --libs) -lpthread -ldl
The -lpthread -ldl is there explicitly because llvm-config prints them
as part of --ldflags before the dependent LLVM libs.
The first of the above commands works well. The second one does not.
It turns out that this isn't a problem with the static constructor at all.
EngineBuilder::create() is calling dlopen (by way of sys::DynamicLibrary::loadLibraryPermanently) with a zero argument to get a handle the current module, which the default memory manager may later use for external symbol resolution. Because in your case the program is statically linked, the call to dlopen fails (errno says the executable couldn't be found in the dynamic linker's module load list). When this happens EngineBuilder::create() also fails.
In reality, the EngineBuilder code shouldn't be doing that. If it is needed at all the memory manager should be doing it. If you comment out that call in the EngineBuilder code, your test case will successfully create the JIT engine. However, you might have subsequent problems with external symbol resolution. In that case, you would need to implement a memory manager that knew how to resolve the missing symbols.
If you prefer not to modify the LLVM code, you can also work around this problem by using ExecutionEngine::createJIT(), which does not make the dlopen check. I suspect that code path is not well tested, so there may be additional problems if you do things that way.