483 lines
19 KiB
Lua
Executable File
483 lines
19 KiB
Lua
Executable File
-- Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
|
--
|
|
-- This software is provided 'as-is', without any express or implied
|
|
-- warranty. In no event will the authors be held liable for any damages
|
|
-- arising from the use of this software.
|
|
--
|
|
-- Permission is granted to anyone to use this software for any purpose,
|
|
-- including commercial applications, and to alter it and redistribute it
|
|
-- freely.
|
|
--
|
|
-- Meta-build system using premake created and maintained by
|
|
-- Benjamin Henning <b.henning@digipen.edu>
|
|
|
|
--[[
|
|
premake4.lua
|
|
|
|
This script sets up the entire premake system. It's responsible for executing
|
|
all of the definition scripts for the SDL2 library and the entire test suite,
|
|
or demos for the iOS platform. It handles each specific platform and uses the
|
|
setup state to generate both the configuration header file needed to build
|
|
SDL2 and the premake lua script to generate the target project files.
|
|
]]
|
|
|
|
-- string utility functions
|
|
dofile "util/sdl_string.lua"
|
|
-- utility file wrapper for some useful functions
|
|
dofile "util/sdl_file.lua"
|
|
-- system for defining SDL projects
|
|
dofile "util/sdl_projects.lua"
|
|
-- offers a utility function for finding dependencies specifically on windows
|
|
dofile "util/sdl_depends.lua"
|
|
-- system for generating a *config.h file used to build the SDL2 library
|
|
dofile "util/sdl_gen_config.lua"
|
|
-- functions to handle complicated dependency checks using CMake-esque functions
|
|
dofile "util/sdl_check_compile.lua"
|
|
-- a list of dependency functions for the SDL2 project and any other projects
|
|
dofile "util/sdl_dependency_checkers.lua"
|
|
|
|
-- the following are various options for configuring the meta-build system
|
|
newoption {
|
|
trigger = "to",
|
|
value = "path",
|
|
description = "Set the base output directory for the generated and executed lua file."
|
|
}
|
|
|
|
newoption {
|
|
trigger = "mingw",
|
|
description = "Runs the premake generation script targeted to MinGW."
|
|
}
|
|
|
|
newoption {
|
|
trigger = "cygwin",
|
|
description = "Runs the premake generation script targeted to Cygwin."
|
|
}
|
|
|
|
newoption {
|
|
trigger = "ios",
|
|
description = "Runs the premake generation script targeted to iOS."
|
|
}
|
|
|
|
-- determine the localized destination path
|
|
local baseLoc = "./"
|
|
if _OPTIONS["to"] then
|
|
baseLoc = _OPTIONS["to"]:gsub("\\", "/")
|
|
end
|
|
|
|
local deps = SDL_getDependencies()
|
|
for _,v in ipairs(deps) do
|
|
newoption {
|
|
trigger = v:lower(),
|
|
description = "Force on the dependency: " .. v
|
|
}
|
|
end
|
|
|
|
-- clean action
|
|
if _ACTION == "clean" then
|
|
-- this is kept the way it is because premake's default method of cleaning the
|
|
-- build tree is not very good standalone, whereas the following correctly
|
|
-- cleans every build option
|
|
print("Cleaning the build environment...")
|
|
os.rmdir(baseLoc .. "/SDL2")
|
|
os.rmdir(baseLoc .. "/SDL2main")
|
|
os.rmdir(baseLoc .. "/SDL2test")
|
|
os.rmdir(baseLoc .. "/tests")
|
|
os.rmdir(baseLoc .. "/Demos")
|
|
os.rmdir(baseLoc .. "/ipch") -- sometimes shows up
|
|
os.remove(baseLoc .. "/SDL.sln")
|
|
os.remove(baseLoc .. "/SDL.suo")
|
|
os.remove(baseLoc .. "/SDL.v11.suo")
|
|
os.remove(baseLoc .. "/SDL.sdf")
|
|
os.remove(baseLoc .. "/SDL.ncb")
|
|
os.remove(baseLoc .. "/SDL-gen.lua")
|
|
os.remove(baseLoc .. "/SDL_config_premake.h")
|
|
os.remove(baseLoc .. "/Makefile")
|
|
os.rmdir(baseLoc .. "/SDL.xcworkspace")
|
|
os.exit()
|
|
end
|
|
|
|
-- only run through standard execution if not in help mode
|
|
if _OPTIONS["help"] == nil then
|
|
-- load all of the project definitions
|
|
local results = os.matchfiles("projects/**.lua")
|
|
for _,dir in ipairs(results) do
|
|
dofile(dir)
|
|
end
|
|
|
|
-- figure out which configuration template to use
|
|
local premakeConfigHeader = baseLoc .. "/SDL_config_premake.h"
|
|
-- minimal configuration is the default
|
|
local premakeTemplateHeader = "./config/SDL_config_minimal.template.h"
|
|
if SDL_getos() == "windows" or SDL_getos() == "mingw" then
|
|
premakeTemplateHeader = "./config/SDL_config_windows.template.h"
|
|
elseif SDL_getos() == "macosx" then
|
|
premakeTemplateHeader = "./config/SDL_config_macosx.template.h"
|
|
elseif SDL_getos() == "ios" then
|
|
premakeTemplateHeader = "./config/SDL_config_iphoneos.template.h"
|
|
elseif os.get() == "linux" then
|
|
premakeTemplateHeader = "./config/SDL_config_linux.template.h"
|
|
elseif SDL_getos() == "cygwin" then
|
|
premakeTemplateHeader = "./config/SDL_config_cygwin.template.h"
|
|
end
|
|
|
|
local genFile = baseLoc .. "/SDL-gen.lua"
|
|
local file = fileopen(genFile, "w")
|
|
print("Generating " .. genFile .. "...")
|
|
-- begin generating the config header file
|
|
startGeneration(premakeConfigHeader, premakeTemplateHeader)
|
|
|
|
-- begin generating the actual premake script
|
|
file:print(0, "-- Premake script generated by Simple DirectMedia Layer meta-build script")
|
|
file:print(1, 'solution "SDL"')
|
|
local platforms = { }
|
|
local platformsIndexed = { }
|
|
for n,p in pairs(projects) do
|
|
if p.platforms and #p.platforms ~= 0 then
|
|
for k,v in pairs(p.platforms) do
|
|
platforms[v] = true
|
|
end
|
|
end
|
|
end
|
|
for n,v in pairs(platforms) do
|
|
platformsIndexed[#platformsIndexed + 1] = n
|
|
end
|
|
file:print(2, implode(platformsIndexed, 'platforms {', '"', '"', ', ', '}'))
|
|
file:print(2, 'configurations { "Debug", "Release" }')
|
|
for n,p in pairs(projects) do
|
|
if p.compat then
|
|
local proj = {}
|
|
if p.projectLocation ~= nil then
|
|
proj.location = p.projectLocation .. "/" .. p.name
|
|
else
|
|
proj.location = p.name .. "/"
|
|
end
|
|
proj.includedirs = { path.getrelative(baseLoc,
|
|
path.getdirectory(premakeConfigHeader)),
|
|
path.getrelative(baseLoc, "../include") }
|
|
proj.libdirs = { }
|
|
proj.files = { }
|
|
local links = { }
|
|
local dbgCopyTable = { }
|
|
local relCopyTable = { }
|
|
-- custom links that shouldn't exist...
|
|
-- (these should always happen before dependencies)
|
|
if p.customLinks ~= nil then
|
|
for k,lnk in pairs(p.customLinks) do
|
|
table.insert(links, lnk)
|
|
end
|
|
end
|
|
-- setup project dependencies
|
|
local dependencyLocs = { }
|
|
if p.projectDependencies ~= nil and #p.projectDependencies ~= 0 then
|
|
for k,projname in pairs(p.projectDependencies) do
|
|
local depproj = projects[projname]
|
|
-- validation that it exists and can be linked to
|
|
if depproj ~= nil and (depproj.kind == "SharedLib" or depproj.kind == "StaticLib") then
|
|
if depproj.kind == "SharedLib" then
|
|
local deplocation = nil
|
|
if depproj.projectLocation ~= nil then
|
|
deplocation = depproj.projectLocation .. "/" .. p.name
|
|
else
|
|
deplocation = depproj.name .. "/"
|
|
end
|
|
table.insert(dependencyLocs, { location = deplocation, name = projname })
|
|
else -- static lib
|
|
-- we are now dependent on everything the static lib is dependent on
|
|
if depproj.customLinks ~= nil then
|
|
for k,lnk in pairs(depproj.customLinks) do
|
|
table.insert(links, lnk)
|
|
end
|
|
end
|
|
-- also include links from dependencies
|
|
for i,d in pairs(depproj.dependencyTree) do
|
|
if d.links then
|
|
for k,v in pairs(d.links) do
|
|
local propPath = v:gsub("\\", "/")
|
|
table.insert(links, propPath)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- finally, depend on the project itself
|
|
table.insert(links, projname)
|
|
elseif depproj == nil then
|
|
print("Warning: Missing external dependency for project: ".. p.name ..
|
|
". Be sure you setup project dependencies in a logical order.")
|
|
else
|
|
print("Warning: Cannot link " .. p.name .. " to second project " ..
|
|
projname .. " because the second project is not a library.")
|
|
end
|
|
end
|
|
end
|
|
-- iterate across all root directories, matching source directories
|
|
local dirs = createDirTable(p.sourcedir)
|
|
-- but first, handle any files specifically set in the project, rather than
|
|
-- its dependencies
|
|
-- register c and h files in this directory
|
|
if (p.files ~= nil and #p.files ~= 0) or (p.paths ~= nil and #p.paths ~= 0) then
|
|
-- handle all lists of files
|
|
if p.files ~= nil and #p.files ~= 0 then
|
|
for k,filepat in pairs(p.files) do
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat)) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
end
|
|
end -- end props files if
|
|
-- add all .c/.h files from each path
|
|
-- handle all related paths
|
|
if p.paths ~= nil and #p.paths ~= 0 then
|
|
for j,filepat in ipairs(p.paths) do
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat .. "*.c")) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat .. "*.h")) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
-- mac osx
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat .. "*.m")) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
end
|
|
end -- end of props paths if
|
|
end -- end of check for files/paths in main project
|
|
-- if this project has any configuration flags, add them to the current file
|
|
if p.config then
|
|
addConfig(p.config)
|
|
end
|
|
-- now, handle files and paths for dependencies
|
|
for i,props in ipairs(p.dependencyTree) do
|
|
if props.compat then
|
|
-- register c and h files in this directory
|
|
-- handle all lists of files
|
|
if props.files ~= nil and #props.files ~= 0 then
|
|
for k,filepat in pairs(props.files) do
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat)) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
end
|
|
end -- end props files if
|
|
-- add all .c/.h files from each path
|
|
-- handle all related paths
|
|
if props.paths ~= nil and #props.paths ~= 0 then
|
|
for j,filepat in ipairs(props.paths) do
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat .. "*.c")) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat .. "*.h")) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
-- mac osx
|
|
for k,f in pairs(os.matchfiles(p.sourcedir .. filepat .. "*.m")) do
|
|
table.insert(proj.files, path.getrelative(baseLoc, f))
|
|
end
|
|
end
|
|
end -- end of props paths if
|
|
-- if this dependency has any special configuration flags, add 'em
|
|
if props.config then
|
|
addConfig(props.config)
|
|
end -- end of props config if check
|
|
end -- end check for compatibility
|
|
end -- end of props loop
|
|
--local debugConfig = configuration("Debug")
|
|
local debugConfig = {}
|
|
local releaseConfig = {}
|
|
debugConfig.defines = { "USING_PREMAKE_CONFIG_H", "_DEBUG" }
|
|
releaseConfig.defines = { "USING_PREMAKE_CONFIG_H", "NDEBUG" }
|
|
-- setup per-project defines
|
|
if p.defines ~= nil then
|
|
for k,def in pairs(p.defines) do
|
|
table.insert(debugConfig.defines, def)
|
|
table.insert(releaseConfig.defines, def)
|
|
end
|
|
end
|
|
debugConfig.buildoptions = { }
|
|
if SDL_getos() == "windows" then
|
|
table.insert(debugConfig.buildoptions, "/MDd")
|
|
end
|
|
debugConfig.linkoptions = { }
|
|
releaseConfig.buildoptions = {}
|
|
releaseConfig.linkoptions = {}
|
|
local baseBuildDir = "/Build"
|
|
if os.get() == "windows" then
|
|
baseBuildDir = "/Win32"
|
|
end
|
|
debugConfig.flags = { "Symbols" }
|
|
debugConfig.targetdir = proj.location .. baseBuildDir .. "/Debug"
|
|
releaseConfig.flags = { "OptimizeSpeed" }
|
|
releaseConfig.targetdir = proj.location .. baseBuildDir .. "/Release"
|
|
-- setup postbuild options
|
|
local dbgPostbuildcommands = { }
|
|
local relPostbuildcommands = { }
|
|
-- handle copying depended shared libraries to correct folders
|
|
if os.get() == "windows" then
|
|
for k,deploc in pairs(dependencyLocs) do
|
|
table.insert(dbgCopyTable, { src = deploc.location .. baseBuildDir .. "/Debug/" .. deploc.name .. ".dll",
|
|
dst = debugConfig.targetdir .. "/" .. deploc.name .. ".dll" })
|
|
table.insert(relCopyTable, { src = deploc.location .. baseBuildDir .. "/Release/" .. deploc.name .. ".dll",
|
|
dst = releaseConfig.targetdir .. "/" .. deploc.name .. ".dll" })
|
|
end
|
|
end
|
|
if p.copy ~= nil then
|
|
for k,file in pairs(p.copy) do
|
|
-- the following builds relative paths native to the current system for copying, other
|
|
-- than the copy command itself, this is essentially cross-platform for paths
|
|
|
|
-- all custom copies should be relative to the current working directory
|
|
table.insert(dbgCopyTable, { src = path.getrelative(baseLoc, p.sourcedir .. "/" .. file), dst = debugConfig.targetdir .. "/" .. file })
|
|
table.insert(relCopyTable, { src = path.getrelative(baseLoc, p.sourcedir .. "/" .. file), dst = releaseConfig.targetdir .. "/" .. file })
|
|
end
|
|
end
|
|
for k,file in pairs(dbgCopyTable) do
|
|
-- all copies should be relative to project location, based on platform
|
|
local relLocation = "./"
|
|
--if os.get() == "windows" then
|
|
relLocation = proj.location
|
|
--end
|
|
local fromPath = "./" .. path.getrelative(relLocation, file.src)
|
|
local toPath = "./" .. path.getrelative(relLocation, file.dst)
|
|
local toPathParent = path.getdirectory(toPath)
|
|
local copyCommand = "cp"
|
|
local destCheck = "if [ ! -d \\\"" .. toPathParent .. "\\\" ]; then mkdir -p \\\"" .. toPathParent .. "\\\"; fi"
|
|
if SDL_getos() ~= "windows" and fromPath:find("*") ~= nil then
|
|
-- to path must be a directory for * copies
|
|
toPath = path.getdirectory(toPath)
|
|
end
|
|
if SDL_getos() == "windows" then
|
|
fromPath = path.translate(fromPath, "/"):gsub("/", "\\\\")
|
|
toPath = path.translate(toPath, "/"):gsub("/", "\\\\")
|
|
toPathParent = path.translate(toPathParent, "/"):gsub("/", "\\\\")
|
|
copyCommand = "copy"
|
|
destCheck = "if not exist \\\"" .. toPathParent .. "\\\" ( mkdir \\\"" .. toPathParent .. "\\\" )"
|
|
else
|
|
fromPath = path.translate(fromPath, nil):gsub("\\", "/")
|
|
toPath = path.translate(toPath, nil):gsub("\\", "/")
|
|
end
|
|
-- command will check for destination directory to exist and, if it doesn't,
|
|
-- it will make the directory and then copy over any assets
|
|
local quotedFromPath = fromPath
|
|
if SDL_getos() == "windows" or fromPath:find("*") == nil then
|
|
quotedFromPath = '\\"' .. quotedFromPath .. '\\"'
|
|
end
|
|
table.insert(dbgPostbuildcommands, destCheck)
|
|
table.insert(dbgPostbuildcommands,
|
|
copyCommand .. " " ..
|
|
quotedFromPath .. " \\\"" ..
|
|
toPath .. "\\\"")
|
|
end
|
|
for k,file in pairs(relCopyTable) do
|
|
-- all copies should be relative to project location, based on platform
|
|
local relLocation = "./"
|
|
relLocation = proj.location
|
|
local fromPath = "./" .. path.getrelative(relLocation, file.src)
|
|
local toPath = "./" .. path.getrelative(relLocation, file.dst)
|
|
local toPathParent = path.getdirectory(toPath)
|
|
local copyCommand = "cp"
|
|
local destCheck = "if [ ! -d \\\"" .. toPathParent .. "\\\" ]; then mkdir -p \\\"" .. toPathParent .. "\\\"; fi"
|
|
if SDL_getos() ~= "windows" and fromPath:find("*") ~= nil then
|
|
-- to path must be a directory for * copies
|
|
toPath = path.getdirectory(toPath)
|
|
end
|
|
if SDL_getos() == "windows" then
|
|
fromPath = path.translate(fromPath, "/"):gsub("/", "\\\\")
|
|
toPath = path.translate(toPath, "/"):gsub("/", "\\\\")
|
|
toPathParent = path.translate(toPathParent, "/"):gsub("/", "\\\\")
|
|
copyCommand = "copy"
|
|
destCheck = "if not exist \\\"" .. toPathParent .. "\\\" ( mkdir \\\"" .. toPathParent .. "\\\" )"
|
|
else
|
|
fromPath = path.translate(fromPath, nil):gsub("\\", "/")
|
|
toPath = path.translate(toPath, nil):gsub("\\", "/")
|
|
end
|
|
-- command will check for destination directory to exist and, if it doesn't,
|
|
-- it will make the directory and then copy over any assets
|
|
local quotedFromPath = fromPath
|
|
if SDL_getos() == "windows" or fromPath:find("*") == nil then
|
|
quotedFromPath = '\\"' .. quotedFromPath .. '\\"'
|
|
end
|
|
table.insert(relPostbuildcommands, destCheck)
|
|
table.insert(relPostbuildcommands,
|
|
copyCommand .. " " ..
|
|
quotedFromPath .. " \\\"" ..
|
|
toPath .. "\\\"")
|
|
end
|
|
debugConfig.postbuildcommands = dbgPostbuildcommands
|
|
debugConfig.links = links
|
|
releaseConfig.postbuildcommands = relPostbuildcommands
|
|
releaseConfig.links = links -- release links?
|
|
for i,d in pairs(p.dependencyTree) do
|
|
if d.includes then
|
|
for k,v in pairs(d.includes) do
|
|
local propPath = v:gsub("\\", "/")
|
|
proj.includedirs[propPath] = propPath
|
|
end
|
|
end
|
|
if d.libs then
|
|
for k,v in pairs(d.libs) do
|
|
local propPath = v:gsub("\\", "/")
|
|
proj.libdirs[propPath] = propPath
|
|
end
|
|
end
|
|
if d.links then
|
|
for k,v in pairs(d.links) do
|
|
local propPath = v:gsub("\\", "/")
|
|
debugConfig.links[#debugConfig.links + 1] = propPath
|
|
end
|
|
end
|
|
end
|
|
if #proj.files > 0 then
|
|
file:print(1, 'project "' .. p.name .. '"')
|
|
file:print(2, 'targetname "' .. p.name .. '"')
|
|
-- note: commented out because I think this hack is unnecessary
|
|
--if iOSMode and p.kind == "ConsoleApp" then
|
|
-- hack for iOS where we cannot build "tools"/ConsoleApps in
|
|
-- Xcode for iOS, so we convert them over to WindowedApps
|
|
-- p.kind = "WindowedApp"
|
|
--end
|
|
file:print(2, 'kind "' .. p.kind .. '"')
|
|
file:print(2, 'language "' .. p.language .. '"')
|
|
file:print(2, 'location "' .. proj.location .. '"')
|
|
file:print(2, 'flags { "NoExceptions" }') -- NoRTTI
|
|
file:print(2, 'buildoptions { }')--"/GS-" }')
|
|
file:print(2, implode(proj.includedirs, 'includedirs {', '"', '"', ', ', '}'))
|
|
file:print(2, implode(proj.libdirs, 'libdirs {', '"', '"', ', ', '}'))
|
|
file:print(2, implode(proj.files, 'files {', '"', '"', ', ', '}'))
|
|
-- debug configuration
|
|
file:print(2, 'configuration "Debug"')
|
|
file:print(3, 'targetdir "' .. debugConfig.targetdir .. '"')
|
|
-- debug dir is relative to the solution's location
|
|
file:print(3, 'debugdir "' .. debugConfig.targetdir .. '"')
|
|
file:print(3, implode(debugConfig.defines, 'defines {', '"', '"', ', ', '}'))
|
|
file:print(3, implode(debugConfig.links, "links {", '"', '"', ', ', "}"))
|
|
if SDL_getos() == "mingw" then
|
|
-- static runtime
|
|
file:print(3, 'linkoptions { "-lmingw32 -static-libgcc" }')
|
|
end
|
|
if SDL_getos() == "cygwin" then
|
|
file:print(3, 'linkoptions { "-static-libgcc" }')
|
|
end
|
|
file:print(3, implode(debugConfig.flags, "flags {", '"', '"', ', ', "}"))
|
|
file:print(3, implode(debugConfig.postbuildcommands, "postbuildcommands {", '"', '"', ', ', "}"))
|
|
-- release configuration
|
|
file:print(2, 'configuration "Release"')
|
|
file:print(3, 'targetdir "' .. releaseConfig.targetdir .. '"')
|
|
-- debug dir is relative to the solution's location
|
|
file:print(3, 'debugdir "' .. releaseConfig.targetdir .. '"')
|
|
file:print(3, implode(releaseConfig.defines, 'defines {', '"', '"', ', ', '}'))
|
|
file:print(3, implode(releaseConfig.links, "links {", '"', '"', ', ', "}"))
|
|
if SDL_getos() == "mingw" then
|
|
-- static runtime
|
|
file:print(3, 'linkoptions { "-lmingw32 -static-libgcc" }')
|
|
end
|
|
file:print(3, implode(releaseConfig.flags, "flags {", '"', '"', ', ', "}"))
|
|
file:print(3, implode(releaseConfig.postbuildcommands, "postbuildcommands {", '"', '"', ', ', "}"))
|
|
end -- end check for valid project (files to build)
|
|
end -- end compatibility check for projects
|
|
end -- end for loop for projects
|
|
|
|
endGeneration() -- finish generating the config header file
|
|
file:close()
|
|
|
|
-- generation is over, now execute the generated file, setup the premake
|
|
-- solution, and let premake execute the action and generate the project files
|
|
dofile(genFile)
|
|
end -- end check for not being in help mode
|