mruby/c をコンパイルする

設計を考えていて MCU を決める事が最優先事項なので、mruby/c を導入してみました. 2週間ぐらい前に試したらリンクさえ通らなかったのですが、手順をやり直しました.

目的

MCU 側のクロスコンパイラで mruby/c をリンク、簡単な動作をみて実用に値するかが目的です. 実用できないと判断した場合は MCUスクリプトシステムを選定し直します.

スクリプトシステムを使うのは MCU 経由で FPGA で自作する予定の簡単な映像機能にたいして、画面描画制御とユーザーインタフェース管理をやりたいためです. C やアセンブラで作るには向いてない用途で、便利な選択肢があるならそれを使って開発時間を節約すべきだと考えております.

ダウンロード

https://github.com/mrubyc/mrubyc/releases/tag/release2.0

今回は release したものを使いました. 前回は git で最新版を clone して意味がわからなくなってしまって諦めてしまいました.

とりあえずコンパイル

src/Makefile の CFLAGS に -DMRBC_NO_TIMER を追加します. その後 msys2 で cd mrubyc-release2.0; make であっさり通りました. これは msys2 のパソコン上でのビルドで MCU のためのクロスコンパイルの記述は別途必要です.

シミュレーション用とターゲット用で分ける

mruby 系は組み込み向けのため、調整して組み込めという要素が強いみたいですので主に Makefile を手直しします.

シミュレーション用は msys2, ターゲット用は STM32F series を想定していきます. いきなりターゲット用にコードを書いても制限が多い MCU 上では問題の切り分けに手間が多いので、ある程度はシミュレーション用として PC で作っておく方が便利なためです.

変更分

いか diff の結果を切り貼りしてコメントをつけていきます.

diff -ru /e/mrubyc-release2.0/Makefile ././Makefile
--- /e/mrubyc-release2.0/Makefile	2019-06-19 19:14:00.000000000 +0900
+++ ././Makefile	2020-03-16 09:44:51.850266900 +0900
@@ -11,16 +11,16 @@
 
 
 mrubyc_lib:
-	cd mrblib ; $(MAKE) all
-	cd src ; $(MAKE) all
+	$(MAKE) -C mrblib all
+	$(MAKE) -C src all
 
 mrubyc_bin:
-	cd sample_c ; $(MAKE) all
+	$(MAKE) -C sample_c all
 
 clean:
-	cd mrblib ; $(MAKE) clean
-	cd src ; $(MAKE) clean
-	cd sample_c ; $(MAKE) clean
+	$(MAKE) -C mrblib clean
+	$(MAKE) -C src clean
+	$(MAKE) -C sample_c clean
 
 package: clean
 	@LANG=C ;\

ここは直さなくてもよかったんですが Makefile 作った人が make の -C を知らなかった気がします.自分も最近まで知りませんでした.

--- /e/mrubyc-release2.0/sample_c/Makefile	2019-06-19 19:14:00.000000000 +0900
+++ ././sample_c/Makefile	2020-03-16 10:05:38.938544900 +0900
@@ -7,10 +7,12 @@
 #  This file is distributed under BSD 3-Clause License.
 #
 
+CC = clang
 TARGETS = mrubyc mrubyc_sample mrubyc_concurrent mrubyc_myclass
-CFLAGS += -g -I ../src -Wall -Wpointer-arith
+CFLAGS = -I../src -I../src/hal_posix -Werror -Wall -Wpointer-arith
+CFLAGS += -O2
 LDFLAGS +=
-LIBMRUBYC = ../src/libmrubyc.a
+LIBMRUBYC = ../obj_msys/libmrubyc.a
 
 all: $(TARGETS)
 
@@ -27,4 +29,4 @@
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ main_myclass.c $(LIBMRUBYC)
 
 clean:
-	@rm -rf $(TARGETS) *.o *.dSYM *~
+	@rm -rf $(TARGETS) *.o *.dSYM

sample_c は libmrubyc をリンクして C の実行ファイルを作る目的のディレクトリです. -g は gdb はいまのところはいらないので削除, -O../src/hal_posix は src/hal の分離で追加. -O2 は好みです.
rm *~ は emacs とかのバックアップファイルだと思いますが私は使わないので消しました.

diff -ru /e/mrubyc-release2.0/src/alloc.c ././src/alloc.c
--- /e/mrubyc-release2.0/src/alloc.c	2019-06-19 19:14:00.000000000 +0900
+++ ././src/alloc.c	2020-03-16 09:57:28.267718100 +0900
@@ -19,7 +19,7 @@
 #include <assert.h>
 #include "vm.h"
 #include "alloc.h"
-#include "hal/hal.h"
+#include "hal.h"
 
 
 // Layer 1st(f) and 2nd(s) model
diff -ru /e/mrubyc-release2.0/src/class.c ././src/class.c
--- /e/mrubyc-release2.0/src/class.c	2019-06-19 19:14:00.000000000 +0900
+++ ././src/class.c	2020-03-16 06:54:07.594869800 +0900
@@ -274,6 +274,7 @@
   // error.
   // raise TypeError.
   assert( !"TypeError" );
+  return 0;
 }
 
 
diff -ru /e/mrubyc-release2.0/src/console.h ././src/console.h
--- /e/mrubyc-release2.0/src/console.h	2019-06-19 19:14:00.000000000 +0900
+++ ././src/console.h	2020-03-16 09:59:04.210404700 +0900
@@ -17,7 +17,7 @@
 #include <stdint.h>
 #include <stdarg.h>
 #include <string.h>
-#include "hal/hal.h"
+#include "hal.h"
 
 #ifdef __cplusplus
 extern "C" {

src 上の hal (hardware abstract layer)はファイルコピーで作るみたいですが、2つの環境向けに1つのファイルでやる場合は邪魔でしたのでディレクトリ指定を消しました.

return 0; は -Werror -Wall で停まる対処です. assert で停まるならいいんでしょうが、 warning は出さない方がいいので追加しました.

diff -ru /e/mrubyc-release2.0/src/hal_posix/hal.h ././src/hal_posix/hal.h
--- /e/mrubyc-release2.0/src/hal_posix/hal.h	2019-06-19 19:14:00.000000000 +0900
+++ ././src/hal_posix/hal.h	2020-03-16 09:55:03.289404300 +0900
@@ -21,7 +21,7 @@
 /***** Feature test switches ************************************************/
 /***** System headers *******************************************************/
 #include <unistd.h>
-
+ int fsync(int fd); 
 
 /***** Local headers ********************************************************/
 /***** Constant values ******************************************************/

私の msys2 が悪いのか fsync() の定義が unistd.h にないみたいでして、その場しのぎに定義をはっつけときました. あとで悪影響があるかもしれませんが、リンクは通りました.

diff -ru /e/mrubyc-release2.0/src/vm_config.h ././src/vm_config.h
--- /e/mrubyc-release2.0/src/vm_config.h	2019-06-19 19:14:00.000000000 +0900
+++ ././src/vm_config.h	2020-03-16 09:37:43.281886700 +0900
@@ -75,9 +75,5 @@
 // #define MRBC_REQUIRE_32BIT_ALIGNMENT
 
 // Debug code.
-#if !defined(MRBC_DEBUG)
-#define MRBC_DEBUG
-#endif
-
 
 #endif

MRBC_DEBUG をつけると arm-xx-gcc で pointer の cast で文句をいってました. MRBC_DEBUG を強制する記述は害なので消しました.

追加分

src/mrubyc.mak

#
# mruby/c  src/Makefile
#
# Copyright (C) 2015-2019 Kyushu Institute of Technology.
# Copyright (C) 2015-2019 Shimane IT Open-Innovation Center.
#
#  This file is distributed under BSD 3-Clause License.
#

.PHONY: all clean
CFLAGS = $(_CFLAGS) -Wall -Werror -Wpointer-arith -std=c99
CFLAGS += #-pedantic -pedantic-errors
CFLAGS += -I$(HALDIR) -DMRBC_NO_TIMER

COMMON_SRCS = alloc.c class.c console.c global.c keyvalue.c load.c rrt0.c static.c symbol.c value.c vm.c $(HAL_C)
RUBY_LIB_SRCS = c_array.c c_hash.c c_numeric.c c_math.c c_range.c c_string.c mrblib.c

TARGET = $(OBJDIR)/libmrubyc.a
OBJS = $(addprefix $(OBJDIR)/, $(COMMON_SRCS:.c=.o) $(RUBY_LIB_SRCS:.c=.o))

all: $(OBJDIR)/$(HALDIR) $(TARGET)
$(OBJDIR)/$(HALDIR):
	mkdir -p $@
$(TARGET): $(OBJS)
	$(AR) $(ARFLAGS) $@ $?
clean:
	@rm -Rf $(TARGET) $(OBJS)

$(OBJDIR)/vm.o:
	$(CC) $(CFLAGS) -Wno-unused-variable $(CPPFLAGS) -c -o $@ $<
$(OBJDIR)/%.o: %.c
	$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
include mrubyc.d

オブジェクト出力ディレクトリとhalディレクトリの分離. 依存関係ファイルは長いので分離. -DMRBC_NO_TIMER はとりあえずでコンパイルを通すのに必要でした.

Makefile

ARMGCC_PREFIX = /d/dev/arm-gcc/bin/arm-none-eabi-
all:
	$(MAKE) -f mrubyc.mak CC=clang _CFLAGS="-O2 -DMRBC_DEBUG" OBJDIR=../obj_msys HALDIR=hal_posix HAL_C=hal_posix/hal.c
	$(MAKE) -f mrubyc.mak CC=$(ARMGCC_PREFIX)gcc.exe AR=$(ARMGCC_PREFIX)ar.exe _CFLAGS=-Os OBJDIR=../obj_arm HALDIR=hal_arm
clean:
	$(MAKE) -f mrubyc.mak OBJDIR=../obj_msys HAL_C=hal_posix/hal.c clean
	$(MAKE) -f mrubyc.mak OBJDIR=../obj_arm clean

こういうライブラリで MCU 用に CFLAGS に -g と -DMRBC_DEBUG をつけるのはよく考える必要がありますし、ユーザーレイヤのデバッグはシミュレーション上でやるのでメモリの節約の観点から MCU 向けには消しました.

mrubyc.d はファイル依存関係を抜き出したものです. xxx.o: を $(OBJDIR)/xxx.o にしただけなので省略します.