HowTo: Compiling libvmime on MinGW/MSYS

This page gives the instructions on how to compile the libvmime sources under the MinGW and MSYS environment on Windows. It is not as straightforward as one might think. To prevent others (like you) from spending too much time on all the steps, this howto was created. It will guide you step-by-step on how to get to a working installation of MinGW and MSYS, with libvmime compiled.

Prerequisites

Before you can start any installation, compiling and so on, make sure you have the following software:

Installing MinGW

Installing and preparing MinGW is pretty straightforward. All you have to do is unpack the downloaded packages in one directory, for instance C:\MinGW\. This will create a directory structure as follows:

C:\MinGW
  bin
  doc
  include
  info
  lib
  libexec
  man
  mingw32
  share

You may delete the original packages from C:\MinGW if you are done, since they are not necessary beyond this point.

Installing MSYS

To install MSYS, execute the MSYS-1.0.11.exe file, and follow the instructions on screen. Choose the default path for installation, which is C:\msys\1.0.

Answer `y’ to the following question:

This is a post install process that will try to normalize between
your MinGW install if any as well as your previous MSYS installs
if any.  I don't have any traps as aborts will not hurt anything.
Do you wish to continue with the post install? [yn ]

Answer `y’ to the following question:

Do you have MinGW installed? [yn ] y

Specify the correct path to MinGW:

Please answer the following in the form of c:/foo/bar.
Where is your MinGW installation? C:/MinGW/

Afterwards, your MSYS installation is finished, and will mention the following:

Creating /etc/fstab with mingw mount bindings.
        Normalizing your MSYS environment.

        You have script /bin/awk
        You have script /bin/cmd
        You have script /bin/echo
        You have script /bin/egrep
        You have script /bin/fgrep
        You have script /bin/printf
        You have script /bin/pwd

        Oh joy, you do not have C:/MinGW//bin/make.exe. Keep it that way.

Try to start up the MSYS environment by opening C:\msys\1.0\msys.bat. If all okay, you should see a shell with sh started. You can go into bash by typing bash followed by a return.

Compile dependencies

Before compiling the dependencies, you may want to move all those packages to your MSYS home directory, e.g. C:\msys\1.0\home\$USERNAME. That way, when you start up MSYS you have all the packages ready.

libvmime is dependent on the following package hierarchy. This effectively describes the inter-dependencies between the packages.

  • libvmime-0.9.0
    • libiconv-1.13.1
    • gnutls-2.4.1
      • libgcrypt-1.4.5
        • libgpg-error-1.4.5
    • gnusasl-1.4.1

Building libiconv

Execute the following, in order:

$ tar -xvvzf libiconv-1.13.1.tar.gz
$ cd ./libiconv-1.13.1
$ ./configure --prefix=/mingw        #configures makefile, use /mingw as a prefix
$ make
$ make install

Building libgpg-error

Execute the following, in order:

$ tar -xvvzf libgpg-errort-1.4.5.tar.gz
$ cd ./libgcrypt-1.4.5
$ ./configure --prefix=/mingw        #configures makefile, use /mingw as a prefix
$ make
$ make install

Building libgcrypt

Execute the following, in order:

$ tar -xvvzf libgcrypt-1.4.5.tar.gz
$ cd ./libgcrypt-1.4.5
$ ./configure --prefix=/mingw        #configures makefile, use /mingw as a prefix
$ make
$ make install

Building gnutls

If you are attempting to build gnutls with a version of 2.8 or higher, stop now and take an earlier version. This is because starting from version 2.8 of gnutls, the tool libgnutls-config is deprecated. Since libvmime’s configure script needs this libgnutls-config, it will fail when you are trying to use 2.8 or higher. This tutorial uses version 2.4.1.

Execute the following, in order, and take a cup of coffee because this may take a while:

$ tar -xvvjf gnutls-2.4.1.tar.bz2
$ cd ./gnutls-2.4.1
$ ./configure --prefix=/mingw        #configures makefile, use /mingw as a prefix
$ make
$ make install

It may be possible to get the following message during the make step:

g++.exe: C:/MinGW/lib/gcc/mingw32/4.4.0/libstdc++.dll.a: No such file or directory

If so, open the following file in a text editor:

C:\MinGW\lib\gcc\mingw32\4.4.0\libstdc++.la,

and modify this line:

library_names='libstdc++.dll.a'

to

library_names=''

Save the file, and re-make the source.

Building libgsasl

Execute the following, in order:

$ tar -xvvzf libgsasl-1.4.1.tar.gz
$ cd ./libgsasl-1.4.1
$ ./configure --prefix=/mingw        #configures makefile, use /mingw as a prefix
$ make
$ make install

Building libvmime

Now the last part, which is building vmime itself using the just compiled dependencies. Execute the following, in order:

$ tar -xvvjf libvmime-0.9.0.tar.bz2
$ cd ./libvmime-0.9.0
$ ./configure --prefix=/mingw        #configures makefile, use /mingw as a prefix
$ make
$ make install

You’ll most likely get the following error:

c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/cwchar:159: error: '::swprintf' has not been declared
c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/cwchar:166: error: '::vswprintf' has not been declared

To circumvent this, you’ll have to hack the file C:\MinGW\lib\gcc\mingw32\4.4.0\include\c++\cwchar. Open that file in a text editor, and find the following lines:

  using ::swprintf;
  using ::swscanf;
  using ::ungetwc;
  using ::vfwprintf;
#if _GLIBCXX_HAVE_VFWSCANF
  using ::vfwscanf;
#endif
  using ::vswprintf;

and change that to

#ifndef __STRICT_ANSI__
  using ::swprintf;
#endif
  using ::swscanf;
  using ::ungetwc;
  using ::vfwprintf;
#if _GLIBCXX_HAVE_VFWSCANF
  using ::vfwscanf;
#endif
#ifndef __STRICT_ANSI__
  using ::vswprintf;
#endif

You’ll have to do this because the Makefile which was generated will execute g++ with the option -ansi. This somehow fails compilation, and is a known bug from MinGW.

After you’ve done this, you’ll 100% surely (if you used the 0.9.0 package of libvmime) get the following errors after you compile again:

../vmime/platforms/windows/windowsFile.hpp:76: error: conflicting return type specified for 'virtual const long unsigned int vmime::platforms::windows::windowsFile::getLength()'
../vmime/utility/file.hpp:150: error:   overriding 'virtual long unsigned int vmime::utility::file::getLength()'

(... lots of warnings ...)

platforms_windows_windowsFile.cpp:467: error: prototype for 'const size_t vmime::platforms::windows::windowsFileReaderInputStream::read(char*, size_t)' does not match any in class 'vmime::platforms::windows::windowsFileReaderInputStream'
../vmime/platforms/windows/windowsFile.hpp:158: error: candidate is: virtual size_t vmime::platforms::windows::windowsFileReaderInputStream::read(char*, size_t)

platforms_windows_windowsFile.cpp:475: warning: type qualifiers ignored on function return type

platforms_windows_windowsFile.cpp:475: error: prototype for 'const size_t vmime::platforms::windows::windowsFileReaderInputStream::skip(size_t)' does not match any in class 'vmime::platforms::windows::windowsFileReaderInputStream'
../vmime/platforms/windows/windowsFile.hpp:159: error: candidate is: virtual size_t vmime::platforms::windows::windowsFileReaderInputStream::skip(size_t)

This bug has been fixed in the most recent svn revision, so what you can do is either change the following files:

  • windowsFile.hpp – remove the const declaration on line #76
  • windowsFile.cpp – remove the const declaration on line #271
  • windowsFile.cpp – remove the first const declaration on line #467
  • windowsFile.cpp – remove the first const declaration on line #475

… or you can use the version which is currently in the trunk of svn. Invoke make again, and it should compile just fine.

Done

Well, that should do it! Try to make a test program, linking against libvmime:

// test.cpp
#include <string>
#include <vmime/vmime.hpp>

int main(int argc, char* argv[]) {
    vmime::ref<vmime::net::message> message;
    return 1;
}
$ g++ test.cpp -lvmime -liconv -lgnutls -lgsasl -lwsock32 -o test.exe

Note that the linked libraries are libvmime.a, libiconv.a, libgnutls.a, libgsasl.a AND libwsock32.a. Even though this last one is not really necessary for the small test application above, you will need it when using the vmime::platforms::windows::windowsHandler.

Linking problems and undefined references

After you’ve tried to compile a program linking against libvmime, you may have encountered the following error messages:

undefined reference to `IID_IMultiLanguage' and
undefined reference to `CLSID_CMultiLanguage'

The only place these are used are in the vmime::platforms::windows::windowsHandler::getLocaleCharset() function, residing in src/vmime/platforms/windows/windowsHandler.cpp. Since I couldn’t find the correct .a files to link against, I decided to comment out a whole block, so the (partial cpp) file looks as follows:

 // windowsHandler.cpp
const vmime::charset windowsHandler::getLocaleCharset() const {
/*
#ifdef VMIME_HAVE_MLANG_H

	char szCharset[256];

	CoInitialize(NULL);
	{
		IMultiLanguage* pMultiLanguage;
		CoCreateInstance(
			CLSID_CMultiLanguage,
			NULL,
			CLSCTX_INPROC_SERVER,
			IID_IMultiLanguage,
			(void**)&pMultiLanguage);

		UINT codePage = GetACP();
		MIMECPINFO cpInfo;
		pMultiLanguage->GetCodePageInfo(codePage, &cpInfo);

		int nLengthW = lstrlenW(cpInfo.wszBodyCharset) + 1;

		WideCharToMultiByte(codePage, 0, cpInfo.wszBodyCharset, nLengthW, szCharset, sizeof(szCharset), NULL, NULL );

		pMultiLanguage->Release();

	}
	CoUninitialize();

	return vmime::charset(szCharset);
#else // VMIME_HAVE_MLANG_H
*/
	vmime::string ch = vmime::charsets::ISO8859_1; // default

	switch (GetACP())
	{
	case 437: ch = vmime::charsets::CP_437; break;
	case 737: ch = vmime::charsets::CP_737; break;
	case 775: ch = vmime::charsets::CP_775; break;
	case 850: ch = vmime::charsets::CP_850; break;
	case 852: ch = vmime::charsets::CP_852; break;
	case 853: ch = vmime::charsets::CP_853; break;
	case 855: ch = vmime::charsets::CP_855; break;
	case 857: ch = vmime::charsets::CP_857; break;
	case 858: ch = vmime::charsets::CP_858; break;
	case 860: ch = vmime::charsets::CP_860; break;
	case 861: ch = vmime::charsets::CP_861; break;
	case 862: ch = vmime::charsets::CP_862; break;
	case 863: ch = vmime::charsets::CP_863; break;
	case 864: ch = vmime::charsets::CP_864; break;
	case 865: ch = vmime::charsets::CP_865; break;
	case 866: ch = vmime::charsets::CP_866; break;
	case 869: ch = vmime::charsets::CP_869; break;
	case 874: ch = vmime::charsets::CP_874; break;

	case 1125: ch = vmime::charsets::CP_1125; break;
	case 1250: ch = vmime::charsets::CP_1250; break;
	case 1251: ch = vmime::charsets::CP_1251; break;
	case 1252: ch = vmime::charsets::CP_1252; break;
	case 1253: ch = vmime::charsets::CP_1253; break;
	case 1254: ch = vmime::charsets::CP_1254; break;
	case 1255: ch = vmime::charsets::CP_1255; break;
	case 1256: ch = vmime::charsets::CP_1256; break;
	case 1257: ch = vmime::charsets::CP_1257; break;

	case 28591: ch = vmime::charsets::ISO8859_1; break;
	case 28592: ch = vmime::charsets::ISO8859_2; break;
	case 28593: ch = vmime::charsets::ISO8859_3; break;
	case 28594: ch = vmime::charsets::ISO8859_4; break;
	case 28595: ch = vmime::charsets::ISO8859_5; break;
	case 28596: ch = vmime::charsets::ISO8859_6; break;
	case 28597: ch = vmime::charsets::ISO8859_7; break;
	case 28598: ch = vmime::charsets::ISO8859_8; break;
	case 28599: ch = vmime::charsets::ISO8859_9; break;
	case 28605: ch = vmime::charsets::ISO8859_15; break;

	case 65000: ch = vmime::charsets::UTF_7; break;
	case 65001: ch = vmime::charsets::UTF_8; break;
	}

	return (vmime::charset(ch));
    /*
#endif*/
}

libvmime has to be recompiled of course for this change to take effect.

Any comments are welcome.

18 Comments

  • By Kevin Pors, April 8, 2010 @ 12:42

    I’ve updated this howto with Linking Problems.

  • By Josh, April 11, 2010 @ 20:23

    I’m having a little trouble installing the gnutls package. I made the change you mentioned, but now I’m getting a bunch of undefined reference errors when I run the ‘make’ command. I tried with the version you posted, and also 2.6.6 to see if maybe that was the problem, but I still get a bunch of errors. I have a full error log at http://circleofcurrent.nfshost.com/error.log

    Some googling tells me that these are linker errors causes by using gcc instead of g++, but I don’t know how to fix that when using the makefiles that were generated. I’ve followed the rest of your instructions very closely (except I installed libiconv, libgpg-error and gnusasl at the same time in three separate windows to save a bit of time)

    Any idea what the problem is?

  • By bosch, April 12, 2010 @ 08:00

    The “Building libgcrypt” method is wrong!
    I can not build according to you procedures when build the libgcrypt!

    ——–
    checking for aCC… no
    checking for CC… no
    checking for cxx… no
    checking for cc++… no
    checking for cl.exe… no
    checking for FCC… no
    checking for KCC… no
    checking for RCC… no
    checking for xlC_r… no
    checking for xlC… no
    checking whether we are using the GNU C++ compiler… no
    checking whether g++ accepts -g… no
    checking dependency style of g++… none
    checking how to run the C++ preprocessor… /lib/cpp
    configure: error: C++ preprocessor “/lib/cpp” fails sanity check
    See `config.log’ for more details.

  • By Jason, April 12, 2010 @ 09:13

    Is there a way to speed this up by using the binaries at http://josefsson.org/gnutls4win/ ?

  • By Kevin Pors, April 12, 2010 @ 09:14

    @Josh:

    Weird, I executed these instructions three times in a row (first time to actually try it all, second time to write the howto with, and the third time to confirm the howto) and I haven’t seen the errors you mention. Are you using all the exact same versions of the software listed here? I assume that the other packages (libiconv, gnusasl, libgpg-error) compiled just fine?

    I’d like to reproduce it, but I am not sure how.

  • By bosch, April 12, 2010 @ 09:49

    Dear Kevin,
    Could you please send your msn account to my email: xuplus@126.com ?
    I hope I could talk with you by MSN.
    Sincerely.
    Bosch

  • By bosch, April 12, 2010 @ 09:50

    Or could you send me the lib and the according dll file of VMiMe to me ?
    Thanks in advance.

  • By bosch, April 12, 2010 @ 09:54

    In fact this link is broken currently.
    MinGW – This can be downloaded from here. Follow

    http://www.mingw.org/wiki/Getting_Started

  • By Kevin Pors, April 12, 2010 @ 12:35

    @Jason: Looks like that it may speed up the process by using precompiled binaries indeed.

  • By bosch, April 12, 2010 @ 13:12

    Kevin,
    I need you help indeed.
    Could you give me your msn?
    Please send it to my email xuplus@126.com
    Thanks in advance.

  • By Kevin Pors, April 12, 2010 @ 13:56

    @Bosch: I already tried to add you as a contact.

  • By Mark Brand, April 12, 2010 @ 22:01

    Just wanted to mention that it’s remarkably easy to cross build for MinGW using mingw-cross-env. This environment comes with vmime and many other libraries working out of the box.

    http://www.nongnu.org/mingw-cross-env/

  • By Josh, April 13, 2010 @ 02:36

    @Kevin: Yeah, I’m using the same versions as you, I even used your links to download them. They all compiled fine until I got to gnutls.

    After looking at the output from running ‘make’ a little more carefully, I noticed this:

    *** Warning: This system can not link to static lib archive /mingw/lib/libstdc++.la.
    *** I have the capability to make that library automatically link in when
    *** you link to this library. But I can only do this if you have a
    *** shared version of the library, which you do not appear to have.

    It seems that one of the tools used by ‘make’ can’t find the libstdc++ shared library. The file it’s talking about does exist though, and I haven’t changed it so I’m not sure why it can’t link. Any ideas?

  • By Josh, April 15, 2010 @ 00:18

    Okay, I don’t know what the problem I had was, but I started everything over from scratch and it works fine. I probably missed a small step or something, but I can’t imagine what. Anyways, thanks for the awesome tutorial!

  • By athkou, April 17, 2010 @ 04:46

    Hello Kevin, first of all nice tutorial. I want to use vmime together with Qt. After building the library I can’t find any dll files in the libvmime folder. There is a libvmime.a file. Is it so right?

  • By Kevin Pors, April 19, 2010 @ 12:50

    Hey Josh, sorry for my late response. Busy at work! I did some searching on Google but I couldn’t find anything useful to help you with the problem. I’m glad you got it working now though!

  • By Kevin Pors, April 19, 2010 @ 12:57

    @athkou: That seems to be correct. Only an .a file is needed for the linking.

  • By tsachy, May 11, 2010 @ 20:55

    Kevin,
    First of all, thank you for this howto. I followed it to the letter and it worked smoothly. I can now compile with vmime.
    I wanted to share a way I found to solve the undefined references problem during link:
    basically, what’s missing is also linking with library libuuid.a, by adding -luuid to the g++ command line.
    However, this only solves one problem (the missing CLSID_CMultiLanguage), but the IID is still missing from that library. Fortunately, it’s easy enough to add it by changing 1 line and compiling libuuid.a.
    You need to get the source code for MinGW’s W32 API (from http://sourceforge.net/projects/mingw/files/MinGW%20API%20for%20MS-Windows/w32api-3.14/w32api-3.14-mingw32-src.tar.gz/download), and edit mingw32/lib/mlang-uuid.c.
    Add this line to the end of the file:
    DEFINE_GUID(IID_IMultiLanguage, 0×275c23e1,0×3747,0×11d0,0×9f,0xea,0×00,0xaa,0×00,0×3f,0×86,0×46);
    then compile and link with the new libuuid.a.
    This should solve the problem.
    I hope this is the right thing to do and that the UUID is correct. it’s the same as for the CLSID. I found this here: http://www.mail-archive.com/wine-devel@winehq.org/msg09272.html

Other Links to this Post

RSS feed for comments on this post. TrackBack URI

Leave a comment

Based on a theme from Blogchemistry