コンパイラやシミュレータをコマンドラインで使用する方法

SOLID ツールチェーンと SOLID_QEMU シミュレータは SOLID 開発環境に統合されているため、SOLID-IDE を使用する場合は特に何もしなくても自動的に使用できますが、ここではそれぞれを単体でコマンドラインから使用する方法を解説します。

注釈

exeGCC はもともとコマンドラインでの使用が前提で、そのためのセットアップツールが付属しており、必要な環境変数が設定済みのコマンドプロンプトを起動したり、設定される環境変数とその内容を確認することができるので割愛します。

コンパイラをコマンドラインで使用する方法

exeClang は exeGCC とは異なり、特別な環境変数を(暗黙的な設定に)使用しません。そのため exeGCC の時のようなセットアップツールは付属しません。ユーザーがツールチェーンをコマンドラインで使用する場合は、必要なオプションを全て陽に指定する必要があります。

注釈

もともと exeGCC は単体で販売されていたので、自動的に必要な設定が行われる方が便利だったのですが、このようなコンパイラが勝手に自分自身の設定を変更してしまう方式は SOLID-IDE と相性が良くない(例えば、コンパイラ自身が暗黙的に設定したオプションは IDE のコンパイルログに出力されません)上に、そもそも IDE ではプロジェクトファイルで設定を管理するため不要な機能となったので、exeClang では廃止されました。

exeClang はデフォルトでは C:\GCC4 以下にインストールされます。(exeGCC からバージョン番号を引き継いだため、インストール場所も同じになっています。)そして、例えば RISC-V の RV64 s008 の場合は C:\GCC4\RV64\s008 にインストールされます。

この下に、例えば以下のようなセットアップスクリプトが大量に存在します。このスクリプトを Windows のコマンドプロンプト(bat ファイル)または MSYS2 の bash(sh ファイル)で実行することで、ツールチェーンを設定し、コマンドラインで使用可能になります。

C:\GCC4\RV64\s008>dir /b setup*
...
setup-rv64g-dll-nosys.bat
setup-rv64g-dll-nosys.sh
setup-rv64g-dll.bat
setup-rv64g-dll.sh
setup-rv64g-nosys.bat
setup-rv64g-nosys.sh
setup-rv64g.bat
setup-rv64g.sh
...

このうち、 setup-*-dll-* のように dll が付いているものは、通常は SOLID-IDE 上で開発する SOLID-OS の DLL で使用する設定なので、コマンドラインで使用する機会はほぼ無いと思われます。

nosys が付いているものは、OS のシステムコール(標準入出力など)が必要な機能が無効化されている設定で、ベアメタル開発には通常これを使用します。

PARTNER デバッガの VLINK 機能や QEMU シミュレータの semihosting 機能を使用する場合は、何も付いていない設定(以後、VLINK 設定)を使用します。

注釈

VLINK 設定と nosys 設定は大部分のライブラリが共通で、違いはリンクされるライブラリが libvlink か livnosys かの違いだけになります。open 関数や write 関数など、標準入出力関数の最後に呼び出される関数が nosys 設定(libnosys)では何もしないスタブ関数になっています。

拡張子が .bat のバッチファイルは、ダブルクリックして実行するとコマンドプロンプトが起動するので、その上でコンパイラが使用可能です。

拡張子が .sh のシェルスクリプトは MSYS2 の bash 上で、source コマンドで実行することによりコンパイラが使用可能になります。(MSYS2 のインストールなどの解説は割愛します。)

コマンドラインに使用可能な環境変数

セットアップスクリプトを実行すると、以下の環境変数がセットされた状態になります。環境変数の内容は、コマンドプロンプトは set コマンド、MSYS2 bash の場合は echo コマンドなどで確認できます。(以下の内容はバージョンごとに異なる場合があります。)

  • コマンドプロンプト

    C:\GCC4\RV64\s008>set CLANG_CFLAGS
    CLANG_CFLAGS=--sysroot C:\GCC4\RV64\s008\riscv64-kmc-elf --target=riscv64-kmc-elf -march=rv64g -mabi=lp64d -mcmodel=medany -DEXECLANG  -fno-math-errno
    
  • MSYS2

    $ source /c/GCC4/RV64/s008/setup-rv64g.sh
    $ echo $CLANG_CFLAGS
    --sysroot /c/GCC4/RV64/s008/riscv64-kmc-elf --target=riscv64-kmc-elf -march=rv64g -mabi=lp64d -mcmodel=medany -DEXECLANG -fno-math-errno
    

必ずコマンドラインに指定する必要がある環境変数

Makefile などでプロジェクトをビルドする際には、以下の環境変数の内容を確認して設定に組み込みんでください。

  • CLANG_CFLAGS

    コンパイル時に必要なオプションを指定。

  • CLANG_LDFLAGS

    リンク時に必要なオプションを指定。CRT(C Runtime Routine)とリンカスクリプトは指定されません。

  • PTHREAD_STUBS

    exeClang 付属 pthread スタブライブラリを指定。

  • QEMU_LDFLAGS(オプション)

    SOLID_QEMU シミュレータを使用する時のみ、追加で必要なオプション。CRT、(QEMU の semihosting 向け)BSP、リンカスクリプトなどを指定。

コマンドラインの例

以下は 後述 する QEMU_SOLID シミュレータで実行可能な ELF ファイルを生成します。この例では C プログラムをコンパイルしていますが、拡張子で自動的に判別されるので C++ プログラム( .cpp 拡張子)も同様の指定になります。

  • コンパイルとリンクを同時に行う例

    -o を指定しない場合、デフォルトの a.out というファイル名で ELF ファイルが生成されます。

    • コマンドプロンプト

      >clang %CLANG_CFLAGS% foo.c %PTHREAD_STUBS% %QEMU_LDFLAGS% %CLANG_LDFLAGS%
      
    • MSYS2

      $ clang $CLANG_CFLAGS foo.c $PTHREAD_STUBS $QEMU_LDFLAGS $CLANG_LDFLAGS
      
  • 分割コンパイルの例

    • コマンドプロンプト

      >clang %CLANG_CFLAGS% -c foo.c
      >clang %CLANG_CFLAGS% -c bar.c
      >clang %CLANG_CFLAGS% -c baz.c
      >clang foo.o bar.o baz.o -o main.out %PTHREAD_STUBS% %QEMU_LDFLAGS% %CLANG_LDFLAGS%
      
    • MSYS2

      $ clang $CLANG_CFLAGS -c foo.c
      $ clang $CLANG_CFLAGS -c bar.c
      $ clang $CLANG_CFLAGS -c baz.c
      $ clang foo.o bar.o baz.o -o main.out $PTHREAD_STUBS $QEMU_LDFLAGS $CLANG_LDFLAGS
      

内部でのみ使用される環境変数

以下は 前述 した環境変数の内部でのみ使用されている環境変数です。通常は指定不要です。

  • CLANG_ROOT

    コンパイラのインストールパス。 C:\GCC4\RV64\s008 など。

  • PATH

    CLANG_ROOT 以下の bin が PATH に追加されます。

  • CLANG_ARCH

    コンパイラがサポートするアーキテクチャ。 aarch64 , arm , riscv など。(RV32 も RV64 も `` riscv`` になります。)

  • CLANG_TRIPLE

    Clang の --target オプションの引数。 --sysroot オプションの引数にも使用されています。

  • CLANG_MARCH

    Clang の -march オプションの引数。

  • CLANG_MABI

    Clang の -mabi など、ABI に関連するオプション。

  • CLANG_MCMODEL

    Clang の -mcmodel など、コードモデルに関連するオプション。

  • CLANG_ISA

    ターゲットの命令セットとエンディアンをエンコードしたもの。 rv64gL など。

  • GCCSW_CFLAGS

    標準 C ライブラリをリビルドする時に必要なオプション。(rebuild-libs.sh でのみ使用。)

  • CLANG_LIBROOT

    ライブラリのルートディレクトリ。 -L オプションの引数に使用。このディレクトリ以下の ldscripts に付属のリンカスクリプトが存在するため、ここにライブラリパスを通しておくことで、 -T オプションの引数に ldscripts/foo.ld のような指定が可能になります。

  • CLANG_TARGET

    ライブラリのターゲット名。CLANG_ISA に float ABI などを追加したもの。 rv64gLd など。

  • CLANG_LIBDIR

    ライブラリが存在するディレクトリ。CLANG_LIBROOT 以下の CLANG_TARGET ディレクトリ。 -L オプションの引数に使用。

  • CLANG_CRT

    exeClang 付属 CRT を指定。

  • CLANG_XLEN

    汎用レジスタのビット幅で、32 か 64 になります。本来は RISC-V の用語ですが、便利なので他のアーキテクチャでも使用可能です。AARCH64 は 64、ARM は 32、RV32 は 32、RV64 は 64 になります。

  • SPIKE_LDSCRIPT(RISC-V のみ)

    SOLID_QEMU シミュレータの spike ターゲット向けリンカスクリプトを指定。

SOLID_QEMU をコマンドラインで使用する方法

コマンドラインの例 で生成した ELF ファイル( a.out )は、以下のようにして実行できます。

AARCH64

  • コマンドプロンプト

    >c:\kmc\QEMU_SOLID\AARCH64\qemu\qemu-system-aarch64.exe -M virt -cpu cortex-a53 -m 1G -nographic -semihosting -kernel a.out
    
  • MSYS2

    $ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -M virt -cpu cortex-a53 -m 1G -nographic -semihosting -kernel a.out
    

ARM

以下は ARMv7-A の場合です。ARMv7-R の場合は、 -cpu オプションを cortex-r5f に、ARMv8-R の場合は cortex-r52 に変更してください。

  • コマンドプロンプト

    >c:\kmc\QEMU_SOLID\AARCH64\qemu\qemu-system-aarch64.exe -M virt -cpu cortex-a7 -m 1G -nographic -semihosting -kernel a.out
    
  • MSYS2

    $ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -M virt -cpu cortex-a7 -m 1G -nographic -semihosting -kernel a.out
    

注釈

qemu-system-aarch64 の virt ターゲットは、本来は cortex-r5fcortex-r52 はサポートしていません。SOLID_QEMU ではコンパイラのテスト用に KMC がパッチを当てて指定可能にしています。そのため CPU と RAM 以外のペリフェラルは未サポートとなります。

それ以外のターゲットの場合は、コンパイルオプションも変更する必要があります。

追加のコマンドラインオプション

Cortex-M には汎用のターゲット(virt)が存在しないので、必要な CPU をサポートする QEMU の FPGA ターゲットに合わせてメモリマップを指定する必要があります。

RAM のサイズは mps2 (an385/386/500/505) の PSRAM 16MiB に揃えています。mps3 (an547) は 1GiB まで指定可能です。

  • armv7m (cpu: cortex-m3, target: mps2-an385)

    -Wl,--defsym=RAM_ADDRESS=0x21000000 -Wl,--defsym=RAM_SIZE=0x01000000 -Wl,--defsym=HEAP_SIZE=0x00400000
    
  • armv7em fpv4-sp (cpu: cortex-m4, target: mps2-an386)

    -Wl,--defsym=RAM_ADDRESS=0x21000000 -Wl,--defsym=RAM_SIZE=0x01000000 -Wl,--defsym=HEAP_SIZE=0x00400000
    
  • armv7em fpv5-dp (cpu: cortex-m7, target: mps2-an500)

    -Wl,--defsym=RAM_ADDRESS=0x60000000 -Wl,--defsym=RAM_SIZE=0x01000000 -Wl,--defsym=HEAP_SIZE=0x00400000
    
  • armv8m.main (cpu: cortex-m33, target: mps2-an505)

    -Wl,--defsym=RAM_ADDRESS=0x80000000 -Wl,--defsym=RAM_SIZE=0x01000000 -Wl,--defsym=HEAP_SIZE=0x00400000
    
  • armv8.1m.main (cpu: cortex-m55, target: mps3-an547)

    -Wl,--defsym=RAM_ADDRESS=0x60000000 -Wl,--defsym=RAM_SIZE=0x01000000 -Wl,--defsym=HEAP_SIZE=0x00400000
    

QEMU コマンドラインオプション

以下は MSYS2 bash 版のみとなります。Windows コマンドラインでは適宜読み替えてください。

Cortex-M には汎用のターゲット(virt)が存在しないので、CPU に合わせて QEMU の FPGA ターゲットを使用しています。

  • armv7m

    $ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -cpu cortex-m3 -M mps2-an385 -nographic -semihosting -device loader,addr=0x21000001,cpu-num=0 -kernel a.out
    
  • armv7em fpv4-sp

    $ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -cpu cortex-m4 -M mps2-an386 -nographic -semihosting -device loader,addr=0x21000001,cpu-num=0 -kernel a.out
    
  • armv7em fpv5-dp

    $ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -cpu cortex-m7 -M mps2-an500 -nographic -semihosting -device loader,addr=0x60000001,cpu-num=0 -kernel a.out
    
  • armv8m.main

    $ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -cpu cortex-m33 -M mps2-an505 -nographic -semihosting -device loader,addr=0x80000001,cpu-num=0 -kernel a.out
    
  • armv8m.main / armv8.1m.main

    $ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -cpu cortex-m55 -M mps3-an547 -nographic -semihosting -device loader,addr=0x60000001,cpu-num=0 -kernel a.out
    

注釈

ターゲットごとに RAM サイズが固定なので -m オプションは指定していません。

armv8m.main の例

$ source /c/GCC4/ARM/s009/setup-armv8m.main_thumb_fp-armv8-fullfp16-sp-d16_hard.sh
$ cat hello.c
#include <stdio.h>
int main() {fprintf(stderr, "hello, world!\n"); return 0;}
$ clang $CLANG_CFLAGS hello.c $PTHREAD_STUBS $QEMU_LDFLAGS $CLANG_LDFLAGS -Wl,--defsym=RAM_ADDRESS=0x80000000 -Wl,--defsym=RAM_SIZE=0x01000000 -Wl,--defsym=HEAP_SIZE=0x00400000
$ /c/KMC/QEMU_SOLID/AARCH64/qemu/qemu-system-aarch64.exe -cpu cortex-m33 -M mps2-an505 -nographic -semihosting -device loader,addr=0x80000001,cpu-num=0 -kernel a.out
hello, world!

RISC-V

以下は RV64 の場合です。RV32 の場合は riscv64/rv64 の部分を riscv32/rv32 に読み替えてください。

  • コマンドプロンプト

    >c:\kmc\QEMU_SOLID\RISCV\qemu\qemu-system-riscv64.exe -M spike -cpu rv64 -m 1G -nographic -semihosting -bios none -kernel a.out
    
  • MSYS2

    $ /c/KMC/QEMU_SOLID/RISCV/qemu/qemu-system-riscv64.exe -M spike -cpu rv64 -m 1G -nographic -semihosting -bios none -kernel a.out
    

-cpu オプションはターゲットごとに異なります。

以下はデフォルト無効の C 拡張を有効にしたパターンになっています。不要な場合は c=true を削除するか、 c=false を指定してください。

  • IMAC ターゲット(F と D 拡張無効)

    -cpu rv64,i=true,m=true,a=true,f=false,d=false,c=true

    注釈

    SOLID_QEMU(RISCV) の QEMU 8.1.0 には f=false 時に Zfa=false を指定しないとエラーになるバグがあります。それ以外のバージョンでは不要なのでここでは指定していませんが、注意してください。

  • IMAFC ターゲット(D 拡張無効)

    -cpu rv64,i=true,m=true,a=true,f=true,d=false,c=true

  • IMAFCV ターゲット(D 拡張無効、V 拡張有効)

    -cpu rv64,i=true,m=true,a=true,f=true,d=false,c=true,v=true,vlen=1024,elen=64,vext_spec=v1.0

  • GC ターゲット

    -cpu rv64,g=true,c=true

  • GCV ターゲット(V 拡張有効)

    -cpu rv64,g=true,c=true,v=true,vlen=1024,elen=64,vext_spec=v1.0

V 拡張はスケーラブルベクタなので vlen が適切な範囲(Clang は 128 から 8192 までの 2 のべき乗をサポート)ならばいずれの値でも動作しなければいけませんが、ここでは 1024 を指定しています。最適化オプションで VLEN を指定した最適化を行った場合は、その VLEN の値に合わせる必要があります。