WSL上にnxtOSEKの開発環境を構築する方法

[nxtosek]:http://lejos-osek.sourceforge.net/
[yagarto]:http://www.yagarto.org/
[etrobo]:https://www.etrobo.jp/
[cygwin]:https://www.cygwin.com/
[lejos-installation-enf]:http://lejos-osek.sourceforge.net/jp/installation_enf.htm
[lejos-installation-nb]:http://lejos-osek.sourceforge.net/jp/installation_nb.htm

# 概要

Lego Mindstorms NXT 向けの開発／実行環境としてnxtOSEK[[nxtosek][]]が，特にETロボコン[[etrobo][]]のコミュニティ界隈では長く使われてきました。

nxtOSEKのWindows上の開発環境[[lejos-installation-enf]，[lejos-installation-nb]]はCygwin[[cygwin][]]上での利用を前提とするGNU ARMベースのものなのですが，本稿執筆時点（2019年4月）で最新のCygwin上では，クロスコンパイラが致命的エラーを出力し nxtOSEKアプリケーションを構築することができません。エラーには今ひとつ再現性がなく，異なる対象のコンパイルで異なるエラーが出ます。forkに失敗したり，スタックやヒープが不足したりで致命的エラーが発生しています。*peflags*コマンドでスタックやヒープの割当を増やしても改善しません。

```
$ make all
Compiling ../../ecrobot/../toppers_osek/kernel/alarm.c to alarm.o
Compiling ../../ecrobot/../toppers_osek/kernel/event.c to event.o
Compiling ../../ecrobot/../toppers_osek/kernel/interrupt.c to interrupt.o
Compiling ../../ecrobot/../toppers_osek/kernel/osctl.c to osctl.o
      3 [main] arm-elf-gcc (16548) C:\WINAPP\Cygwin32\GNUARM\bin\arm-elf-gcc.exe: *** fatal error in forked process - couldn't allocate heap, Win32 error 487, base 0xE00000, top 0xE80000, reserve_size 520192, allocsize 524288, page_const 4096
    677 [main] arm-elf-gcc (16548) cygwin_exception::open_stackdumpfile: Dumping stack trace to arm-elf-gcc.exe.stackdump
      1 [main] arm-elf-gcc 642 dofork: child -1 - forked process 16548 died unexpectedly, retry 0, exit code 0xC0000142, errno 11
      2 [main] arm-elf-gcc (7376) C:\WINAPP\Cygwin32\GNUARM\bin\arm-elf-gcc.exe: *** fatal error in forked process - couldn't allocate heap, Win32 error 487, base 0xE00000, top 0xE80000, reserve_size 520192, allocsize 524288, page_const 4096
    570 [main] arm-elf-gcc (7376) cygwin_exception::open_stackdumpfile: Dumping stack trace to arm-elf-gcc.exe.stackdump
1067495 [main] arm-elf-gcc 642 dofork: child -1 - forked process 7376 died unexpectedly, retry 0, exit code 0xC0000142, errno 11
      2 [main] arm-elf-gcc (20044) C:\WINAPP\Cygwin32\GNUARM\bin\arm-elf-gcc.exe: *** fatal error in forked process - couldn't allocate heap, Win32 error 487, base 0xE00000, top 0xE80000, reserve_size 520192, allocsize 524288, page_const 4096
    621 [main] arm-elf-gcc (20044) cygwin_exception::open_stackdumpfile: Dumping stack trace to arm-elf-gcc.exe.stackdump
3131965 [main] arm-elf-gcc 642 dofork: child -1 - forked process 20044 died unexpectedly, retry 0, exit code 0xC0000142, errno 11
      2 [main] arm-elf-gcc (19644) C:\WINAPP\Cygwin32\GNUARM\bin\arm-elf-gcc.exe: *** fatal error in forked process - couldn't allocate heap, Win32 error 487, base 0xE00000, top 0xE80000, reserve_size 520192, allocsize 524288, page_const 4096
    670 [main] arm-elf-gcc (19644) cygwin_exception::open_stackdumpfile: Dumping stack trace to arm-elf-gcc.exe.stackdump
7200721 [main] arm-elf-gcc 642 dofork: child -1 - forked process 19644 died unexpectedly, retry 0, exit code 0xC0000142, errno 11
arm-elf-gcc: fork: Resource temporarily unavailable
make: *** [../../ecrobot/../ecrobot/tool_gcc.mak:109: build/kernel/osctl.o] エラー 1
```

Lego Mindstorms の最新プロダクトは EV3 ですが，大学や高専などの教育機関では教材用にこれまで NXT を相当数買い込んでいたりするケースが少なくありません。ハードはまだまだ動くのに，開発環境が使えないためにそれらを死蔵してしまうのも勿体ない話です。

Windows 10上では，その標準Linux環境，WSL（Windows Subsystem for Linux）が利用できるようになったこともあり，Cygwinを利用する動機もかなり薄れつつあります。そこでこれを機に，WSL 上でのnxtOSEKアプリケーションの開発環境を構築することにします。

# 開発環境構築の手順

**手順1：** Windows Subsystem for Linux（WSL）を有効化します。本稿ではその方法については触れません。[この記事](https://qiita.com/Aruneko/items/c79810b0b015bebf30bb)などを参考にしてください。

**手順2：** Windows上のARMアーキテクチャ向け開発環境，Yet Another GNU ARM Toolchain（YAGARTO）[[yagarto][]]をインストールします。[このリンク](https://sourceforge.net/projects/yagarto/files/YAGARTO%20for%20Windows/20071117/yagarto-bu-2.17_gcc-4.2.1-c-c%2B%2B_nl-1.15.0_gi-6.5.5_20071117.exe/download)からダウンロードしたインストーラ *yagarto-bu-2.17_gcc-4.2.1-c-c++_nl-1.15.0_gi-6.5.5_20071117.exe* を実行します。

+ YAGARTOはCygwinに依存しない，ARM向けのクロス開発ツールチェインを実現します。
+ インストール先には名前に空白を含まないディレクトリを指定します。ここでは，*C:/WINAPP/yagarto/* を指定するものとして，後の説明を続けます。
+ 筆者の環境（Windows 10 Pro）でインストーラを実行したところ，「次（NEXT）」ボタンが表示されませんでしたが，Enterキーで次のステップに進むことが可能です。
+ 参考文献[[lejos-installation-enf][]]，[[lejos-installation-nb][]]では，GCC-4.0.2ベースのツールチェインでコンパイルしなければコンパイルエラーの要因となり得ることが指摘されているのですが，筆者が試験した範囲ではこのバージョンでも大丈夫でした。

**手順3：** nxtOSEKをダウンロードします。[このリンク](https://sourceforge.net/projects/lejos-osek/files/nxtOSEK/nxtOSEK_v218.zip/download)からダウンロードした *nxtOSEK_v218.zip* を，名前に空白を含まないディレクトリに展開します。ここでは，*C:/Users/Alice/Documents/src* の下に，展開して得られる *nxtOSEK* ディレクトリを配置したものとして，後の説明を続けます。

+ :warning: nxtOSEKは，WSLのホーム（*/home/Alice/*）のようにWindows側からは見えないディレクトリではなく，Windows側から見えるディレクトリ（WSL側からは */mnt/ドライブ名/...* 以下に見えるディレクトリ）に展開してください。そうしなければ，（WSL上ではなく）Windows上で動くコンパイラやOSEK OILパーサ／コード生成ツール等のツール類が，nxtOSEKアプリケーションの構築に必要なファイルにアクセスできなくなってしまいます。

**手順4：** OSEK OILパーサ／コード生成ツールをダウンロードし，インストールします。[このリンク](http://www.toppers.jp/download.cgi/osek_os-1.1.lzh)からダウンロードした *osek_os-1.1.lzh* を展開します。展開して得られるディレクトリ中の *toppers_osek/sg/sg.exe* を，*nxtOSEK/toppers_osek/sg/* の下にコピーします。コピー後，*osek_os-1.1.lzh* を展開して得られたディレクトリはもう要りませんので，削除しても構いません。

**手順5：** Windows PCからNXTへのプログラム転送を行うNeXTToolをインストールします。[このリンク](http://bricxcc.sourceforge.net/nexttool.zip)からダウンロードした *nexttool.zip* を展開します。展開して得られる *NeXTTool.exe* を適当なディレクトリに置きます。ここでは，*C:/WINAPP/bin* の下に置いたものとして，後の説明を続けます。
この時点でディレクトリ構成は以下のようになります。但し，本稿で特に触れてないディレクトリ，ファイルについては省略しています。

```
C:/Users/Alice/Documents/src/nxtOSEK/ -+- ecrobot/
                                       |    +- tool_gcc.mak
                                       |    +- ecrobot.mak
                                       |    +- ecrobot++.mak
                                       +- toppers_osek/
                                            +- sg/
                                                 +- sg.exe
```

**手順6：** PCとNXTのUSB接続を実現するデバイスドライバ「NXTファントムドライバ」をインストールします。[このリンク](https://www.lego.com/r/www/r/mindstorms/-/media/franchises/mindstorms%202014/downloads/firmware%20and%20software/nxt%20software/nxt%20fantom%20drivers%20v120.zip?l.r2=-964392510)からダウンロードした *nxt fantom drivers v120.zip* を展開し，Windows フォルダの下のほうにある *setup.exe* を実行します。

**手順7：** アプリケーションの構築に必要なツールのパスを定義している *ecrobot/tool_gcc.mak* を書き変えます。*CC*，*CXX*，*AS*，...等のツールのコマンド名の定義には，すべて *.exe* が追加されていることに注意してください。

```
...
GNUARM_ROOT = /mnt/c/WINAPP/yagarto
...
NEXTTOOL_ROOT = /mnt/c/WINAPP/bin
...
CC       = $(CROSS)gcc.exe
CXX            = $(CROSS)g++.exe
AS       = $(CROSS)as.exe
AR       = $(CROSS)ar.exe
LD       = $(CROSS)g++.exe -nostartfiles
OBJCOPY  = $(CROSS)objcopy.exe
...
```

**手順8：** アプリケーションのC言語による構築プロセスを定義している *ecrobot/ecrobot.mak* を書き変えます。

303行で，Linux上でWindowsのコマンド実行を可能にする *wine* コマンドの名前を，マクロ *WINECONSOLE* に定義しています。WSLはWindowsのプログラムをそのまま実行できるため，*wine*は不要です。そこで以下のように書き換えます。

```
WINECONSOLE :=
```

330～331行目，ならびに335～336行目では，*wine* を介して *sg.exe* の呼出をしています。その際，*cygpath* コマンドを使って，Cygwin上のパス名をWindows上のパス名に変換する処理を行っています。

```
$(WINECONSOLE) $(TOPPERS_OSEK_ROOT_SG)/sg/sg $(shell cygpath -m -w ${TOPPERS_OSEK_OIL_SOURCE}) \
  -os=ECC2 -com=CCCA -I$(shell cygpath -m -w ${TOPPERS_OSEK_ROOT_SG})/sg/impl_oil -template=$(shell cygpath -m -w       ${TOPPERS_OSEK_ROOT_SG})/sg/lego_nxt.sgt
...（中略）...
$(WINECONSOLE) $(TOPPERS_OSEK_ROOT_SG)/sg/sg $(shell cygpath -m -w ${TOPPERS_OSEK_OIL_SOURCE}) \
  -os=ECC2 -I$(shell cygpath -m -w ${TOPPERS_OSEK_ROOT_SG})/sg/impl_oil -template=$(shell cygpath -m -w ${TOPPERS_OSEK_ROOT_SG})/sg/lego_nxt.sgt
```

先述の通り，*wine*は不要ですし，Windowsのプログラムを実行する場合はWSL上のパス名はWindows上のパス名に変換されるため，パス名の変換は不要です。そこで以下のように書き変えます。

```
$(TOPPERS_OSEK_ROOT_SG)/sg/sg.exe $(TOPPERS_OSEK_OIL_SOURCE) \
  -os=ECC2 -com=CCCA -I$(TOPPERS_OSEK_ROOT_SG)/sg/impl_oil -template=$(TOPPERS_OSEK_ROOT_SG)/sg/lego_nxt.sgt
...（中略）...
$(TOPPERS_OSEK_ROOT_SG)/sg/sg.exe $(TOPPERS_OSEK_OIL_SOURCE) \
  -os=ECC2 -I$(TOPPERS_OSEK_ROOT_SG)/sg/impl_oil -template=$(TOPPERS_OSEK_ROOT_SG)/sg/lego_nxt.sgt
```

**手順9：** アプリケーションのC++による構築プロセスを定義している *ecrobot/ecrobot++.mak* も同様に書き変えます。

307行は以下のように書き変えます。

```
WINECONSOLE :=
```

334～335行目，ならびに339～340行目は以下のように書き変えます。

```
$(TOPPERS_OSEK_ROOT_SG)/sg/sg.exe $(TOPPERS_OSEK_OIL_SOURCE) \
  -os=ECC2 -com=CCCA -I$(TOPPERS_OSEK_ROOT_SG)/sg/impl_oil -template=$(shell cygpath -m -w         ${TOPPERS_OSEK_ROOT_SG})/sg/lego_nxt.sgt
...
$(TOPPERS_OSEK_ROOT_SG)/sg/sg.exe $(TOPPERS_OSEK_OIL_SOURCE) \
  -os=ECC2 -I$(TOPPERS_OSEK_ROOT_SG)/sg/impl_oil -template=$(TOPPERS_OSEK_ROOT_SG)/sg/lego_nxt.sgt
```

以上で開発環境の構築は完了です。

**手順10：** nxtOSEKアプリケーションの構築とNXTへの転送は今まで通りです。たとえば，*nxtOSEK/samples_c/helloworld/* の下のアプリケーションを構築する場合は以下のようにします。

```
cd nxtOSEK/samples_c/helloworld/
make all
```

構築に成功すれば，*helloworld_OSEK.rxe* というバイナリファイルができます。それをNXTに転送するには，以下のようにします。

```
sh ./rxeflash.sh
```

# 参考文献

[[nxtosek][]] nxtOSEK/JSP: ANSI C/C++ with OSEK/μITRON RTOS for LEGO MINDSTORMS NXT
[[yagarto][]] Yet Another GNU ARM Toolchain（YAGARTO）
[[etrobo][]] ETロボコン
[[cygwin][]] Cygwin
[[lejos-installation-enf][]] 「拡張NXTファームウェア+nxtOSEKのインストール方法」 in 「nxtOSEK/JSP」
[[lejos-installation-nb][]] 「NXT BIOS+nxtOSEKのインストール方法」 in 「nxtOSEK/JSP」