Cross-Platform Development – Windows Setup

As explained in the introductory post, the aim is to set up a cross-platform development environment using the following tools:

  • Gnu make tools
  • Gnu C++ compiler
  • Gnu Emacs editor
  • wxWidgets framework

This post is about how to setup this development environment on Windows. I use Windows 7, but this setup has been used on other versions from XP onwards.

Windows is more complicated to setup for software development using Gnu tools, because they are not native to Windows – they are ports of Unix tools.

This is an update to the original article because now the MinGW project provides a package manager which makes the installation very simple and furthermore makes installing updates simple too.

Msys Shell Environment

The first stage is to install the MinGW project’s Msys shell scripting environment that allows build scripts to run.

Download the Windows installer from the MinGW project – choose the mingw-get-setup.exe file – and run it.

I prefer to install in C:\msys to show that this is going to be a basic Msys install with 32-bit compiler tools, in contrast to the 64-bit installation described in a separate article which is installed at C:\msys64.Choose your own convention for this.

The first screen selects the installation path:

Make sure the tick-box for the graphical interface is ticked. Pressing Continue downloads and installs the “mingw-get” package manager. At the end of the download the installer gives another Continue button – clicking this opens the GUI of the package manager.

Select the msys-base and mingw-developer-toolkit packages for now – these are meta packages that select a number of other packages to create all that you need for basic scripts and for the compilers.

Note: at the time of writing there was a bug in the installation such that the zlib1.dll file is not installed as part of the compiler package – this causes compiles to fail. Fix this by installing the mingw32-libz package by looking under “All Packages” and selecting it for installation.

Then select the Installation menu item “Apply Changes”. You get a confirmation dialog showing what changes will be applied, click on Apply to let the installation complete.

The installation creates a batch file to start the Msys shell. This is in a strange location – C:\msys\msys\1.0\msys.bat. Run this from Windows Explorer or from a CMD prompt to confirm that installation succeeded.

There is one final problem to be fixed with this setup – out of the box Msys maps your HOME directory onto a directory within the Msys installation, rather than using your Windows user directory. This can be made to work in a more user-friendly way if you first of all set up the HOME environment variable using the Windows control panel.

First open the dialog for editing environment variables: In Windows open Start->Control Panel->System, and choose the “Advanced System Settings”. Pick the “Advanced” tab and click on “Environment Variables”. Create a new user variable called HOME that maps onto %USERPROFILE%. Click on OK to set the variable.

Now when you open the Msys Shell, it starts in your user profile directory – typically C:/Users/<name>.

Once set up with a correct HOME path, the shell can be configured by writing a $HOME/.profile configuration file. Recommended settings:

# add Unix system tools to the path
export PATH=$PATH:$HOME/bin:/usr/sbin

This is the minimum settings to get started, others will be added on the way, particularly when configuring the emacs editor. Note that I’ve added my own “bin” directory at “$HOME/bin”. I use this to keep common scripts in.

Integration

Once installation is complete, you link the Msys shell with the 32-bit compilers by running a post-install script that comes as part of the Msys installation. First, run the Msys shell. Then in the Msys shell, run the post install script

/postinstall/pi.sh

Answer the questions as they are presented:

  • y to continue the postinstall
  • y to say you have MinGW installed
  • C:/msys as the location of MinGW

Check the postinstall has worked by trying the command “gcc -v”. In this example there is a lot of information which ends with:

gcc version 4.8.1 (GCC)

I prefer to start up Msys shells from shortcuts and have simplified Windows scripts to do this. The first script is my own version of the Msys shell, which is in a command called msys.bat (I have a similar script called msys64.bat to start up the 64-bit compiler version). This is a Windows batch file:

@echo off

rem # set variables that must be set before bash starts
rem # all other variables will be set in .profile
setlocal
rem # set Unix HOME to match Windows USERPROFILE so shell starts up in the user's directory
set HOME=%USERPROFILE%
rem # let the MSYS startup scripts know we're running 32-bit mode
set MSYSTEM=MINGW32
rem # hard-code the path to bash to avoid putting it on Windows PATH
set BASH="c:\msys\msys\1.0\bin\bash"

rem # if there are no parameters, run in interactive mode,otherwise run in batch command mode then exit
if "%1" == "" (
%BASH% --login -i
) else (
%BASH% --login -c "%*"
)

Note that it is not necessary to set HOME here if you’ve already done this via the control panel. But this script eliminates the need to do it through the control panel.

This script works in two ways. With no arguments, it simply opens a bash interactive shell (note the -i switch). With arguments, the arguments are run as a batch command within the Msys bash environment and then the shell exits (note the -c switch).

If you create a shortcut to this batch file and double-click it, the script will run in the no-arguments mode and open a shell window. I have a shortcut to this script in my Quick Launch menu.

Gnu Emacs

There is a stand-alone version of Gnu Emacs for Windows available from the Gnu Emacs for Windows download site. Download the latest-versioned .ZIP file. At the time of writing, the latest version was 24.3. Unzip this to a suitable place, I chose C:Emacs. It is probably not a good idea to put it in the “Program Files” directory in case the spaces in the path cause problems in shell scripts later.

If you just run Emacs from its shortcut icon, you will get a pure Windows Emacs which doesn’t know about or work with MSYS. There are a number of websites that explain how to jump through horrendous hoops to get the Emacs/MSYS combination working, all of which miss the point. The best way of getting Emacs to work with MSYS is simply to run it as a subprocess of MSYS, i.e. by running it from an MSYS shell. The point is that this is how the Unix version does it and Emacs is set up to inherit settings from its parent shell in this way.

To do this, first configure the shell’s configuration file ~/.profile, as described in the last section. Add the path to Emacs and a few environment variables:

# setup Emacs so Gnu Emacs is found in preference to any other emacs
export PATH=/c/emacs/bin/:$PATH
export SHELL=bash
export EDITOR=emacsclient

Note how the Windows path C:Emacs has mapped onto the MSYS path of /c/emacs.

Now start up a new MSYS shell (because any old shells will not have run this version of .profile and will not have these settings) and type:

emacs &

This will start up Emacs which will inherit the environment variables from MSYS and therefore know to use bash for shell operations and also know about the PATH settings that make the MinGW tools available. Note that the Emacs configuration files will now be in $HOME/.emacs.d.

To test that everything is working, try the Emacs shell command:

M-x shell

Where M-x is Meta-x, which is usually mapped onto Alt-x on Windows. This should open a shell buffer in Emacs which lets you try out some shell commands, such as cd, ls, pwd. A useful one to check is:

g++ -v

This will give you the version information for the Gnu C++ compiler.

I prefer to start up Emacs from shortcuts and have simplified Windows scripts to do this. For running Emacs from a shortcut, I have a batch file called msys-emacs.bat:

@echo off
msys runemacs --geometry 160x50+200+50 --title Emacs:MSYS

This runs the “runemacs” command with a set of options (run emacs –help to see the set of options) in the MSYS environment, achieved by passing it to the msys.bat script described in the last section (which must therefore be on the path).

The “runemacs” command fires off Emacs in a subprocess and then exits. The effect of running this via the MSYS batch file is that an MSYS window appears briefly, opens Emacs, then the shell window closes again, leaving Emacs running but configured correctly for use with MSYS tools. I have a shortcut to this script in my Quick Launch menu.

wxWidgets

Start by downloading the latest source code from the wxWidgets website. The link is http://www.wxwidgets.org/downloads/ and at the time of writing the latest version was 2.9.4. Since 2.9 there is a single distribution for all platforms, so download and unpack that. If you are using an earlier version, download the wxMSW distribution. Download and unpack this .gz file wherever you like – the library will be installed into the proper place by the installation process. I unpack it into $HOME/wxWidgets.

Open an MSYS window (or open a shell window in Emacs) and change directory to the unpacked wxWidgets directory. Installation requires three commands:

configure --disable-shared
make
make install

The “configure” command scans the system to work out the options required to build wxWidgets on this platform. In this case I am specifying that wxWidgets should be built as static (non-shared) libraries. There are two options here:

  • –disable-shared: means that the application will include the wxWidgets object code, so will be quite big, but will be easy to install on another system since it will not require any wxWidgets libraries to be installed to work.
  • –enable-shared (default): means that wxWidgets will be built as DLLs, so will not be included in the application. Installation on another machine will require installation of all DLL dependencies as well. Typically this is done by copying the DLLs into the same directory as the program. You can find out which DLLs are needed once you’ve built an application using the Dependency Walker program and opening the .exe with it.

The “make” command compiles the libraries and “make install” installs the libraries and the headers into the appropriate places in the MinGW system for build tools to find them.

If you do choose to build the shared version as well, you can repeat the same sequence of commands but with shared libraries enabled:

configure
make
make install

Both installations co-exist and the right one is chosen by the application’s Makefile – see later.

Once you have at least one version of wxWidgets installed, you can get details of the installed versions of wxWidgets with the “wx-config” command:

wx-config --list

With the example installation I used for this post, I got the following output:

Default config is msw-unicode-static-2.9
Alternate matches:
  msw-unicode-2.9

Universal Makefiles

You can build wxWidgets applications using modified versions of the samples provided in the wxWidgets download. However, they can be over-complicated and difficult to adapt to your own application. I have developed a set of simple-to-use universal makefile utilities which reduce the Makefile required to build a wxWidgets application to 3-4 lines of code.

The recommended practice for using the makefiles project is explained in the online documentation, but basically it is best to put the makefiles project in a folder alongside the project you are going to use it in:

Development/
  |
  +-makefiles/
  |   +-gcc.mak
  |   +-wx.mak
  |   +-...
  |
  +-/
  |
  +-/

Download the universal makefiles project from the website on Sourceforge. Be careful not to click on the quick-link to the STLplus project (which makefiles is a subproject of), but choose the latest version of the makefiles project from the list of versions and download the zip file, which will be called something like “makefiles-01-07.zip” – but use the latest version. Unzip this in the development folder.

Testing the installation

To test the installation I am going to set up and build an application based on one of the samples – the “controls” sample – in the wxWidgets release, but using my own Makefile system to build it.

To start off, create a project folder called “samples” next to the “makefiles” folder and then a subfolder called controls:

Development/
  |
  +-makefiles/
  |
  +-samples/
      |
      +-controls/

There are some files from the samples folder that need to be copied, namely: sample.xpm, sample.ico and sample.rc.

The rest of the application is copied from the samples/controls folder, namely: controls.cpp, controls.rc and the icons subfolder.

Thus you have the following structure:

Development/
  |
  +-makefiles/
  |
  +-samples/
      +-sample.xpm
      +-sample.ico
      +-sample.rc
      |
      +-controls/
          +-controls.cpp
          +-controls.rc
          +-icons/
              +...

There seems to be a problem with this example’s use of the resource compiler that means that #include statements don’t work. Edit controls.rc to comment out the first line, which is a #include. Or, merge the sample.rc file into the controls.rc file.

Next, in emacs, create a file called Makefile in the controls folder and add the following to it:

IMAGE=controls
WXSTATIC=on
include ../../makefiles/gcc.mak
include ../../makefiles/wx.mak

The WXSTATIC=on option links against the wxWidgets static libraries. If you have built the shared libraries, you can link against those instead by setting WXSTATIC=off, or by removing it since “off” is the default.

Note: this Makefile needs makefiles v1.7 or higher (see the makefiles/version.txt to check this). Earlier versions make the wrong assumption about the default build’s use of Unicode characters when used with wxWidgets later than v2.9. In other words, the wxWidgets project has changed the default handling of Unicode and makefiles v1.7 onwards reflect that change.

Now, still in emacs, run make by executing the compile command:

M-x compile

Note that if you are unfamiliar with emacs, “M-x” means Meta-x, which on most keyboards is Alt-x. The default compile command is “make” which is what we want, so just press return to start the compile.

This should build correctly and create a program called controls. You can run this directly by double-clicking on the .exe file, or from within Emacs by using compile again, but changing the compile command to:

make run

And it will pop up the application main window:

Controls Example on Windows

Controls Example on Windows

This is the basic setup, but you probably also need to use Version Control, which is covered in a separate article.

Comments

hi,

GREAT article…

I have followed all the steps properly (I think/hope) but cannot compile the controls sample application.

emacs gives the error:

-*- mode: compilation; default-directory: "~/Development/samples/controls/" -*-
Compilation started at Sun Jul 7 13:24:27

make
Makefile:2: ../../makefiles/gcc.mak: No such file or directory
Makefile:3: ../../makefiles/wx.mak: No such file or directory
make: *** No rule to make target `../../makefiles/wx.mak'. Stop.

Compilation exited abnormally with code 2 at Sun Jul 7 13:24:28

Please know that this is my first time with emacs and any actual cross-platform development, before this I have worked with Visual Studio (C# or simple windows onlyC/C++) mostly…

after downloading the makefiles from sourceforge, I just extracted them to a folder makefiles in the development folder, do i need to compile those too or something, the file emacs mentions is NOT there in the makefiles folder.

HELP is needed…

Hi,

My first suggestion is to check the directories are set up correctly. The makefiles folder should contain gcc.mak and wx.mak. If not, it hasn’t been set up correctly. Sometimes unzipping programs add an extra layer of directory.

Also check that the makefiles directory is at ../../makefiles from the directory you are working in, i.e. two levels up.

Leave a Reply