Can I "include" headers of compiled custom library in a macro?

Hello.

I complied a library libABC.so and I used it in a maro like:

root -l libABC.so

then I can use classes from libABC.so in ROOT prompt like:

ClassABC* x = new ClassABC
 x->fun()
...

This works only without including ClassABC.h.
When ClassABC.h is included, ClassABC becomes a incomplete type ( since it’s defined in ClassABC.cxx) and has a problem with stl vector, here’s the first few lines of the error:

In module 'std' imported from input_line_1:1:
/usr/include/c++/7/bits/stl_vector.h:671:50: error: arithmetic on a pointer to an incomplete type 'MEEvent'
      { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
                         ~~~~~~~~~~~~~~~~~~~~~~~ ^
/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEReconstructManager.hh:44:40: note: in instantiation of member function 'std::vector<MEEvent, std::allocator<MEEvent> >::size' requested here
    int GetNLoaded(){return mEventData.size();}
                                       ^
libME dictionary forward declarations' payload:6:121: note: forward declaration of 'MEEvent'
class __attribute__((annotate("$clingAutoload$/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEEvent.hh")))  MEEvent;
                                                                                                                        ^
Error in <TInterpreter::AutoParse>: Error parsing payload code for class METrack with content:

#line 1 "libME dictionary payload"


#define _BACKWARD_BACKWARD_WARNING_H
// Inline headers
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEEvent.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEEventFactory.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEGUIFrame.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEGeoExtract.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MELib.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEManager.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEProcessedFile.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/MEReconstructManager.hh"
#include "/home/yanghang/Project/MuGrid-EventDisplayApp/app/include/METrack.hh"
...

This problem can be avoided by simply not including headers from my custom library, however, doing so disables the auto-completion feature of IDE. More importantly, these errors indicates that I may have done something in a wrong way.
My goal is to make this library behave like those built-in libraries of ROOT. For example, I can use TCanvas in macro with or without TCanvas.h included. What is the correct way to do so?

Thanks,
JINGYU

Do you header file have the usual code guards?

Yes, there are include guards.

As an update, I found that this problem will not occur if my custom class doesn’t have any std::vector members.

The error I see is:

error: arithmetic on a pointer to an incomplete type 'MEEvent'

which means that Cling has only seen a forward declaration of MEEvent and not a definition. (This is not yet complaining about the lack of implementation or .cxx).

And also

Error in <TInterpreter::AutoParse>: Error parsing payload code for class `METrack`

which means that when loading ClassABC.h, cling needs more information about METrack and thus started parsing the dictionary content.

During the parsing of one of the last file; MEReconstructManager.hh line 44, it need to instantiated the vector of MEEvent but fails because of the incomplete MEvent … which is odd since it is supposed to have parse MEEvent.hh before that.

This usually means that there is some sort of circular dependency invoving ClassABC.h, MEvent.hh and MEReconstructManager.hh. If you share the content of your header we might be able to determine what is going on.

Cheers,
Philippe.

The content of the headers:

MEEvent.hh

#pragma once
//#ifndef ME_FROM_MACRO

#include <vector>
#include <iostream>
#include "TROOT.h"
#include "TVector3.h"
#include "TVector2.h"
#include "TObject.h"
#include "METrack.hh"
using namespace std;


// Representation of a event
class MEEvent:public TObject{

    private:

    //Data of a event

    METrack mTracks;                  
    vector<vector<float>> mPoints;
    vector<vector<float>> mRawPoints;
    vector<vector<int>> mSignalMatrix;      
    vector<string> mListOfHitSiPMGroups;          // The groups that hit by muon
    bool mIsValid;
    double mAverageResidual;
    TVector2 projectPosition;

    public:

    void Print();
    

    
    MEEvent();
    MEEvent(METrack,vector<vector<float>>);
    ~MEEvent();

    //getters
    vector<vector<float>> GetPoints() const{return mPoints;}
    vector<vector<float>> GetRawPoints() const{return mRawPoints;}
    vector<vector<int>> GetSignalMatrix() const{return mSignalMatrix;}
    vector<string> GetHitSiPMGroups() const{return mListOfHitSiPMGroups;}
    TVector2 GetProjectedPosition() const{return projectPosition;}
    METrack GetTrack() const;
    double GetAverageResidual() const;

    //setters
    void SetSignalMatrix(vector<vector<int>> sm){mSignalMatrix=sm;}
    void SetTrack(METrack track){mTracks=track;}
    void SetPoints(vector<vector<float>> points){mPoints=points;}
    void SetRawPoints(vector<vector<float>> rawPoints){mRawPoints = rawPoints;}
    void SetValid(bool valid){mIsValid = valid;}
    void SetAverageResidual(double residual){mAverageResidual = residual;}
    void SetProjectedPosition(TVector2 p){projectPosition = p;}
    bool IsValid() const{return mIsValid;}
    void SetHitSiPMGroup(vector<string>& sipmGroup){mListOfHitSiPMGroups = sipmGroup;}

    void Dump();                                    //show all data in terminal

    ClassDef(MEEvent,1);

};

METrack.hh

#pragma once

#include "TVector3.h"

class METrack{
  public:
    TVector3 point;
    TVector3 direction;


    METrack();
    METrack(TVector3 pointVec,TVector3 dirVec);
  
    void Set(float pointX,float pointY,float pointZ,float dirX,float dirY,float dirZ);
    METrack operator- ();

    ClassDef(METrack,1);

};

MEReconstructManager.hh is a little bit massive, so I removed some of the irrelevent parts. I can post the full header if necessary.

#ifndef MEEventCache_hh
#define MEEventCache_hh 1

#include "MEEvent.hh"
#include "MEEventFactory.hh"
#include "MELib.hh"
#include "TVector3.h"
using namespace std;

class MEReconstructManager{

    private:

    vector<MEEvent> mEventData;
    int curPos;
    MEEventFactory mFactory;
    string curFileName;
    vector<TVector3> projectedPoints;


    public:

    MEReconstructManager();
    ~MEReconstructManager();

    int GetNLoaded(){return mEventData.size();}
    MEEventFactory& GetFactory(){return mFactory;}
    


    ClassDef(MEReconstructManager,1);
};

#endif

And finally MEEventFactory.hh

#pragma once

#include"MEEvent.hh"
#include"MELib.hh"//Only function definations in this header.
#include<map>
#include <vector>

using namespace std;

class MEEventFactory{

    private:

    //Parameters of reconstruction algorithm

    int threshold;                  //thresold of signal
    float correctionFactor;

    map<string,vector<float>> mSiPMPos;   //position coordinate of sipm
    map<string,int> channelMap;          //mapping sipm key to channel index.
    map<string,vector<string>> sipmGroup;


    public:

    MEEventFactory();
    ~MEEventFactory();




    MEEvent MakeEvent(const vector<int>& signalMatrix) const;        //take unrolled signal matrix as input
    MEEvent MakeEvent(TH1D signalMatrix) const;

    //getter
    map<string,vector<float>> GetPmtPos() const {return mSiPMPos;}

    //setter
    void SetThreshold(int t){threshold=t;}
    void SetCorrectionFactor(float t){correctionFactor=t;}

    //config
    void SetPmtPos(string fileName);
    void SetChannelMap(string fileName);
    void SetSiPMGroup(string fileName);

    tuple<vector<vector<int>>,vector<vector<vector<float>>>> Grouping (const vector<int>& signalVec) const;    //Enrolll vector into matrix
    vector<bool> GenerateThresholdMask(const vector<vector<int>>& signalMatrix,int threshold) const;

    ClassDef(MEEventFactory,1);
};

And following root macro (with .so loaded) causes the same error :upside_down_face:

#include "../MuGrid-EventDisplayApp/app/include/MEEvent.hh"
void testEvent(){
    MEEvent event();
}

Let’s try a couple of things:

{
    MEEvent event();
}

and then

R__LIBRARY_LOAD(libABC.so)
void testEvent(){
    MEEvent event();
}

and then

{
   #include "../MuGrid-EventDisplayApp/app/include/MEEvent.hh"
  gSystem->Load("libABC.so");
}

and then

{
   #include "MEEvent.hh"
  gSystem->Load("libABC.so");
}

For the first one:

Processing testEvent.cxx...
In file included from input_line_11:1:
/home/yanghang/Project/playground/testEvent.cxx:9:5: error: unknown type name 'MEEvent'
    MEEvent event;

For the second one.

In file included from input_line_11:1:
/home/yanghang/Project/playground/testEvent.cxx:11:18: warning: empty parentheses interpreted as a function declaration [-Wvexing-parse]
    MEEvent event();
                 ^~
/home/yanghang/Project/playground/testEvent.cxx:11:18: note: replace parentheses with an initializer to declare a variable
    MEEvent event();

No error from the last two. However, when I Added another line of “MEevent event;”, there was:

Processing testEvent.cxx...
In file included from input_line_11:1:
In file included from /home/yanghang/Project/playground/testEvent.cxx:8:
/home/yanghang/Project/playground/../MuGrid-EventDisplayApp/app/include/MEEvent.hh:37:5: warning: function 'testEvent()::MEEvent::MEEvent' has internal linkage but is not defined [-Wundefined-internal]
    MEEvent();
    ^
/home/yanghang/Project/playground/testEvent.cxx:13:13: note: used here
    MEEvent event;
            ^
In file included from input_line_11:1:
In file included from /home/yanghang/Project/playground/testEvent.cxx:8:
/home/yanghang/Project/playground/../MuGrid-EventDisplayApp/app/include/MEEvent.hh:39:5: warning: function 'testEvent()::MEEvent::~MEEvent' has internal linkage but is not defined [-Wundefined-internal]
    ~MEEvent();
    ^
/home/yanghang/Project/playground/testEvent.cxx:13:13: note: used here
    MEEvent event;
            ^
IncrementalExecutor::executeFunction: symbol '_ZZ9testEventvEN7MEEventD1Ev' unresolved while linking [cling interface function]!
You are probably missing the definition of testEvent()::MEEvent::~MEEvent()
Maybe you need to load the corresponding shared library?
IncrementalExecutor::executeFunction: symbol '_ZZ9testEventvEN7MEEventC1Ev' unresolved while linking [cling interface function]!
You are probably missing the definition of testEvent()::MEEvent::MEEvent()
Maybe you need to load the corresponding shared library?

I am bit confused. The first post says:

This works only without including ClassABC.h.
When ClassABC.h is included, ClassABC becomes a incomplete type

I tried to emulated the 2nd/bad case with the 3rd and 4th case but their work (the error mentioned linkage is still a bit concerning but seems different).

At this point I think the best would be if you produce a self contained reproducer so we can investigate further.

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