227 lines
9.8 KiB
C
227 lines
9.8 KiB
C
|
#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 <c10/macros/Export.h>
|
||
|
#include <string>
|
||
|
|
||
|
#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 library.
|
||
|
// 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 explicitly 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_API 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_
|