8.2 Testing program options

(Linux version)

< 8.1 | 8.2 | 9.0 >

Modify main.cpp to contain the following code.

#include &lt;iostream&gt; 
#include "strom.hpp"

using namespace strom;

// static data member initializations
std::string  Strom::_program_name        = "strom";
unsigned     Strom::_major_version       = 1;
unsigned     Strom::_minor_version       = 0;
const double Node::_smallest_edge_length = 1.0e-12;

int main(int argc, const char * argv[]) {
    Strom strom;
    try {
        strom.processCommandLineOptions(argc, argv);
        strom.run();
    }
    catch(std::exception & x) {
        std::cerr &lt;&lt; "Exception: " &lt;&lt; x.what() &lt;&lt; std::endl;
        std::cerr &lt;&lt; "Aborted." &lt;&lt; std::endl;
    }
    catch(...) {
        std::cerr &lt;&lt; "Exception of unknown type!\n";
    }

    return 0;
}   

The main function now creates a Strom object, then passes argc and argv off to the Strom object’s processCommandLineOptions function, and finally calls the Strom object’s run method. Any exceptions thrown are caught and their error messsages displayed to the user.

The main.cpp file will not change very much from now on. Any new options will be added to the Strom class instead.

Static data members

Some data members (_program_name, _major_version, and _minor_version) of the Strom class were declared static. We must therefore initialize these in main.cpp, as it is our only source code file, just like we have been doing for Node::_smallest_edge_length.

Compiling the Boost program_options library

The extra capability we’ve added to our program requires us to:

Compile the Boost program_options library

Navigate to where you previously (in step 5) installed the Boost headers (~/Documents/libraries/boost_1_71_0) and enter the following command:

./bootstrap.sh --with-toolset=gcc --with-libraries=program_options,filesystem,system

The bootstrap.sh script will fairly quickly return, instructing you to type ./b2 to perform the actual compilation.

./b2 cxxflags="-std=c++11" -d 2

Note that I’ve added cxxflags="-std=c++11" to ensure that the Boost libraries are compiled under the same C++ dialect used to compile the main strom program. This will ensure that the libraries can be linked to the strom executable. I’ve also specified -d 2 to specify debugging level 2, which causes the Boost build system to display the compile and link commands it is using (this helps when trying to diagnose what happened if the compiling or linking fails).

Assuming the compilation was successful, you should now see something similar to the following output:

The Boost C++ Libraries were successfully built!

The following directory should be added to compiler include paths:

    /home/plewis/Documents/libraries/boost_1_71_0

The following directory should be added to linker library paths:

    /home/plewis/Documents/libraries/boost_1_71_0/stage/lib

Copy the files libboost_program_options.a, libboost_filesystem.a, and libboost_system.a to the ~/lib/static folder.

Tell meson where to find libboost_program_options.a for linking purposes

Here is the meson.build file we’ve been building up, with the highlighted lines either added or modified to accommodate program options:

project('strom', 'cpp',
    default_options : ['cpp_std=c++11','cpp_link_args=-static','prefix=/home/paul/Documents/strom/distr'],
    version : '1.0')
cpp = meson.get_compiler('cpp')
<span style="color:#0000ff"><strong>lib_program_options = cpp.find_library('boost_program_options', dirs: ['/home/paul/lib/static'], required: true)</strong></span>
lib_ncl = cpp.find_library('ncl', dirs: ['/home/paul/lib/static'], required: true)
incl_ncl = include_directories('/home/paul/include')
incl_boost = include_directories('/home/paul/Documents/libraries/boost_1_71_0')
<span style="color:#0000ff"><strong>executable('strom', 'main.cpp', install: true, install_dir: '.', dependencies: [lib_ncl,lib_program_options], include_directories: [incl_ncl,incl_boost])</strong></span>
install_data('test.tre', install_dir: '.')

Note the meson variable lib_program_options stores the location of the libboost_program_options.a, and this variable is added to the lib_ncl variable to form a list that is supplied to the dependencies argument to the executables command.

The last line in the meson.build file copies the test.tre file to the distr directory so that it will be available in the same directory as the strom executable when you test the program.

Running strom

If you run the program now by typing simply ./strom, from your ~/Documents/strom/distr directory, you should see an error message:

Exception: the option '--treefile' is required but missing

Why did we get this error message? Try running the program like this from the command line:

./strom --treefile test.tre

Because the name of the tree file is no longer hard-coded in the main function, the program forces you to supply these file names.

Expected output

Here is the output you should see if everything is working correctly:

Note: configuration file (strom.conf) not found
Starting...
storing read block: TAXA
storing read block: TREES

Read 14 trees from file
Topology 1 seen in these 4 trees:
  10 11 12 13 
Topology 2 seen in these 2 trees:
  8 9 
Topology 3 seen in these 8 trees:
  0 1 2 3 4 5 6 7 

Topologies sorted by sample frequency:
            topology            frequency
                   3                    8
                   1                    4
                   2                    2

Finished!

If the lines in your output are flooded with lines such as “Creating Node object” and “Destroying Node object”, then you failed to heed the advise in the section “Lost at sea” at the very bottom of the Test the TreeSummary class page.

You may have wondered about this line:

Note: configuration file (strom.conf) not found

The Boost program_options library makes it possible to store command line options inside a configuration file rather than entering them from the command line. If you create a file named strom.conf inside the install directory (~/Documents/strom/distr) containing these two lines…

# this is a comment
treefile = test.tre

you should be able to run strom without specifying any command line options. You may wish to create the strom.conf file inside your src directory and add a line to your meson.build file to copy it to the install directory.

Note that in the config file the convention is to use key/value pairs, whereas on the command line, -- is the convention. Be sure to use one key/value pair per line, and note that lines starting with # are ignored (this feature can be used to insert comments into your configuration files).

< 8.1 | 8.2 | 9.0 >