2010-3-9[火] マイナーなCコンパイラをちょっと触る

フリーでwin環境用exeが作れる、ちょっとマイナーな Cコンパイラをちょろっと触ってみた、というかインストールしてみた時のメモ.

試したのは LLVM-gcc, PCC, LCC, TinyCC, COINS。

(マイナーというと語弊のあるモノもあるけど win環境用のcコンパイラとしては、で)

LLVM-gcc

(※追記:LLVM-gccでllvmを使う場合-emit-llvmオプションとつけないとダメだったよう)

(wikipedia)

LLVM&clang は、 そのvmな仕組みとか、 オプティマイズ等の実力とか、 使用用途(appleの動向)とか、 GPL(v3)より緩いライセンスがらみとか、 いろいろ話題で今後の発展に期待大なコンパイラ(vm)、 だけど、 win環境で試すには、 mingw-msys 環境に追加する方法になっていて、 ちょっとまだ敷居が高い感じ。

また、残念ながら win 環境向けにはまだ clang バイナリは無いようなので、試せるのは gccフロントエンドのモノのみ。 (追記:clangのほうは自分でコンパイルすれば使える..ということでさらに敷居が高い)

ただ llvm-gcc側にコンパイル環境として(mingw-gccをベースにした)必要なものは一通り入っているので、mingwコンパイラをインストールしておく必要はない(あってもかまわないけど)。

設定としては、まず msys 環境が必要。 mingw本家TDM等から適当なのをインストール。
うちは 猫研pack のtdm-gcc環境を使ってるのでそこに寄生。
ここでは c:\msys にmsysがあるとする。

LLVMのダウンロード頁から以下の2つを取得

    • LLVM Binaries for Mingw32/x86 (試した時は、v2.6)
    • LLVM-GCC 4.? Front End Binaries for Mingw32/x86 (試した時は gcc-4.2)

ダウンロードしたファイルを適当な場所、たとえば
  x:\llvm-2.6 x:\llvm-gcc-4.2
に解凍したとする。(来月には2.7が出るみたいだけど、今はまだ)

msys込みで、パスを設定。

set "path=x:\llvm-2.6;x:\llvm-gcc-4.2\bin;c:\msys\bin;%path%;"

あとは、llvmc 、または、llvm-gcc, llvm-g++ を用いて、 適当なソースをコンパイル、といった感じだろう。 (※簡単にヤッたら間違ってた。追記参照)

mingw 環境のコンパイラだけ置き換えた状態のようなんで、 使い方は mingw(gcc)。 win-apiアプリの コンパイルもできるよう。 (簡単な窓を出すだけのhelloプログラムは動いた)。

速度等はろくに調べていないけれど、xorshiftのときのサンプルをコンパイルしてみたところ、inline展開が働いた時のスコアは結構よいほうだった。 ただ、inline 展開をあきらめるのがvcやg++4.4より早いようで、xorshift128あたり から関数呼出になってスコア落ちた。gcc3.4.5同様素直な感じなのかな、と。

追記: llvmとしてコンパイルするにはオプションが必要のよう. でもってコンパイラ環境がうまく設定されていないのか、一度にコンパイルできず.こちら等を参考にして

llvm-gcc -O2 -DNDEBUG --emit-llvm -S test.c
llvm-as test.s
llc test.s.bc
llvm-gcc -o test.exe test.s.s

llvm-gcc -DNDEBUG -O2 --emit-llvm -S test.c
llvm-as -o tmp.bc test.s
llvm-ld -o tmp.2.exe tmp.bc
llc tmp.2.exe.bc
llvm-gcc -o test.exe tmp.2.exe.s

て感じにしてみる(後者のほうが全体に対するオプティマイズが効くかも)

※ llc で -march=x86 を付けるとwin用でなくなるみたいでマズイのだった.

※追記 こっちでLLVM-Clangを使ってみた。


PCC(Portable C Compiler)

(wikipedia)

かって(ANSI-C以前)の Cの標準だったろう Cコンパイラで、 最近はこちらでC99化していってるらしい。 (こちらもGPLv3の影響で脚光を浴びてるかんじ?)

もともと移植性のいいモノなためか、ちゃんとwin32版も用意されている。
コンパイラ以外はgnuツールなりmingwツール/ライブラリが採用されているようだ。

こちら から、 pcc-20090818-win32.exe をダウンロード。実行してインストール。

とりあえず通常のプログラムフォルダ c:\Program Files (win64なら c:\Program Files (x86)) にインストールしたとする.
※ひょっとすると、win64でも(x86)ついてなかったかもしれないので注意.

コマンドプロンプト窓でコンパイラを使う場合は、

set "path=%ProgramFiles%\pcc\bin;%path%"

を先に実行。この状態で pcc を用いてコンパイル。

pcc --help でヘルプ表示すると ld の分しか表示されず涙目だけど、 元はunix系のccそのものだろうから、そのあたりを見ればいいのか。 (基本部分はgccが同じにしてるはずだろうからgccのを試せばよいのかも)

mingwベースなんで、winプログラムも同様。とりあえず窓helloは、

pcc w_p_smp1.c -l gdi32

でいけた。

なお、出来たexeは mingw 同様 msvcrt.dll に依存している。


PCC コンパイラのコンパイル

当初 win32バイナリの配布に気づかず、ソースにwin32用バッチがあったので コンパイルしてみてた。 ので、そのメモも。
ソース修正は1行挿入のみだけど環境設定がちょっと面倒だった。

ソースについては、こちらから pcc-cvs-100306.tgz、こちら から pcc-libs-cvs-100306.tgz をダウンロード。 展開してできたフォルダを x:\pcc, x:\pcc-libs とする。
(どうも毎日バックアップされてるもののようで日による差分は不明、最新版とればいいんじゃね、で)

ソース修正は pcc/os/win32/config.h の31行目付近の

#if !defined(vsnprintf)
#include <stdio.h>     //この一行を追加.
#define vsnprintf _vsnprintf
#endif

をコメントのように#include <stdio.h> を追加するだけ。 (あとからstdio.hがincludeされるとvsnprintf置換でバグになるため)

面倒なのは bison や flex を使うのでそれらを用意する必要があること。 幸い猫研パックのmsys に入ってるので、msys環境を用いれば済みそう。

と実際にためすと、flex がハング。msys-regex-1.dll が無いと怒られる。mingwのダウンロード頁 から regex の dll 版をダウンロードして解凍(lzmaというあまり普及していない形式なので解凍ソフト(7z)も入れたり). とりだせた msys-regex-1.dll を msys\bin にコピーしたらok。(ああ、うちのmsysはちょっと古くパックの_a004のモノなので最新で直ってる可能性あり)

vc2008 でコンパイルする場合は

call "%VS90COMNTOOLS%vsvars32.bat"

をしておき(2005なら%VS80…,2003なら%VS71…だろう)

x:/pcc/os/win32 へカレントディレクトリを移動し、

build /cl /pccsrcdir x:\pcc /pcclibssrcdir x:\pcc-libs

を実行。うまくいけば pcc.exe (とmkext.exe) が出来ているハズ。

※bison等のツールの具合によっては、build /cl のみでコンパイルできるかもだが、己の使ったバージョンの場合、bisonに(相対パスの)ファイルが見つからないと怒られた。で、絶対パス指定してみたら回避できた、という状態。

できたexeを試す場合は、配布バイナリをインストールした環境のpcc.exeと置き換えてみれば、で。


また pcc 自身でもコンパイルできる。この場合は、インストールしたpcc環境のbinへパスを通した状態で

build /pcc /pccsrcdir x:\pcc /pcclibssrcdir x:\pcc-libs

を実行.

もし pccのインストールディレクトリを c:\program files\pcc 以外にしていた場合は、build オプションとして /pccdir c:\hoge\pcc のようにインストールしたpccフォルダを追加する必要がある。win64の場合 (x86)付なので指定が必要だろう(/pccdir "%ProgramFiles%" かな)。

LCC

LCC は、こちら が大本。 コンパイラ作成の教材のような感じで、 配布されているものは、ソースのみでバイナリなし。

ただ、これをベースに使える環境にしたパッケージがいくつかあるようで

といったものがある。


こちら にlcc対応のデバッガが公開されてる。

LCC-WIN32

LCC-WIN32 は結構昔からあって、 昔試した時点で、IDE環境完備でデバッガ等の出来もよく、 言語仕様拡張や生成改善等もされていて で独自発展していたのだけれど、 今、サイトをみると頁はあるけれどコンパイラ等へのリンク等がことごとく切れてる。 一応、去年の秋はまだダウンロードできてたのだけど。 開発会社のトップページを みると権利関係が別の会社に移譲されたようなことが書いてあるようで... 現状フリー配布はなくなったってことなのかな(LCC-WIN32系のサイトをあたれば、FTPからのダウンロードがまだできるかもだけど、リンクしないでおく)。


Pelles C

PellesC もLCC-WIN32同様に IDE完備の開発環境になっている。 IDE上でSJIS入力できたり、char文字列中に表やソで\含文字を使っても 実行で文字化けせず表示されてちょっと感動。 デバッガもそこそこいい感じ。ただwatchポイントは貼れず(LCC-WIN32は出来てた)。 プロジェクト設定は DEBUG/RELEASE切り替え等はできないようで、 プロジェクトのオプション設定でコンパイラ頁とリンカ頁のデバッグ設定をそのつど 切り替えないと駄目なよう(たぶん。でも、その程度)。

当然Winアプリ作れる。(ウィザードもあり)
(あとWinCE用の開発環境にもなっている)

コマンドプロンプトで使用するときは、まず、

set "PATH=%ProgramFiles%\PellesC\bin;%PATH%"

を実行。cc を用いて

cc hello.c

といった感じ。win窓helloなら

cc /Ze w_p_smp1.c user32.lib gdi32.lib

で、とりあえず。


LCC コンパイラのコンパイル

大本のLCCはソースしかないけれど、win32様のコンパイルバッチが入ってたので 試してみた... が、少々修正する必要があった。 のでそのメモ。

試したのは v4.2 のもの。tar.gz, tar.Z, zip の3つの圧縮ファイルがあるけれど、 基本同じものだけど、ソースの改行コードが違うかも。 winなら zip のモノを選ぶのが吉。

※実は tar.gz のを使った。lburg/lburg.c ファイルのみ改行コードが lf(\0a) でなくcr(\0d) だったためコンパイラに怒られた。lfに置換して済ましたけれど、zipのを展開したらcrlfでそもそも出会わないはずの不具合だったorz

win向けにコンパイルするのには、makefile.nt を使う。 使用するコンパイラは vc. ただちょっと古いバージョン(vc6ぽい) 向けみたいでvc2008にはすでにないオプションが使われていたり。

makefile.nt の9行目付近からの

CFLAGS=-DWIN32 -Zi -MLd -Fd$(BUILDDIR)^\
LD=cl -nologo
LDFLAGS=-Zi -MLd -Fd$(BUILDDIR)^\

の部分を

BUILDDIR=.
CFLAGS=-Doutp=outP -DWIN32 -Zi -MT -Fd$(BUILDDIR)^\
LD=cl -nologo
LDFLAGS=-Zi -MT -Fd$(BUILDDIR)^\

のように修正.
-Doutp=outP として、マクロ置換しているのは、関数宣言された名前を変数名としてつかったといって怒られたため、その回避。 (outpはx86系のout命令をc用にした名前として昔からある...のでビルトイン関数かなにかの影響だろうか... とりあえずのお試しで回避できたため原因追求せず)
(-MTにしてるから-Ziいらないけど、面倒なので残したまま。逆に-MTdにするでもいいが後述の修正箇所の.lib名もそれにあわせる必要あり)

あと、etc/win32.c の

  • 8行目付近

    #define LCCDIR "\\progra~1\\lcc\\4.1\\bin\\"

    の内容を、実際にlcc.exeをインストールするフォルダに変更.
    とりあえず、お試しなので "x:\lcc42" で作業しているとして、そこを設定。


  • 20行目付近の "libc.lib""libcmt.lib" に修正する。

win32.c を見ての通り、結構、環境をハードコーディングしているので、 本格的に使うならば、いろいろ修正したほうがよさげな雰囲気。
また、この内容から、コンパイラ以外のリンカやライブラリ等は VCに寄生するスタイルのよう。

とりあえず、staticリンクライブラリが使えるエディションならコンパイル可能になったはず。

dllランタイム版でコンパイルする場合は、上記までの修正に対してさらに、

  • makefile.nt の CFLAGS,LDFLAGS の -MT-MD に変更
  • cpp/unix.c の memmove関数の定義を #ifndef _MSC_VER で挟む.
  • etc/lcc.c の extern int getpid(void);宣言を #ifndef _MSC_VER で挟む.
  • etc/win32.c の "libcmt.lib"(元"libc.lib") を "msvcrt.lib" に変更.

を施す。

で、vc2008を使ってコマンドプロンプトでコンパイル

call "%VS90COMNTOOLS%vsvars32.bat"

を実行(2005なら%VS80…,2010なら%VS100…って感じか)

作業場所が x:\lcc42 フォルダだとして、そこに移動して

nmake -f makefile.nt clean
nmake -f makefile.nt all

を実行. 上手くいけばlcc.exe,cpp.exe等が作られてる(ハズ)。

お試しは

extern int printf(const char* fmt, ...);
int main(int argc, char* argv[]) {
    printf("hello world\n");
    return 0;
}

を hello.c としてセーブ.

lcc hello.c

でコンパイル。 うまくいけば a.exe ができるので、a.exeを実行してhello worldが表示できたらokと。
※ リンカー等はvcのモノを使うので、vcコンソール環境が使える状態で使うこと.

なお、#include をせずに直接 extern でprintfを宣言してるのは、#include <stdio.h> をすると cpp.exe 実行中に帰ってこなくなったため... 追求するのは面倒なので、お試しとしては、これで終わりにしておく。


TinyCC

TinyCC は小さいCコンパイラ。 (コンパイラ本体のc,hソース行数は3万行弱)。

けど、文法は、ほぼフルスペックのC89+α(C99の一部)。 (浮動小数点数も構造体もビットフィールドもあるし long long もある, らしい)

とりあえず、サイトからwin用のバイナリを取得して、適当な フォルダに展開。とりあえず、c:\tcc にいれたとする。

set "PATH=c:\tcc;%path%"

でパスを通して、あとは tcc hello.c のようにしてコンパイルするだけ。 winアプリも出来るよう(examples/hello_win.c )
※ランタイムとしてmsvcrtを使用の様.

すごく、あっさり使えてしまう代物のよう。


※実は試すまで、この作者のotcc の延長のモノかと思ってた。 舐めてました。すみません。 otccのほうはwin用でなくlinux用の 1000行に満たない小さいソースのKR-C系ミニ言語. 実行ファイル生成. (IOCCC 2002優勝らしく. 配布ではちゃんと可読なバージョンもあるのでそれをみるのも吉. それどもトリッキーですが)

TinyCC コンパイラのコンパイル

mingw-gcc を用いる。
mingw-gcc を使える状態にしておいて、 サイトから取ってきたソースのzipを x:\tcc-0.9.?? にでも展開する。

x:\tcc-0.9.??\win32 フォルダに移動して、 build-tcc.bat を実行する。exeができたら吉。


COINS

COINS についてはリンク先の概要をみるなりして。 コンパイラ研究のインフラとしてのCコンパイラが配布されてるよう。 ライセンスはApache Licene Version 2.0

モノは java で作られていて、また win環境では cygwin を使う ので、予め、それらがインストールされている必要がある。

javaに関しては、コンパイラをコンパイルするのでなければ jdk は必要でなく jre がインストールされていればよさそう。何かの折にjre6がインストール済みなのでそれを利用。
c:\Program Files (x86)\java\jre6 にインストールされているとする。

cygwin は gcc等の基本的な開発ツールがインストールされていればよく。 かなり昔にインストール済みなので、新規インストールについては他のサイトを適当にみてもらって。 と自分の環境はしばらく更新してなかったのでsetupで更新... したら、どうも最新のcygwin環境だとCOINSはちょっと不具合がでるようで対処が必要になる.後述)
cygwin は c:\cygwin にインストールされているとする。

COINSコンパイラのインストールや使い方については、こちらこちら やその他諸々を参考に...

ダウンロードはCOINSのダウンロード頁 から、 こちらのサイトの助言にしたがい 国際(en)版をダウンロード。 (jp版は euc が使われているためツールによっちゃwin環境では不味い場合があるらしい... なおjp版だけならSourceForgeの頁 からもダウンロードできる)。
己が入手したのは coins-1.4.4.3-en.jar

ダウンロードしたファイルを(jarだけど)zipファイルとして適当なフォルダに解凍。
とりあえず、 x:\coins\ に解凍したとして、
  x:\coins\coins-1.4.4.3-en
ができているとする。

※この中には classes\ フォルダがあり中身が生成済みだったので、今回はそれをそのまま使うことにした。ソースのみ配布のバージョンなら当然再コンパイルが必要。


最新のcygwin での不具合回避のため、c:\cygwin\bin 中から gcc-3.exe cpp-3.exe
gcc.exe cpp.exe に変名して x:\coins\bin\ フォルダ作ってコピー.

こちらで紹介されてる不具合回避方法だとCOINS以外で不味い場合もあるかも(?)なので、また、今回はhello world のみの簡易なお試しなので暫定的な回避にした。


コンパイルでのコマンドプロンプトでの記述が長くなるので、次の一行をバッチにしておく。

java -class x:/coins/coins-1.4.4.3-en/classes coins.driver.Driver -coins:target=x86-cygwin,assembler=as %1 %2 %3 %4 %5 %6 %7 %8 %9

名前は coins_tc.bat として x:\coins\bin\ にセーブ。


コマンドプロンプト窓(dos窓)をあけ、pathを設定する。

set "PATH=x:\coins\bin;c:\cygwin\bin;%ProgramFiles%\java\jre6\bin;%PATH%"

※不具合回避で置換すべきexeのあるフォルダがpath検索で先に見つかるように設定。

hello.cとして以下を適当なフォルダに作成しておく.

#include <stdio.h>
int main() {
    printf("Hello World!\n");
    return 0;
}

先のバッチを使い

coins_tc.bat -o hello.exe hello.c

のようにコンパイル。出来た hello.exe を実行して、hello world が出力されたらok.

cygwin ツールを cygwin 環境以外で使うため、パス関係の警告がいろいろ出るけど無視。

もし cygwin 環境で実行したいならば、この(上記path設定の)状態で

bash --login -i

を実行。カレントがhomeに移動してるので、お試しフォルダへ再度移動。
そこで coins_tc.bat -o hello.exe hello.c を実行すれば、パス名警告は減る(無くなる)かも。


コンパイルして出来上がったexeは、cygwinのgccのライブラリをリンクしているだろうで、当然、その制限をうける。


(※だめもとでmingw環境でコンパイルしたらやっぱり駄目だった。リンク関係でいろいろ無いと怒られる。けど、そのへんの問題だけなのかも?)


その他

  • hello world頁をどうこうしようと思ってやり始めたが面倒になってあきらめ... が、折角試した分くらいは、で書いたのがこの頁。
  • vc,bcc,dmc,watcom はとりあえず、いろんなサイトあるし。
  • Fail-Safe Cというモノもある模様。win用はなさそう?で、cygwinで試しみるも失敗。(どちらかというとocaml関係に振り回される時間のほうが多くorz)
  • COINSしたくてcygwinも使ったが、cygwinだとunix系のモノが試せてしまい、前行のようにダークサイドへ突入...で疲れたので止め。ポート済み以外はみないですまさないと... TenDRAはないのかな。
  • 試して無いけどwinで動くcインタプリタとして Ch とか CINTとか
  • Under C++ とか、 その他諸々以外とある模様。