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 | |
38 | namespace c10 { |
39 | /** |
40 | * Sets the usage message when a commandline tool is called with "--help". |
41 | */ |
42 | C10_API void SetUsageMessage(const std::string& str); |
43 | |
44 | /** |
45 | * Returns the usage message for the commandline tool set by SetUsageMessage. |
46 | */ |
47 | C10_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 | */ |
57 | C10_API bool ParseCommandLineFlags(int* pargc, char*** pargv); |
58 | |
59 | /** |
60 | * Checks if the commandline flags has already been passed. |
61 | */ |
62 | C10_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_ |
100 | namespace 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 | |
157 | namespace c10 { |
158 | |
159 | class 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 | |
171 | C10_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 | |