Cross-Platform Development – Windows 64-bit 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 an update to the Windows setup article. This version of the article explains how to use the 64-bit version of the Gnu compiler with the Msys environment.

Gnu Tools – MinGW-w64 and Msys

The secret of setting up a 64-bit compiler is to combine the MinGW project’s Msys shell (which is a 32-bit environment) with the MinGW-w64 project’s 64-bit compiler tools.

The problem is that there are a plethora of different packages containing the 64-bit compiler. It seems there are several teams packaging up almost identical collections of Gnu tools, some as downloads, some using installers. Most of these teams seem to have no communication skills, so the packages generally don’t have any useful documentation explaining what they’re for, the differences versus other packages, the pros/cons of using them or even how to use them.

I’ve tried about 3 different packages and found that I could sort-of make them work, but not well enough to build wxWidgets. The one that seemed to be usable was the TDM package. This has a simple installer and a website that was at the same time simple but informative.

One of the encouraging things about this combination is that both packages come with a package manager, so installing updates in the future will be simple.

The following sections explain how to install the Msys shell, the TDM compiler collection and then link the two together into a usable system.

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.

The first screen selects the installation path. I prefer to install in C:\msys64 to show that this is going to be Msys with 64-bit compiler tools.:

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.

mingw-get installer

Select only the msys-base package for now – this is a meta package that selects a number of other packages to create all that you need for basic scripts. Do not install any compilers, the Msys project only supports 32-bit compilers and this tutorial is about setting up 64-bit compilers, which is done as a separate task. 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:\msys64\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.

TDM Package of the MinGW64 Tools

The next stage is to install the 64-bit compiler tools such that they work in the Msys environment. Go to the TDM project and download the on-demand installer (tdm-gcc-webdl.exe).

Run the installer.

tdm-installer-options

The first screen gives you the options to Create a new installation, Manage an existing installation or Remove an existing installation. In this case, Create a new installation.

tdm-installer-edition

This screen allows you to choose whether to install the standard 32-bit compiler or the 64-bit compiler. Select the latter.

The next screen is a disclaimer screen to read, then click next.

tdm-installer-path

This screen chooses the installation path. The default is to install into a separate directory on the C: drive, but I prefer to install it within the msys64 directory, so the relationship between the Msys scripting environment and the compiler is clearly shown. Click Next. This brings you to the selector for the download site to get the software from, I always just choose SourceForge default for this. Clicking Next brings you to the package selector screen:

tdm-installer-packages

Generally, leave the settings to the default values. This will give you the latest compiler and all the other tools you will need. Click on Install to install the 64-bit C++ compiler as a sub-directory called “tdm” of the Msys installation.

Integration

Once installation of both systems is complete, you link them together 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:/msys64/tdm 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 (x86_64-posix-seh-rev1, Built by MinGW-W64 project)

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 msys64.bat (I have a similar script called msys.bat to start up the 32-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 # override the makefiles algorithm for deducing the CPU - because we're building 64-bit in a 32-bit environment
set CPU=x86_64
rem # let the MSYS startup scripts know we're running 64-bit mode
set MSYSTEM=MINGW64
rem # hard-code the path to bash to avoid putting it on Windows PATH
set BASH="c:\msys64\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 anywhere in the “Program Files” directory in case the spaces in the path cause problems in shell scripts later.

Note: there is also a 64-bit version of Gnu Emacs, available from the emacs-w64 project. This is a full 64-bit build of the latest source code for Emacs. I haven’t given this as the first option (I’ve listed the 32-bit build above) because this is not an official Gnu distribution. I’ve tried it though and it works. Download the latest .7z (7-zip) file. Unzip this to a suitable place – you will need the 7-Zip program to unzip this, download and install the 64-bit version of 7-zip from its website. I chose to unzip this package to C:\emacs64. It is probably not a good idea to put it anywhere 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 Emacs to the path 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 been mapped onto the Msys path of /c/emacs. If you are using the 64-bit version, use /c/emacs64 as the path instead.

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 msys64-emacs.bat:

@echo off
msys64 runemacs --geometry 160x50+200+50 --title Emacs:MSYS64

This runs the “runemacs” command with a set of options (run “emacs –help” to see the set of options) in the Msys 64-bit environment, achieved by passing it to the msys64.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 3.0. 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 configure command typically creates some warnings. Some are obviously OK – for example there are warnings that the system image libaries are notpresent and the internal ones will be used. There is one warning that may alarm you:

configure: WARNING: Catching fatal exceptions not currently supported on this system, wxApp::OnFatalException will not be called

However, this is normal and has never caused any problems for me.

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-3.0
Alternate matches:
  msw-unicode-3.0

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
  |   +-...
  |
  +-project1/
  |
  +-project2/

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.

Leave a Reply