【问题标题】:Dynamically Loading QTGui动态加载 QTGui
【发布时间】:2013-07-26 13:43:01
【问题描述】:

我正在编写一个 QT 应用程序,我希望编译后的二进制文件与 GUI 和 CLI(未安装 X11)环境兼容。

以下是我使用 QApplication 或 QCoreApplication 的主要功能:

int main(int argc, char *argv[]){
    // SOME COMMON CODE will be executed before this
    bool myGUI = getenv("DISPLAY") != 0;

    if(myGUI){
        QApplication a(argc, argv);
        client w; // A MainWindow Object
        w.show();
        doStuff();
        return a.exec();
    }else{
        QCoreApplication a(argc, argv);
        doStuff();
        return a.exec();
    }

    return 1;

}

现在,QT 构建具有 libQtGui 作为动态共享对象的二进制文件。我想知道是否可以动态加载 libQtGui,以便它可以在 CLI 环境中工作,而无需安装 libQtGui 所需的所有库。

【问题讨论】:

    标签: c++ qt dynamic-loading


    【解决方案1】:

    尝试这样做是不切实际的。这在理论上是可行的,但您需要为大量内容创建 C 包装器。

    您可以尝试将应用程序的 GUI 部分拆分为它自己的共享库,然后使用 dlopen() 将其拆分。比如gui.cpp:

    // Needs to be extern "C" so that dlopen() can find it later.
    extern "C"
    int runGui(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        client w;
        w.show();
        doStuff();
        return a.exec();
    }
    

    您将以上内容编译为共享库,链接到 QtGui。例如:

    g++ -c -fPIC $(pkg-config QtGui --cflags) -o gui.o gui.cpp g++ -shared -o gui.so gui.o $(pkg-config QtGui --libs)

    这将为您提供gui.so,然后您可以在主程序中使用 dlopen():

    #include <dlfcn.h>
    
    int main(int argc, char *argv[])
    {
        // SOME COMMON CODE will be executed before this
        bool myGUI = getenv("DISPLAY") != 0;
        int ret = 0;
    
        if (myGUI) {
            void* handle = dlopen("./gui.so", RTLD_NOW);
            if (!handle) {
                // Error: dlopen failed
            }
            dlerror(); // Clear/reset errors.
    
            // Create a function pointer type for runGui()
            typedef int (*runGui_t)(int, char**);
    
            // Load the address of runGui() and store it in a
            // function pointer. The function pointer name doesn't
            // have to be the same as the function we're loading.
            runGui_t runGui = (runGui_t)dlsym(handle, "runGui");
    
            const char* dlsym_error = dlerror();
            if (dlsym_error) {
                // Error: dlsym failed.
                // 'dlsym_error' contains the error msg.
            }
    
            // Call the function as usual by using our 'runGui' pointer.
            ret = runGui(argc, argv);
            dlclose(handle);
        } else {
            QCoreApplication a(argc, argv);
            doStuff();
            ret = a.exec();
        }
        return ret;
    }
    

    请注意,在构建上述 main.cpp 时,您不能链接到 QtGui,以便它可以在 libQtGui.so 不可用的系统上运行。在这种情况下,dlopen() 将无法加载 gui.so。此时,您可以回退到非 GUI 代码(在上面的示例中我没有这样做。)

    【讨论】:

      【解决方案2】:

      这不是Qt的问题,是c++的问题

      你可以在这里找到答案 Dynamically load a function from a DLL

      但基本上我认为这是个坏主意,如果你想要一个纯控制台应用程序或混合控制台/gui 应用程序,你应该在编译时用#ifdef 解决它。

      #ifdef WITH_GUI
      if(myGUI){
          QApplication a(argc, argv);
          client w; // A MainWindow Object
          w.show();
          doStuff();
          return a.exec();
      }else{
      #endif    
          QCoreApplication a(argc, argv);
          doStuff();
          return a.exec();
      #ifdef WITH_GUI
      }
      #endif
      

      并添加一些启动参数。例如 ./myapp --start-gui 表示使用 gui 支持编译的版本。

      【讨论】:

        猜你喜欢
        • 2016-09-26
        • 2018-03-25
        • 2011-01-06
        • 2012-08-13
        • 2014-08-29
        • 2012-11-10
        • 2011-04-14
        • 2011-06-04
        • 2020-04-24
        相关资源
        最近更新 更多