【问题标题】:Getting around __declspec(dllimport) in windows to linux project conversion在 Windows 中绕过 __declspec(dllimport) 到 linux 项目转换
【发布时间】:2020-04-30 06:30:58
【问题描述】:

我正在将 Visual Studio C++ 框架转换为 linux 版本,并且在消除 Windows 依赖项的过程中,我在一些头文件中遇到了一大堆 __declspec(dllimport) 调用。这些头文件定义了一堆在源文件中使用的函数和类,因此构建时需要它们。

以下是使用 __declspec() 调用的确切行。

#ifndef UeiDaqAPI
    #define UeiDaqAPI __declspec(dllimport)
#endif

UeiDaqAPI 是所有源文件使用的类和函数的集合。据我了解,declspec 调用将当前 .h 文件中定义的函数/类链接到动态库“UeiDaqAPI”

__declspec(dllimport) 不受 linux 支持,因此我尝试了使用 dlopen() 的“解决方法”。有关更多背景信息,大约 40 个头文件使用上述 __declspec() 调用,因此测试任何解决方法都非常乏味。我得到了一个用于 linux 的动态库,采用我应该使用的 .so 格式。

我找到了一个使用 dlopen(path-to-library) 的示例,它应该可以让我绕过 __declspec() 调用,但我不确定如何让它正常工作。到目前为止,我已经尝试按照示例进行操作,并更改了所有 40 个左右的头文件,并将 __declspec() 调用替换为以下内容:

#ifndef UeiDaqAPI
    string nameOfLibToLoad("path/to/lib/lib.so");
    UeiDaqAPI = dlopen(nameOfLibToLoad.c_str(), RTLD_LAZY);
    if (!lib_handle) {
        cerr << "Cannot load library: " << dlerror() << endl;
    }
#endif

但是,我收到错误消息,指出未定义在头文件中定义的函数调用,我怀疑这是因为它们没有被添加到 .so 库中,但我不确定。

我想要一些帮助来实现上述解决方法,或者,如果有更好的方法来绕过 __declspec() 调用,那么 id 想要一些关于从哪里开始的指针。

【问题讨论】:

  • dllimportdllexport 是 Windows 特定的 DLL 概念。 Linux 本身不使用.dll 二进制文件; Linux 使用shared object (.so) 二进制文件。您是否尝试在您的 Linux 应用程序中专门加载 .dll 文件?
  • 我对基于 linux 的库加载不太熟悉,但是是的,dllimport 尝试加载一个 dll,我显然没有,所以我正在寻找一种方法来绕过这个 dllimport 调用。我已经有一个应该使用的 .so 二进制文件,但我不确定如何告诉 .h 文件使用 .so 而不是使用 dllimport 加载 dll
  • @Romen 我如何专门链接到.so 文件。这就是我苦苦挣扎的地方,如何将每个头文件准确链接到.so
  • 链接.so 文件的方式与链接.lib.a 库的方式相同。我认为您可能需要寻找一本 C++ 书籍或教程,以确保您对链接器、库和头文件如何协同工作有一个很好的理解。在 linux 上您需要做的就是包含库的标头,并链接到该库的 .so。无需像使用 Windows DLL 那样显式导入或导出函数;在 linux 上,.so 可以像静态库一样使用。
  • 还有@Bendrix,我认为指出您在代码中看到的dllimport 不调用函数或执行任何操作 可能会有所帮助。它是一个属性,是一个函数的描述,它告诉编译器/链接器该函数存在于一个DLL 中。加载 DLL 的实际代码是编译器自动插入的,只要您链接到该 DLL 的 .lib 文件。

标签: c++ linux dynamic-library


【解决方案1】:

您不需要使用dlopen,即用于动态加载(LoadLibrary/dlopenGetProcAddress/dlsymFreeLibrary/dlclose)。

与 Windows 在基本情况下它应该是自动的,但语法略有不同。

Windows/MSVC 通常只从 DLL 中导出 __declspec(dllexport) 明确告知的内容,然后在使用 DLL 时仅尝试链接__declspec(dllimport) 明确告知的内容。

GCC/Linux 但是默认情况下(您可以选择显式导出样式)仅导出 .so 中的所有内容,并且在链接时会考虑任何对象或库,因此只需声明该函数就足够了,例如静态库或多个 C/C++ 文件。

void my_uei_daq_api_function(int a, int b);

通常在可移植库中可能会有以下内容:

#if defined(_WIN32) && defined(MYLIB_DLL)
#    ifdef MYLIB_BUILD
//       Compiling a Windows DLL
#        define MYLIB_EXPORT __declspec(dllexport)
#    else
//       Using a Windows DLL
#        define MYLIB_EXPORT __declspec(dllimport)
#    endif
// Windows or Linux static library, or Linux so
#else
#    define MYLIB_EXPORT
#endif

然后在库头文件中使用:

MYLIB_EXPORT void my_uei_daq_api_function(int a, int b);

【讨论】:

  • 例如,当使用 MYLIB_EXPORT 时,我只需要将上述内容添加到头文件中,或者我需要更改源文件以使用我称之为“MYLIB_EXPORT”的任何内容。以及如何具体告诉这些头文件使用给我的.so文件?
  • 如果没有看到标题就无法确定,我希望他们已经有一个这样的宏,因为需要在 dllexportdllimport 之间切换,而静态库构建则没有任何东西(而不是而不是不同的标头物理副本),如果是这样,只需将“非 Windows DLL”案例添加到它的定义方式中就可以了(可能只是 #define UeiDaqAPI)。
  • 注意:在Unix中,dllexport是默认的; dllimport 不是必需的,因为链接器会检测共享对象中的哪些符号。 (此外,Windows 的 .lib 文件在 Unix 中不存在:它们包含可以自动生成链接时间的代码——实际上 Windows 上的 gcc 就是这样做的:它可以直接从 .dll 文件链接而无需 .lib 文件。)跨度>
猜你喜欢
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 2013-07-29
  • 1970-01-01
  • 2012-07-22
  • 2011-05-28
相关资源
最近更新 更多