Compiling Libjpeg

Compiling libjpeg

Here is how I've built libjpeg using MinGW on Windows :

1. Get MinGW with MSYS

I've got a copy from http://sourceforge.net/projects/mingw/.
Quoting from www.mingw.org :

MSYS is a collection of GNU utilities such as bash, make, gawk and grep to allow building of applications and programs which depend on traditionally UNIX tools to be present.

We will need it to run the configure script that comes with libjpeg sources.


2. Get libjpeg sources

From http://www.ijg.org/, take the Unix format package (the Windows one won't work with this procedure). I took the jpeg_8d version.


3. Prepare a building directory

I've made a temporary directory named tmp in D:\, but you could choose whatever suits your needs. The thing that matters is the name of paths in MSYS. As it brings some * Unixity * to Windows, paths cannot be used in their original form.
In a nutshell:

C:\path\to\file becomes /c/path/to/file in MSYS land, an so
D:\tmp becomes /d/tmp.

Decompress the libjpeg sources in D:\tmp, so you have a jpeg-8d directory in there.

Create a jpeg-build directory inside D:\tmp, it will hold the built library.

Now everything is ready for the build.


4. ./configure, make, make install

That is the mantra of building in Unix land. An option should be added to redirect the install process to D:\tmp\jpeg-build.

Run the following commands in an MSYS shell (also named MinGW shell in Windows start menu):

cd /d/tmp/jpeg-8d
./configure --prefix=/d/tmp/jpeg-build
make
make install

As an additional step, you can run make test for safety.

These commands will build both static and shared versions of libjpeg.


5. Take the goods, delete the temporaries

If everything runs fine, you can delete the D:\tmp\jpeg-8d directory, but keep the jpeg-build one. It contains:

  • an include directory, containing libjpeg headers. You can move them to your compiler's headers directory.
  • a lib directory, with .a file to pass to the linker. You can move them to your compiler's library directory.
  • a bin directory, holding the libjpeg shared library libjpeg-8.dll and jpeg tools.
  • a share directory, containing man pages for the jpeg tools.

You can now build your program and link it against libjpeg by indicating the right include and library paths.


You can find many details about the libjpeg building and installation process in install.txt inside the source package.

I hope this will be useful.

How to build a DLL version of libjpeg 9b?

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) 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 (Nix style) 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" (check [SO]: Linking to CRT (unresolved external symbol WinMainCRTStartup) (@CristiFati's answer) for more details), 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:

  • One very likely to be encountered: fatal error U1052: file 'win32.mak' not found - check [SO]: Visual Studio NMake build fails with: fatal error U1052: file 'win32.mak' not found (@CristiFati's answer)

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 combo-box

  • 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:

VStudio settings

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 practice), 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 (or newer [GitHub]: lucasg/Dependencies). 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):

  • Pass the export list as arguments to the linker ([MS.Docs]: /EXPORT (Exports a Function))

  • Enumerate them in [MS.Docs]: Module-Definition Files

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

    2. Removing _LIB

    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:

  • Submitted the changes to [GitHub]: winlibs/libjpeg - Win: build libjpeg as a dll (rejected)

  • Tried to contact JPEG Reference (several times), but the form froze after hitting SEND (left it even overnight with no luck)

Do C/C++ compilers typically remove duplicate libraries?

Basically yes, it'll only include one copy.

The compile switches you are changing don't actually include one library into another, they just enable functionality that requires those libraries, e.g. libTIFF might include functions to convert between jpeg and tiff formats if you enable libJPEG support, but allows you to compile the rest of the library without that functionality if you don't want that.

When you link a final application with PoDoFo, you will also have to link all of the optional dependencies you enabled. This can be automatic for dynamic libraries but the dependencies will all be required at runtime.

In almost all cases there is only one copy of each library linked with the final application - the one exception is if you mix static and dynamic libraries, but that's a whole new can of worms.

How to check the libjpeg-turbo is built into opencv?

There should be a binary (executable) in your package called opencv_version, which you can run like this:

opencv_version -v | grep -i jpeg

Sample Output

JPEG:                        build-libjpeg-turbo (ver 1.5.3-62)
JPEG 2000: build (ver 1.900.1)

Equally, within Python, you can do:

import cv2
print(cv2.getBuildInformation())

Or, maybe more succinctly:

import cv2
import re

re.findall('.*jpeg.*',cv2.getBuildInformation())

Sample Output:

['    JPEG:                        build-libjpeg-turbo (ver 1.5.3-62)']


Related Topics



Leave a reply



Submit