【问题标题】:Automatically Generate C Code From Header从头文件自动生成 C 代码
【发布时间】:2012-11-27 22:36:11
【问题描述】:

我想生成头文件中定义的过程的空实现。理想情况下,它们应该为指针返回 NULL,为整数等返回 0,并且在理想情况下,还打印到 stderr 调用了哪个函数。

这样做的动机是需要实现一个包装器,该包装器将一个复杂的现有 API(头文件)的子集适应另一个库。 API中只有少数过程需要委托,但不清楚哪些。所以我希望使用一种迭代的方法,在这个自动生成的包装器上运行,看看调用了什么,用委托实现它,然后重复。

我见过Automatically generate C++ file from header?,但答案似乎是特定于 C++ 的。

那么,对于需要简单说明问题的人,如何在给定头文件的情况下自动生成这样的实现?我更喜欢现有的工具 - 我目前对简单解决方案的最佳猜测是使用 pycparser。

更新谢谢大家。两个很好的答案。还发布了我当前的 hack。

【问题讨论】:

  • 现在,据我所知,您还没有真正问过问题,但我猜您要求的是可以做到这一点的现有工具?不幸的是我不知道任何工具,但它听起来足够基本,可以快速实现 python(或任何其他高级语言)来解决它?
  • 我已经澄清了这个问题。是的,我可以编写一个程序来做到这一点。但这并不是微不足道的——例如,它需要一个体面的解析器。标头足够大,也足够复杂,以至于基于正则表达式的临时拼凑将是一个耗时的混乱。
  • 嗨,这个过程需要容易重复吗?例如,您希望能够在 API 的新版本发布时更新存根实现吗?
  • 哦,好问题。不,这没有必要(如果是这样会更好,但我可以看到它使事情变得更加复杂,而且它是一个不太可能发生重大变化的标准 API)。
  • 如果您对脚本编写感到满意,也许您可​​以编写自己的工具?这看起来像是正则表达式可以处理的相对简单的任务......

标签: c code-generation


【解决方案1】:

所以,我将 ea 建议标记为“答案”,因为我认为这可能是总体上最好的主意。尽管我认为 cmock 建议在库开发由测试失败驱动的 tdd 方法中非常有效,但我最终可能会尝试这样做。但是现在,我需要一种以交互方式工作的更快+更脏的方法(有问题的库是另一个交互式程序的动态加载插件,我正在尝试对 api 调用的序列进行逆向工程......)

所以我最终做的是编写一个调用 pycparse 的 python 脚本。我会把它包括在这里以防它帮助其他人,但它根本不是通用的(例如,假设所有函数都返回 int,并且有一个技巧来避免 typedef 中的 func defs)。

from pycparser import parse_file
from pycparser.c_ast import NodeVisitor


class AncestorVisitor(NodeVisitor):

    def __init__(self):
        self.current = None
        self.ancestors = []

    def visit(self, node):
        if self.current:
            self.ancestors.append(self.current)
        self.current = node
        try:
            return super(AncestorVisitor, self).visit(node)
        finally:
            if self.ancestors:
                self.ancestors.pop(-1)


class FunctionVisitor(AncestorVisitor):

    def visit_FuncDecl(self, node):
        if len(self.ancestors) < 3: # avoid typedefs
            print node.type.type.names[0], node.type.declname, '(',
            first = True
            for param in node.args.params:
                if first: first = False
                else: print ',',
                print param.type.type.names[0], param.type.declname,
            print ')'
            print '{fprintf(stderr, "%s\\n"); return 0;}' % node.type.declname


print '#include "myheader.h"'
print '#include <stdio.h>'
ast = parse_file('myheader.h', use_cpp=True)
FunctionVisitor().visit(ast)

【讨论】:

    【解决方案2】:

    UML 建模工具能够以所选语言生成默认实现。通常还支持导入源代码(包括 C 头文件)。您可以尝试导入您的标头并从中生成源代码。我个人有使用Enterprise Architect 的经验,它支持这两种操作。

    【讨论】:

    • 啊,是的,ea 可能会这样做(尽管不是打印语句)。虽然可能只有付费版本,而且我已经多年没有许可证了。会检查出来。谢谢。
    • 我相信也有免费的工具可以做这些事情,问谷歌
    • 以前免费的 uml 工具非常糟糕(我是 ea 的粉丝,只是没有需要 uml 的客户),但它可能已经改变了。会看的。
    【解决方案3】:

    警告:这是一个未经研究的答案,因为我自己没有任何经验。

    我认为您可能会对为单元测试而设计的模拟框架感到幸运。这种框架的一个例子是:cmock

    项目页面建议它将从标头生成代码。然后,您可以获取代码并对其进行调整。

    【讨论】:

    • 这是一个有趣的想法,谢谢。我目前正在与 cpp 进行斗争,只是为了获得我想要的格式的标题,但会更多地考虑这种方法。
    猜你喜欢
    • 2010-11-27
    • 1970-01-01
    • 2015-05-17
    • 2015-12-20
    • 2011-03-15
    • 2011-07-14
    • 1970-01-01
    • 2011-01-20
    • 1970-01-01
    相关资源
    最近更新 更多