HOWTO: Compiling libvmime on MinGW/MSYS

Introduction

This document 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 interdependencies between the packages.

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: ... 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 -o test.exe