2007年8月11日土曜日

(Solaris10) gcc -std=c99のとき、Undefined symbol __builtin_isnan となってエラー

Solaris10で、とあるアプリケーションをビルドしてたら、リンク時に、Undefined  symbol __builtin_isnan というエラーがでて、失敗。



ネット検索すると、よくある話らしいです・・・









とりあえず、isnanを使った、単純なプログラムを書いて試してみました。





#include <stdio.h>
#include <math.h>



int
sol10_test( double x )
{
    if ( isnan(x) ) {
        return 1;
    } else {
        return 0;
    }
}



int
main( int argc, char* argv[] )
{
    double a = 1.2345e-10;
    int r = sol10_test( a );
    printf("a=%g\nr=%d\n", a, r);
    return r;
}




Solarisって、昔はCコンパイラが別売りで、gccをなんとかして入手、インストールしたりしてましたが、いつのまにやら、Sub謹製のCコンパイラが無償提供されるようになったり、最初からgccが勝手にインストールされるようになってたり・・・



今回も、/usr/sfw以下に、勝手にインストールされていたgccを使っていました。
こんなのです。



% /usr/sfw/bin/gcc -v
Reading specs from /usr/sfw/lib/gcc/sparc-sun-solaris2.10/3.4.3/specs
Configured with: /gates/sfw10/builds/sfw10-gate/usr/src/cmd/gcc/gcc-3.4.3/configure --prefix=/usr/sfw --with-as=/usr/sfw/bin/gas --with-gnu-as --with-ld=/usr/ccs/bin/ld --without-gnu-ld --enable-languages=c,c++ --enable-shared
Thread model: posix
gcc version 3.4.3 (csl-sol210-3_4-branch+sol_rpath)



さて、ふつ~にコンパイルしてみると



% /usr/sfw/bin/gcc sol10-test.c



ぜんぜんOKです。



しかし、「-std=c99」オプションというのを追加して、C99なモードでコンパイルすると、エラーになります。



% /usr/sfw/bin/gcc -std=c99 sol10-test.c
sol10-test.c: In function `sol10_test':
sol10-test.c:10: warning: implicit declaration of function `__builtin_isnan'
Undefined                       first referenced
symbol                             in file
__builtin_isnan                     /tmp//ccACgKvc.o
ld: fatal: Symbol referencing errors. No output written to a.out
collect2: ld returned 1 exit status


ちなみに、ふつ~にコンパイルしているのは、「-std=c89」に相当するらしいです。



% /usr/sfw/bin/gcc -std=c89 sol10-test.c



さて、undefined symbolってことなので、gcc -cでコンパイルしてから、nmでみると、まあ、当然ながら、UNDEFです。



% nm sol10-test.o



sol10-test.o:



[Index]   Value      Size    Type  Bind  Other Shndx   Name



[6]     |         0|       0|SECT |LOCL |0    |6      |
[2]     |         0|       0|SECT |LOCL |0    |1      |
[3]     |         0|       0|SECT |LOCL |0    |3      |
[4]     |         0|       0|SECT |LOCL |0    |4      |
[5]     |         0|       0|SECT |LOCL |0    |5      |
[8]     |         0|       0|NOTY |GLOB |0    |UNDEF  |__builtin_isnan
[9]     |        68|      96|FUNC |GLOB |0    |1      |main
[10]    |         0|       0|NOTY |GLOB |0    |UNDEF  |printf
[1]     |         0|       0|FILE |LOCL |0    |ABS    |sol10-test.c
[7]     |         0|      68|FUNC |GLOB |0    |1      |sol10_test



この、__builtin_isnan ってのは、いったいどこから出てきたのか、grepしてみると・・・



% ggrep -R isnan /usr/include
/usr/include/iso/math_c99.h:#undef      isnan
/usr/include/iso/math_c99.h:#define     isnan(x)        __builtin_isnan(x)
(以下省略)



という感じで、ファイル名からして、C99のときだけ、なんか出てきそうな雰囲気です。



このヘッダファイルmath_c99.hと、gccとで、整合性がとれていないのが、問題の原因っぽいです。





■ 解決方法



C99にしない、ってわけにもいかなくて、苦肉の策として、なんとなく発見した方法が、



math.hをincludeしない



ってもの。#include <math.h>をコメントアウトしてしまうと・・・



% gcc -std=c99 sol10-test.c
sol10-test.c: In function `sol10_test':
sol10-test.c:10: warning: implicit declaration of function `isnan'



当然、warningはでますが、一応、コンパイル、リンクまでできてしまいます。



でも気持ち悪すぎです。


別の方法を見つけました。



はじめから入ってた、gcc version 3.4.3ってのが、古すぎじゃないのか? それとも腐った設定でビルドされてるんじゃないか? と思い、pkgsrcを使って、gcc 3.4.6をインストールしてみました。


こんなやつです。



% /usr/pkg/gcc34/bin/gcc -v
Reading specs from /usr/pkg/gcc34/bin/../lib/gcc/sparc-sun-solaris2.10/3.4.6/specs
Configured with: /export/work/lang/gcc34/work/gcc-3.4.6/configure --enable-languages='c' 'c++' 'f77' 'java' 'objc' --with-system-zlib --enable-shared --enable-__cxa_atexit --enable-long-long --with-local-prefix=/usr/pkg/gcc34 --with-libiconv-prefix=/usr/pkg --with-gmp=/usr/pkg --prefix=/usr/pkg/gcc34
Thread model: posix
gcc version 3.4.6


% /usr/pkg/gcc34/bin/gcc -std=c99 sol10-test.c
% ./a.out
a=1.2345e-10
r=0



うまくいきます。



% /usr/pkg/gcc34/bin/gcc -std=c99 -c sol10-test.c



% nm sol10-test.o



sol10-test.o:



[Index]   Value      Size    Type  Bind  Other Shndx   Name



[2]     |         0|       0|SECT |LOCL |0    |2      |
[3]     |         0|       0|SECT |LOCL |0    |3      |
[6]     |       100|      96|FUNC |GLOB |0    |2      |main
[4]     |         0|       0|NOTY |GLOB |0    |UNDEF  |printf
[1]     |         0|       0|FILE |LOCL |0    |ABS    |sol10-test.c
[5]     |         0|     100|FUNC |GLOB |0    |2      |sol10_test



大丈夫みたいです。



というわけで、/usr/sfw以下のgccは捨てろ!ですかね・・・





■ pkgsrcで、lang/gcc34が、すんなりとはビルドできなかった



参考
(Solaris10,pkgsrc) lddしたら、libz.so.1 (SUNW_1.1) => (version not found) とか libgcc_s.so.1 (GCC_3.4) => (version not found) とか出た

1箇所だけ、エラーでひっかかって、Makefileを修正することで解決しました。



以前は、gcc 3.3.xだったような気がしますが、そのころは、64bitコードをはけるgccが、pkgsrcでどうやってもビルドできなかったのですが、今のlang/gcc34は、ごく普通に、sparcv9といったフォルダを掘って、64bit版も作ってくれてました。



ただ、その途中で、こんなエラーが発生。



ld: fatal: file /usr/pkg/lib/libz.so: wrong ELF class: ELFCLASS32
ld: fatal: File processing errors. No output written to .libs/libgcj.so.5.0.0
collect2: ld returned 1 exit status



64bit版をつくってる最中に、32bit版の/usr/pkg/lib/libz.soを混ぜてリンクしちゃってエラーになってました。



/usr/pkg/lib/libz.soがいったいどこから引っ張ってこられるのか、よくわかんなかったのですが、エラーがおきたディレクトリのMakefileを見ると、-lzをつけているマクロがあったので、そこから-lzを抜いてみたところ、あとは最後まで通ってしまいました。






「gcc -m64」で、64ビット版でコンパイルできます。

% /usr/pkg/gcc34/bin/gcc -std=c99  sol10-test.c
% file a.out
a.out: ELF 32-bit MSB executable, SPARC, version 1 (SYSV), dynamically linked (uses shared libs), not stripped


% /usr/pkg/gcc34/bin/gcc -std=c99 -m64 sol10-test.c
% file a.out
a.out: ELF 64-bit MSB executable, SPARC V9, version 1 (SYSV), dynamically linked (uses shared libs), not stripped



0 件のコメント:

コメントを投稿