1、premake5介绍
Premake :https://github.com/premake/premake-core
使用 Premake,开发者可以通过编写简单的 Lua 脚本来描述项目的结构和构建选项。Premake 会根据这些脚本生成特定平台(如 Windows、Linux、Mac 等)的项目文件和构建脚本,例如 Visual Studio 的 .sln 文件、Makefile 或 Xcode 的 .xcodeproj 文件等。
下载最新的windows release版本,不需要自己编译
解压后,只需要其中的premake.exe文件,放在项目路径中
完整的使用教学可以参考wiki
-
tokens,列出了所有预定义的变量,供我们使用,用法类似于vs中项目设置里的宏(ProjectDir 、SolutionDir、ProjecName等等),不同的地方是vs中取值用
$()
,premake中用%{}
-
postbuildcommants,可以使用编译后命令来复制文件(如.dll)到.exe文件目录下
这是wiki的第一个premake使用示例
/* hello.c */
#include <stdio.h>
int main(void) {
puts("Hello, world!");
return 0;
}
在项目中创建一个文件 premake5.lua
workspace "HelloWorld" -- 解决方案名称
configurations { "Debug", "Release" }
project "HelloWorld"
kind "ConsoleApp" -- 项目类型为可执行程序
language "C"
targetdir "bin/%{cfg.buildcfg}" -- 编译输出路径
files { "**.h", "**.c" } -- 所有子文件夹中的所有.h .c文件,递归抓取
filter "configurations:Debug" -- 针对debug和release配置下的一些特定的设置
defines { "DEBUG" } -- 预定义的宏
symbols "On"
filter "configurations:Release"
defines { "NDEBUG" }
optimize "On"
2、案例1
所有项目用一个位于解决方案目录的premake5.lua脚本进行维护
假设解决方案名称为MySolution,其中有两个项目,第一个MyProject1 是生成动态链接库供第二个项目MyApp使用
workspace "MySolution" -- 解决方案名称
architecture "x64"
configurations
{
"Debug",
"Release",
"Dist"
}
-- 输出路径变量:结构类似于 debug-windows-x64
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.arcchitecture}"
project "MyProject1" -- 项目名称
location "MyProject1"
kind "SharedLib" -- DLL
language "C++"
targetdir ("bin/" .. outputdir .. "/%{prj.name}") -- lua的字符串拼接方式 ..
objdir ("bin-int/" .. outputdir .. "/%{prj.name}") -- 编译中间产物存放路径
files -- 包含项目下所有的.h .cpp文件
{
"%{prj.name}/src/**.h",
"%{prj.name}/src/**.cpp"
}
include
{
"%{prj.name}/3rd/glfw/include"
}
filter "system:windows" --对特定的系统(windows、OS..)、配置(Debug/Release)、平台(x64、x86)的项目属性
cppdialect "C++17" --C++特性版本
staticruntime "On"
systemversion "10.0.22000.0" -- windows SKD版本
defines
{
"PLATFORM_WINDOWS",
"BUILD_DLL"
}
postbuildcommands -- 后构建命令,构建完毕后执行的操作
{
-- 拷贝本项目输出文件中的dll到指定文件夹中
("{COPY} %{cfg.buildtarget.relpath} ../bin/" .. outputdir .. "/MyApp")
}
filter "configurations:Debug"
defines "_DEBUG"
symbols "On"
filter "configurations:Release"
defines "_RELEASE"
optimize "On"
filter "configurations:Dist"
defines "_DIST"
optimize "On"
-- 可以过滤多个选项,一起配置
-- filter {"system:windows", "configurations:Release"}
-- buildoptions "/MT"
project "MyApp"
location "Sandbox"
kind "ConsoleApp"
language "C++"
targetdir ("bin/" .. outputdir .. "/%{prj.name}")
objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
files -- 参与编译的文件
{
"%{prj.name}/src/**.h",
"%{prj.name}/src/**.cpp"
}
include
{
"%{prj.name}/vendor/spdlog/include",
"MyProject1/src"
}
links --链接库
{
"MyProject1"
}
filter "system:windows"
cppdialect "C++17"
staticruntime "On"
systemversion "10.0.22000.0"
defines
{
"PLATFORM_WINDOWS"
}
filter "configurations:Debug"
defines "_DEBUG"
symbols "On"
filter "configurations:Release"
defines "_RELEASE"
optimize "On"
filter "configurations:Dist"
defines "_DIST"
optimize "On"
之后在解决方案路径下打开CMD,输入 call premake5.exe vs2022
即可。
- premake5.exe如果不在同一路径下,则在前面加上它的相对路径如:
call premake/premake.exe vs2022;
- 目标vs版本可以自己选择
说明:
(
和)
:这是Lua编程语言中用于创建一个包含多个元素的表(table)的语法。在这里,括号内的内容表示一个表,里面包含了一个要执行的命令。"....."
: 这是Lua中的字符串,如"… outputdir …" 表示把引号之间的内容变成字符串,并与两边的字符串相连{COPY}
: 这是一个占位符,通常在构建系统中用于表示某种特定的操作。在这里,它表示复制操作。%{cfg.buildtarget.relpath}
: 这是一个用于获取构建目标的相对路径的变量。cfg
是一个表示当前配置的变量,buildtarget
表示构建目标(编译生成的文件),relpath
表示相对路径。所以这个表达式会被替换为构建目标的相对路径。../bin/
… outputdir … “/MyApp”: 这是构建目标的输出路径。../bin/
表示输出目录的上一级目录,outputdir
是一个变量,表示构建时指定的输出目录(可能是Debug或Release等),"/MyApp"
则是输出文件的名称和路径。
3、案例2
如果还需要链接其他库,可以在解决方案目录的premake脚本里继续添加库项目,但是更好的处理大型项目(包含多个子项目)的方式是采用一定的组织和规划。当项目结构变得更复杂时,你可以考虑将每个子项目都单独创建一个premake脚本来维护,然后在顶级解决方案的premake脚本中引用它们。这种方法可以帮助你更好地组织和管理项目。
项目结构如下:
mySolution/
myApp/
src/
include/
premake5.lua -- myApp 的 Premake 脚本
mylib1/
src/
include/
premake5.lua -- mylib1 的 Premake 脚本
mylib2/
src/
include/
premake5.lua -- mylib2 的 Premake 脚本
在顶级解决方案的premake脚本(例如,MySolution/premake5.lua)中,你可以引用每个子项目的premake脚本,如下所示:
-- 配置解决方案名称
solution "MySolution" -- 在visual studio中solution和workspace是一个意思
-- 配置全局设置,如构建类型、目标目录等
configurations { "Debug", "Release" }
targetdir ("bin/%{cfg.buildcfg}")
-- 包括 myApp 项目的配置
dofile("myApp/premake5.lua")
-- 包括 mylib1 项目的配置
dofile("mylib1/premake5.lua")
-- 包括 mylib2 项目的配置
dofile("mylib2/premake5.lua")
-- 可以在解决方案级别添加全局配置
接下来,你可以为每个子项目创建单独的Premake脚本,以定义项目的构建配置。例如,myApp/premake5.lua 可能如下所示:
-- 定义 myApp 项目
project "myApp"
location "myApp"
kind "ConsoleApp"
language "C++"
-- myApp 项目的源文件和头文件
files
{
"src/**.cpp",
"include/**.h"
}
-- 包括子项目的头文件目录
includedirs
{
"../mylib1/include",
"../mylib2/include"
}
-- 链接子项目(mylib1 和 mylib2)
links
{
"mylib1",
"mylib2"
}
-- 配置编译选项、链接选项等
类似地,你可以在每个子项目的premake脚本中定义项目的构建配置。
通过将每个子项目都单独维护其自己的premake脚本,然后在顶级解决方案的premake脚本中引用它们,你可以更好地组织和管理项目的配置,特别是在项目结构变得更加复杂时。这种方法允许你将每个项目的配置独立管理,从而提高了可维护性。