【问题标题】:How to build a DLL version of libjpeg 9b?如何构建 libjpeg 9b 的 DLL 版本?
【发布时间】:2017-11-11 01:25:54
【问题描述】:

我想构建一个 DLL 版本的 libjpeg 9b。根据文档here看来,除了将Configuration Type设置为“Dynamic Library (.dll)”之外,我们还需要在每个要导出的函数的声明前添加预处理器__declspec(dllexport)__declspec(dllimport) .但这并不是一件容易的事,因为 libjpeg 中有很多功能。那么,是否有任何捷径或变通方法来构建 DLL libjpeg 而无需或几乎不修改 jpeglib.h?是否有任何可用于 DLL 的 libjpeg 9b 源?我在 Windows 7 64 位上使用 Visual Studio 2015。谢谢你的回答。

PS:我从http://www.ijg.org/files/下载了libjpeg 9b的源码。这是官方的下载地址吗?我问是因为 .vcxproj(最初是 .v10)文件的开头字节似乎无效(C2 8B C2 AF C2 A8)所以 Visual Studio 无法打开它。

【问题讨论】:

  • 您想从 VStudio14.0 IDE 构建它还是只想使用 VStudio14.0 工具构建它?
  • @CristiFati:没关系。我的目的只是通过将 libjpeg 构建为 dll 来节省内存消耗,因为在我的机器上使用它的第三方库不止一个。我关心的是如何避免在每个函数之前手动添加 __declspec(dllexport) 或 __declspec(dllimport) 。这应该是可能的,因为我看到许多 3rd 方库生成 dll,而我在它们的源代码中找不到任何 __declspec(dllexport) 或 __declspec(dllimport)。我很好奇他们是怎么做到的。
  • 告诉我这对你有什么作用。

标签: dll visual-studio-2015 dllimport dllexport libjpeg


【解决方案1】:

[GitHub]: CristiFati/Prebuilt-Binaries - (master) Prebuilt-Binaries/LibJPEG 上发布的构建(静态/动态)。



与当今几乎所有的软件一样,libjpeg 也托管在 [GitHub]: winlibs/libjpeg - libjpeg-9b 上。我从这两个地方下载了它,做了一个比较,只有很少的细微差别(源代码中没有)弹出。我将在 GitHub 版本上进行解释。不幸的是,没有这方面的演练,所以我不得不查看一些文件以找出必须做什么。以下是步骤列表:

1。准备地面

1st 事情是将压缩的(zip / tar.gz)文件内容解压到一个文件夹中(并有一个cmd 控制台在那里打开)。该文件夹包含一堆文件。我们需要的第一个stmakefile.vc。顾名思义,它是一个 Makefile,由一系列通常用于构建东西的规则/指令组成。

作为评论,我正在使用 VStudio (Community) 2015 (14.0) 来完成这项任务(但应该没有区别对于较新的版本)。

处理Makefiles 的工具是nmake ([MS.Docs]: NMAKE reference)。我们需要针对该文件调用它。 nmake 位于“%VSTUDIO_INSTALL_DIR%\VC\bin\nmake.exe”(env var 并不存在,它只是一个路径占位符);通常是 "%SystemDrive%\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\nmake.exe" (例如在我的机器上它是 "C:\Install\x86 \Microsoft\Visual Studio Community\2015\VC\bin\nmake.exe”)。

请注意,在处理 VStudio 命令行工具时,最好是:

  • 使用 vcvarsall(这是一个 (batch) 工具,可以设置一些环境变量,例如 %PATH%), %INCLUDE%, %LIB%, ...),所以所有 VStudio 工具都可以在没有完整路径的情况下使用。但由于它也位于“%VSTUDIO_INSTALL_DIR%\VC\vcvarsall.bat”中,因此不值得努力定位/调用它
  • 使用开始菜单中的VS2015工具命令提示符(基本上调用vcvarsall
  • [MS.Docs]: Building on the Command Line 包含有关此主题的更多详细信息

现在我们知道了 nmake 的位置,让我们运行:

"%VSTUDIO_INSTALL_DIR%\VC\bin\nmake.exe" /f makefile.vc setup-v10

(不要忘记将 nmake 的路径包含在 dblquotes(") 中,尤其是如果它包含 SPACEs)。

如果遇到问题,Google 可能会提供解决方案:

setup-v10 是一个 Makefile 目标,它只是简单地重命名文件夹中的一些文件(坦率地说,我不知道为什么这些文件不像已在第 1st 位置重命名)。

在文件夹中运行命令后,应该有2个VStudio解决方案文件:

  • jpeg.sln - 包含一个项目:
    • jpeg.vcxproj - 这是负责构建库的项目
  • apps.sln - 包含一堆项目(我不知道/不在乎他们在做什么):
    • djpeg.vcxproj - 这是我要提到的唯一一个,因为我将使用它来测试构建的库

2。构建 jpeg

要注意的第一个st 是在上一节中生成的解决方案/项目文件是针对VStudio 2010 的。但这不是问题,因为 VStudio 2015 能够处理它们(加载它们时,它会进行所有必要的转换以使它们保持最新状态)。

打开 jpeg.sln,会发现一些关于解决方案(和项目)的(不愉快的)内容:

  • 只有Win32 (32bit or x86) 平台
    • 它只有Release配置
  • 正如您已经提到的,它构建了一个静态库

无论如何,解决方案应该构建OOTB。完成后,您会注意到一个 Release 文件夹,其中应该包含(除了一堆中间 - .obj 文件),4+ MB jpeg.lib 文件,它是静态库。知道代码(和项目相关文件)都OK了,我们继续下一步。

2.1 构建jpeg DLL

为了避免破坏现有功能,我们应该创建一个新的配置(请注意,为您的项目创建一个新的平台的过程(几乎)相同):

  • 从菜单中选择构建 -> 配置管理器...
  • 在弹出的对话框中,向上点击Release组合框并选择
  • New Solution Configuration 对话框中,为新配置选择一个名称:我选择了 Release-DLL(从现在开始我将依赖这个名字)
  • 确保在组合框中复制设置中选择发布
  • 检查创建新项目配置

按下OK后,新的Release-DLL配置将与Release相同。下一步是对其进行必要的更改,以实现我们的目标。在Solution Explorer(在VStudio窗口的左侧)中RClickjpeg项目,然后选择属性:

在上图中,有 jpeg 项目设置窗口,显示了它们最后的样子。我突出显示(使用颜色)不同的兴趣点:

  • 蓝色:平台 / 配置对:

    • 正在修改(在最顶部的对话框中)
    • 活动(在VStudio主窗口后面)

    当修改一些平台/配置设置时确保它是活动的(蓝色矩形中的数据是相同的),否则你会把头撞在墙上,浪费时间试图弄清楚为什么看起来正确的事情没有按预期工作。在我看来,当这个对话框弹出时,它应该有 active 值,但并非总是如此。

  • 红色:应该修改(或至少需要注意)的项目:
    • 配置类型显然应该是动态库(.dll)
    • Platform Toolset 应该是 Visual Studio 2015 (我提这个,因为它碰巧用 VStudio2015 打开了一个 VStudio 2010 项目,它保留了旧的工具集,并继续使用它进行构建,但前提是你同时安装了这两个版本)
  • 绿色:建议修改的项目。这些只是文件夹。请注意$(Platform) 变量(我将其用作一个很好的实践),它在为多个平台(例如Win32x64)构建时会派上用场

全部保存并构建。构建成功后,会出现一个新的文件夹Win32-Release-DLL,和上一个一样,里面会包含一堆文件加上 jpeg.dll 。有人可能认为它已经完成了,但事实并非如此。所有的代码都在 .dll编译/构建,但它没有导出,所以 .dll 是几乎无法使用。您可以使用Dependency Walker 打开许多.dll(或.exe)属性。您可以查看来自[SO]: Excel VBA, Can't Find DLL Entry Point from a DLL file (@CristiFati's answer) 的屏幕截图 - 在我们的示例中,导出区域将为空。

最后一点:如果您认为将来需要为其他平台(x64,甚至 ARM ),并且你还需要做一些调试(添加一个 Debug 配置),在 Win32 平台下添加 Debug 配置首先,然后然后Win32创建新平台,否则您需要为每个平台添加Debug配置在将 Debug 配置添加到 Win32 之前创建。

2.2 从DLL导出数据

请注意:除了 __declspec(dllexport) 方法外,还有 2 个方法(在处理来自 Win 的导出时 .dlls):

但是,由于我们不知道代码并且可能有很多符号要导出,因此这 3 个中没有一个是可扩展的(它们可能需要大量的研究/工作)。无论如何,我们将坚持原来的方法:

  1. 保存以下代码:

    #pragma once
    
    #if defined(_WIN32)
    #  if defined(LIBJPEG_STATIC)
    #    define LIBJPEG_EXPORT_API
    #  else
    #    if defined(LIBJPEG_EXPORTS)
    #      define LIBJPEG_EXPORT_API __declspec(dllexport)
    #    else
    #      define LIBJPEG_EXPORT_API __declspec(dllimport)
    #    endif
    #  endif
    #else
    #  define LIBJPEG_EXPORT_API
    #endif
    

    libjpeg 源文件夹中名为 jexport.h 的文件中。这是一个非常标准的 header 文件,用于处理 .dll 导出。
    接下来,将其添加到项目中:在 Solution Explorer 中,RClick on Header Files -> Add -> Existing Item...

  2. 利用新文件

    --- jmorecfg.h.orig 2016-03-30 09:38:56.000000000 +0300
    +++ jmorecfg.h  2017-06-09 21:04:33.762535400 +0300
    @@ -30,6 +30,8 @@
      * in all cases (see below).
      */
    
    +#include "jexport.h"
    +
     #define BITS_IN_JSAMPLE  8 /* use 8, 9, 10, 11, or 12 */
    
    
    @@ -245,7 +247,8 @@
     /* a function referenced thru EXTERNs: */
     #define GLOBAL(type)       type
     /* a reference to a GLOBAL function: */
    -#define EXTERN(type)       extern type
    +
    +#define EXTERN(type)       extern LIBJPEG_EXPORT_API type
    
    
     /* This macro is used to declare a "method", that is, a function pointer.
    

    以上是一个差异。请参阅[SO]: Run/Debug a Django application's UnitTests from the mouse right click context menu in PyCharm Community Edition? (@CristiFati's answer)Patching utrunner 部分)了解如何在 Win 上应用补丁(基本上,每一行都以 one " 开头+" 符号进入,以 一个 "-" 符号开头的每一行都退出)。但是,由于更改是微不足道的,因此也可以手动完成。需要更改的文件是jmorecfg.h(需要2个东西):

    • 在开头包含新文件 (#include "jexport.h")
    • 修改第251行(将#define EXTERN(type) extern type替换为#define EXTERN(type) extern LIBJPEG_EXPORT_API type

    我认为这一步是一种解决方法(gainarie),但正如我所说,“真正的东西”只需要太多的工作(和时间)。

  3. 告诉编译器考虑我们的更改

    编辑项目设置(再次小心Platform / Configuration),选择Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions 并将旧值(在我的例子中:WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS)替换为 WIN32;LIBJPEG_EXPORTS;_CRT_SECURE_NO_WARNINGS;NDEBUG。我所做的是:

    1. 正在删除 _LIB
    2. 添加 LIBJPEG_EXPORTS
    3. 有些变化

    [MS.Docs]: /D (Preprocessor Definitions) 可能包含一些有用的信息。

    作为旁注,在进行上述更改后,原始(或“正常”)行为(发布配置)将不会OK (它会生成一堆警告,但这在技术上是不正确的)。那是因为我不想依赖 _LIB 宏来区分静态/动态库构建。为了解决问题,Preprocessor Definitions 中添加 LIBJPEG_STATIC 以进行 Release 配置(遵循与上述相同的过程) .

全部保存并构建。构建成功后,jpeg.dll被覆盖,更重要的是:会创建一个新文件jpeg.lib;这告诉我们 jpeg.dll 导出了一些东西。您可以使用 Dependency Walker 再次检查它。

3。测试 DLL

  • 这是可选的,我这样做是为了确保我到目前为止所做的一切没有白费
  • 通过测试,我只指构建和运行,这意味着我不进行任何功能测试(从 .dll 导出的函数实际上会做任何事情'应该)

加载 apps.sln 解决方案,最好在新的 VStudio 实例中。正如我所说,我只关心 djpeg 项目。

  1. 1st 要做的事情,就是为现有的Release 配置构建它。但是,由于对 jpeg 库所做的更改,它不会构建 OOTB(会有 linker 错误)。为了摆脱它们,编辑其设置,预处理器定义(就像在上一步中一样),并添加 LIBJPEG_STATIC(不要忘记分隔符(;))。

    构建应该成功并且在djpeg\Release文件夹下应该有一个djpeg.exe文件。尝试运行它,会成功(这是我唯一关心的事情)。

  2. 使用我们的 .dll 构建一个新的可执行文件:

    • 就像 jpeg 库的情况一样,创建一个新配置:Release-DLL(确保完成所有步骤,但不要更改它)李>
    • 只需要进行一项更改:让 链接器 知道我们在哪里构建 .lib 文件。进入项目设置,Configuration Properties -> Linker -> Input -> Additional Dependencies:第 1stRelease\jpeg.lib。显然路径不正确,所以我们需要将Release替换为Win32-Release-DLL(当然你可以使用VStudio宏(对于平台 / 配置))。可能会检查[MS.Docs]: .Lib Files as Linker Input

全部保存并构建。构建成功后,在djpeg\Release-DLL下,应该有一个djpeg.exe文件。尝试运行它会失败,因为它找不到 jpeg.dll。通过将 jpeg.dll 复制到(检查[MS.Docs]: Dynamic-Link Library Search Order 的语义)来解决这个问题:

  • djpeg.exe 的文件夹
  • %PATH% 环境变量中的一个文件夹(或相反,将 jpeg.dll 文件夹附加到 %PATH%)

再次,您可以使用 Dependency Walker 检查 2 个可执行文件(但大小差异足以说明:2nddjpeg.exe 是明显更小),查看哪个依赖于 jpeg.dll。无论如何,这是我计算机上的输出(是的,Dependency Walker 也可以充当 cmdline :)):

e:\Work\Dev\StackOverflow\q044450813\src\libjpeg-libjpeg-9b>"c:\Install\x86\Depends\Dependency Walker-politist-texan\AllVers\depends.exe" /c /ot:static.txt djpeg\Release\djpeg.exe

e:\Work\Dev\StackOverflow\q044450813\src\libjpeg-libjpeg-9b>"c:\Install\x86\Depends\Dependency Walker-politist-texan\AllVers\depends.exe" /c /ot:dynamic.txt djpeg\Release-DLL\djpeg.exe

e:\Work\Dev\StackOverflow\q044450813\src\libjpeg-libjpeg-9b>type static.txt | findstr -i "jpeg.dll"

e:\Work\Dev\StackOverflow\q044450813\src\libjpeg-libjpeg-9b>type dynamic.txt | findstr -i "jpeg.dll"
     [   ] e:\work\dev\stackoverflow\q044450813\src\libjpeg-libjpeg-9b\djpeg\release-dll\JPEG.DLL
[   ]  e:\work\dev\stackoverflow\q044450813\src\libjpeg-libjpeg-9b\djpeg\release-dll\JPEG.DLL   2017-06-09 21:16  2017-06-09 21:16    237,056  A      0x00000000     0x0003ECC8     x86  GUI        CV,Unknown  0x10000000      Unknown      0x0003E000    Not Loaded  N/A              N/A              0.0        14.0        6.0     6.0



更新#0

我也有:

【讨论】:

  • 感谢您的详细解答。我学到的是 EXTERN(type) 的宏,它一键添加了 __declspec(dllexport) 和 __declspec(dllimport)。我检查了其他 3rd-party 库,如 zlib,发现它与那里使用的技术相同。但是 libtiff 似乎没有使用这种方法。我不知道他们是如何在 tiff.dll 中导出函数的。
  • 正如我在回答中指定的,从 .dlls 导出内容的另一种选择是通过 模块定义文件。刚刚下载了libtiff,发现libtiff\libtiff.def
  • 我明白了。非常感谢您的帮助和有用的信息!
  • 我已经很好地完成了教程(谢谢!),但是 DLL 在第一次测试中没有正确链接。即使我已将JPEG_STATIC 添加到预处理器定义中,它也会给我错误LNK1181: cannot open input file 'Release\jpeg.lib'。我错过了什么?
  • @Draex_ (抱歉,我在 3 个月前发表了此评论,但我忘记明确添加您的 ID,因此您会收到通知):您应该使用新路径:"Win32-Release- DLL\\jpeg.lib" 如第 3 节的项目符号之一所述(如果您想使用动态版本)。检查lib在哪里构建,并添加该文件夹。也许您正在为 Debug 构建?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 2017-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多