[ C++で開発 ] [ TAO CORBA実装 ]

TAO1.4.8 Solaris 10 x86 SunStudio 11インストール記録

Solaris上のコンパイラ環境

Solaris環境では、主に次の2つのコンパイラが利用されています。

  1. Sun製コンパイラ
    製品名称がころころと変わっています。Sun WorkShop C++、Forte Developer C++、Sun ONE Studio C++、Sun Studio C++といった名称が該当します。かなり高価でしたが、SunStudio11から無償となりました。
  2. GCC:GNUコンパイラ・コレクション
    主に2.95および3.3の2バージョンが使用されています。

今回は、SunStudio 11を使用してビルドします。

ただし、ACE+TAOは標準ではGNU make用のGNUmakefileを提供しているので、Solaris標準makeコマンド(/usr/ccs/bin/make)ではビルドできません。GNU makeコマンド(/usr/sfw/bin/gmake)を用いてビルドします。

ACE_SSLをビルドするには、SSLのライブラリが必要です。Solaris 10の場合、標準でインストールされます。/usr/sfw/lib/libssl.so/usr/sfw/lib/libcrypto.so

ACE_QoSをビルドするには、RSVP API(RAPI)が必要です。

ビルドの準備

ソースの展開

作業ディレクトリとして、$HOME/workを設け、その下に展開します。

torutk$ cd work
work$ bzcat ACE+TAO+CIAO.tar.bz2 | tar xvf -
    :
work$ cd ACE_wrappers
ACE_wrapperse$

ビルドの実施記録

1. config.hの編集

$HOME/work/ACE_wrappers/ace/config.h ファイルを新規作成します。

#include "ace/config-sunos5.10.h"

config-sunos5.10.hのインクルードで定義されるもの

#define ACE_THR_PRI_OTHER_MIN (long) -20
#define ACE_HAS_SYS_LOADAVG_H
#undef ACE_LACKS_GETLOADAVG
#undef ACE_HAS_ONLY_SCHED_OTHER
#undef ACE_HAS_BROKEN_T_ERROR
#undef ACE_NEEDS_LWP_PRIO_SET
#define ACE_HAS_AIO_CALLS
#undef ACE_HAS_LIMITED_SELECT
#define ACE_HAS_SOCKLEN_T
#define ACE_HAS_SNPRINTF
#undef ACE_LACKS_ACE_IOSTREAM
#define ACE_LACKS_UNBUFFERED_STREAMBUF 1
#define ACE_TEMPLATES_REQUIRE_SOURCE
#define ACE_HAS_STD_TEMPLATE_SPECIALIZATION 1
#define ACE_HAS_TEMPLATE_TYPEDEFS 1
#define ACE_HAS_TYPENAME_KEYWORD 1
#define ACE_HAS_USING_KEYWORD 1
#define ACE_HAS_THR_C_DEST 1
#define ACE_HAS_THR_C_FUNC 1
#define ACE_HAS_CONSISTENT_SIGNAL_PROTOTYPES 1
#define ACE_HAS_SIG_C_FUNC 1
#define ACE_HAS_STDCPP_STL_INCLUDES 1
#define ACE_HAS_STRING_CLASS 1
#define ACE_HAS_STANDARD_CPP_LIBRARY 1
#define ACE_HAS_STDCPP_STL_INCLUDES 1
#define ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB 1
#define ACE_HAS_TEMPLATE_SPECIALIZATION 1
#define ACE_LACKS_IOSTREAM_FX 1
#define ACE_LACKS_LINEBUFFERED_STREAMBUF 1
#undef ACE_LACKS_MKSTEMP
#define ACE_HAS_POSIX_REALTIME_SIGNALS
#define ACE_HAS_POSIX_MESSAGE_PASSING
#define ACE_HAS_POSIX_SEM
#define ACE_ACE_POSIX_AIOCB_PROACTOR
#define ACE_LACKS_STDINT_H
#define ACE_LACKS_MEMORY_H
#define ACE_HAS_STD_TEMPLATE_CLASS_MEMBER_SPECIALIZATION
#define ACE_HAS_STD_TEMPLATE_METHOD_SPECIALIZATION
#define ACE_CAST_CONST const
#define ACE_HAS_HI_RES_TIMER
#define ACE_HAS_XPG4_MULTIBYTE_CHAR
#define ACE_LACKS_SIGNED_CHAR

2. platform_macros.GNU

$HOME/work/ACE_wrapers/include/makeinclude/platform_macros.GNU ファイルを新規に作成します。

ACE_wrappers/include/makeinclude/platform_macros.GNUの記述
ssl=1
exceptions=1
inline=1
security=1
minimum_corba=0
ami=1
rt_corba=1
smart_proxies=1
interceptors=1
interface_repo=1
corba_messaging=1
rmcast=1
qos=0
probe=0
profile=0
fakesvcconf=0
shared_libs_only=1
debug=1    # (or debug=0 if release build)
fast=0 # (or fast=1 if solaris specific optimize build)
CFLAGS += -D_POSIX_PTHREAD_SEMANTICS
TAO_ORBSVCS=CosNaming,CosEvent,CosNotification,RTEvent
include $(ACE_ROOT)/include/makeinclude/platform_sunos5_sunc++.GNU

使用するオプションについては、$HOME/work/ACE_wrapers/include/makeinclude/wrapper_macros.GNUのコメントを見ると説明が記載されています。

指定フラグ名 内容
debug デバッグオプション指定でコンパイルする
exceptions C++例外機構を使用する
include_env CORBA::Environment引数を使用(TAO 1.2.2後方互換)
minimum_corba minimumCORBAをサポートする
fast Sun C++において最適化-fastオプション指定でコンパイルする
inline ACEインライン化を有効。
templates テンプレート型のインスタンス化を自動
optimize 最適化オプション指定でコンパイルする
probe ACE_Timeprobesを有効にする
profile プロファイリングオプション指定でコンパイルする
purify メモリリーク検査ツールPurify
quantify プロファイリングツールQuantify
repo GNUテンプレートリポジトリを使う
rtti 実行時型識別(RTTI)を有効
shared_libs 共有ライブラリを生成する
static_libs 静的リンクライブラリを生成する
shared_libs_only 共有ライブラリだけを生成する
static_libs_only 静的リンクライブラリだけを生成する
static_link 静的リンクライブラリとだけリンクする
threads スレッドサポート
ace_for_tao ace_for_taoサブセットをビルドする。TAOを使う際に必要な機能だけ持ったACEを生成する
xt X11 Toolkitを使用してビルドする
fl FlTk(Fast Light Toolkit)を使用してビルドする
tk Tcl/Tkを使用してビルドする
qt Qtを使用してビルドする
ssl OpenSSLを使用してビルドする
rapi RAPIを使用してビルドする
stlport STLPortを使用してビルドする
rwho rwhoを使用する
pipes コンパイラに-pipeオプションを渡す
split
sctp
versioned_so
wfmo
winregistry

TAO_ORBSVCSについては、ACE_wrappers/TAO/orbsvcs/orbsvcs/GNUmakefile.*を参照します。CORBA標準サービスやTAOが提供するサービスをビルドする場合に指定します。

Naming
Event
CosEvent
Time
Trader
ImplRepo
Property
AV
Concurrency
LifeCycle
PortableGroup
CosLoadBalancing
Notify
Trader
EventLog
Log
FTORB_Utils
FTRT_ClientORB
FTRT_EventChannel
FT_ServerORB
FaultTolerance
FtRtEvent
HTIOP
IFRService
RTCORBAEvent
Sched
RTEvent
RTEventLog
RTKokyuEvent
RTSchedEvent
RT_Notify
Security
SSLIOP

使用するスレッドAPIの設定

Solaris OSは、2つの種類のスレッドAPIが利用できます。1つは、旧来からのSolarisスレッドAPI、そしてもう1つはPOSIXスレッドAPIです。ACE/TAOではデフォルトでは両方のスレッドAPIを使用可能としていますが、以下の定義を追加することによってPOSIXスレッドに固定することができます。

CFLAGS += -D_POSIX_PTHREAD_SEMANTICS

3. コンパイル・リンク

環境変数の設定

環境変数ACE_ROOT
ACE_wrappers$ export ACE_ROOT=`pwd`
ACE_wrappers$ echo $ACE_ROOT
/export/home/torutk/work/ACE_wrappers
ACE_wrappers$
環境変数TAO_ROOT
ACE_wrappers$ export TAO_ROOT=$ACE_ROOT/TAO
ACE_wrappers$ echo $TAO_ROOT
/export/home/torutk/work/ACE_wrappers/TAO
ACE_wrappers$
環境変数LD_LIBRARY_PATH
ACE_wrappers$ export LD_LIBRARY_PATH=$ACE_ROOT/ace:$TAO_ROOT/lib:$LD_LIBRARY_PATH
ACE_wrappers$
環境変数SSL_ROOT (オプション)

ACE SSLのビルドを行う際は設定する必要があります。

ACE_wrappers$ export SSL_ROOT=/usr/sfw
ACE_wrappers$

ACE+TAOのビルドファイル

TAOディレクトリには、TAOACE.mwcファイルがあります。この中は以下の記述となっています。

// -*- MPC -*-
// TAOACE.mwc,v 1.9 2005/02/15 20:11:11 elliott_c Exp

workspace {
  ../ace
  ../apps/gperf/src
  ../ACEXML/common
  ../ACEXML/parser/parser
  ../ACEXML/apps/svcconf
  ../Kokyu/Kokyu.mpc
  ../protocols
  tao
  TAO_IDL
  utils
  orbsvcs
  exclude {
    orbsvcs/tests
    orbsvcs/performance-tests
    orbsvcs/examples
  }
}

TAOが必要とするACE、gperf、ACEXMLなども含めてビルドする設定となっています。この設定でTAOをビルドします。そこで、MPCツールを使ってまずTAOACE.mwcファイルからGNU make用のメイクファイルを生成します。

ACE_wrappers$ cd TAO
TAO$ mwc.pl TAOACE.mwc
TAO$ mwc.pl TAOACE.mwc
Generating gnuace output using TAOACE.mwc
Skipping ACE_FOR_TAO (ace_for_tao.mpc), it requires ace_for_tao.
Skipping QoS (qos.mpc), it requires qos.
Skipping wxNamingViewer (wxNamingViewer.mpc), it requires wxWindows.
Skipping NamingViewer (NamingViewer.mpc), it requires mfc.
Skipping RTCosScheduling (RTCosScheduling.mpc), it requires dummy_label.
Skipping PSDL (PSDL.mpc), it requires dummy_label.
Skipping PSDL_Datastore (PSDL.mpc), it requires dummy_label.
Skipping PSDL_Parser (PSDL.mpc), it requires dummy_label.
Generation Time: 14m 9s
TAO$ 

ワークスペースを生成するので、MPCツールの中のmwc.plコマンドを使用します。

ACE、TAOのビルド

ACE_wrappers$ gmake
 :
ace$ 

gperfのビルド

ace$ cd ../apps/gperf/src
src$ gmake
 :
src$ ls gperf
gperf
src$

TAOコアのビルド

ダイナミックリンクライブラリをビルドします)。

src$ cd $TAO_ROOT/tao
tao$ 
gmake
 :
tao$  

TAOサービスのビルド

各種COSサービスなどをビルドします。

tao$ cd ../orbsvcs/orbsvcs
orbsvcs$ 
gmake
 :
orbsvcs$  

4. インストール

ACE+TAOをビルドすると、作業ディレクトリは2GB超になります。必要なものだけをコピーして使用します。現状では残念ながらインストール用のスクリプトが提供されていないので、自分でファイルをコピーすることになります。

インストール先

Solarisでは、サードパーティ製のアプリケーションは/opt下にインストールするのが流儀のようです。そこで、/optの下にTAOというディレクトリを作成し、その中にインストールすることにします。

# PS1="\W> "
ACE_wrappers> mkdir /opt/TAO
ACE_wrappers>

TAOの下のディレクトリ構成は、ACE+TAOのディレクトリ構成と同じにします。ディレクトリ構成を変更すると、ACE+TAOで提供されるMakefileのビルド環境を修正する必要が生じるためです。すべて自力でコントロールするなら好みのディレクトリ構成でもよいでしょう。

インストール

ACEのヘッダーファイルをコピーします。

ACE_wrappers> find ace \( -name "*.[hi]" -o -name "*.inl" \) -print |
cpio -pmd /opt/TAO

ACE_wrappers> find ace -name "*.h" | xargs grep "^[ ]*#[ ]*include" |
grep ".cpp" | nawk 'FS="\""{split($0, chank); gsub(/.*\//, "", chank[2]);
print "find ace -name", chank[2], " | cpio -pmd /opt/TAO/"}' > install.sh

ACE_wrappers>
aceディレクトリ下の拡張子.h、.i、.inlを/opt/TAOにディレクトリ構造を維持してコピーします。
拡張子.hの中において、#include文で拡張子.cppをインクルードしているものがあります。この.cppはヘッダーファイルと同じ扱いをする必要があります。したがって、これらを抜き出してコピーします。
抜き出し方法は、aceディレクトリ以下の拡張子.hファイルに含まれる#include "XX.cpp"行を抜き出し、XX.cppの部分文字列を取り出し、これをfind文で検索しcpioでディレクトリ構造を保持したままコピーするスクリプトを生成し実行するものです。
簡単に説明すると、.hファイルの中で#include文の一部に、#の前や#とiの間に空白が含まれていたりするので、空白が含まれてもよいようにgrepで正規表現を組んでいます。また、#include文の行からインクルードするファイル名部分だけを取り出すためにnawkを使っています。セパレータを"とすると簡単にファイル名部分が切り出せます。ただし、ファイル名部分にはディレクトリパスが付いているもの、付いていないものがあるので、ディレクトリ部分を削除するためにnawkのgsub関数でディレクトリ部分を削除しています。このあと、findでファイル名を検索してディレクトリ構造を保持してコピーするスクリプト文を作成しています。

ACE/TAOのメイクファイル類をコピーします

ACE_wrappers> cp -r include /opt/TAO
ACE_wrappers> cp TAO/rules.tao.GNU /opt/TAO/TAO
ACE_wrappers> 
ACE/TAOを利用するアプリケーションをビルドする際に、これらメイクファイル用定義ファイルを使用します。

TAOのヘッダーファイルをコピーします。TAOのコア部分と、CORBA共通サービス類の部分があります。

ACE_wrappers> find TAO/tao TAO/orbsvcs \( -name "*.[hi]" -o -name "*.inl" \)
 -print | grep -v "examples" | grep -v "tests" | cpio -pmd /opt/TAO

ACE_wrappers> find TAO/tao TAO/orbsvcs -name "*.h" -o \( -name tests -o -name
 performance-tests -o -name examples \) -prune | xargs grep "^[ ]*#[ ]*include" |
 grep ".cpp" | nawk 'FS="\""{split($0, chank); gsub(/.*\//, "", chank[2]); print
 "find TAO -name", chank[2], "| cpio -pmd /opt/TAO/"}' > install.sh

ACE_wrappers> sh install.sh
ACE_wrappers>
TAOディレクトリ下の拡張子.h、.i、.inlを/opt/TAOにディレクトリ構造を維持してコピーします。
拡張子.hの中において、#include文で拡張子.cppをインクルードしているものがあります。この.cppはヘッダーファイルと同じ扱いをする必要があります。したがって、これらを抜き出してコピーします。

ACE/TAOのライブラリをコピーします。

ACE_wrappers> find . -name "lib*.so.*" | grep -v "tests" | grep -v "examples" |
gerp -v "./lib/" | sed 's|\(.*/\)\(lib.*.so\)\(.*\)|cp \1\2\3 /opt/TAO/lib;
ln -s ./\2\3 /opt/TAO/lib/\2 |g' > install.sh
ACE_wrappers> sh install.sh
ACE_wrappers>
ACE/TAOのライブラリ群を/opt/TAO/lib直下にコピーします。ライブラリファイルは、拡張子.soの後にバージョン番号が付与されています(例:libACE.so.5.4.8)。これらをコピーした後に、バージョン番号なしのライブラリファイル名をシンボリックリンクとして作成します(例:libACE.so -> ./libACE.so.5.4.8)。これらをコマンドラインで一気に実行する方法が組めなかったので、いったんシェルスクリプトファイルinstall.shを作成しこれを実行しています。

ACE/TAOの実行ファイルをコピーします。

ACE_wrappers> find . -name "*.mpc" -o \( -name tests -o -name performance-tests
 -o -name examples \) -prune | xargs grep exename | sed 's|\(.*/\).*mpc: *exename
 *= *\(.*\) | cp \1\2 /opt/TAO/bin|g' > install.sh
ACE_wrappers> sh install.sh
ACE_wrappers>
ACE/TAOの実行ファイルは、UNIXではファイル名規約だけからは判別できないので、ACE/TAOのプロジェクト設定ファイル(*.mpc)に記載されている実行ファイル名を抜き出し、この名前のファイルをコピーするスクリプトファイルを生成し、これを実行します。

MPCツールのコピー

ACE_wrappers> cp bin/m[pw]c.pl /opt/TAO/bin/
ACE_wrappers> cp -r MPC /opt/TAO/
ACE_wrappers> cp -r bin/MakeProjectCreator /opt/TAO/bin/
ACE_wrappers>
bin/mpc.plとMPC/mpc.plは同じファイル名ながら内容が異なっています。ACE/TAOプロジェクト生成時は、bin/mpc.plを使用します。

ACE/TAOプログラムのビルドと実行

はじめに、環境設定

work$ PATH=$PATH:/opt/TAO/bin
work$ export ACE_ROOT=/opt/TAO
work$ export TAO_ROOT=/opt/TAO/TAO
work$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/TAO/lib
work$

HelloACEプログラム

ACEライブラリを使用するプログラムを作成し、ビルド・実行します。

HelloACEソースファイル

hello_ace.cc
// hello_ace.cc
#include <ace/OS.h>

int main(int argc, char* argv[])
{
    ACE_OS::printf("Hello, ACE World!\n");
}

HelloACEプロジェクト設定ファイル

MPCツール用の設定ファイルを作成し、GNU make用のメイクファイルを生成します。今回は、ワークスペースは作成せずプロジェクトファイル1つだけを作成します。

Hello.mpc
project(Hello) : aceexe {
  exename = hello_ace
  Source_Files {
    hello_ace.cc
  }
}

mpc.plコマンドを実行し、GNU make用メイクファイルを生成します。

hello$ mpc.pl Hello.mpc
Generating gnuace output using default input
Generation Time: 1s
hello$ ls
GNUmakefile.Hello    hello_ace.cc
Hello.mpc
hello$
注記1
mpcファイルを指定せずにmpc.plコマンドを実行すると、カレントディレクトリに存在するソースファイルをもとに、ディレクトリ名を接尾子にしたGNUmakefile.helloを生成してしまいます。しかしそれは不十分なものになっているので要注意。

HelloACEのコンパイル・リンク

hello$ gmaek -f GNUmakefile.Hello
touch .depend.Hello

GNUmakefile: /home/torutk/work/hello/GNUmakefile.Hello MAKEFLAGS=

CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__ -I/opt/TAO  -c -o .obj/hello_ace.o hello_ace.cc
"/opt/TAO/ace/OS_NS_dirent.inl", 行 175: 警告 (旧式機能): scandir(const
 char*, dirent***, extern "C" int(*)(const dirent*), extern "C" int(*)
(const dirent**,const dirent**)) への呼び出しにおいて extern "C" int(*)
(const dirent*) 型の仮引数 3 に int(*)(const dirent*) が渡されています.
"/opt/TAO/ace/OS_NS_dirent.inl", 行 179: 警告 (旧式機能): scandir(const
 char*, dirent***, extern "C" int(*)(const dirent*), extern "C" int(*)
(const dirent**,const dirent**)) への呼び出しにおいて extern "C" int(*)
(const dirent**,const dirent**) 型の仮引数 4 に int(*)(const dirent**,
const dirent**) が渡されています.
2 個の警告が検出されました.
CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__ -I/opt/TAO  -mt -R /opt/TAO/lib -R./ -xildoff
 -L/opt/TAO/ace -L./  -L. -L/opt/TAO/lib -o hello_ace .obj/hello_ace.o
 -lACE  -lsocket -ldl -lnsl -lgen -lposix4 -ladm

hello$

HelloACEの実行

hello$ ./hello_ace
Hello, ACE World!
hello$

HelloTAOプログラム

TAOライブラリを使用するプログラムを作成し、ビルド・実行します。

HelloTAOソースファイル

CORBAを利用するプログラムは、クライアントとサーバと2種類があります。このクライアントとサーバ間での通信をIDLで定義します。

hello.idl
interface Hello {
    string get_greeting();
};
サーバ・プログラムのソースコード
hello_server.h
// hello_server.h
#include "helloS.h"

class HelloImpl : public virtual POA_Hello
{
public:
    virtual char* get_greeting() throw (CORBA::SystemException);
};
hello_server.cpp
#include "hello_server.h"
#include <iostream>

char* get_greeting() throw (CORBA_SystemException)
{
    return "Hello, CORBA TAO";
}

int main(int argc, char* argv[])
{
    try {
        CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
        CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
        PortableServer::POA_var poa = PortableServer::POA::_narrow(obj.in());
        PortableServer::POAManager_var manager = poa->the_POAManager();
        manager->activate();

        HelloImpl hello_servant;
        Hello_var hello = hello_servant._this();
        CORBA::String_var ior_string = orb->object_to_string(hello.in());
        std::cout << ior_string.in() << std::endl;

        orb->run();
    } catch (const CORBA::Exception& e) {
        std::cerr << "Uncaught CORBA exception" << std::endl;
        return 1;
    }
    return 0;
}
クライアント・プログラムのソースコード
hello_client.cpp
#include "helloC.h"
#include <iostream>

int main(int argc, char* argv[])
{
    try {
        if (argc != 2) {
            std::cerr << "Usage:" << argv[0] << " IOR_string" << std::endl;
            throw 0;
        }
        CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
        CORBA::Object_var obj = orb->string_to_object(argv[1]);
        if (CORBA::is_nil(obj.in())) {
            std::cerr << "Nil Hello Reference" << std::endl;
            throw 0;
        }

        Hello_var hello = Hello::_narrow(obj.in());
        if (CORBA::is_nil(hello.in())) {
            std::cerr << "Argument is not a Hello reference" << std::endl;
            throw 0;
        }
        {
            std::cout << "Validating connection" << std::endl;
            CORBA::PolicyList_var policies;
            hello->_validate_connection(policies.out());
            std::cout << "Successfull" << std::endl;
        }
        char* greeting = hello->get_greeting();
        std::cout << "Hello server: " << greeting << std::endl;
    } catch (const CORBA::Exception& e) {
        ACE_PRINT_EXCEPTION(e, "Who is the culprit\n");
        std::cerr << "Uncaught CORBA exception" << std::endl;
        return 1;
    }
    return 0;
}

Hello TAOプロジェクト設定ファイル

MPCツール用の設定ファイルを作成し、GNU make用のメイクファイルを生成します。今回は、ワークスペースは作成せずプロジェクトファイル1つだけを作成します。

Hello.mpc
project(*server): taoserver {
  Source_Files {
    hello_server.cpp
  }
}

project(*client): taoclient {
  Source_Files {
    hello_client.cpp
  }
}

mpc.plコマンドを実行し、GNU make用メイクファイルを生成します。

hello$ mpc.pl hello.mpc
Generating gnuace output using hello.mpc
Generation Time: 3s
hello$ ls
GNUmakefile.hello_client
GNUmakefile.hello_server
hello.idl
hello.mpc
hello_client.cpp
hello_server.cpp
hello_server.h
hello$

HelloTAOのコンパイル・リンク

サーバ・プログラムのコンパイル・リンクを行います。

hello$ gmaek -f GNUmakefile.hello_server

GNUmakefile: /home/toru/cw/corba/tao/suncc/ex1/GNUmakefile.hello_server MAKEFLAGS=

/opt/TAO/bin/tao_idl -Ge 1 -Wb,pre_include=ace/pre.h -Wb,post_include=ace/post.h
 -I/opt/TAO/TAO hello.idl
CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO -I/opt/TAO/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__    -I/opt/TAO -I/opt/TAO/TAO  -c -o .obj/helloC.o helloC.cpp
CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO -I/opt/TAO/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__    -I/opt/TAO -I/opt/TAO/TAO  -c -o .obj/helloS.o helloS.cpp
CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO -I/opt/TAO/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__    -I/opt/TAO -I/opt/TAO/TAO  -c -o .obj/hello_server.o hello_server.cpp
"hello_server.cpp", 行 6: 警告: 初期設定で文字列リテラルを char* に変換しました.
1 個の警告が検出されました.
CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO -I/opt/TAO/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__    -I/opt/TAO -I/opt/TAO/TAO  -mt -R /opt/TAO/lib -R./ -xildoff
 -L/opt/TAO/ace -L./  -L/opt/TAO/TAO/tao -L. -L/opt/TAO/lib -o server .obj/helloC.o
 .obj/helloS.o .obj/hello_server.o -lTAO_PortableServer -lTAO_AnyTypeCode -lTAO -lACE
  -lsocket -ldl -lnsl -lgen -lposix4 -ladm

hello$

IDLコンパイラを呼び出して、IDLファイルからスタブ、スケルトンファイルも生成いています。

続いてクライアント・プログラムのコンパイル・リンクを行います。

hello$ gmaek -f GNUmakefile.hello_client

GNUmakefile: /home/toru/cw/corba/tao/suncc/ex1/GNUmakefile.hello_client MAKEFLAGS=

CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO -I/opt/TAO/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__    -I/opt/TAO -I/opt/TAO/TAO  -c -o .obj/hello_client.o hello_client.cpp
CC -mt -g   -DSUN_CC_HAS_PVFC_BUG   -I/opt/TAO -I/opt/TAO/TAO  -DACE_HAS_EXCEPTIONS
 -D__ACE_INLINE__    -I/opt/TAO -I/opt/TAO/TAO  -mt -R /opt/TAO/lib -R./ -xildoff
 -L/opt/TAO/ace -L./  -L/opt/TAO/TAO/tao -L. -L/opt/TAO/lib -o client .obj/helloC.o
 .obj/helloS.o .obj/hello_client.o -lTAO -lACE  -lsocket -ldl -lnsl -lgen -lposix4 -ladm
未定義の                       最初に参照している
シンボル                             ファイル
void operator<<=(CORBA::Any&,const char*)         .obj/helloS.o
以下幾つかのリンクエラーメッセージ

hello$

かなりのリンクエラーが発生しています。

Hello TAOのリンクエラー解析

以下の未定義シンボルを参照しているとリンクエラー
未定義の                       最初に参照している
シンボル                             ファイル
void operator<<=(CORBA::Any&,const char*)         .obj/helloS.o
int TAO_Perfect_Hash_OpTable::find(const char*,void(*&)(TAO_ServerRequest&,void*,void*),const unsigned) .obj/helloS.o
TAO::TypeCode::Objref<const char*,TAO::Null_RefCount_Policy>::__vtbl .obj/helloC.o
TAO::__RTTI__1nDTAOQUnknown_IDL_Type_ .obj/helloC.o
TAO_Operation_Table::~TAO_Operation_Table #Nvariant 1()   .obj/helloS.o
TAO_ServantBase::~TAO_ServantBase()         .obj/helloS.o
void TAO_ServantBase::_remove_ref() .obj/helloS.o
void TAO_ServantBase::synchronous_upcall_dispatch(TAO_ServerRequest&,void*,void*) .obj/helloS.o
char*TAO_ServantBase::_repository_id() .obj/helloS.o
int TAO::Any_Impl::_tao_byte_order()const .obj/helloC.o
CORBA::Object*TAO_ServantBase::_get_component() .obj/helloS.o
CORBA::TypeCode::~TypeCode #Nvariant 1()        .obj/helloC.o
int TAO_Perfect_Hash_OpTable::find(const char*,void(*&)(TAO_Abstract_ServantBase*,TAO::Argument**,int),TAO::Collocation_Strategy,const unsigned) .obj/helloS.o
unsigned TAO_ServantBase::_refcount_value()const .obj/helloS.o
TAO::__RTTI__1nDTAOIAny_Impl_  .obj/helloC.o
TAO::Any_Impl::~Any_Impl #Nvariant 1()          .obj/helloC.o
int TAO_ServantBase::_find(const char*,void(*&)(TAO_Abstract_ServantBase*,TAO::Argument**,int),TAO::Collocation_Strategy,const unsigned) .obj/helloS.o
void TAO::Any_Impl::_remove_ref()  .obj/helloC.o
TAO_Stub*TAO_ServantBase::_create_stub() .obj/helloS.o
TAO::Any_Impl::Any_Impl #Nvariant 1(void(*)(void*),CORBA::TypeCode*,bool) .obj/helloC.o
void TAO_ServantBase::_add_ref()  .obj/helloS.o
void CORBA::Any::operator<<=(ACE_OutputCDR::from_boolean) .obj/helloS.o
TAO_ServantBase::~TAO_ServantBase #Nvariant 1()       .obj/helloS.o
TAO_ServantBase::TAO_ServantBase #Nvariant 1()       .obj/helloS.o
void CORBA::Any::replace(TAO::Any_Impl*) .obj/helloC.o
int TAO_Perfect_Hash_OpTable::bind(const char*,const TAO::Operation_Skeletons) .obj/helloS.o
PortableServer::POA*TAO_ServantBase::_default_POA() .obj/helloS.o
bool TAO_ServantBase::_is_a(const char*)  .obj/helloS.o
int TAO_ServantBase::_find(const char*,void(*&)(TAO_ServerRequest&,void*,void*),const unsigned) .obj/helloS.o
TAO::Upcall_Command::~Upcall_Command #Nvariant 1()    .obj/helloS.o
bool CORBA::TypeCode::equivalent(CORBA::TypeCode*)const .obj/helloC.o
void TAO::Upcall_Wrapper::upcall(TAO_ServerRequest&,TAO::Argument*const*,unsigned,TAO::Upcall_Command&,void*,CORBA::TypeCode*const*,unsigned) .obj/helloS.o
TAO_Perfect_Hash_OpTable::~TAO_Perfect_Hash_OpTable #Nvariant 1() .obj/helloS.o
void TAO::Any_Impl::_add_ref()     .obj/helloC.o
CORBA::TypeCode*CORBA::Any::_tao_get_typecode()const .obj/helloC.o
CORBA::InterfaceDef*TAO_ServantBase::_get_interface() .obj/helloS.o
TAO_ServantBase::TAO_ServantBase #Nvariant 1(const TAO_ServantBase&)    .obj/helloS.o
bool TAO::Any_Impl::encoded()const     .obj/helloC.o
CORBA::TypeCode::__vtbl         .obj/helloC.o
int TAO_POA_Initializer::init()  .obj/helloS.o
void TAO_ServantBase::asynchronous_upcall_dispatch(TAO_ServerRequest&,void*,void*) .obj/helloS.o
void operator<<=(CORBA::Any&,CORBA::Object*const) .obj/helloS.o
bool TAO_ServantBase::_non_existent() .obj/helloS.o
ld: 重大なエラー: シンボル参照エラー。client に書き込まれる出力はありません。
gmake: *** [client] Error 1


hello$

暫定対処

未定義シンボルが含まれているライブラリをnmコマンドで探し、リンク時に指定するように対応します。その結果、以下のライブラリを追加すればよいことが判明しました。

GNUmakefile.hello_clientの以下の行を

LDLIBS = -lTAO -lACE

以下に修正します。

LDLIBS = -lTAO_AnyTypeCode -lTAO_PortableServer -lTAO -lACE

問題の原因

クライアント用のMakefileを生成するルールは、$ACE_ROOT/bin/MakeProjectCreator/config/taoclient.mpbファイルです。これを見ると、taoclientプロジェクトは、taoexeプロジェクトおよびnegotiate_codesetsプロジェクトを継承しています。taoexeプロジェクトではlibTAO.soをリンクする指定があり、negotiate_codestsプロジェクトではlibTAO_Codeset.soをリンクする指定があります。

一方、サーバ用のMakefileを生成するスールは、$ACE_ROOT/bin/MakeProjectCreator/config/taoserver.mpbファイルです。これを見ると、taoserverプロジェクトは、taoexeプロジェクト、negotiate_codesetsプロジェクトを継承している点ではtaoclientプロジェクトと同じですが、さらにportableserverプロジェクトを継承しています。portableserverプロジェクトでは、libTAO_PortableServer.soとリンクする指定があり、さらにtaolibプロジェクト、anytypecodeプロジェクトを継承しています。anytypecodeプロジェクトでは、libTAO_AnyTypeCode.soをリンクする指定があります。

以上を図示すると、次のようになります。

プロジェクトの継承関係とリンク指定(主要抜粋)
taoserver 
  +--- taoexe
  |      +---> libTAOとリンク
  +--- negotiate_codesets
  |      +---> libTAO_Codesetとリンク
  +--- portableserver
         +---> libTAO_PortableServerとリンク
         +--- taolib
         +--- anytypecode
                +---> libTAO_AnyTypeCodeとリンク

taoclient
  +--- taoexe
  |      +---> libTAOとリンク
  +--- negotiate_codesets
         +---> libTAO_Codesetとリンク

そこで、問題の解決としては、$ACE_ROOT/bin/MakeProjectCreator/config/taoclient.mpdファイルを以下のように修正します。

修正前
project : taoexe, negotiate_codesets {
修正後
project : taoexe, negotiate_codesets, portableserver {