我正在对底层操作系统库进行一堆ctypes调用.只要文档引用存储在a中的常量值,我的进度就会慢慢爬行.h.文件在哪里,因为我必须追踪它,并弄清楚实际值是什么,以便我可以将它传递给函数.
有没有办法加载.h带有ctypes 的文件并访问所有常量?
没有.
早期版本ctypes附带一个名为的模块codegenerator,它将解析头文件,既可以获取常量值,也可以将原型转换为restype/ argtypes声明.但是,据我所知,这从未完成,并且在包含在stdlib之前从包中删除.
您可以深入挖掘源代码并提取常量,同时跳过更复杂的原型.
但是,我通常这样做的方法是编写自己的生成器.
例如,在安装过程中运行此脚本:
constants = {}
with open('foo.h') as infile:
for name, value in re.findall(r'#define\s+(\w+)\s+(.*)', infile):
try:
constants[name] = ast.literal_eval(value)
except Exception as e:
pass # maybe log something
with open('_foo_h.py', w) as outfile:
outfile.write(repr(constants))
Run Code Online (Sandbox Code Playgroud)
然后foo.py可以from _foo_h import *.
为此写一个完美的正则表达式是非常困难的,也许是不可能的; 编写一个适用于您在给定项目中实际关注的标题的标题非常简单.实际上,通常,无论是上面的那个,还是跳过评论的,都是你需要的.
但有时这不起作用.例如,头文件可能#define FOO_SIZE 8用于64位构建,和#define FOO_SIZE 4用于32位构建.你怎么处理?
为此,您要求编译器为您执行此操作.大多数编译器都有一种方法可以对文件进行预处理,以获得所有活动定义.有些编译器甚至可以以漂亮的格式转储宏定义,跳过其他所有内容.随着gcc兼容标志编译器一样clang,-E预处理和-dM转储宏.所以:
macros = subprocess.check_output(['gcc', '-dM', '-E', '-', 'foo.h'])
for line in macros.splitlines():
try:
_, name, value = line.split(None, 2)
constants[name] = ast.literal_eval(value)
except Exception as e:
pass # again, do something nicer
Run Code Online (Sandbox Code Playgroud)
您可能希望传入一些额外的编译器标志来控制适当定义的内容,如结果 pkgconfig foo --cflags.
这也将为您提供在foo.h(递归)包含的任何内容中定义的宏,以及gcc的内置宏.您可能想要也可能不想要这些.在69105 gcc旗帜的某处,我相信有办法控制它,但我不记得了.
请注意,这些都不会为您提供常量变量或枚举,例如:
static const int SPAM_SPAM_SPAM = 73;
enum {
kSPAM = 1,
kEGGS
};
Run Code Online (Sandbox Code Playgroud)
解析变得更加困难; 你想要使用像pycparser-or 这样的真正的C99解析器,或者,你想要解析类似的输出gccxml而不是gcc -E.但即使这样也不会告诉你,kEGGS如果你没有写一点逻辑,那就是2.
如果你想处理C++,那就更糟了,constexpr和静态类成员以及用户定义的文字......
或者......你必须使用ctypes?
CFFI 提供了一种从Python调用C代码的不同方法 - 它使这更容易.
Cython 让你编写几乎可以编译成C的Python代码,编译成Python扩展模块,它可以直接包含头文件.
还有各种绑定生成器(例如,SWIG)或绑定写入库(例如,boost :: python),可以通过扩展模块更轻松地将值导出到Python.
| 归档时间: |
|
| 查看次数: |
2995 次 |
| 最近记录: |