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