如何找到库以使用 dlopen 动态加载它们
在我正在进行的项目中,我们提供了动态加载附加功能的可能性。为此,我们使用 dlopen。
为了找到这个库,我们有一个称为模块路径的东西。在那里我们有一个默认路径,共享库所在的位置(其中很多都是已发布的)。
目前我们有两个默认路径:我们首先在构建目录中查找共享库,然后在安装目录中查找。这是因为它也应该可以在不安装应用程序的情况下运行它(因此在这种情况下,它需要首先在构建目录中查找)。
现在的问题是,如果用户从源代码构建应用程序并使用 make install 安装它,则默认情况下会加载其构建目录中的库。这将导致崩溃。因此,只有当用户随后删除或重命名构建目录时,它才有效。
不,问题是:是否有一个技巧(通过 C++ 或通过构建系统)来知道应用程序是否已安装。问题是,该功能是在共享库中实现的,并且搜索模块的实现方式也必须适用于链接到我们的库的其他应用程序(因此我们不能依赖可执行文件的路径)。我们使用 CMake 作为构建系统。
为了使情况变得更加困难,该解决方案必须在 Windows、Linux 和 Mac OS X 上运行。
编辑:
我进一步调查,问题更加复杂。情况是这样的:
- 有一个小的可执行文件 a
- 此外还有一个“主”库 main.so
- 然后有一个动态加载的库 lib.so lib.so
- 链接到 main.so
问题是,lib.so 有rpath 中构建目录中 main.so 的绝对路径。感谢 @MSalters 的提示,我现在能够进行黑客攻击,以确保加载正确版本的 lib.so (安装目录中的版本),但由于它在 rpath 中具有构建路径,因此它加载了错误的 main .so (所以实际上内存中有两个 main.so 的副本 - 这把事情搞砸了)。
有没有办法从库中删除对构建路径的引用?我尝试了 cmake 与 rpath 相关的所有选项,但没有成功
In the project I am working on, we provide the possibility to dynamically load additional features. For that we use dlopen.
To find this libraries we have something we call module path. There we have a default path, where the shared libraries are (a lot of them are shipped).
At the moment we have two default paths: we first look in the build directory for the shared library and afterwards in the install directory. This is because it should also be possible to run the application without installing it (so in that case it needs to look first in the build directory).
Now the problem ist, if a user builds the application from source and installs it with make install, the libraries in her build directory are loaded by default. This will result in a crash. So it only works if the user afterwards removes or renames the build directory.
No the question: is there a trick (either by C++ or by the build system) to know whether the application is installed or not. The problem is, that the functionality is implemented in a shared library and the implemented way to search for modules has to work also for other applications that link against our library (so we can not rely on the path of the executable). We use CMake as a build system.
To make the situation even harder, the solution has to work on Windows, Linux and Mac OS X.
EDIT:
I further investigated and the problem is more complicated. This is the situation:
- There is a small executable a
- Furthermore there is a "main" library main.so
- then there is a dynamically loaded library lib.so
- lib.so links against main.so
The problem is, that lib.so has the absolute path to main.so in the build directory in its rpath. Thanks to the tip of @MSalters I now was able to make a hack to make sure to load the correct version of lib.so (the one in the install directory) but since it has the build path in the rpath it loads the wrong main.so (so in fact there are two copies of main.so in the memory - this messes things up).
Is there a way to remove this reference to the build path from the library? I tried all options of cmake related to rpath without success
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你不能检查可执行文件本身在哪里吗?如果它在构建目录中,请使用构建库 - 如果它在安装中,请使用 install?
getcwd() 在所有这些平台上都有等效项,但它可能不是您想要的 - 这取决于您运行可执行文件的方式。
我认为,获取进程的位置是特定于系统的,但包装它应该不会太难。
Can't you check where the executable itself is? If it's in the build directories, use build libraries -- if it's in the install, use install?
getcwd()
has equivalents on all of those platforms, but it might not be what you want -- it depends on how you run the executable.To get the process's location is system specific, I think, but it shouldn't be too hard to wrap that.
安装的版本不应在 rpath 中包含构建目录。
您可能需要进行两次链接(一次针对构建版本,一次针对已安装版本)。通常,在 *nix 系统上,安装的二进制文件有一些静态路径,它会尝试在其中查找插件。您可以定义一些环境变量(或命令行参数)以在构建执行时重载它(并使用包装器脚本在构建环境中设置它)。
检查一些项目(例如 Firefox)如何解决这个问题。
我对 Windows 系统了解不多,但我认为执行此操作的标准方法是在与可执行文件相同的目录中搜索插件。
The installed version should not have the build directory in the rpath.
You might want to do the linking twice (once for the build version and once for the installed version). Usually, on *nix systems, the installed binary has some static path where it tries to find plugins. You might define some environment variable (or command-line argument) to overload it for the build execution (and use a wrapper script to set it in the build environment).
Check how it is solved by some projects (Firefox for example).
I don't know much about windows system but I think the standard way of doing this is to search plugins in the same directory as the executable.