4

私は、ライブラリを使用するプログラムの存続期間中に1回だけ実行する必要がある初期化コードを持つOCamlライブラリを作成しています(そして、プログラムの存続期間中持続するが、ライブラリ自体の中でのみ使用される状態を保存します)、およびライブラリを使用するプログラムが終了するときにのみ実行する必要があるいくつかのクリーンアップコード。

関連性がある場合、私のライブラリは2つの部分に分かれています。低レベルのCライブラリへのインターフェイスと、それを使用したプログラミングを容易にするための高レベルのものです。Cのどこかで必要なことを実行できますか?理想的には、私のユーザーはそれがどのように実装されているかを気にせず、Cビットを見ることはありません。

Pythonでは、コードを実行してこれを行いますimportが、OCamlopenは実際には何も実行せず、モジュールの名前空間、次にPythonの名前空間をatexitシュガーしますが、Ocamlに相当するものが見つかりません。

私が検討したアプローチの1つは、ライブラリを「フレームワーク」として構造化することですが、そのような過剰に設計されたアプローチを正当化するほど重要ではないと思います。ありがとう!

更新:わかりました-わかりました-私は思います。終了時のクリーンアップを処理するためにCコードを使用していますが、コードを少し操作したので、C側にグローバル状態へのポインターがあります。

私の図書館には今持っているように見えます

let global_env = env_create ()

そして、それがopenメインプログラムによって実行されると、これ実行されます...しかし、どのように?

4

2 に答える 2

7

これは、OCaml側でPervasives.at_exitトップレベルのステートメントを使用して実行し、環境を作成してクリーンアップコードをインストールできることに注意してください。

let env = init ()
let cleanup () = do_clean env
let () = at_exit cleanup 

let f x = f_stub env x

トップレベルのステートメントは、モジュールがロードされたときに実行され(最終的に使用するかどうかに関係なく)、リンク時に指定した順序でモジュールがロードされます(したがって、他のモジュールに依存するモジュールは、順番が来たときに依存関係が初期化されることが保証されます) 、ocamlcのマニュアルの「.cmoで終わる引数」を参照してください。これは、モジュールにアクセスしようとする前にトップレベルのステートメントが実行されることを意味します。モジュールを開くことは問題でopenはなく、単に(悪い)構文上の便利さです。

モジュールの関数が最終的に呼び出された場合にのみ初期化コードを実行する場合は、遅延値を使用します。

let env = lazy (init ())
let cleanup () = if Lazy.lazy_is_val env then (do_clean env) else () 
let () = at_exit cleanup

let f x = f_stub (Lazy.force env) x

ところで。結果として生じるスレッドセーフの問題を文書化することを忘れないでください...

于 2011-05-06T14:26:36.680 に答える
1

その時点以降で使用できるlet x = function ...関数を定義するのと同じように、はである値を定義します。の戻り値が必要ない場合は、副作用のためだけに実行するため、mlファイルの最後(正直なところ、どこでも)に言及することもできます。この場合、私はそうしますが、それはもっと明確だと思います。xlet global_env = ...global_envenv_createenv_create ()let _ = env_create ()

編集:Rは次のことが間違っていると指摘しました:「純粋にCでそれを行うには、それを探すべきだと思います。_init_finiこのHOWTOで説明されているように、これは実際に非推奨であり、属性を介して実行する必要があります。

于 2011-05-06T11:53:18.410 に答える