公開技術情報

[English] [Japanese]

23. ビルド 編

今回は LuneScript を使用したプロジェクトを、ビルドする方法について説明します。

+LuneScript は、コマンドラインから利用するトランスコンパイラを提供しますが、 LuneScript 専用のビルドツールは提供していません。 よって、ここでは一般的なビルド方法について説明します。

LuneScript をトランスコンパイルするには、以下の方法があります。

  • 個別ビルド
  • バッチビルド

バッチビルドは、複数の .lns ファイルを一括でトランスコンパイルします。

個別ビルド

Lua へトランスコンパイルするには、次のコマンドを実行します。

$ lnsc hello.lns save

これにより hello.lns をトランスコンパイルし、 変換後のコードを hello.lua に出力します。

この hello.lua は Lua コマンドで実行できます。

$ lua hello.lua

これを、全ての .lns ファイルに対して行なうことで、 全ての .lns ファイルをトランスコンパイルできます。

ただし、 .lns ファイルが多い場合、これだと効率が悪いです。

バッチビルド

バッチビルドは、複数の .lns ファイルを一括でトランスコンパイルします。

複数の .lns ファイルを指定するには、 lnsc のオプションに @- を指定し、 stdin に .lns ファイルパスを渡します。 stdin に渡す .lns ファイルパスは、1 行につき 1 ファイル出力します。

例えば、 proj ディレクトリ以降の全 .lns ファイルを渡す場合、以下になります。

$ find proj -name '*.lns' | lnsc @- save

現時点で、これが最も高速に処理できる方法です。

参考情報

以降は参考情報です。

メタ情報ファイル

メタ情報ファイルとは、モジュールが公開しているクラスや、 そのモジュールが import している他のモジュールの依存関係などの情報を まとめたファイルです。

import する際、モジュールを解析する代わりに このメタ情報ファイルを読み込むことで、解析時間を短縮できます。

メタ情報ファイルは、次のコマンドで生成できます。

$ lnsc hello.lns SAVE

先程のコマンドと何が違うかというと、 "save" と "SAVE" の違いです。

小文字の save は、トランスコンパイルした Lua コードだけ生成しますが、 大文字の SAVE は、 Lua コードとメタ情報ファイルを生成します。

具体的には、上記コマンドを実行すると hello.lua と hello.meta が生成されます。

LuneScript はモジュールを import する際、 次の条件が全て成り立つ時に .meta ファイルをロードします。 このとき、import 対象の .lns ファイルの解析は行ないません。

  • .lns に対応する .lua と .meta が存在する
  • それぞれのファイルの更新時間について、次の条件を満す

    • .lns < .meta
  • インポート対象の mod1.lns 内で import しているモジュール mod2 の更新時間に対し、 次の条件を満す。

    • mod1 > mod2
  • .meta ファイルのフォーマットバージョンが正しい

依存関係

2 つのモジュール mod1, mod2 があった時、 mod1 が mod2 を import していると、「mod1 が mod2 に依存する」ことになります。

「mod1 が mod2 に依存する」ということは、 mod2 を修正した時は「mod2 だけでなく、mod1 もトランスコンパイルが必要になる」 ということです。

このような依存関係があるモジュールをビルドするには、 古くから make コマンドが利用されています。 近年は様々なビルドツールがありますが、 make が代表的なビルドツールであることには違いありません。

make コマンドは、定義された依存関係によって、 あるファイルが修正された際、 そのファイルに依存するファイルを更新する制御を行ないます。

この依存関係を手動で定義するのは、意外と面倒なものです。

LuneScript は、 make コマンドの依存関係を自動生成する機能を提供します。

LuneScript で依存関係を自動生成するには、次のように SAVE 時にオプションを指定します。

$ lnsc mod1.lns --depends depends/mod1.d SAVE

これは、 mod1.lns をトランスコンパイルすると同時に、 depends/mod1.d に mod1.lns の依存関係情報を出力します。

この依存関係情報を Makefile に取り込むことで、 手動で依存関係を定義することなく、簡単に make によるビルド制御が可能になります。

サンプル

例えば次のようなモジュールをもつプロジェクトを作成したとします。

test/proj/
      |
      +--- Mod1.lns
      |
      +--- Mod2.lns
      |
      +--- Mod3.lns
      |
      +--- Mod4.lns

ここで、それぞれのファイルの中身は次とします。

  • Mod1.lns
// @lnsFront: skip
import test.proj.Mod2;

pub fn func(): str {
   return "%s -> %s" (__func__, Mod2.func() );
}
print( func() );
  • Mod2.lns
// @lnsFront: skip
import test.proj.Mod3;

pub fn func(): str {
   return "%s -> %s" (__func__, Mod3.func() );
}
  • Mod3.lns
// @lnsFront: skip
import test.proj.Mod4;

pub fn func(): str {
   return "%s -> %s" (__func__, Mod4.func() );
}
  • Mod4.lns
// @lnsFront: ok
pub fn func(): str {
   return __func__;
}

上記のファイルの依存関係は次のようになっています。

ファイル 依存ファイル
Mod1.lns Mod2.lns
Mod2.lns Mod3.lns
Mod3.lns Mod4.lns
Mod4.lns なし

このプロジェクトをビルドする Makefile は、次のようになります。

PROJ_DIR=test/proj
MKFILE=$(PROJ_DIR)/Makefile
SRC_DIR=$(PROJ_DIR)/

.PHONY: test all build setup

define comp
	@echo "$1 -> $2"
	lnsc $1 --depends depends/$(shell echo $1 | sed 's@/@.@g').d SAVE
endef

%.meta: %.lns
	$(call comp,$<,$@)

SRCS =
SRCS += Mod1.lns
SRCS += Mod2.lns
SRCS += Mod3.lns
SRCS += Mod4.lns

SRCS := $(addprefix $(SRC_DIR),$(SRCS))

META_LIST=$(SRCS:.lns=.meta)
LUA_LIST=$(SRCS:.lns=.lua)

-include depends/*.d

all:
	@echo make setup
	@echo make build

setup:
	mkdir -p depends

build: $(META_LIST)

ここで重要なのが、 define comp-include depends/*.d の部分です。

  • define comp は、トランスコンパイルと依存情報ファイルの生成処理を登録しています。
  • -include depends/*.d は、生成した依存情報ファイルを読み込んでいます。

このような makefile を作成することで、 import の依存関係に応じたビルドが可能になります。

まとめ

make コマンドを使うことで、 LuneScript プロジェクトのビルド制御を簡単に実現できます。