Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Building a DLL on macOS for a non Qt application
QtWS25 Last Chance

Building a DLL on macOS for a non Qt application

Scheduled Pinned Locked Moved Solved General and Desktop
macdllmacosthread
9 Posts 2 Posters 816 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Basile Sens
    wrote on 4 Nov 2024, 14:54 last edited by Basile Sens 11 Apr 2024, 15:09
    #1

    Hello,

    I've built myself a dynamically linked library that will be used in a non Qt application. Creating the QApplication and calling exec() in another thread works well on Windows but fails on macOS.

    I've seen people refer to an issue with Cocoa but I haven't been able to find a solution that doesn't either block the original application's main thread or require changing the original application (can't be done).

    So how does one use Qt on mac in a dll ?

    Below is a bit of sample code as an example of what i'm trying to achieve:

    QtModuleDemo::QtModuleDemo()
        : running_(false)
    {
        QApplication::setQuitOnLastWindowClosed(false);
        appThread_ = std::thread(&QtModuleDemo::run, this);
    }
    
    void QtModuleDemo::run()
    {
        int argc = 0;
        app_ = new QApplication(argc, nullptr); // fails here on macOS
    
        // App code goes here.
        widget_ = new Custom3DView;
        widget_->show();
    
        running_ = true;
        app_->exec();
        running_ = false;
    }
    

    Thank you !

    1 Reply Last reply
    0
    • I Offline
      I Offline
      IgKh
      wrote on 4 Nov 2024, 17:36 last edited by
      #2

      The only surprise is that such a dubious setup works on Windows at all. AFAIK all GUI systems want only one main event loop to run, and it has to run on the "main" thread. So even if you create a QApplication later in the program's lifecycle, you don't want to exec it. There are other solutions if a Qt event loop is needed on a side thread.

      Specifically for your case, do you have any console logs from when creating the QApplication instance for context? I suspect that this the Qt Cocoa integration trying to install its' application delegate on the global NSApplication which is almost surely not something allowed not on the main thread, but could be something more mundane too.

      Also, are you familiar with https://developer.apple.com/documentation/dispatch/1453057-dispatch_async?

      B I 2 Replies Last reply 5 Nov 2024, 09:51
      0
      • I IgKh
        4 Nov 2024, 17:36

        The only surprise is that such a dubious setup works on Windows at all. AFAIK all GUI systems want only one main event loop to run, and it has to run on the "main" thread. So even if you create a QApplication later in the program's lifecycle, you don't want to exec it. There are other solutions if a Qt event loop is needed on a side thread.

        Specifically for your case, do you have any console logs from when creating the QApplication instance for context? I suspect that this the Qt Cocoa integration trying to install its' application delegate on the global NSApplication which is almost surely not something allowed not on the main thread, but could be something more mundane too.

        Also, are you familiar with https://developer.apple.com/documentation/dispatch/1453057-dispatch_async?

        B Offline
        B Offline
        Basile Sens
        wrote on 5 Nov 2024, 09:51 last edited by
        #3

        @IgKh unfortunately there is no console log given. I am curious about the other solutions for having a Qt event loop on a side thread. Would you happen to have any documentation regarding this ?

        I am not familiar with dispatch_async but i will definetly look into it, thanks.

        I 1 Reply Last reply 6 Nov 2024, 08:41
        0
        • B Basile Sens
          5 Nov 2024, 09:51

          @IgKh unfortunately there is no console log given. I am curious about the other solutions for having a Qt event loop on a side thread. Would you happen to have any documentation regarding this ?

          I am not familiar with dispatch_async but i will definetly look into it, thanks.

          I Offline
          I Offline
          IgKh
          wrote on 6 Nov 2024, 08:41 last edited by
          #4

          @Basile-Sens said in Building a DLL on macOS for a non Qt application:

          unfortunately there is no console log given.

          How do you know that it failed at the point you marked then? Did it crash? If so - the stack trace should be instructive.

          But basically, and without having ever tried to do something like what you describe and without knowing more about it, you'll need to use Grand Central Dispatch from your plugin's entry point to schedule an Objective-C++ block to the main thread that will initialize the QApplication and create/show the top-level widgets inside AppKit's event loop. Any background processing should be done via the worker QObject pattern on a side QThread, with any resulting updates to the UI again being posted to the main thread.

          P.S You'll probably want to look into the Qt::AA_PluginApplication application attribute. The Objective C runtime is very dynamic, and Qt's Cocoa integration plugin takes advantage of it to inject all kinds of things that make some behaviors more consistent with how Qt behaves on other platforms; that could mess up your host application.

          I am curious about the other solutions for having a Qt event loop on a side thread.

          QEventLoop for when you need a sub-loop that will block a thread while still processing Qt and UI system events, and the built-in event loop of QThread.

          B 1 Reply Last reply 6 Nov 2024, 10:43
          1
          • I IgKh
            4 Nov 2024, 17:36

            The only surprise is that such a dubious setup works on Windows at all. AFAIK all GUI systems want only one main event loop to run, and it has to run on the "main" thread. So even if you create a QApplication later in the program's lifecycle, you don't want to exec it. There are other solutions if a Qt event loop is needed on a side thread.

            Specifically for your case, do you have any console logs from when creating the QApplication instance for context? I suspect that this the Qt Cocoa integration trying to install its' application delegate on the global NSApplication which is almost surely not something allowed not on the main thread, but could be something more mundane too.

            Also, are you familiar with https://developer.apple.com/documentation/dispatch/1453057-dispatch_async?

            I Offline
            I Offline
            IgKh
            wrote on 6 Nov 2024, 08:46 last edited by IgKh 11 Jun 2024, 08:47
            #5

            @IgKh said in Building a DLL on macOS for a non Qt application:

            The only surprise is that such a dubious setup works on Windows at all

            Well, it appears that Win32 actually allows exactly that; different thread can independently own different windows and process events for them. That's normally a strange architecture to run, but looks like it exactly fits OP's case. However, AppKit is indeed much less accommodating.

            B 1 Reply Last reply 6 Nov 2024, 10:25
            1
            • I IgKh
              6 Nov 2024, 08:46

              @IgKh said in Building a DLL on macOS for a non Qt application:

              The only surprise is that such a dubious setup works on Windows at all

              Well, it appears that Win32 actually allows exactly that; different thread can independently own different windows and process events for them. That's normally a strange architecture to run, but looks like it exactly fits OP's case. However, AppKit is indeed much less accommodating.

              B Offline
              B Offline
              Basile Sens
              wrote on 6 Nov 2024, 10:25 last edited by
              #6

              @IgKh said in Building a DLL on macOS for a non Qt application:

              How do you know that it failed at the point you marked then? Did it crash? If so - the stack trace should be instructive.

              Here is the full stack trace of the crash, basically Appkit is not happy that we are not in the main thread:

              Thread 24 Crashed:
              0   libdispatch.dylib             	       0x18ad16a60 _dispatch_assert_queue_fail + 120
              1   libdispatch.dylib             	       0x18ad169e8 dispatch_assert_queue + 196
              2   HIToolbox                     	       0x196441bb4 islGetInputSourceListWithAdditions + 160
              3   HIToolbox                     	       0x196439940 isValidateInputSourceRef + 92
              4   HIToolbox                     	       0x196439e14 TSMGetInputSourcePropertyWithSetter + 48
              5   libqcocoa.dylib               	       0x11f9d03f0 QCocoaInputContext::updateLocale() + 68 (qcocoainputcontext.mm:144)
              6   libqcocoa.dylib               	       0x11f9d0334 QCocoaInputContext::QCocoaInputContext() + 248 (qcocoainputcontext.mm:55)
              7   libqcocoa.dylib               	       0x11f9d1460 QCocoaIntegration::QCocoaIntegration(QList<QString> const&) + 1140 (qcocoaintegration.mm:129)
              8   libqcocoa.dylib               	       0x11f9bb994 QCocoaIntegrationPlugin::create(QString const&, QList<QString> const&) + 112 (main.mm:29)
              9   QtGui                         	       0x15504be7c QPlatformIntegration* qLoadPlugin<QPlatformIntegration, QPlatformIntegrationPlugin, QList<QString> const&, int&, char**&>(QFactoryLoader const*, QString const&, QList<QString> const&, int&, char**&) + 80 (qfactoryloader_p.h:100) [inlined]
              10  QtGui                         	       0x15504be7c QPlatformIntegrationFactory::create(QString const&, QList<QString> const&, int&, char**, QString const&) + 204 (qplatformintegrationfactory.cpp:23)
              11  QtGui                         	       0x15501769c init_platform(QString const&, QString const&, QString const&, int&, char**) + 1716 (qguiapplication.cpp:1291)
              12  QtGui                         	       0x155016e4c QGuiApplicationPrivate::createPlatformIntegration() + 1404 (qguiapplication.cpp:1580)
              13  QtGui                         	       0x155018f7c QGuiApplicationPrivate::createEventDispatcher() + 36 (qguiapplication.cpp:1599)
              14  QtCore                        	       0x1236dc984 QCoreApplicationPrivate::init() + 1588 (qcoreapplication.cpp:925)
              15  QtGui                         	       0x1550130c4 QGuiApplicationPrivate::init() + 76 (qguiapplication.cpp:1627)
              16  QtGui                         	       0x155013f1c QGuiApplication::QGuiApplication(int&, char**, int) + 140 (qguiapplication.cpp:647) [inlined]
              17  QtGui                         	       0x155013f1c QGuiApplication::QGuiApplication(int&, char**, int) + 168 (qguiapplication.cpp:646)
              18  QtModuleDemo.usr-macos64uni   	       0x11cc82a3c QtModuleDemo::run() + 104 (QtModuleDemo.cpp:142)
              
              1 Reply Last reply
              0
              • I IgKh
                6 Nov 2024, 08:41

                @Basile-Sens said in Building a DLL on macOS for a non Qt application:

                unfortunately there is no console log given.

                How do you know that it failed at the point you marked then? Did it crash? If so - the stack trace should be instructive.

                But basically, and without having ever tried to do something like what you describe and without knowing more about it, you'll need to use Grand Central Dispatch from your plugin's entry point to schedule an Objective-C++ block to the main thread that will initialize the QApplication and create/show the top-level widgets inside AppKit's event loop. Any background processing should be done via the worker QObject pattern on a side QThread, with any resulting updates to the UI again being posted to the main thread.

                P.S You'll probably want to look into the Qt::AA_PluginApplication application attribute. The Objective C runtime is very dynamic, and Qt's Cocoa integration plugin takes advantage of it to inject all kinds of things that make some behaviors more consistent with how Qt behaves on other platforms; that could mess up your host application.

                I am curious about the other solutions for having a Qt event loop on a side thread.

                QEventLoop for when you need a sub-loop that will block a thread while still processing Qt and UI system events, and the built-in event loop of QThread.

                B Offline
                B Offline
                Basile Sens
                wrote on 6 Nov 2024, 10:43 last edited by
                #7

                @IgKh said in Building a DLL on macOS for a non Qt application:

                P.S You'll probably want to look into the Qt::AA_PluginApplication application attribute.

                Thanks for the tip, this solved my next issue where AppKit would not let me have an open window for more than 10 seconds before crashing in NSPersistentUIRequiresSecureCoding. Had no effect on the main issue though. Anyways I've refactored my code to this and it works somewhat:

                QtModuleDemo::QtModuleDemo() // always called from the app's main thread
                {
                    int argc = 0;
                    
                    QGuiApplication::setAttribute(Qt::AA_PluginApplication);
                    QGuiApplication::setQuitOnLastWindowClosed(false);
                    
                    app_ = new QGuiApplication(argc, nullptr);
                    
                    // App code goes here.
                    widget_ = new Custom3DView;
                    widget_->show();
                }
                

                The 3D renderer works and i can move the camera around. So do i really need a call to exec() ? If I was to call QGuiApplication::ProcessEvents() periodically from the main thread would it have the same effect ? What in Qt requires an event loop ?

                I know that we are moving out of scope on this one, I might create a new topic instead.

                I 1 Reply Last reply 7 Nov 2024, 07:44
                0
                • B Basile Sens
                  6 Nov 2024, 10:43

                  @IgKh said in Building a DLL on macOS for a non Qt application:

                  P.S You'll probably want to look into the Qt::AA_PluginApplication application attribute.

                  Thanks for the tip, this solved my next issue where AppKit would not let me have an open window for more than 10 seconds before crashing in NSPersistentUIRequiresSecureCoding. Had no effect on the main issue though. Anyways I've refactored my code to this and it works somewhat:

                  QtModuleDemo::QtModuleDemo() // always called from the app's main thread
                  {
                      int argc = 0;
                      
                      QGuiApplication::setAttribute(Qt::AA_PluginApplication);
                      QGuiApplication::setQuitOnLastWindowClosed(false);
                      
                      app_ = new QGuiApplication(argc, nullptr);
                      
                      // App code goes here.
                      widget_ = new Custom3DView;
                      widget_->show();
                  }
                  

                  The 3D renderer works and i can move the camera around. So do i really need a call to exec() ? If I was to call QGuiApplication::ProcessEvents() periodically from the main thread would it have the same effect ? What in Qt requires an event loop ?

                  I know that we are moving out of scope on this one, I might create a new topic instead.

                  I Offline
                  I Offline
                  IgKh
                  wrote on 7 Nov 2024, 07:44 last edited by
                  #8

                  @Basile-Sens said in Building a DLL on macOS for a non Qt application:

                  So do i really need a call to exec() ? If I was to call QGuiApplication::ProcessEvents() periodically from the main thread would it have the same effect ? What in Qt requires an event loop ?

                  No, you don't. A lot of things in Qt require an event loop to be running, but Qt doesn't actually have an event loop (well it has, but it is not often used). Each platform integration plugin has an implementation of QAbstractEventDispatcher that is responsible for picking up events that are relevant to Qt from the native windowing system and letting its' event loop know about events that are posted from within the QApplication and async IO/timers requested by Qt classes.

                  So as long as something is running a native event loop and the platform integration plugin is initialized (by creating the QApplication instance), all event dispatching and queued signal/slot connections should just work. QApplication::exec is just a way to start an event loop, but you don't want that if something else has already started it.

                  Had no effect on the main issue though

                  Can you, just for sake of clarity, state the remaining issues?

                  B 1 Reply Last reply 7 Nov 2024, 11:57
                  0
                  • I IgKh
                    7 Nov 2024, 07:44

                    @Basile-Sens said in Building a DLL on macOS for a non Qt application:

                    So do i really need a call to exec() ? If I was to call QGuiApplication::ProcessEvents() periodically from the main thread would it have the same effect ? What in Qt requires an event loop ?

                    No, you don't. A lot of things in Qt require an event loop to be running, but Qt doesn't actually have an event loop (well it has, but it is not often used). Each platform integration plugin has an implementation of QAbstractEventDispatcher that is responsible for picking up events that are relevant to Qt from the native windowing system and letting its' event loop know about events that are posted from within the QApplication and async IO/timers requested by Qt classes.

                    So as long as something is running a native event loop and the platform integration plugin is initialized (by creating the QApplication instance), all event dispatching and queued signal/slot connections should just work. QApplication::exec is just a way to start an event loop, but you don't want that if something else has already started it.

                    Had no effect on the main issue though

                    Can you, just for sake of clarity, state the remaining issues?

                    B Offline
                    B Offline
                    Basile Sens
                    wrote on 7 Nov 2024, 11:57 last edited by
                    #9

                    @IgKh Thank you for your precious help, things are a lot clearer now. Further tests have shown that most of the features I need still work without a call to exec(). I still can't quite understand what in my example started the event loop or if Qt just plugs in the existing NSApplication's event loop.

                    @IgKh said in Building a DLL on macOS for a non Qt application:

                    Had no effect on the main issue though

                    Can you, just for sake of clarity, state the remaining issues?

                    The main issue i refered to was me wanting to have a separate thread with a QApplication in it and the Qt::AA_PluginApplication attribute had no effect on this. The other issues I have are not within the scope of this topic though.

                    Thank you very much !

                    1 Reply Last reply
                    0
                    • B Basile Sens has marked this topic as solved on 7 Nov 2024, 11:58

                    1/9

                    4 Nov 2024, 14:54

                    • Login

                    • Login or register to search.
                    1 out of 9
                    • First post
                      1/9
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved