Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPからC#のライブラリを呼べるようにしたdotnet_ffiを趣味でつくってみた

johgus
September 24, 2022

 PHPからC#のライブラリを呼べるようにしたdotnet_ffiを趣味でつくってみた

PHP Conference Japan 2022 の 09/25に行なわれる
dotnet_ffiについての講演資料です。
https://fortee.jp/phpcon-2022/proposal/6fa15e19-4a11-4af0-b5ff-ee19aa8ff931

dotnet_ffiソース
https://github.com/pg-ito/dotnet_ffi

文: よーがす
Twitter: @pg_ito
Blog: https://b64.pw/blog/

johgus

September 24, 2022
Tweet

Other Decks in Programming

Transcript

  1. もくじ • dotnet_ffiってなに? • 作った動機 • 想定される利用ケース • dotnet_ffiの構成 •

    dotnet_ffiの簡単な使い方 • CoreCLRって? • Extensionを作るための情報源 • まとめ • 今後の展望
  2. PHP Process 設計の特徴 ・PHP ExtensionがC/C++で書けることを利用してCoreCLR経由でC#とバインド PHP ➡ dotnet_ffi(C,C++) ➡ CoreCLR(C++)

    ➡ C# Library PHP 標準 Extension CoreCLR (C++) C# Library PHP 標準関数等 PHP 言語 構造 dotnet_ffi (C, C++) ※CoreCLRについては後述
  3. PHP8対応での影響 ・ARG_INFOの対応 PHP8でビルドするとついにwarningが出るようになった。 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &arg1, &arg2) == FAILURE)

    { ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ret_s64_arg_s64_s64, 0, 2, IS_LONG, 0) ZEND_ARG_INFO(0, long_arg1) ZEND_ARG_INFO(0, long_arg2) ZEND_END_ARG_INFO() PHP_ME(DotnetFFI, ret_s64_arg_s64_s64, arginfo_ret_s64_arg_s64_s64, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 型情報を追加
  4. ビルド ・ソースのクローン git clone https://github.com/pg-ito/dotnet_ffi.git . ・docker composeでビルドと実行 cd build_env

    docker compose -up -d --build docker compose exec php_fpm /bin/bash -c "cd /var/www && ./br.sh && ./run.sh" ・もし直接ビルドする場合 yum install -y devtoolset-7-gcc devtoolset-7-gcc-c++ yum install -y --enablerepo=epel,remi,remi-php81 php php-devel yum install -y dotnet-sdk-6.0 ./br.sh
  5. dotnet_ffiの簡単な使い方 ・引数がint、戻り値もintの場合の呼び出し方 $retInt64 = DotnetFFI::ret_s64_arg_s64(30); ※デフォルト設定だとdotnet_dllディレクトリにある fibonacci数のサンプルコードを呼び出すようになっている(iniで変更可) ・実行 docker compose

    exec php_fpm /bin/bash -c "cd /var/www && ./run.sh mycode.php" ・その他サンプルコード ./ext_test.php … 各種メソッドの動作サンプル ./benchmarker/runbench.php … フィボナッチのベンチマーク
  6. CoreCLRの使い方(初期化) ・libcoreclr.soをdlopenする coreClr = dlopen(coreClrPath.c_str(), RTLD_NOW | RTLD_LOCAL); ・dlsymでそれぞれのシンボルのアドレスを取得 initializeCoreClr

    = (coreclr_initialize_ptr)dlsym(coreClr, "coreclr_initialize"); createManagedDelegate = (coreclr_create_delegate_ptr)dlsym(coreClr, "coreclr_create_delegate"); shutdownCoreClr = (coreclr_shutdown_ptr)dlsym(coreClr, "coreclr_shutdown");
  7. CoreCLRの使い方(初期化) ・CoreCLR初期化 CoreCLRにpublishされたC#の.dllファイルパスを「:」区切りで propertyValuesに一通りわたして初期化します int hr = initializeCoreClr( runtimePath, //

    App base path "HostingOnPHP", // AppDomain friendly name sizeof(propertyKeys) / sizeof(char*), // Property count propertyKeys, // Property names propertyValues, // Property values &hostHandle, // Host handle &domainId); // AppDomain ID dotnet_ffiではPHPプロセスが作られるタイミングで初期化 PHP_MINIT_FUNCTION(dotnet_ffi)
  8. CoreCLRの使い方(C#呼び出し) ・C#のメソッドの関数ポインタを取得 C#のプロジェクト名、名前空間までつけた完全修飾のクラス名、メソッド名とC#のクラスへ のアドレスが格納されるポインタを渡す *hr = createManagedDelegate ( hostHandle, domainId,

    target_project_name .c_str(), target_class_name.c_str(), method_name, (void**)&managedDelegateInvokeReturnString); ・C#のメソッド呼び出し std::string ret = managedDelegateInvokeReturnString(inStr); この関数ポインタを実行することで C#のメソッドを呼び出せる
  9. Extensionのひな形の作り方 extension_exampleというExtensionを作る場合の例 php ext_skel.php --ext extension_example cd extension_example phpize ./configure

    make make test ※PECLでXMLを書いてひな形にする方法もあります ここに作りたいExtension名を指定する