- (2016-03-06) ふつうのコンパイラをつくろう Ubuntu64bit : 勉強日誌
- (2020-07-23) 「ふつうのコンパイラをつくろう」のcbcをJava8以降+64bitで動かす - Qiita
こちらの2つの記事を参考にさせてもらいました。ありがとうございます。以下の内容はこれらの記事で書かれていることとほぼ同じです。
ホスト側で適当な作業用ディレクトリを用意。
以下 WORK_DIR
。
cd {WORK_DIR}
cbc を用意:
git clone https://github.com/aamine/cbc.git
ブランチを 1.0.1
に合わせておきます:
( cd cbc git checkout 1.0.1 -b ubuntu1804_64bit )
クリーンな環境で確認したいので Docker コンテナで作業します。
{WORK_DIR}/Dockerfile
FROM ubuntu:18.04 RUN apt update \ && apt install -y --no-install-recommends \ make \ openjdk-8-jdk-headless
とりあえず最低限のものだけ。
この時点でのディレクトリ・ファイル階層はこう:
- WORK_DIR/ - cbc/ - Dockerfile
build と run:
# (作り直す場合) # docker rmi cbc_ubuntu1804_64bit docker build -t cbc_ubuntu1804_64bit . dk run --rm -it \ -v"$(pwd)/cbc:/root/cbc" \ cbc_ubuntu1804_64bit
以下、コンテナ内での作業。 ただし、ファイルの編集はホスト側で行っています。
コンテナ内なので root で作業していますが、一般ユーザで実行する場合は適宜 sudo apt
などに読み替えてください。
apt install -y --no-install-recommends gcc javacc ant
apt だと JavCC 5.0 が入るようです。
ちなみに、 openjdk の前に ant をインストールすると依存パッケージとして openjdk 11 がインストールされます。
cd /root/cbc
cbc のビルド手順に従う場合ここで build.properties
を修正しないといけないのですが、 apt で JavaCC をインストールした場合 /usr/share/java/
に javacc.jar
が配置されるので、今回はこの手順はスキップします。
ちなみに、このディレクトリ指定が間違っていると次のようなメッセージを出して失敗します。
# make ant compile Buildfile: /root/cbc/build.xml init: parser: BUILD FAILED /root/cbc/build.xml:9: JavaCC home must be a valid directory. Total time: 0 seconds Makefile:8: recipe for target 'lib/cbc.jar' failed make: *** [lib/cbc.jar] Error 1
make を実行:
make clean make
コンパイルエラーになります。
[javac] both class java.lang.reflect.Parameter in java.lang.reflect and class net.loveruby.cflat.entity.Parameter in net.loveruby.cflat.entity match
これは Parser.jj
に import 文を1行追加すれば消えます。
--- a/net/loveruby/cflat/parser/Parser.jj +++ b/net/loveruby/cflat/parser/Parser.jj @@ -11,6 +11,7 @@ PARSER_BEGIN(Parser) package net.loveruby.cflat.parser; import net.loveruby.cflat.ast.*; import net.loveruby.cflat.entity.*; +import net.loveruby.cflat.entity.Parameter; import net.loveruby.cflat.type.*; import net.loveruby.cflat.asm.Label; import net.loveruby.cflat.utils.ErrorHandler;
再度 make:
$ make ...snip... compile: [javac] /root/cbc/build.xml:16: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds [javac] Compiling 193 source files to /root/cbc/build/classes [jar] Building jar: /root/cbc/lib/cbc.jar BUILD SUCCESSFUL Total time: 2 seconds cd lib; make libcbc.a make[1]: Entering directory '/root/cbc/lib' ../bin/cbc -O -fPIC -c stdarg.cb -o stdarg.o stdarg.s: Assembler messages: stdarg.s:6: Error: invalid instruction suffix for `push' stdarg.s:14: Error: invalid instruction suffix for `pop' stdarg.s:20: Error: invalid instruction suffix for `push' stdarg.s:43: Error: invalid instruction suffix for `pop' cbc: error: as failed. (status 1) cbc: error: compile error Makefile:14: recipe for target 'stdarg.o' failed make[1]: *** [stdarg.o] Error 1 make[1]: Leaving directory '/root/cbc/lib' Makefile:11: recipe for target 'lib/libcbc.a' failed make: *** [lib/libcbc.a] Error 2
Java のコンパイルは通って、今度は lib/
内での make で失敗します。
lib/Makefile
を修正:
--- a/lib/Makefile +++ b/lib/Makefile @@ -11,9 +11,9 @@ AR_CREATE = ar crs .SUFFIXES: .cb .s .o .cb.o: - $(CBC) $(CBFLAGS) -c $< -o $@ + $(CBC) $(CBFLAGS) -Wa,"--32" -c $< -o $@ .s.o: - $(CBC) -c $< + $(CBC) -Wa,"--32" -c $< $(TARGET): $(OBJS) $(AR_CREATE) $(TARGET) $(OBJS)
再度 make:
root@9aee3742173e:~/cbc# make cd lib; make libcbc.a make[1]: Entering directory '/root/cbc/lib' ../bin/cbc -O -fPIC -Wa,"--32" -c stdarg.cb -o stdarg.o ../bin/cbc -Wa,"--32" -c alloca.s ar crs libcbc.a stdarg.o alloca.o make[1]: Leaving directory '/root/cbc/lib' root@9aee3742173e:~/cbc# echo $? 0
成功しました。
ビルドが成功したのでインストールしてみます。 ちなみにインストール先を変えたい場合は 引数で指定してやれば良いようです。
root@9aee3742173e:~/cbc# ./install.sh prefix=/usr/local/cbc mkdir -p /usr/local/cbc/bin install -m755 bin/cbc /usr/local/cbc/bin mkdir -p /usr/local/cbc/lib cp lib/cbc.jar lib/libcbc.a /usr/local/cbc/lib rm -rf /usr/local/cbc/import cp -r import /usr/local/cbc/import cbc successfully installed as /usr/local/cbc/bin/cbc
とりあえずヘルプを表示してみます。
root@9aee3742173e:~/cbc# /usr/local/cbc/bin/cbc --help Usage: cbc [options] file... Global Options: --check-syntax Checks syntax and quit. --dump-tokens Dumps tokens and quit. ... snip ...
動かせますね。
サンプルコードを用意して、
int main (int argc, char** argv) { return 42; }
root@9aee3742173e:~/cbc# /usr/local/cbc/bin/cbc sample.cb sample.s: Assembler messages: sample.s:6: Error: invalid instruction suffix for `push' sample.s:12: Error: invalid instruction suffix for `pop' cbc: error: as failed. (status 1) cbc: error: compile error
cbc のオプションで -Wa,"--32" -Wl,"-melf_i386"
を指定して実行してみます。
root@9aee3742173e:~/cbc# /usr/local/cbc/bin/cbc -Wa,"--32" -Wl,"-melf_i386" \ > sample.cb /usr/bin/ld: cannot find /usr/lib/crt1.o: No such file or directory /usr/bin/ld: cannot find /usr/lib/crti.o: No such file or directory /usr/bin/ld: cannot find -lc /usr/bin/ld: cannot find /usr/lib/crtn.o: No such file or directory cbc: error: /usr/bin/ld failed. (status 1) cbc: error: compile error
メッセージが変わりました。
crt1.o
などが必要なので、 libc6-dev-i386
をインストールします。
これら(Cランタイム)が何かということについては p574, 575 で解説されています。
apt install -y --no-install-recommends libc6-dev-i386
/usr/lib32/
にインストールされました。
root@9aee3742173e:~/cbc# ls /usr/lib32/ | grep crt Mcrt1.o Scrt1.o crt1.o crti.o crtn.o gcrt1.o grcrt1.o rcrt1.o
これらを参照している箇所を修正:
--- a/net/loveruby/cflat/sysdep/GNULinker.java +++ b/net/loveruby/cflat/sysdep/GNULinker.java @@ -10,10 +10,10 @@ class GNULinker implements Linker { // #@@range/vars{ static final private String LINKER = "/usr/bin/ld"; static final private String DYNAMIC_LINKER = "/lib/ld-linux.so.2"; - static final private String C_RUNTIME_INIT = "/usr/lib/crti.o"; - static final private String C_RUNTIME_START = "/usr/lib/crt1.o"; - static final private String C_RUNTIME_START_PIE = "/usr/lib/Scrt1.o"; - static final private String C_RUNTIME_FINI = "/usr/lib/crtn.o"; + static final private String C_RUNTIME_INIT = "/usr/lib32/crti.o"; + static final private String C_RUNTIME_START = "/usr/lib32/crt1.o"; + static final private String C_RUNTIME_START_PIE = "/usr/lib32/Scrt1.o"; + static final private String C_RUNTIME_FINI = "/usr/lib32/crtn.o"; // #@@} ErrorHandler errorHandler;
再度 make + install:
make clean make ./install.sh
サンプルコードをコンパイル:
/usr/local/cbc/bin/cbc -Wa,"--32" -Wl,"-melf_i386" sample.cb
コンパイルが成功して実行ファイル sample
が作られました。
実行してみます。
root@9aee3742173e:~/cbc# ./sample root@9aee3742173e:~/cbc# echo $? 42
正しく動いているようです。
毎回
-Wa,"--32" -Wl,"-melf_i386"
を付けるのは煩雑なので bin/cbc
に追加してしまいます。
--- a/bin/cbc +++ b/bin/cbc @@ -9,4 +9,5 @@ srcdir_root="$(dirname "$(dirname "$cmd_path")")" net.loveruby.cflat.compiler.Compiler \ -I"$srcdir_root/import" \ -L"$srcdir_root/lib" \ + -Wa,"--32" -Wl,"-melf_i386" \ "$@"
再度インストール:
./install.sh
次のように使えるようになりました。
root@9aee3742173e:~/cbc# /usr/local/cbc/bin/cbc sample.cb root@9aee3742173e:~/cbc# ./sample root@9aee3742173e:~/cbc# echo $? 42
cbc に加えた変更をまとめて見る場合はこちら:
https://github.com/sonota88/cbc/compare/1.0.1...sonota88:ubuntu1804_64bit