Continuing along the lines of extending ROOT functionality with external libraries I have run into another issue that I am hoping someone here can help resolve. If I make a library containing a class foo and write a script bar1.C that calls the the class:
void bar1() {
foo f;
}
I can call this from root with no issues as follows:
[0] .L libFoo.dylib
[1] .x bar1.C
If I then try to have the script bar2.C do the library loading using gSystem::Load as follows:
IncrementalExecutor::executeFunction: symbol '_ZN11fooC1Ev' unresolved while linking [cling interface function]!
You are probably missing the definition of foo::foo()
Maybe you need to load the corresponding shared library?
Any ideas? What is the āproperā way to load an external library for use like this?
As the first step of interpreting, cling ācompilesā that script before running it. For that it cannot resolve the foo constructor. I.e. things are out of sequence. Simply use
R__ADD_LIBRARY_PATH($FOODIR) // if needed
R__LOAD_LIBRARY(libFoo.dylib)
the interpreter of ROOT6 is based on a real compiler and, as such, it looks for all symbols before running the code. So it is somehow ātoo lateā to load the library at runtime since the symbols inside it are needed at compile time.
Now, there are several ways out. The first one, which is the one I recommend, is to use rootmpafiles. These allow ROOT to autoload the libraries needed for running the code and to parse the necessary headers. Creating a rootmapfile is very easy: just use the -rmf switch or --rootmap in rootcling or genreflex respectively.
In case libFoo is a library you did not build and you want to use it interactively I think the best option is to
Include the header (as you correctly did)
Use the R__LOAD_LIBRARY(libFoo.dylib) macro: this will trigger the loading of the library at parsing time, therefore in time for letting cling finding the symbols necessary for the compilation
In ROOT5 your code was working since the interpreter, CINT, was interpreting the code line by line.
This worked nicely. The only downside was that the entire absolute path needed to be added. Does ROOT following environment variable for where to find headers and libraries? Something similar to gccās INCLUDE_PATH, CPLUS_INCLUDE_PATH and LIBRARY_PATH?
I am generating the rootmap files as I am using the cmake macro ROOT_GENERATE_LIBRARY (which I have an issue with, but will not discuss here). Iām not sure how to use these files, it seems they need to be placed somewhere in particular? Remember I am trying to develop this for others to use so the idea is that a cmake file would properly place all the files in the correct places and the user would have to do very little to get it working.
Thanks for the responses so far, they are helpful.
Also, what do I need to do so that I can recall the same macro multiple times? Currently it crashes with warning of āunknown typesā when calling it more than once:
[0] .x macro.C
Success!
[1] .x macro.C
... error: unknown type name 'foo' ...
EDIT: I tried wrapping the library loading in a header guard, but that didnāt resolve the issue.
My problem here is that I am using CMake and ROOT_GENERATE_DICTIONARY. This macro builds a rootmapfile, but it doesnāt work correctly.
First, it needs to be manually installed, more of an annoyance than anything else:
#Install the ROOT 6 PCM and rootmap files.
if (${ROOT_VERSION} VERSION_GREATER "6.0")
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libFooDict_rdict.pcm
${CMAKE_CURRENT_BINARY_DIR}/libFooDict.rootmap
DESTINATION lib/)
endif (${ROOT_VERSION} VERSION_GREATER "6.0")
Secondly the rootmap file is incorrectly named for the library libFooDict.rootmap and top of the rootmap file reads:
[ libFooDict.so ]
This is incorrect as I am on a Mac and the extension should by .dylib and in addition it should not have the Dict. At some point I will make a small example and open a new thread with issues related to ROOT_GENERATE_DICTIONARY (I have a couple additional issues as well).
both Philippe and I are right. If you are running a macro, you will need to load the libraries so better to rely on autoloading and therefore rootmaps. If you build executables or shared objects, better to directly link.
Plus, the first library should be loaded with the help of a rootmap file, all dependent libraries should be loaded by the dynamic linker because they were explicitly linked against the first library.