我在QT 5.4中有一个应用程序但是当我需要包含一个新功能时,我需要重新编译所有应用程序,这需要一些时间,我需要知道如何创建或修改我的应用程序以使用我创建的插件。
答案 0 :(得分:1)
基于插件的架构需要二进制兼容且稳定的接口。有了这些,完整项目重新编译应该花费与重新编译单个插件相同的时间。
最有可能的是,您的代码中存在相互依赖性,无论如何都会妨碍维护二进制兼容性 - 如果不这样做,您的更改将会进行足够的本地化,以便重新编译只会触及几个文件。
您正在尝试做的是提出解决错误问题的方法。修复代码的结构,重新编译时间将会减少。不需要插件。
答案 1 :(得分:0)
有很多选择;一个流行的包括使用实现定义良好的API的共享库。
例如。想象一下,这是您要打开以进行自定义的API:
// pluggin_api.hpp
// This file defines the pluggin interface.
#pragma once
extern "C" { // avoid name mangling
const char* pluggin_name();
void foo(int x);
void bar(int y);
}
然后,您的用户(或您自己)将实施此API的不同变体,例如:
// pluggin_1.cpp
#include "pluggin_api.hpp"
#include <iostream>
const char* pluggin_name() {
return "Pluggin 1";
}
void foo(int x) {
std::cout << "2 * x = " << 2 * x << std::endl;
}
void bar(int y) {
std::cout << " 3 * y = " << 3 * y << std::endl;
}
和
// pluggin_2.cpp
#include "pluggin_api.hpp"
#include <iostream>
const char* pluggin_name() {
return "Pluggin 2";
}
void foo(int x) {
std::cout << "20 * x = " << 20 * x << std::endl;
}
void bar(int y) {
std::cout << " 30 * y = " << 30 * y << std::endl;
}
这些.cpp文件被编译为共享库;在Linux下它看起来像这样:
$ g++ -shared -fPIC -o pluggin_1.so pluggin_1.cpp
$ g++ -shared -fPIC -o pluggin_2.so pluggin_2.cpp
最后,主应用程序可以按名称调用不同的插件:
// main.cpp
#include <iostream>
#include <dlfcn.h> // POSIX --- will work on Linux and OS X, but
// you'll need an equivalent library for Windows
void execute_pluggin(const char* name) {
// declare the signature of each function in the pluggin -- you
// could do this in the header file instead (or another auxiliary
// file)
using pluggin_name_signature = const char*(*)();
using foo_signature = void(*)(int);
using bar_signature = void(*)(int);
// open the shared library
void* handle = dlopen(name, RTLD_LOCAL | RTLD_LAZY);
// extract the functions
auto fun_pluggin_name = reinterpret_cast<pluggin_name_signature>(dlsym(handle, "pluggin_name"));
auto fun_foo = reinterpret_cast<foo_signature>(dlsym(handle, "foo"));
auto fun_bar = reinterpret_cast<bar_signature>(dlsym(handle, "bar"));
// call them
std::cout << "Calling Pluggin: " << fun_pluggin_name() << std::endl;
fun_foo(2);
fun_bar(3);
// close the shared library
dlclose(handle);
}
int main(int argc, char *argv[]) {
for(int k = 1; k < argc; ++k) {
execute_pluggin(argv[k]);
}
}
编译并链接到dl
库:
$ g++ -o main main.cpp -std=c++14 -ldl
并运行(注意在名称前需要./
;这与库命名约定和搜索路径有关):
$ ./main ./pluggin_1.so ./pluggin_2.so
Calling Pluggin: Pluggin 1
2 * x = 4
3 * y = 9
Calling Pluggin: Pluggin 2
20 * x = 40
30 * y = 90
我遗漏了很多细节(最重要的是错误管理)。我建议您阅读本书API Design for C++以查找其他想法(例如使用脚本语言,使用继承,使用模板以及它们的混合)。
我喜欢共享库方法,因为我可以在其他应用程序中使用插件(例如:我可以使用Python&#39; s ctypes
库,或者Matlab&#39; loadlibrary
) 。我也可以在Fortran中编写插件,然后将其封装在与API兼容的接口中。
最后:请注意,这与QT完全无关(尽管QT可能提供独立于平台的共享库加载器;我不知道)。这只是人们为定制提供钩子的常见方式。