体験!マイコンボードで組込みLinux

第11回 最新カーネル事情と組込みボードでのLua言語-C言語連携

この記事を読むのに必要な時間:およそ 3 分

Lua言語とC言語の連携

Lua言語でC言語の関数を使う

Lua言語とC言語の連携では,C言語からLua言語のスクリプトを呼び出すこともでき,反対にLua言語からC言語の関数を呼び出すこともできます。今回は,Lua言語からC言語の関数を呼び出す方法について解説します。

Lua言語は高水準のインタープリタなので柔軟にプログラム開発や試作などを手軽にオンボードで行うことができます。一方,C言語では低水準プログラミングに対応しており,かつ,ライブラリも完備しているので,Linuxの全ての機能を使ったり,ハードウェアの直接アクセスを行ったりすることができます。

組込みボードでは低水準のハードウェアアクセスの部分のみをC言語の関数にまとめて,それ以外の高水準のプログラミングをLua言語で行うのが最適だと思われます。最初は入門としてC言語で簡単な演算を行う関数を作成し,それを共有ライブラリへとこコンパイルをし,Lua言語のスクリプトからC言語で書かれた自作共有ライブラリを呼び出すことをやってみます。

Lua言語から呼び出すC言語関数

全ての引数の数と累積加算と累積積算の3つの戻り値を返すC言語側の関数はリスト1となります。

リスト1 引数の数,累積加算,累積積算を返す処理(C)

01: #include <lua.h>
02 #include <lualib.h>
03 #include <lauxlib.h>
04 
05 int    calc(lua_State *List) {
06     int        i, n;
07     lua_Number    sum, mul;
08 
09     n = lua_gettop(List);            // argc
10     sum = 0;
11     mul = 1;
12     for(i = 1;i <= n; i++) {
13         if(!lua_isnumber(List, i)) {
14             lua_pushstring(List, "Argument is not number.");
15             lua_error(List);
16         }
17         sum += lua_tonumber(List, i);    // argv[i]
18         mul *= lua_tonumber(List, i);    // argv[i]
19      }
20      lua_pushnumber(List, n);        // 1st
21      lua_pushnumber(List, sum);        // 2nd
22      lua_pushnumber(List, mul);        // 3rd
23      return 3;
24 }

Lua言語から呼び出されるC言語の関数を記述する場合は,Lua言語インターフェースのためのヘッダが必要になり,リスト1の1~3行目となります。

C言語側での関数名はLua言語から呼び出す関数名である必要はないので,適当なわかりやすい関数名にしておきます。Lua言語処理系からC言語へのインターフェースは,C言語においてはlua_State型のリスト構造のデータを介して行います。

Lua言語からC言語の関数へ渡す引数やLua言語がC言語の関数から受け取る戻り値は,lua_State型のリスト構造のデータに格納して行います。

C言語側の関数の引数は,lua_State型のリストのポインタとなり,リスト1の5行目のように指定します。

Lua言語からC言語の関数へ渡す引数の数は,リストのポインタを引数に指定したlua_gettop関数で得られます(リスト1の9行目⁠⁠。

Lua言語からC言語の関数へ渡す引数が数値かどうかをチェックする関数は,リストのポインタとインデックスを引数に指定したlua_isnumber関数で判定をします(リスト1の13行目⁠⁠。

Lua言語からC言語の関数へ渡す引数を数値として受け取る関数は,リストのポインタとインデックスを引数に指定したlua_tonumber関数でlua_Number型というLua処理系独特の数値型変数で得ます(リスト1の17~18行目⁠⁠。

C言語などの典型的な関数の言語仕様では引数は複数で戻り値は1つとなっていますが,Lua言語での関数の言語仕様では引数は複数で戻り値も複数となっていて,関数としての使い勝手が良くなっています。ただ,Lua言語で呼び出すC言語の関数はC言語の仕様で戻り値は1つなので,Lua言語で呼び出すC言語の関数で複数の戻り値を戻す場合は,Lua言語とのインターフェースとなるリストに対して順次,戻り値を格納し,最後にLua言語への戻り値の数をC言語関数の戻り値としています(リスト1の20~23行目⁠⁠。

Lua言語で呼び出すC言語の関数で複数の戻り値を戻す関数は,リストのポインタと戻り値を引数に指定したlua_pushnumber関数で格納し,lua_pushnumber関数を実行した順番がそのままLua言語への戻り値のインデックスとなります(リスト1の20~22行目⁠⁠。

Lua言語からC言語関数を呼び出す

Lua言語からC言語関数を呼び出すためにはC言語関数を共有ライブラリのかたちでコンパイルしなければなりません。

リスト1のソースファイル名をcalc.c,共有ライブラリ名と共有ライブラリのファイル名をcalc.soとすると以下のようにコンパイルします。

# sh3-linux-gcc -shared -Wl,-soname,calc.so -o calc.so calc.c

Lua言語からC言語関数を呼び出すスクリプト例はリスト2となります。

リスト2 Lua言語からC言語関数を呼び出すスクリプト例

01: func = package.loadlib("./calc.so", "calc")
02: num,sum,mul = func(3,4,7,2)
03: print("num="..num, "sum="..sum, "mul="..mul)

Lua言語からC言語関数を呼び出す場合は,package.loadlib関数で共有ライブラリのパスと共有ライブラリ内のC言語での関数名を引数として指定し,Lua言語側での関数名へ戻り値を代入します(リスト2の1行目⁠⁠。前述でC言語側での関数名はLua言語から呼び出す関数名と異なると述べましたが,このようにC言語側での関数名はLua言語から呼び出す関数名をリンクさせています。

リスト2の2行目ではC言語で書かれた関数を呼び出して複数の戻り値を格納し,リスト2の3行目でC言語で書かれた関数の処理結果をそれぞれ出力をしています。

次回は

次回はtcl言語とC言語の連携についてと,組込みボード上ではそのままでハードウェアアクセスが不可能なスクリプト言語からハードウェアアクセスを行う実例について解説します。

著者プロフィール

みついわゆきお

1986年日立製作所入所,その3年後に自社ワークステーションでの開発業務をきっかけにBSDを経てLinux利用を始める。

1991年日立を退社し,その後,ボランティアでLinux関連ツールの整備と開発しながらWindows否定運動およびLinux普及運動を開始し,Linuxディストリビューション草創期にはPlamoLinuxのメンテナンスにもかかわる。

2001年ごろより非営利ベースでボードコンピュータの開発を開始し,やがて,無償によりハードとソフトを開発したH8マイコンボードの販売を秋月電子にて開始した。

現在,ボードコンピュータ用基本ソフトMES2.5や,SHプロセッサ向けLinuxパッチおよびTOPPERS/JSPパッチを無償で一般に提供しながら,ティーエーシーやエムイーシステムより原価率100%を目標(ただし,販売店の営業・販売費用や開発・製造の際の差損を除く)としたSuperHボードコンピュータを販売中。

また,現在でも頑固にMS社否定及びWindows撲滅運動に邁進中。