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.

Tuesday, February 10, 2015

Finding index of Nth occurrence of a string

Recently I was working on a task that require me to find the Nth occurrence of a string. In other words, this function should return the position index of Nth occurrence. For example, the 2nd occurrence of o in a string hello world will locate at 7. Thus, I have following code created for this:
int searchNth(const char* work, const char* find, const int nth) {

 int work_len = strlen(work);
 int find_len = strlen(find);
 int match_count = 0;
 int match_index_pos = -1;
 int occurrence = -1;

 for (int i = 0; i < work_len; i++) {

  if (work[i] == find[match_count]) {
   match_count++;

   if (match_count == 1) {
    match_index_pos = i;
   }
  }
  else if (match_count > 0 && work[i] != find[match_count]) {
   match_count = 0;
   match_index_pos = -1;
  }

  if (find_len == match_count) {
   occurrence++;
  }

  if (nth == occurrence) {
   return match_index_pos;
  }
 }

 return -1;
}
Sample of execution:

searchNth("hello world", "o", 1); // output: 7
searchNth("hello world", "o", 2); // output: -1
searchNth("hello world", "o ", 0); // output: 4

Well, I'm pretty proud of myself because I have created such a nice piece of code that could return the nth occurrence of a string. (Not really!) Someone has better solution than mine. I just found the answer in this thread.
size_t find_Nth(
    const std::string & str ,   // where to work
    unsigned            N ,     // N'th ocurrence
    const std::string & find    // what to 'find'
) {
    if ( 0==N ) { return std::string::npos; }
    size_t pos,from=0;
    unsigned i=0;
    while ( i<N ) {
        pos=str.find(find,from);
        if ( std::string::npos == pos ) { break; }
        from = pos + 1; // from = pos + find.size();
        ++i;
    }
    return pos;
/**
    It would be more efficient to use a variation of KMP to
    benefit from the failure function.
    - Algorithm inspired by James Kanze.
    - http://stackoverflow.com/questions/20406744/
*/
}
What a nice piece. The code is much cleaner than mine, lesser if statement, easier to digest with human brain. (Perfect!) Somehow, here is still better one. Believe or not, Boost library did have such algorithm developed:
    string work = "hello world";
    iterator_range<string::iterator> r = find_nth(work, "o", 1);
    cout << distance(work.begin(), r.begin()) << endl;
Wow!!! This piece was just damn real simple. From the top most till the bottom, although there are producing the same output, but the implementation was totally different. I can see the code is evolving gradually. What is next? What else can be done in the future? Fewer code?

Last but not least, thanks to Boost algorithm, nice work!

class not found in wsgen

When I have finished coding on the web service (using document style), I'm ready to generate extra classes with wsgen. Usually the following command will be used for this purpose.

wsgen -keep -cp . org.huahsin.HelloWorld

Anyhow, this command is incomplete because I receive a class not found error immediately as shown below:
C:\workspace\WebService1>wsgen -verbose -cp . org.huahsin.HelloWorld
Class not found: "org.huahsin.HelloWorld"


Usage: WSGEN [options] 

...
...

Referring to the wsgen documentation, it did mention that the -classpath or -cp is referring to an input class file, not the source file. Thus to ensure the command above work correctly, change to the root of the project directory (not bin/ or src/), then fire the command with -cp point to bin/ instead of current directory like this:

wsgen -verbose -cp ./bin org.huahsin.HelloWorld

Besides that, I notice this command doesn't keep the source files after the extra class files being generated. To keep the source files, command below would help:

wsgen -verbose -cp ./bin -s ./src org.huahsin.HelloWorld

Tuesday, February 3, 2015

How to switch on C++11 on Eclipse?

This is, somehow, quite annoying me. I was compiling C++11 on Eclipse Kepler, but there was an error (as shown below) complaining to me that I must enable C++11 in order to proceed. But where is the C++11 switch?
Invoking: Cygwin C++ Compiler
g++ -I"D:\tool\boost_1_54_0" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/main.d" -MT"src/main.d" -o "src/main.o" "../src/main.cpp"
In file included from /usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/initializer_list:36:0,
                 from ../src/main.cpp:6:
/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
 #error This file requires compiler and library support for the \
  ^
In file included from D:\tool\boost_1_54_0/boost/filesystem/path_traits.hpp:23:0,
                 from D:\tool\boost_1_54_0/boost/filesystem/path.hpp:25,
                 from D:\tool\boost_1_54_0/boost/filesystem.hpp:16,
                 from ../src/main.cpp:7:
D:\tool\boost_1_54_0/boost/system/error_code.hpp:222:36: warning: 'boost::system::posix_category' defined but not used [-Wunused-variable]
src/subdir.mk:18: recipe for target 'src/main.o' failed
     static const error_category &  posix_category = generic_category();
                                    ^
D:\tool\boost_1_54_0/boost/system/error_code.hpp:223:36: warning: 'boost::system::errno_ecat' defined but not used [-Wunused-variable]
     static const error_category &  errno_ecat     = generic_category();
                                    ^
D:\tool\boost_1_54_0/boost/system/error_code.hpp:224:36: warning: 'boost::system::native_ecat' defined but not used [-Wunused-variable]
     static const error_category &  native_ecat    = system_category();

The switch was locate at project's properties > C/C++ Build > Settings > Tool Settings tab > Cygwin C++ Compiler > Miscellenous, put -std=c++11 in the Other Flags to switch on C++11 (append on it if it is not empty). Then the compilation will proceed as usual.

Unresolved inclusion on Eclipse

I have a C++ project which pretty well developed on Linux with Eclipse Kepler. Since this program is very well developed on Linux, I was thinking to have one Windows version as well. Since the development was done on Eclipse, the transition process should be super easy. But in fact, it wasn't.

I was using cygwin tool chain for my case, it doesn't compile as expected. There are so many unresolved error lying around, such as Unresolved inclusion: <iostream> is one of the example. This error was weird to me as the compiler was unable to find the header files. I was thinking this could be cause by cygwin path is different from regular path. Maybe path mapping could help? Go to project's properties > C/C++ > Debug >  Source Lookup Path, add a new path mapping as shown below:


Compilation path Local file system path
\cygdrive\c C:\
\cygdrive\d D:\

Since I got 2 partitions on my hard drive, I just put them all to let Eclipse search what it needs. Rebuild the project and the error still exists.

It took me a decade to work around this issue only realize that I was missing the configuration in C/C++ General > Preprocessor Include Paths, Macros etc > Providers tab > CDT GCC Builtin Compiler Settings Cygwin [shared] wasn't selected. Guess what? Without this option being selected, I suppose, to see the complain.