2013-07-26 28 views
2

我正在編寫QT應用程序,我希望編譯後的二進制文件與GUI和CLI(安裝時沒有X11)環境兼容。動態加載QTGui

以下是使用的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所需的所有庫。

回答

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支持編譯的版本。

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代碼(我在上例中沒有這樣做)。