TGMainFrame undefined reference to vtable

Hi.
I am trying to compile a graphical user interface that was working in 2017 (I don’t know on which machine).
Now I got compilation errors that seems to be due to the inheritance of my class from TGMainframe.

The code can be found here: https://gitlab.cern.ch/eshields/tb24-tracking/-/blob/EventDisplay_development/README.md?ref_type=heads

I reduced the code to a minimum (MyMainFrame.h and MyMainFrame.cpp) and it gives the following error:

/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `vtable for Tracking::MyMainFrame'
/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `TGMainFrame::TGMainFrame(TGWindow const*, unsigned int, unsigned int, unsigned int)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/BuildTracks.dir/build.make:117: BuildTracks] Error 1
make[1]: *** [CMakeFiles/Makefile2:138: CMakeFiles/BuildTracks.dir/all] Error 2

I hope you can help.
Thank you
Best regards

_ROOT Version: 6.30/02
_Platform: linux
_Compiler: g++ (GCC) 13.1.0

@bellenot, our GUI expert, is on vacation right now. He will help you when he will be back.

Hi @mole.luca,

are those the only errors or there are some other warnings as well?
I tried downloading your branch on lxplus and compiling it and I get warnings such as:

The C++ standard in this build does not match ROOT configuration (202002L); this might cause unexpected issues

which might be related to your issue.

Aside that, you could try marking your class’s destructor as override and use ClassDefOverride, like you see in this tutorial.

Also, make sure you are linking against -lGui (but it seems like you are so I doubt that’s the issue)

1 Like

Hi @silverweed, thank you for checking this.
Indeed I get the same warning

The C++ standard in this build does not match ROOT configuration (202002L); this might cause unexpected issues

What can I do to match the ROOT configuration in the C++ standard?

I will also try to mark the class destructor as you suggest.

I implemented the suggested change, marking class destructor as override and using ClassDefOverride. You can see the change in git.
I now get a different error:

/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `non-virtual thunk to Tracking::MyMainFrame::Streamer(TBuffer&)'
/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `Tracking::MyMainFrame::Streamer(TBuffer&)'
/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `Tracking::MyMainFrame::Class()'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/BuildTracks.dir/build.make:117: BuildTracks] Error 1
make[1]: *** [CMakeFiles/Makefile2:140: CMakeFiles/BuildTracks.dir/all] Error 2

@mole.luca try adding your class to dict/TB24TrackingLinkDef.h:

diff --git a/dict/TB24TrackingLinkDef.h b/dict/TB24TrackingLinkDef.h
index d2d39f6..21bb650 100644
--- a/dict/TB24TrackingLinkDef.h
+++ b/dict/TB24TrackingLinkDef.h
@@ -8,5 +8,6 @@
 #pragma link C++ class Tracking::Cluster+;
 #pragma link C++ class Tracking::Track+;
 #pragma link C++ class Tracking::Event+;
+#pragma link C++ class Tracking::MyMainFrame+;
1 Like

@silverweed, thank you for the suggestion. It seems that this solved part of the problem.
Now I get this error:

[100%] Linking CXX executable EventDisplay
/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: /lib/../lib64/crt1.o: in function `_start':
(.text+0x1b): undefined reference to `main'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/EventDisplay.dir/build.make:117: EventDisplay] Error 1
make[1]: *** [CMakeFiles/Makefile2:166: CMakeFiles/EventDisplay.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

Cheers

@mole.luca you implemented the main function in the namespace Tracking. If you move it outside of it it should compile.

Hi @silverweed.
In main.cpp I see that there is no namespace Tracking. Am I missing something?
Thank you

@mole.luca it’s in tools/EventDisplay.cpp.

Thanks @silverweed. Got it. Now I removed the namespace and I get the following

/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `non-virtual thunk to MyMainFrame::Streamer(TBuffer&)'
/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `MyMainFrame::Class()'
/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `MyMainFrame::Streamer(TBuffer&)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/BuildTracks.dir/build.make:117: BuildTracks] Error 1
make[1]: *** [CMakeFiles/Makefile2:140: CMakeFiles/BuildTracks.dir/all] Error 2

Weird, this is the same error as before…
I tried doing all the steps (adding the class dictionary and removing the namespace from main) and it compiles fine for me.
Can you please show me the output of git diff from the branch you posted in the OP to the changes you made so far?

Hi @silverweed. Here is the git diff.
Thank you

diff --git a/dict/TB24TrackingLinkDef.h b/dict/TB24TrackingLinkDef.h
index d2d39f6..21bb650 100644
--- a/dict/TB24TrackingLinkDef.h
+++ b/dict/TB24TrackingLinkDef.h
@@ -8,5 +8,6 @@
 #pragma link C++ class Tracking::Cluster+;
 #pragma link C++ class Tracking::Track+;
 #pragma link C++ class Tracking::Event+;
+#pragma link C++ class Tracking::MyMainFrame+;
 
 #endif
diff --git a/tools/EventDisplay.cpp b/tools/EventDisplay.cpp
index 3411f73..88d1d6d 100644
--- a/tools/EventDisplay.cpp
+++ b/tools/EventDisplay.cpp
@@ -21,8 +21,6 @@
 #include "hit.h"
 #include "TGFrame.h"
 
-namespace Tracking {
-
 int main(int argc, char **argv) {
   std::cout<<"Starting EventDisplay..."<<std::endl;
 
@@ -45,5 +43,3 @@ int main(int argc, char **argv) {
 
   return 0;
 }
-
-}
\ No newline at end of file

@mole.luca did you remember to make this change as well?

@@ -40,10 +39,9 @@ int main(int argc, char **argv) {

   std::string fname_in = std::string(argv[1]);
   TApplication theApp("App",&argc,argv);
-  new MyMainFrame(gClient->GetRoot(),500,500,fname_in.c_str());
+  new Tracking::MyMainFrame(gClient->GetRoot(),500,500,fname_in.c_str());
1 Like

Hi @silverweed. That line was actually commented out.
Now I took care that all the changes are in git. When I compile I get this error:

/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `typeinfo for Tracking::MyMainFrame'
/cvmfs/sft.cern.ch/lcg/releases/binutils/2.40-acaab/x86_64-el9/bin/ld: libTB24TrackingLib.so: undefined reference to `vtable for Tracking::MyMainFrame'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/BuildTracks.dir/build.make:117: BuildTracks] Error 1
make[1]: *** [CMakeFiles/Makefile2:140: CMakeFiles/BuildTracks.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

@mole.luca it looks like you’re not defining ~MyMainFrame(). Try:

diff --git a/src/MyMainFrame.h b/src/MyMainFrame.h
index 6ec7b02..5d21ca4 100644
--- a/src/MyMainFrame.h
+++ b/src/MyMainFrame.h
@@ -31,7 +31,7 @@ protected:

  public:
   MyMainFrame(const TGWindow *p,UInt_t w,UInt_t h,const char* fname_in);
-  ~MyMainFrame() override;
+  ~MyMainFrame() override = default;
   void ProcessEvent(int NextFlag);
   ClassDefOverride(MyMainFrame, 0)
 };
1 Like

Hi @silverweed.
This worked, now it compiles fine.
Can you please tell briefly what is the override doing and why the default made the difference (it is not there in the example that you referred to)?
Thank you

@mole.luca the difference was actually made by = default, which tells the compiler to define the destructor, rather than just declare it (and in this case, since it’s a trivial destructor, I believe the entire line could actually be removed with no consequence). If you declare a function and don’t implement it, you’ll get linking errors like the one above.

The override specifier is just a way to tell the compiler: “this method is a virtual method that exists in my parent class and I’m overriding it”. It is technically optional but it’s good practice to use it, since it acts as documentation and it becomes an error if the method is not really overriding a virtual method as intended.

1 Like

Hi @silverweed.
Thank you for the help and for the clear explanation.
Best regards

Hi again. After compiling I incur into segmentation violation.
Commenting it out piece by piece I noticed that it is due to this line

fEc1 = new TRootEmbeddedCanvas("ec1", fcomposite2, 6000, 6000);

To confirm that it is not only a problem of my code, I run the example.C script from this tutorial.
The result is similar, i.e. I get segmentation violation because of this line:

fEcanvas = new TRootEmbeddedCanvas("Ecanvas",fMain,200,200);

In both cases it is related to the TRootEmbeddedCanvas declaration.
Here is the error for the latter case:

*** Break *** segmentation violation



===========================================================
There was a crash.
This is the entire stack trace of all threads:
===========================================================
#0  0x00007f11ff8d89fa in wait4 () from /lib64/libc.so.6
#1  0x00007f11ff84b243 in do_system () from /lib64/libc.so.6
#2  0x00007f1201b12519 in TUnixSystem::StackTrace() () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libCore.so
#3  0x00007f1201b11ed4 in TUnixSystem::DispatchSignals(ESignals) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libCore.so
#4  <signal handler called>
#5  0x00007f11f8b7f633 in asim_parse_argb_color () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#6  0x00007f11f8bd410c in build_xpm_colormap () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#7  0x00007f11f8baffc8 in xpm_file2ASImage () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#8  0x00007f11f8bb0176 in xpm2ASImage () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#9  0x00007f11f8bb12cc in file2ASImage_extra () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#10 0x00007f11f8b71f2f in TASImage::ReadImage(char const*, TImage::EImageFileTypes) () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#11 0x00007f1200d38a1b in TImage::Open(char const*, TImage::EImageFileTypes) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGraf.so
#12 0x00007f12020ee2fa in TGPicturePool::GetPicture(char const*) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#13 0x00007f12020f68fc in TGHScrollBar::TGHScrollBar(TGWindow const*, unsigned int, unsigned int, unsigned int, unsigned long) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#14 0x00007f1202001cf7 in TGCanvas::TGCanvas(TGWindow const*, unsigned int, unsigned int, unsigned int, unsigned long) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#15 0x00007f120219e8c6 in TRootEmbeddedCanvas::TRootEmbeddedCanvas(char const*, TGWindow const*, unsigned int, unsigned int, unsigned int, unsigned long) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#16 0x00000000004022ec in MyMainFrame_ex::MyMainFrame_ex(TGWindow const*, unsigned int, unsigned int) ()
#17 0x0000000000402553 in main ()
===========================================================


The lines below might hint at the cause of the crash. If you see question
marks as part of the stack trace, try to recompile with debugging information
enabled and export CLING_DEBUG=1 environment variable before running.
You may get help by asking at the ROOT forum https://root.cern/forum
preferably using the command (.forum bug) in the ROOT prompt.
Only if you are really convinced it is a bug in ROOT then please submit a
report at https://root.cern/bugs or (preferably) using the command (.gh bug) in
the ROOT prompt. Please post the ENTIRE stack trace
from above as an attachment in addition to anything else
that might help us fixing this issue.
===========================================================
#5  0x00007f11f8b7f633 in asim_parse_argb_color () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#6  0x00007f11f8bd410c in build_xpm_colormap () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#7  0x00007f11f8baffc8 in xpm_file2ASImage () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#8  0x00007f11f8bb0176 in xpm2ASImage () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#9  0x00007f11f8bb12cc in file2ASImage_extra () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#10 0x00007f11f8b71f2f in TASImage::ReadImage(char const*, TImage::EImageFileTypes) () from /cvmfs/sft.cern.ch/lcg/releases/ROOT/6.30.02-fb5be/x86_64-el9-gcc13-opt/lib/libASImage.so
#11 0x00007f1200d38a1b in TImage::Open(char const*, TImage::EImageFileTypes) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGraf.so
#12 0x00007f12020ee2fa in TGPicturePool::GetPicture(char const*) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#13 0x00007f12020f68fc in TGHScrollBar::TGHScrollBar(TGWindow const*, unsigned int, unsigned int, unsigned int, unsigned long) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#14 0x00007f1202001cf7 in TGCanvas::TGCanvas(TGWindow const*, unsigned int, unsigned int, unsigned int, unsigned long) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#15 0x00007f120219e8c6 in TRootEmbeddedCanvas::TRootEmbeddedCanvas(char const*, TGWindow const*, unsigned int, unsigned int, unsigned int, unsigned long) () from /cvmfs/sft.cern.ch/lcg/releases/LCG_105/ROOT/6.30.02/x86_64-el9-gcc13-opt/lib/libGui.so
#16 0x00000000004022ec in MyMainFrame_ex::MyMainFrame_ex(TGWindow const*, unsigned int, unsigned int) ()
#17 0x0000000000402553 in main ()
===========================================================

You can find the full code here.
I hope you can help me to spot the problem.
Thank you