premake

  • CMake와 같은 멀티 플랫폼 오픈소스 개발에 유용한 툴.
  • lua를 통해 스크립트를 작성한다. 루아 파일 이름과 같은 이름의 솔루션 파일을 만들어준다.
  • 현재 premake4와 premake5 두 가지 버전이 있다.
    • Visual Studio 2013 이상을 지원하려면 premake5를 사용해야 한다.
  • C, C++, or C# projects targeting:
    • Microsft Visual Studio 2008-2015
    • GNU Make, including Cygwin and MinGW
    • Previous version of Premake also supported exporting for Xcode, MonoDevelop, Code::Blocks, and CodeLite. We are in the process of bringing these exporters back online for the final release.
  • Premake 5.0 generated projects can support:
    • 32- and 64-bit builds
    • Xbox 360 (Visual Studio only)
  • Addon module
  • 오피셜 페이지
  • 깃허브 페이지
  • Premake를 사용하는 단체 혹은 프로젝트
  • premake-cookbook(ver 4 기준)

키워드

  • location
    • 쓰기 폴더(작성 환경에서의 패스가 된다)
    • 후에 filter에서 대응 플랫폼에 나누어 쓸 수 있다.
  • characterset
    • MBCS는 멀티 바이트 문자 세트
  • kind
    • StaticLib: .lib
    • SharedLib: .dll
    • ConsoleApp: 콘솔 응용 프로그램
    • WindowedApp: win32 어플리케이션
  • postbuildcommands
    • 빌드 전에 실행하는 명령어
    • fxc 등을 실행하는 것도 가능
  • filter
    • 특정 환경에서의 동작을 지정
  • flags
    • Symbols:심볼 정보를 읽기(브레이크 포인트 정보)

다른 키워드는 아래 링크의 코드를 참고한다.
https://github.com/GPUOpen-LibrariesAndSDKs/ForwardPlus11

실습

hello world

+ HelloWorld
  + hello.c
  + premake5.lua
  + premake5.exe
  + vc2013.bat
//hello.c
#include <stdio.h>

int main(void) {
   puts("Hello, word!");
   return 0;
}
-- premake5.lua
solution "HelloWorld"
do
    configurations { "Debug", "Release" }
end

project "HelloWorld"
do
    kind "ConsoleApp"
    language "C"
    -- todo: この記述の意味
    targetdir "bin/%{cfg.buildcfg}"

    files { "**.h", "**.c" }

    filter "configurations:Debug"
    do
        defines { "DEBUG" }
        flags { "Symbols" }
    end

    filter "configurations:Release"
    do
        defines { "NDEBUG" }
        optimize "On"
    end
end

simple_console. 간단한 기능의 console 프로젝트

-- A solution contains projects, and defines the available configurations
solution "MyApplication"
  configurations { "Debug", "Release" }

  -- A project defines one build target
  project "MyApplication"
    kind "ConsoleApp"
    language "C++"
    files { "**.h", "**.cpp" }

    configuration "Debug"
      defines { "DEBUG" }
      flags { "Symbols" }

    configuration "Release"
      defines { "NDEBUG" }
      flags { "Optimize" }

빌드 전

빌드 후

VS 상태

출력 디렉토리를 분리한다

  • build 디렉토리에 파일이 생성되도록 한다
-- premake5.lua
location "build"

solution "HelloWorld"
do
    configurations { "Debug", "Release" }
end

project "HelloWorld"
do
    kind "ConsoleApp"
    --language "C"
    language "C++"
    targetdir "build/%{cfg.buildcfg}"

    files { "**.h", "**.cpp" }

    filter "configurations:Debug"
    do
        defines { "DEBUG" }
        flags { "Symbols" }
    end

    filter "configurations:Release"
    do
        defines { "NDEBUG" }
        optimize "On"
    end
end
+ HelloWorld
  + .gitignore
  + hello.c
  + premake5.lua
  + premake5.exe
  + vc2013.bat
  + build
     + HelloWorld.sln
     + HelloWorld.vcxproj
     + Debug
        + HelloWorld.exe
     + Release
        + HelloWorld.exe
  • make의 clean과 비슷한 방법으로 premake5 clean 을 사용하면 build 디렉토리가 삭제된다

실용적인 예

  • sln, vcxproj 등의 출력 디렉터리를_build_premake에 격리
  • 32bit, 64bit의 2종류
  • Debug, Release의 2종류
  • 성과물(exe, dll)의 출력을_build_premake/Win64_Release 라는 식으로 지정
  • 출력 디렉터리를 나눈 것으로 라이브러리 이름에_d 같은 서픽스는 붙이지 않는다

premake5.lua

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

솔루션과 프로젝트를 나눈다

-- premake5.lua
location "build"

solution "HelloWorld"
do
    configurations { "Debug", "Release" }
end

-- 서브 디렉토리의 premake5.lua 에 기술된 Project를 읽는다
include "src"
-- src/premake5.lua
project "HelloWorld"
do
    kind "ConsoleApp"
    --language "C"
    language "C++"
    targetdir "build/%{cfg.buildcfg}"

    files { "**.h", "**.cpp" }

    filter "configurations:Debug"
    do
        defines { "DEBUG" }
        flags { "Symbols" }
    end

    filter "configurations:Release"
    do
        defines { "NDEBUG" }
        optimize "On"
    end
end
+ HelloWorld
  + .gitignore
  + src
      + premake5.lua
      + hello.cpp
  + premake5.lua
  + premake5.exe
  + vc2013.bat
  + build
     + HelloWorld.sln
     + HelloWorld.vcxproj
     + Debug
        + HelloWorld.exe
     + Release
        + HelloWorld.exe

Filter로 Debug, Release와 win32, win64 라는 4개 패턴의 프로젝트

-- premake5.lua
location "build"

solution "HelloWorld"
do
    configurations { "Debug", "Release" }
    platforms { "Win32", "Win64" }
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 "src"
</pre>
<pre>
-- src/premake5.lua
-- targetdir이 빠진 부분

project "HelloWorld"
do
    kind "ConsoleApp"
    --language "C"
    language "C++"

    files { "**.h", "**.cpp" }

    filter "configurations:Debug"
    do
        defines { "DEBUG" }
        flags { "Symbols" }
    end

    filter "configurations:Release"
    do
        defines { "NDEBUG" }
        optimize "On"
    end
end
</pre>
<pre>
+ HelloWorld
  + .gitignore
  + src
      + premake5.lua
      + hello.cpp
  + premake5.lua
  + premake5.exe
  + vc2013.bat
  + build
     + HelloWorld.sln
     + HelloWorld.vcxproj
     + Win32
       + Debug
         + HelloWorld.exe
       + Release
         + HelloWorld.exe
     + Win64
       + Debug
         + HelloWorld.exe
       + Release
         + HelloWorld.exe

외부 헤더 파일과 lib 파일 참조하는 프로젝트

-- premake4.lua
solution "SampleSolution"
   configurations { "Debug", "Release" }

   -- A project defines one build target
   project "SampleProject"
      kind "WindowedApp"
      language "C++"
      files { "**.h", "**.cpp" }

      includedirs { -- -I/usr/include/openglに相当
        "/usr/include/opengl"
      }
      libdirs { -- -L/usr/lib/w32apiに相当
        "/usr/lib/w32api"
      }
      links { -- -lopengl32 -lglu32 -lglut32 に相当
        "opengl32", "glu32", "glut32"
      }

      configuration "Debug"
         defines { "DEBUG" } -- -DDEBUG
         flags { "Symbols" }
         targetname "sample_debug"

      configuration "Release"
         defines { "NDEBUG" } -- -NDEBUG
         flags { "Optimize" }
         targetname "sample"

premake5.lua

solution "TestModule"
    location "../../"
    configurations{ "Debug", "Release" }
    platforms{ "x64", "x86" }


project "TestModule"
    location "../../build"
    configurations{ "Debug", "Release" }
    platforms{ "x64", "x86" }
    kind "SharedLib"
    language "C++"
    targetdir "../../build/VisualEffectsEditor/"
    characterset("MBCS")

    includedirs{
        "../include/",
        "../../common/include"
    }

    files{
        "../src/**.*",
        "../include/**.h",
    }

       postbuildcommands{}

filter { "platforms:x64", "configurations:Debug" }
    targetsuffix "d"
    defines{ "DEBUG" }
    flags{ "Symbols" }

filter { "platforms:x64", "configurations:Release" }
    defines{ "NDEBUG" }
    flags{ "Optimize" }

filter{ "platforms:x86", "configurations:Debug" }
    targetsuffix "d"
    defines{ "DEBUG" }
    flags{ "Symbols" }

filter{ "platforms:x86", "configurations:Release" }
    defines{ "NDEBUG" }
    flags{ "Optimize" }

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"
-- zlib-1.2.8/premake5.lua
project "zlib"
do
    kind "StaticLib"
    language "C"
    --language "C++"

    files { "*.h", "*.c" }
end
</pre>
<pre>
-- 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)

  • premake5.lua 에 기술
-- buildoptions { "/wd4996" } 다음 행쯤에
flags { "StaticRuntime" }

서식

-- premake5.lua
location "build"

solution "sample"
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 "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"

project "sample"
do
    kind "ConsoleApp"
    --kind "WindowedApp"
    --kind "StaticLib"
    --kind "SharedLib"
    --language "C"
    language "C++"

    flags{
        --"WinMain"
    }
    files { "*.h", "*.cpp" }
    includedirs {}
    defines {
        "WIN32",
        "_WINDOWS",
    }
    buildoptions { "/wd4996" }
    libdirs {}
    links {}
end

어느 lua 파일이 있는 경우만 설정을 추가한다

local.lua

local p = premake
p.override(p.vstudio.vc2010.elements, "user", function(base, cfg)
    -- configurations 마다 호출된다.
    local calls = base(cfg)

    -- \ 을 그대로 출력하고 싶으므로 [[ ]] 로 문자열 설정
    p.x([[<RemoteDebuggerCommand>\\192.168.0.1\$(TargetFileName)</RemoteDebuggerCommand>]])
    p.x([[<RemoteDebuggerServerName>192.168.0.1</RemoteDebuggerServerName>]])
    p.x([[<DebuggerFlavor>WindowsRemoteDebugger</DebuggerFlavor>]])

    -- return calls
end)

-- 빌드 후 이벤트로 실행 파일을 복사
filter "configurations:*"
  postbuildcommands { [[xcopy "$(Configuration)" "\\192.168.0.1\" /Y /Q]] }
filter {}

premake5.lua

workspace "sample"
  location "build_premake"
  configurations { "Debug", "Release" }

  project "sample"
    kind            "ConsoleApp"
    language        "C++"
    targetdir       "build_premake/%{cfg.buildcfg}"
    files           { "src/**.h", "src/**.cpp", }
    -- 일단 필터 정리
    filter {}

    -- local.lua 파일이 있다면 읽어서 실행
    local fh = io.open("local.lua", "rb")
    if fh then
      fh:close()
      includeexternal("local.lua")
    end

외부 프로젝트 추가

premake5.lua

workspace "sample"
  location "build_premake"
  configurations { "Debug", "Release" }

  externalproject "sampleLib"                        -- 외부 프로젝트
    location "../sampleLib/build_premake/"           -- 상대 패스로 .vcxproj가 있는 디렉토리 지정
    kind     "StaticLib"
    language "C++"

  project "sample"
    kind            "ConsoleApp"                     -- .lib은 "StaticLib"、.dll은 "SharedLib"
    language        "C++"
    targetdir       "build_premake/%{cfg.buildcfg}"  -- %{cfg.buildcfg}는 Debug or Release
    defines         { "NOMINMAX" }                   -- 프리프로세서
    disablewarnings { "4100", "4200" }               -- C4100,C4200 경고를 표시하지 않도록

    files           { "src/**.h", "src/**.cpp", }
    includedirs     { "include" }                    -- 추가 인크루드 디렉토리

    --libdirs       { "lib" }                        -- 추가 라이브러리 디렉토리(필요하다면)
    --links         { "hoge.lib" }                   -- 추가 의존 파일(필요하다면)
    links           { "sampleLib" }                  -- 외부 프로젝트와 링크

    filter "configurations:Debug"                    -- 아래의 Debug 설정
      targetsuffix  "_d"                             -- exe 파일의 서픽스(sample_d.exe 처럼 된다)
      defines       { "DEBUG" }
      flags         { "Symbols" }                    -- 심볼 작성 정보
      optimize      "OFF"                            -- 최적화 없음

    filter "configurations:Release"                  -- 아래의 Release 설정
      optimize      "Speed"                          -- 속도 중시로 최적화
    filter {}                                        -- 필터 클리어

정적 라이브러리를 만들 때 외부 라이브러리를 포함하고 있다면

premake5.lua

local p = premake
function myAdditionalStaticDependencies(cfg)
    -- **.lib 같은 것만 추가
    local links = p.config.getlinks(cfg, "system", "fullpath")
    if #links > 0 then
        links = path.translate(table.concat(links, ";"))
        p.x('<AdditionalDependencies>%s;%%(AdditionalDependencies)</AdditionalDependencies>', links)
    end

    local dirs = p.config.getlinks(cfg, "system", "directory")
    if #dirs > 0 then
        dirs = path.translate(table.concat(dirs, ";"))
        p.x('<AdditionalLibraryDirectories>%s;</AdditionalLibraryDirectories>', dirs)
    end

end
p.override(p.vstudio.vc2010.elements, "lib", function(base, cfg, explicit)
    local calls = base(cfg, explicit)
    if cfg.kind == p.STATICLIB then
        table.insert(calls, myAdditionalStaticDependencies)
    end
    return calls
end)

-- 아래가 빌드 정의
workspace "sample"
  location "build_premake"
  configurations { "Debug", "Release" }

  project "sampleLib"
    kind            "StaticLib"                      -- .lib 파일을 만든다
    language        "C++"
    targetdir       "build_premake/%{cfg.buildcfg}"
    files           { "src/**.h", "src/**.cpp", }

    libdirs         { "lib" }                        -- 추가 라이브러리 디렉토리
    links           { "additional.lib" }             -- 라이브러리 > 추가 의존 파일에 additional.lib 이 추가된다

WPF 프로젝트

premake5.lua

solution "TestEditor"
    configurations{ "Debug", "Release" }
    platforms{ "x64", "x86" }
    startproject "TestEditor"
    location "../../"

project "TestEditor"
    platforms{"x64", "x86"}
    location "../../build"
    kind "WindowedApp"
    language "C#"
    flags {"WPF"}
    icon ("../Resource/vfx_icon.ico")
    targetdir "../../build/VisualEffectsEditor/"

    files {
        "../App.config",
        "../**.xaml",
        "../**.cs",
        "../**.ico"
    }

    excludes{
        "../obj/**"
    }

    links ("Microsoft.Csharp")
    links ("PresentationCore")
    links ("PresentationFramework")
    links ("System")
    links ("System.Core")
    links ("System.Data")
    links ("System.Data.DataSetExtensions")
    links ("System.Xaml")
    links ("System.Xml")
    links ("System.Xml.Linq")
    links ("System.Windows.Forms")
    links ("WindowsBase")

    configuration "**.ico"
        buildaction "Resource"

    configuration "Debug"
    do
        flags{ "Symbols" }
    end

    configuration "Release"
    do
        flags{ "Optimize" }
    end

dependson("TestModule")


external("TestModule")
    location "../../build"
    kind "SharedLib"
    language "C++"
    configmap{
        ["Debug"] = "Debug",
        ["Release"] = "Release",
    }

참고


이 글은 2019-04-29에 작성되었습니다.