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