Problem compiling RooFit with ACLiC

Hi, ROOT’ers

I created pdf via RooClassFactory::makePdf method (in ROOT session):

RooClassFactory::makePdf( "dummy", "x,a" );

Then I want to create a shared library with ACLiC. I used to separate header files from its sources. So I place class declaration inside inc dir and its definition inside src dir. Here is the structure:

testCompile/
├── inc
│   └── dummy.h
└── src
    └── dummy.cxx

2 directories, 2 files

NOTE: I changed include directive in dummy.cxx so path is OK.

Then I try to compile the source file so I do in ROOT session (from src dir):

.L dummy.cxx+

Here is the output:

Info in TUnixSystem::ACLiC: creating shared library /home/lrdprdx/BINP/projects/Scintibrary/RooFit/testCompile/srs/./dummy_cxx.so

RooFit v3.60 – Developed by Wouter Verkerke and David Kirkby
Copyright (C) 2000-2013 NIKHEF, University of California & Stanford University
All rights reserved, please read http://roofit.sourceforge.net/license.txt

cling::DynamicLibraryManager::loadLibrary(): /home/lrdprdx/BINP/projects/Scintibrary/RooFit/testCompile/srs/dummy_cxx.so: undefined symbol: _ZN5dummy8StreamerER7TBuffer
/usr/lib/gcc/x86_64-linux-gnu/5/…/…/…/x86_64-linux-gnu/crt1.o: In function _start': (.text+0x20): undefined reference to main’
/home/lrdprdx/BINP/projects/Scintibrary/RooFit/testCompile/srs/dummy_cxx_ACLiC_dict.o: In function __static_initialization_and_destruction_0(int, int)': dummy_cxx_ACLiC_dict.cxx:(.text+0x350): undefined reference to ROOT::GenerateInitInstance(dummy const*)’
/home/lrdprdx/BINP/projects/Scintibrary/RooFit/testCompile/srs/dummy_cxx_ACLiC_dict.o: In function dummy::IsA() const': dummy_cxx_ACLiC_dict.cxx:(.text._ZNK5dummy3IsAEv[_ZNK5dummy3IsAEv]+0xd): undefined reference to dummy::Class()’
/home/lrdprdx/BINP/projects/Scintibrary/RooFit/testCompile/srs/dummy_cxx_ACLiC_dict.o: In function dummy::ShowMembers(TMemberInspector&) const': dummy_cxx_ACLiC_dict.cxx:(.text._ZNK5dummy11ShowMembersER16TMemberInspector[_ZNK5dummy11ShowMembersER16TMemberInspector]+0x11): undefined reference to dummy::Class()’
/home/lrdprdx/BINP/projects/Scintibrary/RooFit/testCompile/srs/dummy_cxx_ACLiC_dict.o:(.rodata._ZTV5dummy[_ZTV5dummy]+0x1e0): undefined reference to dummy::Streamer(TBuffer&)' /home/lrdprdx/BINP/projects/Scintibrary/RooFit/testCompile/srs/dummy_cxx_ACLiC_dict.o:(.rodata._ZTV5dummy[_ZTV5dummy]+0x660): undefined reference to non-virtual thunk to dummy::Streamer(TBuffer&)’
collect2: error: ld returned 1 exit status

All is OK if I don’t separate header from source. I suspect that all the stuff due to the ClassDef macro but I am not sure. So is it possible to compile a .so file having headers and sources separated?

Thanks in advance.

Does the generated code contain the ClassDef macro in the header, and the ClassImp macro in the source file?

Yes, it does. The first line (after directives) in dummy.cxx is the following:

ClassImp(dummy);

Hi @p73,

There are several possibilities, but you don’t give much information. Here are some ideas:

  • It could be that something is wrong in the header/implementation:
    – ClassDef / ClassImp are in the wrong place
    – The class name is wrong (Try something else than dummy maybe?)
    – What is the class version in the ClassDef macro? Did you use something else than 0?
  • The include directive is wrong. Do you know where root is searching for headers? (gSystem->GetIncludePath())
  • Does the result of the above match what you expect?
  • Does the include path you used resolve to something reasonable relative to the include search directory?
  • Are you using root from a package that contains all relevant libraries or did you compile yourself and something might be missing?

First of all, I do not provide much information because I am using standard way to build the code, namely RooClassFactory.

Now about your ideas. From bottom to top.

I compiled ROOT myself with the all=ON option so I don’t think it’s the point.

Include path is OK because I use thisroot.sh script and some additional configuration such as CPLUS_INCLUDE_PATH variable.

Again I use the RooClassFactory::makePdf method to build the code. Of course, I don’t know much about all the stuff behind the scene but I want to notice that If header and source in the same directory all compiles fine.

You can (I hope) easily reproduce the issue by the following actions.
Open ROOT interactive session. Then type:

RooClassFactory::makePdf( "some_name", "x,a" );

You should see then in your directory two files

some_name.h
some_name.cxx

Then try to compile it with ACLiC. In ROOT session type

.L some_name.cxx+

It should compile.

BUT. If you only separate the header and the source, say, you placed some_name.h in the inc dir and the some_name.cxx in the src (only you need to change the #include a little in some_name.cxx from #include "some_name.h" to #include "../inc/some_name.h") and try to compile with the above procedure it won’t compile.

The problem is in the include path, though. This is because root does not only compile (CPLUS_INCLUDE_PATH), it also has to generate a dictionary with information about the new class. This requires information about where the headers are.

Following your instructions and my question about gSystem->GetIncludePath(), I found this on my computer:

$ root -l
root [5] gSystem->GetIncludePath()
-I$ROOTSYS/include -I"/Users/user/code/root-release/etc" -I"/Users/user/code/root-release/etc/cling" -I"/Users/user/code/root-release/include" -I"/usr/include"

At this point, it’s missing the relevant directory. So I add it using this:

root [0] gSystem->AddIncludePath("-I/Users/user/code/root-release/testClassFactory/inc")
root [1] .L some_name.cxx+
Info in <TMacOSXSystem::ACLiC>: creating shared library /Users/user/code/root-release/testClassFactory/src/./some_name_cxx.so

RooFit v3.60 -- Developed by Wouter Verkerke and David Kirkby 
                Copyright (C) 2000-2013 NIKHEF, University of California & Stanford University
                All rights reserved, please read http://roofit.sourceforge.net/license.txt

root [2] .q

If you do it like this, there’s no need to change the include statement in the cxx.

Thank you for your work. I see I should learn the ACLiC more deeply.

Which information about ACLiC did you use? Maybe this needs updating or more information?

Hm… I just used the info that ACLiC can generate dictionary for me with the + sign at the end of file. (:
I didn’t dive into how it really works. OK. I will learn.

Ok, you can check this out:
https://root.cern.ch/root/htmldoc/guides/users-guide/Cling.html#aclic-compiling-scripts-into-libraries

9.4.2 has more information about the include path.

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