Uploaded image for project: 'ROOT'
  1. ROOT
  2. ROOT-8719

rootcling failes to parse files which include Qt5 headers if Qt5 was built with -reduce-relocations

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: High
    • Resolution: Won't Fix
    • Affects Version/s: 6.08/06, 6.09/02
    • Fix Version/s: None
    • Component/s: Dictionaries
    • Labels:
      None
    • Environment:

      Arch Linux x86_64
      GCC 6.3.0
      Qt 5.8.0 (built with -reduce-relocations)

      Description

      I've been scratching my head how to workaround the following problem. This may not actually be a problem with ROOT, but I would really appreciate it if you could take a look and let me know if you have some idea for a workaround.

      Let us say you have a class declared in a header file wich looks like this:

      #ifndef MyClass_hh
      #define MyClass_hh
       
      #include <QtCore/qglobal.h>
       
      class MyClass {
      public:
        MyClass();
        ~MyClass();
       
      private:
        ClassDef(MyClass, 1)
      };
       
      #endif

      with Linkdef.h

      #ifndef Linkdef_h
      #define Linkdef_h
       
      #pragma link C++ nestedclass;
      #pragma link C++ nestedtypedefs;
       
      #pragma link off all globals;
      #pragma link off all classes;
      #pragma link off all functions;
       
      #pragma link C++ class MyClass;
       
      #endif

      And you want to make root dictionary from this class:

      rootcling -f MyClassDict.cc -I/usr/include/qt MyClass.hh Linkdef.h

      Then, this will fail if Qt5 version is recent enough (I have 5.8 but 5.5 should also work) and Qt5 was built with "-reduce-relocations" in its configure flags. The reason is that, if '-reduce-relocations' was used to build Qt5, then "qconfig.h" header (indirectly included in qglobal.h) will include a line that defines QT_REDUCE_RELOCATIONS. And then the problem is that "qglobal.h" uses "#error" to abort compilation unless the user code is compiled with -fPIC. Here's the relevant section of qglobal.h:

      #if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && \
          (!defined(__PIC__) || (defined(__PIE__) && defined(Q_CC_GNU) && Q_CC_GNU >= 500))
      #  error "You must build your code with position independent code if Qt was built with -reduce-relocations. "\
               "Compile your code with -fPIC (-fPIE is not enough)."
      #endif

      Now I admit that this is a nasty thing that they added in Qt. Here are some references:

      https://bugreports.qt.io/browse/QTBUG-45755
      https://bugs.archlinux.org/task/45283

      which explain the rationale behind the code above. But I have to find a way to workaround this issue. We are already compiling all our code with -fPIC. The MyClassDict.cxx would also be compiled with -fPIC, if it were created. The issue is that the rootcling invocation which generates MyClassDict.cxx does not define "_PIC_" and I can't add -fPIC to the rootcling flags since that flag is ignored (see rootcling_impl.cxx "ShouldIgnoreClingArgument").

      It works when I add "-D_PIC_" to the rootcling arguments, but that's an ugly hack:

      rootcling -f MyClassDict.cc -D__PIC__ -I/usr/include/qt MyClass.hh Linkdef.h

      And things are actually even more complicated. While defining _PIC_ on the rootcling commandline works around this particular problem, it doesn't help when trying to compile a macro with TSystem::CompileMacro("macro.C", "kf"), since that will internally construct a rootcling call with some fixed arguments which I can't change, so I don't know how I would inject "-D_PIC_" there.

      The next thing I tried is to write a "qglobal.h" wrapper and put it in a place that comes first in my include path. It looks like this:

      #ifndef __qglobal_wrapper__
      #define __qglobal_wrapper__
       
      // If Qt5 is build with '-reduce-relocations', then user code must be compiled with -fPIC, which we do.
      // However, rootcint / rootcling in ROOT 6 uses clang to preprocess the source files and there is no way
      // to pass -fPIC to clang as used in rootcint.
      // Workaround this by defining __PIC__ manually.
      #if defined(__CLING__) && !defined(__PIC__)
       
      #define __PIC__
      #include_next <QtCore/qglobal.h>
      #undef __PIC__
       
      #else
       
      #include_next <QtCore/qglobal.h>
       
      #endif
       
      #endif

      Now this makes things mostly work, but there are some macros which I can't compile with ACLiC anymore, because after the macro_C.so is generated in TSystem::CompileMacro() it gets loaded with "gSystem->Load()" and in this step root.exe crashes with a segmentation violation, possibly due to the _PIC_ define?!

      Now I'm really lost and have no more ideas...

        Attachments

          Activity

            People

            Assignee:
            axel Axel Naumann
            Reporter:
            bbeische Bastian Beischer
            Votes:
            2 Vote for this issue
            Watchers:
            5 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: