我看不出这种解决方案有什么缺点。
我不是一个经常使用Windows的用户,但我必须承认,隐式查找可执行文件所在位置的动态库的解决方案非常有帮助。
您可以将应用程序的全部内容(可执行文件和动态库/插件)放在任何地方,只要成功运行可执行文件,其他所有内容都会被找到。
当然,如果您计划提供许多不同的应用程序并共享一组公共的动态库,则最好将所有这些库放在一个公共位置,并相应地调整PATH环境变量。
但对于单个应用程序来说,这样做并不值得。
几个月前,我交付了一个基于mingw-w64(不完全是Msys64和MingW,但非常接近)的应用程序(带有插件),我只提供了libgcc_s_seh-1.dll、libstdc++-6.dll和libwinpthread-1.dll作为我的二进制文件的补充,它可以正常工作。
使用
objdump.exe -p my_program.exe
(然后递归地在显示的结果上)有助于找到所需的动态库(就像Linux上的
ldd
或Macosx上的
otool -L
一样)。
这就是我喜欢mingw-like解决方案的原因:它可以创建一个本地的Windows应用程序,不依赖于许多其他不寻常的组件(用户必须首先检索这些组件)。
没有必要处理一些
.lib
文件;构建一个
.dll
并链接就足够了(请参见下面的示例)。
它与我们在UNIX上使用
.so
文件完全相同。
我真的不知道为什么Visual-C++会依赖于如此复杂的
.lib
和
.dll
文件组合...
我刚刚使用这个简单的示例进行了重新测试。
文件
prog.cpp
#include <windows.h>
#include <iostream>
__declspec(dllimport)
int
my_library_function(int arg);
int
main()
{
std::cout << "~~~~ entering " << __func__ << " ~~~~\n";
int result=my_library_function(123);
std::cout << "result=" << result << '\n';
std::cout << "~~~~ still in " << __func__ << " ~~~~\n";
HINSTANCE lib=LoadLibrary("my_plugin.dll");
if(lib)
{
FARPROC symbol=GetProcAddress(lib, "my_plugin_function");
if(symbol)
{
int (*fnct)(int)=NULL;
memcpy(&fnct, &symbol, sizeof(fnct));
int result=fnct(123);
std::cout << "result=" << result << '\n';
}
FreeLibrary(lib);
}
std::cout << "~~~~ leaving " << __func__ << " ~~~~\n";
return 0;
}
file my_library.cpp
#include <iostream>
__declspec(dllexport)
int
my_library_function(int arg)
{
std::cout << "~~~~ entering " << __func__ << " ~~~~\n";
std::cout << "arg=" << arg << '\n';
std::cout << "~~~~ leaving " << __func__ << " ~~~~\n";
return 2*arg;
}
文件 my_plugin.cpp
#include <iostream>
extern "C" __declspec(dllexport)
int
my_plugin_function(int arg)
{
std::cout << "~~~~ entering " << __func__ << " ~~~~\n";
std::cout << "arg=" << arg << '\n';
std::cout << "~~~~ leaving " << __func__ << " ~~~~\n";
return 2*arg;
}
构建过程
==== compiling [opt=0] my_plugin.cpp ====
g++ -o my_plugin.o my_plugin.cpp -c -g -O0 -MMD -pedantic -Wall -Wextra -Wconversion -Wno-unused -Wno-unused-parameter -Werror -Wfatal-errors -UNDEBUG -std=c++17 -Wno-missing-braces -Wno-sign-conversion
==== linking [opt=0] my_plugin.dll ====
g++ -shared -o my_plugin.dll my_plugin.o -g -O0
==== compiling [opt=0] my_library.cpp ====
g++ -o my_library.o my_library.cpp -c -g -O0 -MMD -pedantic -Wall -Wextra -Wconversion -Wno-unused -Wno-unused-parameter -Werror -Wfatal-errors -UNDEBUG -std=c++17 -Wno-missing-braces -Wno-sign-conversion
==== linking [opt=0] my_library.dll ====
g++ -shared -o my_library.dll my_library.o -g -O0
==== compiling [opt=0] prog.cpp ====
g++ -o prog.o prog.cpp -c -g -O0 -MMD -pedantic -Wall -Wextra -Wconversion -Wno-unused -Wno-unused-parameter -Werror -Wfatal-errors -UNDEBUG -std=c++17 -Wno-missing-braces -Wno-sign-conversion
==== linking [opt=0] prog.exe ====
g++ -o prog.exe prog.o -g -O0 -lmy_library
执行
C:\Work\PluginTest>prog.exe
~~~~ entering main ~~~~
~~~~ entering my_library_function ~~~~
arg=123
~~~~ leaving my_library_function ~~~~
result=246
~~~~ still in main ~~~~
~~~~ entering my_plugin_function ~~~~
arg=123
~~~~ leaving my_plugin_function ~~~~
result=246
~~~~ leaving main ~~~~
C:\Work\PluginTest>
即使mingw64目录(包含工具链)更名,只要将libgcc_s_seh-1.dll
、libstdc++-6.dll
和libwinpthread-1.dll
文件放置在与prog.exe
相同的目录中,此方法仍然有效。
即使通过点击(而非从命令行)启动prog.exe
,它也可以正常运行。为了观察到显示的消息,我不得不在程序末尾添加一个无限循环来保持窗口打开足够长的时间。