こちらの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 build -t cbc_ubuntu1804_64bit .
dk run --rm -it \
-v"$(pwd)/cbc:/root/cbc" \
cbc_ubuntu1804_64bit
以下、コンテナ内での作業。
ただし、ファイルの編集はホスト側で行っています。
コンテナ内なので root で作業していますが、一般ユーザで実行する場合は適宜 sudo apt
などに読み替えてください。
まずは GCC, JavaCC, Ant をインストール:
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;
}
インストールした cbc でコンパイルしてみます。
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
この記事を読んだ人は(たぶん)こちらも読んでいます
qiita.com
memo88.hatenablog.com
memo88.hatenablog.com
memo88.hatenablog.com