Change gflags to Make It Work With boost::program_options

I changed the gflags-1.4/src/gflags.cc file to make it does not treat “undefined” flags as errors, which cause program fail. The patch content is as follows:

1049,1058c1049,1050
<       // NOTE(yiwang): here the original code invokes
<       //
<       //   undefined_names_[key] = "";    // value isn't actually used
<       //   error_flags_[key] = error_message;
<       //
<       // however, I commented these two lines out, because SplitArgumentLocked
<       // returns NULL only if it does not recognize the flag name, and we do
<       // not want to treat unrecognizable flag names as errors, when we want to
<       // make gflags work together with other flag parsing toolkit such as
<       // boost::program_options.
---
>       undefined_names_[key] = "";    // value isn't actually used
>       error_flags_[key] = error_message;

A test program is as follows:

#include <sys/utsname.h>

#include <iostream>                     // DEBUG
#include <string>
#include <vector>

#include <boost/program_options/option.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>

#include "glog/logging.h"
#include "gflags/gflags.h"
#include "mpi.h"

#include "../strutil/stringprintf.hh"

using std::string;
using std::vector;

DEFINE_string(lda_vocab_file, "",
              "This flag is a gflags flag, useless except test.");

int main(int argc, char** argv) {
  MPI_Init(&argc, &argv);

  std::cout << "Parameters after MPI_Init:\n";
  for (int i = 0; i < argc; ++i) {
    std::cout << "option " << i << " : " << argv[i] << "\n";
  }


  google::ParseCommandLineFlags(&argc, &argv, false);

  std::cout << "Parameters after ParseCommandLineFlags:\n";
  for (int i = 0; i < argc; ++i) {
    std::cout << "option " << i << " : " << argv[i] << "\n";
  }

  // Initialize glog and set log destination file.
  google::InitGoogleLogging(argv[0]);
  struct utsname buf;
  if (0 != uname(&buf)) {
    *buf.nodename = '\0'; // ensure null termination on failure
  }
  google::SetLogDestination(google::INFO,
                            StringPrintf(
                                "/tmp/ohmygod.%s.%s.INFO.",
                                buf.nodename, getenv("USER")).c_str());
  google::SetLogDestination(google::ERROR,
                            StringPrintf(
                                "/tmp/ohmygod.%s.%s.ERROR.",
                                buf.nodename, getenv("USER")).c_str());

  // Parse command line flags left after google::ParseCommandLineFlags.
  namespace po = boost::program_options;

  po::options_description desc("Supported options");
  desc.add_options()
      ("mrml_help",
       "Produce help message.")
      ("mrml_map_only",
       po::value<bool>()->default_value(false),
       "Specify a map-only mapreduce task, and must not specify reduce class.")
      ;

  vector<string> rest_options;
  po::variables_map vm;
  try {
    po::parsed_options parsed = po::command_line_parser(argc, argv).
                                options(desc).allow_unregistered().run();
    po::store(parsed, vm);
    po::notify(vm);
    rest_options =
        po::collect_unrecognized(parsed.options, po::include_positional);
  } catch (const po::error& e) {
    LOG(ERROR) << "Error in parsing command line options: " << e.what();
    return false;
  }

  // Print help message if requested.
  if (vm.count("mrml_help")) {
    std::cout << desc << "\n";
  }

  std::cout << "Set lda_vocab_file = " << FLAGS_lda_vocab_file << "\n";

  LOG(INFO) << "Hello world!";
  return 0;
}