ADVENT CALENDAR 2019
.NETビルドスクリプトFAKEの紹介
By wraikny
これは AmusementCreators 2019 アドベントカレンダー その1 の5日目の記事です。
はじめに
ビルドスクリプト?
GNU Makeに代表されるような、複雑なビルド作業を自動化する簡易的なプログラムを言います。
Visual Studioであればビルド前後にコマンドを実行する機能があったり、*.sh
や*.cmd
ファイルを書いて実行することもありますが、基本的にOS等に依存してしまいます。
PythonやRubyで書く場合もあると思いますが、実行環境を別途インストールする必要があったり、その性質上コード量が多くなればメンテナンスも大変になります。 また、.NETの開発であればすべて.NETで済ませたいという気持ちもあります。
今回は.NET上で動く.NET向けのビルドスクリプトFAKE(F#製Make)を紹介していきます。 FAKEはF#の拡張なので、nugetのライブラリを読み込んで利用することもできます。
また、VisualStudioやdotnet
コマンドと問題なく共存するため、あくまでも追加機能に過ぎません。
例としてこのようにシンプルな記述ができます。
Target.create "Clean" <| fun _ ->
!! "src/**/bin"
++ "src/**/obj"
|> Shell.cleanDirs
Target.create "Build" <| fun _ ->
!! "src/**/*.*proj"
|> Seq.iter (DotNet.build id)
"Clean" ==> "Build"
Target.runOrDefault "Build"
それでは、使っていきましょうか。
今回解説するコードはこちらのリポジトリで公開しています。 wraikny/ACAC2019-05 - GitHub
環境
.NET Core SDK 3.0以上が必要です。
未インストールの方はこちらから
https://dotnet.microsoft.com/download
$ dotnet --version
3.0.100
また、VSCodeやVimを使っている方は、Ionideという拡張機能をインストールすることで補完等が効くようになります。 自分はVSCode + Ionideを使っていてオススメです。
そして、FAKEを使用する際のテンプレートをインストールします。
$ dotnet new -i "fake-template::*"
FAKE
FAKEのウェブサイトを見てみると
A DSL for build tasks and more
とありますが、実体はF#スクリプトに演算子の追加などをして拡張したものです。
とにかく、使ってみましょう。
セットアップ
新たなプロジェクトを作ってやっていきます。
$ mkdir ACAC2019-05
$ cd ACAC2019-05
$ dotnet new fake
The template "FAKE - Template" was created successfully.
Processing post-creation actions...
Template is configured to run the following action:
Description: update to latest version
Manual instructions: Run 'dotnet tool update fake-cli'
Actual command: dotnet tool update fake-cli
Do you want to run this action (Y|N)?
Y
Running command 'dotnet tool update fake-cli'...
Command succeeded.
以下の階層が出来上がります。
ACAC2019-05
|--.config
| |--dotnet-tools.json
|--build.fsx
|--fake.cmd
|--fake.sh
.gitignore
はVisualStudio.gitignore - GitHubを使うと良いでしょう。
VSCodeの.gitignore拡張から追加するのも楽ですね。
プロジェクト作成
.NET Coreを使用してプロジェクトを作成しましょう。
$ dotnet new console -o src/TestApp
FAKEでビルドします。
> fake.cmd build # Windows
$ ./fake.sh build # sh
$ dotnet fake build # 直接実行する場合
FAKEでデフォルトでは./src
以下にあるプロジェクトをビルドする設定になっているので、適切にできていればビルドが成功するはずです。
なお、.NET Coreに慣れていない人向けに説明すると、dotnet
コマンドだけなら以下で良いです。
.NET Coreを利用する多くの場合はこちらで十分だと思います。
$ dotnet build src/TestApp -c Debug # Debugモードでビルド
$ dotnet run src/TestAPp -c Release # Releaseモードで実行
build.fsx
FAKEではbuild.fsx
にスクリプトを記述します。
エディタで開いてみましょう。
なお、好みで2インデントにしています。 Tabは使えません。
Target.create
で、処理の単位に名前をつけています。
Target.create "Clean" (fun _ ->
!! "src/**/bin"
++ "src/**/obj"
|> Shell.cleanDirs
)
Target.create "Build" (fun _ ->
!! "src/**/*.*proj"
|> Seq.iter (DotNet.build id)
)
Target.create "All" ignore
!!
演算子と++
演算子でパスを指定しています。
また、以下で依存関係を記述しています。
"Clean"
==> "Build"
==> "All"
All
にはBuild
が必要で、Build
には Clean
が必要という構造です。
リソースフォルダを扱ってみる
Altseedを使ってゲームを作る場合、Debug
時はResources
フォルダ、Release
時はResources.pack
ファイルを参照する事が多いですね。
bin
以下に直接置くのは怖いですし、プロジェクトルートに置いて自動的にコピーやパッキングをしたくなります。
FAKEのShell
経由でFilePackageGeneratorを呼び出してみましょう。
CUI版のあるAltseed1.1.5.3を使用します。 なお、Windows以外の場合はMono Frameworkが必要になります。 (本来はdll参照で直接呼び出せるといいのですが……)
tool
フォルダ以下にファイルを置きましょう。
tool
|--FilePackageGenerator.exe
|--FilePackageGeneratorCore.dll
FilePackageGenerator.exe
を呼び出す関数を作ります。
Helper
というモジュールを作って、そこに以下の型を持つ関数packResources
を追加しました。
val packResources : target : string -> output : string -> password : string option -> unit
実装は記事末尾に載せておきます。
この関数を呼び出すために、新たにResources
というターゲットを作ります。
Resources
フォルダをDebug
にはコピー、Release
にはパッキングを行っています。
let targetProject = "TestApp"
let resources = "Resources"
let password = Some "password"
Target.create "Resources" (fun _ ->
let outDir x = sprintf "src/%s/bin/%s/netcoreapp3.0" targetProject x
// for Debug
let dir = outDir "Debug"
let target = dir + "/" + resources
Directory.create dir
Directory.delete target |> ignore
Shell.copyDir target resources (fun _ -> true)
Trace.trace "Finished Copying Resources for Debug"
// for Release
let dir = outDir "Release"
let target = sprintf "%s/%s.pack" dir resources
Directory.create dir
Helper.packResources resources target password
Trace.trace "Finished Packing Resources for Release"
)
FAKEのDirectory
やShell
の関数はプラットフォームの差異を吸収してくれて楽です。
各関数の使い方はググるかリファレンスを見てください。
なお通常の.NETのメソッドを使いたい場合は、open
の前に以下のように記述することで呼び出せるようになります。
#r "netstandard"
では、これを実行していきましょう。 まず仮のフォルダを作りました。
ACAC2019-05
|--Resources
|----nyan.txt
それから、ターゲットを指定してFAKE
を呼びます。
$ dotnet fake build -t Resources
src/TestApp/bin
以下を見れば、ファイルのコピーが成功しているのがわかるでしょう。
まとめ
Shellを直接書くのは大変です。 .NET Core SDKがあるだけで使えて、プラットフォームの差分も吸収してくれるFAKEを使うと簡単にビルドスクリプトが記述できて嬉しいですね。
今回紹介した以外にも多くのことが楽にできるので、特にF#ユーザの方は使ってみるとよさそうです。
FAKEのリファレンスはこちら
https://fake.build/apidocs/v5/index.html
今回のリポジトリはこちら
wraikny/ACAC2019-05 - GitHub
補足:packResources関数の実装
Windows以外ではmono
コマンド経由で実行する必要があり、その差分を吸収しています。
また、扱いやすいようにもしています。
module Helper =
let shellExec cmd args =
let args = String.concat " " args
Shell.Exec(cmd, args) |> function
| 0 -> Trace.tracefn "Success '%s %s'" cmd args
| code -> failwithf "Failed '%s %s', Exit Code: %d" cmd args code
let runNetExe cmd args =
if Environment.isWindows then
shellExec cmd args
else
shellExec "mono" (cmd::args)
let packResources target output password =
let cmd = "./tool/FilePackageGenerator.exe"
runNetExe cmd [
yield target
yield output
match password with
| Some(x) -> yield (sprintf "/k %s" x)
| None -> ()
]
参考
SHARE THIS POST
Tweet