Fail to link GUI example

Hi,
I try to compile the GUI example buttonTest.C
At the prompt it work using .x buttonTest.C++
But if I had a main and try to compile:
produit@yoga$ c++ buttonTest.C (root-config --cflags) (root-config --glibs)
/usr/bin/ld: /tmp/ccNjYcVb.o: warning: relocation against _ZTV12ButtonWindow' in read-only section .text’
/usr/bin/ld: /tmp/ccNjYcVb.o: in function ButtonWindow::ButtonWindow()': buttonTest.C:(.text+0x60): undefined reference to vtable for ButtonWindow’
/usr/bin/ld: buttonTest.C:(.text+0x71): undefined reference to vtable for ButtonWindow' /usr/bin/ld: /tmp/ccNjYcVb.o: in function TextMargin::TextMargin(TGWindow const*, char const*)‘:
buttonTest.C:(.text._ZN10TextMarginC2EPK8TGWindowPKc[_ZN10TextMarginC5EPK8TGWindowPKc]+0x50): undefined reference to vtable for TextMargin' /usr/bin/ld: buttonTest.C:(.text._ZN10TextMarginC2EPK8TGWindowPKc[_ZN10TextMarginC5EPK8TGWindowPKc]+0x5e): undefined reference to vtable for TextMargin’
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status

I can solve some problems by using -fPIC (why it is not given by root-config?)
produit@yoga$ c++ buttonTest.C (root-config --cflags) (root-config --glibs) -f PIC
c++: error: unrecognized command-line option ‘-f’
produit@yoga$ c++ buttonTest.C (root-config --cflags) (root-config --glibs) -fPIC
/usr/bin/ld: /tmp/ccBRVDtf.o: in function ButtonWindow::ButtonWindow()': buttonTest.C:(.text+0x60): undefined reference to vtable for ButtonWindow’
/usr/bin/ld: buttonTest.C:(.text+0x75): undefined reference to vtable for ButtonWindow' /usr/bin/ld: /tmp/ccBRVDtf.o: in function TextMargin::TextMargin(TGWindow const*, char const*)‘:
buttonTest.C:(.text._ZN10TextMarginC2EPK8TGWindowPKc[_ZN10TextMarginC5EPK8TGWindowPKc]+0x50): undefined reference to vtable for TextMargin' /usr/bin/ld: buttonTest.C:(.text._ZN10TextMarginC2EPK8TGWindowPKc[_ZN10TextMarginC5EPK8TGWindowPKc]+0x62): undefined reference to vtable for TextMargin’
collect2: error: ld returned 1 exit status

_ROOT Version: 6.24/06
_Platform: Ubuntu 22.04.1 LTS
_Compiler: gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)


Hi @produit ,

indeed I get the same with my ROOT build, after adding a main function at the end of tutorials/gui/buttonTest.C:

$ g++ buttonTest.C $(root-config --libs --cflags --glibs)
/usr/bin/ld: /tmp/ccIsXq8F.o: warning: relocation against `_ZTV12ButtonWindow' in read-only section `.text'
/usr/bin/ld: /tmp/ccIsXq8F.o: in function `ButtonWindow::ButtonWindow()':
buttonTest.C:(.text+0x5c): undefined reference to `vtable for ButtonWindow'
/usr/bin/ld: buttonTest.C:(.text+0x6d): undefined reference to `vtable for ButtonWindow'
/usr/bin/ld: /tmp/ccIsXq8F.o: in function `TextMargin::TextMargin(TGWindow const*, char const*)':
buttonTest.C:(.text._ZN10TextMarginC2EPK8TGWindowPKc[_ZN10TextMarginC5EPK8TGWindowPKc]+0x4c): undefined reference to `vtable for TextMargin'
/usr/bin/ld: buttonTest.C:(.text._ZN10TextMarginC2EPK8TGWindowPKc[_ZN10TextMarginC5EPK8TGWindowPKc]+0x5a): undefined reference to `vtable for TextMargin'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status

The warnings and errors are due to two classes (TextMargin and ButtonWindow) having a ClassDef – it looks like cling and ACLiC can deal with it just fine but g++ cannot. @Axel @pcanal @bellenot do you have any more insight into what’s going on?

Cheers,
Enrico

P.S.

as far as I can tell, the ClassDefs are not needed and buttonTest.C can be compiled as a standalone program and runs correctly with these changes:

diff --git a/tutorials/gui/buttonTest.C b/tutorials/gui/buttonTest.C
index bbd0134299..2c72b8dd83 100644
--- a/tutorials/gui/buttonTest.C
+++ b/tutorials/gui/buttonTest.C
@@ -36,7 +36,6 @@ public:
    }
    TGTextEntry *GetEntry() const { return fEntry->GetNumberEntry(); }

-   ClassDef(TextMargin, 0)
 };

 ////////////////////////////////////////////////////////////////////////////////
@@ -54,7 +53,6 @@ public:
    void DoTopMargin(char*);
    void DoBottomMargin(char*);

-   ClassDef(ButtonWindow, 0)
 };


@@ -234,3 +232,9 @@ void buttonTest()

    new ButtonWindow();
 }
+
+int main() {
+   TApplication app("app", nullptr, nullptr);
+   buttonTest();
+   app.Run();
+}

Hi Nicolas,

This example was not intended to be built. To compile it, you need to create a dictionary for the two classes. To do so, move their definition in a header file (e.g. buttonTest.h) and create a Linkdef.h file containing the following code:

#ifdef __CINT__
#pragma link C++ class TextMargin;
#pragma link C++ class ButtonWindow;
#endif

Then create the dictionary with:

rootcling -f buttonTestDict.cxx buttonTest.h Linkdef.h

And finally:

g++ buttonTest.C buttonTestDict.cxx $(root-config --libs --cflags --glibs)

That should work (hopefully).

Cheers, Bertrand.

The linkdef fragment can be improved as follow:

#ifdef __ROOTCLING__
#pragma link C++ class TextMargin+;
#pragma link C++ class ButtonWindow+;
#endif

@pcanal Out of curiosity, for a “ClassDef(..., 0)” (i.e., no I/O, dummy streamer), why do you want the “+”?

I missed the 0 (read too fast), so indeed in this case it makes no practical difference. However since it makes no difference I prefer to recommend the ‘default/recommended’ syntax (and it would make a difference it such a class is then has its version number incremented)

Thanks,
for me removing the classdef is the most simple solution.

Cheers