Flags.h 9.8 KB

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