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が、すんなりとはビルドできなかった
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 件のコメント:
コメントを投稿