[openrtm-users 00500] Re: 質問:サービスポートのIDLにおいて、複数のIDL間で、共通に利用する型を参照する方法

Ando Noriaki n-ando @ aist.go.jp
2008年 7月 1日 (火) 18:42:47 JST


小田様

産総研 安藤です

方法は3つ位あります。

一番簡単な方法は、以下のように一つのIDLに記述することです。
Observer と Notifier は Subject で相互に依存してますので、
それほど変なやり方じゃないと思います。

好みの問題になりますが、IDLはあまり分割しないのが一般的です。
OpenRTMに付属のIDLを見ていただければわかると思いますが、
ある機能を提供するインターフェースのセットをまとめてIDLで定義しています。
CORBAのその他のIDL定義も、それほど細かく分割されていません。

原理的には分割しても、ちゃんとコンパイルできなければならないのですが、
rtc-templateはファイル間の依存関係まで調べてコードを生成しているわけでは
ありませんので、複雑依存関係のあるIDLの場合、Makefileやコードなどに
いろいろ手直しが必要になります。

-------------------------Observer.idl---------------------------
interface Subject {
        void    foo();
};

interface Observer {
        void listenUpdate(in Subject aSubject);
};

interface Notifier {
       void    notifyUpdate(in Subject aSubject);
};
-------------------------Observer.idl---------------------------

rtc-template -bcxx \
    --module-name=SubjectObserverEngine --module-type='DataFlowComponent' \
    --module-desc='Subject Observer Engine test' \
    --module-version=1.0 --module-vendor='Kyushu Institute of Technology' \
    --module-category=Consumer \
    --module-comp-type=DataFlowComponent --module-act-type=SPORADIC \
    --module-max-inst=1 \
    --service=Notifier:notifier:Notifier \
    --consumer=Observer:observer0:Observer \
    --consumer=Observer:observer1:Observer \
    --consumer=Observer:observer2:Observer \
    --service-idl=Observer.idl


2番目のやり方は、面倒ですがMakefileを修正するやり方です。
以下の修正を施したMakefileでビルドできました。

--- Makefile.SubjectObserverEngine      2008-07-01 17:44:43.000000000 +0900
+++ n-ando.Makefile     2008-07-01 18:12:29.000000000 +0900
@@ -28,7 +28,7 @@
 WRAPPER  = rtm-skelwrapper
 WRAPPER_FLAGS = --include-dir="" --skel-suffix=Skel --stub-suffix=Stub

-SKEL_OBJ = NotifierSkel.o
+SKEL_OBJ = NotifierSkel.o SubjectSkel.o
 STUB_OBJ = ObserverStub.o
 IMPL_OBJ = NotifierSVC_impl.o
 OBJS     = SubjectObserverEngine.o $(SKEL_OBJ) $(STUB_OBJ) $(IMPL_OBJ)
@@ -60,6 +60,13 @@
        rm -f *Skel.h *Skel.cpp
        rm -f *Stub.h *Stub.cpp

+SubjectSkel.cpp : Subject.idl
+       $(IDLC) $(IDLFLAGS) Subject.idl
+       $(WRAPPER) $(WRAPPER_FLAGS) --idl-file=Subject.idl
+SubjectSkel.h : Subject.idl
+       $(IDLC) $(IDLFLAGS) Subject.idl
+       $(WRAPPER) $(WRAPPER_FLAGS) --idl-file=Subject.idl
+
 NotifierSkel.cpp : Notifier.idl
        $(IDLC) $(IDLFLAGS) Notifier.idl
        $(WRAPPER) $(WRAPPER_FLAGS) --idl-file=Notifier.idl
@@ -75,7 +82,7 @@
        $(WRAPPER) $(WRAPPER_FLAGS) --idl-file=Observer.idl

 SubjectObserverEngine.so: $(OBJS)
-SubjectObserverEngine.o: SubjectObserverEngine.h NotifierSkel.h
NotifierSVC_impl.h ObserverStub.h
+SubjectObserverEngine.o: SubjectObserverEngine.h NotifierSkel.h
NotifierSVC_impl.h ObserverStub.h SubjectSkel.h
 SubjectObserverEngineComp.o: SubjectObserverEngineComp.cpp
SubjectObserverEngine.cpp SubjectObserverEngine.h NotifierSkel.h
NotifierSVC_impl.h

 NotifierSVC_impl.o: NotifierSVC_impl.cpp NotifierSVC_impl.h
NotifierSkel.h NotifierStub.h


3番目のやり方はSubjectをサービスポートのプロバイダとしてrtc-templateの
引数に渡して、あとでregisterProviderしている部分を削除する方法です。


        rtc-template -bcxx \
            --module-name=SubjectObserverEngine
--module-type='DataFlowComponent' \
            --module-desc='Subject Observer Engine test' \
            --module-version=1.0 --module-vendor='Kyushu Institute of
Technology' \
            --module-category=Consumer \
            --module-comp-type=DataFlowComponent --module-act-type=SPORADIC \
            --module-max-inst=1 \
            --service=Notifier:dummy:Subject \
            --service=Notifier:notifier:Notifier \
            --service-idl=Subject.idl \
            --service-idl=Notifier.idl \
            --consumer=Observer:observer0:Observer \
            --consumer=Observer:observer1:Observer \
            --consumer=Observer:observer2:Observer \
            --consumer-idl=Observer.idl

"--service=Notifier:dummy:Subject"の部分がポイントです。
上記を実行すると、Subjectの実装ファイルも生成されます。
SubjectObserverEngine.cpp のコンストラクタ内の、

  m_NotifierPort.registerProvider("dummy", "Subject", m_dummy);

を削除すればとりあえず目的は達せられると思います。
気になるのであれば、SubjectObserverEngine.hの以下のダミー変数も
削除すればいいと思います。

  SubjectSVC_impl m_dummy;

ちなみに、お送りいただいたNotifier.idl内の、コメントアウトされた
  /*
 interface Subject {
         void    foo();
  };
  */
をみて rtc-template がSubject のインターフェース定義がそこにあると
勘違いしてしまいますので、これは消してください。



以上3つくらいの方法が考えられるのですが、お勧めは 1>3>2 の順です。

Subject は Consumerである Observerの引数に渡しているので、コンポーネント内では
SubjectのCORBAオブジェクトを生成しなければいけませんよね。
したがって、SVC_impl.[cpp|h] も同時に生成させたいのではないでしょうか?

2番目の方法では、SubjectSVC_impl.[cpp|h] が生成されません。
(自分で実装ファイルを書き起こすのであればこれでも全然問題ありません。)
1番目と3番目の方法では SubjectSVC_impl.[cpp|h] も生成されるので、
Subjectを実装するのが若干楽になりますね。

以上、簡単ですが参考になりましたでしょうか?



2008/07/01 17:10 小田 謙太郎 / Kentaro Oda <oda @ ci.kyutech.ac.jp>:
> 皆様
> 九州工業大学 小田と申します。
>
> Open-RTM 0.4.2 C++、Ubuntu 7、omniORB 4.0.7にて開発を行っています。
> そこで質問なのですが、サービスポートのIDL定義において、複数のIDL間で、共通に利用する型を参照する方法を知りたくメールしております。
>
> 例えば、デザインパターンでいうSubject-Observerパターンにおいて、Subjectの更新にともなって、複数のObserverに更新の通知を行うような
> コンポーネントSubjectObserverEngineを実装することを想定します。(最後に具体的なrtc-templateコマンドを挙げています)
> そこで、
> 監視の対象:Subject型、
> Subjectの通知の対象:Observer型、
> 通知を行う主体:Notifier型
> として宣言します。
>
> このとき、Observer型とNotifier型は、メソッドの引数にSubjectが必要なので、共にSubject型の宣言を必要としますが、これを素直を行う方法が分からなくて困っています。
>
>
> より詳細には、
>
> --- Subject.idl定義 ---
> interface Subject {
>        void    foo();
> };
>
> --- Observer.idl定義 ---
> /* includeによる方法
> #include "Subject.idl"
> */
> /* 埋め込みによる方法
> interface Subject {
>        void    foo();
> };
> */
> interface Observer {
>        void listenUpdate(in Subject aSubject);
> };
>
> --- Notifier.idl定義 ---
> /* includeによる方法
> #include "Subject.idl"
> */
> /* 埋め込みによる方法
> interface Subject {
>        void    foo();
> };
> */
> interface Notifier {
>        void    notifyUpdate(in Subject aSubject);
> };
>
> NotifierとObserverの宣言にて、Subject型を利用するには、Subject.idlをincludeによって取り込む方法と、Subject型の宣言を
> 埋め込む方法があると思いますが、これらの両方においてエラーが発生してしまいます。
>
> ・includeによる方法を用いた場合のエラー:
> ******** 途中省略 ******
> g++ `rtm-config --cflags` -I. -c -o SubjectObserverEngine.o
> SubjectObserverEngine.cpp
> NotifierSkel.h:31 から include されたファイル中,
>                 NotifierSVC_impl.h:8 から,
>                 SubjectObserverEngine.h:19 から,
>                 SubjectObserverEngine.cpp:7 から:
> Notifier.hh:24:22: error: Subject.hh: No such file or directory
> Notifier.hh:120: error: 'Subject_ptr' has not been declared
> Notifier.hh:154: error: 'Subject_ptr' has not been declared
> NotifierSVC_impl.h:32: error: 'Subject_ptr' has not been declared
> Observer.hh:120: error: 'Subject_ptr' has not been declared
> Observer.hh:154: error: 'Subject_ptr' has not been declared
> make[1]: *** [SubjectObserverEngine.o] エラー 1
> make[1]: ディレクトリ `/home/oda/opentest' から出ます
> make: *** [all] エラー 2
>
>
> ・埋め込みによる方法を用いた場合のエラー:
> ******** 途中省略 ******
> g++ `rtm-config --cflags` -I. -c -o SubjectObserverEngine.o
> SubjectObserverEngine.cpp
> Observer.hh:85: error: redefinition of 'class Subject'
> Notifier.hh:85: error: previous definition of 'class Subject'
> Observer.hh:112: error: redefinition of 'class _objref_Subject'
> Notifier.hh:114: error: previous definition of 'class _objref_Subject'
> Observer.hh:135: error: redefinition of 'class _pof_Subject'
> Notifier.hh:135: error: previous definition of 'class _pof_Subject'
> Observer.hh:144: error: redefinition of 'class _impl_Subject'
> Notifier.hh:146: error: previous definition of 'class _impl_Subject'
> Observer.hh:270: error: redefinition of 'class POA_Subject'
> Notifier.hh:273: error: previous definition of 'class POA_Subject'
> Observer.hh:312: error: redefinition of 'static void
> Subject::_marshalObjRef(_objref_Subject*, cdrStream&)'
> Notifier.hh:312: error: 'static void
> Subject::_marshalObjRef(_objref_Subject*, cdrStream&)' previously defined
> here
> make[1]: *** [SubjectObserverEngine.o] エラー 1
> make[1]: ディレクトリ `/home/oda/opentest' から出ます
> make: *** [all] エラー 2
>
> そもそも、rtc-templateのhelpによると、
> "    --consumer-idl=[IDL filename]:
>        Specify IDL file of service consumer.
>        For simplicity, please define one interface in one IDL file, although
>        this IDL file can include two or more interface definition,"
> となっており、1IDLにinterface定義を1つのみにすることは理解できます。
> しかしこれは、他のインターフェース型を参照することも防ぐものでしょうか?
>
>
> 利用したRTCテンプレート:
>  rtc-template -bcxx \
>            --module-name=SubjectObserverEngine
> --module-type='DataFlowComponent' \
>            --module-desc='Subject Observer Engine test' \
>            --module-version=1.0 --module-vendor='Kyushu Institute of
> Technology' \
>            --module-category=Consumer \
>            --module-comp-type=DataFlowComponent --module-act-type=SPORADIC \
>            --module-max-inst=1 \
>            --service=Notifier:notifier:Notifier \
>            --service-idl=Notifier.idl \
>            --service-idl=Subject.idl \
>            --consumer=Observer:observer0:Observer \
>            --consumer=Observer:observer1:Observer \
>            --consumer=Observer:observer2:Observer \
>            --consumer-idl=Observer.idl
>
> 小さいので(約700bytes)これらのファイルのセットを添付しておきます:
>
>



-- 
安藤慶昭@独立行政法人産業技術総合研究所 研究員
 知能システム研究部門 タスクインテリジェンス研究グループ
 〒305-8568 茨城県つくば市梅園1-1-1 中央第2
 TEL: 029-861-5981 FAX: 029-861-5971
 n-ando @ aist.go.jp, n-ando @ ieee.org



openrtm-users メーリングリストの案内