Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-96513

CI: qmake examples should not be built from tainted source tree

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 6.2.5
    • 6.2.0 Beta4
    • Build System: CMake
    • None
    • All

    Description

      In the CI, we're building the examples with CMake in-source.
      Then, we're building the examples with qmake out-of-source, meaning that the qmake build will operate on a source directory, tainted with generated files.

      This is not only ugly, but leads to actual problems:

      https://codereview.qt-project.org/c/qt/qtbase/+/370280
      tries to remove .qmake.conf from qtbase, however it fails when building the dbus/chat example with qmake:

      agent:2021/09/13 13:33:07 build.go:391: 	link /NOLOGO /DYNAMICBASE /NXCOMPAT /OPT:REF /OPT:ICF /INCREMENTAL:NO /SUBSYSTEM:WINDOWS "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /MANIFEST:embed /OUT:release\chat.exe @C:\Users\qt\AppData\Local\Temp\chat.exe.1620.412110.jom
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_interface.obj : error LNK2005: "private: static void __cdecl OrgExampleChatInterface::qt_static_metacall(class QObject *,enum QMetaObject::Call,int,void * *)" (?qt_static_metacall@OrgExampleChatInterface@@CAXPEAVQObject@@W4Call@QMetaObject@@HPEAPEAX@Z) already defined in chat_interface.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_interface.obj : error LNK2005: "public: void __cdecl OrgExampleChatInterface::action(class QString const &,class QString const &)" (?action@OrgExampleChatInterface@@QEAAXAEBVQString@@0@Z) already defined in chat_interface.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_interface.obj : error LNK2005: "public: void __cdecl OrgExampleChatInterface::message(class QString const &,class QString const &)" (?message@OrgExampleChatInterface@@QEAAXAEBVQString@@0@Z) already defined in chat_interface.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_interface.obj : error LNK2005: "public: virtual struct QMetaObject const * __cdecl OrgExampleChatInterface::metaObject(void)const " (?metaObject@OrgExampleChatInterface@@UEBAPEBUQMetaObject@@XZ) already defined in chat_interface.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_interface.obj : error LNK2005: "public: virtual int __cdecl OrgExampleChatInterface::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@OrgExampleChatInterface@@UEAAHW4Call@QMetaObject@@HPEAPEAX@Z) already defined in chat_interface.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_interface.obj : error LNK2005: "public: virtual void * __cdecl OrgExampleChatInterface::qt_metacast(char const *)" (?qt_metacast@OrgExampleChatInterface@@UEAAPEAXPEBD@Z) already defined in chat_interface.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_interface.obj : error LNK2005: "public: static struct QMetaObject const OrgExampleChatInterface::staticMetaObject" (?staticMetaObject@OrgExampleChatInterface@@2UQMetaObject@@B) already defined in chat_interface.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_adaptor.obj : error LNK2005: "private: static void __cdecl ChatAdaptor::qt_static_metacall(class QObject *,enum QMetaObject::Call,int,void * *)" (?qt_static_metacall@ChatAdaptor@@CAXPEAVQObject@@W4Call@QMetaObject@@HPEAPEAX@Z) already defined in chat_adaptor.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_adaptor.obj : error LNK2005: "public: void __cdecl ChatAdaptor::action(class QString const &,class QString const &)" (?action@ChatAdaptor@@QEAAXAEBVQString@@0@Z) already defined in chat_adaptor.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_adaptor.obj : error LNK2005: "public: void __cdecl ChatAdaptor::message(class QString const &,class QString const &)" (?message@ChatAdaptor@@QEAAXAEBVQString@@0@Z) already defined in chat_adaptor.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_adaptor.obj : error LNK2005: "public: virtual struct QMetaObject const * __cdecl ChatAdaptor::metaObject(void)const " (?metaObject@ChatAdaptor@@UEBAPEBUQMetaObject@@XZ) already defined in chat_adaptor.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_adaptor.obj : error LNK2005: "public: virtual int __cdecl ChatAdaptor::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@ChatAdaptor@@UEAAHW4Call@QMetaObject@@HPEAPEAX@Z) already defined in chat_adaptor.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_adaptor.obj : error LNK2005: "public: virtual void * __cdecl ChatAdaptor::qt_metacast(char const *)" (?qt_metacast@ChatAdaptor@@UEAAPEAXPEBD@Z) already defined in chat_adaptor.obj
      agent:2021/09/13 13:33:07 build.go:391: moc_chat_adaptor.obj : error LNK2005: "public: static struct QMetaObject const ChatAdaptor::staticMetaObject" (?staticMetaObject@ChatAdaptor@@2UQMetaObject@@B) already defined in chat_adaptor.obj
      agent:2021/09/13 13:33:07 build.go:391: release\chat.exe : fatal error LNK1169: one or more multiply defined symbols found
      agent:2021/09/13 13:33:07 build.go:391: jom: C:\Users\qt\work\qt\qtbase_qmake\examples\dbus\chat\Makefile.Release [release\chat.exe] Error 1169
      

      Several things contribute to this.

      In the CMake build, we're calling dbusxml2cpp with the -m option that generates #include "filename.moc" statements in the .cpp files. We don't do that in the qmake build.

      In the qmake build of the examples/dbus/chat, when .qmake.conf is not present, we're compiling chat_adapter.cpp from the source directory (which includes chat_adapter.moc) but qmake sees the generated chat_adapter.cpp from the build directory and calls moc on chat_adapter.h, generates moc_chat_adapter.cpp and adds this as source file.

      And now we have the metaobject symbols duplicated.

      The presence of .qmake.conf affects how source paths are handled inside qmake and how nmake inference rules are generated.

      With .qmake.conf present, Makefile.Release has the rules

      {C:\Users\qt\work\qt\qtbase\examples\dbus\chat}.cpp{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {C:\Users\qt\work\qt\qtbase\examples\dbus\chat}.cc{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {C:\Users\qt\work\qt\qtbase\examples\dbus\chat}.cxx{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {C:\Users\qt\work\qt\qtbase\examples\dbus\chat}.c{release\}.obj::
      	$(CC) -c $(CFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {release}.cpp{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {release}.cc{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {release}.cxx{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {release}.c{release\}.obj::
      	$(CC) -c $(CFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.cpp{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.cc{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.cxx{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.c{release\}.obj::
      	$(CC) -c $(CFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      

      With .qmake.conf removed, the rules look like this:

      {release}.cpp{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {release}.cc{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {release}.cxx{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {release}.c{release\}.obj::
      	$(CC) -c $(CFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.cpp{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.cc{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.cxx{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {.}.c{release\}.obj::
      	$(CC) -c $(CFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {..\..\..\..\qtbase\examples\dbus\chat}.cpp{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {..\..\..\..\qtbase\examples\dbus\chat}.cc{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {..\..\..\..\qtbase\examples\dbus\chat}.cxx{release\}.obj::
      	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      
      {..\..\..\..\qtbase\examples\dbus\chat}.c{release\}.obj::
      	$(CC) -c $(CFLAGS) $(INCPATH) -Forelease\ @<<
      	$<
      <<
      

      This smells a lot like infamous QTBUG-13496, and indeed, specifying CONFIG += no_batch makes the examples build. Magic.

      Attachments

        Issue Links

          Activity

            People

              jbornema Joerg Bornemann
              jbornema Joerg Bornemann
              Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: