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 <c10/macros/Export.h> 34 #include <string> 35 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 library. 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 explicitly 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: success()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_API 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