Files
ygopro/premake5.lua
Mercury233 3734faa3ad Upgrade Premake from v5.0.0-beta8 to the stable v5.0.0 release (#3176)
* upgrade premake from v5.0.0-beta8 to v5.0.0

* include local fixed in premake5 stable
2026-10-09 09:07:01 +08:00

535 lines
21 KiB
Lua

----- YGOPro build configuration script using Premake5
--- Supported systems: Windows, Linux, macOS
-- Windows (Visual Studio) build supports x86, x86_64, and ARM64, with cross-compilation support.
-- Linux build supports x86_64 and ARM64.
-- macOS build supports x86_64 and ARM64, with cross-compilation support.
---- Global settings
--- Use global variables to share settings across different scripts.
USE_DXSDK = true
USE_AUDIO = true
AUDIO_LIB = "miniaudio" -- only miniaudio is supported for now
-- Available: none, sse2, avx2, neon, best
-- "best" means avx2 on x86-* and neon on ARM
USE_SIMD = "best"
-- On Linux and macOS, builds target the current machine's CPU architecture by default, but Premake needs an explicit
-- architecture for the corresponding filters to take effect, so use os.hostarch() to detect it.
HOST_ARCH = os.hostarch()
-- Return val if it's not nil; otherwise, return default.
local function ifnil(val, default)
if val ~= nil then
return val
else
return default
end
end
---- Dependency settings
--- When building dependencies from source, the corresponding source code must be placed in the corresponding location
--- in the project folder (local), with the folder name fixed as the dependency name and the folder structure fixed as
--- the official source package extraction.
---
--- Some dependencies need extra configuration (run configure scripts, copy or rename files), see the documentation or
--- the CI workflow script for details.
-- On Windows, build all dependencies from source by default.
-- On Linux/macOS, most dependencies should be installed via the package manager.
BUILD_ALL_FROM_SOURCE = os.istarget("windows")
-- Build Lua from source by default:
-- Most package managers provide Lua compiled as C, but ocgcore requires Lua compiled as C++.
-- Some package managers do provide lua-c++ variants (e.g. liblua5.4-c++.so), which can be specified manually.
BUILD_LUA = true
-- Modified Irrlicht is required; the official version from package managers lacks proper CJK support
-- (clipboard and IME). Also, Irrlicht's bundled jpeglib/libpng/zlib/lzma are not used here.
BUILD_IRRLICHT = true
-- miniaudio is always built from source (originally a header-only library, now an independent subproject).
-- When building Opus/Vorbis from source, they are integrated directly into the miniaudio subproject.
-- To simplify the build process, support for Ogg format audio (Opus/Vorbis) is optional.
MINIAUDIO_SUPPORT_OPUS_VORBIS = true
MINIAUDIO_INCLUDE_DIR = path.getabsolute("./miniaudio")
MINIAUDIO_OPUS_INCLUDE_DIR = path.getabsolute("./miniaudio/extras/decoders/libopus")
MINIAUDIO_VORBIS_INCLUDE_DIR = path.getabsolute("./miniaudio/extras/decoders/libvorbis")
-- When building freetype, a custom include dir is prepended to prioritize custom header files.
FREETYPE_CUSTOM_INCLUDE_DIR = path.getabsolute("./freetype/custom")
-- When building libevent from source, event_pthreads is integrated into the event subproject.
-- When not building from source, both "event" and "event_pthreads" need to be linked.
EVENT_PTHREADS_LIB_NAME = "event_pthreads"
-- When building Vorbis from source, vorbisfile is integrated into the miniaudio subproject.
-- When not building from source, both "vorbis" and "vorbisfile" need to be linked.
VORBISFILE_LIB_NAME = "vorbisfile"
--- Dependency metadata entries are used to generate global variables such as LUA_INCLUDE_DIR, LUA_LIB_NAME, LUA_LIB_DIR, etc. during processing.
-- Fields:
-- name (will resolve to global variable prefix)
-- prebuilt_header (for finding directory)
-- prebuilt_header_subdir (for dependencies which require a subdirectory in the compiler's include path)
-- prebuilt_libname (for prebuilt dependencies only; default: same as name)
-- source_dir (when building dependency from source, its code should be in this directory relative to the project root; default: ./name)
-- source_header_subdir (dependency's header subdirectory relative to source_dir; default: .)
DEPENDENCIES_METADATA = {
{
name = "lua",
prebuilt_header = "lua.h",
source_header_subdir = "src",
},
{
name = "event",
prebuilt_header = "event2/event.h",
source_header_subdir = "include",
},
{
name = "freetype",
prebuilt_header = "ft2build.h",
prebuilt_header_subdir = "freetype2",
source_header_subdir = "include",
},
{
name = "sqlite",
prebuilt_header = "sqlite3.h",
prebuilt_libname = "sqlite3",
source_dir = "sqlite3",
},
{
name = "irrlicht",
prebuilt_header = "irrlicht.h",
source_header_subdir = "include",
},
{
name = "jpeg",
prebuilt_header = "jpeglib.h",
source_header_subdir = "src",
},
{
name = "png",
prebuilt_header = "png.h",
},
{
name = "lzma",
prebuilt_header = "lzma.h",
source_header_subdir = "src/liblzma/api",
},
{
name = "zlib",
prebuilt_header = "zlib.h",
prebuilt_libname = "z",
},
}
-- These dependencies do not have separate [no-]build-* options; instead, they use [no-]build-opus-vorbis as general build option.
-- When building from source, they are integrated into the miniaudio subproject instead of being maintained as separate subprojects,
-- and their locations are predefined in the miniaudio subproject (./miniaudio/external/*), so those options are ignored in this case.
MINIAUDIO_DEPENDENCIES_METADATA = {
{
name = "opus",
prebuilt_header = "opus.h",
prebuilt_header_subdir = "opus",
},
{
name = "opusfile",
prebuilt_header = "opusfile.h",
prebuilt_header_subdir = "opus",
},
{
name = "vorbis",
prebuilt_header = "vorbis/vorbisfile.h",
},
{
name = "ogg",
prebuilt_header = "ogg/ogg.h",
},
}
---- Register options
--- The *-include-dir, *-lib-dir, and *-lib-name options are only used for prebuilt dependencies.
--- These options are ignored when building from source.
---
--- For *-lib-name option: Most users don't need to set it, as the script already provides conventional values.
--- The only known case where setting it is necessary is when using prebuilt lua-c++, where the lib name must be specified.
--- Platform-specific notes:
---
--- Windows: Prebuilt support is incomplete (static lib, dynamic lib, debug-specific lib to be refined).
---
--- Linux: The script already attempts to automatically locate include and lib paths for prebuilt dependencies.
--- In most cases, you should not need to manually specify parameters.
--- If a package is not found, please specify it manually. In this case, if you installed it from a well-known package manager,
--- please consider reporting the issue.
---
--- macOS: When using Homebrew, use `DYLD_LIBRARY_PATH=$(brew --prefix)/lib` to ensure Homebrew installation paths are found.
--- Note: macOS/Xcode already provides "system" versions of sqlite and zlib; Homebrew treats those packages as "keg-only"
--- and won't install them to common directories. You must manually specify paths to use Homebrew-installed versions.
--- Parameters are read from premake options (priority) and environment variables.
--- Environment variable names are uppercase versions with hyphens replaced by underscores.
---
--- Note on default values: Default values should be defined at the top of the script, not as premake option defaults;
--- otherwise, the premake option default will always take priority over environment variables.
for _, dep in ipairs(DEPENDENCIES_METADATA) do
local name = dep.name
local cat = "YGOPro - " .. name
local build = ifnil(_G["BUILD_" .. string.upper(name)], BUILD_ALL_FROM_SOURCE)
newoption { trigger = "build-" .. name, category = cat, description = "Build " .. name .. " from source; default: " .. tostring(build) }
newoption { trigger = "no-build-" .. name, category = cat, description = "" }
newoption { trigger = name .. "-include-dir", category = cat, description = "", value = "PATH" }
newoption { trigger = name .. "-lib-dir", category = cat, description = "", value = "PATH" }
newoption { trigger = name .. "-lib-name", category = cat, description = "", value = "NAME" }
end
for _, dep in ipairs(MINIAUDIO_DEPENDENCIES_METADATA) do
local name = dep.name
local cat = "YGOPro - miniaudio"
newoption { trigger = name .. "-include-dir", category = cat, description = "", value = "PATH" }
newoption { trigger = name .. "-lib-dir", category = cat, description = "", value = "PATH" }
newoption { trigger = name .. "-lib-name", category = cat, description = "", value = "NAME" }
end
newoption { trigger = "build-all", category = "YGOPro", description = "Build all dependencies from source" }
newoption { trigger = "no-dxsdk", category = "YGOPro - irrlicht", description = "Do not use DirectX SDK, disable D3D9 support" }
newoption { trigger = "no-audio", category = "YGOPro", description = "Disable audio support" }
newoption { trigger = "audio-lib", category = "YGOPro", description = "Specify audio library (only miniaudio is supported for now)", value = "NAME" }
newoption { trigger = "miniaudio-support-opus-vorbis", category = "YGOPro - miniaudio", description = "Enable support for OGG format (Opus and Vorbis) in miniaudio" }
newoption { trigger = "no-miniaudio-support-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
do
local build_opus_vorbis = ifnil(_G["BUILD_OPUS_VORBIS"], BUILD_ALL_FROM_SOURCE)
newoption { trigger = "build-opus-vorbis", category = "YGOPro - miniaudio", description = "Build Opus and Vorbis libraries from source; default: " .. tostring(build_opus_vorbis) }
newoption { trigger = "no-build-opus-vorbis", category = "YGOPro - miniaudio", description = "" }
end
newoption { trigger = "vs2026-win7-support", category = "YGOPro", description = "Enable Windows 7 support (toolset v143) for Visual Studio 2026" }
newoption { trigger = "mac-arm", category = "YGOPro", description = "Cross Compile for Apple Silicon Mac" }
newoption { trigger = "mac-intel", category = "YGOPro", description = "Cross Compile for Intel Mac" }
newoption { trigger = "use-openmp", category = "YGOPro", description = "Enable OpenMP support for card picture resizing (only for benchmarking)" }
newoption { trigger = "use-simd", category = "YGOPro", description = "Specify SIMD instruction set", allowed = {
{ "none", "Turn off extra SIMD support" },
{ "sse2", "Use SSE2 instructions" },
{ "avx2", "Use AVX2 instructions" },
{ "neon", "Use NEON instructions" },
{ "best", "Default, use the best SIMD instructions (AVX2 on x86-*, NEON on ARM)" },
}}
---- Process options
-- Read settings from command line or environment variables.
-- Command-line options take priority over environment variables.
local function GetParam(param)
return ifnil(_OPTIONS[param], os.getenv(string.upper(string.gsub(param,"-","_"))))
end
local function ResolveDirectoryVariableToFullPath(varname)
local dir = _G[varname]
if not dir or dir == "" then
print("::warning:: " .. varname .. " is not set")
return
elseif not os.isdir(dir) then
print("::warning:: " .. varname .. " is not a valid directory: " .. dir)
return
end
_G[varname] = path.getabsolute(dir)
end
-- Set dependency directories from command line or environment variables, and check their validity.
local function ResolvePreBuiltDependencyDirectory(dep)
local upper = string.upper(dep.name)
local include_dir_var = upper .. "_INCLUDE_DIR"
local lib_name_var = upper .. "_LIB_NAME"
local lib_dir_var = upper .. "_LIB_DIR"
_G[include_dir_var] = GetParam(dep.name .. "-include-dir")
if not _G[include_dir_var] then
if dep.prebuilt_header_subdir then
_G[include_dir_var] = os.findsubdirheader(dep.prebuilt_header, dep.prebuilt_header_subdir)
else
_G[include_dir_var] = os.findheader(dep.prebuilt_header)
end
end
_G[lib_name_var] = GetParam(dep.name .. "-lib-name") or dep.prebuilt_libname or dep.name
_G[lib_dir_var] = GetParam(dep.name .. "-lib-dir") or os.findlib(_G[lib_name_var])
ResolveDirectoryVariableToFullPath(include_dir_var)
ResolveDirectoryVariableToFullPath(lib_dir_var)
end
-- Set the include directory for a dependency being built from source, and validate its path.
local function ResolveBuildFromSourceDependencyDirectory(dep)
local upper = string.upper(dep.name)
local include_dir_var = upper .. "_INCLUDE_DIR"
local source_dir = dep.source_dir or ("./" .. dep.name)
local source_header_subdir = dep.source_header_subdir or "."
_G[include_dir_var] = path.join(source_dir, source_header_subdir)
ResolveDirectoryVariableToFullPath(include_dir_var)
end
if GetParam("build-all") then
BUILD_ALL_FROM_SOURCE = true
end
-- Process build flags and external directory settings for all library dependencies.
for _, dep in ipairs(DEPENDENCIES_METADATA) do
local name = dep.name
local upper = string.upper(name)
local flag = "BUILD_" .. upper
local build = ifnil(_G[flag], BUILD_ALL_FROM_SOURCE)
if GetParam("no-build-" .. name) then
build = false
elseif GetParam("build-" .. name) then
build = true
end
_G[flag] = build
if build then
ResolveBuildFromSourceDependencyDirectory(dep)
else
ResolvePreBuiltDependencyDirectory(dep)
end
end
if GetParam("no-dxsdk") then
USE_DXSDK = false
end
if USE_DXSDK and os.istarget("windows") then
if not os.getenv("DXSDK_DIR") then
print("::warning:: DXSDK_DIR environment variable not set, it seems you don't have the DirectX SDK installed. DirectX mode will be disabled.")
USE_DXSDK = false
end
end
if GetParam("no-audio") then
USE_AUDIO = false
end
if USE_AUDIO then
AUDIO_LIB = GetParam("audio-lib") or AUDIO_LIB
if AUDIO_LIB == "miniaudio" then
if GetParam("no-miniaudio-support-opus-vorbis") then
MINIAUDIO_SUPPORT_OPUS_VORBIS = false
elseif GetParam("miniaudio-support-opus-vorbis") then
MINIAUDIO_SUPPORT_OPUS_VORBIS = true
end
if MINIAUDIO_SUPPORT_OPUS_VORBIS then
MINIAUDIO_BUILD_OPUS_VORBIS = BUILD_ALL_FROM_SOURCE
if GetParam("no-build-opus-vorbis") then
MINIAUDIO_BUILD_OPUS_VORBIS = false
elseif GetParam("build-opus-vorbis") then
MINIAUDIO_BUILD_OPUS_VORBIS = true
end
if MINIAUDIO_BUILD_OPUS_VORBIS then
-- Opus, Vorbis and Ogg dependencies are integrated into the miniaudio subproject instead of being maintained as separate subprojects.
-- Since their locations are predefined in the miniaudio subproject, nothing needs to be done here.
else
for _, dep in ipairs(MINIAUDIO_DEPENDENCIES_METADATA) do
ResolvePreBuiltDependencyDirectory(dep)
end
end
end
else
error("Unknown audio library: " .. AUDIO_LIB)
end
end
USE_SIMD = GetParam("use-simd") or USE_SIMD
-- Variables indicating the target Mac architecture for cross-compilation; automatically detected based on Premake's
-- host architecture if neither --mac-arm nor --mac-intel is specified.
local mac_arm = false
local mac_intel = false
if os.istarget("macosx") then
if GetParam("mac-arm") then
mac_arm = true
end
if GetParam("mac-intel") then
mac_intel = true
end
end
if not mac_arm and not mac_intel and table.indexof({ "x86", "x86_64", "ARM64" }, HOST_ARCH) == nil then
print("::warning:: Detected architecture '" .. HOST_ARCH .. "' is not recognized. Proceeding with the build; SIMD will be disabled.")
USE_SIMD = "none"
end
-- Normalize "avx2" and "neon" to "best": downstream code only checks "best",
-- which already maps to AVX2 on x86-* and NEON on ARM.
if USE_SIMD == "avx2" or USE_SIMD == "neon" then
USE_SIMD = "best"
end
if os.istarget("windows") and GetParam("vs2026-win7-support") then
WIN7_SUPPORT = true
end
if GetParam("use-openmp") then
USE_OPENMP = true
if os.istarget("macosx") then
print("::warning:: OpenMP is not supported on Clang provided by Xcode.")
end
end
---- Premake workspace and project configuration
workspace "YGOPro"
location "build"
language "C++"
objdir "obj"
configurations { "Release", "Debug" }
defaultconfiguration "Release"
filter "system:windows"
systemversion "latest"
startproject "YGOPro"
-- Target Windows 7 or later. (Building requires Windows 10 SDK 1803 or newer.)
defines { "WINVER=0x0601", "_WIN32_WINNT=0x0601" }
if WIN7_SUPPORT then
filter { "system:windows", "action:vs2026" }
toolset "v143"
end
filter { "system:windows", "action:vs*" }
platforms { "Win32", "x64", "ARM64" }
defaultplatform "x64"
filter { "system:windows", "action:vs*", "platforms:Win32" }
architecture "x86"
if USE_SIMD == "none" then
vectorextensions "IA32"
end
if USE_SIMD == "sse2" then
vectorextensions "SSE2"
end
if USE_SIMD == "best" then
vectorextensions "AVX2"
end
filter { "system:windows", "action:vs*", "platforms:x64" }
architecture "x86_64"
-- x86_64 must have SSE2, so we shouldn't check USE_SIMD for SSE2
if USE_SIMD == "best" then
vectorextensions "AVX2"
end
filter { "system:windows", "action:vs*", "platforms:ARM64" }
architecture "AARCH64"
filter "system:macosx"
systemversion "11"
if mac_arm and mac_intel then
print("::warning:: Universal binary is no longer supported. Please choose either --mac-arm or --mac-intel and combine the binaries with lipo manually.")
mac_arm = false
mac_intel = false
end
if not mac_arm and not mac_intel then
if HOST_ARCH == "ARM64" then
mac_arm = true
else
mac_intel = true
end
end
-- We need to specify architecture on macOS to make the premake filters work correctly.
if mac_arm then
architecture "AARCH64"
end
if mac_intel then
architecture "x86_64"
end
-- We need to specify architecture on Linux to make the premake filters work correctly.
filter "system:linux"
if HOST_ARCH == "ARM64" then
architecture "AARCH64"
else
architecture "x86_64"
end
filter "configurations:Release"
optimize "Speed"
targetdir "bin/release"
filter "configurations:Debug"
symbols "On"
defines "_DEBUG"
targetdir "bin/debug"
filter { "system:windows", "platforms:Win32", "configurations:Release" }
targetdir "bin/release/x86"
filter { "system:windows", "platforms:Win32", "configurations:Debug" }
targetdir "bin/debug/x86"
filter { "system:windows", "platforms:x64", "configurations:Release" }
targetdir "bin/release/x64"
filter { "system:windows", "platforms:x64", "configurations:Debug" }
targetdir "bin/debug/x64"
filter { "system:windows", "platforms:ARM64", "configurations:Release" }
targetdir "bin/release/arm64"
filter { "system:windows", "platforms:ARM64", "configurations:Debug" }
targetdir "bin/debug/arm64"
filter { "configurations:Release", "action:vs*" }
linktimeoptimization "On"
staticruntime "On"
disablewarnings {
"4996", -- Currently only some dependencies use deprecated functions.
}
filter { "configurations:Release", "not action:vs*" }
defines "NDEBUG"
filter "action:vs*"
cdialect "C11"
conformancemode "On"
buildoptions { "/utf-8" }
defines { "_CRT_SECURE_NO_WARNINGS" }
disablewarnings {
"4244", -- Intentional narrowing conversions are pervasive in the program and dependencies.
"4267", -- The 32-bit APIs frequently consume container sizes represented by size_t on 64-bit builds.
}
filter "action:gmake"
buildoptions { "-fno-strict-aliasing" }
filter { "action:gmake", "architecture:x86_64" }
if USE_SIMD == "best" then
vectorextensions "AVX2"
isaextensions { "FMA" }
end
filter {}
include "ocgcore"
include "gframe"
for _, dep in ipairs(DEPENDENCIES_METADATA) do
if _G["BUILD_" .. string.upper(dep.name)] then
-- Build dependency as subproject, using our pre-provided premake script (copy from the premake directory of the project before running premake)
include(dep.source_dir or dep.name)
end
end
if USE_AUDIO then
if AUDIO_LIB == "miniaudio" then
include "miniaudio"
end
end