#头文件
#include <co/flag.h>
如果同时使用日志,可以只包含 co/log.h,它已包含 co/flag.h。
API 在 flag 命名空间。
#概述
flag 提供命令行参数与配置文件解析功能,coost 中所有组件的配置项都通过 flag 定义。
- 定义 flag 即定义全局变量,变量名是
FLG_<name>; - 支持命令行参数与配置文件两种方式;
- 命令行中支持
-help打印帮助信息、-mkconf生成配置文件、-version显示程序版本;
#定义 flag
#DEF 宏
DEF_bool(name, value, help, ...);
DEF_int32(name, value, help, ...);
DEF_int64(name, value, help, ...);
DEF_uint32(name, value, help, ...);
DEF_uint64(name, value, help, ...);
DEF_double(name, value, help, ...);
DEF_string(name, value, help, ...);
定义后通过全局变量访问,例如 FLG_name。
类型对应关系:
| 宏 | 类型 | 内部标识 |
|---|---|---|
DEF_bool |
bool |
'b' |
DEF_int32 |
int32 |
'i' |
DEF_int64 |
int64 |
'I' |
DEF_uint32 |
uint32 |
'u' |
DEF_uint64 |
uint64 |
'U' |
DEF_double |
double |
'd' |
DEF_string |
co::string& |
's' |
示例:
// 定义全局 bool 类型变量,变量名是 FLG_debug
DEF_bool(debug, false, "enable debug mode");
#DEC 宏
DEC_bool(name);
DEC_int32(name);
DEC_int64(name);
DEC_uint32(name);
DEC_uint64(name);
DEC_double(name);
DEC_string(name);
用于跨文件声明,类型必须与 DEF_xxx 一致,否则同一项目中编译会报错。
#别名
flag 支持别名,命令行或配置文件中可以用别名替代原名。
DEF_xxx 的最后一个变参可以给 flag 指定最多一个别名:
// d 是 debug 的别名
DEF_bool(debug, false, "debug mode", d);
别名会显示在帮助信息中,例如 -version,v。
#解析参数
co::vector<co::string> parse(int argc, char** argv, bool command_line_only=false);
- 解析命令行参数与配置文件,更新 flag 的值。
- 返回值包含所有非 flag 参数;
command_line_only == true时只解析命令行参数;- 通常在
main开头调用; - 遇到错误时,打印错误信息,并退出程序。
#命令行参数
支持两种形式:
-name=value
-name value
- 的数量可以是 1 个或多个,-debug、--debug、---debug 等价。
#bool 类型
-debug # 等价于 -debug=true
-debug=true
-debug=false
#整数单位
整数类型支持单位 k, m, g, t, p,不分大小写,1k = 1024。
-co_stack_size=2m # 2 * 1024 * 1024
#单字母 flag 的简写语法
coost 对单字母 flag 提供了两种简写,仅用于命令行,配置文件不支持:
- 多个单字母 bool flag 可以合并:如 x、y、z 都是 bool flag,则
-xyz可以将三者都置为 true。 - 单字母整数类型 flag 可以连写值:如
-n8相当于-n=8。
#配置文件
默认命令行中第一个非 flag 参数且名字以 .conf 结尾的文件作为配置文件:
./xx xx.conf
有多个 .conf 参数时,只有第一个作为配置文件。
也可以用 set_config_path (需要在 parse 前调用)设置默认配置文件路径,命令行传入的 .conf 会覆盖它。
配置文件格式:
# 注释
debug = true
threads = 8
port = 8080
name = "my app"
n = 8k # 8192
规则:
#表示注释;- 支持空行;
- 行首或行尾可以有空格;
- key 不加
--; =前后可以有空格;- string 首尾有空格时需要加引号,单引号和双引号都支持;
- 字符串中支持常见转义字符,具体见
co::string::unescape; - bool 支持
true/false、1/0,其余值都当作false; - 整数支持
k, m, g, t, p单位,不区分大小写; - 配置文件中出现未定义 flag 时,会在终端打印一行 warning 信息,不会退出程序;
- flag 名大小写敏感。
#命令行与配置文件优先级
- 命令行参数与配置文件同时存在时,命令行参数会覆盖配置文件中的值;
- 命令行传入的
.conf会覆盖set_config_path设置的默认路径。
#内部 flag
flag 组件内部定义了三个 bool 类型 flag:
DEF_bool(help, false, s_help);
DEF_bool(version, false, s_version);
DEF_bool(mkconf, false, s_mkconf);
#-help
打印帮助信息。
./xx -help
帮助信息格式示例:
usage: ./xx [xx.conf] [-flag [value]] [-flag=value]...
flags: -name[,alias] type comments (default value)
-help b 显示帮助信息 (false)
-version,v b 显示版本信息 (false)
-mkconf b 生成配置文件 (false)
-boo b bool flag (false)
...
如果用户包含了 coost 相关组件头文件(co/log.h, co/co.h, co/rpc.h),coost 内部定义的 flag 会显示在帮助信息中。
#-version
显示程序版本,需要在 flag::parse 前调用 flag::set_program_version 设置版本号。未设置时版本信息为空。
./xx -version
#-mkconf
生成配置文件:
./xx -mkconf
- 在当前执行命令的目录生成配置文件;
- 文件名规则:可执行文件名去掉
.exe,再加上.conf; - 包含所有用户 flag,以及用到的 coost 内部组件中的 flag;
- 如果不想 flag 出现在配置文件中,可以用
flag::hide()隐藏 flag。
#运行时 API
// 添加别名,@new_name 必须有静态生命周期
// 如果 @new_name 为空,则移除已有别名
void flag::alias(const char* name, const char* new_name);
// 设置默认配置文件路径
void flag::set_config_path(const char* path);
// 设置程序版本
void flag::set_program_version(const char* ver);
// 隐藏 flag,使其不出现在帮助信息与 -mkconf 生成的配置文件中
void flag::hide(const char* name);
// 与 hide 相反
void flag::unhide(const char* name);
// 设置 flag 的值,出错时返回 false
bool flag::set_value(const char* flag_name, const char* value);
// 注册回调,在 flag::parse 解析完命令行参数后执行
void flag::run_after_parse(void(*cb)());
// 注册回调,在 flag::parse 解析命令行参数前执行
void flag::run_before_parse(void(*cb)());
#alias
- 添加别名,最多只能有一个别名;
new_name必须有静态生命周期;- 如果
new_name为空,则移除已有别名; - 别名会显示在帮助信息中,例如
-version,v; - 必须在
flag::parse前调用,否则flag::parse看不到这个别名,-help也不会显示。
#set_config_path
- 设置默认配置文件路径;
- 设置后,用户在命令行中可以不传配置文件参数,
flag::parse会从默认路径解析配置文件; - 多次调用时,会覆盖之前的值;
- 命令行传入的
.conf会覆盖这个默认路径。 - 必须在
flag::parse前调用;
#set_program_version
- 设置程序版本号;
- 必须在
flag::parse前调用,若在flag::parse后调用,./xx -version无法显示版本信息。
#hide / unhide
hide隐藏 flag,使其不出现在帮助信息和-mkconf生成的配置文件中;unhide与hide相反;- 必须在
flag::parse前调用。
#set_value
- 按名字设置 flag 的值,
value是字符串形式,内部按 flag 类型解析; - 出错时返回
false,并用co::println打印错误信息,不会退出程序; - 通常在
flag::parse前调用,用于修改 flag 默认值,这样命令行与配置文件中传入的值依旧可以覆盖它; - 若在
flag::parse后调用,命令行、配置文件中的设置将失去作用,一般不建议这样做。
#run_after_parse
- 注册的回调在
flag::parse解析完命令行参数与配置文件后执行; - 允许注册多个回调,按注册顺序执行;
- coost 内部用它启动协程调度线程、日志线程。
- 必须在
flag::parse前调用。
#run_before_parse
- 注册的回调在
flag::parse解析参数前执行; - 允许注册多个回调,按注册顺序执行;
- coost 内部用它来 unhide 组件中的 flag,例如包含
co/rpc.h后,RPC 组件会在回调中调用flag::unhide("rpc_max_msg_size")等。 - 必须在
flag::parse前调用。
#线程安全
flag 本质是全局变量或对象,若有多个线程访问或修改 FLG_xxx。用户需要自己保证并发安全。
#示例
#include <co/log.h> // 已包含 co/flag.h
DEF_bool(debug, false, "enable debug mode");
DEF_int32(threads, 4, "number of threads");
DEF_uint32(port, 8080, "server port");
DEF_string(name, "coost", "app name", n); // n 为别名
int main(int argc, char** argv) {
// 设置程序版本号
flag::set_program_version("1.0.0");
// 日志组件内置 flag,日志也输出到终端
flag::set_value("also_log2console", "true");
// 可选:设置默认配置文件路径
// flag::set_config_path("my.conf");
auto non_flags = flag::parse(argc, argv);
log::info("debug=", FLG_debug);
log::info("threads=", FLG_threads);
log::info("port=", FLG_port);
log::info("name=", FLG_name);
for (auto& s : non_flags) {
log::info("non-flag: ", s);
}
return 0;
}
运行:
./app -debug -threads=8 -port 8080 -name=myapp xx.conf
配置文件 xx.conf:
# comment
debug = true
threads = 8
port = 8080
name = "my app"
生成配置:
./app -mkconf
查看帮助:
./app -help
查看版本:
./app -version