2001/01/15    g77 on MacOS X

(2001/05/15 ここにある情報は、Public Beta の時のものですので、新しい情報に付いては 2001/05/11 または HEP-on-X ページ(英語)を御覧ください。Note added on 2001/05/15: The information here is of Public Beta and therefore more or less obsolete. More up-to-date information is available from 2001/05/11 or a new HEP-on-X page.) とりあえず、そこそこの作業環境ができたので、いよいよ仕事環境の整備に入る。最初のハードルは g77。

[1] g77

仕事に使う開発環境としては g77 は必須。MacOS X は egcs ベースのコンパイラーと聞き及んでいたので、g77 の移植はそれほど大変でもなかろうという甘い考えで移植に着手する。確かに、現状の MacOS X のコンパイラーは gcc-2.95.2 ベースではあるが、Apple の変更により、Language 間の独立性が大幅に損なわれていることが判明。back end 部分に、objc のためのコードが紛れ込んでいるのである。甘い期待はあっさりと裏切られた。
このせいで、ただ単に g77 と libf2c をソースツリーに加えてコンパイルするだけでは、大量の undefined symbols がでてしまう。これにさらに、altivec のサポートという問題がある。altivec サポートは back end はできているはずなので、fortran の front end のサポートを C++ や Objective C の front end を参考に実装すればよいはずであるが、これは将来計画ということで、とにかく g77 を動かすことを目標とする。

g77 の build の手順は、まず、Darwin の gcc ソースを展開し

$ cd gcc-2
$ cp -pr <gcc-2.95.2 のソースディレクトリー>/libf2c .
$ cp -pr <gcc-2.95.2 のソースディレクトリー>/gcc/f gcc/.
$ patch -p1 -s < <somewhere>/gcc-2.95.2-libg2c.patch
$ patch -p1 -s < <somewhere>/gcc-2.95.2-macosx.patch

$ export RC_ARCHS=ppc
$ export RC_CFLAGS='-arch ppc'
$ export RC_OS='macos'
$ export SRCROOT=/Users/fujiik/sandbox/gcc-2
$ make TARGETS='ppc' HOSTS='ppc' >& make.log &
$ make install TARGETS='ppc' HOSTS='ppc' >& install.log &

libg2c パッチは例によって、libg2c.a を PIC flag を立ててコンパイルするためのパッチ。macosx patch のポイントは、build_gcc の中で LANGUAGES に f77 を加えることと、gcc/config/apple/apple-specs.h に #include "f/lang-specs.h" を加えること、そして、gcc-2/gcc/f/com.c に 上で述べた undefined symbols を解決するための dummy routines をつけ加えることである。これで取り合えず f771、g77 を build できる。

次に libg2c.a を build する。

$ cd gcc
$ for i in ../obj/cc-ppc-on-ppc/*.h; do ln -s $i .; done
$ cd ..
$ mkdir obj/ppc/libf2c
$ cd obj/ppc/libf2c
$ CFLAGS='-traditional-cpp' $SRCROOT/libf2c/configure --srcdir=/Users/fujiik/sandbox/gcc-2/libf2c --host=ppc --target=ppc
$ make TARGETS='ppc' HOSTS='ppc' >& make.log &
注意

できた g77 で Hello World がコンパイルできたと喜んだのもつかの間、以下の例で早くも失敗。g77 -O0 は リテラル数が関数コールの引数に含まれているとインターナルコンパイラーエラーを起こしてしまう。最適化をすれば(g77 -O)この例の場合問題を回避できるが、多重ループを含む複雑なプログラムでどうしても -O0 でコンパイルしなくてはならない場合が予想されるので、何とか -O0 で動かせないと後々困る。

(例)

$ cat test.F
      a = abs(1.)
      end
$ g77 test.F
main2.F: In program `MAIN__':
main2.F:2: internal error--unrecognizable insn:
(insn 10 8 11 (set (reg:SF 115)
         (mem/u:SF (lo_sum:SI (reg:SI 116)
                (symbol_ref/u:SI ("*LC0"))) 0)) -1 (nil)
        (nil))
上記の問題の RTL expression は、LinuxPPC が発生するものとレジスターの番号を除き同じであった。RTL (Register Transfer Language) については gcc の info に詳しい解説があるが、簡単に言えば、コンパイラーがマシン依存のアセンブラコードを吐く際のもととなる、マシン非依存の中間言語である。つまり、g77 などの front end は ソースを RTL 表現に変換し、これを back end に渡すのである。RTL で表現された命令(insn)を RTX (RTL EXpression) と呼ぶが、RTX を解釈し、マシン依存のアセンブラを吐くのが back end の仕事である。

RTX が LinuxPPC と同じということは RTX を解釈する back end の問題と思われる。この back end のコントロール部分は、gcc/recog.c で、そのマシン依存の実体は insn-recog.c である。insn-recog.c は genrecog.c により自動生成されるが、そのもととなるのが gcc/config/rs6000/rs6000.md などの Machine Description ファイルである。つまり、GNU コンパイラーのポーティングの作業の中心はこの部分になるわけである。

この rs6000.md を LinuxPPC のものと比べてみると、当然であるが、多くの部分は altivec 対応のための変更である。これに加え、少数の PIC (Position Independent Code) 生成の際の分岐に変更があった。そこで PIC Flag を立てれば、上記の問題を回避できることが分かった。正しくは、rs6000.md を修正するべきであろうが、取り合えず -fPIC をつけてコンパイルすれば動くということである。もともと、CERNLIB などでは、共有ライブラリーへの組み込みを可能とするためアーカイブも PIC Flag を立ててコンパイルする必要があったので、格好は悪いが当面はよしとする(時間ができれば altivec のこともあるので、再挑戦することとする)。

(問題の回避法)

$ g77 -fPIC test.F
格好悪いが取り合えず動くということで。
 

[2] Topdrawer のコンパイルで試運転

もう少し複雑なプログラムで動作することを確認するため、高エネルギー業界で根強い人気を持つグラフ作成プログラムである Topdrawer (TDR) をコンパイルしてみる。
$ cd tdr-1.7
$ patch -p1 -s < ../tdr-1.7_linux.patch
$ make compile F77='g77 -O -fPIC'
$ make lib F77='g77 -O -fPIC'
$ make tdr F77='g77 -O -fPIC' MAINDIR=`pwd`
問題なくコンパイルでき、正常動作した。これで、少しではあるが、大物 CERNLIB に挑戦する元気がでてきた。

今までにコンパイルしたもののソースおよびパッチは macosx/src に、またバイナリーの tar ball は macosx/tgz にそれぞれ置いてある。いつものように使う場合は自己責任で。
 


Back to Keisuke Fujii's MkLinux/LinuxPPC Life