Preparing Boost libraries for the MinGW compiler

Before we go through to program our C++ application by using Boost libraries, the libraries need to be configured in order to be recognized by MinGW compiler. Here, we are going to prepare our programming environment so that our compiler is able use Boost libraries.

Downloading Boost libraries

The best source from which to download Boost is the official download page. We can go there by pointing our internet browser to www.boost.org/users/download. Find the Download link in Current Release section. At the time of writing, the current version of Boost libraries is 1.58.0, but when you read this book, the version may have changed. If so, you can still choose the current release because the higher version must be compatible with the lower. However, you have to adjust as we're going to talk about the setting later. Otherwise, choosing the same version will make it easy for you to follow all the instructions in this book.

There are four file formats to be choose from for download; they are .zip, .tar.gz, .tar.bz2, and .7z. There is no difference among the four files but their file size. The largest file size is of the ZIP format and the lowest is that of the 7Z format. Because of the file size, Boost recommends that we download the 7Z format. See the following image for comparison:

Downloading Boost libraries

From the preceding image, we can see the size of ZIP version is 123.1 MB while the size of the 7Z version is 65.2 MB. It means that the size of the ZIP version is almost twice that of the 7Z version. Therefore, they suggest that you choose the 7Z format to reduce download and decompression time. Let us choose boost_1_58_0.7z to be downloaded and save it to our local storage.

Deploying Boost libraries

After we have got boost_1_58_0.7z in our local storage, decompress it using the 7ZIP application and save the decompression files to C:oost_1_58_0.

Note

The 7ZIP application can be grabbed from www.7-zip.org/download.html.

The directory then should contain file structures as follows:

Deploying Boost libraries

Note

Instead of browsing to the Boost download page and searching for the Boost version manually, we can go directly to sourceforge.net/projects/boost/files/boost/1.58.0. It will be useful when the 1.58.0 version is no longer the current release.

Using Boost libraries

Most libraries in Boost are header-only; this means that all declarations and definitions of functions, including namespaces and macros, are visible to the compiler and there is no need to compile them separately. We can now try to use Boost with the program to convert the string into int value as follows:

/* lexical.cpp */
#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>

int main(void) {
  try 	{
    std::string str;
    std::cout << "Please input first number: ";
    std::cin >> str;
    int n1 = boost::lexical_cast<int>(str);
    std::cout << "Please input second number: ";
    std::cin >> str;
    int n2 = boost::lexical_cast<int>(str);
    std::cout << "The sum of the two numbers is ";
    std::cout << n1 + n2 << "
";
    return 0;
  }
  catch (const boost::bad_lexical_cast &e) {
    std::cerr << e.what() << "
";
    return 1;
  }
}

Open the Notepad++ application, type the preceding code, and save it as lexical.cpp in C:CPP—the directory we had created in Chapter 1, Simplifying Your Network Programming in C++. Now open the command prompt, point the active directory to C:CPP, and then type the following command:

g++ -Wall -ansi lexical.cpp –Ic:oost_1_58_0 -o lexical

We have a new option here, which is –I (the "include" option). This option is used along with the full path of the directory to inform the compiler that we have another header directory that we want to include to our code. Since we store our Boost libraries in c: boost_1_58_0, we can use –Ic:oost_1_58_0 as an additional parameter.

In lexical.cpp, we apply boost::lexical_cast to convert string type data into int type data. The program will ask the user to input two numbers and will then automatically find the sum of both numbers. If a user inputs an inappropriate number, it will inform them that an error has occurred.

The Boost.LexicalCast library is provided by Boost for casting one data type to another (converting numeric types such as int, double, or floats into string types, and vice versa). Now, let us dissect lexical.cpp to for a more detailed understanding of what it does:

#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>

We include boost/lexical_cast.hpp in order to be able to invoke boost::lexical_cast function since the function is declared in lexical_cast.hpp. Also we use string header to apply std::string function as well as iostream header to apply std::cin, std::cout and std::cerr function.

Other functions, such as std::cin and std::cout, have been talked about in Chapter 1, Simplifying Your Network Programming in C++, and we saw what their functions are so we can skip those lines:

int n1 = boost::lexical_cast<int>(str);
int n2 = boost::lexical_cast<int>(str);

We used the preceding two separate lines to convert the user-provided input string into the int data type. Then, after converting the data type, we summed up both of the int values.

We can also see the try-catch block in the preceding code. It is used to catch the error if user inputs an inappropriate number, except 0 to 9.

catch (const boost::bad_lexical_cast &e)
{
  std::cerr << e.what() << "
";
  return 1;
}

The preceding code snippet will catch errors and inform the user what exactly the error message is by using boost::bad_lexical_cast. We call the e.what() function to obtain the string of the error message.

Now let us run the application by typing lexical at the command prompt. We will get output like the following:

Using Boost libraries

I put 10 for first input and 20 for the second input. The result is 30 because it just sums up both input. But what will happen if I put in a non-numerical value, for instance Packt. Here is the output to try that condition:

Using Boost libraries

Once the application found the error, it will ignore the next statement and go directly to the catch block. By using the e.what() function, the application can get the error message and show it to the user. In our example, we obtain bad lexical cast: source type value could not be interpreted as target as the error message because we try to assign the string data to int type variable.

Building Boost libraries

As we discussed previously, most libraries in Boost are header-only, but not all of them. There are some libraries that have to be built separately. They are:

  • Boost.Chrono: This is used to show the variety of clocks, such as current time, the range between two times, or calculating the time passed in the process.
  • Boost.Context: This is used to create higher-level abstractions, such as coroutines and cooperative threads.
  • Boost.Filesystem: This is used to deal with files and directories, such as obtaining the file path or checking whether a file or directory exists.
  • Boost.GraphParallel: This is an extension to the Boost Graph Library (BGL) for parallel and distributed computing.
  • Boost.IOStreams: This is used to write and read data using stream. For instance, it loads the content of a file to memory or writes compressed data in GZIP format.
  • Boost.Locale: This is used to localize the application, in other words, translate the application interface to user's language.
  • Boost.MPI: This is used to develop a program that executes tasks concurrently. MPI itself stands for Message Passing Interface.
  • Boost.ProgramOptions: This is used to parse command-line options. Instead of using the argv variable in the main parameter, it uses double minus (--) to separate each command-line option.
  • Boost.Python: This is used to parse Python language in C++ code.
  • Boost.Regex: This is used to apply regular expression in our code. But if our development supports C++11, we do not depend on the Boost.Regex library anymore since it is available in the regex header file.
  • Boost.Serialization: This is used to convert objects into a series of bytes that can be saved and then restored again into the same object.
  • Boost.Signals: This is used to create signals. The signal will trigger an event to run a function on it.
  • Boost.System: This is used to define errors. It contains four classes: system::error_code, system::error_category, system::error_condition, and system::system_error. All of these classes are inside the boost namespace. It is also supported in the C++11 environment, but because many Boost libraries use Boost.System, it is necessary to keep including Boost.System.
  • Boost.Thread: This is used to apply threading programming. It provides classes to synchronize access on multiple-thread data. In C++11 environments, the Boost.Thread library offers extensions, so we can interrupt thread in Boost.Thread.
  • Boost.Timer: This is used to measure the code performance by using clocks. It measures time passed based on usual clock and CPU time, which states how much time has been spent to execute the code.
  • Boost.Wave: This provides a reusable C preprocessor that we can use in our C++ code.

There are also a few libraries that have optional, separately compiled binaries. They are as follows:

  • Boost.DateTime: It is used to process time data; for instance, calendar dates and time. It has a binary component that is only needed if we use to_string, from_string, or serialization features. It is also needed if we target our application in Visual C++ 6.x or Borland.
  • Boost.Graph: It is used to create two-dimensional graphics. It has a binary component that is only needed if we intend to parse GraphViz files.
  • Boost.Math: It is used to deal with mathematical formulas. It has binary components for cmath functions.
  • Boost.Random: It is used to generate random numbers. It has a binary component, which is only needed if we want to use random_device.
  • Boost.Test: It is used to write and organize test programs and their runtime execution. It can be used in header-only or separately compiled mode, but separate compilation is recommended for serious use.
  • Boost.Exception: It is used to add data to an exception after it has been thrown. It provides non-intrusive implementation of exception_ptr for 32-bit _MSC_VER==1310 and _MSC_VER==1400, which requires a separately compiled binary. This is enabled by #define BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR.

Let us try to recreate the random number generator program we created in Chapter 1, Simplifying Your Network Programming in C++. But now we will use the Boost.Random library instead of std::rand() from the C++ standard function. Let us take a look at the following code:

/* rangen_boost.cpp */
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <iostream>

int main(void) {
  int guessNumber;
  std::cout << "Select number among 0 to 10: ";
  std::cin >> guessNumber;
  if(guessNumber < 0 || guessNumber > 10) {
    return 1;
  }
  boost::random::mt19937 rng;
  boost::random::uniform_int_distribution<> ten(0,10);
  int randomNumber = ten(rng);
  if(guessNumber == randomNumber) {
    std::cout << "Congratulation, " << guessNumber << " is your lucky number.
";
  }
  else {
    std::cout << "Sorry, I'm thinking about number " << randomNumber << "
"; 
  }
  return 0;
}

We can compile the preceding source code by using the following command:

g++ -Wall -ansi -Ic:/boost_1_58_0 rangen_boost.cpp -o rangen_boost

Now, let us run the program. Unfortunately, for the three times that I ran the program, I always obtained the same random number as follows:

Building Boost libraries

As we can see from this example, we always get number 8. This is because we apply Mersenne Twister, a Pseudorandom Number Generator (PRNG), which uses the default seed as a source of randomness so it will generate the same number every time the program is run. And, of course, it is not the program that we expect.

Now, we will rework the program once again, just in two lines. First, find the following line:

#include <boost/random/mersenne_twister.hpp>

Change it as follows:

#include <boost/random/random_device.hpp>

Next, find the following line:

boost::random::mt19937 rng;

Change it as follows:

boost::random::random_device rng;

Then, save the file as rangen2_boost.cpp and compile the rangen2_boost.cpp file by using the command like we compiled rangen_boost.cpp. The command will look like this:

g++ -Wall -ansi -Ic:/boost_1_58_0 rangen2_boost.cpp -o rangen2_boost

Sadly, there will be something wrong and the compiler will show the following error message:

cc8KWVvX.o:rangen2_boost.cpp:(.text$_ZN5boost6random6detail20generate_uniform_intINS0_13random_deviceEjEET0_RT_S4_S4_N4mpl_5bool_ILb1EEE[_ZN5boost6random6detail20generate_uniform_intINS0_13random_deviceEjEET0_RT_S4_S4_N4mpl_5bool_ILb1EEE]+0x24f): more undefined references to boost::random::random_device::operator()()' follow
collect2.exe: error: ld returned 1 exit status

This is because, as we saw earlier, the Boost.Random library needs to be compiled separately if we want to use the random_device attribute.

Boost libraries have a system to compile or build Boost itself, called Boost.Build library. There are two steps we have to achieve to install the Boost.Build library. First, run Bootstrap by pointing the active directory at the command prompt to C:oost_1_58_0 and typing the following command:

bootstrap.bat mingw

We use our MinGW compiler we had installed in Chapter 1, Simplifying Your Network Programming in C++, as our toolset in compiling the Boost library. Wait a second and then we will get the following output if the process is a success:

Building Boost.Build engine

Bootstrapping is done. To build, run:

    .2

To adjust configuration, edit 'project-config.jam'.
Further information:

    - Command line help:
    .2 --help

    - Getting started guide:
    http://boost.org/more/getting_started/windows.html

    - Boost.Build documentation:
    http://www.boost.org/build/doc/html/index.html

In this step, we will find four new files in the Boost library's root directory. They are:

  • b2.exe: This is an executable file to build Boost libraries
  • bjam.exe: This is exactly the same as b2.exe but it is a legacy version
  • bootstrap.log: This contains logs from the bootstrap process
  • project-config.jam: This contains a setting that will be used in the building process when we run b2.exe

We also find that this step creates a new directory in C:oost_1_58_0 oolsuildsrcenginein.ntx86 , which contains a bunch of .obj files associated with Boost libraries that needed to be compiled.

After that, run the second step by typing the following command at the command prompt:

b2 install toolset=gcc

Grab yourself a cup of coffee after running that command because it will take about twenty to fifty minutes to finish the process, depending on your system specifications. The last output we will get will be as follows:

...updated 12562 targets...

This means that the process is complete and we have now built the Boost libraries. If we check in our explorer, the Boost.Build library adds C:oost_1_58_0stagelib, which contains a collection of static and dynamic libraries that we can use directly in our program.

Note

bootstrap.bat and b2.exe use msvc (Microsoft Visual C++ compiler) as the default toolset, and many Windows developers already have msvc installed on their machines. Since we have installed the GCC compiler, we set the mingw and gcc toolset options in Boost's build. If you also have mvsc installed and want to use it in Boost's build, the toolset options can be omitted.

Now, let us try to compile the rangen2_boost.cpp file again, but now with the following command:

c:CPP>g++ -Wall -ansi -Ic:/boost_1_58_0 rangen2_boost.cpp -Lc:oost_1_58_0stagelib -lboost_random-mgw49-mt-1_58 -lboost_system-mgw49-mt-1_58 -o rangen2_boost

We have two new options here, they are –L and –l. The -L option is used to define the path that contains the library file if it is not in the active directory. The –l option is used to define the name of library file but omitting the first lib word in front of the file name. In this case, the original library file name is libboost_random-mgw49-mt-1_58.a, and we omit the lib phrase and the file extension for option -l.

The new file called rangen2_boost.exe will be created in C:CPP. But before we can run the program, we have to ensure that the directory that the program installed has contained two library files which the program is dependent on. These are libboost_random-mgw49-mt-1_58.dll and libboost_system-mgw49-mt-1_58.dll, and we can get them from the library directory c:oost_1_58_0_1stagelib.

Just to make it easy for us to run that program, run the following copy command to copy the two library files to C:CPP:

copy c:oost_1_58_0_1stageliblibboost_random-mgw49-mt-1_58.dll c:cpp
copy c:oost_1_58_0_1stageliblibboost_system-mgw49-mt-1_58.dll c:cpp

And now the program should run smoothly.

In order to create a network application, we are going to use the Boost.Asio library. We do not find Boost.Asio—the library that we are going to use to create a network application—in the non-header-only library. It seems that we do not need to build the Boost library since Boost.Asio is header-only library. This is true, but since Boost.Asio depends on Boost.System and Boost.System needs to be built before being used, it is important to build Boost first before we can use it to create our network application.

Tip

For option –I and –L, the compiler does not care if we use backslash () or slash (/) to separate each directory name in the path because the compiler can handle both Windows and Unix path styles.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset