Building OpenEXR libraries for Windows x64

May 25th, 2010 by Bramz

LiAR supports the OpenEXR file format for several months now, but I only had it working on 32-bit windows. I was still missing the binaries for the 64-bit build, as you need to build the library yourself. For 64-bit Windows that turns out to be one tricky affair:

  1. Only Visual Studio solution files are available so that rules out nmake.
  2. DLL creation involves an custom build tailored for x86.
  3. The Visual C++ Express editions are x86 only anyway, so you have to work around that as well.
  4. And surprisingly, it seems that no-one has ever bothered so before because there’s hardly anything to be found on the web.

After several hours of hairpulling, I’ve finally managed to set up a working x64 build. To document it for future reference, and for other people on the same adventure, here are the magic build steps:

Setting up the build tree

The OpenEXR build is rather picky on the build tree layout. While the absolute location is free for choice, you need to add an extra layer for things to play out nicely. On my machine, I’ve put everything in C:\libs-x64\openexr-1.6.1, but that could be just any other location.

  1. Download ilmbase-1.0.1.tar.gz and openexr-1.6.1.tar.gz.
  2. Create C:\libs-x64\openexr-1.6.1\openexr.

    This extra layer is necessary to make sure the goodies are gathered in C:\libs-x64\openexr-1.6.1\Deploy. Otherwise, they would end up in C:\libs-x64\Deploy.

  3. Extract ilmbase-1.0.1.tar.gz to
    C:\libs-x64\openexr-1.6.1\openexr\ilmbase-1.0.1
  4. Extract openexr-1.6.1.tar.gz to
    C:\libs-x64\openexr-1.6.1\openexr\openexr-1.6.1

Using VC Express for x64 builds

For Windows, OpenEXR comes with Visual Studio project files only. So you must use Visual C++ for building. If you’re using the VC Express edition, that’s a problem because it only has a x86 compiler on board. And you can’t directly use the x64 compiler of the Windows SDK, as that requires nmake makefiles, which you don’t have. But you can do it indirectly …

  1. Open a Windows SDK CMD shell. This sets all the required environment variables to use the x64 compiler.
  2. "%VCINSTALLDIR%\..\Common7\IDE\VCExpress" /useenv or whatever the location to vcexpress.exe is.

    The /useenv switch is important to tell the IDE not to use the default compiler, but to assume the environment is already setup ready to go. This is exactly why we run this within the Windows SDK shell.

  3. Open a solution and make sure you target the x64 platform.

    You won’t be able to setup a new x64 configuration, but you can just open the Win32 configuration, go to the advanced linker options and specify MachineX64 (/MACHINEX64) as target machine.

  4. Build …

Building IlmBase

IlmBase contains the createDLL project that builds a tool for the custom build steps. You need to tweak its sources to correctly skip names starting with an underscore. Because createDLL assumes the x86 __cdecl calling convention which decorates names with an extra underscore, it actually only skips names that start with at least two underscores. But the x64 calling convention does not decorate them as such, so names starting with a single underscore slip through the net.

  1. Start VC Express, open
    ilmbase-1.0.1\vc\vc8\IlmBase\IlmBase.sln and convert if necessary.
  2. Set the target machine to MachineX64 (see above)
  3. Open createDLL.cpp to make the following code changes:
    • Replace /MACHINE:X86 by /MACHINE:X64 (line 683)
    • Replace the following (three occurrences!)

      // symbol starts with two underbars, skip it
      else if (buf[0] == ‘_’ && buf[1] == ‘_’) {

      by

      // symbol starts with underbar, skip it
      else if (buf[0] == ‘_’) {

  4. Build …

    If you get errors like fatal error LNK1112: module machine type 'X86' conflicts with target machine type 'x64', you should have started VCExpress with the /useenv switch from the Windows SDK CMD shell, as described above.

Building zlib:

OpenEXR has a dependency on zlib. So if you don’t have done so yet, now is the time to build it …

  1. Download zlib125.zip and extract to C:\libs-x64\zlib-1.2.5
  2. Open a Windows SDK CMD shell
  3. cd /D C:\libs-x64\zlib-1.2.5
  4. set Include=C:\libs-x64\zlib-1.2.5;%Include%
  5. nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF" OBJA="inffasx64.obj gvmat64.obj inffas8664.obj"

Building OpenEXR

OpenEXR expects the zlib headers and libraries to be in the Deploy directory as well, so that’s where we’re going to put them.

  1. Copy zlib.h and zconf.h from C:\libs-x64\zlib-1.2.5 to Deploy\include
  2. Copy zdll.lib to both Deploy\lib\Debug and
    Deploy\lib\Release
  3. Copy zlib1.dll to both Deploy\bin\Debug and
    Deploy\bin\Release
  4. Start VCExpress and open
    openexr-1.6.1\vc\vc8\OpenEXR\OpenEXR.sln
  5. Set the target machine to MachineX64 (see above)
  6. Build …

That’s it. By now you should have a Deploy directory filled with OpenEXR headers and libraries, ready to be used in your x64 build of, for example, LiAR =)

Happy Towel Day!

18 Responses to “Building OpenEXR libraries for Windows x64”

  1. david Says:

    Hi there ! Thanks for this post !

    I’m using Visual Studio Express on Visual Studio 2010, and when i try compiling it i’ve got the following error for all dll:

    TRACKER : error TRK0002: Failed to execute command: “”C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\Bin\amd64\CL.exe” “@C:\Documents and Settings\Administrator\Local Settings\Temp\b521257dd13848deb2932172c4435339.rsp””. The handle is invalid.

    I’ve googling a bit but without success…. did you face this issue ?

  2. bramz Says:

    Hi David,

    No, I haven’t seen that message before. I didn’t try it with Visual C++ 2010 Express to be honest. I’ve used the 2008 edition. From what I’ve googled, it appears to be a wider issue with VC++ 2010 on x64 windows …

    Bram

  3. Bruce Says:

    Bram,

    You rock! Thanks for the timesaving tips, worked a treat for me…

  4. bramz Says:

    Hi Bruce,

    Thanks, I’m glad it helped …

  5. Johanna Says:

    Hi!
    Your post helped me to figure out where did that Deploy folder go.. I was a bit confused before. So thanks for that!
    I still have one persistent issue that you might be familiar with.. When I try to compile openExr (with the previous steps done) it throws ùe the following error :
    fatal error LNK1181: cannot open input file ‘..\win32\release\ilmimf.lib’
    It seems normal that it cannot open it since it doesn’t seem to exist at all… Do you know how I could fix that ?

    Thanks !

  6. bramz Says:

    Hi Johanna,

    IlmImf should be part of the openexr build itself. What version of OpenEXR are you trying to build?

    Bram

  7. Johanna Says:

    I’m trying to build the 1.6.1 version which is apparently the last stable version. I also tried the 1.7.0, with no more luck.
    Are you saying that I don’t need to build IlmImf separately ? Because in the readme files, it still says to do it this way.

    Jo

  8. Johanna Says:

    OK, so apparently there was some trouble with the 64bits version. I’ve been given a pre-compiled version (I don’t know from who though, sorry..) so no more trouble.
    Anyway, thanks for your interest !

  9. Julien Says:

    Hey!
    I am working with Johanna,
    the prebuild lib isn’t working so we need to rebuild ourselves.
    All the fix for x64 are succesfull for the libs, except the zlib linking on ImfImf :

    1>CreateDLL found 3140 symbols
    1>Exporting DLL
    1> Creating library ..\Win32\Release\IlmImf.lib and object ..\Win32\Release\IlmImf.exp
    1>ImfPxr24Compressor.obj : error LNK2019: unresolved external symbol compress referenced in function “private: int __cdecl Imf::Pxr24Compressor::compress(char const *,int,class Imath::Box<class Imath::Vec2 >,char const * &)” (?compress@Pxr24Compressor@Imf@@AEAAHPEBDHV?$Box@V?$Vec2@H@Imath@@@Imath@@AEAPEBD@Z)
    1>ImfZipCompressor.obj : error LNK2001: unresolved external symbol compress
    1>ImfPxr24Compressor.obj : error LNK2019: unresolved external symbol uncompress referenced in function “private: int __cdecl Imf::Pxr24Compressor::uncompress(char const *,int,class Imath::Box<class Imath::Vec2 >,char const * &)” (?uncompress@Pxr24Compressor@Imf@@AEAAHPEBDHV?$Box@V?$Vec2@H@Imath@@@Imath@@AEAPEBD@Z)
    1>ImfZipCompressor.obj : error LNK2001: unresolved external symbol uncompress
    1>..\Win32\Release\IlmImf.dll : fatal error LNK1120: 2 unresolved externals
    1>createDLL: linking failure. Linker: link.exe, status: 1120
    1>Project : error PRJ0019: A tool returned an error code from “Performing Post-Build Event…”

    I tried linking against
    * recompiled zlib-1.2.5 following your instructions with nmake / platform sdk
    * precompiled zlib zlib125dll\dllx64\zlibwapi.lib
    * libzlib_dll.lib from Hebbut.net
    The linker doesn’t like any of those…It looks like createDll is still the problem ?
    In createDLL_out.txt there is no zlib.lib, although I added it to the linker inputs in VC :
    Input Libraries:
    Half.lib
    Iex.lib
    IlmThread.lib
    MSVCRT.lib
    kernel32.lib
    msvcprt.lib
    createDLL: linking failure. Linker: link.exe, status: 1120

    Thank you!
    best regards

    Julien

  10. Julien Says:

    I found the solution, i had to link ImfImf against zdll.lib…
    thanks!
    Julien

  11. bramz Says:

    Hi Julien,

    I’m glad it works alright now! So IllImf doesn’t link against zlib by default? Or, does it looks for an import library by another name? I’ll see to update the instructions …

    Happy coding!
    Bram

  12. pm Says:

    well,
    great! thanks very much for this survey, it saved me for sure one whole day or even longer. i got openEXR win64 compiled in 1 hour only thanks to you. in fact i complied the 1.7.0 version on visual studio 2010 which works quite the same way as described here. the only issue is the one mentioned by julien – one has to replace the linkage of “zlibwapi.lib” against “zdll.lib” in the IlmImf project setup. of course one has to compile zlib as described above. and there is no need to fix the solution-files for 64 bit anymore; one only needs to convert them to visual studio 2010 and switch the configuration and build targets (which are already well defined) to “release/x64”.
    works fine.
    cheers
    pm

  13. bramz Says:

    Hi pm,

    I didn’t see your comment until now, but thanks! I’m glad it helped. I’ll try out the 1.7.0 version myself, taking this zlib thing into account, and update the instructions accordingly.

    Thanks,
    Bram

  14. OpenEXR x64 for Windows (64 Bit) in Visual Studio 2010 | The Black Hat Says:

    […] Building OpenEXR (Hugin SDK) Building OpenEXR x64 (Liar’s blog) Compiling zlib This entry was posted in C++, Coding, Computer Vision by Michael. Bookmark the […]

  15. Dozie Says:

    I have the same LNK problems and I did the same thing you guys suggested but it doesn’t seem to change anything. I am close to pulling out my hair as I have WASTED two days on this problem. Please someone help!!!

  16. bramz Says:

    OK, for the 1.7.0 version, what I ended up doing is to write CMakeLists for it. Here‘s a zip with the required files if you know what you’re doing. I should eventually write an update on this. Hope it helps!

  17. bramz Says:

    Dozie, in OpenEXR, there should be a line somewhere like:

    #define ZLIB_WINAPI

    Try to comment it out. If it doesn’t work, put it back and tell us the exact linker problems.

  18. senna Says:

    Hi all,

    I comment out that line, but it still get linker error like this:

    ImfHeader.obj : error LNK2019: unresolved external symbol “public: static char const * __cdecl Imf::TypedAttribute<class std::vector<class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::allocator<class std::basic_string<char,struct std::char_traits,class std::allocator > > > >::staticTypeName(void)” (?staticTypeName@?$TypedAttribute@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Imf@@SAPBDXZ) referenced in function “public: static void __cdecl Imf::TypedAttribute<class std::vector<class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::allocator<class std::basic_string<char,struct std::char_traits,class std::allocator > > > >::registerAttributeType(void)” (?registerAttributeType@?$TypedAttribute@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Imf@@SAXXZ)
    1>ImfStandardAttributes.obj : error LNK2001: unresolved external symbol “public: static char const * __cdecl Imf::TypedAttribute<class std::vector<class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::allocator<class std::basic_string<char,struct std::char_traits,class std::allocator > > > >::staticTypeName(void)” (?staticTypeName@?$TypedAttribute@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Imf@@SAPBDXZ)
    1>ImfHeader.obj : error LNK2001: unresolved external symbol “public: virtual void __thiscall Imf::TypedAttribute<class std::vector<class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::allocator<class std::basic_string<char,struct std::char_traits,class std::allocator > > > >::writeValueTo(class Imf::OStream &,int)const ” (?writeValueTo@?$TypedAttribute@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Imf@@UBEXAAVOStream@2@H@Z)
    1>ImfStandardAttributes.obj : error LNK2001: unresolved external symbol “public: virtual void __thiscall Imf::TypedAttribute<class std::vector<class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::allocator<class std::basic_string<char,struct std::char_traits,class std::allocator > > > >::writeValueTo(class Imf::OStream &,int)const ” (?writeValueTo@?$TypedAttribute@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Imf@@UBEXAAVOStream@2@H@Z)
    1>ImfHeader.obj : error LNK2001: unresolved external symbol “public: virtual void __thiscall Imf::TypedAttribute<class std::vector<class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::allocator<class std::basic_string<char,struct std::char_traits,class std::allocator > > > >::readValueFrom(class Imf::IStream &,int,int)” (?readValueFrom@?$TypedAttribute@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Imf@@UAEXAAVIStream@2@HH@Z)
    1>ImfStandardAttributes.obj : error LNK2001: unresolved external symbol “public: virtual void __thiscall Imf::TypedAttribute<class std::vector<class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::allocator<class std::basic_string<char,struct std::char_traits,class std::allocator > > > >::readValueFrom(class Imf::IStream &,int,int)” (?readValueFrom@?$TypedAttribute@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@std@@@Imf@@UAEXAAVIStream@2@HH@Z)
    1>..\Release/IlmImf.dll : fatal error LNK1120: 3 unresolved externals

    Please help me.

    Thanks,