ビルドツールpremakeについてご紹介。
20161014追記
201609更新
Premakeの守備範囲はだいたいCMakeに似ていて、定義ファイルからvcソリューションやMakeFileの生成をすることができます。プロジェクトで各ライブラリのオプション(/MTとか/MTDとかDEFINEなど)をまとめて変えたい場合、生成物の出力ディレクトリをDebug, Release, Win32, Win64, VS2010, VS2013で違うディレクトリに出力したい、もしくは同じディレクトリに違う名前で出力したい場合などに設定をluaコードで記述することができます。
こういった場合、VSで開発しているとプロジェクトの設定を開いてマウスでぽちぽちしたりvcxprojのXMLを直接編集するのを強いられますし、CMakeではCMake語がよくわかりません。しかしPremakeで管理していれば次のように記述してソリューションを再生成するだけでさくっと設定完了できるかもしれません。
-- PlatformとConfiguration毎に出力ディレクトリを分ける
filter {"platforms:Win32", "configurations:Debug" }
targetdir "build/Win32/Debug"
filter {"platforms:Win32", "configurations:Release" }
targetdir "build/Win32/Release"
filter {"platforms:Win64", "configurations:Debug" }
targetdir "build/Win64/Debug"
filter {"platforms:Win64", "configurations:Release" }
targetdir "build/Win64/Release"
-- すべてのPlatformとConfiigurationのvcのリンクをStaticRuntime(/MT, /MTdの方)にする
filter {} -- filterをクリア。すべてが対象になる
flags { "StaticRuntime" }
#Download
https://premake.github.io/download.html
のリンクからPremake 5.0 (alpha)を取得するべし。
#HelloWorldプロジェクト
HelloWorldしてみる。
新しいディレクトリを作ってファイルを配置します。
+ hello_premake
+ hello.c
+ premake5.lua
+ premake5.exe
#include <stdio.h>
int main(void)
{
puts("Hello, word!");
return 0;
}
各コマンドは呼び出しにスコープのような効果範囲が決まっていて
直近のprojectとfilterが呼び出しが範囲を決める。
エディタでインデントをかけるとフラットになっていしまうので
lua言語のブロックdo, endで人工的にインデントしてみた。
-- premake5.lua
workspace "hello_premake"
configurations { "Debug", "Release" }
project "hello_premake"
do
kind "ConsoleApp"
language "C"
files { "**.h", "**.c" }
filter "configurations:Debug"
do
defines { "DEBUG" }
flags { "Symbols" }
end
filter "configurations:Release"
do
defines { "NDEBUG" }
optimize "On"
end
end
premake5.exeを実行してプロジェクトを生成。
> premake5.exe vs2015
Building configurations...
Running action 'vs2015'...
Generated hello_premake.sln...
Generated hello_premake.vcxproj...
Done (24ms).
が生成されます。
ビルド
> set MSBUILD=C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe
> "%MSBUILD%" hello_premake.sln /p:Configuration=Release /p:Platform=Win32
Microsoft (R) Build Engine バージョン 14.0.25420.1
Copyright (C) Microsoft Corporation. All rights reserved.
このソリューション内のプロジェクトを 1 度に 1 つずつビルドします。並行ビルドを有効にするには、"/m" スイッチを追加してください。
2016/09/25 0:10:16 にビルドを開始しました。
ノード 1 上のプロジェクト "D:\dev\hello_premake\hello_premake.sln" (既定のターゲット)。
ValidateSolutionConfiguration:
ソリューション構成 "Release|Win32" をビルドしています。
プロジェクト "D:\dev\hello_premake\hello_premake.sln" (1) は、ノード 1 上に "D:\dev\hello_premake\hello_premake.
vcxproj" (2) をビルドしています (既定のターゲット)。
PrepareForBuild:
ディレクトリ "obj\Release\" を作成しています。
ディレクトリ "bin\Release\" を作成しています。
ディレクトリ "obj\Release\hello_premake.tlog\" を作成しています。
InitializeBuildStatus:
"AlwaysCreate" が指定されたため "obj\Release\hello_premake.tlog\unsuccessfulbuild" を作成していま す。
ClCompile:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\CL.exe /c /Zi /nologo /W3 /WX- /Ox /Oi
/Oy- /D NDEBUG /D _UNICODE /D UNICODE /GF /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:for
Scope /Zc:inline /Fo"obj\Release\\" /Fd"obj\Release\vc140.pdb" /Gd /TC /analyze- /errorReport:que
ue hello.c
hello.c
Link:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\link.exe /ERRORREPORT:QUEUE /OUT:"bin\
Release\hello_premake.exe" /INCREMENTAL:NO /NOLOGO kernel32.lib user32.lib gdi32.lib winspool.lib
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /M
ANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /PDB:"bin\Release\hello
_premake.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /TLBID:1 /ENTRY:"mainCRTStartup" /DYNAMICBASE
/NXCOMPAT /IMPLIB:"bin\Release\hello_premake.lib" /MACHINE:X86 /SAFESEH obj\Release\hello.obj
hello_premake.vcxproj -> D:\dev\hello_premake\bin\Release\hello_premake.exe
FinalizeBuildStatus:
ファイル "obj\Release\hello_premake.tlog\unsuccessfulbuild" を削除しています。
"obj\Release\hello_premake.tlog\hello_premake.lastbuildstate" のタッチ タスクを実行しています。
プロジェクト "D:\dev\hello_premake\hello_premake.vcxproj" (既定のターゲット) のビルドが完了しました 。
プロジェクト "D:\dev\hello_premake\hello_premake.sln" (既定のターゲット) のビルドが完了しました。
ビルドに成功しました。
0 個の警告
0 エラー
以下のbatファイルを作っておくとわりと便利。
premake5.exe vs2015
ファイル名の命名規則
カレントのpremake5.luaがデフォルトの設定として使われる。なければpremake4.luaも検索される。
個別にファイルを指定するには"--file="コマンドラインを使う。
luaのシンタックス上の注意
関数呼び出し時に、引数が文字列かテーブルのリテラルの場合のみ括弧を省略できる。
project "project_name"
files {
"hello.c",
}
リテラルじゃない場合エラーになります
local name="project_name"
project name -- x
project(name) -- o
環境、種別を切り分ける概念
action
どの種類のプロジェクトを生成しているか。premake5.exeのコマンドライン引数。
vs2010, vs2013, vs2015, gmake, etc...
action別に切り分けできる。
filter { "action:vs*" }
-- vs用の設定
filter { "action:gmake" }
-- gmake用の設定
configuration
バリエーション。
よく使うのはこれ。
-- 定義して
configurations { "Debug", "Release" }
-- 設定する
filter "configurations:Debug"
do
defines { "DEBUG", "_DEBUG" }
flags { "Symbols" }
end
filter "configurations:Release"
do
defines { "NDEBUG" }
optimize "On"
end
以外にも
dll_debug32, static_debug32
等自由に定義できる。
platform
バリエーションその2。
Unlike build configurations, platforms are completely optional. If you don't need them, just don't call the platforms function at all and the toolset's default behavior will be used.
x86, x86_64, etc...
-- 定義して
platforms { "x86_64", "x86" }
-- 設定する
filter { "platforms:x86" }
architecture "x86"
filter { "platforms:x86_64" }
architecture "x86_64"
#実用的な雛形
筆者がいつも使っているものです。
- sln, vcxproj等の出力ディレクトリを_build_premakeに隔離
- 32bit, 64bitの2種類
- Debug, Releaseの2種類
- 成果物(exe, dll)の出力を_build_premake/Win64_Releaseという風に指定
- 出力ディレクトリを分けたのでライブラリ名に_dといったサフィックスは付けない
実際には、Win32をばっさり削ってます。
あと、プロジェクト定義は別々のファイルに分割してincludeかdofileで読み込みます(後述)。
local build_dir="_build_premake"
-- premake5.lua
location(build_dir)
workspace "workspace"
do
configurations { "Debug", "Release" }
platforms { "Win32", "Win64" }
end
filter "configurations:Debug"
do
defines { "DEBUG", "_DEBUG" }
flags { "Symbols" }
end
filter "configurations:Release"
do
defines { "NDEBUG" }
optimize "On"
end
filter { "platforms:Win32" }
architecture "x86"
filter {"platforms:Win32", "configurations:Debug" }
targetdir(build_dir.."/Win32_Debug")
filter {"platforms:Win32", "configurations:Release" }
targetdir(build_dir.."/Win32_Release")
filter { "platforms:Win64" }
architecture "x64"
filter {"platforms:Win64", "configurations:Debug" }
targetdir(build_dir.."/Win64_Debug")
filter {"platforms:Win64", "configurations:Release" }
targetdir(build_dir.."/Win64_Release")
filter { "action:vs*" }
buildoptions {
"/wd4996",
}
defines {
"_CRT_SECURE_NO_DEPRECATE",
"NOMINMAX",
}
--characterset "Unicode"
characterset "MBCS"
filter {} -- filter clear
project "project"
do
--kind "ConsoleApp"
--kind "WindowedApp"
--kind "StaticLib"
kind "SharedLib"
--language "C"
language "C++"
objdir "%{prj.name}"
flags{
--"WinMain" -- with WindowedApp kind
--"StaticRuntime",
}
files {
"*.cpp",
"*.h",
}
includedirs {
}
defines {
}
buildoptions {
}
libdirs {
}
links {
}
postbuildcommands{
"copy $(TargetDir)$(TargetName).dll ..",
}
filter { "configurations:Debug" }
do
postbuildcommands{
"copy $(TargetDir)$(TargetName).pdb ..",
}
end
end
premakeでプロジェクト設定を管理してgitignoireに_build_premakeを設定し、slnやvcxprojを生成物と見なして
リビジョン管理から外してます。
howto/tips
##プロジェクト定義を外部ファイルに分ける
dofileを使う。
dofile "subproject/premake5.lua"
省略形として
include "subproject"
変数展開
configurations { "debug", "release" }
platforms { "x86_64", "x86" }
libdirs {
"$(FBXSDK_DIR)/lib/%{cfg.action}/%{cfg.platform}/$(Configuration)",
}
-- $(FBXSDK_DIR)\lib\vs2015\x86_64\$(Configuration)と展開される
実例
##libpng
+ libpng
+ premake5.lua
+ libpng-1.6.16
+ premake5.lua
+ zlib-1.2.8
+ premake5.lua
-- premake5.lua
location "build"
solution "libpng"
do
configurations { "Debug", "Release" }
platforms { "Win32", "Win64" }
end
defines {
"WIN32",
"_WINDOWS",
"_USRDLL",
}
buildoptions { "/wd4996" }
filter "configurations:Debug"
do
defines { "DEBUG", "_DEBUG" }
flags { "Symbols" }
end
filter "configurations:Release"
do
defines { "NDEBUG" }
optimize "On"
end
filter { "platforms:Win32" }
architecture "x32"
filter { "platforms:Win64" }
architecture "x64"
filter {"platforms:Win32", "configurations:Debug" }
targetdir "build/Win32/Debug"
filter {"platforms:Win32", "configurations:Release" }
targetdir "build/Win32/Release"
filter {"platforms:Win64", "configurations:Debug" }
targetdir "build/Win64/Debug"
filter {"platforms:Win64", "configurations:Release" }
targetdir "build/Win64/Release"
include "libpng-1.6.16"
include "zlib-1.2.8"
project "zlib"
do
kind "StaticLib"
language "C"
--language "C++"
files { "*.h", "*.c" }
end
project "libpng"
do
kind "SharedLib"
language "C"
--language "C++"
files { "*.h", "*.c" }
-- 依存関係を記述できる(libファイル名か他のproject名を書ける)
links { "zlib" }
end
とりあえずソースをダウンロードしてlibpng.dllを生成するべく定義してみた。zlibはあっさりとビルドできてしまったが、libpngの方はさすがに通らない。修正する。
libpng-1.6.16/projects/vstudio/libpng/libpng.vcxprojを参考にlibpng-1.6.16/premake5.luaを改造する。
project "libpng"
do
kind "SharedLib"
language "C"
--language "C++"
files {
"png.c",
"pngerror.c",
"pngget.c",
"pngmem.c",
"pngpread.c",
"pngread.c",
"pngrio.c",
"pngrtran.c",
"pngrutil.c",
"pngset.c",
"pngtrans.c",
"pngwio.c",
"pngwrite.c",
"pngwtran.c",
"pngwutil.c",
}
includedirs {
"../zlib-1.2.8",
}
-- 基準ディレクトリはvcxprojのあるところ
prebuildcommands {
"copy ..\\libpng-1.6.16\\scripts\\pnglibconf.h.prebuilt ..\\libpng-1.6.16\\pnglibconf.h",
}
links { "zlib" }
end
/MT(/MTD)の件
-- buildoptions { "/wd4996" }の次の行あたり
flags { "StaticRuntime" }
MSVCR12D.DLLへの参照を消し去った。
こんな感じでプロジェクトを見通しのいい状態で管理できる。