From 9cc8a5e187b6b95b1eaf012d4b916fb7ea9f3768 Mon Sep 17 00:00:00 2001 From: zhaoxi <535394140@qq.com> Date: Sat, 22 Jun 2024 17:27:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=A7=84=E8=8C=83=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmake/RMVLGenPara.cmake | 263 ++++++++++++++++------- cmake/templates/para_generator_header.in | 5 + cmake/templates/para_generator_source.in | 3 +- 3 files changed, 192 insertions(+), 79 deletions(-) diff --git a/cmake/RMVLGenPara.cmake b/cmake/RMVLGenPara.cmake index 7fc57ecd..40514199 100644 --- a/cmake/RMVLGenPara.cmake +++ b/cmake/RMVLGenPara.cmake @@ -44,7 +44,7 @@ function(system_date out_y out_m out_d) endfunction() # ---------------------------------------------------------------------------- -# 修正类型符号: 增加作用域 +# 修正类型符号: 增加 C++ 的作用域 # string -> std::string vector -> std::vector # Point... -> cv::Point... Matx... -> cv::Matx... # 用法: @@ -59,41 +59,159 @@ endfunction() # ---------------------------------------------------------------------------- function(_type_correct value_type out_value_type) set(retval ${value_type}) - string(REGEX REPLACE "string" "std::string" retval "${retval}") - string(REGEX REPLACE "vector" "std::vector" retval "${retval}") - string(REGEX REPLACE "Point" "cv::Point" retval "${retval}") - string(REGEX REPLACE "Vec" "cv::Vec" retval "${retval}") - string(REGEX REPLACE "Mat" "cv::Mat" retval "${retval}") - string(REGEX REPLACE "([^\\.])51f" "\\1" retval "${retval}") - string(REGEX REPLACE "([^\\.])51d" "\\1" retval "${retval}") - string(REGEX REPLACE "([^\\.])15f" "\\1" retval "${retval}") - string(REGEX REPLACE "([^\\.])15d" "\\1" retval "${retval}") - string(REGEX REPLACE "([^\\.])61f" "\\1" retval "${retval}") - string(REGEX REPLACE "([^\\.])61d" "\\1" retval "${retval}") - string(REGEX REPLACE "([^\\.])16f" "\\1" retval "${retval}") - string(REGEX REPLACE "([^\\.])16d" "\\1" retval "${retval}") + string(REGEX REPLACE "(size_t|string|vector)" "std::\\1" retval "${retval}") + string(REGEX REPLACE "(Point|Vec|Mat)" "cv::\\1" retval "${retval}") + string(REGEX REPLACE "Matx([1-9])([1-9])f" "Matx" retval "${retval}") + string(REGEX REPLACE "Matx([1-9])([1-9])d" "Matx" retval "${retval}") + string(REGEX REPLACE "Vec([1-9])f" "Vec" retval "${retval}") + string(REGEX REPLACE "Vec([1-9])d" "Vec" retval "${retval}") set(${out_value_type} ${retval} PARENT_SCOPE) endfunction() +# ---------------------------------------------------------------------------- +# 按照常规的赋值模式解析参数规范文件的某一行内容 +# 用法: +# _parse_assign( +#
+# ) +# 示例: +# _parse_assign( +# line_str # 传入字符串: 一行的内容 +# ret_header # 传出字符串: 头文件内容 +# ret_source # 传出字符串: 源文件内容 +# ) +# ---------------------------------------------------------------------------- +function(_parse_assign content_line header_line source_line) + list(LENGTH ${content_line} l) + if(l GREATER 1) + # get value type symbol + list(GET ${content_line} 0 type_sym) + # correct the value type + _type_correct("${type_sym}" type_sym_correct) + # get id symbol + list(GET ${content_line} 1 id_sym) + # get default value and comment + if(l GREATER 2) + list(SUBLIST ${content_line} 2 -1 default_cmt) + else() + set(default_cmt "") + endif() + string(REGEX REPLACE ";" "" default_cmt "${default_cmt}") + # split default value and comment + string(FIND "${default_cmt}" "#" cmt_idx) + if(cmt_idx EQUAL -1) + set(default_sym "${default_cmt}") + set(comment_sym "${id_sym}") + else() + string(SUBSTRING "${default_cmt}" 0 ${cmt_idx} default_sym) + math(EXPR cmt_idx "${cmt_idx} + 1") + string(SUBSTRING "${default_cmt}" ${cmt_idx} -1 comment_sym) + endif() + # add default value to comment + if(NOT default_sym STREQUAL "") + set(comment_sym "${comment_sym} @note 默认值:`${default_sym}`") + endif() + # correct default_sym + if(NOT type_sym STREQUAL "string") + _type_correct("${default_sym}" default_sym) + string(REGEX REPLACE "," ", " default_sym "${default_sym}") + endif() + else() + return() + endif() + # get return value (header) + set(ret_header_line "${ret_header_line} //! ${comment_sym}\n") + if("${default_sym}" STREQUAL "") + set(ret_header_line "${ret_header_line} ${type_sym_correct} ${id_sym}{};\n") + else() + set(ret_header_line "${ret_header_line} ${type_sym_correct} ${id_sym} = ${default_sym};\n") + endif() + # get return value (source) + set(ret_source_line "${ret_source_line} node = fs[\"${id_sym}\"];\n") + if(type_sym MATCHES "^uint\\w*|size_t") + set(ret_source_line "${ret_source_line} if (!node.isNone())\n {\n") + set(ret_source_line "${ret_source_line} int tmp{};\n node >> tmp;\n") + set(ret_source_line "${ret_source_line} ${id_sym} = static_cast<${type_sym_correct}>(tmp);\n }\n") + elseif(type_sym MATCHES "int|float|double|string|vector|Point\\w*|Mat\\w*|Vec\\w*") + set(ret_source_line "${ret_source_line} node.isNone() ? void(0) : (node >> ${id_sym});\n") + else() # enum type + set(ret_source_line "${ret_source_line} if (!node.isNone())\n {\n") + set(ret_source_line "${ret_source_line} std::string tmp{};\n node >> tmp;\n") + set(ret_source_line "${ret_source_line} ${id_sym} = map_${type_sym}.at(tmp);\n }\n") + endif() + # return to parent scope + set(${header_line} "${ret_header_line}" PARENT_SCOPE) + set(${source_line} "${ret_source_line}" PARENT_SCOPE) +endfunction() + +# ---------------------------------------------------------------------------- +# 按照枚举定义模式解析参数规范文件的某一行内容 +# 用法: +# _parse_enumdef( +# +# ) +# 示例: +# _parse_enumdef( +# line_str # [in] 一行的内容 +# enum_name # [in] 枚举名称 +# header_extra_line # [out] 头文件额外内容 +# source_extra_line # [out] 源文件额外内容 +# ) +# ---------------------------------------------------------------------------- +function(_parse_enumdef content_line enum_name header_extra_line source_extra_line) + list(LENGTH ${content_line} l) + # get tag symbol + list(GET ${content_line} 0 tag_sym) + # get ref value and comment + if(l GREATER 1) + list(SUBLIST ${content_line} 1 -1 ref_cmt) + else() + set(ref_cmt "") + endif() + string(REGEX REPLACE ";" "" ref_cmt "${ref_cmt}") + # split ref value and comment + string(FIND "${ref_cmt}" "#" cmt_idx) + if(cmt_idx EQUAL -1) + set(ref_sym "${ref_cmt}") + set(comment_sym "${tag_sym}") + else() + string(SUBSTRING "${ref_cmt}" 0 ${cmt_idx} ref_sym) + math(EXPR cmt_idx "${cmt_idx} + 1") + string(SUBSTRING "${ref_cmt}" ${cmt_idx} -1 comment_sym) + endif() + # get return value (extra header) + set(ret_header_extra_line " //! ${comment_sym}\n") + if("${ref_sym}" STREQUAL "") + set(ret_header_extra_line "${ret_header_extra_line} ${tag_sym},\n") + else() + set(ret_header_extra_line "${ret_header_extra_line} ${tag_sym} = ${ref_sym},\n") + endif() + # get return value (extra source) + set(ret_source_extra_line " {\"${tag_sym}\", ${enum_name}::${tag_sym}},\n") + # return to parent scope + set(${header_extra_line} "${ret_header_extra_line}" PARENT_SCOPE) + set(${source_extra_line} "${ret_source_extra_line}" PARENT_SCOPE) +endfunction() + # ---------------------------------------------------------------------------- # 将指定的 *.para 参数规范文件解析成 C++ 风格的内容 # 用法: # _para_parser( # -# +# # ) # 示例: # _para_parser( # core.para # 名为 core.para 的参数规范文件 -# core_header_details # 对应 .h/.hpp 文件的细节 -# core_source_details # 对应 .cpp 文件的实现细节 +# para_header_details # 对应 .h/.hpp 文件的细节 +# para_header_extra # 对应 .h/.hpp 文件的额外细节 +# para_source_details # 对应 .cpp 文件的实现细节 +# para_source_extra # 对应 .cpp 文件的额外实现细节 # status # 返回值: 解析是否成功,成功返回 TRUE,失败返回 FALSE # ) # ---------------------------------------------------------------------------- -function(_para_parser file_name header_details source_details status) +function(_para_parser file_name header_details header_extra source_details source_extra status) # init - set(ret_header "") - set(ret_source "") file(READ ${file_name} out_val) if(NOT out_val) set(${status} FALSE PARENT_SCOPE) @@ -102,7 +220,7 @@ function(_para_parser file_name header_details source_details status) string(REGEX REPLACE "\n" ";" out_val "${out_val}") # parser each line foreach(substr ${out_val}) - # get substring: line_str + ################ get subing: line_str ################ string(REGEX REPLACE "[ =]" ";" line_str "${substr}") set(tmp) foreach(word ${line_str}) @@ -110,64 +228,50 @@ function(_para_parser file_name header_details source_details status) endforeach() set(line_str ${tmp}) unset(tmp) - # parser - list(LENGTH line_str l) - if(l GREATER 1) - # get value type symbol - list(GET line_str 0 type_sym) - if(type_sym MATCHES "^#") - continue() - endif() - # correct the value type - _type_correct("${type_sym}" type_sym) - # get id symbol - list(GET line_str 1 id_sym) - # get default value and comment - list(SUBLIST line_str 2 -1 default_cmt) - string(REGEX REPLACE ";" "" default_cmt "${default_cmt}") - # split default value and comment - string(FIND "${default_cmt}" "#" cmt_idx) + # parser mode + if(line_str MATCHES "^enum") + list(GET line_str 1 enum_name) + string(REGEX REPLACE ";" "" enum_cmt "${line_str}") + # find comment of enum + string(FIND "${enum_cmt}" "#" cmt_idx) if(cmt_idx EQUAL -1) - set(default_sym "${default_cmt}") - set(comment_sym "${id_sym}") + set(enum_cmt "${enum_name} 枚举类型") else() - string(SUBSTRING "${default_cmt}" 0 ${cmt_idx} default_sym) math(EXPR cmt_idx "${cmt_idx} + 1") - string(SUBSTRING "${default_cmt}" ${cmt_idx} -1 comment_sym) + string(SUBSTRING "${enum_cmt}" ${cmt_idx} -1 enum_cmt) endif() - # add default value to comment - if(NOT default_sym STREQUAL "") - set(comment_sym "${comment_sym} @note 默认值:`${default_sym}`") - endif() - # correct default_sym - if(NOT type_sym STREQUAL "std::string") - _type_correct("${default_sym}" default_sym) - string(REGEX REPLACE "," ", " default_sym "${default_sym}") - endif() - else() + set(ret_header_extra "${ret_header_extra}//! ${enum_cmt}\nenum class ${enum_name}\n{\n") + set(ret_source_extra "${ret_source_extra}static const std::unordered_map map_${enum_name} = {\n") + set(parse_mode "enum") + continue() + elseif(line_str MATCHES "^endenum") + set(ret_header_extra "${ret_header_extra}};\n") + set(ret_source_extra "${ret_source_extra}};\n") + unset(parse_mode) continue() endif() - # get return value (header) - set(ret_header "${ret_header} //! ${comment_sym}\n") - if("${default_sym}" STREQUAL "") - set(ret_header "${ret_header} ${type_sym} ${id_sym}{};\n") - else() - set(ret_header "${ret_header} ${type_sym} ${id_sym} = ${default_sym};\n") - endif() - # get return value (source) - set(ret_source "${ret_source} node = fs[\"${id_sym}\"];\n") - if(type_sym MATCHES "uint" OR type_sym STREQUAL "size_t") - set(ret_source "${ret_source} if (!node.isNone())\n {\n") - set(ret_source "${ret_source} int tmp_${id_sym}{};\n node >> tmp_${id_sym};\n") - set(ret_source "${ret_source} ${id_sym} = static_cast<${type_sym}>(tmp_${id_sym});\n }\n") + # parser + unset(ret_header_extra_line) + unset(ret_header_line) + unset(ret_source_line) + if(line_str MATCHES "^#") + continue() + elseif("${parse_mode}" STREQUAL "enum") + _parse_enumdef(line_str "${enum_name}" ret_header_extra_line ret_source_extra_line) + set(ret_header_extra "${ret_header_extra}${ret_header_extra_line}") + set(ret_source_extra "${ret_source_extra}${ret_source_extra_line}") else() - set(ret_source "${ret_source} node.isNone() ? void(0) : (node >> ${id_sym});\n") + _parse_assign(line_str ret_header_line ret_source_line) + set(ret_header "${ret_header}${ret_header_line}") + set(ret_source "${ret_source}${ret_source_line}") endif() endforeach(substr ${out_val}) set(${header_details} "${ret_header}" PARENT_SCOPE) + set(${header_extra} "${ret_header_extra}" PARENT_SCOPE) set(${source_details} "${ret_source}" PARENT_SCOPE) + set(${source_extra} "${ret_source_extra}" PARENT_SCOPE) set(${status} TRUE PARENT_SCOPE) -endfunction(_para_parser file_name header_details source_details) +endfunction() # ---------------------------------------------------------------------------- # 根据指定的目标名在 param 文件夹下对应的 *.para 参数规范文件和可选的模块名生成对应的 C++ 代码 @@ -195,7 +299,7 @@ function(rmvl_generate_para target_name) set(para_msg "Performing Conversion ${target_name}.para") message(STATUS "${para_msg}") if(DEFINED BUILD_${the_module}_INIT AND NOT BUILD_${the_module}_INIT) - message(STATUS "Performing Conversion ${target_name}.para - skipped") + message(STATUS "${para_msg} - skipped") return() endif() ################## snake to camel (get class name) ################## @@ -215,7 +319,12 @@ function(rmvl_generate_para target_name) set(RMVLPARA_${module_name} "${RMVLPARA_${module_name}}" "${target_name}" CACHE INTERNAL "${module_name} parameters") endif() # parser - _para_parser(${file_name} para_header_details para_source_details para_status) + _para_parser( + ${file_name} + para_header_details para_header_extra + para_source_details para_source_extra + para_status + ) if(NOT para_status) message(STATUS "${para_msg} - failed") return() @@ -223,8 +332,7 @@ function(rmvl_generate_para target_name) set(para_include_path) # has module if(PARA_MODULE) - set(header_ext "h") - set(para_include_path "rmvlpara/${module_name}/${target_name}.${header_ext}") + set(para_include_path "rmvlpara/${module_name}/${target_name}.h") configure_file( ${para_template_path}/para_generator_source.in ${CMAKE_CURRENT_LIST_DIR}/src/${target_name}/para/param.cpp @@ -232,8 +340,7 @@ function(rmvl_generate_para target_name) ) # dosen't have module else() - set(header_ext "hpp") - set(para_include_path "rmvlpara/${module_name}.${header_ext}") + set(para_include_path "rmvlpara/${module_name}.hpp") configure_file( ${para_template_path}/para_generator_source.in ${CMAKE_CURRENT_LIST_DIR}/src/para/param.cpp @@ -253,7 +360,7 @@ function(rmvl_generate_para target_name) unset(para_include_path) ############################ message end ############################ message(STATUS "${para_msg} - done") -endfunction(rmvl_generate_para target_name) +endfunction() # ---------------------------------------------------------------------------- # 根据给定模块下所有的 para 目标,生成对应的 C++ 代码 @@ -272,10 +379,10 @@ function(rmvl_generate_module_para module_name) system_date(year month day) set(para_module_header_details "") foreach(_sub ${RMVLPARA_${module_name}}) - string(TOUPPER "${_sub}" upper) - set(para_module_header_details "${para_module_header_details}\n#ifdef HAVE_RMVL_${upper}\n") + string(TOUPPER "${_sub}" _upper) + set(para_module_header_details "${para_module_header_details}\n#ifdef HAVE_RMVL_${_upper}\n") set(para_module_header_details "${para_module_header_details}#include \"${module_name}/${_sub}.h\"\n") - set(para_module_header_details "${para_module_header_details}#endif // HAVE_RMVL_${upper}\n") + set(para_module_header_details "${para_module_header_details}#endif // HAVE_RMVL_${_upper}\n") endforeach() # generate C++ file configure_file( @@ -285,4 +392,4 @@ function(rmvl_generate_module_para module_name) ) ############################ message end ############################ message(STATUS "${para_msg} - done") -endfunction(rmvl_generate_module_para module_name) +endfunction() diff --git a/cmake/templates/para_generator_header.in b/cmake/templates/para_generator_header.in index 47eb3ebf..22666f52 100644 --- a/cmake/templates/para_generator_header.in +++ b/cmake/templates/para_generator_header.in @@ -24,6 +24,11 @@ namespace rm::para //! @addtogroup para_@module_name@ //! @{ +////////////////////// 扩展部分 ////////////////////// + +@para_header_extra@ +////////////////////// 参数部分 ////////////////////// + //! @class_name@ 参数模块 struct @class_name@ { diff --git a/cmake/templates/para_generator_source.in b/cmake/templates/para_generator_source.in index bca9d6fe..5df1189c 100644 --- a/cmake/templates/para_generator_source.in +++ b/cmake/templates/para_generator_source.in @@ -14,10 +14,11 @@ namespace rm::para { +@para_source_extra@ bool @class_name@::load(const std::string &path) { cv::FileStorage fs(path, cv::FileStorage::READ); - if(!fs.isOpened()) + if (!fs.isOpened()) return false; cv::FileNode node;