Wednesday, July 23, 2008

win32 native mono from scratch

As a command line jockey, linux expert, and general unix fanatic, you can imagine my dismay when I learned I would be maintaining a significant C# code base. Until recently, I had never give the mono project a second thought (other than to question why a team of obviously talented programmers would want to spend their time implementing a language from microsoft), but suddenly, I find by daily programming productivity, prowess, and general happiness utterly depends on being able to build my C# apps with a reasonable open source tool chain. Enter mono.



Building mono from scratch proved to be a bit of a challenge, most of the instructions I was able to find either require that either mono be first installed (can you say circular dependency) or that some binary packages be downloaded. Neither of these solutions seemed quite satisfactory, so here are my instructions, for building mono, from scratch, using cygwin/mingw32.



First, you will need a basic cygwin installation, including gcc and the gcc-mingw32 packages.



Second, you will need to get the source for each of these packages:


libiconv (I used version 1.12)

gettext (I used version 0.17)

glib (I used version 2.14.5)

mono (I used both 1.2.6)



Next, we will build libiconv.


./configure --build=i686-pc-mingw32 \

    CC="gcc -mno-cygwin -mms-bitfields" \

    CXX="g++ -mno-cygwin -mms-bitfields"

make

make install


The key here is to make sure that you include the "-mno-cgywin" flag for gcc to ensure a native win32 executable (or library in this case).



After, libiconv, we can build gettext in a similar fashion. We do need to take care to ensure that gettext can find libiconv built and installed above.


./configure --build=i686-pc-mingw32 \

    CC="gcc -mno-cygwin -mms-bitfields" \

    CXX="g++ -mno-cygwin -mms-bitfields" \

    PATH="<libiconv-path>/bin:$PATH" \

    LDFLAGS="-L<libiconv-path>/lib"

make

make install


Note, windows uses PATH to find libraries as well as executables, as opposed to LD_LIBRARY_PATH. Also, I like to disable stuff I don't need, so I'll add --without-emacs, --disable-java, and LINGUAS="" to that configure command, you can pick and choose your own options as well.



glib is probably the most difficult of the mono dependencies to build. For one, in addition to libiconv and gettext, it requires the win32 api provided by mingw32, but can't seem to find it without some help (note the -L/usr/lib/w32api entry in LDFLAGS).


./configure --build=i686-pc-mingw32 \

    CC="gcc -mno-cygwin -mms-bitfields" \

    CXX="g++ -mno-cygwin -mms-bitfields" \

    CPPFLAGS="-I<libiconv-path>/include -I<gettext-path>/include" \

    LDFLAGS="-L<libiconv-path>/lib -L<libiconv-path>/lib -L/usr/lib/w32api"

make

make install


You may also find that line endings (win32 prefers crlf, while cygwin and the gnu toolchain may only expect lf) get in the way of some of the autoconf test. I had to fix up the configure script with the following sed one-liner.

sed -i 's/\(fopen *(.*\)"w"/\1"wb"/' configure



Finally, we are ready to build mono. So here goes.


./configure --build=i686-pc-mingw32 \

    CC="gcc -mno-cygwin -mms-bitfields" \

    CXX="g++ -mno-cygwin -mms-bitfields" \

    PKG_CONFIG_PATH="<glib-path>/lib/pkgconfig"

    CPPFLAGS="-I<libiconv-path>/include -I<gettext-path>/include -I<glib-path>/include"
\

    LDFLAGS="-L<libiconv-path>/lib -L<gettext-path>lib -L<glib-path>/lib -L/usr/lib/w32api"

make

make install


Nothing really new there, just as before, add the path to the glib headers to CPPFLAGS, the glib libraries to LDLFAGS, and the glib pkgconfig path to PKG_CONFIG_PATH (ok, I guess the pkgconfig part is kind of new).



Congratulations, if you've gotten this far, you should have a working native win32 version of mono built from scratch. Next, you'll want to checkout how to use autotools to build that C# project using your shiny new mono compiler.

No comments: