【问题标题】:Obtaining filename at runtime for a shared library c++在运行时获取共享库 C++ 的文件名
【发布时间】:2018-12-28 18:44:12
【问题描述】:

我有一些代码被编译为共享库并与通用驱动程序一起使用,该驱动程序可以与特定于特定应用程序的其他共享库一起使用。

我的问题是关于获取某种指示二进制文件名称的指示符,该二进制文件包含位于该共享库中的代码。

比如说我有3个文件,第一个是driver.cpp,通用驱动:

#include "interface.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
    //perform a function from the shared library
    std::cout << foobar() << std::endl;
}

第二个是sharedlibrary.cpp,多例一的具体实现:

#include "interface.h"
char* foobar() {
    return x;
}

其中x 表示此函数在 sharedlibrary.cpp 中定义,或者此函数从 sharedlibrary.so 链接,或者当前堆栈帧正在使用特定的二进制文件而不是仅包含在 driver.cpp 中.

最后一个文件是interface.h,它通过extern "C"提供库的接口

extern "C" {
char foobar();
}

为了清楚起见,我想重申一下,我正在寻找一些迹象表明这个函数是从 sharedlibrary.so 链接的。许多寻找运行时文件名的解决方案使用 argv[0] 或 readlink() 给出 可执行文件名,但我无法控制 driver.cpp 的实际命名或其可执行文件名。相反,我可以分发 sharedlibrary.so,并且希望能够在其内部使用它的名称,如果可能的话。

如果有帮助,我知道微软特定的解决方案可能是使用AfxGetApp()-&gt;m_pszAppName 来获取 DLL 名称。但是,我正在寻找一种不一定需要便携的 linux 解决方案。

编辑:我在编译时不知道或控制 driver.cpp、sharedlibrary.cpp 或 sharedlibrary.h 的名称。我希望在运行时发现 sharedlibrary.cpp 的名称。

x 替换为解决方案的更新 sharedlibrary.cpp 如下所示

#include "interface.h"
#include <dlfcn.h>
void func() {
    //Some function that is defined in sharedlibrary.cpp
}

char* foobar() {
    Dl_info DlInfo;
    if(!dladdr((void*)func, &DlInfo)) {
        return "default_name";
    }
    return DlInfo.dli_fname;
}

【问题讨论】:

  • 有一种方法可以通过使用 dlsym() 查找符号来从 .so 文件中找到可用函数,但您无法确定参数的类型,我的意思是您无法确定完整的签名。
  • C 和 C++ 非常不同,请仅使用正确的标签。谢谢:)
  • 你是否也有 sharedlibrary.h 文件?也提一下
  • 如果我理解错了,请纠正我,你想弄清楚哪个库包含特定的功能
  • @yadhu 是的,但在运行时来自实际共享库中,而不是外部。该解决方案必须在 sharedlibrary.cpp 中实现。

标签: c++ linux unix


【解决方案1】:

在运行时获取共享库 c++ 的文件名

我的问题是关于获取某种指示二进制文件名称的指示符,该二进制文件包含位于该共享库中的代码。

您可以使用int dladdr(void *addr, Dl_info *info。它为您填充以下结构:

typedef struct {
    const char *dli_fname;  /* Pathname of shared object that contains address */
    void       *dli_fbase;
    const char *dli_sname;
    void       *dli_saddr;
} Dl_info;

您可以将共享库导出的函数的地址作为参数addr 传递。或者在这样的函数中,您可以使用当前堆栈帧的指令指针值 - 如果您知道如何获取它。

我相信你必须链接 libdl 库。

【讨论】:

    【解决方案2】:

    您可以使用构建系统生成动态库名称,以便使用返回已定义宏的函数在标头内部进行链接和预处理,在 cmake 中您可以看到如何做到这一点here

    然后您使用配置文件在从 dll 中导出的函数中返回定义的值。

    #include "library_name_macro.h"
    
    auto __dllexport libraryName() -> std::string { return LIBRARY_NAME_MACRO; } 
    

    【讨论】:

      【解决方案3】:

      我希望,我正确理解了您的问题。我希望我的回答有帮助。您知道共享库名称,将该共享库链接到您的程序,稍后在运行时您想确定库中是否存在特定函数,并且此逻辑应该是共享库本身的一部分。

      让我们举个例子,你有一个名为 librandom.so 的共享库,你已经将这个库链接到你的应用程序。您可以在 librandom.so 库中实现以下函数,您可以传递要检查它是否存在的函数名称。我没有测试过这段代码,可能有错误。我提出的想法是库再次加载自身以检查调用该函数时该函数是否存在。可能不是理想的方法,但应该可以达到您的目的。

      int isFuncPresent(char funcName[])
      {
          int isFuncFound = 1;
          void *lib_handle;
          int x;
          char *error;
          lib_handle = dlopen("librandom.so", RTLD_LAZY);
      
          if (!lib_handle)
          {
             fprintf(stderr, "%s\n", dlerror());
             isFuncFound = 0;
          }
      
          fn = dlsym(lib_handle, funcName);
          if ((error = dlerror()) != NULL)
          {
             fprintf(stderr, "%s\n", error);
             isFuncFound = 0;
          }
          dlclose(lib_handle);
          return isFuncFound;
      }
      

      【讨论】:

      • 抱歉没有很好地传达我的问题。我无法控制驱动程序或共享库的名称。所以我无法指定要使用 dlopen() 打开的库。
      猜你喜欢
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      • 2017-06-18
      • 1970-01-01
      • 1970-01-01
      • 2018-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多