From Documentation
Jump to: navigation, search
(Compiling Programs Using CMake With Boost)
(Building an Example Boost Program)
Line 260: Line 260:
 
<pre>
 
<pre>
 
$ mpirun -np 2 ./a.out
 
$ mpirun -np 2 ./a.out
 +
</pre>
 +
 +
== A Header-Only Example ==
 +
 +
Many libraries in Boost are header-only (i.e., the program does not need to be linked to a library). With header-only libraries one does not specify any linking options when compiling/linking the code.
 +
 +
Consider the following Boost.Multiprecision program:
 +
 +
<pre>
 +
// This program's code combines code from the following Boost.Multiprecision documentation's pages:
 +
//  1) http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/cpp_int.html
 +
//  2) http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/cpp_bin_float.html
 +
//  3) http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/cpp_dec_float.html
 +
 +
#include &lt;boost/multiprecision/cpp_int.hpp&gt;
 +
#include &lt;boost/multiprecision/cpp_bin_float.hpp&gt;
 +
#include &lt;boost/multiprecision/cpp_dec_float.hpp&gt;
 +
#include &lt;boost/math/special_functions/gamma.hpp&gt;
 +
#include &lt;iostream&gt;
 +
 
 +
void mp_int()
 +
{
 +
  // For integer type docs see:
 +
  // http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints.html
 +
 +
  // Example Boost docs code follows...
 +
 +
  using namespace boost::multiprecision;
 +
 +
  // Do some fixed precision arithmetic:
 +
  int128_t v = 1;
 +
  for (unsigned i = 1; i &lt;= 20; ++i)
 +
    v *= i;
 +
  std::cout &lt;&lt; v &lt;&lt; std::endl; // prints 20
 +
 +
  // Repeat at arbitrary precision:
 +
  cpp_int u = 1;
 +
  for (unsigned i = 1; i &lt;= 100; ++i)
 +
    u *= i;
 +
  std::cout &lt;&lt; u &lt;&lt; std::endl; // prints 100
 +
}
 +
 +
void mp_bin_float()
 +
{
 +
  // For floating-point type docs see:
 +
  // http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats.html
 +
 +
  // Example Boost docs code follows...
 +
 +
  using namespace boost::multiprecision;
 +
 +
  // Operations at fixed precision and full numeric_limits support:
 +
  cpp_bin_float_100 b = 2;
 +
  std::cout &lt;&lt; std::numeric_limits&lt;cpp_bin_float_100&gt;::digits &lt;&lt; std::endl;
 +
  std::cout &lt;&lt; std::numeric_limits&lt;cpp_bin_float_100&gt;::digits10 &lt;&lt; std::endl;
 +
 +
  // We can use any C++ std lib function, lets print all the digits as well:
 +
  std::cout &lt;&lt; std::setprecision(std::numeric_limits&lt;cpp_bin_float_100&gt;::max_digits10)
 +
      &lt;&lt; log(b) &lt;&lt; std::endl; // print log(2)
 +
 +
  // We can also use any function from Boost.Math:
 +
  std::cout &lt;&lt; boost::math::tgamma(b) &lt;&lt; std::endl;
 +
 +
  // These even work when the argument is an expression template:
 +
  std::cout &lt;&lt; boost::math::tgamma(b * b) &lt;&lt; std::endl;
 +
 +
  // And since we have an extended exponent range we can generate some really large
 +
  // numbers here (4.0238726007709377354370243e+2564):
 +
  std::cout &lt;&lt; boost::math::tgamma(cpp_bin_float_100(1000)) &lt;&lt; std::endl;
 +
}
 +
 +
void mp_dec_float()
 +
{
 +
  using namespace boost::multiprecision;
 +
 +
  // Operations at fixed precision and full numeric_limits support:
 +
  cpp_dec_float_100 b = 2;
 +
  std::cout &lt;&lt; std::numeric_limits&lt;cpp_dec_float_100&gt;::digits &lt;&lt; std::endl;
 +
 +
  // Note that digits10 is the same as digits, since we&apos;re base 10! :
 +
  std::cout &lt;&lt; std::numeric_limits&lt;cpp_dec_float_100&gt;::digits10 &lt;&lt; std::endl;
 +
 +
  // We can use any C++ std lib function, lets print all the digits as well:
 +
  std::cout &lt;&lt; std::setprecision(std::numeric_limits&lt;cpp_dec_float_100&gt;::max_digits10)
 +
      &lt;&lt; log(b) &lt;&lt; std::endl; // print log(2)
 +
 +
  // We can also use any function from Boost.Math:
 +
  std::cout &lt;&lt; boost::math::tgamma(b) &lt;&lt; std::endl;
 +
 +
  // These even work when the argument is an expression template:
 +
  std::cout &lt;&lt; boost::math::tgamma(b * b) &lt;&lt; std::endl;
 +
 +
  // And since we have an extended exponent range we can generate some really large
 +
  // numbers here (4.0238726007709377354370243e+2564):
 +
  std::cout &lt;&lt; boost::math::tgamma(cpp_dec_float_100(1000)) &lt;&lt; std::endl;
 +
}
 +
 +
 +
int main()
 +
{
 +
  mp_int();
 +
  mp_bin_float();
 +
  mp_dec_float();
 +
}
 +
</pre>
 +
 +
It be compiled and run using GCC v6.3.0 as follows:
 +
 +
<pre>
 +
$ module unload gcc intel openmpi mkl boost
 +
$ module load gcc/6.3.0 boost/gcc630/1.63.0
 +
$ g++ -I$BOOST_ROOT/include boost-multiprecision.cxx
 +
$ ./a.out
 +
</pre>
 +
 +
or with Intel v17.0.1:
 +
 +
<pre>
 +
$ module unload gcc intel openmpi mkl boost
 +
$ module load intel/17.0.1 boost/intel1701/1.63.0
 +
$ icpc -I$BOOST_ROOT/include boost-multiprecision.cxx
 +
$ ./a.out
 
</pre>
 
</pre>
  

Revision as of 14:44, 17 March 2017

BOOST
Description: free peer-reviewed portable C++ source libraries
SHARCNET Package information: see BOOST software page in web portal
Full list of SHARCNET supported software


Which Versions of Boost are Available?

SHARCNET has a number of Boost versions available as special modules. The available versions can be viewed by running:

module avail boost

and/or by viewing the BOOST software page in the web portal.

When you look up the available boost modules you will see output similar tossh-:

$ module avail boost

------------------------------------------------ /opt/sharcnet/modules -------------------------------------------------
boost/gcc482-openmpi183/1.53.0         boost/gcc510-openmpi187/1.59.0         boost/intel1503-openmpi187/1.59.0
boost/gcc482-openmpi183/1.55.0         boost/gcc510-openmpi187debug/1.59.0    boost/intel1503-openmpi187debug/1.59.0
boost/gcc492-openmpi187/1.59.0         boost/intel12-openmpi162/1.53.0
boost/gcc492-openmpi187debug/1.59.0    boost/intel12-openmpi162/1.55.0
$

i.e., the following versions of Boost are available:

  1. versions 1.53 and 1.55 built with GCC v4.8.2 and OpenMPI v1.8.3
    • i.e., boost/gcc482-openmpi183/1.53.0 and boost/gcc482-openmpi183/1.55.0
  2. version 1.59 built with GCC v4.9.2 and non-debug and debug versions of OpenMPI v1.8.7
    • i.e.,, boost/gcc492-openmpi187/1.59.0 and boost/gcc492-openmpi187debug/1.59.0
  3. version 1.59 built with GCC v5.1.0 and non-debug and debug versions of OpenMPI v1.8.7
    • i.e., boost/gcc510-openmpi187/1.59.0 and boost/gcc510-openmpi187debug/1.59.0
  4. versions 1.53 and 1.55 built with Intel v12 and OpenMPI v1.6.2
    • i.e., boost/intel12-openmpi162/1.53.0 and boost/intel12-openmpi162/1.55.0
  5. version 1.59 built with Intel v15.0.3 and non-debug and debug versions of OpenMPI v1.8.7
    • i.e., boost/intel1503-openmpi187/1.59.0 and boost/intel1503-openmpi187debug/1.59.0

NOTE: You may experience problems compiling Boost codes with the Intel v12 compiler (e.g., some incompatible headers). If you do, try the GCC compiler to see if that works.

All of the aforementioned versions of Boost have been built with the operating system's installed Python. You can see which version of Python it will use by running:

rpm -qi python

NOTE: If you need a specific version of Boost compiled for a specific C++ compiler, version of OpenMPI, and/or a specific version of Python, then submit a ticket requesting such. Be sure to mention all required software packages and which versions are needed.

Loading a module

To load a specific module of Boost simply use "module load" followed by the module name, e.g.,

module load boost/intel1503-openmpi187debug/1.59.0

If an error occurs, ensure that you load all pre-requisite modules first. Often it is easier to remove all modules, load the required ldwrapper module (which is needed for your programs to work when submitted using sqsub), and the the modules you need to use, e.g.,

$ module purge
$ module load ldwrapper
$ module load gcc/5.1.0
$ module load openmpi/gcc-5.1.0/std/1.8.7
$ module load boost/gcc510-openmpi187/1.59.0

Compiling Programs Using CMake With Boost

With CMake you will want code similar to the following to properly load Boost:

find_package(
    Boost 1.56.0 REQUIRED
    COMPONENTS
        filesystem
        system
)

where:

  1. 1.56.0 is the MINIMUM version that can be used by your program. You should replace this with the version you are using, e.g., 1.59.0. (Know that omitting the minimum version setting can cause issues with CMake not finding Boost.)
  2. REQUIRED means that if the minimum version is not about to be used, an error will occur and compilation will be aborted. Generally it is a good idea to use REQUIRED to avoid cryptic compilation error messages when an incompatible version of Boost is used.
  3. If you use any Boost components that have library code that must be linked into your program, you will need to specify COMPONENTS followed by the names of those components.

If CMake finds the wrong version of boost. Try telling CMake to not use the built in boost system path:

set(Boost_NO_SYSTEM_PATHS ON)

This will cause CMake to look at the BOOST_ROOT environment variable, instead of the default locations.

You can view the names of all required-to-be-linked-to-a-library components for the version of Boost you are using by running the following command (after using "module load" to load the version of Boost you want to use):

ls -1 $BOOST_ROOT/lib/libboost*{so,a}* | xargs -n 1 basename | sed -e 's/^libboost_//' -e 's/\.so.*$//' -e 's/\.a.*$//' | sort -u

which will output something similar to this:

$ ls -1 $BOOST_ROOT/lib/libboost*{so,a}* | xargs -n 1 basename | sed -e 's/^libboost_//' -e 's/\.so.*$//' -e 's/\.a.*$//' | sort -u
atomic
chrono
context
coroutine
date_time
exception
filesystem
graph
graph_parallel
iostreams
locale
log
log_setup
math_c99
math_c99f
math_c99l
math_tr1
math_tr1f
math_tr1l
mpi
prg_exec_monitor
program_options
python
random
regex
serialization
signals
system
test_exec_monitor
thread
timer
unit_test_framework
wave
wserialization
$

Some of the library components depend on other components. For example, the "filesystem" component depends on the "system" component --so both of these must be specified in the find_package() CMake function call.

You also will need lines similar to the follwing in your CMakeLists.txt:

add_executable(
    program.exe
    src/somecode.cxx
)

target_link_libraries(
    program.exe
    ${Boost_LIBRARIES}
)

where:

  1. program.exe is the executable being produced.
  2. ${Boost_LIBRARIES} is set by the find_package() function and contains all of the libraries it discovered (for the listed COMPONENTS section above).

NOTE: With the target_link_libraries() set, you do not need or want to set LD_LIBRARY_PATH at all for Boost to work, i.e., if you are loading the SHARCNET module, everything is properly set. (With CMake you must tell it which libraries must be linked in to your executable --it is not automatic.)

Using a Specific Version of Boost

To use a specific version of Boost, do the following:

  • Unload any loaded OpenMPI modules that will conflict.
  • Unload any loaded C++ compiler modules that will conflict.
  • Load any required C++ and OpenMPI modules.
  • Load the required version of Boost.

e.g.,

$ module list                                 # View which modules are currently loaded
$ module unload openmpi/intel/1.6.2           # Unload the OpenMPI (for Intel)
$ module unload intel/12.1.3                  # Unload the Intel C++ compiler
$ module load gcc/4.8.2                       # Load GCC v4.8.2
$ module load openmpi/gcc/1.8.3               # Load OpenMPI (for GCC)
$ module load boost/gcc482-openmpi183/1.57.0  # Load Boost v1.57 for GCC 4.8.2 and OpenMPI v1.8.3

Once this is done, you may use Boost (e.g., write #include <boost/filesystem.hpp> in your code, etc.). No special compiler options will be required.

If you want to start with NO modules loaded, then you can do the same by purging first, loading ldwrapper, followed by what you need, e.g.,

$ module purge
$ module load ldwrapper
$ module load gcc/4.8.2                       # Load GCC v4.8.2
$ module load openmpi/gcc/1.8.3               # Load OpenMPI (for GCC)
$ module load boost/gcc482-openmpi183/1.57.0  # Load Boost v1.57 for GCC 4.8.2 and OpenMPI v1.8.3

If Special Compiler Options are Required

If you are not having success building your code using Boost (e.g., in a Makefile), you might need to manually specify the INCLUDE and LIB directories. You can get these paths by running the following command (replacing the full Boost module name with the one you've loaded), e.g.,

$ module show boost/gcc482-openmpi183/1.57.0
-------------------------------------------------------------------
/opt/sharcnet/modules/boost/gcc482-openmpi183/1.57.0:

module-whatis    Provides boost 1.57.0 (flavor gcc482-openmpi183) built using gcc/4.8.2, openmpi/gcc/1.8.3 on centos64.
conflict         intel
conflict         pgi
conflict         python
prereq   gcc/4.8.2
prereq   openmpi/gcc/1.8.3
prepend-path     --delim   CPPFLAGS -I/opt/sharcnet/boost/1.57.0/gcc482-openmpi183/include
prepend-path     --delim   LDFLAGS -L/opt/sharcnet/boost/1.57.0/gcc482-openmpi183/lib
prepend-path     LD_RUN_PATH /opt/sharcnet/boost/1.57.0/gcc482-openmpi183/lib
-------------------------------------------------------------------
$

i.e., for Boost 1.57.0 (flavour gcc482-openmpi183) you could explicitly invoke the compiler with:

g++ $CPPFLAGS $CXXFLAGS $LDFLAGS yoursourcecode.cxx

Also be aware that you must specify any Boost-required libraries for linking purposes using the -l option. You can see the actual available library names for any given Boost installation by running:

$ for a in `ls $BLIBS` ; do basename $a ; done

where $BLIBS is the directory you see with LDFLAGS in the module show output, thus, to see all libraries available with the gcc482-openmpi183/lib module, you would write:

$ for a in `ls /opt/sharcnet/boost/1.57.0/gcc482-openmpi183/lib/libboost_*` ; do basename $a ; done

NOTE: Using the -l option is important when using any non-header-only Boost library, e.g., MPI, serialization, program_options, etc.


Building an Example Boost Program

First create/write/copy your program somewhere suitable (this example is from the Boost.MPI documentation):

$ cd
$ mkdir boost-test
$ cat >boost-mpi-eg.cxx
#include <iostream>
#include <string>
#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>

namespace mpi = boost::mpi;

int main(int argc, char *argv[])
{
  mpi::environment env(argc, argv);
  mpi::communicator world;

  if (world.rank() == 0) {
    world.send(1, 0, std::string("Hello"));
    std::string msg;
    world.recv(1, 1, msg);
    std::cout << msg << "!" << std::endl;
  } else {
    std::string msg;
    world.recv(0, 0, msg);
    std::cout << msg << ", ";
    std::cout.flush();
    world.send(0, 1, std::string("world"));
  }

  return 0;
}
$

compile it:

$ mpic++ $CPPFLAGS $CXXFLAGS $LDFLAGS -lboost_mpi -lboost_serialization boost-mpi-eg.cxx

and run it (as it is very fast and short, sqsub is not used here):

$ mpirun -np 2 ./a.out

A Header-Only Example

Many libraries in Boost are header-only (i.e., the program does not need to be linked to a library). With header-only libraries one does not specify any linking options when compiling/linking the code.

Consider the following Boost.Multiprecision program:

// This program's code combines code from the following Boost.Multiprecision documentation's pages:
//   1) http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/cpp_int.html
//   2) http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/cpp_bin_float.html
//   3) http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/cpp_dec_float.html

#include <boost/multiprecision/cpp_int.hpp> 
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp> 
#include <boost/math/special_functions/gamma.hpp>
#include <iostream>
  
void mp_int()
{
  // For integer type docs see:
  // http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints.html

  // Example Boost docs code follows...

  using namespace boost::multiprecision;

  // Do some fixed precision arithmetic:
  int128_t v = 1;
  for (unsigned i = 1; i <= 20; ++i)
    v *= i;
  std::cout << v << std::endl; // prints 20

  // Repeat at arbitrary precision:
  cpp_int u = 1;
  for (unsigned i = 1; i <= 100; ++i)
    u *= i;
  std::cout << u << std::endl; // prints 100
}

void mp_bin_float()
{
  // For floating-point type docs see:
  // http://www.boost.org/doc/libs/1_63_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats.html

  // Example Boost docs code follows...

  using namespace boost::multiprecision;

   // Operations at fixed precision and full numeric_limits support:
   cpp_bin_float_100 b = 2;
   std::cout << std::numeric_limits<cpp_bin_float_100>::digits << std::endl;
   std::cout << std::numeric_limits<cpp_bin_float_100>::digits10 << std::endl;

   // We can use any C++ std lib function, lets print all the digits as well:
   std::cout << std::setprecision(std::numeric_limits<cpp_bin_float_100>::max_digits10)
      << log(b) << std::endl; // print log(2)

   // We can also use any function from Boost.Math:
   std::cout << boost::math::tgamma(b) << std::endl;

   // These even work when the argument is an expression template:
   std::cout << boost::math::tgamma(b * b) << std::endl;

   // And since we have an extended exponent range we can generate some really large 
   // numbers here (4.0238726007709377354370243e+2564):
   std::cout << boost::math::tgamma(cpp_bin_float_100(1000)) << std::endl;
}

void mp_dec_float()
{
   using namespace boost::multiprecision;

   // Operations at fixed precision and full numeric_limits support:
   cpp_dec_float_100 b = 2;
   std::cout << std::numeric_limits<cpp_dec_float_100>::digits << std::endl;

   // Note that digits10 is the same as digits, since we're base 10! :
   std::cout << std::numeric_limits<cpp_dec_float_100>::digits10 << std::endl;

   // We can use any C++ std lib function, lets print all the digits as well:
   std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_100>::max_digits10)
      << log(b) << std::endl; // print log(2)

   // We can also use any function from Boost.Math:
   std::cout << boost::math::tgamma(b) << std::endl;

   // These even work when the argument is an expression template:
   std::cout << boost::math::tgamma(b * b) << std::endl;

   // And since we have an extended exponent range we can generate some really large 
   // numbers here (4.0238726007709377354370243e+2564):
   std::cout << boost::math::tgamma(cpp_dec_float_100(1000)) << std::endl;
}


int main()
{
  mp_int();
  mp_bin_float();
  mp_dec_float();
}

It be compiled and run using GCC v6.3.0 as follows:

$ module unload gcc intel openmpi mkl boost
$ module load gcc/6.3.0 boost/gcc630/1.63.0
$ g++ -I$BOOST_ROOT/include boost-multiprecision.cxx
$ ./a.out

or with Intel v17.0.1:

$ module unload gcc intel openmpi mkl boost
$ module load intel/17.0.1 boost/intel1701/1.63.0
$ icpc -I$BOOST_ROOT/include boost-multiprecision.cxx
$ ./a.out

Operating System Installed Boost

If you don't load a SHARCNET boost module, your program will most likely link to the operating system's installed version of Boost. To determine which version(s) of boost and boost-devel are installed run the following commands:

rpm -qi boost
rpm -qi boost-devel

NOTE: System versions are rather old and won't be upgraded or maintained by SHARCNET staff unless something in the operating system requires it to be updated. Therefore we strongly encourag using the SHARCNET provided Boost modules discussed above on this page.

References

o Boost Homepage
http://www.boost.org/