我正在编写一个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所需的所有库。
答案 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支持编译的版本。