How to use linkdef.h

Dear experts,
I’m confused about linkdef.h. Seeing https://root.cern/manual/python/#loading-c-libraries-with-dictionaries , it seems that we don’t need to add ROOT.gInterpreter.ProcessLine() in the python file. But it doesn’t work without ROOT.gInterpreter.ProcessLine() , is there something wrong with my usage method?

#ifdef __CINT__
#pragma link C++ class MyClass;
#pragma link C++ function MyFunction;
#pragma link C++ global MyGlobal;
#endif

linkdef.h (127 Bytes)

__
Please read tips for efficient and successful posting and posting code

_ROOT Version:6.24/06
_Compiler:gcc version 8.3.0 (GCC)


Yes, you are on the right track!

You should also add this at the beginning right after #ifdef __CINT__:

// Standard preamble: turn off creation of dictionaries for "everything":
// we then turn it on only for the types we are interested in.
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

You can find some nice examples on how to generate your own dictionaries here:

If you are building your own library, I would recommend using cmake, like in this example.

Only that you are building a library and not an executable. So add_executable(readwrite_twoints readwrite_twoints.cpp twoints.cpp) has to be replaced with add_library(readwrite_twoints SHARED readwrite_twoints.cpp twoints.cpp) (and changing the filenames too obviously).

Feel free to follow up here if you have more questions!

Hi jonas
Thanks for your answer. I download the code in git and follow it’s steps, but I still meet some questions.

cmake_minimum_required(VERSION 3.9)
project (readwrite_twoints CXX)

message(STATUS “Looking for ROOT”)
find_package(ROOT REQUIRED COMPONENTS RIO)
add_library(readwrite_twoints SHARED readwrite_twoints.cpp twoints.cpp )
target_link_libraries(readwrite_twoints ROOT::RIO)
target_include_directories(readwrite_twoints PRIVATE
${CMAKE_CURRENT_SOURCE_DIR})
ROOT_GENERATE_DICTIONARY(twoints_dict twoints.hpp MODULE readwrite_twoints LINKDEF LinkDef.h)

this is my CMakeLists.txt, I only change the add_executable to add_library, and I get a libreadwrite_twoints.so, and I change main function to “f” function in readwrite_twoints.cpp

#include “TFile.h”
#include “twoints.hpp”
#include
int main(){return 0;}
int f() {
{
// write the ti object to an output file
TwoInts ti(1, 2);
TFile out_f(“f.root”, “recreate”);
out_f.WriteObjectAny(&ti, “TwoInts”, “ti”);
std::cout << “Written TwoInts(” << ti.GetA() << ", " << ti.GetB() << “)\n”;
}
TFile in_f(“f.root”);
auto *tiptr = in_f.Get(“ti”);
std::cout << “Read TwoInts(” << tiptr->GetA() << ", " << tiptr->GetB() << “)\n”;

                               return 0;
                               }

and I write a test.py in order to call this “f” function

import ROOT
ROOT.gSystem.Load('./build/libreadwrite_twoints.so')
ROOT.f()

but it doesn’t work

Traceback (most recent call last):
File “/scratchfs/cepc/wangshengyi/test/cmake2/test.py”, line 5, in
ROOT.f()
File “/cvmfs/sft.cern.ch/lcg/releases/ROOT/6.24.06-3455f/x86_64-centos7-gcc8-opt/lib/ROOT/_facade.py”, line 192, in _fallback_getattr
raise AttributeError(“Failed to get attribute {} from ROOT”.format(name))
AttributeError: Failed to get attribute f from ROOT

but it work when I add this line in my python file

ROOT.gInterpreter.ProcessLine('#include "./readwrite_twoints.cpp"')

I think using linkdef can omit this line, or Is my usage wrong?

Hi, you are still missing a function declaration in the header, otherwise it doesn’t get picked up by the dictionary generation. If you add a line with int f(); to twoints.hpp it should work!

Hi jonas
Thanks to your advice, the question is solved! I add

int f();

in .hpp and add

#pragma link C++ function f;

in LinkDef.h, and now I can call the function “f” in python without ROOT.gInterpreter.ProcessLine().

By the way, is every c++ function and class needed to be added in LinkDef.h before we call it in the python file?

Cheers,
ShengYi