如何构建libjpeg 9b的DLL版本? [英] How to build a DLL version of libjpeg 9b?

查看:130
本文介绍了如何构建libjpeg 9b的DLL版本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想构建一个libjpeg 9b的DLL版本。根据文档



上图是 jpeg 项目设置窗口,显示了最后的外观。我突出显示了(使用颜色)不同的兴趣点:




  • 蓝色:平台 / 配置对:




    • 正在修改(在最上方的对话框中)

    • 活动(在后面的 VStudio 主窗口中)



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


  • 红色:项目进行修改(或至少需要注意):


    • 配置类型显然应为动态库(.dll)

    • 平台工具集应该是 Visual Studio 2015 (我提到了这个,因为它碰巧用 VStudio2015 打开了 VStudio 2010 项目,并且保留了旧的工具集,并继续使用它进行构建,但这仅当您同时安装了两个版本时)


  • 绿色:建议修改的项目。这些只是文件夹。请注意 $(Platform)变量(我将其作为一个很好的实践),在构建多个平台(例如 Win32 和 x64



保存所有并进行构建。构建成功后,将出现一个新文件夹 Win32-Release-DLL ,并且与前一个文件夹一样,它将包含一堆文件 plus jpeg.dll 。也许有人认为它已经完成了,但事实并非如此。所有代码都是在 .dll 编译/构建的,但是它未导出,因此 .dll 是几乎无法使用。您可以使用.dll (或 .exe )属性。 > Dependency Walker 。您可以查看 [SO]:Excel VBA,无法从DLL文件中找到DLL入口点(@CristiFati的回答)-在我们的示例中,导出区域为空。



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



2.2从 DLL导出数据



请注意:除了 __ declspec(dllexport) 方法,还有2种(当处理 Win .dll s的出口时):





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


  1. 保存以下代码:

      #pragma一旦

    #如果已定义(_WIN32)
    #如果已定义(LIBJPEG_STATIC )
    #定义LIBJPEG_EXPORT_API
    #否则
    #如果已定义(LIBJPEG_EXPORTS)
    #定义LIBJPEG_EXPORT_API __declspec(dllexport)
    #否则
    #定义LIBJPEG_EXPORT_API __declspec( dllimport)
    #endif
    #endif
    #else
    #define LIBJPEG_EXPORT_API
    #endif

    libjpeg 源文件夹中名为 jexport.h 的文件中。这是一个非常标准的 header 文件,用于处理 .dll 导出。

    接下来,将其添加到项目中:在 Solution Explorer 头文件上的 RClick ->添加->现有项...


  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 @@
    *在所有情况下(请参阅下文)。
    * /

    +#include jexport.h
    +
    #define BITS_IN_JSAMPLE 8 / *使用8、9、10、11或12 * /


    @@ -245,7 +247,8 @@
    / *通过外部引用的函数:* /
    #define GLOBAL(type)type
    / *对GLOBAL函数的引用:* /
    -#define EXTERN(type)extern类型
    +
    +#define EXTERN(type)extern LIBJPEG_EXPORT_API类型


    / *此宏用于声明方法,即函数指针。

    上面是 diff 。参见 [ [SO]:从鼠标右键单击PyCharm Community Edition中的上下文菜单运行/调试Django应用程序的UnitTests? (@CristiFati的答案)修补 utrunner 部分),了解如何在 Win 上应用补丁(基本上,每行以一个 + 符号进入,以一个- 符号开头的每一行都熄灭)。但是,由于更改是微不足道的,因此也可以手动完成。需要更改的文件是 jmorecfg.h (需要2项):




    • 包括开头的新文件( #include jexport.h

    • 修改第251行(替换#通过定义EXTERN(type)extern类型 #define EXTERN(type)extern LIBJPEG_EXPORT_API type



    我认为此步骤是一种变通方法( gainarie ),但是正如我所说,真实的东西仅需要太多的工作(和时间) )。


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



    编辑项目设置(再次注意 Platform / Configuration ),选择 Configuration Properties-> C / C ++-> Preprocessor ->预处理程序定义,并将旧值(在我的情况下为: WIN32; NDEBUG; _LIB; _CRT_SECURE_NO_WARNINGS )替换为 WIN32; LIBJPEG_EXPORTS; _CRT_SECURE_NO_WARNINGS; NDEBUG 。我所做的是:


    1. 正在移除 _LIB

    2. 添加 LIBJPEG_EXPORTS

    3. 有些变化

    [MS.Docs]:/ D(预处理程序定义)可能包含一些有用的信息。



    作为附带说明上述更改后,原始(或正常)行为( Release 配置)将不会 OK (它将生成一堆警告,但这在技术上不正确) )。那是因为我不想依靠 _LIB 宏来区分静态库还是动态库。为了解决问题,请在预处理器定义中为发布配置添加 LIBJPEG_STATIC (遵循与上述相同的过程) 。


保存所有并进行构建。构建成功后, jpeg.dll 被覆盖,更重要的是:将创建一个新文件 jpeg.lib ;告诉我们 jpeg.dll 会导出某些内容。您可以使用 Dependency Walker 再次进行检查。



3。测试 DLL




  • 这是可选的,我这样做是为了确保到目前为止我所做的是并非徒然

  • 通过测试,我仅指代构建和运行,这意味着我不执行任何功能测试(从 .dll 实际上会执行应做的事情)



加载 apps.sln VStudio 实例中。正如我说的,我只关心 djpeg 项目。


  1. 1 st 要做的是为现有的 Release 配置构建它。但是,由于对 jpeg 库所做的更改,它不会生成 OOTB (会出现 linker 错误)。为了摆脱它们,请编辑其设置 Preprocessor Definitions (就像上一步一样),然后添加 LIBJPEG_STATIC (请不要忘记分隔符(; ))。



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


  2. 构建一个使用我们的 .dll




    • 就像在 jpeg 库的情况下一样,创建一个新配置: Release- DLL (确保执行所有步骤,但不要更改)

    • 仅需进行一项更改:让 linker 知道在哪里我们构建了 .lib 文件。转到项目设置,配置属性->链接器->输入->其他依赖项:第一个 st Release\jpeg.lib 。显然,该路径不正确,因此我们需要将 Release 替换为 Win32-Release-DLL (当然,您可以使用 VStudio 宏(用于平台 / 配置))。可能检查 [MS.Docs]:.lib文件作为链接器输入


保存所有并构建。构建成功后,在 djpeg\Release-DLL 下,应该有一个 djpeg.exe 文件。尝试运行它会失败,因为它找不到 jpeg.dll 。通过将 jpeg.dll 复制到(请检查 [MS.Docs]:语义的动态链接库搜索顺序):




  • djpeg.exe 的文件夹

  • %PATH% env var中的文件夹之一(或否则,将 jpeg.dll 文件夹附加到%PATH%



同样,您可以使用 Dependency Walker 检查2个可执行文件(但大小差异足以说明问题:2 nd djpeg.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\发布\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>键入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,未知0x10000000未知0x0003E000未加载N / AN / A 0.0 14.0 6.0 6.0








更新#0



我还:




I want to build a DLL version of libjpeg 9b. According to the document here, it seems that we need to add a preprocessor __declspec(dllexport) or __declspec(dllimport) before the declaration of each function to be exported, in addition to setting the Configuration Type to "Dynamic Library (.dll)". But this is not an easy job because there are so many functions in libjpeg. So, is there any short-cut or work-around to build a DLL libjpeg without or with little modification of the jpeglib.h? Is there any DLL-ready source of libjpeg 9b available? I am using Visual Studio 2015 on Windows 7 64bit. Thanks for your answer.

PS: I downloaded the source of libjpeg 9b from http://www.ijg.org/files/. Is this the official place to download it? I ask because the beginning bytes of .vcxproj (originally .v10) files seems invalid (C2 8B C2 AF C2 A8) so Visual Studio is unable to open it.

解决方案

Published builds (static / dynamic) on [GitHub]: CristiFati/Prebuilt-Binaries - (master) Prebuilt-Binaries/LibJPEG.



Like almost all of the nowadays software, libjpeg is also hosted on [GitHub]: winlibs/libjpeg - libjpeg-9b. I downloaded it from both places, did a comparison and only few minor differences (out of which none in the source code) popped up. I'm going to explain on the GitHub version. Unfortunately, there is no walkthrough on this, so I had to look inside some of the files in order to figure out what has to be done. Here's a list of steps:

1. Prepare the ground

1st thing is to extract the compressed (zip / tar.gz) file content into a folder (and have a cmd console opened there). That folder contains a bunch of files. The 1st one that we need is makefile.vc. As it name suggests, it's a Makefile that consists of a series of rules/instructions used in general to build stuff.

As a remark, I'm using VStudio (Community) 2015 (14.0) for this task (but there should be no differences for newer versions).

The tool that deals with Makefiles is nmake ([MS.Docs]: NMAKE reference). We need to call it against that file. nmake is located in "%VSTUDIO_INSTALL_DIR%\VC\bin\nmake.exe" (the env var doesn't really exist, it's just a path placeholder); typically that is "%SystemDrive%\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\nmake.exe" (e.g. on my machine it's "C:\Install\x86\Microsoft\Visual Studio Community\2015\VC\bin\nmake.exe").

Note that when dealing with VStudio command line tools, it's better to either:

  • Use vcvarsall (that's a (batch) tool that sets some env vars like %PATH%, %INCLUDE%, %LIB%, ...), so all the VStudio tools are available without their full path. But since it's also located in "%VSTUDIO_INSTALL_DIR%\VC\vcvarsall.bat", it doesn't worth the effort to locate/call it
  • Use VS2015 Tools Command Prompt from Start Menu (which basically calls vcvarsall)
  • [MS.Docs]: Building on the Command Line contains more details on this topic

Now that we know where nmake is located, let's run:

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

(don't forget to enclose nmake's path in dblquotes("), especially if it contains SPACEs).

If running into issues, Google will probably yield solutions:

setup-v10 is a Makefile target, which simply renames some of the files in the folder (frankly, I don't know why the files aren't like already renamed in the 1st place).

After running the command in the folder, there should be 2 VStudio solution files:

  • jpeg.sln - which contains one project:
    • jpeg.vcxproj - this is the project responsible of building the lib
  • apps.sln - which contains a bunch of projects (which I don't know/care what they do):
    • djpeg.vcxproj - this is the only one that I'm going to mention, since I'll be using it to test the built lib

2. Build the jpeg library

The 1st thing to notice is that the solution/project files generated in the previous section are for VStudio 2010. But that's not a problem, since VStudio 2015 is able to handle them (when loading them, it will do all the necessary conversions to bring them up to date).

Opening jpeg.sln, will reveal some (unpleasant) stuff about the solution (and project):

  • It only has Win32 (32bit or x86) platform
    • It only has Release configuration
  • As you already mentioned, it builds a static library

Anyway, the solution should build OOTB. After completion, you'd notice a Release folder which should contain (besides a bunch of intermediary - .obj files), a 4+ MB jpeg.lib file which is the static lib. Knowing that the code (and project related files) is OK, let's move on to the next step.

2.1 Build the jpeg DLL

In order to avoid breaking existing functionality, we should create a new configuration (note that the process of creating a new platform for your project is (almost) the same):

  • From menu, choose Build -> Configuration Manager...
  • In the dialog box that popped, up click on the Release combo box and select < New...>
  • In the New Solution Configuration dialog box, select a name for the new configuration: I chose Release-DLL (and from now on I'm going to rely on this name)
  • Make sure to select Release in the Copy settings from combobox
  • Check Create new project configurations

After pressing OK, the new the Release-DLL configuration will be identical to Release. Next step is to do the necessary changes to it, in order to achieve our goal. RClick on the jpeg project in the Solution Explorer (in the left side of VStudio window), and choose Properties:

In the image above, there's the jpeg project settings window, showing how they should look like at the end. I highlighted (using colors) different points of interest:

  • Blue: the Platform / Configuration pair:

    • That is being modified (in the topmost dialog box)
    • Active (in the VStudio main window in the back)

    When modifying some Platform / Configuration settings make sure that it's the active one (the data in the blue rectangles is identical), otherwise you'd bang your head against the walls and waste time trying to figure out why something that seems correct, doesn't work as expected. On my opinion, when this dialog box pops up, it should have the active values, but that's not always the case.

  • Red: items that should be modified (or at least require attention):
    • Configuration Type should obviously be Dynamic Library (.dll)
    • Platform Toolset should be Visual Studio 2015 (I'm mentioning this, since it happened to open a VStudio 2010 project with VStudio2015, and it kept the old toolset, and continued to build with it, but that's only if you have both versions installed)
  • Green: items recommended to be modified. Those are only folders. Notice the $(Platform) variable (that I use as a good practise), which comes in handy when building for more than 1 platform (e.g. Win32 and x64)

Save All and build. After the build succeeds, a new folder Win32-Release-DLL will appear, and like the previous one, it will contain a bunch of files plus jpeg.dll. One might think that it's done, but it's not quite so. All the code is compiled/built in the .dll, but it's not exported, so the .dll is pretty much unusable. You can check many of .dll (or .exe) properties opening it with Dependency Walker. You can look at the screenshots from [SO]: Excel VBA, Can't Find DLL Entry Point from a DLL file (@CristiFati's answer) - in our case the export area will be empty.

One final note: If you think that in the future you'll need to build for other platforms (x64, or even ARM), and also you'll need to do some debugging (add a Debug configuration), add the Debug configuration under Win32 platform first, and only then create the new platform from Win32, otherwise you'll need to add the Debug configuration for every platform created before adding the Debug configuration to Win32.

2.2 Export data from the DLL

Just as a note: besides the __declspec(dllexport) approach, there are 2 more (when dealing with exports from Win .dlls):

But, since we don't know the code and there might be many symbols to export, neither one of the 3 is scalable (they would probably require lots of research/work). Anyway, we'll stick to the original approach:

  1. Save the following piece of code:

    #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
    

    in a file called jexport.h in the libjpeg source folder. This is a pretty standard header file that deals with .dll exports.
    Next, add it to the project: in Solution Explorer, RClick on Header Files -> Add -> Existing Item...

  2. Make use of the new file

    --- 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.
    

    The above is a diff. See [SO]: Run/Debug a Django application's UnitTests from the mouse right click context menu in PyCharm Community Edition? (@CristiFati's answer) (Patching utrunner section) for how to apply patches on Win (basically, every line that starts with one "+" sign goes in, and every line that starts with one "-" sign goes out). But, since the changes are trivial, they can also be done manually. The file that needs to be changed, is jmorecfg.h (2 things are required):

    • Include the new file at the beginning (#include "jexport.h")
    • Modify line 251 (replace #define EXTERN(type) extern type by #define EXTERN(type) extern LIBJPEG_EXPORT_API type)

    I consider this step some kind of a workaround (gainarie), but as I stated, the "real thing" would simply require too much work (and time).

  3. Tell the compiler to take our changes into account

    Edit the project settings (again be careful with Platform / Configuration), select Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions and replace the old value (in my case: WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS) to WIN32;LIBJPEG_EXPORTS;_CRT_SECURE_NO_WARNINGS;NDEBUG. What I did was:

    1. Removing _LIB
    2. Adding LIBJPEG_EXPORTS
    3. Some shifting

    [MS.Docs]: /D (Preprocessor Definitions) might contain some useful info.

    As a side note, after the above changes, the original (or "normal") behavior (Release configuration) will not be OK (it will build with a bunch of warnings, but that's not correct technically). That is because I didn't want to rely on the _LIB macro to differentiate between the static / dynamic library build. To straighten things out, add LIBJPEG_STATIC in the Preprocessor Definitions for Release configuration (following the same procedure as above).

Save All and build. After the build succeeds, the jpeg.dll is overwritten, and what's more important: a new file jpeg.lib will be created; that tells us that jpeg.dll exports something. You can check it again with Dependency Walker.

3. Test the DLL

  • This is optional, I did it to be sure that what I did so far, was not in vain
  • By tests, I only refer to building and running, meaning that I don't do any functional testing (the functions exported from the .dll actually do whatever they're supposed to)

Load the apps.sln solution, preferably in a new VStudio instance. As I said, I only care about the djpeg project.

  1. 1st thing to do, is to build it for the existing Release configuration. But, because of the changes done to jpeg library, it won't build OOTB (there will be linker errors). In order to get rid of them, edit its settings, the Preprocessor Definitions (just like in the previous step), and add LIBJPEG_STATIC (don't forget the separator (;)).

    The build should be successful and under djpeg\Release folder, there should be a djpeg.exe file. Attempting to run it, will succeed (and this is the only thing I care about).

  2. Build a new executable that uses our .dll:

    • Just like in jpeg library's case, create a new configuration: Release-DLL (make sure to do all the steps, but don't change it)
    • There's only one change required: let the linker know where we built our .lib file. Go to project settings, Configuration Properties -> Linker -> Input -> Additional Dependencies: the 1st is Release\jpeg.lib. Obviously, the path is not correct, so we need to replace Release by Win32-Release-DLL (of course you could use VStudio macros (for Platform / Configuration)). Might check [MS.Docs]: .Lib Files as Linker Input.

Save All and build. After the build succeeds, under djpeg\Release-DLL, there should be a djpeg.exe file. Attempting to run it will fail, since it can't find jpeg.dll. Fix that by either copying jpeg.dll to (check [MS.Docs]: Dynamic-Link Library Search Order for the semantics):

  • The djpeg.exe's folder
  • One of the folders that's in the %PATH% env var (or the other way around, append the jpeg.dll folder to %PATH%)

Again, you can check the 2 executables with Dependency Walker (but the size difference says enough: the 2nd djpeg.exe is significantly smaller), to see which one depends on the jpeg.dll. Anyway, here's the output on my computer (yes, Dependency Walker can act as a cmdline as well :) ):

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



Update #0

I've also:

这篇关于如何构建libjpeg 9b的DLL版本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆