动态加载QTGui

时间:2013-07-26 10:17:32

标签: c++ qt dynamic-loading

我正在编写一个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所需的所有库。

2 个答案:

答案 0 :(得分:3)

尝试这个是不切实际的。这在理论上是可行的,但你需要为大量的东西创建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代码(我在上面的示例中没有这样做。)

答案 1 :(得分:0)

这不是关于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支持编译的版本。