さて、これは長いものになります、事前にお詫び申し上げます。=)
ここで使用されているコードは、機密保持の理由から、残念ながら実際の製品コードと正確には一致していませんが、問題、いくつかのテスト済みの解決策を説明し、議論を容易にするために構築されていることを指摘する必要があります。概念レベルでは、すべてが削除されて簡略化されていますが、十分に似ています。データ保護は、実際には必要ですが、ここでは無視されています。
問題
Adaコードから生成された共有オブジェクト「data_provider」があります。Data_providerには内部データレコードがあり、これも(異なる)Adaコードから生成された多数の共有オブジェクト'data_user'1からnからアクセスする必要があります。これらは型defを含むAda仕様を共有しますが、パフォーマンス上の理由から、基本的にデータは共有オブジェクトの境界を越えて共有する必要があります。
これらの共有オブジェクトは、コンパイル時または実行時にlibdl(これはまだ石で書かれていません)を介してc ++メインプログラム(ここでは「ラッパー」と呼ばれます)にリンクされているため、ソリューションはどちらの方法でも機能する必要があります。完全な型defが利用できない場合でも、c++側からもデータを検査できると有益であると付け加えておきます。
-05はピンチで機能する可能性がありますが、コードはAda95コンパイルに合格する必要がある可能性があります。-12はテーブルから外れています。プラットフォームはRHEL5のGNATです。
私が試したもの
現在、「機能する」ソリューションは、データレコードのアドレスを取得し、それをラッパーに渡し、data_userオブジェクトに渡し、アドレス->アクセスを変換し、ポインティデータを内部オブジェクトにコピーすることです。これは、以下のサンプルコードで実装されているメソッドです。ただし、余分なコピーはパフォーマンスの面で問題になる可能性があります。
'動作する'別のテスト済みの方法は、data_providerに変数をエクスポートさせ、data_usersに同じものをインポートさせることですが、これには、コンパイル時にすべてをリンクする必要があり、データをグローバルに公開するため、もろいのは言うまでもなく、かなり汚い感じがします。
条項for data'address use addr
は、精緻化時に住所を知る必要があるため、機能しないと思います。
他のいくつかのことは試されて破棄されましたが、私は今のところそれらをテーブルから外しておきます。
以下のコードと組み合わせると、いくつかの提案を得るのに十分であることを願っています。ぜひ聞きたいです。何か説明が必要な場合は、それを求めてください。=)
私は実際、私がただ気が狂っていて、ここで明白な何かを見逃していることを望んでいます。そして、私は、この混乱全体が、Adaやその他の方法で、優れたコーディング慣行に完全に準拠していないことを認識していますが、それでも私はそれに固執しています。
wrapper.cpp
extern "C" {
void update_data( int fa, int fb );
int get_address( void );
void set_address( int addr );
void handle_new_data( void );
}
int main( int argc, char** argv ) {
int addr;
addr = get_address();
set_address( addr );
for (int i = 0; i < 42; i++) {
update_data( i, -i );
handle_new_data();
}
}
data_types.ads
package data_types is
-- dummy data type
-- SIMPLIFIED from actual use case
type data_t is
record
field_a : integer := 16#c0ffee#;
field_b : integer := 16#c0ffee#;
end record;
for data_t use
record
field_a at 0 range 0..31;
field_b at 4 range 0..31;
end record;
type data_t_ptr is access data_t;
end data_types;
data_provider.ads
with system,
data_types;
use system,
data_types;
package data_provider is
-- update internal data structure
-- SIMPLIFIED from actual use case
procedure update_data
( fa : in integer;
fb : in integer );
pragma export_procedure
( internal => update_data,
external => "update_data" );
-- return address to record containing data
function get_address return system.address;
pragma export_function
( internal => get_address,
external => "get_address" );
-- 'dummy' data; this needs to be passed to data_user
data : data_t;
end data_provider;
data_provider.adb
with system;
use system;
package body data_provider
is
procedure update_data
( fa : in integer;
fb : in integer )
is
begin
data.field_a := fa;
data.field_b := fb;
end ;
function get_address return system.address
is
begin
return data'address;
end;
end data_provider;
data_user.ads
with system,
data_types;
use system,
data_types;
package data_user
is
-- set address for the data record
procedure set_address
( addr : system.address );
pragma export_procedure
( internal => set_address,
external => "set_address" );
-- use the new data in internal data structure
-- SIMPLIFIED from actual use case
procedure handle_new_data;
pragma export_procedure
( internal => handle_new_data,
external => "handle_new_data" );
-- 'dummy' data; this needs to be passed from data_provider
data : data_t;
end data_user;
data_user.adb
with system,
unchecked_conversion,
data_types;
use system,
data_types;
package body data_user
is
function to_ptr is new unchecked_conversion
( source => system.address,
target => data_t_ptr );
-- set address for the data record
procedure set_address
( addr : system.address )
is
ptr : data_t_ptr;
begin
ptr := to_ptr( addr );
data := ptr.all;
end;
-- use the new data in internal data structure
-- SIMPLIFIED from actual use case
procedure handle_new_data
is
begin
null;
end;
end data_user;
TLDR
Adaで記述され、C ++から外部から呼び出される複数の共有ライブラリは、できればコピーせずに、Adaレコードに格納されている同じデータにアクセスする必要があります。それ、どうやったら出来るの?