如何将带有宏的头文件预处理为非宏头文件
How do I preprocess a header file with macros to a non macro header file
这里是C新手。我的用例是将 here 发布的头文件提供给 python 库 cffi
,以便我可以绑定到 C 库。前面link中的头文件有宏。 cffi
我认为只接受没有宏的头文件。
- 有没有办法通过指定任何选项将带有宏的头文件提供给
cffi
?
- 如果没有,我该如何预处理该文件以便将其提供给
cffi
?我尝试了 gcc -E ddlog.h > ddlog-processed.h
,但是当我 运行 使用 cffi
以下代码时,它出错了。
重现步骤:
- 下载
ddlog.h
pip install cffi
gcc -E ddlog.h > ddlog-processed.h
- 在与
ddlog.h
相同的文件夹中的文件 build.py
中,放置
import cffi
import pathlib
ffi = cffi.FFI()
this_dir = pathlib.Path().absolute()
h_file_name = this_dir / "ddlog-processed.h"
with open(h_file_name) as h_file:
ffi.cdef(h_file.read())
python build.py
它给出错误:
Traceback (most recent call last):
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 305, in _parse
ast = _get_parser().parse(fullcsource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/c_parser.py", line 152, in parse
debug=debuglevel)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/ply/yacc.py", line 331, in parse
return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/ply/yacc.py", line 1199, in parseopt_notrack
tok = call_errorfunc(self.errorfunc, errtoken, self)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/ply/yacc.py", line 193, in call_errorfunc
r = errorfunc(token)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/c_parser.py", line 1861, in p_error
column=self.clex.find_tok_column(p)))
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/plyparser.py", line 67, in _parse_error
raise ParseError("%s: %s" % (coord, msg))
pycparser.plyparser.ParseError: /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/sys/_types/_int8_t.h:30:18: before: char
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/bin/invoke", line 10, in <module>
sys.exit(program.run())
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/program.py", line 384, in run
self.execute()
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/program.py", line 566, in execute
executor.execute(*self.tasks)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/executor.py", line 129, in execute
result = call.task(*args, **call.kwargs)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/tasks.py", line 127, in __call__
result = self.body(*args, **kwargs)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/tasks.py", line 48, in build_cffi
ffi.cdef(h_file.read())
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/api.py", line 112, in cdef
self._cdef(csource, override=override, packed=packed, pack=pack)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/api.py", line 126, in _cdef
self._parser.parse(csource, override=override, **options)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 358, in parse
self._internal_parse(csource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 363, in _internal_parse
ast, macros, csource = self._parse(csource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 307, in _parse
self.convert_pycparser_error(e, csource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 336, in convert_pycparser_error
raise CDefError(msg)
cffi.CDefError: parse error
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/sys/_types/_int8_t.h:30:18: before: char
使用 CFFI 有两个步骤。第一个是决定您是使用 ABI 还是 API 模式---ffi.dlopen()
与 ffi.set_source()
;有关详细信息,请参阅 https://cffi.readthedocs.io/en/latest/overview.html#abi-versus-api。然后你需要相应地编写对 ffi.cdef()
的调用。我通常建议使用 API 模式,这种模式更加灵活,但需要 C 编译器 install-time (就像你编写标准 CPython C 扩展模块一样)。在这两种模式下,您应该在对 ffi.cdef()
的调用中手动复制 C header 的部分;在 API 模式下,您可以省略更多细节并用 ...
(dot-dot-dot).
替换它们
在这两种模式中,您都不能随意粘贴一个 C header 来利用所有标准 C 功能。调用 gcc -E
只会让问题变得更难(但在某些情况下已经完成了非常大的库,有很多自定义 post-processing)。 ffi.cdef()
的要点是,通常情况下,您粘贴 的 简化 版本只是 您需要的功能。
准确回答您的问题:
直接支持只是常量的宏,如整数。在 API 模式下你也可以写 #define MY_CONSTANT ...
和 dot-dot-dot.
在 API 模式(仅)中支持像函数一样工作的宏,方法是使用以下技巧:将它们写在 ffi.cdef()
中,就好像它们是常规函数一样。这足以调用它们了。
对于更复杂的情况,您可能必须编写一个真正的 C 函数来根据需要包装一个或多个宏的使用。随便起一个新的函数名,在ffi.cdef()
声明函数,最后在ffi.set_source()
.
直接实现函数
在ABI模式下,完全不支持后两种情况---ABI中不再存在宏。
这里是C新手。我的用例是将 here 发布的头文件提供给 python 库 cffi
,以便我可以绑定到 C 库。前面link中的头文件有宏。 cffi
我认为只接受没有宏的头文件。
- 有没有办法通过指定任何选项将带有宏的头文件提供给
cffi
? - 如果没有,我该如何预处理该文件以便将其提供给
cffi
?我尝试了gcc -E ddlog.h > ddlog-processed.h
,但是当我 运行 使用cffi
以下代码时,它出错了。
重现步骤:
- 下载 ddlog.h
pip install cffi
gcc -E ddlog.h > ddlog-processed.h
- 在与
ddlog.h
相同的文件夹中的文件build.py
中,放置
import cffi
import pathlib
ffi = cffi.FFI()
this_dir = pathlib.Path().absolute()
h_file_name = this_dir / "ddlog-processed.h"
with open(h_file_name) as h_file:
ffi.cdef(h_file.read())
python build.py
它给出错误:
Traceback (most recent call last):
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 305, in _parse
ast = _get_parser().parse(fullcsource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/c_parser.py", line 152, in parse
debug=debuglevel)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/ply/yacc.py", line 331, in parse
return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/ply/yacc.py", line 1199, in parseopt_notrack
tok = call_errorfunc(self.errorfunc, errtoken, self)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/ply/yacc.py", line 193, in call_errorfunc
r = errorfunc(token)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/c_parser.py", line 1861, in p_error
column=self.clex.find_tok_column(p)))
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/pycparser/plyparser.py", line 67, in _parse_error
raise ParseError("%s: %s" % (coord, msg))
pycparser.plyparser.ParseError: /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/sys/_types/_int8_t.h:30:18: before: char
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/bin/invoke", line 10, in <module>
sys.exit(program.run())
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/program.py", line 384, in run
self.execute()
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/program.py", line 566, in execute
executor.execute(*self.tasks)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/executor.py", line 129, in execute
result = call.task(*args, **call.kwargs)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/invoke/tasks.py", line 127, in __call__
result = self.body(*args, **kwargs)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/tasks.py", line 48, in build_cffi
ffi.cdef(h_file.read())
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/api.py", line 112, in cdef
self._cdef(csource, override=override, packed=packed, pack=pack)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/api.py", line 126, in _cdef
self._parser.parse(csource, override=override, **options)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 358, in parse
self._internal_parse(csource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 363, in _internal_parse
ast, macros, csource = self._parse(csource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 307, in _parse
self.convert_pycparser_error(e, csource)
File "/Users/rabraham/Documents/dev/ddlog/playpen_ddlog/venv/lib/python3.7/site-packages/cffi/cparser.py", line 336, in convert_pycparser_error
raise CDefError(msg)
cffi.CDefError: parse error
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/sys/_types/_int8_t.h:30:18: before: char
使用 CFFI 有两个步骤。第一个是决定您是使用 ABI 还是 API 模式---ffi.dlopen()
与 ffi.set_source()
;有关详细信息,请参阅 https://cffi.readthedocs.io/en/latest/overview.html#abi-versus-api。然后你需要相应地编写对 ffi.cdef()
的调用。我通常建议使用 API 模式,这种模式更加灵活,但需要 C 编译器 install-time (就像你编写标准 CPython C 扩展模块一样)。在这两种模式下,您应该在对 ffi.cdef()
的调用中手动复制 C header 的部分;在 API 模式下,您可以省略更多细节并用 ...
(dot-dot-dot).
在这两种模式中,您都不能随意粘贴一个 C header 来利用所有标准 C 功能。调用 gcc -E
只会让问题变得更难(但在某些情况下已经完成了非常大的库,有很多自定义 post-processing)。 ffi.cdef()
的要点是,通常情况下,您粘贴 的 简化 版本只是 您需要的功能。
准确回答您的问题:
直接支持只是常量的宏,如整数。在 API 模式下你也可以写
#define MY_CONSTANT ...
和 dot-dot-dot.在 API 模式(仅)中支持像函数一样工作的宏,方法是使用以下技巧:将它们写在
ffi.cdef()
中,就好像它们是常规函数一样。这足以调用它们了。对于更复杂的情况,您可能必须编写一个真正的 C 函数来根据需要包装一个或多个宏的使用。随便起一个新的函数名,在
ffi.cdef()
声明函数,最后在ffi.set_source()
. 直接实现函数
在ABI模式下,完全不支持后两种情况---ABI中不再存在宏。