1#ifndef C10_UTIL_FLAGS_H_
2#define C10_UTIL_FLAGS_H_
3
4/* Commandline flags support for C10.
5 *
6 * This is a portable commandline flags tool for c10, so we can optionally
7 * choose to use gflags or a lightweight custom implementation if gflags is
8 * not possible on a certain platform. If you have gflags installed, set the
9 * macro C10_USE_GFLAGS will seamlessly route everything to gflags.
10 *
11 * To define a flag foo of type bool default to true, do the following in the
12 * *global* namespace:
13 * C10_DEFINE_bool(foo, true, "An example.");
14 *
15 * To use it in another .cc file, you can use C10_DECLARE_* as follows:
16 * C10_DECLARE_bool(foo);
17 *
18 * In both cases, you can then access the flag via FLAGS_foo.
19 *
20 * It is recommended that you build with gflags. To learn more about the flags
21 * usage, refer to the gflags page here:
22 *
23 * https://gflags.github.io/gflags/
24 *
25 * Note about Python users / devs: gflags is initiated from a C++ function
26 * ParseCommandLineFlags, and is usually done in native binaries in the main
27 * function. As Python does not have a modifiable main function, it is usually
28 * difficult to change the flags after Python starts. Hence, it is recommended
29 * that one sets the default value of the flags to one that's acceptable in
30 * general - that will allow Python to run without wrong flags.
31 */
32
33#include <string>
34
35#include <c10/macros/Macros.h>
36#include <c10/util/Registry.h>
37
38namespace c10 {
39/**
40 * Sets the usage message when a commandline tool is called with "--help".
41 */
42C10_API void SetUsageMessage(const std::string& str);
43
44/**
45 * Returns the usage message for the commandline tool set by SetUsageMessage.
46 */
47C10_API const char* UsageMessage();
48
49/**
50 * Parses the commandline flags.
51 *
52 * This command parses all the commandline arguments passed in via pargc
53 * and argv. Once it is finished, partc and argv will contain the remaining
54 * commandline args that c10 does not deal with. Note that following
55 * convention, argv[0] contains the binary name and is not parsed.
56 */
57C10_API bool ParseCommandLineFlags(int* pargc, char*** pargv);
58
59/**
60 * Checks if the commandline flags has already been passed.
61 */
62C10_API bool CommandLineFlagsHasBeenParsed();
63
64} // namespace c10
65
66////////////////////////////////////////////////////////////////////////////////
67// Below are gflags and non-gflags specific implementations.
68// In general, they define the following macros for one to declare (use
69// C10_DECLARE) or define (use C10_DEFINE) flags:
70// C10_{DECLARE,DEFINE}_{int,int64,double,bool,string}
71////////////////////////////////////////////////////////////////////////////////
72
73#ifdef C10_USE_GFLAGS
74
75////////////////////////////////////////////////////////////////////////////////
76// Begin gflags section: most functions are basically rerouted to gflags.
77////////////////////////////////////////////////////////////////////////////////
78#include <gflags/gflags.h>
79
80// C10 uses hidden visibility by default. However, in gflags, it only uses
81// export on Windows platform (with dllexport) but not on linux/mac (with
82// default visibility). As a result, to ensure that we are always exporting
83// global variables, we will redefine the GFLAGS_DLL_DEFINE_FLAG macro if we
84// are building C10 as a shared libray.
85// This has to be done after the inclusion of gflags, because some early
86// versions of gflags.h (e.g. 2.0 on ubuntu 14.04) directly defines the
87// macros, so we need to do definition after gflags is done.
88#ifdef GFLAGS_DLL_DEFINE_FLAG
89#undef GFLAGS_DLL_DEFINE_FLAG
90#endif // GFLAGS_DLL_DEFINE_FLAG
91#ifdef GFLAGS_DLL_DECLARE_FLAG
92#undef GFLAGS_DLL_DECLARE_FLAG
93#endif // GFLAGS_DLL_DECLARE_FLAG
94#define GFLAGS_DLL_DEFINE_FLAG C10_EXPORT
95#define GFLAGS_DLL_DECLARE_FLAG C10_IMPORT
96
97// gflags before 2.0 uses namespace google and after 2.1 uses namespace gflags.
98// Using GFLAGS_GFLAGS_H_ to capture this change.
99#ifndef GFLAGS_GFLAGS_H_
100namespace gflags = google;
101#endif // GFLAGS_GFLAGS_H_
102
103// Motivation about the gflags wrapper:
104// (1) We would need to make sure that the gflags version and the non-gflags
105// version of C10 are going to expose the same flags abstraction. One should
106// explicitly use FLAGS_flag_name to access the flags.
107// (2) For flag names, it is recommended to start with c10_ to distinguish it
108// from regular gflags flags. For example, do
109// C10_DEFINE_BOOL(c10_my_flag, true, "An example");
110// to allow one to use FLAGS_c10_my_flag.
111// (3) Gflags has a design issue that does not properly expose the global flags,
112// if one builds the library with -fvisibility=hidden. The current gflags (as of
113// Aug 2018) only deals with the Windows case using dllexport, and not the Linux
114// counterparts. As a result, we will explciitly use C10_EXPORT to export the
115// flags defined in C10. This is done via a global reference, so the flag
116// itself is not duplicated - under the hood it is the same global gflags flag.
117#define C10_GFLAGS_DEF_WRAPPER(type, real_type, name, default_value, help_str) \
118 DEFINE_##type(name, default_value, help_str);
119
120#define C10_DEFINE_int(name, default_value, help_str) \
121 C10_GFLAGS_DEF_WRAPPER(int32, gflags::int32, name, default_value, help_str)
122#define C10_DEFINE_int32(name, default_value, help_str) \
123 C10_DEFINE_int(name, default_value, help_str)
124#define C10_DEFINE_int64(name, default_value, help_str) \
125 C10_GFLAGS_DEF_WRAPPER(int64, gflags::int64, name, default_value, help_str)
126#define C10_DEFINE_double(name, default_value, help_str) \
127 C10_GFLAGS_DEF_WRAPPER(double, double, name, default_value, help_str)
128#define C10_DEFINE_bool(name, default_value, help_str) \
129 C10_GFLAGS_DEF_WRAPPER(bool, bool, name, default_value, help_str)
130#define C10_DEFINE_string(name, default_value, help_str) \
131 C10_GFLAGS_DEF_WRAPPER(string, ::fLS::clstring, name, default_value, help_str)
132
133// DECLARE_typed_var should be used in header files and in the global namespace.
134#define C10_GFLAGS_DECLARE_WRAPPER(type, real_type, name) DECLARE_##type(name);
135
136#define C10_DECLARE_int(name) \
137 C10_GFLAGS_DECLARE_WRAPPER(int32, gflags::int32, name)
138#define C10_DECLARE_int32(name) C10_DECLARE_int(name)
139#define C10_DECLARE_int64(name) \
140 C10_GFLAGS_DECLARE_WRAPPER(int64, gflags::int64, name)
141#define C10_DECLARE_double(name) \
142 C10_GFLAGS_DECLARE_WRAPPER(double, double, name)
143#define C10_DECLARE_bool(name) C10_GFLAGS_DECLARE_WRAPPER(bool, bool, name)
144#define C10_DECLARE_string(name) \
145 C10_GFLAGS_DECLARE_WRAPPER(string, ::fLS::clstring, name)
146
147////////////////////////////////////////////////////////////////////////////////
148// End gflags section.
149////////////////////////////////////////////////////////////////////////////////
150
151#else // C10_USE_GFLAGS
152
153////////////////////////////////////////////////////////////////////////////////
154// Begin non-gflags section: providing equivalent functionality.
155////////////////////////////////////////////////////////////////////////////////
156
157namespace c10 {
158
159class C10_API C10FlagParser {
160 public:
161 bool success() {
162 return success_;
163 }
164
165 protected:
166 template <typename T>
167 bool Parse(const std::string& content, T* value);
168 bool success_{false};
169};
170
171C10_DECLARE_REGISTRY(C10FlagsRegistry, C10FlagParser, const std::string&);
172
173} // namespace c10
174
175// The macros are defined outside the c10 namespace. In your code, you should
176// write the C10_DEFINE_* and C10_DECLARE_* macros outside any namespace
177// as well.
178
179#define C10_DEFINE_typed_var(type, name, default_value, help_str) \
180 C10_EXPORT type FLAGS_##name = default_value; \
181 namespace c10 { \
182 namespace { \
183 class C10FlagParser_##name : public C10FlagParser { \
184 public: \
185 explicit C10FlagParser_##name(const std::string& content) { \
186 success_ = C10FlagParser::Parse<type>(content, &FLAGS_##name); \
187 } \
188 }; \
189 } \
190 RegistererC10FlagsRegistry g_C10FlagsRegistry_##name( \
191 #name, \
192 C10FlagsRegistry(), \
193 RegistererC10FlagsRegistry::DefaultCreator<C10FlagParser_##name>, \
194 "(" #type ", default " #default_value ") " help_str); \
195 }
196
197#define C10_DEFINE_int(name, default_value, help_str) \
198 C10_DEFINE_typed_var(int, name, default_value, help_str)
199#define C10_DEFINE_int32(name, default_value, help_str) \
200 C10_DEFINE_int(name, default_value, help_str)
201#define C10_DEFINE_int64(name, default_value, help_str) \
202 C10_DEFINE_typed_var(int64_t, name, default_value, help_str)
203#define C10_DEFINE_double(name, default_value, help_str) \
204 C10_DEFINE_typed_var(double, name, default_value, help_str)
205#define C10_DEFINE_bool(name, default_value, help_str) \
206 C10_DEFINE_typed_var(bool, name, default_value, help_str)
207#define C10_DEFINE_string(name, default_value, help_str) \
208 C10_DEFINE_typed_var(std::string, name, default_value, help_str)
209
210// DECLARE_typed_var should be used in header files and in the global namespace.
211#define C10_DECLARE_typed_var(type, name) C10_IMPORT extern type FLAGS_##name
212
213#define C10_DECLARE_int(name) C10_DECLARE_typed_var(int, name)
214#define C10_DECLARE_int32(name) C10_DECLARE_int(name)
215#define C10_DECLARE_int64(name) C10_DECLARE_typed_var(int64_t, name)
216#define C10_DECLARE_double(name) C10_DECLARE_typed_var(double, name)
217#define C10_DECLARE_bool(name) C10_DECLARE_typed_var(bool, name)
218#define C10_DECLARE_string(name) C10_DECLARE_typed_var(std::string, name)
219
220////////////////////////////////////////////////////////////////////////////////
221// End non-gflags section.
222////////////////////////////////////////////////////////////////////////////////
223
224#endif // C10_USE_GFLAGS
225
226#endif // C10_UTIL_FLAGS_H_
227