klitsche / ffigen
FFI绑定生成器
v0.8.1
2023-01-21 00:42 UTC
Requires
- php: ^7.4 || ^8.0
- brick/varexporter: ^0.3.2
- ircmaxell/php-c-parser: dev-master#fd8f5efefd0fcc6c5119d945694acaa3a6790ada
- symfony/console: ^5.0
- symfony/filesystem: ^5.0
- symfony/yaml: ^5.0
Requires (Dev)
- phpunit/phpunit: ^9.1
- symplify/easy-coding-standard: ^11.2
README
ffigen
是一个简单的命令行助手,用于快速生成和更新用于C库的低级PHP FFI绑定。
它根据提供的C头文件生成两个PHP文件
constants.php
- 存储常量值Methods.php
- 存储函数绑定作为静态方法,并在trait中包含phpdoc
它深受FFIMe的启发,并依赖于ircmaxell的PHPCParser。
进行中:所有0.*预发布版本都可能发生破坏性更改。
要求
- PHP ^7.4 || ^8.0
- 例如:必须启用FFI扩展
快速入门
在你的项目中安装
composer require --dev klitsche/ffigen
安装一个c库(例如uuid)。
将配置文件添加到项目根目录
.ffigen.yml
修改此配置文件(示例)
headerFiles: - uuid/uuid.h libraryFile: libuuid.so.1 parserClass: Klitsche\FFIGen\Examples\UUID\FFIGen\Parser outputPath: ./ excludeConstants: - /^(?!(FFI|UUID)_).*/ excludeMethods: namespace: Klitsche\FFIGen\Examples\UUID
可选:添加自己的Parser类来自定义预处理或后处理逻辑(示例)
<?php declare(strict_types=1); namespace Klitsche\FFIGen\Examples\UUID\FFIGen; use Klitsche\FFIGen\Config; class Parser extends \Klitsche\FFIGen\Adapter\PHPCParser\Parser { public function __construct(Config $config) { parent::__construct($config); $this->context->defineInt('_SYS_TYPES_H', 1); $this->context->defineInt('_SYS_TIME_H', 1); $this->context->defineInt('_TIME_H', 1); } protected function parseHeaderFile(string $file): array { $file = $this->searchHeaderFilePath($file); $prependHeaderFile = ' typedef long time_t; '; $tmpfile = tempnam(sys_get_temp_dir(), 'ffigen'); file_put_contents($tmpfile, $prependHeaderFile . file_get_contents($file)); $declarations = parent::parseHeaderFile($tmpfile); unlink($tmpfile); return $declarations; } private function searchHeaderFilePath(string $file): string { if (file_exists($file)) { return $file; } foreach ($this->context->headerSearchPaths as $headerSearchPath) { if (file_exists($headerSearchPath . '/' . $file)) { return $headerSearchPath . '/' . $file; } } throw new \RuntimeException(sprintf('File not found: %s', $file)); } }
别忘了在composer.json中注册Parser命名空间以进行自动加载(开发环境可以)
"autoload-dev": { "psr-4": { "Klitsche\\FFIGen\\Examples\\": "examples" } },
使用以下命令进行自动加载
composer dump-autoload
运行ffigen生成绑定文件
vendor/bin/ffigen
这将生成输出路径中的两个文件
constants.php
- 将此添加到你的自动加载中Methods.php
- 将此添加到你的自己的类上下文中,并在你的高级PHP库中使用它
别忘了将constants.php
添加到composer.json中以进行自动加载
"autoload": { "files": [ "tweak-path-to/constants.php", ] },
尝试示例
构建带有预安装c库的docker镜像(uuid,snappy & librdkafka)
docker-compose build php74
运行uuid示例
docker-compose run --rm php74 php bin/ffigen generate -c examples/UUID/.ffigen.yml
docker-compose run --rm php74 php examples/UUID/test.php
运行snappy示例(请参阅Snappy类以获取一个简单的示例)
docker-compose run --rm php74 bin/ffigen generate -c examples/Snappy/.ffigen.yml
docker-compose run --rm php74 php examples/Snappy/test.php
运行rdkafka示例(librdkafka 1.5.2 & 模拟集群)
docker-compose run --rm php74 bin/ffigen generate -c examples/RdKafka/.ffigen.yml
docker-compose run --rm php74 php examples/RdKafka/test.php
待办事项
- 添加travis
- 添加更多测试
- 添加文档
- 添加Windows,macOS的支持
- 添加更多示例(并从中学习)
- 考虑多版本支持
- 考虑为类型生成自定义接口/类
- 考虑添加clang / cpp / readelf适配器(cpp定义仅包含 & 清洁文件,clang -c11 ast-dump=json,readelf --dyn-syms)