使用Coccinelle修改结构体名称为小写时遇属性错误求助
如何用Coccinelle将结构体typedef名称转换为Linux内核编码风格
我尝试用Coccinelle批量修改C代码的结构体typedef名称为Linux内核风格,但遇到了AttributeError: Cocci instance has no attribute 'make_type'的错误,下面是我的问题详情和解决方案:
问题背景
我想要将驼峰式的结构体typedef名称(比如strName)转换为下划线分隔的小写风格(比如str_name),示例代码转换目标如下:
原始代码:
typedef struct { char me; long you; } strName; int main (void) { strName *DeV; return 0; }
期望转换后代码:
typedef struct { char me; long you; } str_name; int main (void) { str_name *DeV; return 0; }
我编写了如下Coccinelle脚本,但运行时报错:
原始Coccinelle脚本:
@rule1 disable all@ type t; @@ typedef struct { ... } t; @ script:python foo @ t_fixed; var; t << rule1.t; @@ import re def split_uppercase(s): return re.sub(r'([a-z-0-9])((?<![0-9]{4})[A-Z])',r'\1_\2',s).replace("_k_Hz", "_kHz").replace("_M_Hz", "_MHz").replace("d_B", "dB").lower() print coccinelle.t coccinelle.t_fixed = split_uppercase(t) print coccinelle.t_fixed coccinelle.var = cocci.make_type(t_fixed) print var @rule2 disable all@ type rule1.t; type foo.var; @@ + var - t
错误信息
运行脚本时出现以下错误:
init_defs_builtins: /usr/lib/coccinelle/standard.h ----------------------------------------------------------------------- processing semantic patch file: structs_test.cocci with isos from: /usr/lib/coccinelle/standard.iso ----------------------------------------------------------------------- dependencies for script satisfied: HANDLING: test_basic.c dependencies for rule rule1 satisfied: transformation info is empty dependencies for script satisfied: Traceback (most recent call last): File "<string>", line 10, in <module> AttributeError: Cocci instance has no attribute 'make_type' while running simple python string: from coccinelle import * import re def split_uppercase(s): return re.sub(r'([a-z-0-9])((?<![0-9]{4})[A-Z])',r'\1_\2',s).replace("_k_Hz", "_kHz").replace("_M_Hz", "_MHz").replace("d_B", "dB").lower() print coccinelle.t coccinelle.t_fixed = split_uppercase(t) print coccinelle.t_fixed coccinelle.var = cocci.make_type(t_fixed) print var : Failure in foo Fatal error: exception Yes_pycocci.Pycocciexception
解决方案
错误的根源是cocci.make_type并不是PyCoccinelle提供的有效API函数。我们不需要创建“类型对象”,只需要将处理后的字符串直接赋值给var即可——Coccinelle会自动将这个字符串识别为类型名称用于替换。
修正后的Coccinelle脚本
@rule1 disable all@ type t; @@ typedef struct { ... } t; @ script:python foo @ t_fixed; var; t << rule1.t; @@ import re def split_uppercase(s): return re.sub(r'([a-z0-9])((?<![0-9]{4})[A-Z])', r'\1_\2', s)\ .replace("_k_Hz", "_kHz")\ .replace("_M_Hz", "_MHz")\ .replace("d_B", "dB")\ .lower() coccinelle.t_fixed = split_uppercase(t) coccinelle.var = coccinelle.t_fixed @rule2 disable all@ type rule1.t; type foo.var; @@ + var - t
关键修改说明
- 移除了错误的
cocci.make_type(t_fixed)调用,直接将处理好的t_fixed字符串赋值给var - 移除了调试用的
print语句,让脚本更简洁(如果需要调试可以重新添加) - 调整了正则表达式中的
[a-z-0-9]为[a-z0-9](避免误匹配连字符,若你的代码中有带连字符的类型名可以保留原表达式)
额外优化:匹配所有类型引用
如果想要同时修改代码中所有使用该类型的地方(比如示例中的strName *DeV;也需要改成str_name *DeV;),可以扩展规则,让rule1不仅匹配typedef定义,还能匹配类型的使用:
@rule1 disable all@ type t; identifier obj; @@ // 匹配typedef定义 typedef struct { ... } t; // 匹配类型的变量声明 t obj; @ script:python foo @ t_fixed; var; t << rule1.t; @@ import re def split_uppercase(s): return re.sub(r'([a-z0-9])((?<![0-9]{4})[A-Z])', r'\1_\2', s)\ .replace("_k_Hz", "_kHz")\ .replace("_M_Hz", "_MHz")\ .replace("d_B", "dB")\ .lower() coccinelle.t_fixed = split_uppercase(t) coccinelle.var = coccinelle.t_fixed @rule2 disable all@ type rule1.t; type foo.var; identifier rule1.obj; @@ // 替换typedef定义中的类型名 + var - t // 替换变量声明中的类型名 + var - t obj;
这个优化后的脚本会同时修改typedef定义和所有使用该类型的变量声明,完全符合Linux编码风格的转换需求。
内容的提问来源于stack exchange,提问作者curious_penguin
相关产品推荐
相关产品推荐

