Friday, April 26, 2013

I Can Do It Better...

At work I have to deal with QtCreator and building it from source. Please keep in mind this was Qt 2.5.0 that I was dealing with; so things may have changed. When looking through the code I was baffled by their design motivations. I guess given that it's an open source project the design is probably more of an afterthought. The goal of the project was simple, use their "model" to store QML so that we could use it in something that could run physical hardware. QML is an excellent language because of its declarative syntax it makes a world of sense to use when writing software that needs to map information onto hardware.

The more I dug my heels into the code the more I loathed it. Despised it. I thought, "What in the hell are you guys doing?!" There were even times that I ventured onto the message boards to attempt to get answers only to be ignored. I can't imagine why.

The final conclusion that was made at the time was that the Designer plugin didn't offer everything we needed to write our hardware descriptions. Extending the QML via plugins or static Declarative Item's was not going to work either because at the time (2.5.0) it was impossible for the QML Designer to display custom C++ Declarative Items. The only viable solution was to write a front end ourselves. Thus stating clearly, "I can do it better."

The only piece of QtCreator I borrowed was the QmlJS library which contains code that can parse QML Documents ( I definitely did not want to rewrite this! ). What does all of this have to do with Boost? In summary, the performance of my custom Model was not very good. It lags when trying to enter a couple hundred items. The underlying data structure I used was a sorted vector because I felt it gave me the best performance when looking up items. Find functionality was key to the model and an efficient solution would mean that the Model should be efficient. Sorted vector lookups take O(log n) time; if using equal_range the insertion takes O(log n).

The sorted vector isn't working. Today I'd like to demonstrate how to replace the sorted std::vector with a boost::unordered_map then remark about what the difference in performance feels like- it could be nothing at all. In order to provide a comparison I'm going to use C-style macro definitions to optionally enable the unordered map:

#define USE_UNORDERED

Let's say that my model looks like this:

struct Item
{
    std::string id;
    std::string description;
};


bool ModelComparator( boost::shared_ptr<Item> lhs
                    , boost::shared_ptr<Item> rhs )
{
    return (lhs->id < rhs->id);
}


class Model : public boost::noncopyable
{
    public:

        typedef std::vector<boost::shared_ptr<Item> > ItemsContainer;
        typedef ItemsContainer::iterator ItemsIterator;
        typedef std::pair<ItemsIterator, ItemsIterator> ItemRange;


    public:
        Model() { }
        void AddItem(boost::shared_ptr<Item> item)
        {
            ItemIterator begin;
            ItemIterator end;
            Find( item->id, begin, end );
            this->items.insert(end, item);
        }

        boost::shared_ptr<Item> Get(std::string const& itemKey)
        {
            ItemIterator begin;
            ItemIterator end;
            Find( itemKey, begin, end );
            return *begin;
        }

        ItemsContainer const& GetContainer() const
        {
            return this->items;
        }

    private:
        ItemsContainer items;


    private:

        /**
         * The key method in this model for performing O(log n) lookups
         * using equal_range.
         */
        void Find( std::string const& id
                 , ItemsIterator& begin
                 , ItemsIterator& end )
        {
            if (this->items.empty()) 
            {
                begin = this->items.begin();
                end = this->items.end();
            }
            else
            {
                 boost::shared_ptr<Item> item(new Item());
                 item->id = id;
                 ItemRange range = std::equal_range( this->items.begin()
                                                   , this->items.end()
                                                   , item
                                                   , ModelComparator );
            }
        }
};


This is the original code to perform lookups. I even threw in a general "GetContainer" method because this might throw a wrench into what we are trying to accomplish. The first task we have is to set up boost::hash and std::equal_to template specializations [1]:

#if defined USE_UNORDERED

namespace std
{

template <>
struct equal_to 
{
    bool operator()( boost::shared_ptr<Item> const& lhs
                   , boost::shared_ptr<Item> const& rhs) const
    {
        return (lhs->id == rhs->id);
    }
};

} // End of std.

namespace boost
{

template <>
struct hash 
{
    size_t operator()(boost::shared_ptr<Item> const& item) const
    {
        // Just use the boost::hash with a string, because that's what we 
        // need.
        return boost::hash<std::string>(item->id)
    }
};

} // End of boost.

#endif

That sets up the basic hashing mechanism for the items. Now the class member also needs to be redefined if we are using USE_UNORDERED:



        typedef std::vector<boost::shared_ptr<Item> > ItemsContainer;

becomes

#if defined USE_UNORDERED
        typedef boost::unordered_set<boost::shared_ptr<Item> > ItemsContainer;
#else
        typedef std::vector<boost::shared_ptr<Item> > ItemsContainer;
#endif



That's simple enough. Note that the example will fail now because the Add/Get methods do not work with equal_range. Let's fix that by modifying the Add operation:


        void AddItem(boost::shared_ptr<Item> item)
        {
            ItemIterator begin;
            ItemIterator end;
            Find( item->id, begin, end );
            this->items.insert(end, item);
        }

becomes:

        void AddItem(boost::shared_ptr<Item> item)
        {
#if defined USE_UNORDERED
            this->items.insert(item);
#else
            ItemIterator begin;
            ItemIterator end;
            Find( item->id, begin, end );
            this->items.insert(end, item);
#endif
        }


Notice that the code for unordered_set is much simpler and easier to read. The macros are doing a great job in making the code unreadable; my advice is to take them out once you've proven/disproven there is a performance increase. The second to last item is the Get operation:

        boost::shared_ptr<Item> Get(std::string const& itemKey)
        {
            ItemIterator begin;
            ItemIterator end;
            Find( itemKey, begin, end );
            return *begin;
        }

becomes:

        boost::shared_ptr<Item> Get(std::string const& itemKey)
        {
#if defined USE_UNORDERED
            boost::unordered_set<boost::shared_ptr>::iterator iter = 
                this->items.find(itemKey);
#else
            ItemIterator begin;
            ItemIterator end;
            Find( itemKey, begin, end );
            return *begin;
#endif
        }

The last part of the example that needs modification is the GetContainer() method. There are two solutions for refactoring the GetContainer() method:

1) Leave it alone and fix compiler errors. Just replace use of operator[] with equivalent iterator operations. This is the solution I used at work because the second solution while probably being more correct would have required more refactoring.

2) Replace GetContainer() with begin() and end() methods that return iterators to the underlying container. This is the preferable solution! However it requires more work. It's a much more CPlusPlusee solution. 

I'd like to say that the story above resulted in a happy ending and that after all of the refactoring the code was so fast that there were no hiccups. The good news is that it made the model MUCH faster; but the bad news was that it wasn't as fast as it needed to be. There are always other opportunities for optimization! Also please remember if you find the better solution get rid of the macros! Here is the final code from above:


#define USE_UNORDERED

struct Item
{
    std::string id;
    std::string description;
};



namespace std
{

template <>
struct equal_to 
{
    bool operator()( boost::shared_ptr<Item> const& lhs
                   , boost::shared_ptr<Item> const& rhs) const
    {
        return (lhs->id == rhs->id);
    }
};

} // End of std.

namespace boost
{

template <>
struct hash 
{
    size_t operator()(boost::shared_ptr<Item> const& item) const
    {
        // Just use the boost::hash with a string, because that's what we 
        // need.
        return boost::hash<std::string>(item->id)
    }
};

} // End of boost.

#endif


bool ModelComparator( boost::shared_ptr<Item> lhs
                    , boost::shared_ptr<Item> rhs )
{
    return (lhs->id < rhs->id);
}


class Model : public boost::noncopyable
{
    public:

#if defined USE_UNORDERED
        typedef boost::unordered_set<boost::shared_ptr<Item> > ItemsContainer;
#else
        typedef std::vector<boost::shared_ptr<Item> > ItemsContainer;
#endif
        typedef ItemsContainer::iterator ItemsIterator;
        typedef std::pair<ItemsIterator, ItemsIterator> ItemRange;


    public:
        Model() { }


        void AddItem(boost::shared_ptr<Item> item)
        {
#if defined USE_UNORDERED
            this->items.insert(item);
#else
            ItemIterator begin;
            ItemIterator end;
            Find( item->id, begin, end );
            this->items.insert(end, item);
#endif
        }



        boost::shared_ptr<Item> Get(std::string const& itemKey)
        {
#if defined USE_UNORDERED
            boost::unordered_set<boost::shared_ptr>::iterator iter = 
                this->items.find(itemKey);
#else
            ItemIterator begin;
            ItemIterator end;
            Find( itemKey, begin, end );
            return *begin;
#endif


        ItemsContainer const& GetContainer() const
        {
            return this->items;
        }

    private:

#if defined USE_UNORDERED
        typedef boost::unordered_set<boost::shared_ptr<Item> > ItemsContainer;
#else
        typedef std::vector<boost::shared_ptr<Item> > ItemsContainer;
#endif




    private:

#if !defined USE_UNORDERED        /**
         * The key method in this model for performing O(log n) lookups
         * using equal_range.
         */
        void Find( std::string const& id
                 , ItemsIterator& begin
                 , ItemsIterator& end )
        {
            if (this->items.empty()) 
            {
                begin = this->items.begin();
                end = this->items.end();
            }
            else
            {
                 boost::shared_ptr<Item> item(new Item());
                 item->id = id;
                 ItemRange range = std::equal_range( this->items.begin()
                                                   , this->items.end()
                                                   , item
                                                   , ModelComparator );
            }
        }
#endif

};



References
[1] - http://jrscppboostnotes.blogspot.com/2013/04/unordered-set.html


Wednesday, April 24, 2013

Unordered Set

The first container in Boost I want to take a look at is unordered_set [1]. The unordered_map is also very similar. In either case the goal is simple: put together an unordered_set that contains classes other than strings. 

Let's start by creating a main function (complete with includes for using unordered_set):

// boost dependencies
#include <boost/unordered_set.hpp>

// std dependencies
#include <string>

/**
 * A class that has a couple of members, just a simple number
 * and string. In a real world class you would probably put 
 * more "stuff" in here. 
 */
class Item
{
    public:
        Item(int importanceIn, std::string const& descriptionIn)
        : importance(importanceIn)
        , description(descriptionIn)
        {
        }

        int importance;
        std::string description;
};

std::ostream& operator<<(std::ostream& out, Item const& i)
{
    out << "ITEM(" << i.importance << "," << i.description << ");
    return out;
}

int main(int argc, char** argv)
{
    boost::unordered_set<Item> items;
    return 0;
}

Before you type all of this in, know that the example will NOT compile as it is! The reason it will not compile should be apparent in the definition of unordered set [1]:

namespace boost {
template <
class Key,
class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class unordered_set;

The second template argument to the unordered_set is assumed to be boost::hash<Item> in our case. Currently that specialization doesn't exist. Therefore we must provide a specialization to appease our compiler. To specialize, simply refer to the original template definition of boost::hash [2]. Our specialization is simply going to use the "importance" member variable as our hash value:

namespace boost
{

template <>
struct hash<Item>
{
    std::size_t operator()(Item const& item) const
    {
        // SHOULD USE boost::numeric_cast INSTEAD!
        return static_cast<size_t>(item.importance);
    }
};

}

This will please our compiler; but it's not the last of our problems! Currently we still do not have a specialization for std::equal_to [3]:

namespace std //< You aren't supposed to do this!
{

template <> 
struct equal_to<Item>
{
    bool operator()(Item const& lhs, Item const& rhs) const
    {
        return (lhs.importance == rhs.importance) && (lhs.description == rhs.description);
    }
};

}

Because we added an equal_to specialization we must also include <functional>. Our implementation now looks like this:

// boost dependencies
#include <boost/unordered_set.hpp>

// std dependencies
#include <functional>
#include <iostream>
#include <ostream>
#include <string>

/**
 * A class that has a couple of members, just a simple number
 * and string. In a real world class you would probably put 
 * more "stuff" in here. 
 */
class Item
{
    public:
        Item(int importanceIn, std::string const& descriptionIn)
        : importance(importanceIn)
        , description(descriptionIn)
        {
        }

        int importance;
        std::string description;
};

std::ostream& operator<<(std::ostream& out, Item const& i)
{
    out << "ITEM(" << i.importance << "," << i.description << ");
    return out;
}

//-----------------------------
// Our Specialization for Hash!
//-----------------------------
namespace boost
{

template <>
struct hash<Item>
{
    std::size_t operator()(Item const& item) const
    {
        // SHOULD USE boost::numeric_cast INSTEAD!
        return static_cast<size_t>(item.importance);
    }
};

}

//---------------------------------
// Our Specialization for equal_to!
//---------------------------------
namespace std //< You aren't supposed to do this!
{

template <> 
struct equal_to<Item>
{
    bool operator()(Item const& lhs, Item const& rhs) const
    {
        return (lhs.importance == rhs.importance) && (lhs.description == rhs.description);
    }
};

}


int main(int argc, char** argv)
{
    typedef boost::unordered_set<Item> ItemsContainer;
    typedef ItemsContainer::iterator Iterator;

    ItemsContainer items;

    items.insert(Item(5, "Fiver"));
    items.insert(Item(15, "Fifteen"));
    items.insert(Item(15, "Second Fifteen!"));        

    for(Iterator iter=items.begin(); iter != items.end(); ++iter)
    {
        std::cout << *iter << std::endl;
    }

    return 0;
}

I found the use of boost::unordered_set really simple and easy! I think what I like the best about this is that it is a header only class; this means we don't need to do any linking to use! All that the developer has to do is implement their own boost::hash and std::equal_to and they are good to go. I hope later classes are as easy to use. The full listing of unordered_set is at [4].

References 





Library Naming

One of the things I find the most confusing about the Boost libraries is the naming convention. Boost libraries can have a strict naming convention. To get an idea of what I'm talking about go to the Boost libraries location on your system (keep in mind today I'm working with Visual Studio in Windows). If you look at the directory, you might see:

boost_bzip2-vc80-mt.lib
boost_bzip2-vc80-mt-1_45.dll
boost_bzip2-vc80-mt-1_45.lib
boost_bzip2-vc80-mt-gd.lib
boost_bzip2-vc80-mt-gd-1_45.dll

boost_bzip2-vc80-mt-gd-1_45.lib
boost_bzip2-vc90-mt.lib
boost_bzip2-vc90-mt-1_45.dll
boost_bzip2-vc90-mt-1_45.lib
boost_bzip2-vc90-mt-gd.lib
boost_bzip2-vc90-mt-gd-1_45.dll

boost_bzip2-vc90-mt-gd-1_45.lib
boost_bzip2-vc100-mt.lib
boost_bzip2-vc100-mt-1_45.dll
boost_bzip2-vc100-mt-1_45.lib
boost_bzip2-vc100-mt-gd.lib
boost_bzip2-vc100-mt-gd-1_45.dll

boost_bzip2-vc100-mt-gd-1_45.lib

And these are only the libraries regarding bzip2 functionality in Boost! It's an awful lot to take in. Two main questions arise: How do I dissect the filenames? What file do I link against?

How to Dissect File Names

First, look at the boost documentation. [1] This highlights the rules so I won't cover the name of the boost library.

Compiler Used
Example: vc80, vc90, vc100
Obviously the compiler used to build a project should match. If the developer is building an application using Visual Studio 2010 then the appropriate version of the library to use is vc100. 

MultiThreaded?
Example: mt
Should the library being used use the multi-threaded version. If you are wondering whether or not your project is being built with multithreaded support in Visual Studio do the following:
1) Right click on a project.
2) Select properties
3) Under C/C++ select Code Generation.
4) Take note of the Runtime Library flag, it will be /MD, /MT, /MTd, /MDd.

Interoperability Flag
Example: gd
Take a look at the table in the reference material [1]. For the example above you'll see that we reference gd in some of the libraries; this means that we are using the debug version of the runtime and a debug version of the project. This is also a great place to look for static library functionality. 

What file do I link against?

This is where I believe Boost does too much for the developer. Boost uses a feature called "Auto-Linking" in Windows [2]. Auto-linking uses "special code" to link the correct library into your project. This is at odds with the method in Linux which is simply to find the right library and link it. The inconsistency is a challenge when writing make generator tools such as premake4 because the premake4 files have to execute different code on Linux vs. Windows. At that point why do we even bother with cross-platform make tools?

There is hope for those writing cross-platform make tools; boost allows us to turn the Auto-linking feature off through defining "BOOST_ALL_NO_LIB" [3]. This is a pretty good solution and I'm not surprised it exists.

Conclusion

Linking libraries in Boost can be a mess and neater than anything. With the myriad of different configurations in the library binaries it's nice that the authors have provided a way to automatically link the dependencies on Windows. The messy part of linking in Boost occurs in Linux where we don't have the option to Auto-Link. In Linux we must pay attention to the configuration of the project we are building that uses Boost and choose the appropriate link targets using the dissected Boost library filenames.

References

[1] - http://www.boost.org/doc/libs/1_53_0/more/getting_started/windows.html#library-naming



[4] 



Monday, April 22, 2013

Boost.Build (Part 2)

For this post, I want to do something a little more practical. Anyone can sift through the boost examples on the website and post a rehash. I want to produce some original content because 1) rehashes aren't useful and 2) the boost examples sometimes are not appropriate.

The Goal: Put together a stub to build a Client/Server application where the Client/Server both use a library called Messages to implement a protocol. This post will not go into threading or asio. I only want to illustrate how to put together a project with multiple executables that relies on a single library.

Project Organization: I'm putting the client/server/messages into their own directories:

app
  client
    main.cpp
  server
    main.cpp
  messages
    messages.h
    messages.cpp

I'll create a container object in messages that contains all message objects in the system. That way I can grab the container from client or server and print the contents. This proves that the library gets linked:

File: messages.h
#include <boost/noncopyable.hpp>
#include <string>
#include <vector>

class Message : public boost::noncopyable
{
     protected:
         explicit Message(std::string const& id);

     public:
         virtual ~Message();
         std::string const& getId() const;

     private:
         std::string id;
};

class Messages : public boost::noncopyable
{
    public:
        typedef std::vector<Message*> MessagesContainer;
        typedef MessagesContainer::iterator Iterator;
        
        Messages();
        ~Messages();

        Iterator begin();
        Iterator end();

    private:
        MessagesContainer messages;        
};

File: messages.cpp

#include "messages.h"

Message::Message(std::string const& idIn) : id(idIn) { }
Message::~Message() { }
std::string const& Message::getId() const
{
    return this->id;
}

class Message1 : public Message 
{
    public:
        Message1() : Message("message1") { }
};

Messages::Messages() 
: messages() 

    this->messages.push_back(new Message1()); 
}

Messages::~Messages() { /* Add messages deletion */ }
Messages::Iterator Messages::begin() { return this->messages.begin(); }
Messages::Iterator Messages::end() { return this->messages.end(); }

File: main.cpp

/**
 * The main is just a simple test program that 
 * prints out the contents of the 
 * messages. We don't really do anything here.
 */
#include "messages/messages.h"
#include <algorithm>
#include <iostream>

void print(Message* const& message)
{
    std::cout << message->getId() << std::endl;
}

int main(int , char** )
{
    Messages m;
    std::for_each( m.begin(), m.end(), print );
    return 0;
}


Now comes the point of this post: where do we put the Jamfiles and Jamroot files? The first experiment I did was to simply build the messages library using Boost.Build:

File: messages/Jamroot
lib messages : messages.cpp : <include>.. ;

If you don't put the semicolon at the end, you'll get an error stating:
Jamroot:1: syntax error at EOF

Building the library is a great first step- but we need to build this as part of a larger project. Let's place a Jamroot at the root of the project that will in turn build the messages library:

File: Jamroot
build-project messages ;

NOTE: Make sure to put a space between messages and the semicolon! Boost.Build is unnecessarily picky about this for some reason! This call will of course build the project messages (which has its own Jamroot file!). Let's flesh the project out a bit more with the file to build the client and server stubs:

File: client/Jamroot
exe client : main.cpp ../messages//messages : <include>.. ;

File: server/Jamroot
exe server : main.cpp ../messages//messages : <include>.. ;

File: Jamroot (EDIT)

build-project messages ;
build-project client ;
build-project server ;


NOTE: Make sure there are no spaces between <include> and the ..- If there are spaces there will be vague errors! The last file modified in the root Jamroot since we want to build client and server. Notice that in the client/server Jamroot's, we have additional dependencies that we want to build (../messages//messages).

After building, this is what the directory structure will look like:


app/
  client/
    main.cpp
    Jamroot
    bin/
      gcc-4.7/
        debug/
          client (bin)
  server
    main.cpp
    Jamroot
    bin/
      gcc-4.7/
        debug/
          server (bin)
  messages
    messages.h
    messages.cpp


    Jamroot
    bin/
      gcc-4.7/
        debug/
          libmessages.so (bin)


In conclusion I have to say that the parser for Boost.Build needs a lot to be desired! Positioning of whitespace shouldn't matter but it does with the Jamroot files! The documentation also perplexes me: when do I name a file a Jamfile vs. Jamroot? Also, what's the deal with using xml-like tags inside of Makefile looking syntax? Consistency is key when attracting new users. I can honestly say with confidence that I won't recommend using this tool in the future. Instead I'll fall back to premake4, qmake, or cmake as they are much easier and consistent to use.

(I would normally begin with what I found appealing; I couldn't find anything. Sorry Boost.Build!)




Boost.Build (Part 1)

Linux developers know "make". The good old fashioned Makefile with targets and dependencies. Makefile's feel warm and fuzzy. They are like an open invitation saying, "Hey, you can come on in. You can type make and everything magically works, it's safe!" Makefiles are the standard- and most platforms know it. There are even tools that can be used to generate Makefiles (cmake, premake4, and qmake).

Boost's Build System is a replacement for make rather than a Makefile generator. Benefits to using Boost.Build:


  • Has no dependency on Boost itself. [1]
  • Cross-platform support. [1]
The downside is obvious in that no one really uses this tool. This small tutorial explores whether or not this is a useful tool. Keep in mind I'm heavily biased. 

The first thing we want to do is build a Hello World example [2]. I created the following two files in a single folder:

File: hello.cpp
#include <iostream>
int main(int, char**)
{
     std::cout << "Hello World!" << std::endl;
}

File: Jamroot
exe hello : hello.cpp ;

One of the cool things that I didn't know about Boost.Build is that it can build both debug and release configurations using the same command! Simply invoke:

b2 release debug

It creates the following subtree under bin:

bin
  gcc-4.7
    debug
      hello (bin)
      hello.o
    release
      hello (bin)
      hello.o

I think this is actually pretty cool. Very useful if the output of what is being written is a library that will be distributed to users. There has to be more to this, let's continue the tutorial. One of the next parts of the tutorial covers features/properties. The example they give is to turn on some of the builtin features using b2:

b2 release inlining=off debug-symbols=on

Boost.Build is very explicit about what it builds. When this command is invoked, the subtree under bin looks like:

bin
  gcc-4.7
    release
      debug-symbols-on
        inlining-off
          hello (bin)
          hello.o

I have mixed feelings about this; on one hand it's very handy to know how these targets are built. The information is useful at link-time in a lot of cases. On the other hand I think that categorizing these binaries in such a fine-grained way is a little overkill. In conclusion, it's useful but overkill. 

It's also interesting to note that the examples (seem to) encourage multiple executables within the same Jamroot file [3]. I think this is a novel idea because projects are no longer single executables; they can be comprised of server apps, client apps, shared libraries, etc. 

References







Sunday, April 21, 2013

Building Boost From Source

This topic is all about building projects using the Boost tools (aka bjam). Whenever I deal with bjam there is an automatic cringe. The first case that I'll go over is building Boost. Keep in mind that this is being done in Ubuntu:

Step 1: Go to http://www.boost.org and download the latest tarball of the sources.
As of this writing, the current version is 1.53.0. The tarball has an extension of .tar.gz. 

Step 2: Unzip and Untar the file:
This is just basic linuxy knowledge. If you want more info about gunzip or tar check the manpage.

gunzip boost_1_53_0.tar.gz
tar -xf boost_1_53_0.tar

Step 3: Run bootstrap.sh.
If the reader has skipped ahead of the boost instructions or has prior knowledge of the Boost.Build process they know that ultimately we run a program called b2 to build Boost. The b2 application is Boost.Build (get it, b2?). We are also missing the bjam application; bootstrap.sh also generates this program. 

./bootstrap.sh

After running the bootstrap script there will be two new executables in the same directory: b2 and bjam. Also take note of the output from bootstrap.sh; it shares what components will be built along with what components will not build. This can be important later! If missing components look into installing the source components from Ubuntu's main repository. 

There may also be situations where bootstrap.sh doesn't find the development libraries. For example, say the machine has installed python in an obscure location. The user can invoke bootstrap.sh with --with-python=yourobscurelocation. There are a lot more build options that can be configured. The best tip I can give you is to open bootstrap.sh in the best editor you have (vim) and take a look.

Step 4: Run b2.

./b2

At this point boost should build. The application spews out what libraries are about to build before starting. This is annoying as this is important information! For example, if dependencies on the source code for posix threads cannot be found on Linux the thread library will not report as "building". The output looks like this:

Component configuration:

    - atomic                : building

    - chrono                : building
    - context               : building
    - date_time             : building
    - exception             : building
    - filesystem            : building
    - graph                 : building
    - graph_parallel        : building
    - iostreams             : building
    - locale                : building
...

This output can save you a lot of time. Make no mistake about it: building boost takes a LOT of time. If this output is ignored (as it scrolls by really fast) the user may end up with only part of the boost libraries having been built! Seems like there should be a pause here for input.

Results

The results should be that the boost libraries are placed inside of directory tree rooted at bin.v2. Each directory is under:

bin.v2
  libs
    library-name
      compiler
        debug/release
          link-mode
            threading-multi

Both static and dynamic libraries are available. Another way to get at the libraries quickly is the stage directory which contains symbolic links to all libraries under bin.v2. Another directory of interest is the boost directory, that contains all of the headers used when developing against boost.