How to test if a function exists

Assume I have executed a couple of: gSystem->Load("libSomePackage.so");

One of these libraries possibly provides a function (note: these libraries have NO dictionaries): void SomeFunction();

How can I “test” if a function (knowing just its “prototype”) is provided by one of the currently loaded shared libraries?

I think the interpreter can tell you, like this

TInterpreter::EErrorCode err;
gInterpreter->ProcessLine("auto fn = MyFunc;", &err);
if (err == TInterpreter::kNoError) {
   // MyFunc exists
}

The preferred solution is through TFunction / TMethod; you can look up the latter from a TClass.

Or you use C++'s enable_if / SFINAE: SFINAE - cppreference.com

Or with C++17 if constexpr.

The " void SomeFunction()" is not related to any class (and the shared library, which possibly provides it, has no dictionary).

I need something that works from inside of the interpreted “rootlogon.C” and with ROOT 6 that supports C++11.

Could you give me a small “example” of how to do it, please?

It seems I almost succeeded:

gSystem->DynFindSymbol(nullptr, "_Z38vtkRenderingOpenGL2_AutoInit_Constructv")

Unfortunately, it requires the mangled name of the function.

How can I get this from ROOT?

I tried:

root [0] gInterpreter->GetMangledName(0, "SomeFunction", "()")
(TString) ""[0]
root [1] gInterpreter->GetMangledNameWithPrototype(0, "SomeFunction", "SomeFunction()")
(TString) ""[0]
root [2] gInterpreter->GetMangledNameWithPrototype(0, "SomeFunction", "void SomeFunction()")
(TString) ""[0]
root [4] gInterpreter->GetMangledNameWithPrototype(0, "SomeFunction", "SomeFunction(void)")
(TString) ""[0]
root [3] gInterpreter->GetMangledNameWithPrototype(0, "SomeFunction", "void SomeFunction(void)")
(TString) ""[0]

It seems that if the Cling itself does not know the function, the “gInterpreter” will not return its mangled name at all.

Sorry for the late reply. This should work:

  1. For me to try this out, I’m declaring a function such that ROOT knows about it:
root [0] .rawInput
Using raw input
root [1] int SomeFunction();
root [2] .rawInput
  1. Now I can test whether ROOT knows about it:
auto ci = gInterpreter->ClassInfo_Factory();
bool found = gInterpreter->ClassInfo_HasMethod(ci, "SomeFunction");
gInterpreter->ClassInfo_Delete(ci);

Not really …

root [0] .rawInput
Using raw input
root [1] void It_s_a_Lulu();
root [2] .rawInput
Not using raw input
root [3] auto ci = gInterpreter->ClassInfo_Factory();
root [4] gInterpreter->ClassInfo_HasMethod(ci, "It_s_a_Lulu")
(bool) true
root [5] gInterpreter->ClassInfo_Delete(ci);

Oh you don’t want to know whether it’s declared - you want to know whether it is implemented or an unresolved symbol! Yes, that’s through mangling. Are you in a position to name the function yourself? If so, mark it as extern "C" (so it doesn’t get mangled) and use just dlsym(RTLD_DEFAULT, "It_s_a_Lulu"). That’s for shared libraries; if you also want to query the interpreter then tell me because dlsym won’t know.

Thanks.

I cannot use “dlsym” from inside of “rootlogon.C”, but I can use “TSystem::DynFindSymbol”.

I am using an “extern” C++ library so I cannot name functions as I want.
I need to find the “C++ mangled name”.
What I came with is:

root [0] gInterpreter->Declare("void SomeFunction();");
root [1] gInterpreter->GetMangledName(0, "SomeFunction", "")
(TString) "_Z12SomeFunctionv"[17]

Is this o.k. or would you recommend something else / better?

BTW. How does one actually use “TInterpreter::GetMangledNameWithPrototype”?

Sounds fine!

Example use for GetMangledNameWithPrototype:

root [0] .rawInput
Using raw input
root [1] int SomeFunction() { return 42; }
root [2] .rawInput
Not using raw input
root [3] gInterpreter->GetMangledNameWithPrototype(nullptr, "SomeFunction", "")
(TString) "_Z12SomeFunctionv"[17]

Thanks. I think I finally start to understand how it works (in my earlier trials, I missed the requirement that “.rawInput” must be used, otherwise these “GetMangledName*” functions return empty strings):

root [0] gInterpreter->Declare("void SomeFunction();");
root [1] gInterpreter->Declare("void SomeFunction(int i);");
root [2] gInterpreter->Declare("void SomeFunction(double x, double y);");
root [3] gInterpreter->GetMangledName(nullptr, "SomeFunction", "")
(TString) "_Z12SomeFunctionv"[17]
root [4] gInterpreter->GetMangledName(nullptr, "SomeFunction", "1")
(TString) "_Z12SomeFunctioni"[17]
root [5] gInterpreter->GetMangledName(nullptr, "SomeFunction", "1.1")
(TString) "_Z12SomeFunctioni"[17]
root [6] gInterpreter->GetMangledName(nullptr, "SomeFunction", "1, 1")
(TString) "_Z12SomeFunctiondd"[18]
root [7] gInterpreter->GetMangledName(nullptr, "SomeFunction", "1.1, 1.1")
(TString) "_Z12SomeFunctiondd"[18]
root [8] gInterpreter->GetMangledNameWithPrototype(nullptr, "SomeFunction", "")
(TString) "_Z12SomeFunctionv"[17]
root [9] gInterpreter->GetMangledNameWithPrototype(nullptr, "SomeFunction", "int")
(TString) "_Z12SomeFunctioni"[17]
root [10] gInterpreter->GetMangledNameWithPrototype(nullptr, "SomeFunction", "double")
(TString) "_Z12SomeFunctioni"[17]
root [11] gInterpreter->GetMangledNameWithPrototype(nullptr, "SomeFunction", "int, int")
(TString) "_Z12SomeFunctiondd"[18]
root [12] gInterpreter->GetMangledNameWithPrototype(nullptr, "SomeFunction", "double, double")
(TString) "_Z12SomeFunctiondd"[18]

In one of your previous posts, you say that one could also use enable_if and constexpr. Could you give some examples (I guess this may be interesting for many people).

2 Likes

I was missing the point that you wanted to check for available definitions. SFINAE cannot (intentionally) check for that, it can only check whether there’s a declaration or not. And the link I gave for SFINAE is basically as good as it gets :wink:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.