Showing posts with label boost. Show all posts
Showing posts with label boost. Show all posts

Tuesday, April 17, 2018

Boost Intrusive Set lookup function doesn't accept search key as object?

Would it be easier if I change the intrusive list to intrusive set? Okay, my initial goal is to capture the files into the memory, which is an intrusive list for my case, and then search through the list for each input entry. The input entry might go up 1000 items in total. Now the problem here is I had never decide what algorithm to use for the searching part. Then I come across the intrusive set does provide the API for me to work with, code sample below is my experiment on this:
class FileNode3;
typedef boost::intrusive::set<FileNode3, compare<std::greater<FileNode3> >, constant_time_size<false> > BaseSet;


class FileNode3 : public set_base_hook<link_mode<safe_link> > {
public:
    boost::filesystem::path root;
    boost::filesystem::path name;
    char type; // f is file, d is directory

    BaseSet sibling;

    FileNode3() {}
    FileNode3(boost::filesystem::path name_) : name(name_) {}
    FileNode3(boost::filesystem::path name_, const char type_) : name(name_), type(type_) {}

public:
    void setName(boost::filesystem::path name) { this->name = name; }
    void setRoot(boost::filesystem::path root) { this->root = root; }
    void setType(char type) { this->type= type; }

    friend bool operator< (const FileNode3 &a, const FileNode3 &b)
        {  return a.name.compare(b.name) < 0;  }

    friend bool operator> (const FileNode3 &a, const FileNode3 &b)
        {  return a.name.compare(b.name) > 0;  }

    friend bool operator== (const FileNode3 &a, const FileNode3 &b)
        {  return a.name.compare(b.name) == 0;  }
};

BOOST_AUTO_TEST_CASE(TL_IntrusiveSet, *boost::unit_test::precondition(skipTest(false)))
{
    struct FileNodeEqual
    {
        bool operator()(const char *search, const FileNode3 &node) const
        {
            cout << "StrEqual arg1: " << search << " " << node.name.c_str() << endl;

            return strcmp(search, node.name.c_str()) == 0 ? false : true;
        }

        bool operator()(const FileNode3 &node, const char *search) const
        {
            cout << "StrEqual arg2: " << search << " " << node.name.c_str() << endl;

            return strcmp(node.name.c_str(), search) == 0 ? false : true;
        }
    };

    BaseSet s1;

    FileNode3 fn3;
    fn3.name = "fileB";
    fn3.type = 'f';

    FileNode3 fn1;
    fn1.name = "path_A";
    fn1.type = 'd';
    fn1.sibling.push_back(fn3);

    FileNode3 fn2;
    fn2.type = 'f';
    fn2.name = "fileA";

    s1.insert(fn1);
    s1.insert(fn2);

    FileNode3 f;
    f.name = "fileB";
    f.type = 'd';

    boost::intrusive::set<FileNode3>::iterator it = s1.find(f.name.c_str(), FileNodeEqual());

    FileNode3 *n = (&*it);

    if( it == s1.end() ) {
        cout << "record not found" << endl;
    }
    else {
        FileNode3 *n = (&*it);
        cout << "record found: " << n->name << endl;
    }

    if( fn1.sibling.size() > 0 ) {
        cout << "fn1 sibling has more child: " << fn1.sibling.size() << endl;

        boost::intrusive::set<FileNode3>::iterator it = fn1.sibling.find(fn3);

        if( it == s1.end() ) {
            cout << "record not found" << endl;
        }
        else {
            FileNode3 *n = (&*it);
            cout << "record found: " << n->name << endl;
        }
    }

    s1.remove_node(fn1);
    s1.remove_node(fn2);
    s1.remove_node(fn3);

    cout << "Test 1 end!" << endl;
}
But that is one problem with this code, I can only compare the name property of this object. How can I compare the rest of the properties of the object? Why don't I just pass down the whole object and then do the comparison? Then I modify the FileNodeEqual struct as follows, the search key has become an FileNode3 instead of char*:
struct FileNodeEqual
    {
        bool operator()(const FileNode3 &search, const FileNode3 &node) const
        {
            cout << "StrEqual arg1: " << search.name.c_str() << " " << node.name.c_str() << endl;

            return true;
        }

        bool operator()(const FileNode3 &node, const FileNode3 &search) const
        {
            cout << "StrEqual arg2: " << search.name.c_str() << " " << node.name.c_str() << endl;

            return true;
        }
    };
Then the compiler will complain following error to me:
error: 'bool testlab::TL_IntrusiveSet::test_method()::FileNodeEqual2::operator()(const testlab::FileNode3&, const testlab::FileNode3&) const' cannot be overloaded
         bool operator()(const FileNode3 &node, const FileNode3 &search) const
              ^~~~~~~~
error: with 'bool testlab::TL_IntrusiveSet::test_method()::FileNodeEqual2::operator()(const testlab::FileNode3&, const testlab::FileNode3&) const'
         bool operator()(const FileNode3 &search, const FileNode3 &node) const
              ^~~~~~~~
I have tested with other primitive data types are working fine. Not sure whether this is due to the performance penalty when calling those functions, thus it was design not allow to take any expensive object?

Sunday, February 25, 2018

Grouping test cases with test suite

Sometimes I just want to skip those unit test cases that have already been pass and focus those test cases on my current development. And then re-run again the whole unit test case again when I have finished the task to ensure no flaw happened to the other unit test cases. Sometimes it is so annoying to run all unit test cases that are not relevant to the task I'm currently working on. I found out one trick that could allow me to control which unit test code should execute and which should stop.

The code snippet below is the ordinary declaration for my unit test code, this declaration form will be executed whenever the code were run.
BOOST_AUTO_TEST_CASE(TL_1)
{
   ...
}
Then later I added some spice to tell the framework whether the unit test case should be executed or not. Following code snippet is the trick I have done for this purpose.
BOOST_AUTO_TEST_CASE(TL_1, *boost::unit_test::enable_if<false>())
{
   ...
}
In my case, this would be a great help. I don't need to wait for all unit test cases are finished in order to see the result. Some more there is only one or two test cases I can really focus on for the same tasks at the same time. Now, as my unit test code are expanding, I need more flexibility and the ability to group relevant test cases together in one source file, and then I can decide which test code to run. Here is the code snippet for the solution.
BOOST_AUTO_TEST_SUITE(testlab, *boost::unit_test::label("testlab"))

BOOST_AUTO_TEST_CASE(TL_1, *boost::unit_test::enable_if<false>())
{
   ...
   ...
}

BOOST_AUTO_TEST_SUITE_END()
With this code, the test case are grouped under the test suite named testlab. When the code is run, all test cases under this suite will be execute. But there is one flaw in this code, the enable_if() is not working. The test will continue to execute even though it is false. Not only that, neither disabled() and enabled() are working. Luckily precondition() comes to a rescue. The code snippet below tells the framework to continue to execute the test case.
struct skipTest
{
    bool skip;
    skipTest(bool s) : skip(s){}

    boost::test_tools::assertion_result operator()(boost::unit_test::test_unit_id)
    {
        if( skip == false )
            return true;
        else
            return false;
    }
};

BOOST_AUTO_TEST_CASE(TL_1, *boost::unit_test::precondition(skipTest(false)))
{
   ...
   ...
}
As of now, the test suite will help me to control which group of test case to execute and precondition() will allow me to choose which test case should skip whenever I want during the development.

Wednesday, November 8, 2017

Accessing the last element of an Intrusive list

I always thought that retrieving the last element from an intrusive list just as easy as one two three. In fact, it is not. Let's dive into the story. Here I have the intrusive list declaration:
/***** FileNode.h *****/

class FileNode : public boost::intrusive::list_base_hook<link_mode<auto_unlink> >
{
...
...

};


/***** FileBot.h *****/

typedef boost::intrusive::list<FileNode, base_hook<list_base_hook<link_mode<auto_unlink> > >, constant_time_size<false> > FileNodeListType;

class FileBot
{
private:
    FileNodeListType fileList;

...
...
};
And then I'll use the iterator as shown below go straight to access the element located at the end of the list, but somehow this a hit segmentation fault error.
        FileNodeListType::iterator it(fileList.end());

        // following piece basically doing some data manipulation
        // on the element retrieve from the list.
        FileNode *p = &*it;
        (*it).sibling.push_back(*node);

        cout << p << endl; // memory address shows 0x7ffedff8e808
The error is due to the wrong memory address is being accessed. As I verify on the element being inserted into the list (only one element is inserted in this test case) is having an address different from the one mention in the code above. Thus, according to the expert, in order to access the correct element located at the end of the list is by doing this:
        FileNodeListType::iterator it(fileList.end());
        FileNode *p = &*(--it);
        cout << p << endl; // memory address shows 0xa01bc0

Sunday, October 29, 2017

Removing an item from the Boost Intrusive list

Over the pass few weeks, I was reading the a lot of articles about the intrusive list, its benefits of using it, and its use case example on game development. This brings me a strong message that there are so many peoples on Earth promoting this container. What was so special about this container? Due to the limitation on the container provided by STL and intrusive container's low memory footprint which could benefit to the application's performance.

Does Boost provide this container. Yes! During this great moment with a sudden impulse, I begin my journey to develop a demo program using the Boost Intrusive container. Tadaa~

So far the journey was up and down, a lot of road pump, and feel tired to continue. When trying to remove an item from the list using following method will not work. Before that, let's presume I have the following declaration in the header file:
typedef boost::intrusive::list<FileNode, base_hook<list_base_hook<link_mode<auto_unlink> > >, constant_time_size<false> > FileNodeListType;

class FileBot
{
private:
    FileNodeListType fileList;

    ...
    ...
};
Then I begin to insert something into the list, assume the object type is a FileNode, do take note that I do this purely in one method:
void FileBot::addFileNode()
{
    FileNode *f1 = new FileNode();
    f1->setName("ASD");
    fileList.push_back(*f1);

    cout << "addFileNode(): memory address of insert object: " << f1 << endl;
}
Then I have another method to remove an object from the list:
void FileBot::clearMemoryByName(string filename)
{
    cout << "before delete: " << fileList.size() << endl;

    FileNode *p = new FileNode();
    p->setName("ASD");

    fileList.erase(FileNodeListType::s_iterator_to(*p));
    delete p;

    cout << "clearMemoryByName(): memory address of remove object: " << p << endl;

    cout << "after delete: " << fileList.size() << endl;
}
But somehow this method will cause a memory leak due to the following assertion failed in boost/intrusive/list.hpp, line 1270:
Assertion failed: !node_algorithms::inited(value_traits::to_node_ptr(value)), file D:\tool\boost_1_61_0\msvc\boost/intrusive/list.hpp, line 1270
Detected memory leaks!
Dumping objects ->
...
...
...
Object dump complete.
Press <return> to close this window...
A million hours were spent on studying the weak spot of this creature has finally found a solution. The clue was lying on the memory address of the object. The memory address of the object inserted into the list in addFileNode() was different from the memory object created in the clearMemoryByName().
...

addFileNode(): memory address of insert object: 001180C8
clearMemoryByName(): memory address of remove object: 00111DE0

...
In the revise's version, the object was retrieved from the list and then perform some filtering (e.g. match the property field's value), then only perform the deletion.
void FileBot::clearMemoryByName(string filename)
{
    FileNode *p = NULL;
    FileNodeListType::iterator it(fileList.begin());

    for(; it != fileList.end(); it++)
    {
        cout << &*it << endl;

        // look for particular node
        string curName = (*it).getName().c_str();
        if( filename == curName) {
            p = &*it;
            break;
        }
    }

    cout << "claerMemoryByName(): memory address of remove object: " << p << endl;

    fileList.erase(FileNodeListType::s_iterator_to(*p));
    delete p;
The result was stunning! The object was removed from the list. And here is the output of the memory address:
...

addFileNode(): memory address of insert object: 00E2DAF0
claerMemoryByName(): memory address of remove object: 00E2DAF0

...
To conclude this, in order to remove an object from the list, O(n) algorithm is the only way to filter the object, then only come to deletion.

Saturday, October 14, 2017

Convert Windows file separator into Linux format

I wrote a function to extract the parent path for a given path. An interesting thing happens here; Windows's file system was used (\) backslash as file separator, whereas Linux's using (/) slash as file separator. Thus, this will end up I have following code produce:
void FileBot::constructParentPath()
{
   ...

   string sep = string(1, boost::filesystem::path::preferred_separator);
   if( sep == "/" )
      boost::replace_last(filePath, "/", "|");
   else
      boost::replace_last(filePath, "\", "|");

   ...
}
When handling file separator with Boost library, the library will able to convert the Windows's file separator into Linux format. Therefore, my code will reduce into one line from the previous version:
void FileBot::constructParentPath()
{
   ...

   string filePath = fileNode.getName().generic_string();
   boost::replace_last(filePath, "/", "|");

   ...
}

Sunday, September 24, 2017

Never forget qmake

Oh come on! Error again! I encounter a weird error on QT compiler today. I though I had the thing fixed on last week, wonder why the fix on last week is not working on today? What a joke. Now the error is different. The error mentions that I have multiple definition found. The root cause is coming from the Boost library.
13:12:11: Starting: "D:\tool\Qt\Tools\QtCreator\bin\jom.exe" 
 D:\tool\Qt\Tools\QtCreator\bin\jom.exe -f Makefile.Debug
 cl -c -nologo -Zc:wchar_t -FS -Zc:strictStrings -Zc:throwingNew -Zi -MDd -GR -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -EHsc /Fddebug\wqt1.vc.pdb -DUNICODE -DWIN32 -DQT_QML_DEBUG -DQT_CORE_LIB -I..\wqt1 -I. -I..\..\..\tool\boost_1_61_0 -I..\..\tool\Qt\5.7\msvc2015\include -I..\..\tool\Qt\5.7\msvc2015\include\QtCore -Idebug -I..\..\tool\Qt\5.7\msvc2015\mkspecs\win32-msvc2015 -Fodebug\ @C:\Users\HUAHS_~1\AppData\Local\Temp\main.obj.4132.31.jom
main.cpp
 link /NOLOGO /DYNAMICBASE /NXCOMPAT /DEBUG /SUBSYSTEM:CONSOLE "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /MANIFEST:embed /OUT:debug\wqt1.exe @C:\Users\HUAHS_~1\AppData\Local\Temp\wqt1.exe.4132.8453.jom
libboost_filesystem-vc140-mt-gd-1_61.lib(path_traits.obj) : error LNK2005: "void __cdecl boost::filesystem::path_traits::convert(char const *,char const *,class std::basic_string<wchar_t std::char_traits="" struct="" wchar_t="">,class std::allocator<wchar_t> > &,class std::codecvt<wchar_t _mbstatet="" char="" struct=""> const &)" (?convert@path_traits@filesystem@boost@@YAXPBD0AAV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@ABV?$codecvt@_WDU_Mbstatet@@@5@@Z) already defined in boost_filesystem-vc140-mt-gd-1_61.lib(boost_filesystem-vc140-mt-gd-1_61.dll)
libboost_filesystem-vc140-mt-gd-1_61.lib(path.obj) : error LNK2005: "public: static class std::codecvt<wchar_t _mbstatet="" char="" struct=""> const & __cdecl boost::filesystem::path::codecvt(void)" (?codecvt@path@filesystem@boost@@SAABV?$codecvt@_WDU_Mbstatet@@@std@@XZ) already defined in boost_filesystem-vc140-mt-gd-1_61.lib(boost_filesystem-vc140-mt-gd-1_61.dll)
debug\wqt1.exe : fatal error LNK1169: one or more multiply defined symbols found
jom: D:\workspaceqt\build-wqt1-Desktop_Qt_5_7_1_MSVC2015_32bit-Debug\Makefile.Debug [debug\wqt1.exe] Error 1169
jom: D:\workspaceqt\build-wqt1-Desktop_Qt_5_7_1_MSVC2015_32bit-Debug\Makefile [debug] Error 2
How could I resolve them? I am spending hours experiment this error, by making a clean build or start a new project from scratch just to simulate this error have no result. Until late night only found out there is a very important step was missing during the build.

Whenever the PRO file is updated, I'm required to run qmake, because this will allow to update the Makefile generate by the QT. No wonder why sometimes I get an error on undefined reference on blah_blah_blah_functionA() when I add a new library in PRO file.

Saturday, September 9, 2017

When Boost Log meet MinGW, everything will not work!

My mission on migrating Boost code from Linux to Windows is almost failed. The error was strange enough that I have no idea why there are so many undefined reference happened in the code. I mean, since the code is designed for cross platform, it should not have any trouble if it is migrating to the other platform.

My finding on this matter was that the compiler will throw error whenever I have the following piece appear in my code.
boost::log::add_file_log
(
   keyword::file_name = "sample.log",
   keyword::rotation_size = 10 * 1024 * 1024,
   keyword::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0,0,0),
   keyword::format = "[%TimeStamp%]: %Message%"
);
Yippee! I start to see some light on the problem. That piece is belongs to Boost Log. I am pretty sure the error comes from this piece.
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `make_absolute':
d:\tool\boost_1_61_0/libs/log/src/text_file_backend.cpp:597: undefined reference to `boost::filesystem::absolute(boost::filesystem::path const&, boost::filesystem::path const&)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `store_file':
d:\tool\boost_1_61_0/libs/log/src/text_file_backend.cpp:695: undefined reference to `boost::filesystem::path::parent_path() const'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `scan_for_files':
d:\tool\boost_1_61_0/libs/log/src/text_file_backend.cpp:776: undefined reference to `boost::filesystem::path::parent_path() const'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost3log10v2s_mt_nt55sinks17text_file_backend7consumeERKNS1_11record_viewERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE':
d:\tool\boost_1_61_0/libs/log/src/text_file_backend.cpp:1218: undefined reference to `boost::filesystem::path::parent_path() const'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost3log10v2s_mt_nt55sinks17text_file_backend30set_file_name_pattern_internalERKNS_10filesystem4pathE':
d:\tool\boost_1_61_0/libs/log/src/text_file_backend.cpp:1265: undefined reference to `boost::filesystem::path::parent_path() const'
d:\tool\boost_1_61_0/libs/log/src/text_file_backend.cpp:1265: undefined reference to `boost::filesystem::absolute(boost::filesystem::path const&, boost::filesystem::path const&)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZNK5boost10filesystem4path15has_parent_pathEv':
d:\tool\boost_1_61_0/./boost/filesystem/path.hpp:516: undefined reference to `boost::filesystem::path::parent_path() const'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystemdvERKNS0_4pathES3_':
d:\tool\boost_1_61_0/./boost/filesystem/path.hpp:789: undefined reference to `boost::filesystem::path::operator/=(boost::filesystem::path const&)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem12current_pathEv':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:596: undefined reference to `boost::filesystem::detail::current_path(boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem10equivalentERKNS0_4pathES3_':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:608: undefined reference to `boost::filesystem::detail::equivalent(boost::filesystem::path const&, boost::filesystem::path const&, boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem9file_sizeERKNS0_4pathE':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:614: undefined reference to `boost::filesystem::detail::file_size(boost::filesystem::path const&, boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem9file_sizeERKNS0_4pathERNS_6system10error_codeE':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:618: undefined reference to `boost::filesystem::detail::file_size(boost::filesystem::path const&, boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem15last_write_timeERKNS0_4pathE':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:637: undefined reference to `boost::filesystem::detail::last_write_time(boost::filesystem::path const&, boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem6renameERKNS0_4pathES3_':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:677: undefined reference to `boost::filesystem::detail::rename(boost::filesystem::path const&, boost::filesystem::path const&, boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem5spaceERKNS0_4pathE':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:698: undefined reference to `boost::filesystem::detail::space(boost::filesystem::path const&, boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem15system_completeERKNS0_4pathE':
d:\tool\boost_1_61_0/./boost/filesystem/operations.hpp:710: undefined reference to `boost::filesystem::detail::system_complete(boost::filesystem::path const&, boost::system::error_code*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(text_file_backend.o): In function `ZN5boost10filesystem4pathaSINS0_15directory_entryEEENS_9enable_ifINS0_11path_traits11is_pathableINS_5decayIT_E4typeEEERS1_E4typeERKS8_':
d:\tool\boost_1_61_0/./boost/filesystem/path.hpp:202: undefined reference to `boost::filesystem::path_traits::dispatch(boost::filesystem::directory_entry const&, std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&)'
collect2.exe: error: ld returned 1 exit status
Notice that all Boost Log library were failed. When things are working fine on Linux platform, but error on the other, I have a very strong feeling that this could be the compiler version issue. Base on my pass experience and common sense of programming knowledge, I make a quit decision on the MinGW to switch to the Microsoft C++ compiler.

Going through all the hassle setup on the QT + MSVC compiler, together with the same configuration on the .pro file:
...

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib64-msvc-14.0/ -lboost_system-vc140-mt-1_61
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib64-msvc-14.0/ -lboost_system-vc140-mt-gd-1_61
else:unix:!macx: LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_system

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib32-msvc-14.0/ -lboost_filesystem-vc140-mt-1_61
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib32-msvc-14.0/ -lboost_filesystem-vc140-mt-gd-1_61
else:unix:!macx: LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_filesystem

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib32-msvc-14.0/ -lboost_log_setup-vc140-mt-1_61
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib32-msvc-14.0/ -lboost_log_setup-vc140-mt-1_61
else:unix:!macx: LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log_setup

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib32-msvc-14.0/ -lboost_log-vc140-mt-1_61
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/msvc/lib32-msvc-14.0/ -lboost_log-vc140-mt-1_61
else:unix:!macx: LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log

...
The code was compiled successfully at least. And now I am declaring to myself to abandon and give up any use of MinGW compiler with Boost library on Windows platform. I am very serious about this matter. (>.<)

Friday, September 1, 2017

Undefined reference to WinMain@16 in Boost Test

My bad!! Ever wonder what causes this error in my Boost Test?
crt0_c.c:-1: error: undefined reference to `WinMain@16'
collect2.exe:-1: error: error: ld returned 1 exit status
I was in the midst of preparing a new test script for my unit test, but somehow I was so struggling when I got hit on that error. Googling around couldn't find any answer, I sit back and doing code review again on my unit test script. What is surprising me is that I was missing the one time setup code in the beginning of the code:
#define BOOST_TEST_DYN_LINK

#define BOOST_NO_CXX11_SCOPED_ENUMS
#define BOOST_TEST_MODULE "syncFile core function"

#include <initializer_list>
#include <boost/test/unit_test.hpp>

...
The first line is very important, this is the crucial part of the success or failure of the compilation. What if I have multiple unit test source file, and BOOST_TEST_DYN_LINK was declared in both files? I am using QT compiler, script below shows 2 unit test source files was included in the project:
...

SOURCES += \
    ../unittest/testCaptureFiles.cpp \
    ../unittest/testlab.cpp

...
This is what I got from the compiler:
D:\tool\boost_1_61_0\boost\test\unit_test_suite.hpp:338: error: multiple definition of `init_unit_test()'
D:\tool\boost_1_61_0\boost\test\unit_test.hpp:62: error: multiple definition of `main'
collect2.exe:-1: error: error: ld returned 1 exit status
So please be careful on using Boost Test.

Sunday, August 13, 2017

Boost Log can't live without thread library

In one of my experiment project, I have the Boost Log configure in QT's build path, see below:
...

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log_setup-mgw53-mt-1_61
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log_setup-mgw53-mt-d-1_61
else:unix:!macx: LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log_setup

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log-mgw53-mt-1_61
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log-mgw53-mt-d-1_61
else:unix:!macx: LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_log

...
End up when I try to compile this program, I get these bunch of undefined error on boost::detail::set_tss_data() in my console output window:
g++ -Wl,-subsystem,console -mthreads -o debug/backupUtilUnitTest.exe debug/FileHelper.o debug/FilePath.o debug/filenode.o debug/testlab.o  -LD:/tool/boost_1_61_0/stage/lib -lboost_system-mgw53-mt-d-1_61 -lboost_filesystem-mgw53-mt-d-1_61 -lboost_timer-mgw53-mt-d-1_61 -lboost_chrono-mgw53-mt-d-1_61 -lboost_log_setup-mgw53-mt-d-1_61 -lboost_log-mgw53-mt-d-1_61 -lboost_regex-mgw53-mt-d-1_61 -lboost_unit_test_framework-mgw53-mt-d-1_61 -LD:/tool/Qt/5.7/mingw53_32/lib D:/tool/Qt/5.7/mingw53_32/lib/libQt5Cored.a 
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(core.o): In function `ZN5boost19thread_specific_ptrINS_3log10v2s_mt_nt54core14implementation11thread_dataEED1Ev':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:79: undefined reference to `boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(core.o): In function `ZNK5boost19thread_specific_ptrINS_3log10v2s_mt_nt54core14implementation11thread_dataEE3getEv':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:84: undefined reference to `boost::detail::get_tss_data(void const*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(core.o): In function `ZN5boost19thread_specific_ptrINS_3log10v2s_mt_nt54core14implementation11thread_dataEE5resetEPS5_':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:105: undefined reference to `boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(record_ostream.o): In function `get':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:84: undefined reference to `boost::detail::get_tss_data(void const*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(record_ostream.o): In function `reset':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:105: undefined reference to `boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(record_ostream.o): In function `get':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:84: undefined reference to `boost::detail::get_tss_data(void const*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(record_ostream.o): In function `reset':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:105: undefined reference to `boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(record_ostream.o): In function `~thread_specific_ptr':
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:79: undefined reference to `boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool)'
d:\tool\boost_1_61_0/./boost/thread/tss.hpp:79: undefined reference to `boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(severity_level.o): In function `ZN5boost11this_thread14at_thread_exitINS_3_bi6bind_tINS2_11unspecifiedENS_15checked_deleterIyEENS2_5list1INS2_5valueIPyEEEEEEEEvT_':
d:\tool\boost_1_61_0/./boost/thread/detail/thread.hpp:862: undefined reference to `boost::detail::add_thread_exit_function(boost::detail::thread_exit_function_base*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(thread_id.o): In function `at_thread_exit<boost::log::v2s_mt_nt5::aux::this_thread:: anonymous="" id_storage::deleter="" namespace="">':
d:\tool\boost_1_61_0/./boost/thread/detail/thread.hpp:862: undefined reference to `boost::detail::add_thread_exit_function(boost::detail::thread_exit_function_base*)'
D:/tool/boost_1_61_0/stage/lib/libboost_log-mgw53-mt-d-1_61.a(once_block.o): In function `ZN5boost6detail19basic_cv_list_entry4waitENS0_7timeoutE':
d:\tool\boost_1_61_0/./boost/thread/win32/condition_variable.hpp:94: undefined reference to `boost::this_thread::interruptible_wait(void*, boost::detail::timeout)'
collect2.exe: error: ld returned 1 exit status
As of my finding from the forum, they mention that it requires to compile with -pthread option. Unfortunately, that solution is only applicable to Linux. Since I'm using Boost, the only option I have is to link the Boost Thread library:
...

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_thread-mgw53-mt-1_61
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_thread-mgw53-mt-d-1_61
else:unix:!macx: LIBS += -L$$PWD/../../../tool/boost_1_61_0/stage/lib/ -lboost_thread

...
And the compilation proceeds successfully.

Sunday, June 4, 2017

Boost Intrusive container must be clear before exits

A few weeks ago when I was working on a problem involving linked list, I was stuck in an interesting test case on Boost Intrusive. The error I'm getting is coming from the comment of a source code as seen below:
void destructor_impl(Hook &hook, detail::link_dispatch<safe_link>)
{  //If this assertion raises, you might have destroyed an object
   //while it was still inserted in a container that is alive.
   //If so, remove the object from the container before destroying it.
   (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked());
}
I was in debug mode, and the program was stopped right there. At first I had overlooked into this important piece, but then later only I got to realize that the comment is giving some clue over there. The comment has clearly stated that I must have the container to be clear before destroying it. So what I did in my class was I extend the list_base_hook:
class FileNode : public list_base_hook<> {
public:
    string name;
    char type;

public:
    FileNode() {}

    void setName(string name) { this->name = name; }
    void setType(char type) { this->type= type; }
};

typedef boost::intrusive::list<FileNode> FileNodeList;
And this is my test case that causes the error:
BOOST_AUTO_TEST_CASE(TL_2)
{
    FileNodeList fnl;

    FileNode fn1;
    fn1.name = "path_A";

    assert(fn1.is_linked() == false);

    FileNode fn2;
    fn2.name = "fileA";

    fnl.push_front(fn1);

    fnl.clear(); // error will be thrown if this code is removed!
}
Do take note the above class FileNode does not take any template argument. There is another version using auto_unlink as template argument, just like below:
class FileNode : public list_base_hook<link_mode<auto_unlink> > { 
    ...
    ...
}; 
 
typedef boost::intrusive::list<FileNode, constant_time_size<false> > FileNodeList;
This feature does not require me to clear the container when the container's destructor is invoked, which happened when the function is exited.

Monday, February 20, 2017

Using Boost.Log in the project

Boost.Log, just like other module, it must be built first before it can be used. But most of the time I will just go for the default compilation, just like below

> ./b2 --with-log 

According to this documentation, I can have a lot more option to the build. Say for example -DBOOST_LOG_DYN_LINK, below is the definition of the macro:

BOOST_LOG_DYN_LINK If defined in user code, the library will assume the binary is built as a dynamically loaded library ("dll" or "so"). Otherwise it is assumed that the library is built in static mode. This macro must be either defined or not defined for all translation units of user application that uses logging. This macro can help with auto-linking on platforms that support it.

When I build with -DBOOST_LOG_DYN_LINK just like the sample below:

> ./b2 --with-log define=BOOST_LOG_DYN_LINK

I must have the following statement in the .pro file:

DEFINES += BOOST_LOG_DYN_LINK

Take a closer look into the console output. Notice that BOOST_LOG_DYN_LINK option is added into g++ build command:
g++ -c -pipe -g -std=gnu++0x -Wall -W -D_REENTRANT -fPIC -DBOOST_LOG_DYN_LINK -DQT_QML_DEBUG 
-DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I../../backupUtil -I. -I../../../tool/boost_1_61_0 -I../../backupUtil 
-I../../../tool/Qt5.6.0/5.6/gcc_64/include -I../../../tool/Qt5.6.0/5.6/gcc_64/include/QtWidgets 
-I../../../tool/Qt5.6.0/5.6/gcc_64/include/QtGui -I../../../tool/Qt5.6.0/5.6/gcc_64/include/QtCore -I. -I. 
-I../../../tool/Qt5.6.0/5.6/gcc_64/mkspecs/linux-g++ -o main.o ../main.cpp
If the above define statement is missing from the .pro file, the compiler will throw out the link error. Tracing that error could lead to a wrong way fixing the problem because the root cause wasn't there. This documentation would give some hints on how this thing could be fixed. Below is the important text from that documentation:
<version><linkage>_<threading>_<system>
  • The <version> component describes the library major version. It is currently v2.
  • The <linkage> component tells whether the library is linked statically or dynamically. It is s if the library is linked statically and empty otherwise.
  • The <threading> component is st for single-threaded builds and mt for multi-threaded ones.
  • The <system> component describes the underlying OS API used by the library. Currently, it is only specified for multi-threaded builds. Depending on the target platform and configuration, it can be posix, nt5 or nt6.
Same to the default Boost.Log build without BOOST_LOG_LINK, link error will be throw if the define statement was declared in the .pro file.

Tuesday, December 15, 2015

Filter file name with Boost regular expression

The story of the use case is like this; given a file name having the pattern, dummyx.txt, where x is a running number, how could I effectively filter out those doesn't match with this pattern? My initial answer would be this:
set<wstring> files = ... // assuming a list of file name are return and kept in the variable files

set<wstring>::iterator it;

for( it=list.begin(); it != list.end(); it++ ) {
    if ((*it).find(L"dummy.txt") != string::npos) {
        /***** proceed with the flow *****/
    }
}
I just feel that this piece is so rough. Instead of comparing the file name using wildcard search, I start to think of a more elegant way to get this done. So the first idea pops up in my mind is to use regular expression, here come to the second revision of the piece:
boost::regex expr("([\\:/\\\\\\w]+)?dummy(\\d{1,3})(\\.txt)$");
set<wstring>::iterator it;

for( it=list.begin(); it != list.end(); it++ ) {
    string s((*it).begin(), (*it).end());
    if (boost::regex_match(s, expr)) {
        /***** proceed with the flow *****/
    }
}
Much better? At least the code look much more elegant than the previous piece. Not only that it will filter out those doesn't match with the pattern, it will also filter out the name with only dummy in the file name.

Sunday, November 22, 2015

My new reinforcement on C++ unit test

A few weeks ago, while I was working out on CppUnit in unit testing and I found out that it wouldn’t work as I doesn’t have MFC framework install in my Windows. Now I had discovered Boost.Test for this critical mission. The first contact on the new discovery, I have following code ready to charge:
#define BOOST_TEST_MODULE Hello
#include <boost/test/unit_test.hpp>

int add(int i, int j)
{
    return i+j;
}

BOOST_AUTO_TEST_CASE(Case1)
{
    BOOST_CHECK(add(2,2) == 4);
}
Interestingly, the test doesn’t get executed, but the main entry point of the program, int main(int argc, char* argv[]) was called. I spent the whole day reading through the documentation still has not got any clue on it. Until I remove the main entry point, and something were shown on the screen:
Running 1 test case...

*** No errors detected
Press <return> to close this window...
This is pretty exciting as I got a first unit test up and running. Thinking out from the plan, I need a separate project just for the unit test.

Tuesday, November 10, 2015

Duplicate section has different size

Looking at the following error, I think I have messed up the build.
C:\Tool\boost_1_54_0\stage\lib\libboost_filesystem-mgw48-mt-1_54.a(operations.o):-1: 
error: duplicate section `.rdata$_ZTSN5boost6detail17sp_counted_impl_pINS_10filesystem6detail11dir_itr_impEEE[__ZTSN5boost6detail17sp_counted_impl_pINS_10filesystem6detail11dir_itr_impEEE]' 
has different size
I was rebuilding the Boost unit test framework, once done, when I try to build my application, this error comes out. As I search in the forum, it is due to the object file and executable file were out of date, meaning to say that the linker unable to link them together, thus compiler will make some noise.

I do not have much choice to solve this error, rebuild everything is the only way.

Sunday, November 1, 2015

Building Boost with MinGW compiler

Does it really hard to build Boost libraries with MinGW compiler on Windows?

I have the Windows version Boost library build for Microsoft compiler, when I tried to link them in QT creator, as shown below, was failed even though I have configured the build kit to the Microsoft compiler in QT creator.
win32 {
   INCLUDEPATH += C:/Tool/boost_1_54_0
   LIBS += -LC:/Tool/boost_1_54_0/lib64-msvc-11.0 -lboost_filesystem-vc110-1_54
}
Looking on the Internet, the majority of them are using MinGW version of Boost library whenever working on QT, not the Microsoft version. To build a MinGW version of Boost, it wasn't that straight forward as following command.
c:\tool\boost_1_54_0>bootstrap.bat

c:\tool\boost_1_54_0>b2.exe --toolset=gcc
I did try on the command mention above, but end up nothing were being generated in stage/lib. I then found there is a workaround for building the MinGW version of Boost:

Step 1
Go to <BOOST_ROOT>/tools/build/v2/engine, and fire the command: build.bat mingw. This will generate bin.ntx86 folder under the same path.

Step 2
Set environment variable: set PATH=%PATH%;<BOOST_ROOT>/tools/build/v2/engine/bin.ntx86. Without this Windows will not recognize who is bjam.

Step 3
Set environment variable: set PATH=%PATH%;<MinGW_ROOT>/bin. Without this the compiler will not recognize who is gcc.

Step 4
Fire the command: bjam toolset=gcc. This should generate a bunch of libraries with file name that contain mgw with .a extension.

One last note, bjam command will require mingw32-libz to be installed with MinGW compiler before Boost is start building. Once done, reconfigure the .pro file with following code:

win32 {
   INCLUDEPATH += C:/Tool/boost_1_54_0
   LIBS += -LC:/Tool/boost_1_54_0/stage/lib -lboost_filesystem-mgw48-mt-1_54
}

Sunday, March 1, 2015

How do CMake determine static or dynamic Boost library?

I was trying to integrate Boost filesystem and system module into CMake in the project, but interestingly, I found out that find_package were not functioning properly:

find_package(Boost 1.54.0 COMPONENTS filesystem system REQUIRED)

I just spot this symptom in this morning. When I am generating a project file from Cmake with this command cmake -G “xxx”, I hit an error as mention below:

CMake Error at D:/tool/cmake-3.2.0-rc1-win32-x86/share/cmake-3.2/Modules/FindBoost.cmake:1182 (message):
  Unable to find the requested Boost libraries.

  Boost version: 1.54.0

  Boost include path: C:/Boost/include/boost-1_54

  Could not find the following Boost libraries:

          boost_filesystem
          boost_system

No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.

When I have the debug mode turned on, like this set(Boost_DEBUG 1), I have the following piece captured:
-- [ D:/tool/cmake-3.2.0-rc1-win32-x86/share/cmake-3.2/Modules/FindBoost.cmake:890 ] _boost_LIBRARY_SEARCH_DIRS = C:/Boost/lib;C:/Boost/stage/lib;C:/Boost/include/boost-1_54/lib;C:/Boost/include/boost-1_54/../lib;C:/Boost/include/boost-1_54/stage/lib;PATHS;C:/boost/lib;C:/boost;/sw/local/lib
-- [ D:/tool/cmake-3.2.0-rc1-win32-x86/share/cmake-3.2/Modules/FindBoost.cmake:1001 ] Searching for FILESYSTEM_LIBRARY_RELEASE: boost_filesystem-vc110-mt-1_54;boost_filesystem-vc110-mt;boost_filesystem-mt-1_54;boost_filesystem-mt;boost_filesystem
-- [ D:/tool/cmake-3.2.0-rc1-win32-x86/share/cmake-3.2/Modules/FindBoost.cmake:1037 ] Searching for FILESYSTEM_LIBRARY_DEBUG: boost_filesystem-vc110-mt-gd-1_54;
boost_filesystem-vc110-mt-gd;boost_filesystem-mt-gd-1_54;boost_filesystem-mt-gd;boost_filesystem-mt;boost_filesystem
-- [ D:/tool/cmake-3.2.0-rc1-win32-x86/share/cmake-3.2/Modules/FindBoost.cmake:1001 ] Searching for SYSTEM_LIBRARY_RELEASE: boost_system-vc110-mt-1_54;boost_sys
tem-vc110-mt;boost_system-mt-1_54;boost_system-mt;boost_system
-- [ D:/tool/cmake-3.2.0-rc1-win32-x86/share/cmake-3.2/Modules/FindBoost.cmake:1037 ] Searching for SYSTEM_LIBRARY_DEBUG: boost_system-vc110-mt-gd-1_54;boost_sy
stem-vc110-mt-gd;boost_system-mt-gd-1_54;boost_system-mt-gd;boost_system-mt;boost_system
-- [ D:/tool/cmake-3.2.0-rc1-win32-x86/share/cmake-3.2/Modules/FindBoost.cmake:1088 ] Boost_FOUND = 1

...
CMake was searching for boost_xxx but I had only libboost_xxx installed in my system. I was wondering how could I direct CMake to take libboost_xxx instead of boost_xxx? Thanks to open source that could allow me to dive into the source code to see what is happening actually. From the clue given above, there is a piece of logic in FindBoost.cmake governing CMake whether a boost library prefix with “lib” or without “lib” should be taken. Here is the piece:
...

set(Boost_LIB_PREFIX "")
if ( WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN )
  set(Boost_LIB_PREFIX "lib")
endif()

...
Since I'm doing this in DOS prompt, WIN32 and NOT CYGWIN are returning true, but Boost_USE_STATIC_LIBS were returning false. This reminds me that I have something in my code:
...

set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(Boost_ALL_DYN_LINK ON)

...
Clearly, I should ON the Boost_USE_STATIC_LIBS to resolve this problem. And this is interesting to know that a boost static library is prefixed with “lib”.

Tuesday, February 24, 2015

CMake unable to read Boost's version.hpp

Ever wonder how Boost works together with CMake? I have no knowledge prior to this setup, thus this is my initial code in CMakeLists.txt.
cmake_minimum_required(VERSION 2.8.4)
project("Project A")

set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(Boost_ALL_DYN_LINK ON)

find_package(Boost 1.54.0 COMPONENTS filesystem system REQUIRED)

if(Boost_FOUND)
 message(STATUS "Boost library were found")
 
 include_directories(${Boost_INCLUDE_DIRS})
 add_executable(Project_A source/main.cpp)
 target_link_libraries(syncFile ${Boost_LIBRARIES})
else()
 message(STATUS "No Boost library were found")
endif()
As of this writing, I'm using Boost 1.54 and CMake 3.1.2. Anyhow, there is an error when generating the Makefile. Here is the error:
CMake Error at /usr/share/cmake-3.1.2/Modules/FindBoost.cmake:685 (file):
  file STRINGS file "/cygdrive/d/visual studio
  2012/projectA/C:/boost/include/boost-1_54/boost/version.hpp" cannot be
  read.
Call Stack (most recent call first):
  CMakeLists.txt:19 (find_package)


-- Could NOT find Boost
-- No Boost library were found
-- Configuring incomplete, errors occurred!
I have been trying on cygwin, and DOS prompt, it is somewhat weird that the error was happening in FindBoost.cmake. This is the code snippet on the piece that throw an error:
# Set Boost_FOUND based only on header location and version.
# It will be updated below for component libraries.
if(Boost_INCLUDE_DIR)
  if(Boost_DEBUG)
    message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
                   "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp")
  endif()

  # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp
  set(Boost_VERSION 0)
  set(Boost_LIB_VERSION "")
  file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ")
A quick check on ${Boost_INCLUDE_DIR}, it shows C:/boost/include/boost-1_54, but I don't know why there is a default path and why ${Boost_INCLUDE_DIR} appended to that default path. I have tried the workaround on BOOST_ROOT as described here, and here, and also try the workaround on CMAKE_PREFIX_PATH as describe here but none of them work. I also found this link were quite useful, but it doesn't work on find_package command.

I'm running out of clues on this problem. Since the default path was bundled together with CMake as one package, I choose to override Boost_INCLUDE_DIR instead of shake him off away.
  ...

  set(Boost_INCLUDE_DIR /cygdrive/c/boost/include/boost-1_54)
But this isn't a perfect solution as it wouldn't work on Linux since the Boost path is referring to Windows. I'm still searching a solution for this.

Sunday, February 15, 2015

undefined reference of copy_file

./source/main.o: In function `boost::filesystem::copy_file(boost::filesystem::path const&, boost::filesystem::path const&)':
/home/kokhoe/tool/boost_1_54_0/boost/filesystem/operations.hpp:384: undefined reference to `boost::filesystem::detail::copy_file(boost::filesystem::path const&, boost::filesystem::path const&, boost::filesystem::copy_option, boost::system::error_code*)'
collect2: error: ld returned 1 exit status
make: *** [syncFile] Error 1
I got this error when I have the following piece executed:
path source = file_A;
path dest = path_B;
copy_file(source, dest);
Luckily, there is already a programmer had the problem solved (read here), what he did is to put this code before #include <boost/filesystem.hpp>.

#define BOOST_NO_CXX11_SCOPED_ENUMS

Do take note also path_B must be a file name rather than a path name.