- ベストアンサー
SolarisとLinuxのグローバル変数の扱いについて
Solaris用のソースをLinuxで使えるように変更したいのですが、 グローバル変数について以下のようなことが発生していて困っています。 なにか、コンパイルオプションなどで対応はできないものでしょうか? Solaris (CC)では 特にextern宣言しなくても同じシンボルの外部変数はコモンセグメントに1つだけ作成しコンパイル自体は正常である。 しかし、Linux (g++)では externを宣言しないと同じシンボルを再定義したことになりエラーとなる。 これにより、グローバル変数を多用しているプログラムはLinuxでうまくコンパイルができない。 しかし、単純にextern宣言での対応は難しい。 extern宣言は外部で定義してあるグローバル変数を参照する というものだがLinux では 1つの定義を意外は全てexternしなければ、2重定義エラーになってしまう。 つまり、実体が1つであとはそれを参照しているという形でなければいけない。 ところが、その実体をどこにするか特定することができない。 例えば、gというグローバル変数を仮定する。 A.c,B.c,C.cはその3つのソースよりAA.aという静的ライブラリを構成する。 gはA.cで定義してありB.c,C.cはそれを参照する。 ところが C.cは個別にC.oというオブジェクトで他からの呼び出しがあり 別LMにリンクされる。 その時C.c内のgは実体を失うことになり未定義となる。 つまり、どれが実体になるかは何にリンクするかで決まるため 実態を特定できない。 また、共通のヘッダにグローバル変数が定義されている場合も、重複するというエラーを起こすため、 共通ヘッダからグローバル変数を分離し、何れかのソースにグローバル変数の実態を定義させる必要がある。 共通ヘッダを使っている他のソースはそのグローバル変数の実態を参照するようにexternの宣言をする。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
GCCの拡張機能 __attribute__ を使えば、外部変数をコモンセグメントに置くことができるらしいです。 // サンプル #if defined(__GNUC__) #define COMMON __attribute__((common)) #else #define COMMON #endif int g COMMON; まあ、あまりいい書き方ではないとは思うけど。
その他の回答 (3)
- Tacosan
- ベストアンサー率23% (3656/15482)
もともと C では (C++ でも) 「複数の翻訳単位で同じ名前の外部定義を行う」ことは基本的に undefined behavior です. なので, どういう形になっているのか明確でないのではっきりとは言えないのですが, もとのプログラムが (C/C++ の規格から見て) undefined behavior であり, Solaris のコンパイラである CC (あるいはリンカ?) の機能に依存している可能性も考えられます. だいたい, 「C.c は個別に C.o というオブジェクトで他からの呼び出しがあり」という時点で構造がおかしい気がします. ライブラリを作ってるんだからそのライブラリをリンクするのが普通じゃないかなぁ?
お礼
アドバイスありがとうございます。 ごもっともなご意見ですが、元々数社が共同で作った大きなシステム(それを全部引き取った。)だけにこの辺の整合性というか管理というかぼろぼろなんですよね。同じヘッダが数十個あるとか。同じソースでバージョンが違うものが同時に生きているとか、他人のオブジェクトを直接リンクしているとか、ソースが古いとかも。。。なので普通のことが行われていない部分が一杯あるんです。。。
- m_mik
- ベストアンサー率26% (31/117)
私が良く使う手ですと… 共通ヘッダとして、com.h を作成して、 <<<<< com.h >>>>> #ifndef __MAIN_LOGIC #define EXTERN extern #endif EXTERN int g; <<<<< A.c >>>>> #define __MAIN_LOGIC #include "com.h" <<<<< B.c >>>>> #include "com.h" <<<<< C.c >>>>> #include "com.h" このようにすると、いつでも同一のグローバル変数を参照するようになります。 注意点は、メインとなる1つのファイル(この場合はA.c)で、共通ファイルをインクルードする前に __MAIN_LOGIC という定義を宣言するということです。 他のサブとなるプログラムでは __MAIN_LOGIC の定義をしなければいいのです。 いかがでしょうか?
お礼
回答ありがとうございます。 了解です。 やはりコンパイルオプションでは対応できないということですかね。
- foobar
- ベストアンサー率44% (1423/3185)
ソースファイルがCで記述されているなら、g++ではなくてgccで処理してみては如何でしょうか。 手元のVine linux +gcc/g++ の処理系で試したところ、 gccを使えば、duplicated... のメッセージがでずに処理されるようです。
お礼
アドバイスありがとうございます。 gccでは上手くいくことは、こちらでも調査済みですが、C++で書かれているソースもあるので、g++でコンパイルする必要があるのです。
お礼
この方法でやってみたところ、上手く行きました。 g++でも使えるみたいです。 とりあえず、この方法でやって行きたいと思います。 ありがとうございました。