Book Image

Instant MinGW Starter

By : Ilya Shpigor
Book Image

Instant MinGW Starter

By: Ilya Shpigor

Overview of this book

If you need stable, dynamically developed, and easy-to-configure instrumentation for application development, look no further than MinGW. It supplies all the dynamic tools you need to enable you to develop Microsoft Windows applications, while allowing for easy integration with the software that you already use. This book will give you the expert guidance you will need to start developing applications with Instant MinGW. As well as help you to become an experienced user of MinGW, the book will also detail some of the more common pitfalls that beginners face when first using the software, and more importantly, how to avoid them yourself. This book will help  you through the installation process, and help introduce you to compilation, debugging, and profiling with MinGW. It will guide you in importing existing projects developed with Visual C++ Integrated Development Environment to MinGW, and show you how to start using it to develop your current projects with minimal effort.This book will also introduce you to developing applications with several well-known, open source, GUI libraries and the MinGW software.With Instant MinGW Starter, you will gain a reliable, comprehensive, and supremely beneficial introduction to the MinGW software, and quickly learn how to use it for new, and old, projects.  
Table of Contents (8 chapters)

Top features you'll want to know about


Several useful features of MinGW software will be described in detail in this section. You will get detailed knowledge about the most commonly used GNU toolchain utilities, such as C++ compiler, GNU Make, GNU Debugger, and the GNU gprof profiler. Also the integration of MinGW software with several well-known GUI libraries and IDE systems will be described.

1 – Make utility usage

We created a simple Makefile in the previous section. Let's explore the GNU Make utility's behavior and the syntax of Makefile in more detail.

You can run the GNU Make utility from the command shell with the make command. It will search one of the Makefile, GNUmakefile, or makefile named files and start to build the first line target. For changing this behavior, type the following command:

$ make -f OtherMakefile other_target

This leads to reading OtherMakefile as input file of rules and executing commands to build other_target.

In the previous section we created the following Makefile:

win32-app.exe: main.cpp resource.rc.res.o
  g++ -o win32-app.exe main.cpp resource.rc.res.o

resource.rc.res.o: resource.rc
  windres -o resource.rc.res.o -i resource.rc

clean:
  rm -f *.o win32-app.exe

This works, but it has some problems. First of all the main.cpp and resource.rc.res.o files are specified several times. You must rename these in several places if one of these has been changed. This violates one of the most important principles of software development, Don't repeat yourself (DRY). Variables can help you to avoid this problem. The GNU Make variables are often used to save constant values and change behavior during the build process. Our Makefile with variables will be as follows:

EXE=win32-app.exe
CPP=main.cpp
RES=resource.rc 

$(EXE): $(CPP) $(RES).res.o
  g++ -o $(EXE) $(CPP) $(RES).res.o

$(RES).res.o: $(RES)
  windres  -o $(RES).res.o -i $(RES)

clean:
  rm -f *.o *.exe

The variable definition contains the name and variable value after the equals sign. You must use the dollar sign before the variable name within parentheses to access its value after the variable definition.

The source, resource, and executable files are defined as variables in our example. Now you should change the variable value in one place only to rename any of these files.

GNU Make allows the user to define variables, but there are several special automatic variables. These variables are computed for each rule that is executed. You can use the $@ variable to specify the previously defined target and the $^ variable to specify all the prerequisites of this target. After doing all this Makefile will look as follows:

CPP=main.cpp
RES=resource.rc

win32-app.exe: $(CPP) $(RES).res.o
  g++ -o $@ $^

$(RES).res.o: $(RES)
  windres -o $@ -i $^

clean:
  rm -f *.o *.exe

The automatic variables can be used just like the user-defined ones. Now output files of g++ and the windres command are declared with the $@ variable and source files with the $^ one.

Suppose you want to link your application with a third-party library. The library is supplied with the header file and a dynamic-link or static-link library. You must inform the compiler about these files' paths and the library to link with. The simplest way to do it is using the GNU Make environment variables.

An environment variable is a variable that comes from the command shell in which GNU Make runs. There are several predefined environment variables with standard names. You can add custom environment variables from your command shell, but the most common practice is to operate with the standard one in Makefile. Environment variables affect target producing commands in Makefile (for example, additional compiler options are usually passed through environment variables).

The following Makefile is a linking example with the static-link boost program options library (the file path of the library is C:\MinGW\lib\libboost_program_options.a):

OBJ=main.o options.o
RES=resource.rc

CXXFLAGS+=-IC:\MinGW\include
LIBS+=-LC:\MinGW\lib -lboost_program_options

win32-app.exe: $(OBJ) $(RES).res.o
  g++ -o $@ $^ $(LIBS)

$(RES).res.o: $(RES)
  windres -o $@ -i $^

clean:
  rm -f *.o *.exe

CXXFLAGS is a predefined environment variable that contains command line options for the C++ compiler. This variable can be used to specify the paths of additional header files required for source compilation. Paths to headers are specified there with the -I prefix. You can specify several paths separated by a space as follows:

CXXFLAGS+=-IC:\first_include_path -IC:\second_include_path

LIBS is a simple variable with a list of static-link libraries to link with. This variable is passed to the C++ compiler explicitly in the win32-app.exe target producing rule. Libraries to link are specified with the -l prefix, and without the first three letters (lib), as well as the suffix (.a). The full path to linked libraries must be specified too with the -L prefix.

The following command is used to print all the predefined GNU Make environment variables:

$ make -p

Notice that the additional options.cpp source file has been added to the project in this example. Also the CPP variable has been renamed to OBJ and contains object files list now. GNU Make will compile object files from source files automatically if they have same names (for example, main.o and main.cpp).

The following Makefile is a linking example with a dynamic-link zlib library (the file path of the library is C:\MinGW\git\bin\libz.dll):

OBJ=main.o
RES=resource.rc

CXXFLAGS+=-IC:\MinGW\include
LIBS+=-LC:\MinGW\git\bin –lz

win32-app.exe: $(OBJ) $(RES).res.o
  $(CXX) -o $@ $^ $(LIBS)

$(RES).res.o: $(RES)
  windres -o $@ -i $^

clean:
  rm -f *.o *.exe

Dynamic-link libraries are described in the LIBS variable by the same rules as for static-link libraries.

CXX is an environment variable with the C++ compiler's application name. This is equal to g++ by default.

You can call the GNU Make utility for the Makefile subdirectory's processing. This is an example of the root project directory, Makefile, that performs the GNU Make utility for subdirectories (foo and bar):

SUBDIRS = foo bar

.PHONY: subdirs $(SUBDIRS)

subdirs: $(SUBDIRS)

$(SUBDIRS):
  $(MAKE) -C $@

The .PHONY rule is a special rule. It is used to specify the fact that the target is not a file. This is required in our case because subdirectories always exist and the GNU Make will not rebuild targets whose files already exist. MAKE is an environment variable with GNU Make application name. This is equal to C:\MinGW\bin\make by default if the installation path of MinGW software is equal to C:\MinGW.

Makefiles can include comments. All lines starting with the # symbol will be considered by GNU Make as comments.

Makefiles can be complex and consists of several separated files. To include external file content in Makefile use include directive, for example:

include Makefile.mingw

GNU Make is a great instrument for compiling small projects with a couple of source files and headers. There are more powerful instruments for building complex applications that consist of several libraries and executables. Some of them are based on the GNU Make utility and produce Makefiles as the output (for example, GNU Autotools and CMake). I strongly recommend you to study and use one of these for your daily projects.

2 – Compiler options

The MinGW compiler behavior is highly dependent on command line options. These options are usually set through GNU Make environment variables. The following is a list of commonly used predefined environment variables:

  • CC: This variable sets the C compiler in use

  • CFLAGS: This variable sets the C compiler command line options

  • CPPFLAGS: This variable sets the C PreProcessor flags, which are used by C and C++ compilers

  • CXX: This variable sets the C++ compiler in use

  • CXXFLAGS: This variable sets the C++ compiler command line options

  • LD: This variable sets the linker in use

  • LDFLAGS: This variable sets the linker command line options

  • LDLIBS: This variable sets libraries to link

The following is a list of commonly used MinGW C and C++ compilers' command line options:

  • -o file-name: This gives the name of the compiler output file.

  • -c: This is used for compilation only. The object files will be created without further linking.

  • -Dname=value: This defines the C preprocessor macro with a specified name and value. The =value part can be skipped. The default value (equal to 1) will be used instead. The result of this option will be the same as the following declaration in the source file:

    #define name value
  • -llibrary-name: This uses the specified dynamic-link or static-link library for linking.

  • -Idirectory: This uses the directory to search headers by compiler.

  • -Ldirectory: This uses the directory to search dynamic-link libraries for linking.

  • -g: This produces debugging information to be used by GDB debugger.

  • -pg: This generates extra code to write profiling information for the gprof performance analyzer.

  • -Wall: This shows all the compiler's warning messages.

  • -On: This sets the compiler's optimization level to an n value. The available levels are -O0, -O1, -O2, -O3, -Os, and -Ofast. The -O0 option disables all optimizations. The -O3 option provides the maximum optimization of code size and execution time. The -Os option optimizes for code size. The -Ofast option is the -O3 option with non-accurate math calculation.

  • -std=standard: This uses the specified language standard (example for C++ standard: -std=C++11).

3 – Importing the existing Visual C++ project

You can use MinGW software even if you already have your project developed with Visual C++. The importing process from Visual C++ to MinGW is quite simple. All you need is to remove unusable headers and create Makefiles to compile and link existing C++ sources.

This process will be described in detail in this section by an example application. The application is a simple command-line archiving utility based on the zlib compression library. The boost library is also used for command-line option parsing. The application consists of the core static-link library and the z_pack executable. This separation by library and executable is required for complex project linking example with several modules.

You can see the Visual C++ project structure in the Solution Explorer window in the following screenshot:

First of all, let's look at the source code of the core library. This library contains the implementation of most of the application's functionality. The command-line parsing and compressing mechanisms are implemented here. Each of these mechanisms are encapsulated in a separate class. The Options class implements the command-line options' parsing. The Packer class implements the compressing and decompressing algorithms.

Let's look at the Options class. The following code shows the class declaration in the options.h file:

namespace po = boost::program_options;
class Options
{
public:
    Options(int argc, char* argv[]);

    std::string GetString(std::string option_name);
    po::options_description& GetDescription();
    bool IsUnzip();
    bool IsComplete();

private:
    po::variables_map options_;
    po::options_description description_;
};

The following code shows the constructor definition of the Options class in the options.cpp file:

Options::Options(int argc, char* argv[])
{
    description_.add_options()
        (kHelp.c_str(), "produce help message")
        (kInFile.c_str(), po::value<string>(), "input file name")
        (kOutFile.c_str(), po::value<string>(), "output file name")
        (kUnzip.c_str(), "unzip the archive");

    try
    {
        po::store(po::parse_command_line(argc, argv, description_),
                       options_);
    }
    catch(...)
    {
        cout << GetDescription() << "\n";
        exit(1);
    }
}

The constructor's input parameters are the count of command-line arguments and the vector with arguments' values. First of all the object from the boost library of the options_description class with the description_ name is configured here with the available command-line arguments. This object is a field of the Options class.

All available command-line arguments are defined as global constants of the string type in the options.h file:

static const std::string kHelp = "help";
static const std::string kInFile = "in";
static const std::string kOutFile = "out";
static const std::string kUnzip = "unzip";

These arguments with descriptions are passed to the add_options method of the description_ object to configure it. Now this object stores information about available command-line arguments. After that, arguments passed to the constructor input parameters are parsed and saved to the variables map. This map is an object from the boost library of the variables_map class with the options_ name. This object is a field of the Options class.

The available command-line arguments are printed if any exception occurs in the arguments' parsing operation. The application's termination will be caused with the exit function in this case.

The following code is the GetString method's definition of the Options class in the options.cpp file:

string Options::GetString(string option_name)
{
    if ( options_.count(option_name) == 0 )
        return string();

    return options_[option_name].as<string>();
}

The method returns the specified program option value of the string type or an empty string if the option has not been passed as a command-line argument. I suggest you name command-line arguments as program options after parsing them in the constructor of the Options class.

The following three methods of the Options class are quite simple. These perform a check on the existence of specific program options or return them:

  • The IsComplete method checks if input and output filenames have been passed as command-line arguments to the application. This method returns the true value if the filenames exist.

  • The IsUnzip method checks if the --unzip command-line argument exists.

  • The GetDescription method returns the reference to the description_ field of the Options class. You can print available command-line arguments if this object is passed to the cout standard output stream.

The second class of the core library is Packer. The compressing and decompressing algorithms are implemented here. This class contains the Compress and Decompress static methods. The static class methods may be very helpful to implement algorithms without state and mutable data. You don't need the object of the class to call static methods.

The following code shows the declaration of the class in the packer.h file:

class Packer
{
public:
  static void Compress(std::string in_file, std::string out_file);
  static void Decompress(std::string in_file, std::string out_file);
};

The following code shows the Compress method's definition in the packer.cpp file:

void Packer::Compress(string in_file, string out_file)
{
  io::filtering_ostreambuf out;
  out.push(io::zlib_compressor());
  out.push(io::file_sink(out_file.c_str(), ios::binary));
  io::copy(io::file_source(in_file.c_str(), ios::binary), out);
}

The input parameters of this method are strings with filenames of source and target files.

The compression is performed with the copy function from the boost library that copies one stream content to another. The stream of the file_source class from the boost library is used in this function as input parameter. The copy function produces the object of the filtering_ostreambuf class with the out name as the result. The stream of the file_source class is anonymous and is created from the source filename and stream type. This is the binary type in our case. The out object has been configured by the compression filter of the zlib_compressor type and anonymous stream of the file_sink boost library class. This anonymous stream represents the target file.

After performing the Compress method, the compressed file with the specified target filename will be created.

The following code shows the Decompress method's definition of the Packer class in the packer.cpp file:

void Packer::Decompress(std::string in_file, std::string out_file)
{
  io::filtering_istreambuf in;
  in.push(io::zlib_decompressor());
  in.push(io::file_source(in_file.c_str(), ios::binary));
  io::copy(in, io::file_sink(out_file.c_str(), ios::binary));
}

This method is similar to the Compress method, but the filter of the zlib_decompressor type has been used here. The decompressed file with a specified target filename will be created after this method is performed.

The rest of the core library source files have been automatically generated by Visual C++.

Another solution's project is z_pack. This project binds the core library classes' functionality in to use them in the complete application. The z_pack project consist of one source file with the main function implementation and several autogenerated files by Visual C++.

The following code shows the main function's definition in the z_pack.cpp file:

int main(int argc, char* argv[])
{
    Options options(argc, argv);

    If ( ! options.IsComplete() )
    {
        cout << options.GetDescription() << "\n";
        return 1;
    }

    if ( options.IsUnzip() )
        Packer::Decompress(options.GetString(kInFile), options.GetString(kOutFile));
    else
        Packer::Compress(options.GetString(kInFile), options.GetString(kOutFile));
    return 0;
}

The input parameters of this function are the same as the Options class constructor. These are count of command-line arguments and vectors with argument values. First of all the object of the Options class with the options name is created here. The next operation is checking the source and target filenames for correctness using the IsComplete method of the options object. The available command-line arguments will be printed and the application will be terminated if this checking fails. The specified compression or decompression operation is performed if command-line arguments are correct. The IsUnzip method of the options object defines what kind of operation must be performed. The Compression and Decompression operations perform as per the Packer class static methods.

The input parameters for these methods are available from the GetString method of the Options class execution result.

Full Visual C++ project sources are available in the code bundle uploaded on the Packt website.

You can build this project and check its functionality. The Visual C++ versions of the boost and zlib libraries are required to compile the project. The comfortable distribution of both libraries is available at the following website:

http://www.boostpro.com/download

You can test the functionality of our example application after building one. Type the following command to compress the existing file:

$ z_pack.exe --in test.txt --out test.zip

The following command is used to decompress the existing archive:

$ z_pack.exe --unzip --in test.zip --out test.txt

Now you have the necessary information about our example Visual C++ project to import it to the MinGW software. The following are step-by-step instructions to do this:

  1. Create a new directory for the MinGW project version with the core and z_pack subdirectories.

  2. Copy the options.h, options.cpp, packer.h, and packer.cpp files to the core subdirectory.

  3. Copy the z_pack.cpp file to the z_pack subdirectory.

  4. Remove the following line from all the files in the project that have the cpp extension:

    #include "stdafx.h"
  5. Add the following Makefile to the root project directory:

    SUBDIRS = core z_pack
    
    .PHONY: all $(SUBDIRS)
    
    all: $(SUBDIRS)
    
    $(SUBDIRS):
      $(MAKE) -C $@ clean
      $(MAKE) -C $@

    This Makefile allows you to perform the make clean and make commands for the core and z_pack subdirectories. The make command will build your application and the make clean command will remove output files generated by the compiler and linker.

  6. Add the following Makefile to the core subdirectory:

    OBJ=options.o packer.o
    
    CXXFLAGS+=-IC:\MinGW\include
    
    libcore.a: $(OBJ)
      ar rcs $@ $^
    
    clean:
      rm -f *.o *.a

    The ar archive utility is used to maintain the options.o and packer.o object files into the libcore.a archive here. This archive will be used for static linking with the z_pack executable. The libcore.a archive is conceptually the same as the Visual C++ static-link library. You can get additional information about the ar archive utility by the executing following command:

    $ ar --help
    
  7. Add the following Makefile to the z_pack subdirectory:

    OBJ=z_pack.o
    
    MINGW_DIR=C:\MinGW
    CXXFLAGS+=-I..\core
    LIBS+=-L..\core -lcore -L$(MINGW_DIR)\lib -lboost_program_options -lboost_iostreams -L$(MINGW_DIR)\git\bin -lz
    
    z_pack.exe: $(OBJ)
      $(CXX) -o $@ $^ $(LIBS)
    
    clean:
      rm -f *.o *.exe

    Linking with all necessary external libraries (boost and zlib) occurs here because the ar archive utility does not perform any linking.

  8. Type the make command in the root project directory to build our application.

This is all you need to import our example Visual C++ project to the MinGW software. You will get the z_pack.exe executable file after building it.

It is quite simple to change the libcore.a static-link library to the dynamic-link variant one. All you need is to change the Makefile files for the z_pack executable and the core library.

The following Makefile will create the dynamic-link core library variant:

OBJ=options.o packer.o

MINGW_DIR=C:\MinGW
CXXFLAGS+=-I$(MINGW_DIR)\include
LIBS+=-L$(MINGW_DIR)\lib -lboost_program_options -lboost_iostreams -L$(MINGW_DIR)\git\bin -lz

libcore.dll: $(OBJ)
  $(CXX) -shared -o $@ $^ $(LIBS)

clean:
  rm -f *.o *.dll

The C++ compiler and linker will be called here unlike the static-link core library variant. Furthermore, the -shared compiler option must be specified to create the dynamic-link library.

The following Makefile is for the z_pack executable to link with the core library dynamically:

OBJ=z_pack.o

CXXFLAGS+=-I..\core
LIBS+=-L..\core -lcore

z_pack.exe: $(OBJ)
  $(CXX) -o $@ $^ $(LIBS)

clean:
  rm -f *.o *.exe *.dll

Linking with external libraries (boost and zlib) is not required here because it has occurred in the core library building.

You must copy the libcore.dll library and the z_pack.exe executable files into one directory to run the application.

It is important to note that libraries, objects, and executable files compiled with Visual C++ and MinGW software are incompatible. This means that you need the MinGW version of all static-link and dynamic-link libraries that you want to link with your application compiled with MinGW software. You must check the existing MinGW version of all third-party libraries that have been used in your project before importing this to MinGW software.

4 – Debugging application

MinGW software contains GNU Debugger (GDB). This is a standard tool to debug applications developed with MinGW software. You can't use GDB to debug projects compiled with the Visual C++ compiler.

You can install GDB manually if it doesn't exist in your MinGW software distribution. Perform the following instructions to do the same:

  1. Download the GDB application archive from the official download page:

    http://sourceforge.net/projects/mingw/files/MinGW/Extension/gdb

    Some problems might occur with the latest GDB version's launching. Try to install the previous debugger version if you get errors.

  2. Extract the downloaded archive to the MinGW software installation directory. I recommend you to extract the archive to C:\MinGW\git if you have installed MinGW software with Git as described in this book.

    After installing GDB you can test its functionality by typing the following command:

    $ gdb --help
    

GDB has been installed correctly if you see the application using information. Now you have the necessary debugger utility to start debugging your MinGW-based application.

Let's debug the example application with GDB. The application is a simple program with anull-pointer assignment.

The following code shows the content of the source file named segfault.cpp:

#include <string.h>

void bar()
{
  int* pointer = NULL;
  *pointer = 10;
}

void foo()
{
  bar();
}

int main()
{
  foo();

  return 0;
}

The null-pointer assignment operation occurs in the bar function. The bar function is called from foo and the foo function is called from the main function.

The following Makefile is to compile the example:

OBJ=segfault.o

CXXFLAGS+=-g

segfault.exe: $(OBJ)
  $(CXX) -o $@ $^

clean:
  rm -f *.o *.exe

The MinGW C++ compiler doesn't include debug information in output binary files by default. We need to add the -g compiler option to do it in this Makefile.

You will get the segfault.exe executable file with debugging symbols after compilation. It means that GDB can inform you not only about memory addresses but also the names of routines and variables.

Type the following command to start debugging our example application:

$ gdb segfault.exe

To start the application with command-line arguments use the --args GDB option. For example:

$ gdb --args z_pack.exe --in test.txt --out test.zip

The input and output filenames will be passed to the z_pack.exe application in this case.

You will see the GDB command prompt after launching the debugger. Type the r command to run the loaded application:

(gdb) r

This is the short variant of the run command. Most of the GDB commands have common and short variants. All future commands will be described with short variants because they are easy to remember and type.

You will see this program crash message after the application starts running, as shown in the following screenshot:

You can see that the program abortion is receiving the SIGSEGV signal by application. The POSIX system sends this signal to process when it makes an invalid virtual memory reference or segmentation fault. Furthermore the source file's line, where the error has occurred, is displayed here. The following is the sixth line of the segfault.cpp file:

*pointer = 10;

Our example program execution has stopped after the crash. You can interact with the debugger through the command line when the program is stopped. For example, you can get the stack backtrace to explore the nested functions' calls. Type the bt command as follows:

(gdb) bt

You will see something like the following screenshot:

You will see called functions' names and source file lines, where these have been called by the program just before it crashed.

Moreover, you can get a list of source file lines in the error place by the l command:

(gdb) l

You will see the bar function source code. Now you have enough information to fix the segmentation fault error.

To quit from GDB type the q command:

(gdb) q

And type y to confirm.

GDB allows you to set breakpoints to stop program execution in a predefined place. There are several breakpoint types. The simplest types are a breakpoint at entry to the function and a breakpoint at a line in a source file. You need to specify the application source files directory to provide access to these for GDB. The command to start the application debugging in this case will look like the following:

$ gdb --directory=. segfault.exe

The --directory command-line option defines the source files directory. The current directory has been added in this example (the current directory equals to point symbol).

All the loaded directories are available by typing the following command:

(gdb) show directories

The following command is used to set a breakpoint at the foo function from the segfault.cpp source file:

(gdb) b segfault.cpp:foo

To set a breakpoint at the fifth line of the segfault.cpp source file type the following command:

(gdb) b segfault.cpp:5

A list with information about all the current defined breakpoints is available by using the following command:

(gdb) i b

You can run our example program after setting breakpoints:

(gdb) r

Program execution will be stopped at the first breakpoint in the foo function after that. You can continue execution by using the c command:

(gdb) c

Type this and the next breakpoint at the fifth line of the segfault.cpp source file will be achieved. The backtrace information and source file lines are available at each breakpoint.

Watchpoint is a special breakpoint type to detect read and write variable operations. This command is used to set a watchpoint for the pointer variable:

(gdb) aw pointer

GDB can set such watchpoints if variables have been defined in the current context. This means that you must stop program execution at the bar function and then set a watchpoint for its local pointer variable. The program can be stopped in the main function to set a watchpoint for any global variable.

Moreover, you can configure GDB to display a list of variables with the current values at each breakpoint hit. To add the pointer variable in this list type the following command:

(gdb) display pointer

The value of the pointer variable will be displayed at the next breakpoint program stop.

You can disable a breakpoint of any type to prevent the program from stopping at it. The following is the command to do it:

(gdb) disable 1

The specified number is a breakpoint identifier. This identifier is declared in the breakpoints information list.

To enable the breakpoint type the following command:

(gdb) enable 1

The breakpoint can be removed if it is no longer needed:

(gdb) d 1

There are several useful commands for tracing a program:

  • Continue to run a program until the control reaches a different source line (analogous of trace into):

    (gdb) s
    
  • Continue to the next source line in the current stack frame (analogous of step over):

    (gdb) n
    
  • Continue execution until the function in the selected stack frame returns:

    (gdb) fin
    

These commands can be used after the program has run and been stopped by breakpoint.

You can rebuild your application without debug information to produce release variants of executable files and libraries. But there is a possibility to remove debug information from existing binary files. Use the strip command as follows:

$ strip segfault.exe

GDB is quite useful to debug abnormal program behavior (segmentation faults, for example). But using the same approaches as the test suite and event logging can complete the GDB capabilities for the algorithms' correctness checking.

5 – Profiling application

MinGW software contains the gprof performance analyzing tool. This instrument can be useful for tracking down an application's bottlenecks. The gprof tool is a part of the GNU Binutils collection and therefore it is present in all MinGW distributions. You can't use gprof to analyze the performance of applications compiled with Visual C++ compiler.

Let's profile an example application with gprof. This application reads bytes from a file to an STL vector type container, sorts them, and writes the result to an output file. The application source code is present in the file named sorting.cpp.

The following is the main function definition:

int main()
{
  ReadData();

  SortData();

  WriteResult();

  return 0;
}

You can see the basic application algorithm in this function. First of all, the data is reading from the input text file. Then the data is sorted and written to the output file. Each of these steps are implemented in the separate function.

The following code shows the ReadData function's definition:

void ReadData()
{
  ifstream in_file("source.txt", ios::in | ios::binary);

  copy(istream_iterator<char>(in_file), istream_iterator<char>(), 
     back_inserter(gData));
}

The stream of the ifstream class with the in_file name is used here to read the source.txt input file content. Then the STL copy algorithm is used to copy the in_file stream content to the global gData container of the vector<char> class. We use the iterator of the istream_iterator class to access elements of the in_file stream in the copy algorithm.

The SortData function implements the simplest bubble sort algorithm:

void SortData()
{
  char temp;
  size_t size = gData.size();
 
  for (int i = (size - 1); i > 0; i--)
  {
    for (int j = 1; j <= i; j++)
    {
    if (gData[j-1] > gData[j])
    {
      temp = gData[j-1];
      gData[j-1] = gData[j];
      gData[j] = temp;
    }
    }
  }
}

This sort algorithm processes the elements of the gData container.

The following is the WriteResult function definition:

void WriteResult()
{
  ofstream out_file("result.txt", ios::out | ios::binary);
  out_file.write(&gData[0], gData.size());
}

The stream of the ofstream class with the out_file name is used here to write the gData container content to the output result.txt file. The write method of the out_file stream is called here to perform the file writing operation. An empty file with the result.txt name will be created to write if this file already exists. The sorting.cpp file is available in the code bundle uploaded on the Packt website.

The following is Makefile for the example application:

OBJ=sorting.o

CXXFLAGS+=-pg

sorting.exe: $(OBJ)
  $(CXX) -o $@ $^ $(CXXFLAGS)

clean:
  rm -f *.o *.exe *.out *.dot

Profiling information is needed for performance analyzing. This information can be generated by an executable file's extra code. The same kind of extra code creation is an optional feature of the compiler and this feature can be specified by the compiler -pg option. This option must be specified for each object file compilation and final linking. The CXXFLAGS environment variable is used to do this in our Makefile.

You can test our example application after compilation. Just copy any plain text file to project directory with, name it source.txt, and run the sorting.exe executable file. You will get the result.txt file with the sorted source file content after the application finishes its work. Perform the following steps to profile our example application:

  1. Launch the application's executable file. After that you will get the gmon.out file with the profiling data in the current working directory.

  2. Run the gprof utility to interpret the gmon.out file information and write the result to the profile.txt output file:

    $ gprof -zq sorting.exe > profile.txt

These gprof utility options have been used in the preceding:

  • The -z option is required to include all used functions in the output file

  • The -q option causes a call-graph of the program for a more detailed report

You have got a text report with the profiling data in the profile.txt file. It can be opened in any text editor. But this text representation of the profiling information is not comfortable to discovery. There are handy tools for visualizing a gprof report.

For visualization we need the following tools:

  • Python 2.7 interpreter

  • Python script to convert the gprof report to dot file format

  • Graphviz package with visualization utilities for dot format

You can download Python version 2.7 from the following official website:

http://python.org/download

Python can be installed with the standard Windows Installer. To do this just run the downloaded MSI file.

The script to convert a gprof report text file to dot format is available on the following developer page:

http://code.google.com/p/jrfonseca/wiki/Gprof2Dot

This script is a free software and you can use, distribute, and modify it as you want. To install this script copy it to C:\MinGW\bin or C:\MinGW\git\bin.

The Graphviz package is available at the following official website:

http://www.graphviz.org/Download_windows.php

Graphviz can be installed with Windows Installer in the same way as Python interpreter.

Now you have the necessary scripts and the visualization utility to visualize our profiling results. Perform the following steps to do this:

  1. Run the gprof2dot.py script to get the dot file:

    $ gprof2dot.py -s profile.txt > profile.dot
    

    This gprof2dot.py utility option has been used here.

    The -s option removes functions and templates argument information.

    After that you will get the profile.dot file with call-graph of the program.

  2. Run the gvedit.exe application. It is available from the Start menu of Windows. Go to File | Open from the main menu. Specify the profile.dot file.

You will see a call-graph of the program as shown in the following screenshot:

You can see a call-graph in the preceding screenshot. Nodes of this graph are represented as colored edges. These nodes represent called functions of the analyzing program. Each edge contains the following information:

  • Total time % is the percentage of the running time spent in this function and all its children

  • Self time % (in brackets) is the percentage of the running time spent in this function alone

  • Total calls is the total number of times this function was called (including recursive calls)

Moreover, nodes have temperature-like colors according to the total time percent value. Most time expensive functions display as red (hot-spot) edges and the most cheap ones as dark blue.

The most execution time of our example application has been spent in the red colored SortData function. Statistic information about the SortData function at graph confirms it:

  • Total time is equal to 99.35 percent

  • Self time is equal to 55.81 percent

  • Total calls is equal to 1

We can use the STL sort algorithm instead of the bubble one to optimize our example application. Let's change the code of the SortData function as follows:

void SortData()
{
  sort(gData.begin(), gData.end());
}

Now you need to rebuild the application, run the application, and run gprof and the gprof2dot.py script. Open the resulting dot file in the Graphviz application. You will see the call-graph as shown in the following screenshot:

The red edges disappear from the graph. This means that we don't have any explicit bottleneck. All program execution time has been evenly distributed between several functions.

You can remove the profiling extra code from executable files and libraries after profiling with the strip command:

$ strip sorting.exe

Profiling is a significant technique that allows you to find and remove bottlenecks in your applications. This may be very helpful for performance analyzing of the complex systems with many components and libraries. MinGW software allows you to include this technique in your software development process in a simple and fast manner.

6 – Developing with cross-platform libraries

MinGW software allows you to develop applications based on any library compiled with the MinGW C++ compiler. Open source libraries are often supplied in Visual C++ and MinGW compilation variants. Moreover, you can always get the source code of these libraries and build them with your MinGW software. Several well-known open source cross-platform frameworks and toolkits are described as follows:

  • Qt framework

  • Gtk+ widget toolkit

  • wxWidgets framework

The same functionality example application will be developed with each of these libraries. The goal of these examples is to show the first steps to deploy and to start working with these libraries.

Our example application consists of a window with two buttons. A click on the first button leads to the display of a message and a click on the second button leads to the application termination. This functionality is the same as the one described in the Quick start section.

The Qt framework

The Qt framework provides not only a cross-platform widget toolkit for GUI development but also contains features for SQL database access, XML parsing, thread management, interaction over a network, and internalization support. The Qt framework has its own container classes such as Qstring or QVector and a set of well-known algorithms such as sorting, searching, and copying to process data in these containers that allow you to substitute the capabilities of STL and Boost libraries by the Qt ones. This kind of Qt framework self-sufficiency is of great advantage to develop cross-platform applications. All you need to do to import your Qt application to a new platform is building a Qt framework for this one. There are a lot of platforms that are supported by Qt framework developers:

  • Windows

  • Mac OS X

  • Linux

  • Solaris

  • Symbian

  • Android (unofficial framework port with the name Ministro)

Let's begin our work with the Qt framework. It is important to note that Qt libraries have been compiled with the specific MinGW software version. Your application must be compiled with the same MinGW version and therefore you must install it. The alternative way is the compilation of Qt libraries sources with your already installed MinGW software, but this variant will not be described in this book. You can find some helpful instructions to do this at the following website:

http://www.formortals.com/build-qt-static-small-microsoft-intel-gcc-compiler

All other toolkits described here don't need a specific MinGW software version. The following are instructions to install Qt libraries version 4.6.4 and some necessary software to start developing with it:

  1. Download the MinGW version of the Qt libraries for Windows from the following official website:

    http://qt-project.org/downloads

    Note that this library has been compiled with a specific (equal in our case to 4.4) MinGW software version.

  2. Install the downloaded Qt libraries with the setup wizard. Run the downloaded exe file to do it.

  3. Download the MinGW software of version 4.4 from the following official download page:

    http://sourceforge.net/projects/mingw/files/MinGW/Base/gcc/Version4/Previous%20Release%20gcc-4.4.0/

    You need the file to be named gcc-full-4.4.0-mingw32-bin-2.tar.lzma. This is an archive with the MinGW compilers' executable files and necessary core libraries.

  4. Extract the downloaded MinGW software archive to the directory without spaces in the path (for example, C:\MinGW4.4).

    You can use the 7-Zip application to extract the LZMA archive type. This application is available at the following official website:

    http://www.7-zip.org/download.html

  5. Download the GNU Binutils for MinGW software from the following official download page:

    http://sourceforge.net/projects/mingw/files/MinGW/Base/binutils/binutils-2.19

    You need the archive to be named binutils-2.19-2-mingw32-bin.tar.gz.

  6. Extract the downloaded GNU Binutils archive to the same directory as the MinGW software. This is C:\MinGW4.4 in our case.

  7. Download the GNU Make utility from the following web page:

    http://sourceforge.net/projects/mingw/files/MinGW/Extension/make/mingw32-make-3.80-3

    You need to download the mingw32-make-3.80.0-3.exe file.

  8. Install GNU Make utility to the MinGW software directory (C:\MinGW4.4). Run the downloaded exe file and use the setup wizard to do it.

  9. Add the installation MinGW software path to the PATH Windows environment variable. Remove the existing paths of other MinGW software installations from there. The C:\MinGW4.4\bin path must be added in our example.

Now you have the necessary libraries and specific MinGW software version to start developing an application based on the Qt framework.

Our example application is implemented in the main.cpp source file. The following is the main function definition:

int main(int argc, char* argv[])
{
  QApplication application(argc, argv);
  
  QMainWindow* window = CreateWindow();

  CreateMsgButton(window);

  CreateQuitButton(window, application);
  
  return application.exec();
}

First of all, the object of the QApplication class named application is created here. This object is used to manage the application's control flow and main settings. After that, the window of the QMainWindow class named window is created by the CreateWindow function. Two window buttons are created by the CreateMsgButton and CreateQuitButton functions. The exec method of the application object is called to enter the main event loop when all user interface objects have been created. Now the application starts processing events such as button pressing.

The following is the CreateWindow function that encapsulate's the main application window creation:

QMainWindow* CreateWindow()
{
  QMainWindow* window = new QMainWindow(0, Qt::Window);
  
  window->resize(250, 150);
  window->setWindowTitle("Qt Application");
  window->show();

  return window;
}

The main application window is an object of the QMainWindow class named window . It is created by a constructor that has two input parameters. The first parameter is of the QWidget* type. This is a pointer to the window's parent widget. It equals to zero in our case which means that there is no parent widget. The second parameter is of the Qt::WindowFlags type and defines the window style. It equals to Qt::Window that matches the standard window appearance with the system frame and title bar.

After the main window creation its size is set with the resize method of the window object. Then the window title is set with the setWindowTitle method of the window object. The next action is to make the main window visible by using the show method of the window object. The function returns the pointer to the created window object.

The following code shows the CreateMsgButton function that encapsulates the creation of button with message showing action:

void CreateMsgButton(QMainWindow* window)
{
  QMessageBox* message = new QMessageBox(window);
  message->setText("Message text");
  
  QPushButton* button = new QPushButton("Message", window);
  button->move(85, 40);
  button->resize(80, 25);
  button->show();
  QObject::connect(button, SIGNAL(released()), message, SLOT(exec()));
}

At first, we need to create a message window to display it when we click on the button. This message window is an object of the QMessageBox class named message. It is created by a constructor with one input parameter of the QWidget* type. This is a pointer to the parent widget. The text displayed in the message window is set by the setText method of the message object.

Now we need a button that will be placed at the main window. This button is the object of the QPushButton class named button. The constructor with two input parameters is used here to create this object. The first parameter is a string with the button text of the QString class. The second parameter is the parent widget pointer. The position and size of the button object are set by the move and resize methods. After configuring the button we make it visible by using the show method.

Now we need to bind the button press event and message window displaying. The connect static method of the QObject class is used here for this goal. It allows to create a connection between the button object's release signal and the exec method of the message object. The exec method causes the displaying of window with message.

The following code shows the CreateQuitButton function that encapsulates the creation of the close application button:

void CreateQuitButton(QMainWindow* window, QApplication& application)
{
  QPushButton* quit_button = new QPushButton("Quit", window);
  quit_button->move(85, 85);
  quit_button->resize(80, 25);
  quit_button->show();
  QObject::connect(quit_button, SIGNAL(released()), &application, SLOT(quit()));
}

This function is similar the CreateMsgButton function. But the message window isn't created here. The close application button is an object of the QPushButton class named quit_button. The release signal of the quit_button button is connected to the quit method of the application object. This method leads to the application closing with successful code.

The full main.cpp file is available in the code bundle uploaded on the Packt website.

Now you are ready to build an example application. You need to perform the following instructions:

  1. Create a Qt project file with the following command:

    $ qmake -project
    

    You will get a file with the pro extension and name of the current directory.

  2. Create Makefile, service files, and subdirectories with the following command:

    $ qmake
    
  3. Compile the project with the GNU Make utility:

    $ mingw32-make
    

The GNU Make utility executable name is mingw32-make in the official distribution. This one has been installed with the MinGW software of version 4.4.

You will get the qt.exe executable file in the debug subdirectory after compilation.

This is the debugging version of our example application. Type the following command to build the release version:

$ mingw32-make release

The qt.exe executable file will be created in the release subdirectory after this compilation.

The Gtk+ widget toolkit

Gtk+ is a cross-platform toolkit with many widgets to construct user interfaces. It is important to note that Gtk+ has been written in C language. This toolkit has an object model, but there are no C++ classes and objects. You can use the toolkit in your C++ applications, but it may be helpful to use the gtkmm. The gtkmm is an official C++ interface for Gtk+. The gtkmm interface is not described in this book, but you can get more information about it at the following official website:

http://www.gtkmm.org

Gtk+ is a good choice if you are looking for a widget toolkit for user interface creation and you don't need any additional features provided by the Qt framework.

The following are the instructions to install the Gtk+ widget toolkit:

  1. Download the all-in-one bundle archive with the Gtk+ widget toolkit from the following official website:

    http://www.gtk.org/download/win32.php

  2. Extract the archive to the directory without spaces in the path (for example, C:\Gtk+).

  3. Add the installation path of the Gtk+ toolkit to the PATH Windows environment variable. The path, C:\Gtk+\bin, must be added in our case.

  4. Create a new Windows environment variable named PKG_CONFIG_PATH. Specify the path to the pkg-config utility files as a value of this variable. This is C:\Gtk+\lib\pkgconfig in our case.

Now you have the necessary libraries to start developing applications with the Gtk+ widget toolkit. Unlike the Qt framework you don't need the same MinGW software version as Gtk+ libraries have been compiled with. Any already installed MinGW software can be used to compile your applications.

Our example application is implemented in the main.cpp source file. The following is the main function definition:

int main(int argc, char* argv[])
{
  gtk_init(&argc, &argv);

  GtkWidget* window = CreateWindow();

  GtkWidget* box = gtk_vbox_new(FALSE, 0);
  gtk_widget_show(box);

  CreateMsgButton(box);

  CreateQuitButton(box);

  gtk_container_add(GTK_CONTAINER(window), box);
  gtk_widget_show(window);
  gtk_main();

  return 0;
}

First of all the gtk_init function is called. It initializes everything that we need to operate with Gtk+ toolkit. Four widgets are created in the main function after that. There are the main window, vertical box container, and two buttons. The main window is a pointer to the GtkWidget Gtk+ structure that is created by the CreateWindow function.

The box container is needed to place several widgets in the main window (two buttons in our case). This box container is a pointer to the GtkWidget structure that is created by the gtk_vbox_new Gtk+ function. This function has two input parameters. The first parameter is of the gboolean type that defines whether all children widgets are to be given equal space allotments. The second parameter is of the gint type that defines the number of pixels to place between child widgets. The gtk_widget_show function is called to make the box container visible.

Buttons to show messages and close applications are created in the CreateMsgButton and CreateQuitButton functions.

The gtk_container_add function is used to put one widget into another. The box container has been put into the main window in our case. After that the window widget is made visible with the gtk_widget_show function.

The gtk_main function leads to run main application loop to process events.

The following is the CreateWindow function that creates the main window:

GtkWidget* CreateWindow()
{
  GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  gtk_window_set_title(GTK_WINDOW(window), "Gtk+ Application");
  g_signal_connect(window, "delete-event",                           G_CALLBACK(gtk_main_quit), NULL);
  g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit),               NULL);

  return window;
}

The main window of the GTK_WINDOW_TOPLEVEL type is created here with the gtk_window_new function. This window type equals to a regular application window. Then the window title is set with the gtk_window_set_title function.

Now we must bind the application closing and main window destroy events. This is needed to close the application after the main window closes. The events are named signals in Gtk+ terminology. The g_signal_connect macro is used here for signal binding. This macro has four arguments. The first argument is the pointer to the widget that you need to connect to. The second argument is a string with the signal name. The third argument is a callback function that will process this signal. The fourth argument is the pointer to additional signal data.

There are two signals named delete-event and destroy that match the window closing event. The gtk_main_quit function will be called when these signals occur in our case. This function will stop the application event loop and will lead to the application termination.

The following is the CreateMsgButton function that creates the message showing button:

void CreateMsgButton(GtkWidget* box)
{
  GtkWidget* button = gtk_button_new_with_label("Message"); 
  gtk_widget_show(button);	
  g_signal_connect(G_OBJECT(button), "clicked",
                     G_CALLBACK(ShowMessage), NULL);
  gtk_container_add(GTK_CONTAINER(box), button);
}

This function has one input parameter of the pointer to the GtkWidget structure type. This is used to pass the pointer of the button container widget.

The button widget is a pointer to the GtkWidget structure named button. It is created by the gtk_button_new_with_label function. This function has only one input parameter with the button label string. After that the button widget is made visible with the gtk_window_show function. The clicked signal of the button widget is connected to the ShowMessage function. The button widget is added to the box container when it has been configured.

The following is the ShowMessage function to create and display the message window:

void ShowMessage(GtkWidget* widget, gpointer data)
{
  GtkWidget* message = gtk_message_dialog_new((GtkWindow*)data, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Message text");
  gtk_dialog_run(GTK_DIALOG(message));
  gtk_widget_destroy(message);
}

The message window is the Gtk+ dialog widget that has been created with the gtk_message_dialog_new function. Parent window pointers, dialog flags, message types, dialog buttons, and message text are passed to this function. The gtk_dialog_run function is called to display the created dialog. This function will return control when the dialog button has been clicked. The gtk_widget_destroy function at the next line will destroy our message window.

The following is the CreateQuitButton function that creates the quit button:

void CreateQuitButton(GtkWidget* box)
{
  GtkWidget* button = gtk_button_new_with_label("Quit"); 
  gtk_widget_show(button);	
  g_signal_connect(G_OBJECT(button), "clicked",
                     G_CALLBACK(gtk_main_quit), NULL);
  gtk_container_add(GTK_CONTAINER(box), button);
}

This is the same as the CreateMsgButton function, but the button labels differ. Moreover, the clicked signal of this button is bound with the gtk_main_quit function. This function will lead to the application termination.

The full main.cpp file is available in the code bundle uploaded on the Packt website.

The following is Makefile to compile our example application:

OBJ=main.o

CXXFLAGS+='pkg-config --cflags gtk+-win32-2.0'
LIBS+='pkg-config --libs gtk+-win32-2.0'

gtk.exe: $(OBJ)
  $(CXX) -o $@ $^ $(LIBS)

clean:
  rm -f *.o *.exe

The pkg-config utility from the Gtk+ toolkit is used here to get the compiler and linker Gtk+ specific flags. The grave accent mark means that the wrapped string will be performed as a command and the result of the execution will be returned as a string value.

The following pkg-config options have been used here:

  • --cflags: This prints the preprocessor and compiler flags to compile the application with a specified library

  • --libs: This prints the linker flags to link the application with a specified library

gtk+-win32-2.0 is the name of the package with the Gtk+ libraries that we want to link with.

The results of the pkg-config utility execution are assigned to the CXXFLAGS and LIBS variables.

Now you have all the source files that are needed to compile our example application. Type the make command to do this. You will get the gtk.exe executable file in the current directory.

wxWidgets framework

The wxWidgets framework contains the widget toolkit for user interface development and features for network programming, threading support, image processing, database support, and HTML and XML processing. The wxWidgets have a set of their own containers and algorithms that can be enough to develop applications with this framework resources only.

Implementing own user interface elements is common practice for many widget toolkits and frameworks. This is what makes the Qt framework and Gtk+ widget toolkit. wxWidgets unlike these, uses the native platform's user interface elements through the platform's API. Thanks to this, wxWidgets-based applications look and feel like a native one.

wxWidgets is a good base to develop cross-platform high-quality, native-looking applications for Mac OS X, Windows, Linux, and other Unix family operating systems.

Several wxWidgets framework versions are available from the official website as source code archives. You can download one of these and build it with your currently installed MinGW software.

The following are the instructions to install the wxWidgets widget toolkit:

  1. Download the wxMSV version of wxWidgets from the following official website:

    http://www.wxwidgets.org/downloads

  2. Install the downloaded wxWidgets toolkit with the setup wizard. Run the downloaded exe file to do it. We will assume that the C:\wxWidgets target directory has been specified for example.

  3. Build the wxWidgets toolkit with your already installed MinGW software. Type the following commands to do it:

    cd C:\wxWidgets\build\msw
    make -f makefile.gcc SHARED=1 UNICODE=1 BUILD=release clean
    make -f makefile.gcc SHARED=1 UNICODE=1 BUILD=release
    
  4. Download the wx-config utility from the developer's page:

    http://code.google.com/p/wx-config-win

    This utility is used to search the wxWidgets toolkit libraries and header files by GNU Make.

  5. Copy the wx-config utility to the wxWidgets installation directory (in our case C:\wxWidgets).

  6. Add the path to the wxWidgets installation directory and the path to the dynamic-linked libraries in the PATH Windows environment variable. The C:\wxWidgets and C:\wxWidgets\lib\gcc_dll values must be added in our example.

Now you have the necessary libraries to start developing applications with the wxWidgets widget toolkit.

The example wxWidgets application is implemented in the main.cpp source file. User classes must be created here unlike the Gtk+ and Qt example application variants. The MyApp class is the base application class that is derived from the wxApp wxWidgets library standard class.

The following is the MyApp class definition:

class MyApp : public wxApp
{
public:
  virtual ~MyApp() {}

private:
  virtual bool OnInit();
};

The virtual destructor and the OnInit virtual method are defined here. The virtual destructor is needed here for correct parent class data deleting. All application functionality is implemented in the OnInit method of the MyApp class.

The following is the OnInit method of the MyApp class:

bool MyApp::OnInit()
{
  MyDialog* dialog = new MyDialog(NULL, 0, _("wxWidgets application"));

  wxSizer* sizer = dialog->CreateButtonSizer(wxOK | wxCANCEL);
  sizer->SetDimension(175, 50, 100, 100);

    while ( dialog->ShowModal() == wxID_OK )
    {
      wxMessageBox(_("Message text"), 
                    _("Information"),
                    wxOK | wxICON_INFORMATION, dialog);
  }

  dialog->Destroy();
  return true;
}

The main application window is created here. This window is the object of the MyDialog class with the dialog name. The MyDialog class is a user defined class derived from the wxDialog widget class. The constructor of the MyDialog class has three input parameters. These are parent widget pointer, widget identifier, and title bar caption string.

Then two buttons with OK and Cancel captions are created for the dialog object by the CreateButtonSizer method. This method has one parameter that defines the standard buttons list to creation. Each of these buttons is represented by the bit flag. The CreateButtonSizer method returns the pointer to the object of the wxSizer class with the sizer name. This object represents the sub-window that contains the buttons. Thanks to the sizer object the button's position can be changed with the SetDimensions method. This method has four input parameters. The first two parameters are x and y coordinates and the second two parameters are the width and height of the sizer subwindow.

The ShowModal method of the dialog object method will be called in a loop after the widget's initialization. This is the main application loop. It will be interrupted when the main application window has been destroyed.

The information message will be displayed when the button with the wxID_OK identifier is clicked on. The wxMessageBox function is used to show an informational message. This function has six input parameters. The four of these are used here and the other two have values by default. The first parameter is a string with the message text. The second parameter is a string with message window caption bar text. The third parameter defines the message window style by bit flags. The fourth parameter is a pointer to the parent widget. The last two parameters are the coordinates of the message window.

The main application window will be hidden when the button with the Cancel caption will be clicked. The Destroy method of the dialog object is called here to destroy the main application window.

The following is the MyDialog class definition:

class MyDialog : public wxDialog
{
public:
  MyDialog(wxWindow* parent, wxWindowID id,
              const wxString& title) : wxDialog(parent, id, title) {}
  virtual ~MyDialog() {}
};

The MyDialog class is derived from the wxDialog widget. The class constructor and destructor are defined here. The MyDialog class constructor just passes input parameters to the parent class constructor.

You must specify this macro in the main.cpp source file to create the application instance and start the program:

IMPLEMENT_APP(MyApp)

The full main.cpp file is available in the code bundle uploaded on the Packt site.

The following is Makefile to compile our example application:

OBJ=main.o

CXXFLAGS+='wx-config --cxxflags --wxcfg=gcc_dll/mswu'
LIBS+='wx-config --libs --wxcfg=gcc_dll/mswu'

wxwidgets.exe: $(OBJ)
  $(CXX) -o $@ $^ $(LIBS)

clean:
  rm -f *.o *.exe

The wx-config utility is used here. This is the wxWidgets framework's alternative of the pkg-config utility of Gtk+ toolkit. The wx-config utility is used here to get the compiler and linker wxWidgets specific flags.

The next wx-config utility options have been used here:

  • --cxxflags: This prints the preprocessor and compiler flags to compile the application with the wxWidget library

  • --libs: This prints linker flags to link the application with the wxWidget library

  • --wxcfg: This specifies a relative path to the build.cfg configuration file

Now you are ready to compile our example application. Type the make command to do it. You will get the wxwidgets.exe executable file in the current directory after compilation.

It is important to note that you can debug and profile your applications based on any of the described toolkit and frameworks with the MinGW software tools (GDB debugger and gprof profiler).

7 – Integrating with IDE

MinGW software can be integrated with a lot of well-known free IDE systems. Integration with the following systems will be described here:

  • Code::Blocks

  • Qt Creator

  • Eclipse

Integration in this case means the ability to edit MinGW-based project source code, building this project, and debugging it from the IDE. This integration provides a comfortable interface to interact with the most commonly used MinGW instruments.

Code::Blocks

Code::Blocks is an open source cross-platform IDE for developing C and C++ applications. Code::Blocks has an open architecture. Thanks to this, IDE capabilities can be expanded with plugins with significant facilitates software development process.

Code::Blocks supports a lot of C and C++ compilers and several debuggers. This IDE is a good alternative for the Visual C++ one to develop C++ applications.

The following are instructions to install and configure the Code::Blocks IDE:

  1. Download the Code::Blocks IDE distribution with the already integrated MinGW software from the official website:

    http://www.codeblocks.org/downloads/binaries

  2. Install the downloaded Code::Blocks distribution. Run the downloaded exe file to do it.

  3. Select additional IDE components in Choose Components dialog during installation process.

    The default installable components will be enough to start developing the C++ application. But you can choose additional languages supporting GNU utilities and IDE plugins.

  4. Start installed Code::Blocks system and select GNU GCC Compiler to use in the compilers auto-detection dialog.

Now you are ready to use the Code::Blocks IDE system with integrated MinGW software.

You can install the Code::Blocks IDE without integrated MinGW software if you have already installed it. The following are instructions to set up Code::Blocks working with your already installed MinGW software:

  1. Run Code::Blocks IDE.

  2. Select Settings | Compiler and Debugger... in the main menu. You will see the compiler setting dialog:

  3. Switch to the Toolchain executables tab. Specify the MinGW software installation directory and its utility executables file names.

Perform the following actions to create a new MinGW based project in Code::Blocks IDE:

  1. Run Code::Blocks IDE. You will see the main system window:

    You can see the Start here tab content in the middle of the window. The main IDE menu is placed at the top of the window. The messages panel is placed at the bottom of the window. The build error messages, build log, debugger messages, and search results will be displayed here.

  2. Click on the create a new project icon on the Start here tab or choose File | New | Project...in the main menu.

  3. We will create a template Windows application in this example. Choose the Win32GUI project icon in the new from template dialog to do it.

  4. Choose a frame-based type of project in the next dialog.

  5. Specify the project name and path to store its sources.

  6. Select the compiler to build the application in the last dialog. It will be equal to the GNU GCC compiler by default. Leave it unchanged.

You will get template source files of the MinGW-based Windows API application. This application just shows an empty window at launch.

You can build our example application from the Code::Blocks IDE interface. Choose Build | Build in the main menu or press Ctrl + F9 to do it. The build log and build messages will be displayed in the messages panel after that. Note what debug variant of build has been performed. You can change it to a release variant by switching the Build target combobox in the main menu. The application executable files will be created at the bin subdirectory of the our project directory.

Now the application is ready to be run. Choose Build | Run in the main menu or press Ctrl + F10 to run the application. You will see the application window and console window , where the standard output stream messages will be displyed.

Code::Blocks IDE allows you to debug applications with the GDB debugger. First of all you must set breakpoints to stop program execution in specified places. Press the F5 key to set a breakpoint at the current line in the source file. Press F8 or choose Debug | Start from the main menu to start debugging. After that program execution stops at the specified line. Now you can get information about variables, call stack, CPU registers, and threads, or continue execution. All this functionality is available from the Debug submenu. You can continue the application debugging with the next line (F7) and step into (Shift + F7) commands.

Qt Creator

Qt Creator is a cross-platform open source IDE, which is part of the Qt software development kit. It includes a source code editor, visual debugger, and forms designer. It supports both MinGW and Visual C++ software.

Qt Creator is the best choice to develop Qt framework-based C++ applications. But other frameworks, toolkits, and programming languages are supported poorly. This obstacle must be considered when you choose this IDE for your application's development.

MinGW software and Qt libraries are not present in the Qt Creator IDE distribution and therefore you must install these separately.

The following are instructions to install and configure Qt Creator IDE:

  1. Download Qt Creator IDE distribution from the official website:

    http://qt-project.org/downloads

  2. Install Qt Creator with the help of the setup wizard. Just run the downloaded exe file to do it. Run the installed Qt Creator IDE. You will see the main system window:

    The Welcome tab content is placed in the middle of the window. You can see the main system menu at the top of the window. The control panel is placed at the left-hand side of the window. The most commonly used commands are available in this panel. Moreover the icons of different Qt Creator IDE modes (Editor, Designer and so on) are placed here. The messages' output panels are available at the bottom of window.

  3. Select Tools | Options... in the main menu. You will see the Options dialog.

  4. Switch to the Build & Run icon in the left-hand side of the dialog panel.

  5. Switch to the Qt Versions tab at the top of the dialog window. Now you see the following screenshot:

  6. Click on the Add button and specify the path to the qmake.exe file. This is C:\Qt\4.6.4\bin\qmake.exe for the default Qt libraries installation path.

  7. Switch to the Tool Chains tab at the top of the dialog window. You will see the following screenshot:

    Qt Creator can find already installed MinGW software automatically, but I recommend you manually add it for detailed configuration.

  8. Click on the Add button and choose the MinGW variant in the pop-up list.

  9. Click on the Browse... button near the Compiler path field and specify the path to the g++.exe file. This is equal to C:\MinGW4.4\bin\g++.exe if the MinGW software has been installed to the C:\MinGW4.4 directory.

  10. Click on the Browse... button near the Debugger input field and specify the path to the gdb.exe file. You can install the GDB debugger separately if your MinGW software distribution doesn't already contain it. The debugger path equals to C:\MinGW4.4\bin\gdb.exe for our example.

  11. Click on the Apply and then OK button to complete the configuration.

Now you are ready to use the Qt Creator IDE system integrated with MinGW software and Qt libraries. Note that your MinGW software version must be the same as the MinGW software that has been used to build your installed Qt libraries.

The following are the instructions to create example Qt-based application with Qt Creator IDE:

  1. Select File | New File or Project from the main menu. You will see the template application choosing dialog.

  2. Select Applications and Qt Gui Application variant in the project type selecting fields:

  3. Click on the Choose... button.

  4. Specify the project name (for example, qt) and location to store the source files in the Location tab of the Qt Gui Application dialog. Click on the Next button.

  5. Choose Desktop target in the Targets tab of the dialog and click on Next.

  6. You can change the default source files and class names in the Details tab. I suggest you leave these unchanged for our example application. Just click on the Next button.

  7. The subproject and version control can be added in the Summary dialog tab. Switch version control to None and click on the Finish button.

You will get a template of the Qt-based application with the source files located in a specified location.

Click on the Build Project icon at the left-hand side of the control panel or press Ctrl + B to build our example application. The qt.exe executable file will be created in the debug subdirectory of the project directory. You can select the debug or release build variant in the control panel's project configuration submenu (this is placed under the Run icon).

Click on the Run icon to launch our example application. You will see the empty application window with the status bar and toolbar.

Qt Creator IDE allows you to debug your applications with the GDB debugger. This is standard procedure to do it; you must specify breakpoints at source file lines and then start debugging. Use the F9 key to set a breakpoint and the F5 key to start debugging.

The variables' current values, call-stack, and watchpoints configuration are available in debugging mode. You can find all this information in the additional panels of Qt Creator main window. Use Step Over (F10) and Step Into (F11) Debug submenu items to continue application execution.

Eclipse

Eclipse is a cross-platform open source IDE with multi-language support. There are a huge amount of plugins that have been developed for this IDE. Eclipse supports many compilers, interpreters, debuggers, version control systems, unit testing frameworks, and so on. You can use Eclipse for developing applications in any popular programming language and framework.

Eclipse is an excellent IDE for comfortable application developing, but it has been developed in Java and has a massive architecture. Therefore there are high demands on the performance of your computer.

This is not the Eclipse IDE system distribution that contains the MinGW software. You must install it separately to integrate with Eclipse.

The following are instructions to install and configure the Eclipse IDE system:

  1. Download Java Runtime Environment (JRE) from the official website:

    http://www.oracle.com/technetwork/java/javase/downloads/index.html

  2. Install it with the setup wizard. Just run the downloaded exe file to do it.

  3. Add the path of the JRE executable files to the PATH Windows environment variable (for example, C:\Program Files\Java\jre7\bin).

  4. Download the Eclipse IDE for C/C++ Developers version archive from the official website:

    http://www.eclipse.org/downloads

    Note what you need the 32-bit Eclipse IDE system version for 32-bit JRE and 64-bit one for 64-bit JRE.

  5. Unpack the Eclipse archive to any directory (for example, C:\Program Files)

Now you are ready to use the Eclipse IDE system. The MinGW software utilities will be integrated automatically thanks to Windows environment variables. Therefore the MinGW bin subdirectory with executable files must be specified there.

The following are instructions to create an example application in Eclipse IDE:

  1. Run Eclipse IDE. You will see the Welcome screen.

  2. Select File | New | C++ Project from the main menu. You will see the project configuration dialog as shown in the following screenshot:

  3. Select the Hello world C++ Project item in the Project type selection field. Select the MinGW GCC item in the Toolchains selection field. Click on the Next button. You will see the Basic Settings dialog. The author, copyright notice, and source files directory can be specified here.

  4. Click on the Next button. This is the Select Configurations dialog. Debug, release, or both build configurations availability can be selected here.

  5. Click on the Finish button.

After that you get a template C++ console project with the source files placed at the src subdirectory of the project directory. Now you see the Eclipse IDE window as shown in the following screenshot:

The Project Explorer panel is placed at the left-hand side of the window. You can find all the project source files here. The source file editor is placed in the middle part of the window. You can find the messages' output panel at the bottom of the window.

Select Project | Build Project from the main menu to build our example application. After that the executable file will be created in the Debug subdirectory of the project directory. You can switch to the release configuration to build the project. Click on the build icon (hammer icon) at the main menu and select Release configuration to build. The Release subdirectory will be created with the compiled executable file.

Select Run | Run from the main menu or press Ctrl + F11 to launch our example application. You will see the result of the application execution in the console output panel at the bottom of the Eclipse window.

You can debug applications with the Eclipse IDE system. Press Ctrl + Shift + B key to set the breakpoint at the current line of a source file. After setting the breakpoints select Run | Debug from the main menu or press the F11 key to start debugging. You will see panels with call-stack, variable values, CPU registers values, breakpoints, and loaded modules in the debugging mode. Use the Step Over (F6) and Step Into (F5) Run submenu items to continue application execution.