I’ve got a quite technical question. I’m fitting some data using TMinuit, and
the setup procedure takes quite some time and I’m still debugging my
fit function so I spend quite some time waiting for the setup to finish
in order to test the function itself. Now, in one source file I got something
like
TMinuit *fMyFitter = new TMinuit(95);
fMyFitter->SetFCN(Chi2);
while GetSquareSum(…) is implemented in another file. Is there a
way I can “relink” the loaded libraries and just change GetSquareSum()
without having to reload everything? Had I been working outside of ROOT
I would have used dlopen and a function pointer. Should I do this here
as well?
I am not sure I have understood your problem. If you are working from the ROOT prompt, running the application interactively or using ACLIC you can load the file (or library) implementing the minimization function by doing
root>.L GetSquareSum.C+
GetSquareSum.C is the file implementing your function and the “+” is need if you want the code compiled. If you are not runnining from the ROOT prompt you can then use gROOT->ProcessLine
I’m probably not so clear then Seems to be a problem of mine on this
page…
I want to change how I calculate the square sum, i.e. GetSquareSum(), without having to reload the chi2 function I use for the the TMinuit fitter
object. I tried naively to reload the GetSquareSum function using
root> .L GetSquareSum.cxx+
but my Chi2 function still uses the old GetSquareSum when I do the fit.
This is what I would like to change without having to recompile the chi2 function, which would remove some variables I want to keep. I could possible rewrite the code so I use TMinuit::SetFCN instead, but I prefer
not to do it that way.
It is clear why, in fit_cxx.so the double squaresum() from sqsum.cxx is
still used. Doing
root [1] .L sqsum2.cxx++
Info in : unmodified script has already been compiled and loaded
Info in : it will be regenerated and reloaded!
Info in TUnixSystem::ACLiC: creating shared library /users/joa/test/root/./sqsum2_cxx.so
root [2] .L fit.cxx+
root [3] fit()
(double)2.00000000000000000e+00
root [4] .q
A-MacBook-Pro:root joa$ root -l
root [0] .L sqsum.cxx+
Info in TUnixSystem::ACLiC: creating shared library /users/joa/test/root/./sqsum_cxx.so
root [1] .L fit.cxx+
root [2] fit()
(double)1.00000000000000000e+00 !!!
root [3]
it is also clear that root is doing the “right” thing when linking. My question
was how can I replace the squaresum() in sqsum.cxx with the one in
sqsum2.cxx without loosing any other variables etc? If the answer is too use dlopen etc I know how to do it, but I hoped there was a simple solution
I missed using the “.L” of root
your script does not work because you cannot have two implementations of the same symbols in two libraries.
You should use two function names, since you are using a function pointer you can set easily to one of the name as you wish.
Or, if you are using Minuit, via the new Minimizer interface you can have two different objects implementing the function via the same interface.
This is much simpler and it will solve your use case
To insure that in the general case library loading and unloading works, the .L library loading function is keeping track of dependencies between libraries. At the moment this dependency tracking is very simply based on the order of loading; i.e. .L assumes that if you loaded library B after library A, it might use any symbols coming from library A. In particular some of this symbols might be a class definition, in particular a class size (for example you might have ‘class A { … };’ and ‘class B { … A fObject; }’. So this means that if A is unloaded and reloaded, the definition and size of A might have changed, if this happens, the B class definition and the B object we may have allocated are now invalidated (i.e. using the old object or the old class B definition will lead to certain data corruption and/or crashes).
So as you found out, you would need to either load the library containing the actual function definition as the last library via .L or, as you did, take that library loading out of band from the .L. In addition to the dlopen you have in SetSuareum you probably should unload (dlclose) the previous one to avoid confusing the linker ; also to avoid potential confusion, as Lorenzo pointed out, you ought to use a different name for the pointer to function and the functions themselves.
More over, as Lorenzo pointed out, it might be simplier (and more C++ ‘like’ ) to use a series of concrete implementation of a base/interface class instead.