Setting up wxWidgets Environment for C++ in Windows 10

OVERVIEW

wxWidgets is primarily something which is used under Linux and *nix platforms and is definitely not the first choice of a UI framework for C++ when it comes to Windows. Visual Studio offers several options in that department – WinForms, WPF, Silverlight, Razor, Blazor etc.. And with the advent of .NET Core , you can create cross-platform apps using native libraries. Anyway, wxWidgets can still be used on Windows and here we see how to set it up for use under Windows 10.

I have avoided using any Microsoft tools and IDEs like Visual Studio or Visual Code. This is meant to be a bare bones environment which you can use from the command line.

SETUP MSYS2

The objective is to use Mingw64 as the C++ compiler to use for compiling wxWidgets itself and then building applications using wxWidgets. We can directly go to the MingW site and download the binaries and set them up, but it is quite error prone and can take a good amount of back and forth till you get it right.

A far easier and better option is to use MSYS2 to setup the MingW compiler. It takes care of all the headaches for you and is a life-saver. MingW not only installs MingW but all other possible C++ compilers like CLang and CygWin.

  • Go to https://www.msys2.org/ and download the installer exe file.
  • After downloading, run the installer.
  • Select the path where it should be installed: eg.d:\msys64 and click Next
  • Set a Start Menu shortcut name and click Next
  • The installation will start
  • Click Next and then click Finish
  • At this point , the command console of MSYS2 will open up
  • Update the package database by typing pacman -Syu and pressing Enter

The command window now closes. To complete the process, we need to run MSYS2 from the Start Menu

  • Go to Start->MSYS2 MSYS
  • In the command window type pacman -Su and press Enter

The next step is to install MingW64 toolset,

  • Use the command pacman -S –needed base-devel mingw-w64-x86_64-toolchain and press Enter
  • For Enter a Selection choose default=all and press Enter
  • For the next option Enter a Selection choose default=all and press Enter

Press Enter to start the installation of the required files

Once the process finishes, installation of MSYS2 is complete.

SETTING UP WXWIDGETS

We will download and compile the wxWidgets library .

  • Go to http://wxwidgets.org/downloads/ and click on the Windows Zip link under Source Code. This will download the windows source for wxWidgets
  • Create a folder where the file will be unzipped eg. d:\wxWidgets and unzip the contents into that folder.
  • We will now use the MSYS2 console to build the library
  • Go to Start->MSYS2 MinGW x64
  • In the MSYS2 console go to the folder where the wxWidgets source has been unzipped. To change the drive use cd /<drive>/ eg. cd /d/
  • To see the current working directory use the pwd command.
  • Assuming the folder is d:\wxWidgets, once we are in drive d. do cd wxWidgets
  • Type dir to see the contents of the directory
  • To create the static (non-shared) debug version do the following commands
  • mkdir build-debug
  • cd build-debug
  • ../configure –disable-shared –enable-debug
  • This will take some time to configure the files
  • Once the configuration process is complete, we build the library by typing make

BUILDING A SAMPLE APPLICATION

We will now create a very basic C++ application using wxWidgets and then build an executable. Create a folder where your source files will go eg. d:\projects\wxWidgets. Create the following file called simplewindow.cpp in a text editor:

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif
class MyFrame : public wxFrame
{
public:
    MyFrame()
        : wxFrame(NULL, wxID_ANY, _("Test"))
    {}
};
class MyApp : public wxApp
{
public:
    virtual bool OnInit() override
    {
        myFrame.Show();
        return true;
    }
private:
    MyFrame myFrame;
};
IMPLEMENT_APP(MyApp)

What the above code does is show a simple resizable window and nothing else. We need to copy the generated files and folders from the d:\wxWidgets folder first.

From the build-debug folder copy the lib folder to the application folder

Next copy the includes folder to the application folder.

Now you should have two subfolders include and lib in your application folder.

The makefile used to create the executable is given below. There are a lot of options present there. We have taken a makefile from one of the sample applications which are part of the wxWidgets package and changed it to suit our needs. Make sure that the paths specified in the makefile are matching yours. The file name for makefile is makefile

appname=simplewindow
prefix = /mingw64
exec_prefix = ${prefix}
datarootdir = ${prefix}/share
INSTALL = /usr/bin/install -c
EXEEXT = .exe
WINDRES = windres
NM = nm
BK_DEPS = /d/wxWidgets/build-debug/bk-deps
srcdir = .
top_srcdir = .
LIBS = -lz -lrpcrt4 -loleaut32 -lole32 -luuid -llzma -luxtheme -lwinspool -lwinmm -lshell32 -lshlwapi -lcomctl32 -lcomdlg32 -ladvapi32 -lversion -lwsock32 -lgdi32 -loleacc -lwinhttp
LDFLAGS_GUI = -mwindows
CXX = g++
CXXFLAGS = 
CPPFLAGS = 
LDFLAGS = 
USE_DPI_AWARE_MANIFEST = 2
WX_LIB_FLAVOUR = 
TOOLKIT = MSW
TOOLKIT_LOWERCASE = msw
TOOLKIT_VERSION = 
TOOLCHAIN_FULLNAME = msw-unicode-static-3.1
EXTRALIBS =    -lz -lrpcrt4 -loleaut32 -lole32 -luuid -llzma -luxtheme -lwinspool -lwinmm -lshell32 -lshlwapi -lcomctl32 -lcomdlg32 -ladvapi32 -lversion -lwsock32 -lgdi32 -loleacc -lwinhttp 
EXTRALIBS_XML =  -lexpat
EXTRALIBS_GUI = -llzma
WX_CPPFLAGS = -I${wx_top_builddir}/lib/wx/include/msw-unicode-static-3.1 -I${top_srcdir}/include -D_FILE_OFFSET_BITS=64 
WX_CXXFLAGS = -Wall -Wundef -Wunused-parameter -Wno-ctor-dtor-privacy -Woverloaded-virtual -g -O0   
WX_LDFLAGS =  
HOST_SUFFIX = 
SAMPLES_RPATH_FLAG = 
SAMPLES_CXXFLAGS =  
wx_top_builddir = D:/wxWidgets/build-debug
### Variables: ###
DESTDIR = 
WX_RELEASE = 3.1
WX_VERSION = $(WX_RELEASE).5
LIBDIRNAME = $(wx_top_builddir)/lib
MAINAPP_CXXFLAGS = $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
	$(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) \
	$(__THREAD_DEFINE_p) -I$(srcdir) $(__DLLFLAG_p) -I$(srcdir). \
	$(WX_CXXFLAGS) $(SAMPLES_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
MAINAPP_OBJECTS =  \
	$(__MAINAPP___win32rc) \
	MAINAPP_main.o
### Conditionally set variables: ###
#CXXC = $(CXX)
CXXC = $(BK_DEPS) $(CXX)
#PORTNAME = base
PORTNAME = $(TOOLKIT_LOWERCASE)$(TOOLKIT_VERSION)
#WXBASEPORT = _carbon
#WXDEBUGFLAG = d
WXUNICODEFLAG = u
#WXUNIVNAME = univ
EXTRALIBS_FOR_BASE = $(EXTRALIBS)
#EXTRALIBS_FOR_BASE = $(EXTRALIBS) \
#	$(EXTRALIBS_XML) $(EXTRALIBS_GUI)
EXTRALIBS_FOR_GUI = $(EXTRALIBS_GUI)
#EXTRALIBS_FOR_GUI = 
#__WXUNIV_DEFINE_p = -D__WXUNIVERSAL__
#__WXUNIV_DEFINE_p_1 = --define __WXUNIVERSAL__
#__DEBUG_DEFINE_p = -DwxDEBUG_LEVEL=0
#__DEBUG_DEFINE_p_1 = --define wxDEBUG_LEVEL=0
#__EXCEPTIONS_DEFINE_p = -DwxNO_EXCEPTIONS
#__EXCEPTIONS_DEFINE_p_1 = --define wxNO_EXCEPTIONS
#__RTTI_DEFINE_p = -DwxNO_RTTI
#__RTTI_DEFINE_p_1 = --define wxNO_RTTI
#__THREAD_DEFINE_p = -DwxNO_THREADS
#__THREAD_DEFINE_p_1 = --define wxNO_THREADS
#__DLLFLAG_p = -DWXUSINGDLL
#__DLLFLAG_p_1 = --define WXUSINGDLL
__WIN32_DPI_MANIFEST_p = \
	--define \
	wxUSE_DPI_AWARE_MANIFEST=$(USE_DPI_AWARE_MANIFEST)
COND_PLATFORM_OS2_1___MAINAPP___os2_emxbindcmd = $(NM) $(appname)$(EXEEXT) \
	| if grep -q pmwin.763 ; then emxbind -ep $(appname)$(EXEEXT) ; fi
#__MAINAPP___os2_emxbindcmd = $(COND_PLATFORM_OS2_1___MAINAPP___os2_emxbindcmd)
__RCDEFDIR_p = --include-dir \
	$(LIBDIRNAME)/wx/include/$(TOOLCHAIN_FULLNAME)
#__MAINAPP___win32rc = MAINAPP_MAINAPP_rc.o
#__MAINAPP_app_Contents_PkgInfo___depname \
#	= simplewindow.app/Contents/PkgInfo
#__MAINAPP_bundle___depname = MAINAPP_bundle
#____MAINAPP_BUNDLE_TGT_REF_DEP = \
#	$(__MAINAPP_app_Contents_PkgInfo___depname)
#____MAINAPP_BUNDLE_TGT_REF_DEP \
#	= $(__MAINAPP_app_Contents_PkgInfo___depname)
#____MAINAPP_BUNDLE_TGT_REF_DEP \
#	= $(__MAINAPP_app_Contents_PkgInfo___depname)
#____MAINAPP_BUNDLE_TGT_REF_DEP \
#	= $(__MAINAPP_app_Contents_PkgInfo___depname)
#____MAINAPP_BUNDLE_TGT_REF_DEP = \
#	$(__MAINAPP_app_Contents_PkgInfo___depname)
COND_MONOLITHIC_0___WXLIB_CORE_p = \
	-lwx_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_core-$(WX_RELEASE)$(HOST_SUFFIX)
__WXLIB_CORE_p = $(COND_MONOLITHIC_0___WXLIB_CORE_p)
COND_MONOLITHIC_0___WXLIB_BASE_p = \
	-lwx_base$(WXBASEPORT)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
__WXLIB_BASE_p = $(COND_MONOLITHIC_0___WXLIB_BASE_p)
COND_MONOLITHIC_1___WXLIB_MONO_p = \
	-lwx_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
#__WXLIB_MONO_p = $(COND_MONOLITHIC_1___WXLIB_MONO_p)
#__LIB_SCINTILLA_IF_MONO_p \
#	= \
#	-lwxscintilla$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
__LIB_TIFF_p \
	= \
	-lwxtiff$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
__LIB_JPEG_p \
	= \
	-lwxjpeg$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
__LIB_PNG_p \
	= \
	-lwxpng$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
#__LIB_ZLIB_p = \
#	-lwxzlib$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
COND_wxUSE_REGEX_builtin___LIB_REGEX_p = \
	-lwxregex$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
__LIB_REGEX_p = $(COND_wxUSE_REGEX_builtin___LIB_REGEX_p)
#__LIB_EXPAT_p = \
#	-lwxexpat$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)-$(WX_RELEASE)$(HOST_SUFFIX)
### Targets: ###
all: mainapp$(EXEEXT) $(__MAINAPP_bundle___depname)
install: 
uninstall: 
install-strip: install
clean: 
	rm -rf ./.deps ./.pch
	rm -f ./*.o
	rm -f mainapp$(EXEEXT)
	rm -rf mainapp.app
distclean: clean
	rm -f config.cache config.log config.status bk-deps bk-make-pch shared-ld-sh Makefile
mainapp$(EXEEXT): $(MAINAPP_OBJECTS) 
	$(CXX) -o $@ $(MAINAPP_OBJECTS)    -L$(LIBDIRNAME)  $(LDFLAGS_GUI) $(LDFLAGS)  $(WX_LDFLAGS) $(__WXLIB_CORE_p)  $(__WXLIB_BASE_p)  $(__WXLIB_MONO_p) $(__LIB_SCINTILLA_IF_MONO_p) $(__LIB_TIFF_p) $(__LIB_JPEG_p) $(__LIB_PNG_p)  $(EXTRALIBS_FOR_GUI) $(__LIB_ZLIB_p) $(__LIB_REGEX_p) $(__LIB_EXPAT_p) $(EXTRALIBS_FOR_BASE) $(LIBS)
	$(__MAINAPP___os2_emxbindcmd)
MAINAPP_main.o: $(srcdir)/$(appname).cpp 
	$(CXXC) -c -o $@ $(MAINAPP_CXXFLAGS) $(srcdir)/$(appname).cpp
# Include dependency info, if present:
-include ./.deps/*.d
.PHONY: all install uninstall clean distclean MAINAPP_bundle

Please note that the version number of the wxWidgets library being used has to be correct. For eg. the above makefile assumes that you are using wxWidgets 3.1 . But if you use a later version, then 3.1 has to be changed to 3.2 otherwise the build will fail. The specific places where this change has to be done are shown below:

TOOLCHAIN_FULLNAME = msw-unicode-static-3.2
WX_RELEASE = 3.2
WX_CPPFLAGS = -I${wx_top_builddir}/lib/wx/include/msw-unicode-static-3.2 -I${top_srcdir}/include -D_FILE_OFFSET_BITS=64 

At the MSYS2 command make sure you are in the application folder eg.d:\projects\wxProjects and then type make

You should get the following output signifying that the executable has been made.

Run the executable with ./mainapp. The app will run and show a simple window as shown below

What we have now is the debug version of wxWidgets for building wxWidgets applications. You can create a release version also by going to the wxWidgets folder eg. d:\wxWidgets and then using the following commands as before:

mkdir build-release

cd build-release

../configure –disable-shared

followed by a make command

Coming back to the task of running the application, it runs fine as long as you are running it from within MSYS2 command prompt. But if you double click it from the Windows explorer then it starts giving missing runtime DLL errors. These DLLs are the runtime DLL files required for minGW and not wxWidgets.

These DLLs will be found within the msys folder. Eg.if you installed MSYS2 in D:\msys64 then the required DLL files will be in D:\msys64\mingw64\bin

You can either add this folder to the PATH environment variable or copy them to the same folder as your application. That will solve the problem of the runtime DLL not being found.

Remember if you make changes to your source code, then run make clean first to clean the generated files before you run a make again to make a new executable.

CONCLUSION

This was a quick and practical way of setting up wxWidgets in Windows 10 to enable C++ development. The makefile will undergo more changes as you start building projects with multiple source and header files. If you come from a Visual Studio background then having to deal with makefiles is something new as VS takes care of all that automatically. But its good to understand the basic working of a makefile so you are not dependent on a particular IDE or tool to build your application. I will explore wxWidgets programming more in the coming days.

2 Trackbacks / Pingbacks

  1. 1.wxWidgets – Introduction – Truelogic Blog
  2. Convert IMDB data to MySql tables using C++ – Part 1 – Truelogic Blog

Leave a Reply

Your email address will not be published.


*