(→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 <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(); | ||
+ | } | ||
+ | </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 |
Contents
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:
- 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
- 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
- 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
- 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
- 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.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.)
- 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.
- 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:
- program.exe is the executable being produced.
- ${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/