Showing posts with label Boost. Show all posts
Showing posts with label Boost. Show all posts

Wednesday, 19 February 2020

How to install and use Boost C++ Libraries in CMake project on Ubuntu



Download Boost archive from Version 1.72.0 (that is the current version at the time of writing).

Go to the directory where you want to install Boost:

$ cd ~/dev

Unpack the downloaded archive (tar will create boost_1_72_0 directory):

$ tar --bzip2 -xf ~/Downloads/boost_1_72_0.tar.bz2 
$ ls
boost_1_72_0  github  gnome  go  ssh-keys  vm  vm-shared

Let's see the content of ~/dev/boost_1_72_0/:

~/dev/boost_1_72_0$ ls -A1
boost
boost-build.jam
boostcpp.jam
boost.css
boost.png
bootstrap.bat
bootstrap.sh
doc
index.htm
index.html
INSTALL
Jamroot
libs
LICENSE_1_0.txt
more
README.md
rst.css
status
tools


Let's see the content of ~/dev/boost_1_72_0/boost/:

~/dev/boost_1_72_0/boost$ ls -A1
accumulators
algorithm
align
aligned_storage.hpp
align.hpp
any.hpp
archive
array.hpp
asio
asio.hpp
assert.hpp
assign
assign.hpp
atomic
atomic.hpp
beast
beast.hpp
...

lambda
...


Many Boost libraries are header-only which means we don't need to build them, it is only necessary to add relevant header in the source code and path to it to compiler (-I) options.

Boost documentation page Getting Started on Unix Variants contains a short demo code and I'm gonna use it here. It uses boost/lambda/lambda.hpp header from so let's see the content of ~/dev/boost_1_72_0/boost/lambda/ to confirm it's there:


~/dev/boost_1_72_0/boost/lambda$ ls -A1
algorithm.hpp
bind.hpp
casts.hpp
closures.hpp
construct.hpp
control_structures.hpp
core.hpp
detail
exceptions.hpp
if.hpp
lambda.hpp
loops.hpp
numeric.hpp
switch.hpp

Let's create a project in VSCode with following structure:

.vscode/tasks.json
build/
src/main.cpp
.gitignore
CMakeLists.txt


.vscode/tasks.json:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "type": "shell",
            "label": "CMake && make",
            "options": {
                "cwd": "${workspaceFolder}/build"
            },
            "command": "cmake make -DCMAKE_BUILD_TYPE=Debug .. && make -j 4",
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}


src/main.cpp:

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
    std::cout << "main()" << std::endl;

    using namespace boost::lambda;
    typedef std::istream_iterator<int> in;
    std::for_each(in(std::cin), in(), std::cout << (_1 * 3) << " " );

    return 0;
}


CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)
project(boost-demo)
set(SOURCE src/main.cpp)
set(BOOST_ROOT "$HOME/dev/boost_1_72_0")
include_directories(include)
add_executable(${PROJECT_NAME} ${SOURCE})


Press CTRL+SHIFT+B in order to trigger building the project:


> Executing task: cmake make -DCMAKE_BUILD_TYPE=Debug .. && make -j 4 <

-- Configuring done
-- Generating done
-- Build files have been written to: /home/bojan/dev/github/boost-demo/build
Scanning dependencies of target boost-demo
[ 50%] Building CXX object CMakeFiles/boost-demo.dir/src/main.cpp.o
[100%] Linking CXX executable boost-demo
[100%] Built target boost-demo

Terminal will be reused by tasks, press any key to close it.


The output is an executable which we can run now:


~/dev/github/boost-demo$ ./build/boost-demo 
main()
1
3 2
6 3
9 4
12 7
21 ^C


The example above shows how it's simple to include Boost headers in C++ CMake project.

For some Boost features, we need to compile and install certain Boost libraries.


How to compile and install Boost binaries?



~/dev/boost_1_72_0$ ./bootstrap.sh --help
`./bootstrap.sh' prepares Boost for building on a few kinds of systems.

Usage: ./bootstrap.sh [OPTION]... 

Defaults for the options are specified in brackets.

Configuration:
  -h, --help                display this help and exit
  --with-bjam=BJAM          use existing Boost.Jam executable (bjam)
                            [automatically built]
  --with-toolset=TOOLSET    use specific Boost.Build toolset
                            [automatically detected]
  --show-libraries          show the set of libraries that require build
                            and installation steps (i.e., those libraries
                            that can be used with --with-libraries or
                            --without-libraries), then exit
  --with-libraries=list     build only a particular set of libraries,
                            describing using either a comma-separated list of
                            library names or "all"
                            [all]
  --without-libraries=list  build all libraries except the ones listed []
  --with-icu                enable Unicode/ICU support in Regex 
                            [automatically detected]
  --without-icu             disable Unicode/ICU support in Regex
  --with-icu=DIR            specify the root of the ICU library installation
                            and enable Unicode/ICU support in Regex
                            [automatically detected]
  --with-python=PYTHON      specify the Python executable [python]
  --with-python-root=DIR    specify the root of the Python installation
                            [automatically detected]
  --with-python-version=X.Y specify the Python version as X.Y
                            [automatically detected]

Installation directories:
  --prefix=PREFIX           install Boost into the given PREFIX
                            [/usr/local]
  --exec-prefix=EPREFIX     install Boost binaries into the given EPREFIX
                            [PREFIX]

More precise control over installation directories:
  --libdir=DIR              install libraries here [EPREFIX/lib]
  --includedir=DIR          install headers here [PREFIX/include]


To Be Continued...


References:



Monday, 30 April 2012

pImpl Idiom

If class A has an instance of class B as its member, A.h must include B.h:

A.h:


A's client must include A.h either in its header or in a source file:

clientA.h:


clientA.cpp:



By including A.h, clientA.cpp has implicitly included B.h as well thus creating dependency between clientA and B. clientA now knows about B but it should know only about A. B is a part of the A's implementation which should be hidden from clientA. If anything changes in B.h, it is not just A that has to be recompiled but testA as well. We want to break this compiler dependency.

The most common way to achieve this is through breaking up class A into two parts: publicly accessible shell class, with public interface and minimal dependency on other headers and private implementation class, which depends on other headers. For this Private IMPLementation moment, this idiom got its name - PIMPL. (Or because shell class contains Pointer to IMPLementation class - see the next paragraph.)

Class A declaration contains forward declaration of implementation class (AImpl) and pointer to it, both of which are private. RAII semantics is achieved by using boost::scoped_ptr (std::unique_ptr could have been used as well).

B.h:


B.cpp:


A.h:


A.cpp:


main.cpp:


Output:
A::A()
AImpl::AImpl()
A::foo()
AImpl::foo(). n = 3
AImpl::foo(). res = 1
A::~A()
AImpl::~AImpl()

If we decide to change B's interface, e.g. divide() to return type double instead of int, we just need to recompile unit A but not clientA:

B.h:


B.cpp:


A.cpp:


Output:
A::A()
AImpl::AImpl()
A::foo()
AImpl::foo(). n = 3
AImpl::foo(). res = 1.5
A::~A()
AImpl::~AImpl()

References:
Pointer To Implementation (pImpl)
GotW #100: Compilation Firewalls
Pimpl Idiom
Private class data pattern (Wikipedia)
Opaque pointer (Wikipedia)
pimpl idiom vs. bridge design pattern (SO)
pimpl: shared_ptr or unique_ptr (SO)
std::auto_ptr or boost::shared_ptr for pImpl idiom? (SO)
Private members in pimpl class? (SO)


Friday, 20 April 2012

JSON Data Binding with JSON Spirit

JSON is, like XML, a human readable, text-based format for data representation.

JSON document represents either object or an array.

Object starts and ends with curly brackets ({ }) and contains zero or more key-value pairs. Key (or name) is a string and value can be another object, number, string, array or literal true, false or null. Key is separated from value with a single colon (:). Key-value pars are separated with commas (,).

Array starts and ends with square brackets ([ ]) and contains zero or more values.

I wrote a mini series of articles on XML Data Binding and in this article I want to show how to serialize C++ object to JSON document and how to perform reverse process - how to deserialize JSON document back to the object.

JSON parser I am using here is JSON Spirit. Here is the list of steps of how to get working example from the scratch:

  1. Download and unpack master from http://gitorious.org/json-spirit/json-spirit/trees/master
  2. Find and open provided Visual Studio solution file (convert it to VS2010 format if necessary). It contains projects: json_demo, json_headers_only_demo, json_map_demo, json_spirit_lib and json_test.
  3. We will create test project that will be using JSON Spirit static library and its headers (Boost headers will be necessary as well). Build json_spirit_lib project which output is static library named json_spirit_lib.lib.
  4. In Project Settings for our test project, add json_spirit_lib.lib to Additional Dependencies as well as path to JSON Spirit headers (path to json_spirit directory) and path to Boost.
  5. Use main.cpp provided below which contains couple of functions that demonstrate JSON/C++ serialization/deserialization:
main.cpp:


Output:
Serialization result (generated JSON string):

{
   "name" : "Fyodor",
   "surName" : "Dostoyevsky"
}

Deserialization result:

name: Fyodor
surName: Dostoyevsky

Serialization result (generated JSON string):

{
   "author" : {
      "name" : "Fyodor",
      "surName" : "Dostoyevsky"
   },
   "isbn" : 123456789,
   "title" : "Crime and Punishment",
   "type" : 1
}

Deserialization result:

author name: Fyodor
author surName: Dostoyevsky
isbn: 123456789
title: Crime and Punishment
type: 1


Links and References:
The application/json Media Type for JavaScript Object Notation (JSON) - RFC 4627
Can a JSON start with [? (SO)