Modify main.cpp to contain the following code.
#include <iostream>
#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 << "Exception: " << x.what() << std::endl;
std::cerr << "Aborted." << std::endl;
}
catch(...) {
std::cerr << "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.
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
.
The extra capability we’ve added to our program requires us to:
program_options
library,Open the Terminal or iTerm2 app and navigate to where you previously installed the Boost headers (~/Documents/libraries/boost_1_71_0), then enter the following command:
./bootstrap.sh --with-toolset=clang --with-libraries=program_options,filesystem,system
Note that I’ve added filesystem
and system
to the list of Boost libraries to compile. We will make use of these later, so we might as well compile them now so that we do not need to rerun the bootstrap.sh script again.
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.
In the Xcode main menu, choose View > Navigators > Show Project Navigator, then click on the blue project icon labeled strom at the top of the Project Navigator. Click on the Build Phases tab. Click the +
sign in Link Binary With Libraries and (after clicking the Add Other… button) navigate to the directory ~/lib/static and select the libboost_program_options.a, libboost_filesystem.a, and libboost_system.a files. This informs Xcode where to find the compiled library code for purposes of linking the library into your program’s executable file.
You have already specified the $(BOOST_ROOT)
custom path in the “Header Search Paths” section of Build Settings, and you’ve specified ~/lib/static in the Library Search Paths section of Build Settings, so there is nothing more that needs to be done.
To specify command line arguments when your program is run inside the debugger, follow these steps:
At the top of the Xcode window, to the right of the (run program in debugger) and (stop program running in debugger) buttons, click on the button labeled “strom” (attached to the button labeled “My Mac”).
Choose “Edit Scheme…” from the popup menu, then choose the “Arguments” tab and click the +
button under “Arguments Passed On Launch”.
Click the +
button 1 more time so that there are places for a total of 2 arguments
--treefile
into the first slottest.tre
into the second slotYou can now close the dialog box using the Close button at the bottom right and run the program.
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 the program without specifying any command line options (try unchecking or deleting both --treefile
and test.tre
rows under “Arguments Passed On Launch”).
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).