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:
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?
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:
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.
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.