xref: /aosp_15_r20/external/pytorch/c10/util/Flags.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
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