Building Mono on Windows by Kevin Shockey 02/07/2005

Introduction

Mono, the open source implementation of the CLR, is not just for non-Microsoft platforms. In this article I will walk you through the three phases required to build Mono on Windows without using the .NET framework. There have already been several build processes available before, but they mostly required using the csc.exe C# compiler from the Microsoft .NET framework. This process is distinct in that you will use the mcs.exe Mono C# compiler.

There are three phases in this build process:

  1. We start out installing the Cygwin environment. As described on the Cygwin web site, Cygnus is a Linux-like environment for Windows. This Linux-like environment is required because of the strong Linux legacy of the Mono project.
  2. The next phase involves installing the latest Mono combined Windows installation package. As mentioned, this process will build Mono with Mono; therefore, Mono must be available in order to complete the necessary make steps.
  3. Finally, once Mono for Windows is installed, it is merely a matter completing the actual build process using the standard autogen.sh, make, and make install commands.

This article finishes with a call to arms for the Mono community to improve the build and deployment process for Windows.

Requirements for this process:

  • Cygwin Linux-like environment for Windows (I used version 1.5.7-cr 0x9e, built on 2004-01-30 19:32, located on cygwin1.dll).
  • Internet connection, duh
  • 3.6GB of hard drive space between the Cygwin setup files, the Cygwin installation, the Mono source code, exports and the new build.

1. Getting Started

The first phase of the build process is to install the Cygwin environment. If previous attempts have failed, it is critical that you exorcise these demons from your machine. This is important, because if the Cygwin installer should find the remnants of a previous installation, it will follow the registry keys left and may corrupt the installation. It is always best to start with a clean system.

Note: You can skip this step and proceed to the environment setup if your system does not currently contain Cygwin.

The steps to remove a previous installation of Cygwin are as follows:

  1. If there is an existing shortcut on the Windows desktop, switch to the desktop view. Locate the Cygwin icon, single-click on the shortcut, and press the Shift and Delete simultaneously. Select Yes from the Confirm File Delete dialog.
  2. If there is a Cygwin shortcut on the Quick Launch Toolbar, repeat the process from the previous step and delete the shortcut.
  3. Right-click on the Windows Start button and select Explore All Users. This will open an Explorer session with the current directory as C:\Documents and Settings\All Users\Start Menu.
  4. Click on the Programs directory.
  5. Click on the Cygwin directory in the right-hand side window of Explorer, and press Shift and Delete. Select Yes from the Confirm File Delete dialog.
  6. Repeat the previous step for the Cygwin-XFree86 directory, if it exists. Otherwise, proceed to the next step.
  7. Click on the Start button and select Run.... Enter "explorer c:\" and click OK. Windows should open a new Explorer session with the c:\ as the current directory.
  8. Click on the cygwin directory and press Shift and Delete. Select Yes from the Confirm File Delete dialog.
  9. Click on the Start button and select Run.... Enter "regedit" and click OK.
  10. Locate the HKEY_LOCAL_MACHINE key and expand the key. Locate the SOFTWARE key and expand it. Click on the "Cygnus Software" key and press the Delete key.

These instructions should remove all traces of Cygwin, and you should be ready to begin the setup for the Mono build process.

1.1 Cygwin Environment Setup

The first phase of building Mono involves installing Cygwin. As mentioned in the requirements, I recommend the 1.5.7-1 version, built on 2004-01-30. You might be asking, "What is so special about this particular build of the Cygwin environment?" Well, at some point, Cygwin began including GNOME components as part of their X for Windows. The underlying glib2 that the bundled GNOME/GTK+ uses is incompatible with one of the REQUIRED compiler flags, -- CC="gcc -nno-cygwin". Therefore you can use the newer Cygwin, but you would have to go through great lengths to remove any of the GNOME/GTK+ components before you can compile Mono for Win32 in a way that results in an independent system (independent of Cygwin after its initial compilation). There is a PDF available that lists the contents of the "magic" 1.5.7-1 release. It includes all of the packages and their respective versions. If you have to use a Cygwin release after 1.5.7-1, then delete any package that does not appear in this list.

I will assume that you have the following pre-setup:

  • You have a root-level directory to hold the Cygwin installation packages; let's assume it is called C:\Cyg-install.
  • Within the Cyg-install directory is the Cygwin setup.exe and associated setup.ini.
  • Finally, within the Cyg-install directory, you have a sub-directory C:\Cyg-install\releases, containing the 386 assorted package tarballs required for the installation.

The following steps will lead you through the Cygwin installation process:

  1. Run the Cygwin setup from the Cyg-install directory.
  2. The setup program will launch the installation process. The setup wizard will first display a splash dialog to start the process. Click the Next button to proceed with the installation.
  3. On the next screen of the installation wizard, you must choose the installation type. There are three options: Install from Internet, Download from Internet, and Install from Local Directory. Choose Install from Local Directory and click the Next button.
  4. "Choose Installation Directory" is the next screen of the installation process. In this screen, you will designate the root directory for the Cygwin installation, who the installation is for, and the default text file type. The default root directory should be C:\cygwin, of course assuming that C: is your boot drive. Accept the default directory, the default "All Users" selection, and the default "Unix" text file type and click the Next button.
  5. Figure 1 - Package selection

    Figure 1. Setting up Cygwin

  6. The installation wizard will next request the location of the local package directory. If you launched the setup routine from the C:\Cyg-install directory, the default should be that directory. If that is true, click the Next button to accept the default. Note: After clicking Next, the installation wizard will complete a MD5 check to ensure package integrity before installation.
  7. After the MD5 check, the Select Packages screen should appear. As shown in Figure 1, notice that the screen is in the Category view, and the word "Default" is beside each package selection. Beside the root level category All, there is the word Default. Click on the word Default and it should change to Install. This will instruct the Cygwin installation wizard to install all packages. Click the Next button to initiate the installation.

    Note: This will take some time, so just keep an eye on the progress bars to verify progress.

  1. When the installation completes, the wizard will present one last screen, Create Icons. Ensure that both options of Create icon on Desktop and Add icon to Start Menu are selected, and click the Finish button.

    Note: At this point, the Cygwin installation is complete; however, there are a few more steps to finish the environment setup.

  2. From either the Quick Launch Toolbar or from the desktop, launch the Cygwin environment. This will create several hidden files in the Cygwin root directory. The files will all start with a "." (period). The exact files created are .bash_profile, .baschrc, and .inputrc.
  3. Exit the Cygwin environment by typing "exit" and pressing Enter.
  4. You need to edit the .bashrc file to add the necessary Mono environment variables, and the environment variables for Mono CVS access and .NET, if they are not already in your Windows PATH. To make these changes inside the Cygwin environment, use the following instructions. (Note: You may encounter difficulty if you attempt to use a Windows text editor to make these changes. It may introduce CR/LF characters into the file instead of the LF characters Cygwin is used to.)
    1. Re-enter the Cygwin environment.
    2. Type vi ./.bashrc to edit the file. At this point, you should see the contents of the file and should be able to navigate using the arrow keys.
    3. Position the cursor at the end of the file by using the down arrow key until the cursor stops at the end of the file.
    4. Type "i" to insert text into the file.

      Note: It is possible to cut and paste between Windows and the Cygwin environment (even into a vi session). Simply copy the text from Figure 2, and then click on the Cygwin icon in the title bar of the Cygwin window. Select Edit and then select Paste. That should fill in the text. You can also just type it all in; that is, if you like typing.
    5. Insert the text from Figure 2, and press Escape when you are finished.
    6. Press the ":" (colon) key and you will receive the vi line command prompt.
    7. Enter "wq" and press Enter. This will write the file to disk and quit the vi editor. Note: You need to exit and re-enter Cygwin for these environment variables to become active.

      #Environment Variables for Mono
      export PATH="/usr/local/bin:/usr/local/lib:$PATH:/usr/local/icu/bin"
      export ACLOCAL_FLAGS="-I /usr/share/aclocal"
      export CPPFLAGS="$CPPFLAGS -I/usr/local/include"
      export LDFLAGS="$LDFLAGS -L/usr/local/lib"
      export CC="gcc -mno-cygwin"
      export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:/usr/lib/pkgconfig"
      export LD_LIBRARY_PATH="/usr/local/lib:/usr/lib"
      export MONO_PATH="/usr/local/lib:/usr/lib:$MONO_PATH"
      export MONO_CFG_PATH="/usr/local/etc:/usr/etc:$MONO_CFG_PATH"
      
      #Environment variables for .NET if not already in your Windows PATH
      #These variables could be needed by older Mono build systems
      #export PATH=$PATH:`GetNetSdkLocation -cs msnet_1.1`/v1.1.4322
      #export PATH=$PATH:`GetNetSdkLocation -cs msnetsdk_1.1`/Bin
      
Figure 2 - The environment

Figure 2: Setting up the environment

  1. The final step in the environment setup phase involves setting up the necessary directory structure. Make sure you are in the Cygwin environment, and enter mkdir -p /download/tarball/. Also make a sub-directory for the build directory; enter mkdir -p /download/mono-x.x.x (where x.x.x represents the release number).
  2. If the Cygwin distribution used in this phase did not have the Perl XML parser, you need to add it to your Cygwin environment. To add the parser:

    1. Download the tarball from SourceForge. Choose your c:\cygwin\download\tarball directory as the download destination directory.
    2. Once the download is complete, change directory to the root of Cygwin by typing cd / and pressing Enter.
    3. From the root, type tar -xjvf /download/tarball/perl-XML-Parser-2.34-1.tar.bz2 and press Enter. This will uncompress the necessary files and place them in the correct directory locations.

2. Installing Mono

If you already have the latest development version of Mono installed, you can skip this section. If not, then in this second phase you will need to download the combined installer and complete the installation.

  1. Download the Windows Installer from Mono Latest Development Version and save the file in the directory of your choosing.
  2. Run the combined installer. The setup wizard will present the welcome screen.
  3. Click the Next button to proceed. The setup wizard will present the license agreement.
  4. Select "I accept the agreement" and click the Next button. The setup wizard will present the release notes for the installer.
  5. Click the Next button and the setup wizard will prompt for the installation location.
  6. Do not accept the default suggestion! Enter C:\mono\Mono-1.1.3 instead (see Figure 3 below). This is critical because, for our purposes, spaces in paths are evil. We will later mount this directory within Cygwin and use it to create symbolic links. Click the Next button to proceed to the component selection screen.
    Figure 3. Mono installation destination

    Figure 3. Installing Mono

  1. Verify the component selection; I recommend choosing all components. Click the Next button to proceed.
  2. Verify the start menu folder Mono 1.1.3 for Windows and click the Next button.
  3. The next screen of the setup wizard requires you to select the port XSP will use. Accept the default port, 8088, and click the Next button.
  4. Finally the setup wizard is ready to install Mono, click the Install button. When the installation is complete, the setup wizard will display a screen indicating that the installation complete.
  5. Click Finish to complete the setup.

3. Completing the Build

The last phase of the build process will require you to obtain a copy of the Mono source code. The recommended way to accomplish this is by using anonymous Subversion checkout. The Mono project uses Subversion as its source code management tool. In order to use Subversion, you first need to have a Subversion client installed on your machine. Finally, once you have Subversion installed, and you have checked out and exported the Mono source code, then you can complete the build steps.

3.1 Installing Subversion

If you already have the Subversion, then you can skip this section. You will need to obtain the the Windows installer with the basic Subversion Win32 binaries. You can obtain the installer from the Tigris.org documents and files area.

  1. Run the setup routine from the the directory chosen during the setup download.
  2. Click the Yes button to proceed with the installation.
  3. Click the Next button to begin the installation.
  4. Select "I accept the agreement" and click the Next button.
  5. Click the Next button again, and the installation wizard will request the Subversion install location.
  6. Accept the default, C:\Program Files\Subversion, by clicking the Next button. The installation wizard will then request the start menu folder.
  7. Accept the default, Subversion, and click the Next button. The installation wizard will then request whether you want to install desktop and Quick Launch icons.
  8. Make your desired selections for shortcut icons and click Next to finalize the installation wizard selections.
  9. Finally, on the "Ready to Install" screen, click the Install button to begin the installation. You will receive an information screen after the installation is complete.
  10. Click Next and then Finish to complete the installation. The installation wizard should ask if you want to restart your system. Click Yes to restart your system.

When your system restarts, you should verify that the Tortoise Subversion Windows Explorer plugin was successfully installed. From within Explorer, right-click on any directory. You should see a new menu item: TortoiseSVN. Click on this entry and you should see another menu list. Select the About menu option. You should receive the TortoiseSVN 1.1.1, Build 1857 about dialog box.

3.2 Check Out the Mono Source Code

In order to build Mono, you will need to check out three source subtrees: mono, mcs, and libgdiplus. To anonymously check out the Mono source code:

  1. First, create a directory as a sandbox to check out the source code files. I suggest C:\monosvn\mono\x.x, where x.x should represent the version of the source code.
  2. From within Windows Explorer, locate the sandbox directory you created in the previous step and right-click on the directory.
  3. You should have two TortoiseSVN menu options. Select the Checkout option.
  4. The Subversion Checkout dialog will appear. In order to access the Mono Project source code, you need to point the Subversion client to the Mono Project Subversion repository. In the URL for repository enter "svn://svn.myrealbox.com/source/trunk/mono".
  5. Ensure that your sandbox directory is identified in the checkout directory, and click Ok.
    Note: When the checkout is complete, the subtree will appear in the sandbox directory in explorer. The directory icon will appear with a little check in the lower left-hand corner. This illustrates that the directory was checked out from Subversion.
  6. You need to export the directory into your Cygwin directory structure. Right-click on the c:\monosvn\mono\1.2 directory. On the context menu, select TortoiseSVN and then export. Subversion will provide the Browse For Folder dialog window.
  7. Select C:\cygwin\download\mono-1.1.4 and then click Ok. This will copy the files from the sandbox to the build directory.
  8. Repeat the checkout and export steps for the mcs and libgdiplus subtrees. In the checkout step, substitute the subtree at the end of the repository URL, for example: "svn://svn.myrealbox.com/source/trunk/mcs".

3.3 Build Setup

You are now almost ready to begin the build process. You first need to take care of few preparatory steps and then you'll be ready for the build. These fews steps will redirect the calls for the C# compiler to the Mono C# compiler, allowing you to build Mono with Mono. To finish our preparations, complete the following:

Figure 4. csc.exe --version output

Figure 4. Checking the CSC version

  1. From within the Cygwin environment, type mkdir -p /opt/mono and press Enter.
  2. You now need to mount, within the Cygwin environment, the root directory you used for the Mono combined installation. Enter mount -s c:/mono/Mono-1.1.3 /usr/local and press Enter.
  3. Next, you need to create two symbolic links. First type ln -s /usr/local/bin/mcs ./csc.exe and press Enter. This will substitute the Mono C# compiler for the C# compiler. You can test this by typing csc.exe --version. You should receive the result shown in Figure 4.
Figure 5. resgen.exe output

Figure 5. Generating the resources

  1. Next you need to type ln -s /usr/local/bin/monoresgen.exe ./resgen.exe and press Enter. This will substitute the Mono Resource File Generator for the .NET Framework Resource File Generator. Confirm this by typing resgen.exe. You should receive the result shown in Figure 5.

3.4 Building Mono With Mono

Finally,you are ready to build Mono with Mono. From the mono subdirectory, you will complete the three-step build process involving autogen, make, and make install. To finish the process:

Figure 6. autogen.sh results

Figure 6. Building Mono

  1. From within the Cygwin environment, type cd /download/mono-1.1.4/mono and press Enter. This will put you in the Mono directory of the source code.
  2. Type ./autogen.sh --prefix=/opt/mono --with-preview=yes and press Enter. If autogen encounters any problems with the environment or in terms of dependencies, it will stop. If the process does not halt, you should receive a long stream of console comments; at the end, however, it should resemble Figure 6.
  1. Type make and press Enter. The make command will take a few minutes, so please be patient. Also, just as with the autogen command, the make command will produce a long stream of console comments. What you should be alert for is any type of error message that appears immediately before the make command completes. The output should look like Figure 7.
Figure 7 - make results

Figure 7. Making Mono

  1. Type make install and press Enter. Once again, this will take a few minutes. A successful make install should look like Figure 8.
building mono

Figure 8. Making the installer--Click for full-size image.

Congratulations! This concludes the Mono build with Mono process.

4. Post-Build Instructions

Now that you have successfully built Mono, you now have a directory structure in /opt/mono that is similar to the one that the Mono Combined installer creates for Win32. Keep in mind that the resulting output does not include GTK+, Gtk#, MonoDoc, or XSP. Also missing are prerequisites that almost never change and that originate from other parties like Microsoft (as in the case for msvcr71.dll, found in C:\mono\Mono-1.1.3\bin). However, you now have the essence of the latest Mono release. Your options at this point include repackaging all of the framework and its supporting components or just using a particular library or executable that you know was just fixed in SVN.

To verify the results of the build process, change to the prefix directory, /opt/mono, and study its contents and structure. There are two significant kinds of files created in the directory hierarchy. There are binary files like /opt/mono/lib/mono/1.0/mcs.exe and /opt/mono/lib/mono/1.0/System.Xml.dll. These are examples of managed assemblies. Other resulting binary files include unmanaged executables and static libraries such as /opt/mono/bin/monodis.exe and /opt/mono/lib/libmono.a.

The build process also creates many configuration and/or supporting files that might contain file PATH information that is specific to the choices made when autogen.sh was run for the first time (remember ./autogen.sh --prefix=/opt/mono --with-preview=yes? Refer to 3.4, "Building Mono With Mono"). Examples of these files are /opt/mono/lib/pkgconfig/mono.pc and /opt/mono/bin/ilasm. These are generic text files, so you can edit their contents with any ASCII-friendly text editor. Changing these files is a critical function of the Windows Combined Installer, as you will now see.

In theory, you could take all of the child directories that are found in /opt/mono and simply copy and paste them over to C:\mono\Mono-1.1.3. Unfortunately, the text files that I mentioned above contain an unusable path reference to /opt/mono. The Windows operating system would not be able to resolve this path, and your Mono installation would not work. Remember, that path is only viable in the Cygwin environment, which is not required to run the resulting Mono in Win32. You would also be missing some batch files that parallel the shell scripts. The batch files are the ones that actually invoke the execution of the Mono runtime (C:\mono\Mono-1.1.3\bin\mono.bat) and indispensable tools like gacutil (C:\mono\Mono-1.1.3\bin\gacutil.bat) while in Windows. In fact, if you were to look at the Inno Setup installer script that was used to generate mono-1.1.3-gtksharp-1.9.1-win32-0.4.exe, you will notice that the largest portion of the script goes to searching and replacing a constant, C:\Target, by the path that the user selects during the installation routine.

5. Call to Action

Today, building and deploying Mono on the Win32 platform without the Win32 Mono Combined installer requires extensive manual intervention. This must change. The Linux Mono community enjoys great autonomy with the Linux build process. As I have described, it is clear that the Windows Mono community does not share that same autonomy. I understand that this is partially because Mono originates from a Linux-friendly environment. However, I'm sure that the same spirit of innovation and ingenuity that has distinguished the Mono project thus far, can also help resolve this disparity. Therefore, I urge the Mono community and especially the core Mono team to provide the necessary guidance, resources, and focus to help automate the Windows build and deployment process. I'm sure that if we accomplish this goal, we will unleash significant pent-up demand for the Mono project from the Windows C# community. And if there's anything I've learned about open source software, is that it is all about the community, and the bigger the community the better.

Appreciation

As has been the case for me so many times before, this effort would not be possible without the determination and drive of my good friend Francisco (Paco) Martinez. Through countless hours and cups of coffee, he perfected this process and then made it seem simple as we went through it step by step. Eric Raymond once said that you're not a hacker until someone calls you one, so I'm here to say: "Paco is a hacker extraordinaire." With the continued support of O'Reilly Network, we look forward to sharing many other articles focusing on Mono for Windows geeks.

Kevin Shockey is an emerging high technology entrepreneur.