Caffe2 - C++ API
A deep learning, cross platform ML framework
flags.cc
1 
17 #include "caffe2/core/flags.h"
18 
19 #include <cstdlib>
20 #include <sstream>
21 
22 #include "caffe2/core/logging.h"
23 
24 namespace caffe2 {
25 
26 #ifdef CAFFE2_USE_GFLAGS
27 
28 void SetUsageMessage(const string& str) {
29  if (UsageMessage() != nullptr) {
30  // Usage message has already been set, so we will simply return.
31  return;
32  }
33  gflags::SetUsageMessage(str);
34 }
35 
36 const char* UsageMessage() {
37  return gflags::ProgramUsage();
38 }
39 
40 bool ParseCaffeCommandLineFlags(int* pargc, char*** pargv) {
41  if (*pargc == 0) return true;
42  return gflags::ParseCommandLineFlags(pargc, pargv, true);
43 }
44 
46  // There is no way we query gflags right now, so we will simply return true.
47  return true;
48 }
49 
50 #else // CAFFE2_USE_GFLAGS
51 
52 
53 CAFFE_DEFINE_REGISTRY(Caffe2FlagsRegistry, Caffe2FlagParser, const string&);
54 
55 namespace {
56 static bool gCommandLineFlagsParsed = false;
57 // Since caffe flags is going to be loaded before caffe logging, we would
58 // need to have a stringstream to hold the messages instead of directly
59 // using caffe logging.
60 std::stringstream& GlobalInitStream() {
61  static std::stringstream ss;
62  return ss;
63 }
64 static string gUsageMessage = "(Usage message not set.)";
65 }
66 
67 
68 void SetUsageMessage(const string& str) { gUsageMessage = str; }
69 const char* UsageMessage() { return gUsageMessage.c_str(); }
70 
71 bool ParseCaffeCommandLineFlags(int* pargc, char*** pargv) {
72  if (*pargc == 0) return true;
73  char** argv = *pargv;
74  bool success = true;
75  GlobalInitStream() << "Parsing commandline arguments for caffe2."
76  << std::endl;
77  // write_head is the location we write the unused arguments to.
78  int write_head = 1;
79  for (int i = 1; i < *pargc; ++i) {
80  string arg(argv[i]);
81 
82  if (arg.find("--help") != string::npos) {
83  // Print the help message, and quit.
84  std::cout << UsageMessage() << std::endl;
85  std::cout << "Arguments: " << std::endl;
86  for (const auto& help_msg : Caffe2FlagsRegistry()->HelpMessage()) {
87  std::cout << " " << help_msg.first << ": " << help_msg.second
88  << std::endl;
89  }
90  exit(0);
91  }
92  // If the arg does not start with "--", we will ignore it.
93  if (arg[0] != '-' || arg[1] != '-') {
94  GlobalInitStream()
95  << "Caffe2 flag: commandline argument does not match --name=var "
96  "or --name format: "
97  << arg << ". Ignoring this argument." << std::endl;
98  argv[write_head++] = argv[i];
99  continue;
100  }
101 
102  string key;
103  string value;
104  int prefix_idx = arg.find('=');
105  if (prefix_idx == string::npos) {
106  // If there is no equality char in the arg, it means that the
107  // arg is specified in the next argument.
108  key = arg.substr(2, arg.size() - 2);
109  ++i;
110  if (i == *pargc) {
111  GlobalInitStream()
112  << "Caffe2 flag: reached the last commandline argument, but "
113  "I am expecting a value for " << arg;
114  success = false;
115  break;
116  }
117  value = string(argv[i]);
118  } else {
119  // If there is an equality character, we will basically use the value
120  // after the "=".
121  key = arg.substr(2, prefix_idx - 2);
122  value = arg.substr(prefix_idx + 1, string::npos);
123  }
124  // If the flag is not registered, we will ignore it.
125  if (!Caffe2FlagsRegistry()->Has(key)) {
126  GlobalInitStream() << "Caffe2 flag: unrecognized commandline argument: "
127  << arg << std::endl;
128  success = false;
129  break;
130  }
131  std::unique_ptr<Caffe2FlagParser> parser(
132  Caffe2FlagsRegistry()->Create(key, value));
133  if (!parser->success()) {
134  GlobalInitStream() << "Caffe2 flag: illegal argument: "
135  << arg << std::endl;
136  success = false;
137  break;
138  }
139  }
140  *pargc = write_head;
141  gCommandLineFlagsParsed = true;
142  // TODO: when we fail commandline flag parsing, shall we continue, or
143  // shall we just quit loudly? Right now we carry on the computation, but
144  // since there are failures in parsing, it is very likely that some
145  // downstream things will break, in which case it makes sense to quit loud
146  // and early.
147  if (!success) {
148  std::cerr << GlobalInitStream().str();
149  }
150  // Clear the global init stream.
151  GlobalInitStream().str(std::string());
152  return success;
153 }
154 
156  return gCommandLineFlagsParsed;
157 }
158 
159 template <>
160 bool Caffe2FlagParser::Parse<string>(const string& content, string* value) {
161  *value = content;
162  return true;
163 }
164 
165 template <>
166 bool Caffe2FlagParser::Parse<int>(const string& content, int* value) {
167  try {
168  *value = std::atoi(content.c_str());
169  return true;
170  } catch(...) {
171  GlobalInitStream() << "Caffe2 flag error: Cannot convert argument to int: "
172  << content << std::endl;
173  return false;
174  }
175 }
176 
177 template <>
178 bool Caffe2FlagParser::Parse<int64_t>(const string& content, int64_t* value) {
179  try {
180  static_assert(sizeof(long long) == sizeof(int64_t), "");
181 #ifdef __ANDROID__
182  // Android does not have std::atoll.
183  *value = atoll(content.c_str());
184 #else
185  *value = std::atoll(content.c_str());
186 #endif
187  return true;
188  } catch (...) {
189  GlobalInitStream() << "Caffe2 flag error: Cannot convert argument to int: "
190  << content << std::endl;
191  return false;
192  }
193 }
194 
195 template <>
196 bool Caffe2FlagParser::Parse<double>(const string& content, double* value) {
197  try {
198  *value = std::atof(content.c_str());
199  return true;
200  } catch(...) {
201  GlobalInitStream()
202  << "Caffe2 flag error: Cannot convert argument to double: "
203  << content << std::endl;
204  return false;
205  }
206 }
207 
208 template <>
209 bool Caffe2FlagParser::Parse<bool>(const string& content, bool* value) {
210  if (content == "false" || content == "False" || content == "FALSE" ||
211  content == "0") {
212  *value = false;
213  return true;
214  } else if (content == "true" || content == "True" || content == "TRUE" ||
215  content == "1") {
216  *value = true;
217  return true;
218  } else {
219  GlobalInitStream()
220  << "Caffe2 flag error: Cannot convert argument to bool: "
221  << content << std::endl
222  << "Note that if you are passing in a bool flag, you need to "
223  "explicitly specify it, like --arg=True or --arg True. Otherwise, "
224  "the next argument may be inadvertently used as the argument, "
225  "causing the above error."
226  << std::endl;
227  return false;
228  }
229 }
230 
231 #endif // CAFFE2_USE_GFLAGS
232 
233 } // namespace caffe2
bool ParseCaffeCommandLineFlags(int *pargc, char ***pargv)
Parses the commandline flags.
Definition: flags.cc:71
const char * UsageMessage()
Returns the usage message for the commandline tool set by SetUsageMessage.
Definition: flags.cc:69
void SetUsageMessage(const string &str)
Sets the usage message when a commandline tool is called with "--help".
Definition: flags.cc:68
Copyright (c) 2016-present, Facebook, Inc.
Copyright (c) 2016-present, Facebook, Inc.
bool CommandLineFlagsHasBeenParsed()
Checks if the commandline flags has already been passed.
Definition: flags.cc:155