Initial community commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
--
|
||||
-- _manifest.lua
|
||||
-- Manage the list of built-in Premake scripts.
|
||||
-- Copyright (c) 2002-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
-- The master list of built-in scripts. Order is important! If you want to
|
||||
-- build a new script into Premake, add it to this list.
|
||||
|
||||
return
|
||||
{
|
||||
-- core files
|
||||
"base/os.lua",
|
||||
"base/path.lua",
|
||||
"base/string.lua",
|
||||
"base/table.lua",
|
||||
"base/io.lua",
|
||||
"base/globals.lua",
|
||||
"base/action.lua",
|
||||
"base/option.lua",
|
||||
"base/tree.lua",
|
||||
"base/solution.lua",
|
||||
"base/project.lua",
|
||||
"base/config.lua",
|
||||
"base/bake.lua",
|
||||
"base/api.lua",
|
||||
"base/cmdline.lua",
|
||||
"base/inspect.lua",
|
||||
"base/profiler.lua",
|
||||
"tools/dotnet.lua",
|
||||
"tools/gcc.lua",
|
||||
"tools/ghs.lua",
|
||||
"tools/msc.lua",
|
||||
"tools/ow.lua",
|
||||
"tools/snc.lua",
|
||||
"tools/valac.lua",
|
||||
"tools/swift.lua",
|
||||
"base/validate.lua",
|
||||
"base/help.lua",
|
||||
"base/premake.lua",
|
||||
"base/iter.lua",
|
||||
"base/set.lua",
|
||||
|
||||
-- CMake action
|
||||
"actions/cmake/_cmake.lua",
|
||||
"actions/cmake/cmake_workspace.lua",
|
||||
"actions/cmake/cmake_project.lua",
|
||||
|
||||
-- GNU make action
|
||||
"actions/make/_make.lua",
|
||||
"actions/make/make_solution.lua",
|
||||
"actions/make/make_cpp.lua",
|
||||
"actions/make/make_csharp.lua",
|
||||
"actions/make/make_vala.lua",
|
||||
"actions/make/make_swift.lua",
|
||||
|
||||
-- Visual Studio actions
|
||||
"actions/vstudio/_vstudio.lua",
|
||||
"actions/vstudio/vstudio_solution.lua",
|
||||
"actions/vstudio/vstudio_vcxproj.lua",
|
||||
"actions/vstudio/vstudio_vcxproj_filters.lua",
|
||||
"actions/vstudio/vs2010.lua",
|
||||
"actions/vstudio/vs2012.lua",
|
||||
"actions/vstudio/vs2013.lua",
|
||||
"actions/vstudio/vs2015.lua",
|
||||
"actions/vstudio/vs2017.lua",
|
||||
"actions/vstudio/vs2019.lua",
|
||||
|
||||
-- Xcode action
|
||||
"actions/xcode/_xcode.lua",
|
||||
"actions/xcode/xcode_common.lua",
|
||||
"actions/xcode/xcode_project.lua",
|
||||
"actions/xcode/xcode_scheme.lua",
|
||||
"actions/xcode/xcode_workspace.lua",
|
||||
"actions/xcode/xcode8.lua",
|
||||
"actions/xcode/xcode9.lua",
|
||||
"actions/xcode/xcode10.lua",
|
||||
"actions/xcode/xcode11.lua",
|
||||
|
||||
-- ninja action
|
||||
"actions/ninja/_ninja.lua",
|
||||
"actions/ninja/ninja_base.lua",
|
||||
"actions/ninja/ninja_solution.lua",
|
||||
"actions/ninja/ninja_cpp.lua",
|
||||
"actions/ninja/ninja_swift.lua",
|
||||
"actions/ninja/ninja_swift_incremental.lua",
|
||||
|
||||
-- qbs action
|
||||
"actions/qbs/_qbs.lua",
|
||||
"actions/qbs/qbs_base.lua",
|
||||
"actions/qbs/qbs_solution.lua",
|
||||
"actions/qbs/qbs_cpp.lua",
|
||||
|
||||
-- jcdb action
|
||||
"actions/jcdb/_jcdb.lua",
|
||||
"actions/jcdb/jcdb_solution.lua",
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
--
|
||||
-- _premake_main.lua
|
||||
-- Script-side entry point for the main program logic.
|
||||
-- Copyright (c) 2002-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
_WORKING_DIR = os.getcwd()
|
||||
|
||||
|
||||
--
|
||||
-- Inject a new target platform into each solution; called if the --platform
|
||||
-- argument was specified on the command line.
|
||||
--
|
||||
|
||||
local function injectplatform(platform)
|
||||
if not platform then return true end
|
||||
platform = premake.checkvalue(platform, premake.fields.platforms.allowed)
|
||||
|
||||
for sln in premake.solution.each() do
|
||||
local platforms = sln.platforms or { }
|
||||
|
||||
-- an empty table is equivalent to a native build
|
||||
if #platforms == 0 then
|
||||
table.insert(platforms, "Native")
|
||||
end
|
||||
|
||||
-- the solution must provide a native build in order to support this feature
|
||||
if not table.contains(platforms, "Native") then
|
||||
return false, sln.name .. " does not target native platform\nNative platform settings are required for the --platform feature."
|
||||
end
|
||||
|
||||
-- add it to the end of the list, if it isn't in there already
|
||||
if not table.contains(platforms, platform) then
|
||||
table.insert(platforms, platform)
|
||||
end
|
||||
|
||||
sln.platforms = platforms
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--
|
||||
-- Script-side program entry point.
|
||||
--
|
||||
|
||||
function _premake_main(scriptpath)
|
||||
|
||||
-- if running off the disk (in debug mode), load everything
|
||||
-- listed in _manifest.lua; the list divisions make sure
|
||||
-- everything gets initialized in the proper order.
|
||||
if (scriptpath) then
|
||||
local scripts = dofile(scriptpath .. "/_manifest.lua")
|
||||
for _,v in ipairs(scripts) do
|
||||
dofile(scriptpath .. "/" .. v)
|
||||
end
|
||||
end
|
||||
|
||||
local profiler = newProfiler()
|
||||
if (nil ~= _OPTIONS["debug-profiler"]) then
|
||||
profiler:start()
|
||||
end
|
||||
|
||||
-- Now that the scripts are loaded, I can use path.getabsolute() to properly
|
||||
-- canonicalize the executable path.
|
||||
_PREMAKE_COMMAND = path.getabsolute(_PREMAKE_COMMAND)
|
||||
|
||||
-- Set up the environment for the chosen action early, so side-effects
|
||||
-- can be picked up by the scripts.
|
||||
premake.action.set(_ACTION)
|
||||
|
||||
-- Seed the random number generator so actions don't have to do it themselves
|
||||
math.randomseed(os.time())
|
||||
|
||||
-- If there is a project script available, run it to get the
|
||||
-- project information, available options and actions, etc.
|
||||
if (nil ~= _OPTIONS["file"]) then
|
||||
local fname = _OPTIONS["file"]
|
||||
if (os.isfile(fname)) then
|
||||
dofile(fname)
|
||||
else
|
||||
error("No genie script '" .. fname .. "' found!", 2)
|
||||
end
|
||||
else
|
||||
local dir, name = premake.findDefaultScript(path.getabsolute("./"))
|
||||
if dir ~= nil then
|
||||
local cwd = os.getcwd()
|
||||
os.chdir(dir)
|
||||
dofile(name)
|
||||
os.chdir(cwd)
|
||||
end
|
||||
end
|
||||
|
||||
-- Process special options
|
||||
if (_OPTIONS["version"] or _OPTIONS["help"] or not _ACTION) then
|
||||
printf("GENie - Project generator tool %s", _GENIE_VERSION_STR)
|
||||
printf("https://github.com/bkaradzic/GENie")
|
||||
if (not _OPTIONS["version"]) then
|
||||
premake.showhelp()
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
-- Validate the command-line arguments. This has to happen after the
|
||||
-- script has run to allow for project-specific options
|
||||
action = premake.action.current()
|
||||
if (not action) then
|
||||
error("Error: no such action '" .. _ACTION .. "'", 0)
|
||||
end
|
||||
|
||||
ok, err = premake.option.validate(_OPTIONS)
|
||||
if (not ok) then error("Error: " .. err, 0) end
|
||||
|
||||
-- Sanity check the current project setup
|
||||
ok, err = premake.checktools()
|
||||
if (not ok) then error("Error: " .. err, 0) end
|
||||
|
||||
-- If a platform was specified on the command line, inject it now
|
||||
ok, err = injectplatform(_OPTIONS["platform"])
|
||||
if (not ok) then error("Error: " .. err, 0) end
|
||||
|
||||
-- work-in-progress: build the configurations
|
||||
print("Building configurations...")
|
||||
premake.bake.buildconfigs()
|
||||
|
||||
ok, err = premake.checkprojects()
|
||||
if (not ok) then error("Error: " .. err, 0) end
|
||||
|
||||
premake.stats = { }
|
||||
|
||||
premake.stats.num_generated = 0
|
||||
premake.stats.num_skipped = 0
|
||||
|
||||
-- Hand over control to the action
|
||||
printf("Running action '%s'...", action.trigger)
|
||||
premake.action.call(action.trigger)
|
||||
|
||||
if (nil ~= _OPTIONS["debug-profiler"]) then
|
||||
profiler:stop()
|
||||
|
||||
local filePath = path.getabsolute("GENie-profile.txt")
|
||||
print("Writing debug-profile report to ''" .. filePath .. "'.")
|
||||
|
||||
local outfile = io.open(filePath, "w+")
|
||||
profiler:report(outfile, true)
|
||||
outfile:close()
|
||||
end
|
||||
|
||||
printf("Done. Generated %d/%d projects."
|
||||
, premake.stats.num_generated
|
||||
, premake.stats.num_generated+premake.stats.num_skipped
|
||||
)
|
||||
return 0
|
||||
|
||||
end
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
--
|
||||
-- _cmake.lua
|
||||
-- Define the CMake action(s).
|
||||
-- Copyright (c) 2015 Miodrag Milanovic
|
||||
--
|
||||
|
||||
premake.cmake = { }
|
||||
|
||||
--
|
||||
-- Register the "cmake" action
|
||||
--
|
||||
|
||||
newaction {
|
||||
trigger = "cmake",
|
||||
shortname = "CMake",
|
||||
description = "Generate CMake project files",
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
valid_languages = { "C", "C++" },
|
||||
valid_tools = {
|
||||
cc = { "gcc" },
|
||||
},
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "CMakeLists.txt", premake.cmake.workspace)
|
||||
end,
|
||||
onproject = function(prj)
|
||||
premake.generate(prj, "%%/CMakeLists.txt", premake.cmake.project)
|
||||
end,
|
||||
oncleansolution = function(sln)
|
||||
premake.clean.file(sln, "CMakeLists.txt")
|
||||
end,
|
||||
oncleanproject = function(prj)
|
||||
premake.clean.file(prj, "%%/CMakeLists.txt")
|
||||
end
|
||||
}
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
--
|
||||
-- _cmake.lua
|
||||
-- Define the CMake action(s).
|
||||
-- Copyright (c) 2015 Miodrag Milanovic
|
||||
-- Modifications and additions in 2017 by Maurizio Petrarota
|
||||
--
|
||||
|
||||
local cmake = premake.cmake
|
||||
local tree = premake.tree
|
||||
|
||||
local includestr = 'include_directories(../%s)'
|
||||
local definestr = 'add_definitions(-D%s)'
|
||||
|
||||
|
||||
local function is_excluded(prj, cfg, file)
|
||||
if table.icontains(prj.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
if table.icontains(cfg.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function cmake.excludedFiles(prj, cfg, src)
|
||||
for _, v in ipairs(src) do
|
||||
if (is_excluded(prj, cfg, v)) then
|
||||
_p(1, 'list(REMOVE_ITEM source_list ../%s)', v)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function cmake.list(value)
|
||||
if #value > 0 then
|
||||
return " " .. table.concat(value, " ")
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
function cmake.listWrapped(value, prefix, postfix)
|
||||
if #value > 0 then
|
||||
return prefix .. table.concat(value, postfix .. prefix) .. postfix
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
function cmake.files(prj)
|
||||
local ret = {}
|
||||
local tr = premake.project.buildsourcetree(prj)
|
||||
tree.traverse(tr, {
|
||||
onbranchenter = function(node, depth)
|
||||
end,
|
||||
onbranchexit = function(node, depth)
|
||||
end,
|
||||
onleaf = function(node, depth)
|
||||
assert(node, "unexpected empty node")
|
||||
if node.cfg then
|
||||
table.insert(ret, node.cfg.name)
|
||||
_p(1, '../%s', node.cfg.name)
|
||||
end
|
||||
end,
|
||||
}, true, 1)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function cmake.header(prj)
|
||||
_p('# %s project autogenerated by GENie', premake.action.current().shortname)
|
||||
_p('cmake_minimum_required(VERSION 3.15)')
|
||||
if os.is("windows") then
|
||||
-- Add support for CMP0091, see https://cmake.org/cmake/help/latest/policy/CMP0091.html
|
||||
_p('cmake_policy(SET CMP0091 NEW)')
|
||||
end
|
||||
_p('')
|
||||
_p('project(%s)', premake.esc(prj.name))
|
||||
_p('')
|
||||
_p('include(GNUInstallDirs)')
|
||||
end
|
||||
|
||||
function cmake.customtasks(prj)
|
||||
local dirs = {}
|
||||
local tasks = {}
|
||||
for _, custombuildtask in ipairs(prj.custombuildtask or {}) do
|
||||
for _, buildtask in ipairs(custombuildtask or {}) do
|
||||
table.insert(tasks, buildtask)
|
||||
local d = string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s", path.getdirectory(path.getrelative(prj.location, buildtask[2])))
|
||||
if not table.contains(dirs, d) then
|
||||
table.insert(dirs, d)
|
||||
_p('file(MAKE_DIRECTORY \"%s\")', d)
|
||||
end
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
for _, buildtask in ipairs(tasks) do
|
||||
local deps = string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, buildtask[1]))
|
||||
local outputs = string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, buildtask[2]))
|
||||
local msg = ""
|
||||
|
||||
for _, depdata in ipairs(buildtask[3] or {}) do
|
||||
deps = deps .. string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, depdata))
|
||||
end
|
||||
|
||||
_p('add_custom_command(')
|
||||
_p(1, 'OUTPUT %s', outputs)
|
||||
_p(1, 'DEPENDS %s', deps)
|
||||
|
||||
for _, cmdline in ipairs(buildtask[4] or {}) do
|
||||
if (cmdline:sub(1, 1) ~= "@") then
|
||||
local cmd = cmdline
|
||||
local num = 1
|
||||
for _, depdata in ipairs(buildtask[3] or {}) do
|
||||
cmd = string.gsub(cmd, "%$%(" .. num .. "%)", string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, depdata)))
|
||||
num = num + 1
|
||||
end
|
||||
|
||||
cmd = string.gsub(cmd, "%$%(<%)", string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, buildtask[1])))
|
||||
cmd = string.gsub(cmd, "%$%(@%)", outputs)
|
||||
|
||||
_p(1, 'COMMAND %s', cmd)
|
||||
else
|
||||
msg = cmdline
|
||||
end
|
||||
end
|
||||
_p(1, 'COMMENT \"%s\"', msg)
|
||||
_p(')')
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
|
||||
function cmake.depRules(prj)
|
||||
local maintable = {}
|
||||
for _, dependency in ipairs(prj.dependency) do
|
||||
for _, dep in ipairs(dependency) do
|
||||
if path.issourcefile(dep[1]) then
|
||||
local dep1 = premake.esc(path.getrelative(prj.location, dep[1]))
|
||||
local dep2 = premake.esc(path.getrelative(prj.location, dep[2]))
|
||||
if not maintable[dep1] then maintable[dep1] = {} end
|
||||
table.insert(maintable[dep1], dep2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for key, _ in pairs(maintable) do
|
||||
local deplist = {}
|
||||
local depsname = string.format('%s_deps', path.getname(key))
|
||||
|
||||
for _, d2 in pairs(maintable[key]) do
|
||||
table.insert(deplist, d2)
|
||||
end
|
||||
_p('set(')
|
||||
_p(1, depsname)
|
||||
for _, v in pairs(deplist) do
|
||||
_p(1, '${CMAKE_CURRENT_SOURCE_DIR}/../%s', v)
|
||||
end
|
||||
_p(')')
|
||||
_p('')
|
||||
_p('set_source_files_properties(')
|
||||
_p(1, '\"${CMAKE_CURRENT_SOURCE_DIR}/../%s\"', key)
|
||||
_p(1, 'PROPERTIES OBJECT_DEPENDS \"${%s}\"', depsname)
|
||||
_p(')')
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
|
||||
function cmake.commonRules(conf, str)
|
||||
local Dupes = {}
|
||||
local t2 = {}
|
||||
for _, cfg in ipairs(conf) do
|
||||
local cfgd = iif(str == includestr, cfg.includedirs, cfg.defines)
|
||||
for _, v in ipairs(cfgd) do
|
||||
if(t2[v] == #conf - 1) then
|
||||
_p(str, v)
|
||||
table.insert(Dupes, v)
|
||||
end
|
||||
if not t2[v] then
|
||||
t2[v] = 1
|
||||
else
|
||||
t2[v] = t2[v] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return Dupes
|
||||
end
|
||||
|
||||
function cmake.cfgRules(cfg, dupes, str)
|
||||
for _, v in ipairs(cfg) do
|
||||
if (not table.icontains(dupes, v)) then
|
||||
_p(1, str, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cmake.removeCrosscompiler(platforms)
|
||||
for i = #platforms, 1, -1 do
|
||||
if premake.platforms[platforms[i]].iscrosscompiler then
|
||||
table.remove(platforms, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cmake.project(prj)
|
||||
io.indent = " "
|
||||
cmake.header(prj)
|
||||
_p('set(')
|
||||
_p('source_list')
|
||||
local source_files = cmake.files(prj)
|
||||
_p(')')
|
||||
_p('')
|
||||
|
||||
local nativeplatform = iif(os.is64bit(), "x64", "x32")
|
||||
local cc = premake.gettool(prj)
|
||||
local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native")
|
||||
|
||||
cmake.removeCrosscompiler(platforms)
|
||||
|
||||
local configurations = {}
|
||||
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in premake.eachconfig(prj, platform) do
|
||||
-- TODO: Extend support for 32-bit targets on 64-bit hosts
|
||||
if cfg.platform == nativeplatform then
|
||||
table.insert(configurations, cfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local commonIncludes = cmake.commonRules(configurations, includestr)
|
||||
local commonDefines = cmake.commonRules(configurations, definestr)
|
||||
|
||||
_p('')
|
||||
|
||||
for _, cfg in ipairs(configurations) do
|
||||
_p('if(CMAKE_BUILD_TYPE MATCHES \"%s\")', cfg.name)
|
||||
|
||||
-- list excluded files
|
||||
cmake.excludedFiles(prj, cfg, source_files)
|
||||
|
||||
-- add includes directories
|
||||
cmake.cfgRules(cfg.includedirs, commonIncludes, includestr)
|
||||
|
||||
-- add build defines
|
||||
cmake.cfgRules(cfg.defines, commonDefines, definestr)
|
||||
|
||||
-- set CXX flags
|
||||
_p(1, 'set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} %s\")', cmake.list(table.join(cc.getcppflags(cfg), cc.getcflags(cfg), cc.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_cpp)))
|
||||
|
||||
-- set C flags
|
||||
_p(1, 'set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} %s\")', cmake.list(table.join(cc.getcppflags(cfg), cc.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_c)))
|
||||
|
||||
_p('endif()')
|
||||
_p('')
|
||||
end
|
||||
|
||||
-- force CPP if needed
|
||||
if (prj.options.ForceCPP) then
|
||||
_p('set_source_files_properties(${source_list} PROPERTIES LANGUAGE CXX)')
|
||||
end
|
||||
|
||||
-- add custom tasks
|
||||
cmake.customtasks(prj)
|
||||
|
||||
-- per-dependency build rules
|
||||
cmake.depRules(prj)
|
||||
|
||||
for _, cfg in ipairs(configurations) do
|
||||
_p('if(CMAKE_BUILD_TYPE MATCHES \"%s\")', cfg.name)
|
||||
|
||||
if (prj.kind == 'StaticLib') then
|
||||
_p(1, 'add_library(%s STATIC ${source_list})', premake.esc(cfg.buildtarget.basename))
|
||||
-- Install
|
||||
_p(1, 'install(TARGETS %s RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})', premake.esc(cfg.buildtarget.basename))
|
||||
end
|
||||
|
||||
if (prj.kind == 'SharedLib') then
|
||||
_p(1, 'add_library(%s SHARED ${source_list})', premake.esc(cfg.buildtarget.basename))
|
||||
-- Install
|
||||
_p(1, 'install(TARGETS %s RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})', premake.esc(cfg.buildtarget.basename))
|
||||
end
|
||||
if (prj.kind == 'ConsoleApp' or prj.kind == 'WindowedApp') then
|
||||
_p(1, 'add_executable(%s ${source_list})', premake.esc(cfg.buildtarget.basename))
|
||||
|
||||
local libdirs = cmake.listWrapped(premake.esc(premake.getlinks(cfg, "all", "directory")), " -L\"../", "\"")
|
||||
|
||||
_p(1, 'target_link_libraries(%s%s%s%s%s%s)', premake.esc(cfg.buildtarget.basename), libdirs, cmake.list(cfg.linkoptions), cmake.list(cc.getldflags(cfg)), cmake.list(premake.esc(premake.getlinks(cfg, "siblings", "basename"))), cmake.list(cc.getlinkflags(cfg)))
|
||||
|
||||
-- Install
|
||||
_p(1, 'install(TARGETS %s RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})', premake.esc(cfg.buildtarget.basename))
|
||||
end
|
||||
_p('endif()')
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
Vendored
+55
@@ -0,0 +1,55 @@
|
||||
--
|
||||
-- _cmake.lua
|
||||
-- Define the CMake action(s).
|
||||
-- Copyright (c) 2015 Miodrag Milanovic
|
||||
--
|
||||
|
||||
function premake.cmake.workspace(sln)
|
||||
if (sln.location ~= _WORKING_DIR) then
|
||||
local name = string.format("%s/CMakeLists.txt", _WORKING_DIR)
|
||||
local f, err = io.open(name, "wb")
|
||||
if (not f) then
|
||||
error(err, 0)
|
||||
end
|
||||
f:write([[
|
||||
# CMakeLists autogenerated by GENie
|
||||
project(GENie)
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
#########################################################################
|
||||
|
||||
# Set a default build type if none was specified
|
||||
# Source: https://blog.kitware.com/cmake-and-the-default-build-type/
|
||||
set(default_build_type "Release")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
set(default_build_type "Debug")
|
||||
endif()
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
|
||||
# Set the possible values of build type for cmake-gui
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
#########################################################################
|
||||
]])
|
||||
if os.is("windows") then
|
||||
-- Add support for CMP0091, see https://cmake.org/cmake/help/latest/policy/CMP0091.html
|
||||
f:write('cmake_policy(SET CMP0091 NEW)\n')
|
||||
end
|
||||
f:write('add_subdirectory('.. path.getrelative(_WORKING_DIR, sln.location) ..')\n')
|
||||
f:close()
|
||||
end
|
||||
_p([[
|
||||
# CMakeLists autogenerated by GENie
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
]])
|
||||
if os.is("windows") then
|
||||
-- Add support for CMP0091, see https://cmake.org/cmake/help/latest/policy/CMP0091.html
|
||||
_p('cmake_policy(SET CMP0091 NEW)')
|
||||
end
|
||||
for i,prj in ipairs(sln.projects) do
|
||||
local name = premake.esc(prj.name)
|
||||
_p('add_subdirectory(%s)', name)
|
||||
end
|
||||
end
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
-- Define a namespace for my new action. The second line defines an alias that I
|
||||
-- can use in this file, saving myself some typing. It will not be visible outside
|
||||
-- of this file (though I can always define it again).
|
||||
|
||||
premake.example = { }
|
||||
local example = premake.example
|
||||
|
||||
|
||||
-- The description of the action. Note that only the first three fields are required;
|
||||
-- you can remove any of the additional fields that are not required by your action.
|
||||
|
||||
newaction
|
||||
{
|
||||
-- The trigger is what needs to be typed on the command line to cause
|
||||
-- this action this run (premake4 example)
|
||||
trigger = "example",
|
||||
|
||||
-- The short name is used when this toolset name needs to be shown to
|
||||
-- the user, such as in status or error messages
|
||||
shortname = "Super Studio 3000",
|
||||
|
||||
-- The description is shown in the help text (premake4 /help)
|
||||
description = "An example action that prints simple text files",
|
||||
|
||||
-- Some actions imply a particular operating system: Visual Studio only
|
||||
-- runs on Windows, and Xcode only on Mac OS X. If this is the case,
|
||||
-- uncomment this line and set it to one of "windows", "linux" or "macosx".
|
||||
-- Otherwise, this action will target the current operating system.
|
||||
-- os = "macosx",
|
||||
|
||||
-- Which kinds of targets this action supports; remove those you don't.
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
-- Which programming languages this actions supports; remove those you don't.
|
||||
valid_languages = { "C", "C++", "C#" },
|
||||
|
||||
-- Which compiler sets this action supports; remove those you don't. The set
|
||||
-- is specified with the /cc and /dotnet command-line options. You can find
|
||||
-- the tool interfaces at src/tools.
|
||||
valid_tools = {
|
||||
cc = { "msc", "gcc", "ow" },
|
||||
dotnet = { "mono", "msnet", "pnet" },
|
||||
},
|
||||
|
||||
|
||||
-- This function is called during state validation. If your action has some
|
||||
-- special requirements you can check them here and error if necessary.
|
||||
|
||||
|
||||
oncheckproject = function(prj)
|
||||
-- if this_project_is_no_good(prj) then
|
||||
-- error("Project " .. prj.name .. " is no good", 0)
|
||||
-- end
|
||||
end,
|
||||
|
||||
|
||||
-- These functions will get called for each solution and project. The function
|
||||
-- premake.generate() creates a file for you in the correct place, taking into
|
||||
-- account any location information specified in the script. The sequence "%%"
|
||||
-- will be replaced by the solution/project name. The last parameter is the
|
||||
-- function that will actually do the work of generating the file contents.
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.sln.txt", premake.example.solution)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, "%%.csprj.txt", premake.example.project)
|
||||
else
|
||||
premake.generate(prj, "%%.cprj.txt", premake.example.project)
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
-- These functions are called for each solution, project, and target as part
|
||||
-- of the "clean" action. They should remove any files generated by the tools.
|
||||
-- premake.clean.file() and premake.clean.directory() are convenience functions
|
||||
-- that use the same pattern matching as premake.generate() above.
|
||||
|
||||
oncleansolution = function(sln)
|
||||
premake.clean.file(sln, "%%.sln.txt")
|
||||
end,
|
||||
|
||||
oncleanproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.clean.file(prj, "%%.csprj.txt")
|
||||
else
|
||||
premake.clean.file(prj, "%%.cprj.txt")
|
||||
end
|
||||
end,
|
||||
|
||||
oncleantarget = function(trg)
|
||||
-- 'trg' is the path and base name of the target being cleaned,
|
||||
-- like 'bin/debug/MyApplication'. So you might do something like:
|
||||
-- os.remove(trg .. ".exe")
|
||||
end,
|
||||
}
|
||||
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
-- An example project generator; see _example.lua for action description
|
||||
|
||||
--
|
||||
-- The project generation function, attached to the action in _example.lua.
|
||||
-- By now, premake.generate() has created the project file using the name
|
||||
-- provided in _example.lua, and redirected input to this new file.
|
||||
--
|
||||
|
||||
function premake.example.project(prj)
|
||||
-- If necessary, set an explicit line ending sequence
|
||||
-- io.eol = '\r\n'
|
||||
|
||||
-- Let's start with a header
|
||||
_p('-- Example project file version 1.0')
|
||||
_p('Name: %s', prj.name)
|
||||
_p('Kind: %s', prj.kind)
|
||||
_p('Language: %s', prj.language)
|
||||
_p('ID: {%s}', prj.uuid)
|
||||
_p('')
|
||||
|
||||
|
||||
-- List the build configurations, and the settings for each
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
_p('Configuration %s:', cfg.name)
|
||||
_p(1, 'Objects directory: %s', cfg.objectsdir)
|
||||
|
||||
_p(1, 'Build target:')
|
||||
_p(2, 'Full path: %s', cfg.buildtarget.fullpath)
|
||||
_p(2, 'Directory: %s', cfg.buildtarget.directory)
|
||||
_p(2, 'Name: %s', cfg.buildtarget.name)
|
||||
_p(2, 'Base name: %s', cfg.buildtarget.basename)
|
||||
_p(2, 'Prefix: %s', cfg.buildtarget.prefix)
|
||||
_p(2, 'Suffix: %s', cfg.buildtarget.suffix)
|
||||
_p('')
|
||||
|
||||
_p(1, 'Compiling:')
|
||||
_p(2, 'Defines: %s', table.concat(cfg.defines, ";"))
|
||||
_p(2, 'Include paths: %s', table.concat(cfg.includedirs, ";"))
|
||||
_p(2, 'Flags: %s', table.concat(cfg.flags, ", "))
|
||||
if not cfg.flags.NoPCH and cfg.pchheader then
|
||||
_p(2, 'Precompiled header: %s (%s)', cfg.pchheader, cfg.pchsource)
|
||||
end
|
||||
_p(2, 'Options: %s', table.concat(cfg.buildoptions, " "))
|
||||
_p('')
|
||||
|
||||
_p(1, 'Linking:')
|
||||
_p(2, 'Library paths: %s', table.concat(cfg.libdirs, ";"))
|
||||
_p(2, 'Options: %s', table.concat(cfg.linkoptions, " "))
|
||||
_p(2, 'Libraries: %s', table.concat(premake.getlinks(cfg, "all", "fullpath")))
|
||||
_p('')
|
||||
|
||||
if #cfg.prebuildcommands > 0 then
|
||||
_p(1, 'Prebuild commands:')
|
||||
for _, cmd in ipairs(cfg.prebuildcommands) do
|
||||
_p(2, cmd)
|
||||
end
|
||||
_p('')
|
||||
end
|
||||
|
||||
if #cfg.prelinkcommands > 0 then
|
||||
_p(1, 'Prelink commands:')
|
||||
for _, cmd in ipairs(cfg.prelinkcommands) do
|
||||
_p(2, cmd)
|
||||
end
|
||||
_p('')
|
||||
end
|
||||
|
||||
if #cfg.postbuildcommands > 0 then
|
||||
_p(1, 'Postbuild commands:')
|
||||
for _, cmd in ipairs(cfg.postbuildcommands) do
|
||||
_p(2, cmd)
|
||||
end
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- List out the folders and files that make up the build
|
||||
local tr = premake.project.buildsourcetree(prj)
|
||||
premake.tree.sort(tr)
|
||||
premake.tree.traverse(tr, {
|
||||
onbranch = function(node, depth)
|
||||
_p(depth, path.getname(node.name) .. "/")
|
||||
end,
|
||||
|
||||
onleaf = function(node, depth)
|
||||
_p(depth, path.getname(node.name))
|
||||
end
|
||||
})
|
||||
|
||||
end
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
-- An example solution generator; see _example.lua for action description
|
||||
|
||||
--
|
||||
-- The solution generation function, attached to the action in _example.lua.
|
||||
-- By now, premake.generate() has created the solution file using the name
|
||||
-- provided in _example.lua, and redirected input to this new file.
|
||||
--
|
||||
|
||||
function premake.example.solution(sln)
|
||||
-- If necessary, set an explicit line ending sequence
|
||||
-- io.eol = '\r\n'
|
||||
|
||||
-- Let's start with a header
|
||||
_p('-- Example solution file version 1.0')
|
||||
_p('Name: %s', sln.name)
|
||||
_p('')
|
||||
|
||||
|
||||
-- List the build configurations
|
||||
for _, cfgname in ipairs(sln.configurations) do
|
||||
_p('Config: %s', cfgname)
|
||||
end
|
||||
_p('')
|
||||
|
||||
|
||||
-- List the projects contained by the solution, with some info on each
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
_p('Project: %s', prj.name)
|
||||
_p(1, 'Kind: %s', prj.kind)
|
||||
_p(1, 'Language: %s', prj.language)
|
||||
_p(1, 'ID: {%s}', prj.uuid)
|
||||
_p(1, 'Relative path: %s', path.getrelative(sln.location, prj.location))
|
||||
|
||||
-- List dependencies, if there are any
|
||||
local deps = premake.getdependencies(prj)
|
||||
if #deps > 0 then
|
||||
_p(1, 'Dependencies:')
|
||||
for _, depprj in ipairs(deps) do
|
||||
_p(2, '%s {%s}', depprj.name, depprj.uuid)
|
||||
end
|
||||
end
|
||||
|
||||
_p('')
|
||||
end
|
||||
|
||||
end
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
--
|
||||
-- _jcdb.lua
|
||||
-- Define the compile_commands.json action(s).
|
||||
-- Copyright (c) 2020 Johan Skoeld
|
||||
--
|
||||
|
||||
newaction {
|
||||
trigger = "jcdb",
|
||||
shortname = "compile_commands.json",
|
||||
description = "Generate a compile_commands.json file.",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
valid_languages = { "C", "C++" },
|
||||
valid_tools = { cc = { "gcc" } },
|
||||
|
||||
onsolution = function(sln)
|
||||
local jsonpath = path.join(sln.location, "compile_commands.json")
|
||||
premake.generate(sln, jsonpath, premake.jcdb.generate)
|
||||
end,
|
||||
}
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
--
|
||||
-- jcdb_solution.lua
|
||||
-- compile_commands.json functions.
|
||||
-- Copyright (c) 2020 Johan Skoeld
|
||||
--
|
||||
|
||||
premake.jcdb = {}
|
||||
|
||||
local premake = premake
|
||||
local jcdb = premake.jcdb
|
||||
|
||||
local encode_chars = {
|
||||
[0x22] = '\\"',
|
||||
[0x5c] = "\\\\",
|
||||
[0x08] = "\\b",
|
||||
[0x0c] = "\\f",
|
||||
[0x0a] = "\\n",
|
||||
[0x0d] = "\\r",
|
||||
[0x09] = "\\t",
|
||||
}
|
||||
|
||||
local function encode_string(s)
|
||||
local res = '"'
|
||||
|
||||
for _, cp in utf8.codes(s) do
|
||||
if encode_chars[cp] then
|
||||
res = res..encode_chars[cp]
|
||||
elseif cp < 32 then
|
||||
res = res..string.format("\\u%04x", cp)
|
||||
else
|
||||
res = res..utf8.char(cp)
|
||||
end
|
||||
end
|
||||
|
||||
return res..'"'
|
||||
end
|
||||
|
||||
local function escape_cmdline_arg(s)
|
||||
if s:find("%s") then
|
||||
s = s:gsub("\\", "\\\\")
|
||||
s = s:gsub('"', '\\"')
|
||||
s = '"'..s..'"'
|
||||
end
|
||||
|
||||
return s
|
||||
end
|
||||
|
||||
local function list(tbl)
|
||||
return iif(#tbl > 0, " "..table.concat(tbl, " "), "")
|
||||
end
|
||||
|
||||
local function build_command(cfg, cc, file)
|
||||
local cmdline = ""
|
||||
local function app(s) cmdline = cmdline..s end
|
||||
|
||||
-- Compiler
|
||||
if path.iscfile(file) or path.isasmfile(file) then
|
||||
app(cc.cc)
|
||||
else
|
||||
app(cc.cxx)
|
||||
end
|
||||
|
||||
-- Flags / Defines / Includes
|
||||
app(list(cc.getcppflags(cfg)))
|
||||
app(list(cc.getdefines(cfg.defines)))
|
||||
app(list(cc.getincludedirs(cfg.includedirs)))
|
||||
app(list(cc.getquoteincludedirs(cfg.userincludedirs)))
|
||||
app(list(cc.getsystemincludedirs(cfg.systemincludedirs)))
|
||||
|
||||
-- Custom build options
|
||||
app(list(cc.getcflags(cfg)))
|
||||
|
||||
if path.iscppfile(file) then
|
||||
app(list(cc.getcxxflags(cfg)))
|
||||
end
|
||||
|
||||
if path.isasmfile(file) then
|
||||
app(list(cfg.buildoptions))
|
||||
app(list(cfg.buildoptions_asm))
|
||||
elseif path.isobjcfile(file) then
|
||||
local opts = iif(path.iscfile(file), cfg.buildoptions_objc, cfg.buildoptions_objcpp)
|
||||
app(list(cc.getobjcflags(cfg)))
|
||||
app(list(cfg.buildoptions))
|
||||
app(list(opts))
|
||||
elseif path.iscfile(file) then
|
||||
app(list(cfg.buildoptions))
|
||||
app(list(cfg.buildoptions_c))
|
||||
else
|
||||
app(list(cfg.buildoptions))
|
||||
app(list(cfg.buildoptions_cpp))
|
||||
end
|
||||
|
||||
-- Forced includes
|
||||
if cfg.pchheader and not cfg.flags.NoPCH then
|
||||
-- No need to worry about gch files or anything. Using the pch directly
|
||||
-- should have the same behavior for our purposes.
|
||||
app(" -include ")
|
||||
app(escape_cmdline_arg(cfg.pchheader))
|
||||
end
|
||||
|
||||
for _, i in ipairs(cfg.forcedincludes) do
|
||||
app(" -include ")
|
||||
app(escape_cmdline_arg(i))
|
||||
end
|
||||
|
||||
-- Input / Output
|
||||
local base = path.trimdots(path.removeext(file))..".o"
|
||||
local output = path.join(cfg.objectsdir, base)
|
||||
app(" -o ")
|
||||
app(escape_cmdline_arg(output))
|
||||
app(" -c ")
|
||||
app(escape_cmdline_arg(file))
|
||||
|
||||
return cmdline
|
||||
end
|
||||
|
||||
function jcdb.generate_config(prj, cfg, cc)
|
||||
table.sort(cfg.files)
|
||||
|
||||
local directory = path.getabsolute(prj.location)
|
||||
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.iscppfile(file) or path.isasmfile(file) then
|
||||
_p(' { "directory": %s,', encode_string(directory))
|
||||
_p(' "command": %s,', encode_string(build_command(cfg, cc, file)))
|
||||
_p(' "file": %s },', encode_string(file))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function jcdb.generate_project(prj)
|
||||
local cc = premake.gettool(prj)
|
||||
local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native")
|
||||
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in premake.eachconfig(prj, platform) do
|
||||
jcdb.generate_config(prj, cfg, cc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function jcdb.generate(sln)
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
jcdb.generate_project(prj)
|
||||
end
|
||||
|
||||
-- Remove the last comma as JSON doesn't permit trailing commas
|
||||
io.captured = io.captured:gsub(",%s$", "")
|
||||
|
||||
-- Wrap in brackets
|
||||
io.captured = "["..io.eol..io.captured..io.eol.."]"
|
||||
end
|
||||
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
--
|
||||
-- _make.lua
|
||||
-- Define the makefile action(s).
|
||||
-- Copyright (c) 2002-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
_MAKE = { }
|
||||
premake.make = { }
|
||||
local make = premake.make
|
||||
|
||||
--
|
||||
-- Escape a string so it can be written to a makefile.
|
||||
--
|
||||
|
||||
function _MAKE.esc(value)
|
||||
local result
|
||||
if (type(value) == "table") then
|
||||
result = { }
|
||||
for _,v in ipairs(value) do
|
||||
table.insert(result, _MAKE.esc(v))
|
||||
end
|
||||
return result
|
||||
else
|
||||
-- handle simple replacements
|
||||
result = value:gsub("\\", "\\\\")
|
||||
result = result:gsub(" ", "\\ ")
|
||||
result = result:gsub("%%(", "\\%(")
|
||||
result = result:gsub("%%)", "\\%)")
|
||||
|
||||
-- leave $(...) shell replacement sequences alone
|
||||
result = result:gsub("$\\%((.-)\\%)", "$%(%1%)")
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Escape quoted string so it can be passed as define via command line.
|
||||
--
|
||||
|
||||
function _MAKE.escquote(value)
|
||||
local result
|
||||
if (type(value) == "table") then
|
||||
result = { }
|
||||
for _,v in ipairs(value) do
|
||||
table.insert(result, _MAKE.escquote(v))
|
||||
end
|
||||
return result
|
||||
else
|
||||
-- handle simple replacements
|
||||
result = value:gsub(" ", "\\ ")
|
||||
result = result:gsub("\"", "\\\"")
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Rules for file ops based on the shell type. Can't use defines and $@ because
|
||||
-- it screws up the escaping of spaces and parethesis (anyone know a solution?)
|
||||
--
|
||||
|
||||
function premake.make_copyrule(source, target)
|
||||
_p('%s: %s', target, source)
|
||||
_p('\t@echo Copying $(notdir %s)', target)
|
||||
_p('\t-$(call COPY,%s,%s)', source, target)
|
||||
end
|
||||
|
||||
function premake.make_mkdirrule(var)
|
||||
_p('\t@echo Creating %s', var)
|
||||
_p('\t-$(call MKDIR,%s)', var)
|
||||
_p('')
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Format a list of values to be safely written as part of a variable assignment.
|
||||
--
|
||||
|
||||
function make.list(value)
|
||||
if #value > 0 then
|
||||
return " " .. table.concat(value, " ")
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Get the makefile file name for a solution or a project. If this object is the
|
||||
-- only one writing to a location then I can use "Makefile". If more than one object
|
||||
-- writes to the same location I use name + ".make" to keep it unique.
|
||||
--
|
||||
|
||||
function _MAKE.getmakefilename(this, searchprjs)
|
||||
-- how many projects/solutions use this location?
|
||||
local count = 0
|
||||
for sln in premake.solution.each() do
|
||||
if (sln.location == this.location) then count = count + 1 end
|
||||
if (searchprjs) then
|
||||
for _,prj in ipairs(sln.projects) do
|
||||
if (prj.location == this.location) then count = count + 1 end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (count == 1) then
|
||||
return "Makefile"
|
||||
else
|
||||
return this.name .. ".make"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns a list of object names, properly escaped to be included in the makefile.
|
||||
--
|
||||
|
||||
function _MAKE.getnames(tbl)
|
||||
local result = table.extract(tbl, "name")
|
||||
for k,v in pairs(result) do
|
||||
result[k] = _MAKE.esc(v)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Write out the raw settings blocks.
|
||||
--
|
||||
|
||||
function make.settings(cfg, cc)
|
||||
if #cfg.makesettings > 0 then
|
||||
for _, value in ipairs(cfg.makesettings) do
|
||||
_p(value)
|
||||
end
|
||||
end
|
||||
|
||||
local toolsettings = cc.platforms[cfg.platform].cfgsettings
|
||||
if toolsettings then
|
||||
_p(toolsettings)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Register the "gmake" action
|
||||
--
|
||||
|
||||
newaction {
|
||||
trigger = "gmake",
|
||||
shortname = "GNU Make",
|
||||
description = "Generate GNU makefiles for POSIX, MinGW, and Cygwin",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++", "C#", "Vala", "Swift" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "gcc", "ghs" },
|
||||
dotnet = { "mono", "msnet", "pnet" },
|
||||
valac = { "valac" },
|
||||
swift = { "swift" },
|
||||
},
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, _MAKE.getmakefilename(sln, false), premake.make_solution)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
local makefile = _MAKE.getmakefilename(prj, true)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, makefile, premake.make_csharp)
|
||||
elseif premake.iscppproject(prj) then
|
||||
premake.generate(prj, makefile, premake.make_cpp)
|
||||
elseif premake.isswiftproject(prj) then
|
||||
premake.generate(prj, makefile, premake.make_swift)
|
||||
else
|
||||
premake.generate(prj, makefile, premake.make_vala)
|
||||
end
|
||||
end,
|
||||
|
||||
oncleansolution = function(sln)
|
||||
premake.clean.file(sln, _MAKE.getmakefilename(sln, false))
|
||||
end,
|
||||
|
||||
oncleanproject = function(prj)
|
||||
premake.clean.file(prj, _MAKE.getmakefilename(prj, true))
|
||||
end,
|
||||
|
||||
gmake = {}
|
||||
}
|
||||
+674
@@ -0,0 +1,674 @@
|
||||
-- --
|
||||
-- make_cpp.lua
|
||||
-- Generate a C/C++ project makefile.
|
||||
-- Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.make.cpp = { }
|
||||
premake.make.override = { }
|
||||
premake.make.makefile_ignore = false
|
||||
|
||||
local cpp = premake.make.cpp
|
||||
local make = premake.make
|
||||
|
||||
function premake.make_cpp(prj)
|
||||
|
||||
-- create a shortcut to the compiler interface
|
||||
local cc = premake.gettool(prj)
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native")
|
||||
|
||||
-- output build configurations
|
||||
local action = premake.action.current()
|
||||
premake.gmake_cpp_header(prj, cc, platforms)
|
||||
premake.gmake_cpp_configs(prj, cc, platforms)
|
||||
table.sort(prj.allfiles)
|
||||
|
||||
-- list object directories
|
||||
local objdirs = {}
|
||||
local additionalobjdirs = {}
|
||||
for _, file in ipairs(prj.allfiles) do
|
||||
if path.issourcefile(file) then
|
||||
objdirs[_MAKE.esc(path.getdirectory(path.trimdots(file)))] = 1
|
||||
end
|
||||
end
|
||||
|
||||
for _, custombuildtask in ipairs(prj.custombuildtask or {}) do
|
||||
for _, buildtask in ipairs(custombuildtask or {}) do
|
||||
additionalobjdirs[_MAKE.esc(path.getdirectory(path.getrelative(prj.location,buildtask[2])))] = 1
|
||||
end
|
||||
end
|
||||
|
||||
_p('OBJDIRS := \\')
|
||||
_p('\t$(OBJDIR) \\')
|
||||
for dir, _ in iter.sortByKeys(objdirs) do
|
||||
_p('\t$(OBJDIR)/%s \\', dir)
|
||||
end
|
||||
for dir, _ in iter.sortByKeys(additionalobjdirs) do
|
||||
_p('\t%s \\', dir)
|
||||
end
|
||||
_p('')
|
||||
|
||||
_p('RESOURCES := \\')
|
||||
for _, file in ipairs(prj.allfiles) do
|
||||
if path.isresourcefile(file) then
|
||||
_p('\t$(OBJDIR)/%s.res \\', _MAKE.esc(path.getbasename(file)))
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
-- main build rule(s)
|
||||
_p('.PHONY: clean prebuild prelink')
|
||||
_p('')
|
||||
|
||||
if os.is("MacOSX") and prj.kind == "WindowedApp" and not prj.options.SkipBundling then
|
||||
_p('all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist')
|
||||
else
|
||||
_p('all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET)')
|
||||
end
|
||||
_p('\t@:')
|
||||
_p('')
|
||||
|
||||
if (prj.kind == "StaticLib" and prj.options.ArchiveSplit) then
|
||||
_p('define max_args')
|
||||
_p('\t$(eval _args:=)')
|
||||
_p('\t$(foreach obj,$3,$(eval _args+=$(obj))$(if $(word $2,$(_args)),$1 $(_args)$(EOL)$(eval _args:=)))')
|
||||
_p('\t$(if $(_args),$1 $(_args))')
|
||||
_p('endef')
|
||||
_p('')
|
||||
_p('define EOL')
|
||||
_p('')
|
||||
_p('')
|
||||
_p('endef')
|
||||
_p('')
|
||||
end
|
||||
|
||||
-- target build rule
|
||||
_p('$(TARGET): $(GCH) $(OBJECTS) $(LIBDEPS) $(EXTERNAL_LIBS) $(RESOURCES) $(OBJRESP) $(LDRESP) | $(TARGETDIR) $(OBJDIRS)')
|
||||
|
||||
if prj.kind == "StaticLib" then
|
||||
if prj.msgarchiving then
|
||||
_p('\t@echo ' .. prj.msgarchiving)
|
||||
else
|
||||
_p('\t@echo Archiving %s', prj.name)
|
||||
end
|
||||
if (not prj.archivesplit_size) then
|
||||
prj.archivesplit_size=200
|
||||
end
|
||||
if (not prj.options.ArchiveSplit) then
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p('\t$(SILENT) rm -f $(TARGET)')
|
||||
_p('else')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))')
|
||||
_p('endif')
|
||||
_p('\t$(SILENT) $(LINKCMD) $(LINKOBJS)' .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))
|
||||
else
|
||||
_p('\t$(call RM,$(TARGET))')
|
||||
_p('\t@$(call max_args,$(LINKCMD),'.. prj.archivesplit_size ..',$(LINKOBJS))' .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))
|
||||
_p('\t$(SILENT) $(LINKCMD_NDX)')
|
||||
end
|
||||
else
|
||||
if prj.msglinking then
|
||||
_p('\t@echo ' .. prj.msglinking)
|
||||
else
|
||||
_p('\t@echo Linking %s', prj.name)
|
||||
end
|
||||
_p('\t$(SILENT) $(LINKCMD)')
|
||||
end
|
||||
|
||||
_p('\t$(POSTBUILDCMDS)')
|
||||
_p('')
|
||||
|
||||
-- Create destination directories. Can't use $@ for this because it loses the
|
||||
-- escaping, causing issues with spaces and parenthesis
|
||||
_p('$(TARGETDIR):')
|
||||
premake.make_mkdirrule("$(TARGETDIR)")
|
||||
|
||||
_p('$(OBJDIRS):')
|
||||
if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCreatingMessage")) then
|
||||
_p('\t@echo Creating $(@)')
|
||||
end
|
||||
_p('\t-$(call MKDIR,$@)')
|
||||
_p('')
|
||||
|
||||
-- Mac OS X specific targets
|
||||
if os.is("MacOSX") and prj.kind == "WindowedApp" and not prj.options.SkipBundling then
|
||||
_p('$(dir $(TARGETDIR))PkgInfo:')
|
||||
_p('$(dir $(TARGETDIR))Info.plist:')
|
||||
_p('')
|
||||
end
|
||||
|
||||
-- clean target
|
||||
_p('clean:')
|
||||
if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCleaningMessage")) then
|
||||
_p('\t@echo Cleaning %s', prj.name)
|
||||
end
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p('\t$(SILENT) rm -f $(TARGET)')
|
||||
_p('\t$(SILENT) rm -rf $(OBJDIR)')
|
||||
_p('else')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- custom build step targets
|
||||
_p('prebuild:')
|
||||
_p('\t$(PREBUILDCMDS)')
|
||||
_p('')
|
||||
|
||||
_p('prelink:')
|
||||
_p('\t$(PRELINKCMDS)')
|
||||
_p('')
|
||||
|
||||
-- precompiler header rule
|
||||
cpp.pchrules(prj)
|
||||
|
||||
-- per-file build rules
|
||||
cpp.fileRules(prj, cc)
|
||||
|
||||
-- per-dependency build rules
|
||||
cpp.dependencyRules(prj)
|
||||
|
||||
for _, custombuildtask in ipairs(prj.custombuildtask or {}) do
|
||||
for _, buildtask in ipairs(custombuildtask or {}) do
|
||||
local deps = string.format("%s ",path.getrelative(prj.location,buildtask[1]))
|
||||
for _, depdata in ipairs(buildtask[3] or {}) do
|
||||
deps = deps .. string.format("%s ",path.getrelative(prj.location,depdata))
|
||||
end
|
||||
_p('%s: %s | $(TARGETDIR) $(OBJDIRS)'
|
||||
,path.getrelative(prj.location,buildtask[2])
|
||||
, deps
|
||||
)
|
||||
for _, cmdline in ipairs(buildtask[4] or {}) do
|
||||
local cmd = cmdline
|
||||
local num = 1
|
||||
for _, depdata in ipairs(buildtask[3] or {}) do
|
||||
cmd = string.gsub(cmd,"%$%(" .. num .."%)", string.format("%s ",path.getrelative(prj.location,depdata)))
|
||||
num = num + 1
|
||||
end
|
||||
cmd = string.gsub(cmd, "%$%(<%)", "$<")
|
||||
cmd = string.gsub(cmd, "%$%(@%)", "$@")
|
||||
|
||||
_p('\t$(SILENT) %s',cmd)
|
||||
|
||||
end
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
|
||||
-- include the dependencies, built by GCC (with the -MMD flag)
|
||||
_p('-include $(OBJECTS:%%.o=%%.d)')
|
||||
_p('ifneq (,$(PCH))')
|
||||
_p(' -include $(OBJDIR)/$(notdir $(PCH)).d')
|
||||
_p(' -include $(OBJDIR)/$(notdir $(PCH))_objc.d')
|
||||
_p('endif')
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Write the makefile header
|
||||
--
|
||||
|
||||
function premake.gmake_cpp_header(prj, cc, platforms)
|
||||
_p('# %s project makefile autogenerated by GENie', premake.action.current().shortname)
|
||||
_p('')
|
||||
|
||||
_p('.SUFFIXES:') -- Delete the default suffix rules.
|
||||
_p('')
|
||||
|
||||
-- set up the environment
|
||||
_p('ifndef config')
|
||||
_p(' config=%s', _MAKE.esc(premake.getconfigname(prj.solution.configurations[1], platforms[1], true)))
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifndef verbose')
|
||||
_p(' SILENT = @')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- identify the shell type
|
||||
_p('SHELLTYPE := msdos')
|
||||
_p('ifeq (,$(ComSpec)$(COMSPEC))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(SHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p(' MKDIR = $(SILENT) mkdir -p "$(1)"')
|
||||
_p(' COPY = $(SILENT) cp -fR "$(1)" "$(2)"')
|
||||
_p(' RM = $(SILENT) rm -f "$(1)"')
|
||||
_p('else')
|
||||
_p(' MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul || exit 0')
|
||||
_p(' COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"')
|
||||
_p(' RM = $(SILENT) del /F "$(subst /,\\\\,$(1))" 2> nul || exit 0')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('CC = %s', cc.cc)
|
||||
_p('CXX = %s', cc.cxx)
|
||||
_p('AR = %s', cc.ar)
|
||||
_p('')
|
||||
|
||||
_p('ifndef RESCOMP')
|
||||
_p(' ifdef WINDRES')
|
||||
_p(' RESCOMP = $(WINDRES)')
|
||||
_p(' else')
|
||||
_p(' RESCOMP = %s', cc.rc or 'windres')
|
||||
_p(' endif')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
if (not premake.make.makefile_ignore) then
|
||||
_p('MAKEFILE = %s', _MAKE.getmakefilename(prj, true))
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Write a block of configuration settings.
|
||||
--
|
||||
|
||||
local function is_excluded(prj, cfg, file)
|
||||
if table.icontains(prj.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
if table.icontains(cfg.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function premake.gmake_cpp_configs(prj, cc, platforms)
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in premake.eachconfig(prj, platform) do
|
||||
premake.gmake_cpp_config(prj, cfg, cc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function premake.gmake_cpp_config(prj, cfg, cc)
|
||||
_p('ifeq ($(config),%s)', _MAKE.esc(cfg.shortname))
|
||||
|
||||
-- if this platform requires a special compiler or linker, list it here
|
||||
cpp.platformtools(cfg, cc)
|
||||
|
||||
local targetDir = _MAKE.esc(cfg.buildtarget.directory)
|
||||
|
||||
_p(' ' .. (table.contains(premake.make.override,"OBJDIR") and "override " or "") .. 'OBJDIR = %s', _MAKE.esc(cfg.objectsdir))
|
||||
_p(' ' .. (table.contains(premake.make.override,"TARGETDIR") and "override " or "") .. 'TARGETDIR = %s', iif(targetDir == "", ".", targetDir))
|
||||
_p(' ' .. (table.contains(premake.make.override,"TARGET") and "override " or "") .. 'TARGET = $(TARGETDIR)/%s', _MAKE.esc(cfg.buildtarget.name))
|
||||
_p(' DEFINES +=%s', make.list(_MAKE.escquote(cc.getdefines(cfg.defines))))
|
||||
|
||||
local id = make.list(cc.getincludedirs(cfg.includedirs));
|
||||
local uid = make.list(cc.getquoteincludedirs(cfg.userincludedirs))
|
||||
local sid = make.list(cc.getsystemincludedirs(cfg.systemincludedirs))
|
||||
|
||||
if id ~= "" then
|
||||
_p(' INCLUDES +=%s', id)
|
||||
end
|
||||
|
||||
if uid ~= "" then
|
||||
_p(' INCLUDES +=%s', uid)
|
||||
end
|
||||
|
||||
if sid ~= "" then
|
||||
_p(' INCLUDES +=%s', sid)
|
||||
end
|
||||
|
||||
-- set up precompiled headers
|
||||
cpp.pchconfig(cfg)
|
||||
|
||||
-- CPPFLAGS, CFLAGS, CXXFLAGS, and RESFLAGS
|
||||
cpp.flags(cfg, cc)
|
||||
|
||||
-- write out libraries, linker flags, and the link command
|
||||
cpp.linker(prj, cfg, cc)
|
||||
|
||||
table.sort(cfg.files)
|
||||
|
||||
-- add objects for compilation, and remove any that are excluded per config.
|
||||
if cfg.flags.UseObjectResponseFile then
|
||||
_p(' OBJRESP = $(OBJDIR)/%s_objects', prj.name)
|
||||
else
|
||||
_p(' OBJRESP =')
|
||||
end
|
||||
_p(' OBJECTS := \\')
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.issourcefile(file) then
|
||||
-- check if file is excluded.
|
||||
if not is_excluded(prj, cfg, file) then
|
||||
-- if not excluded, add it.
|
||||
_p('\t$(OBJDIR)/%s.o \\'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
_p(' define PREBUILDCMDS')
|
||||
if #cfg.prebuildcommands > 0 then
|
||||
_p('\t@echo Running pre-build commands')
|
||||
_p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p(' define PRELINKCMDS')
|
||||
if #cfg.prelinkcommands > 0 then
|
||||
_p('\t@echo Running pre-link commands')
|
||||
_p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p(' define POSTBUILDCMDS')
|
||||
if #cfg.postbuildcommands > 0 then
|
||||
_p('\t@echo Running post-build commands')
|
||||
_p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
-- write out config-level makesettings blocks
|
||||
make.settings(cfg, cc)
|
||||
|
||||
_p('endif')
|
||||
_p('')
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Platform support
|
||||
--
|
||||
|
||||
function cpp.platformtools(cfg, cc)
|
||||
local platform = cc.platforms[cfg.platform]
|
||||
if platform.cc then
|
||||
_p(' CC = %s', platform.cc)
|
||||
end
|
||||
if platform.cxx then
|
||||
_p(' CXX = %s', platform.cxx)
|
||||
end
|
||||
if platform.ar then
|
||||
_p(' AR = %s', platform.ar)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Configurations
|
||||
--
|
||||
|
||||
function cpp.flags(cfg, cc)
|
||||
|
||||
if cfg.pchheader and not cfg.flags.NoPCH then
|
||||
_p(' FORCE_INCLUDE += -include $(OBJDIR)/$(notdir $(PCH))')
|
||||
_p(' FORCE_INCLUDE_OBJC += -include $(OBJDIR)/$(notdir $(PCH))_objc')
|
||||
end
|
||||
|
||||
if #cfg.forcedincludes > 0 then
|
||||
_p(' FORCE_INCLUDE += -include %s'
|
||||
,_MAKE.esc(table.concat(cfg.forcedincludes, ";")))
|
||||
end
|
||||
|
||||
_p(' ALL_CPPFLAGS += $(CPPFLAGS) %s $(DEFINES) $(INCLUDES)', table.concat(cc.getcppflags(cfg), " "))
|
||||
|
||||
_p(' ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_asm)))
|
||||
_p(' ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_c)))
|
||||
_p(' ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cc.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_cpp)))
|
||||
_p(' ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cc.getobjcflags(cfg), cfg.buildoptions, cfg.buildoptions_objc)))
|
||||
_p(' ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cc.getcxxflags(cfg), cc.getobjcflags(cfg), cfg.buildoptions, cfg.buildoptions_objcpp)))
|
||||
|
||||
_p(' ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)%s',
|
||||
make.list(table.join(cc.getdefines(cfg.resdefines),
|
||||
cc.getincludedirs(cfg.resincludedirs), cfg.resoptions)))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Linker settings, including the libraries to link, the linker flags,
|
||||
-- and the linker command.
|
||||
--
|
||||
|
||||
function cpp.linker(prj, cfg, cc)
|
||||
local libdeps
|
||||
local lddeps
|
||||
|
||||
if #cfg.wholearchive > 0 then
|
||||
libdeps = {}
|
||||
lddeps = {}
|
||||
|
||||
for _, linkcfg in ipairs(premake.getlinks(cfg, "siblings", "object")) do
|
||||
local linkpath = path.rebase(linkcfg.linktarget.fullpath, linkcfg.location, cfg.location)
|
||||
|
||||
if table.icontains(cfg.wholearchive, linkcfg.project.name) then
|
||||
lddeps = table.join(lddeps, cc.wholearchive(linkpath))
|
||||
else
|
||||
table.insert(lddeps, linkpath)
|
||||
end
|
||||
|
||||
table.insert(libdeps, linkpath)
|
||||
end
|
||||
|
||||
libdeps = make.list(_MAKE.esc(libdeps))
|
||||
lddeps = make.list(_MAKE.esc(lddeps))
|
||||
else
|
||||
libdeps = make.list(_MAKE.esc(premake.getlinks(cfg, "siblings", "fullpath")))
|
||||
lddeps = libdeps
|
||||
end
|
||||
|
||||
_p(' ALL_LDFLAGS += $(LDFLAGS)%s', make.list(table.join(cc.getlibdirflags(cfg), cc.getldflags(cfg), cfg.linkoptions)))
|
||||
_p(' LIBDEPS +=%s', libdeps)
|
||||
_p(' LDDEPS +=%s', lddeps)
|
||||
|
||||
if cfg.flags.UseLDResponseFile then
|
||||
_p(' LDRESP = $(OBJDIR)/%s_libs', prj.name)
|
||||
_p(' LIBS += @$(LDRESP)%s', make.list(cc.getlinkflags(cfg)))
|
||||
else
|
||||
_p(' LDRESP =')
|
||||
_p(' LIBS += $(LDDEPS)%s', make.list(cc.getlinkflags(cfg)))
|
||||
end
|
||||
|
||||
_p(' EXTERNAL_LIBS +=%s', make.list(cc.getlibfiles(cfg)))
|
||||
_p(' LINKOBJS = %s', (cfg.flags.UseObjectResponseFile and "@$(OBJRESP)" or "$(OBJECTS)"))
|
||||
|
||||
if cfg.kind == "StaticLib" then
|
||||
if (not prj.options.ArchiveSplit) then
|
||||
_p(' LINKCMD = $(AR) %s $(TARGET)', make.list(cc.getarchiveflags(prj, cfg, false)))
|
||||
else
|
||||
_p(' LINKCMD = $(AR) %s $(TARGET)', make.list(cc.getarchiveflags(prj, cfg, false)))
|
||||
_p(' LINKCMD_NDX = $(AR) %s $(TARGET)', make.list(cc.getarchiveflags(prj, cfg, true)))
|
||||
end
|
||||
else
|
||||
local tool = iif(cfg.language == "C", "CC", "CXX")
|
||||
local startgroup = ''
|
||||
local endgroup = ''
|
||||
if (cfg.flags.LinkSupportCircularDependencies) then
|
||||
startgroup = '-Wl,--start-group '
|
||||
endgroup = ' -Wl,--end-group'
|
||||
end
|
||||
_p(' LINKCMD = $(%s) -o $(TARGET) $(LINKOBJS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) %s$(LIBS)%s', tool, startgroup, endgroup)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Precompiled header support
|
||||
--
|
||||
|
||||
function cpp.pchconfig(cfg)
|
||||
|
||||
-- If there is no header, or if PCH has been disabled, I can early out
|
||||
|
||||
if not cfg.pchheader or cfg.flags.NoPCH then
|
||||
return
|
||||
end
|
||||
|
||||
-- Visual Studio requires the PCH header to be specified in the same way
|
||||
-- it appears in the #include statements used in the source code; the PCH
|
||||
-- source actual handles the compilation of the header. GCC compiles the
|
||||
-- header file directly, and needs the file's actual file system path in
|
||||
-- order to locate it.
|
||||
|
||||
-- To maximize the compatibility between the two approaches, see if I can
|
||||
-- locate the specified PCH header on one of the include file search paths
|
||||
-- and, if so, adjust the path automatically so the user doesn't have
|
||||
-- add a conditional configuration to the project script.
|
||||
|
||||
local pch = cfg.pchheader
|
||||
for _, incdir in ipairs(cfg.includedirs) do
|
||||
|
||||
-- convert this back to an absolute path for os.isfile()
|
||||
local abspath = path.getabsolute(path.join(cfg.project.location, incdir))
|
||||
|
||||
local testname = path.join(abspath, pch)
|
||||
if os.isfile(testname) then
|
||||
pch = path.getrelative(cfg.location, testname)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
_p(' PCH = %s', _MAKE.esc(pch))
|
||||
_p(' GCH = $(OBJDIR)/$(notdir $(PCH)).gch')
|
||||
_p(' GCH_OBJC = $(OBJDIR)/$(notdir $(PCH))_objc.gch')
|
||||
|
||||
end
|
||||
|
||||
|
||||
function cpp.pchrules(prj)
|
||||
_p('ifneq (,$(PCH))')
|
||||
_p('$(GCH): $(PCH) $(MAKEFILE) | $(OBJDIR)')
|
||||
if prj.msgprecompile then
|
||||
_p('\t@echo ' .. prj.msgprecompile)
|
||||
else
|
||||
_p('\t@echo $(notdir $<)')
|
||||
end
|
||||
|
||||
local cmd = iif(prj.language == "C", "$(CC) $(ALL_CFLAGS) -x c-header", "$(CXX) $(ALL_CXXFLAGS) -x c++-header")
|
||||
_p('\t$(SILENT) %s $(DEFINES) $(INCLUDES) -o "$@" -c "$<"', cmd)
|
||||
|
||||
_p('')
|
||||
|
||||
_p('$(GCH_OBJC): $(PCH) $(MAKEFILE) | $(OBJDIR)')
|
||||
if prj.msgprecompile then
|
||||
_p('\t@echo ' .. prj.msgprecompile)
|
||||
else
|
||||
_p('\t@echo $(notdir $<)')
|
||||
end
|
||||
|
||||
local cmd = iif(prj.language == "C", "$(CC) $(ALL_OBJCFLAGS) -x objective-c-header", "$(CXX) $(ALL_OBJCPPFLAGS) -x objective-c++-header")
|
||||
_p('\t$(SILENT) %s $(DEFINES) $(INCLUDES) -o "$@" -c "$<"', cmd)
|
||||
|
||||
_p('endif')
|
||||
_p('')
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Build command for a single file.
|
||||
--
|
||||
|
||||
function cpp.fileRules(prj, cc)
|
||||
local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native")
|
||||
|
||||
_p('ifneq (,$(OBJRESP))')
|
||||
_p('$(OBJRESP): $(OBJECTS) | $(TARGETDIR) $(OBJDIRS)')
|
||||
_p('\t$(SILENT) echo $^')
|
||||
_p('\t$(SILENT) echo $^ > $@')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifneq (,$(LDRESP))')
|
||||
_p('$(LDRESP): $(LDDEPS) | $(TARGETDIR) $(OBJDIRS)')
|
||||
_p('\t$(SILENT) echo $^')
|
||||
_p('\t$(SILENT) echo $^ > $@')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
table.sort(prj.allfiles)
|
||||
for _, file in ipairs(prj.allfiles or {}) do
|
||||
if path.issourcefile(file) then
|
||||
if (path.isobjcfile(file)) then
|
||||
_p('$(OBJDIR)/%s.o: %s $(GCH_OBJC) $(MAKEFILE) | $(OBJDIR)/%s'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
, _MAKE.esc(file)
|
||||
, _MAKE.esc(path.getdirectory(path.trimdots(file)))
|
||||
)
|
||||
else
|
||||
_p('$(OBJDIR)/%s.o: %s $(GCH) $(MAKEFILE) | $(OBJDIR)/%s'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
, _MAKE.esc(file)
|
||||
, _MAKE.esc(path.getdirectory(path.trimdots(file)))
|
||||
)
|
||||
end
|
||||
if (path.isobjcfile(file) and prj.msgcompile_objc) then
|
||||
_p('\t@echo ' .. prj.msgcompile_objc)
|
||||
elseif prj.msgcompile then
|
||||
_p('\t@echo ' .. prj.msgcompile)
|
||||
else
|
||||
_p('\t@echo $(notdir $<)')
|
||||
end
|
||||
if (path.isobjcfile(file)) then
|
||||
if (path.iscfile(file)) then
|
||||
_p('\t$(SILENT) $(CXX) $(ALL_OBJCFLAGS) $(FORCE_INCLUDE_OBJC) -o "$@" -c "$<"')
|
||||
else
|
||||
_p('\t$(SILENT) $(CXX) $(ALL_OBJCPPFLAGS) $(FORCE_INCLUDE_OBJC) -o "$@" -c "$<"')
|
||||
end
|
||||
elseif (path.isasmfile(file)) then
|
||||
_p('\t$(SILENT) $(CC) $(ALL_ASMFLAGS) -o "$@" -c "$<"')
|
||||
else
|
||||
cpp.buildcommand(path.iscfile(file) and not prj.options.ForceCPP, "o")
|
||||
end
|
||||
for _, task in ipairs(prj.postcompiletasks or {}) do
|
||||
_p('\t$(SILENT) %s', task)
|
||||
_p('')
|
||||
end
|
||||
|
||||
_p('')
|
||||
elseif (path.getextension(file) == ".rc") then
|
||||
_p('$(OBJDIR)/%s.res: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file))
|
||||
if prj.msgresource then
|
||||
_p('\t@echo ' .. prj.msgresource)
|
||||
else
|
||||
_p('\t@echo $(notdir $<)')
|
||||
end
|
||||
_p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(ALL_RESFLAGS)')
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cpp.dependencyRules(prj)
|
||||
for _, dependency in ipairs(prj.dependency or {}) do
|
||||
for _, dep in ipairs(dependency or {}) do
|
||||
if (dep[3]==nil or dep[3]==false) then
|
||||
_p('$(OBJDIR)/%s.o: %s'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(path.getrelative(prj.location, dep[1]))))
|
||||
, _MAKE.esc(path.getrelative(prj.location, dep[2]))
|
||||
)
|
||||
else
|
||||
_p('%s: %s'
|
||||
, _MAKE.esc(dep[1])
|
||||
, _MAKE.esc(path.getrelative(prj.location, dep[2]))
|
||||
)
|
||||
end
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function cpp.buildcommand(iscfile, objext)
|
||||
local flags = iif(iscfile, '$(CC) $(ALL_CFLAGS)', '$(CXX) $(ALL_CXXFLAGS)')
|
||||
_p('\t$(SILENT) %s $(FORCE_INCLUDE) -o "$@" -c "$<"', flags, objext)
|
||||
end
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
--
|
||||
-- make_csharp.lua
|
||||
-- Generate a C# project makefile.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
--
|
||||
-- Given a .resx resource file, builds the path to corresponding .resource
|
||||
-- file, matching the behavior and naming of Visual Studio.
|
||||
--
|
||||
|
||||
local function getresourcefilename(cfg, fname)
|
||||
if path.getextension(fname) == ".resx" then
|
||||
local name = cfg.buildtarget.basename .. "."
|
||||
local dir = path.getdirectory(fname)
|
||||
if dir ~= "." then
|
||||
name = name .. path.translate(dir, ".") .. "."
|
||||
end
|
||||
return "$(OBJDIR)/" .. _MAKE.esc(name .. path.getbasename(fname)) .. ".resources"
|
||||
else
|
||||
return fname
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Main function
|
||||
--
|
||||
|
||||
function premake.make_csharp(prj)
|
||||
local csc = premake.dotnet
|
||||
|
||||
-- Do some processing up front: build a list of configuration-dependent libraries.
|
||||
-- Libraries that are built to a location other than $(TARGETDIR) will need to
|
||||
-- be copied so they can be found at runtime.
|
||||
local cfglibs = { }
|
||||
local cfgpairs = { }
|
||||
local anycfg
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
anycfg = cfg
|
||||
cfglibs[cfg] = premake.getlinks(cfg, "siblings", "fullpath")
|
||||
cfgpairs[cfg] = { }
|
||||
for _, fname in ipairs(cfglibs[cfg]) do
|
||||
if path.getdirectory(fname) ~= cfg.buildtarget.directory then
|
||||
cfgpairs[cfg]["$(TARGETDIR)/" .. _MAKE.esc(path.getname(fname))] = _MAKE.esc(fname)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- sort the files into categories, based on their build action
|
||||
local sources = {}
|
||||
local embedded = { }
|
||||
local copypairs = { }
|
||||
|
||||
for fcfg in premake.project.eachfile(prj) do
|
||||
local action = csc.getbuildaction(fcfg)
|
||||
if action == "Compile" then
|
||||
table.insert(sources, fcfg.name)
|
||||
elseif action == "EmbeddedResource" then
|
||||
table.insert(embedded, fcfg.name)
|
||||
elseif action == "Content" then
|
||||
copypairs["$(TARGETDIR)/" .. _MAKE.esc(path.getname(fcfg.name))] = _MAKE.esc(fcfg.name)
|
||||
elseif path.getname(fcfg.name):lower() == "app.config" then
|
||||
copypairs["$(TARGET).config"] = _MAKE.esc(fcfg.name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Any assemblies that are on the library search paths should be copied
|
||||
-- to $(TARGETDIR) so they can be found at runtime
|
||||
local paths = table.translate(prj.libdirs, function(v) return path.join(prj.basedir, v) end)
|
||||
paths = table.join({prj.basedir}, paths)
|
||||
for _, libname in ipairs(premake.getlinks(prj, "system", "fullpath")) do
|
||||
local libdir = os.pathsearch(libname..".dll", unpack(paths))
|
||||
if (libdir) then
|
||||
local target = "$(TARGETDIR)/" .. _MAKE.esc(path.getname(libname))
|
||||
local source = path.getrelative(prj.basedir, path.join(libdir, libname))..".dll"
|
||||
copypairs[target] = _MAKE.esc(source)
|
||||
end
|
||||
end
|
||||
|
||||
-- end of preprocessing --
|
||||
|
||||
|
||||
-- set up the environment
|
||||
_p('# %s project makefile autogenerated by GENie', premake.action.current().shortname)
|
||||
_p('')
|
||||
|
||||
_p('.SUFFIXES:') -- Delete the default suffix rules.
|
||||
_p('')
|
||||
|
||||
_p('ifndef config')
|
||||
_p(' config=%s', _MAKE.esc(prj.configurations[1]:lower()))
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifndef verbose')
|
||||
_p(' SILENT = @')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- identify the shell type
|
||||
_p('SHELLTYPE := msdos')
|
||||
_p('ifeq (,$(ComSpec)$(COMSPEC))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(SHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p(' MKDIR = $(SILENT) mkdir -p "$(1)"')
|
||||
_p(' COPY = $(SILENT) cp -fR "$(1)" "$(2)"')
|
||||
_p('else')
|
||||
_p(' MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul')
|
||||
_p(' COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifndef CSC')
|
||||
_p(' CSC=%s', csc.getcompilervar(prj))
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifndef RESGEN')
|
||||
_p(' RESGEN=resgen')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- Platforms aren't support for .NET projects, but I need the ability to match
|
||||
-- the buildcfg:platform identifiers with a block of settings. So enumerate the
|
||||
-- pairs the same way I do for C/C++ projects, but always use the generic settings
|
||||
local platforms = premake.filterplatforms(prj.solution, premake[_OPTIONS.cc].platforms)
|
||||
table.insert(platforms, 1, "")
|
||||
|
||||
-- write the configuration blocks
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
premake.gmake_cs_config(cfg, csc, cfglibs)
|
||||
end
|
||||
|
||||
-- set project level values
|
||||
_p('# To maintain compatibility with VS.NET, these values must be set at the project level')
|
||||
_p('TARGET := $(TARGETDIR)/%s', _MAKE.esc(prj.buildtarget.name))
|
||||
_p('FLAGS += /t:%s %s', csc.getkind(prj):lower(), table.implode(_MAKE.esc(prj.libdirs), "/lib:", "", " "))
|
||||
_p('REFERENCES += %s', table.implode(_MAKE.esc(premake.getlinks(prj, "system", "basename")), "/r:", ".dll", " "))
|
||||
_p('')
|
||||
|
||||
-- list source files
|
||||
_p('SOURCES := \\')
|
||||
for _, fname in ipairs(sources) do
|
||||
_p('\t%s \\', _MAKE.esc(path.translate(fname)))
|
||||
end
|
||||
_p('')
|
||||
|
||||
_p('EMBEDFILES := \\')
|
||||
for _, fname in ipairs(embedded) do
|
||||
_p('\t%s \\', getresourcefilename(prj, fname))
|
||||
end
|
||||
_p('')
|
||||
|
||||
_p('COPYFILES += \\')
|
||||
for target, source in pairs(cfgpairs[anycfg]) do
|
||||
_p('\t%s \\', target)
|
||||
end
|
||||
for target, source in pairs(copypairs) do
|
||||
_p('\t%s \\', target)
|
||||
end
|
||||
_p('')
|
||||
|
||||
-- identify the shell type
|
||||
_p('SHELLTYPE := msdos')
|
||||
_p('ifeq (,$(ComSpec)$(COMSPEC))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(SHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- main build rule(s)
|
||||
_p('.PHONY: clean prebuild prelink')
|
||||
_p('')
|
||||
|
||||
_p('all: $(TARGETDIR) $(OBJDIR) prebuild $(EMBEDFILES) $(COPYFILES) prelink $(TARGET)')
|
||||
_p('')
|
||||
|
||||
_p('$(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS)')
|
||||
_p('\t$(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) $(SOURCES) $(patsubst %%,/resource:%%,$(EMBEDFILES))')
|
||||
_p('\t$(POSTBUILDCMDS)')
|
||||
_p('')
|
||||
|
||||
-- Create destination directories. Can't use $@ for this because it loses the
|
||||
-- escaping, causing issues with spaces and parenthesis
|
||||
_p('$(TARGETDIR):')
|
||||
premake.make_mkdirrule("$(TARGETDIR)")
|
||||
|
||||
_p('$(OBJDIR):')
|
||||
premake.make_mkdirrule("$(OBJDIR)")
|
||||
|
||||
-- clean target
|
||||
_p('clean:')
|
||||
_p('\t@echo Cleaning %s', prj.name)
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p('\t$(SILENT) rm -f $(TARGET) $(COPYFILES)')
|
||||
_p('\t$(SILENT) rm -rf $(OBJDIR)')
|
||||
_p('else')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGETDIR)/%s.*) del $(subst /,\\\\,$(TARGETDIR)/%s.*)', prj.buildtarget.basename, prj.buildtarget.basename)
|
||||
for target, source in pairs(cfgpairs[anycfg]) do
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
|
||||
end
|
||||
for target, source in pairs(copypairs) do
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
|
||||
end
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- custom build step targets
|
||||
_p('prebuild:')
|
||||
_p('\t$(PREBUILDCMDS)')
|
||||
_p('')
|
||||
|
||||
_p('prelink:')
|
||||
_p('\t$(PRELINKCMDS)')
|
||||
_p('')
|
||||
|
||||
-- per-file rules
|
||||
_p('# Per-configuration copied file rules')
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
_p('ifneq (,$(findstring %s,$(config)))', _MAKE.esc(cfg.name:lower()))
|
||||
for target, source in pairs(cfgpairs[cfg]) do
|
||||
premake.make_copyrule(source, target)
|
||||
end
|
||||
_p('endif')
|
||||
_p('')
|
||||
end
|
||||
|
||||
_p('# Copied file rules')
|
||||
for target, source in pairs(copypairs) do
|
||||
premake.make_copyrule(source, target)
|
||||
end
|
||||
|
||||
_p('# Embedded file rules')
|
||||
for _, fname in ipairs(embedded) do
|
||||
if path.getextension(fname) == ".resx" then
|
||||
_p('%s: %s', getresourcefilename(prj, fname), _MAKE.esc(fname))
|
||||
_p('\t$(SILENT) $(RESGEN) $^ $@')
|
||||
end
|
||||
_p('')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Write a block of configuration settings.
|
||||
--
|
||||
|
||||
function premake.gmake_cs_config(cfg, csc, cfglibs)
|
||||
|
||||
local targetDir = _MAKE.esc(cfg.buildtarget.directory)
|
||||
|
||||
_p('ifneq (,$(findstring %s,$(config)))', _MAKE.esc(cfg.name:lower()))
|
||||
_p(' TARGETDIR := %s', iif(targetDir == "", ".", targetDir))
|
||||
_p(' OBJDIR := %s', _MAKE.esc(cfg.objectsdir))
|
||||
_p(' DEPENDS := %s', table.concat(_MAKE.esc(premake.getlinks(cfg, "dependencies", "fullpath")), " "))
|
||||
_p(' REFERENCES := %s', table.implode(_MAKE.esc(cfglibs[cfg]), "/r:", "", " "))
|
||||
_p(' FLAGS += %s %s', table.implode(cfg.defines, "/d:", "", " "), table.concat(table.join(csc.getflags(cfg), cfg.buildoptions), " "))
|
||||
|
||||
_p(' define PREBUILDCMDS')
|
||||
if #cfg.prebuildcommands > 0 then
|
||||
_p('\t@echo Running pre-build commands')
|
||||
_p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p(' define PRELINKCMDS')
|
||||
if #cfg.prelinkcommands > 0 then
|
||||
_p('\t@echo Running pre-link commands')
|
||||
_p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p(' define POSTBUILDCMDS')
|
||||
if #cfg.postbuildcommands > 0 then
|
||||
_p('\t@echo Running post-build commands')
|
||||
_p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
end
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
--
|
||||
-- make_solution.lua
|
||||
-- Generate a solution-level makefile.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
function premake.make_solution(sln)
|
||||
-- create a shortcut to the compiler interface
|
||||
local cc = premake[_OPTIONS.cc]
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(sln, cc.platforms, "Native")
|
||||
|
||||
-- write a header showing the build options
|
||||
_p('# %s solution makefile autogenerated by GENie', premake.action.current().shortname)
|
||||
_p('# Type "make help" for usage help')
|
||||
_p('')
|
||||
|
||||
-- set a default configuration
|
||||
_p('ifndef config')
|
||||
_p(' config=%s', _MAKE.esc(premake.getconfigname(sln.configurations[1], platforms[1], true)))
|
||||
_p('endif')
|
||||
_p('export config')
|
||||
_p('')
|
||||
|
||||
local projects = table.extract(sln.projects, "name")
|
||||
table.sort(projects)
|
||||
|
||||
-- list the projects included in the solution
|
||||
_p('PROJECTS := %s', table.concat(_MAKE.esc(projects), " "))
|
||||
_p('')
|
||||
_p('.PHONY: all clean help $(PROJECTS)')
|
||||
_p('')
|
||||
_p('all: $(PROJECTS)')
|
||||
_p('')
|
||||
|
||||
-- write the project build rules
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
_p('%s: %s', _MAKE.esc(prj.name), table.concat(_MAKE.esc(table.extract(premake.getdependencies(prj), "name")), " "))
|
||||
if (not sln.messageskip) or (not table.contains(sln.messageskip, "SkipBuildingMessage")) then
|
||||
_p('\t@echo "==== Building %s ($(config)) ===="', prj.name)
|
||||
end
|
||||
_p('\t@${MAKE} --no-print-directory -C %s -f %s', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(_MAKE.getmakefilename(prj, true)))
|
||||
_p('')
|
||||
end
|
||||
|
||||
-- clean rules
|
||||
_p('clean:')
|
||||
for _ ,prj in ipairs(sln.projects) do
|
||||
_p('\t@${MAKE} --no-print-directory -C %s -f %s clean', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(_MAKE.getmakefilename(prj, true)))
|
||||
end
|
||||
_p('')
|
||||
|
||||
-- help rule
|
||||
_p('help:')
|
||||
_p(1,'@echo "Usage: make [config=name] [target]"')
|
||||
_p(1,'@echo ""')
|
||||
_p(1,'@echo "CONFIGURATIONS:"')
|
||||
|
||||
local cfgpairs = { }
|
||||
for _, platform in ipairs(platforms) do
|
||||
for _, cfgname in ipairs(sln.configurations) do
|
||||
_p(1,'@echo " %s"', premake.getconfigname(cfgname, platform, true))
|
||||
end
|
||||
end
|
||||
|
||||
_p(1,'@echo ""')
|
||||
_p(1,'@echo "TARGETS:"')
|
||||
_p(1,'@echo " all (default)"')
|
||||
_p(1,'@echo " clean"')
|
||||
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
_p(1,'@echo " %s"', prj.name)
|
||||
end
|
||||
|
||||
_p(1,'@echo ""')
|
||||
_p(1,'@echo "For more information, see https://github.com/bkaradzic/genie"')
|
||||
|
||||
end
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
--
|
||||
-- make_swift.lua
|
||||
-- Generate a Swift project makefile.
|
||||
--
|
||||
|
||||
local make = premake.make
|
||||
local swift = { }
|
||||
|
||||
function premake.make_swift(prj)
|
||||
local tool = premake.gettool(prj)
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native")
|
||||
|
||||
_p('# %s project makefile autogenerated by GENie', premake.action.current().shortname)
|
||||
_p('')
|
||||
|
||||
_p('.SUFFIXES:') -- Delete the default suffix rules.
|
||||
_p('')
|
||||
|
||||
-- set up the environment
|
||||
_p('ifndef config')
|
||||
_p(1, 'config=%s', _MAKE.esc(premake.getconfigname(prj.solution.configurations[1], platforms[1], true)))
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifndef verbose')
|
||||
_p(1, 'SILENT = @')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- identify the shell type
|
||||
_p('SHELLTYPE := msdos')
|
||||
_p('ifeq (,$(ComSpec)$(COMSPEC))')
|
||||
_p(1, 'SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(SHELL)))')
|
||||
_p(1, 'SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))')
|
||||
_p(1, 'SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p(1, 'MKDIR = $(SILENT) mkdir -p "$(1)"')
|
||||
_p(1, 'COPY = $(SILENT) cp -fR "$(1)" "$(2)"')
|
||||
_p(1, 'RM = $(SILENT) rm -f "$(1)"')
|
||||
_p('else')
|
||||
_p(1, 'MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul || exit 0')
|
||||
_p(1, 'COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"')
|
||||
_p(1, 'RM = $(SILENT) del /F "$(subst /,\\\\,$(1))" 2> nul || exit 0')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('SWIFTC = %s', tool.swift)
|
||||
_p('SWIFTLINK = %s', tool.swiftc)
|
||||
_p('DSYMUTIL = %s', tool.dsymutil)
|
||||
_p('AR = %s', tool.ar)
|
||||
_p('')
|
||||
|
||||
-- write configuration blocks
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in premake.eachconfig(prj, platform) do
|
||||
swift.generate_config(prj, cfg, tool)
|
||||
end
|
||||
end
|
||||
|
||||
_p('.PHONY: ')
|
||||
_p('')
|
||||
_p('all: $(WORK_DIRS) $(TARGET)')
|
||||
_p('')
|
||||
|
||||
_p('$(WORK_DIRS):')
|
||||
_p(1, '$(SILENT) $(call MKDIR,$@)')
|
||||
_p('')
|
||||
|
||||
_p('SOURCES := \\')
|
||||
for _, file in ipairs(prj.files) do
|
||||
if path.isswiftfile(file) then
|
||||
_p(1, '%s \\', _MAKE.esc(file))
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
local objfiles = {}
|
||||
_p('OBJECTS_WITNESS := $(OBJDIR)/build.stamp')
|
||||
_p('OBJECTS := \\')
|
||||
for _, file in ipairs(prj.files) do
|
||||
if path.isswiftfile(file) then
|
||||
local objname = _MAKE.esc(swift.objectname(file))
|
||||
table.insert(objfiles, objname)
|
||||
_p(1, '%s \\', objname)
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
swift.file_rules(prj, objfiles)
|
||||
swift.linker(prj, tool)
|
||||
swift.generate_clean(prj)
|
||||
end
|
||||
|
||||
function swift.objectname(file)
|
||||
return path.join("$(OBJDIR)", path.getname(file)..".o")
|
||||
end
|
||||
|
||||
function swift.file_rules(prj, objfiles)
|
||||
-- use a witness file per recommendation for handling multiple outputs
|
||||
-- see https://www.gnu.org/software/automake/manual/html_node/Multiple-Outputs.html
|
||||
_p('$(OBJECTS_WITNESS): $(SOURCES)')
|
||||
_p(1, "@rm -f $(OBJDIR)/data.tmp")
|
||||
_p(1, "@touch $(OBJDIR)/data.tmp")
|
||||
_p(1, "$(SILENT) $(SWIFTC) -frontend -c $(SOURCES) -enable-objc-interop $(SDK) -I $(OUT_DIR) $(SWIFTC_FLAGS) -module-cache-path $(MODULECACHE_DIR) -D SWIFT_PACKAGE $(MODULE_MAPS) -emit-module-doc-path $(OUT_DIR)/$(MODULE_NAME).swiftdoc -module-name $(MODULE_NAME) -emit-module-path $(OUT_DIR)/$(MODULE_NAME).swiftmodule -num-threads 8 %s", table.arglist("-o", objfiles))
|
||||
_p(1, "@mv -f $(OBJDIR)/data.tmp $(OBJECTS_WITNESS)")
|
||||
_p('')
|
||||
|
||||
-- posix only for now
|
||||
_p('$(OBJECTS): $(OBJECTS_WITNESS)')
|
||||
_p(1, '@if test -f $@; then :; else \\')
|
||||
_p(2, 'rm -f $(OBJECTS_WITNESS); \\')
|
||||
_p(2, '$(MAKE) $(AM_MAKEFLAGS) $(OBJECTS_WITNESS); \\')
|
||||
_p(1, 'fi')
|
||||
_p('')
|
||||
end
|
||||
|
||||
function swift.linker(prj, tool)
|
||||
local lddeps = make.list(premake.getlinks(prj, "siblings", "fullpath"))
|
||||
|
||||
if prj.kind == "StaticLib" then
|
||||
_p("$(TARGET): $(OBJECTS) %s ", lddeps)
|
||||
_p(1, "$(SILENT) $(AR) cr $(AR_FLAGS) $@ $(OBJECTS) %s", (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))
|
||||
else
|
||||
_p("$(TARGET): $(OBJECTS) $(LDDEPS)", lddeps)
|
||||
_p(1, "$(SILENT) $(SWIFTLINK) $(SDK) -L $(OUT_DIR) -o $@ $(SWIFTLINK_FLAGS) $(LD_FLAGS) $(OBJECTS)")
|
||||
_p("ifdef SYMBOLS")
|
||||
_p(1, "$(SILENT) $(DSYMUTIL) $(TARGET) -o $(SYMBOLS)")
|
||||
_p("endif")
|
||||
end
|
||||
_p('')
|
||||
end
|
||||
|
||||
function swift.generate_clean(prj)
|
||||
_p('clean:')
|
||||
if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCleaningMessage")) then
|
||||
_p('\t@echo Cleaning %s', prj.name)
|
||||
end
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p('\t$(SILENT) rm -f $(TARGET)')
|
||||
_p('\t$(SILENT) rm -rf $(OBJDIR)')
|
||||
_p('\t$(SILENT) rm -rf $(SYMBOLS)')
|
||||
_p('\t$(SILENT) rm -rf $(MODULECACHE_DIR)')
|
||||
_p('else')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(SYMBOLS)) rmdir /s /q $(subst /,\\\\,$(SYMBOLS))')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(MODULECACHE_DIR)) rmdir /s /q $(subst /,\\\\,$(MODULECACHE_DIR))')
|
||||
_p('endif')
|
||||
_p('')
|
||||
end
|
||||
|
||||
function swift.generate_config(prj, cfg, tool)
|
||||
_p('ifeq ($(config),%s)', _MAKE.esc(cfg.shortname))
|
||||
|
||||
_p(1, "OUT_DIR = %s", cfg.buildtarget.directory)
|
||||
_p(1, "MODULECACHE_DIR = $(OUT_DIR)/ModuleCache")
|
||||
_p(1, "TARGET = $(OUT_DIR)/%s", _MAKE.esc(cfg.buildtarget.name))
|
||||
local objdir = path.join(cfg.objectsdir, prj.name .. ".build")
|
||||
_p(1, "OBJDIR = %s", objdir)
|
||||
_p(1, "MODULE_NAME = %s", prj.name)
|
||||
_p(1, "MODULE_MAPS = %s", make.list(tool.getmodulemaps(cfg)))
|
||||
_p(1, "SWIFTC_FLAGS = %s", make.list(tool.getswiftcflags(cfg)))
|
||||
_p(1, "SWIFTLINK_FLAGS = %s", make.list(tool.getswiftlinkflags(cfg)))
|
||||
_p(1, "AR_FLAGS = %s", make.list(tool.getarchiveflags(cfg, cfg, false)))
|
||||
_p(1, "LD_FLAGS = %s", make.list(tool.getldflags(cfg)))
|
||||
_p(1, "LDDEPS = %s", make.list(premake.getlinks(cfg, "siblings", "fullpath")))
|
||||
if cfg.flags.Symbols then
|
||||
_p(1, "SYMBOLS = $(TARGET).dSYM")
|
||||
end
|
||||
|
||||
local sdk = tool.get_sdk_path(cfg)
|
||||
if sdk then
|
||||
_p(1, "TOOLCHAIN_PATH = %s", tool.get_toolchain_path(cfg))
|
||||
_p(1, "SDK_PATH = %s", sdk)
|
||||
_p(1, "PLATFORM_PATH = %s", tool.get_sdk_platform_path(cfg))
|
||||
_p(1, "SDK = -sdk $(SDK_PATH)")
|
||||
else
|
||||
_p(1, "SDK_PATH =")
|
||||
_p(1, "SDK =")
|
||||
end
|
||||
|
||||
_p(1,'WORK_DIRS = $(OUT_DIR) $(OBJDIR)')
|
||||
|
||||
_p('endif')
|
||||
_p('')
|
||||
end
|
||||
+359
@@ -0,0 +1,359 @@
|
||||
--
|
||||
-- make_vala.lua
|
||||
-- Generate a Vala project makefile.
|
||||
--
|
||||
|
||||
premake.make.vala = { }
|
||||
premake.make.makefile_ignore = false
|
||||
|
||||
local vala = premake.make.vala
|
||||
local make = premake.make
|
||||
|
||||
function premake.make_vala(prj)
|
||||
|
||||
-- create a shortcut to the compiler interface
|
||||
local valac = premake.gettool(prj)
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(prj.solution, valac.platforms, "Native")
|
||||
|
||||
-- output build configurations
|
||||
premake.gmake_vala_header(prj, valac, platforms)
|
||||
|
||||
-- write configuration blocks
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in premake.eachconfig(prj, platform) do
|
||||
premake.gmake_valac_config(prj, cfg, valac)
|
||||
end
|
||||
end
|
||||
|
||||
-- list object directories
|
||||
local objdirs = {}
|
||||
local additionalobjdirs = {}
|
||||
for _, file in ipairs(prj.allfiles) do
|
||||
if path.issourcefile(file) or path.isgresource(file) then
|
||||
objdirs[_MAKE.esc(path.getdirectory(path.trimdots(file)))] = 1
|
||||
end
|
||||
end
|
||||
|
||||
_p('OBJDIRS := \\')
|
||||
_p('\t$(OBJDIR) \\')
|
||||
for dir, _ in iter.sortByKeys(objdirs) do
|
||||
_p('\t$(OBJDIR)/%s \\', dir)
|
||||
end
|
||||
for dir, _ in iter.sortByKeys(additionalobjdirs) do
|
||||
_p('\t%s \\', dir)
|
||||
end
|
||||
_p('')
|
||||
|
||||
-- main build rule(s)
|
||||
_p('.PHONY: clean prebuild prelink')
|
||||
_p('')
|
||||
|
||||
_p('all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET)')
|
||||
_p('\t@:')
|
||||
_p('')
|
||||
|
||||
-- target build rule
|
||||
_p('$(TARGET): $(OBJECTS) | $(TARGETDIR)')
|
||||
_p('\t@echo Linking %s', prj.name)
|
||||
_p('\t$(SILENT) $(LINKCMD)')
|
||||
|
||||
_p('\t$(POSTBUILDCMDS)')
|
||||
_p('')
|
||||
|
||||
-- Create destination directories. Can't use $@ for this because it loses the
|
||||
-- escaping, causing issues with spaces and parenthesis
|
||||
_p('$(TARGETDIR):')
|
||||
premake.make_mkdirrule("$(TARGETDIR)")
|
||||
|
||||
_p('$(OBJDIRS):')
|
||||
if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCreatingMessage")) then
|
||||
_p('\t@echo Creating $(@)')
|
||||
end
|
||||
_p('\t-$(call MKDIR,$@)')
|
||||
_p('')
|
||||
|
||||
-- clean target
|
||||
_p('clean:')
|
||||
if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCleaningMessage")) then
|
||||
_p('\t@echo Cleaning %s', prj.name)
|
||||
end
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p('\t$(SILENT) rm -f $(TARGET)')
|
||||
_p('else')
|
||||
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- custom build step targets
|
||||
_p('prebuild:')
|
||||
_p('\t$(PREBUILDCMDS)')
|
||||
_p('')
|
||||
|
||||
_p('prelink:')
|
||||
_p('\t$(PRELINKCMDS)')
|
||||
_p('')
|
||||
|
||||
vala.fileRules(prj, valac)
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Write the makefile header
|
||||
--
|
||||
|
||||
function premake.gmake_vala_header(prj, valac, platforms)
|
||||
_p('# %s project makefile autogenerated by GENie', premake.action.current().shortname)
|
||||
_p('')
|
||||
|
||||
_p('.SUFFIXES:') -- Delete the default suffix rules.
|
||||
_p('')
|
||||
|
||||
-- set up the environment
|
||||
_p('ifndef config')
|
||||
_p(' config=%s', _MAKE.esc(premake.getconfigname(prj.solution.configurations[1], platforms[1], true)))
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifndef verbose')
|
||||
_p(' SILENT = @')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
-- identify the shell type
|
||||
_p('SHELLTYPE := msdos')
|
||||
_p('ifeq (,$(ComSpec)$(COMSPEC))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(SHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))')
|
||||
_p(' SHELLTYPE := posix')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifeq (posix,$(SHELLTYPE))')
|
||||
_p(' MKDIR = $(SILENT) mkdir -p "$(1)"')
|
||||
_p(' COPY = $(SILENT) cp -fR "$(1)" "$(2)"')
|
||||
_p(' RM = $(SILENT) rm -f "$(1)"')
|
||||
_p('else')
|
||||
_p(' MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul || exit 0')
|
||||
_p(' COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"')
|
||||
_p(' RM = $(SILENT) del /F "$(subst /,\\\\,$(1))" 2> nul || exit 0')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('VALAC = %s', valac.valac)
|
||||
_p('CC = %s', valac.cc)
|
||||
_p('GLIBRC = %s', valac.glibrc)
|
||||
_p('')
|
||||
|
||||
if (not premake.make.makefile_ignore) then
|
||||
_p('MAKEFILE = %s', _MAKE.getmakefilename(prj, true))
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Write a block of configuration settings.
|
||||
--
|
||||
|
||||
local function is_excluded(prj, cfg, file)
|
||||
if table.icontains(prj.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
if table.icontains(cfg.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function premake.gmake_valac_config(prj, cfg, valac)
|
||||
|
||||
_p('ifeq ($(config),%s)', _MAKE.esc(cfg.shortname))
|
||||
|
||||
_p(' BASEDIR = %s', _MAKE.esc(path.getrelative(cfg.location, _WORKING_DIR)))
|
||||
_p(' OBJDIR = %s', _MAKE.esc(cfg.objectsdir))
|
||||
_p(' TARGETDIR = %s', _MAKE.esc(cfg.buildtarget.directory))
|
||||
_p(' TARGET = $(TARGETDIR)/%s', _MAKE.esc(cfg.buildtarget.name))
|
||||
_p(' DEFINES +=%s', make.list(valac.getdefines(cfg.defines)))
|
||||
_p(' VAPIDIRS +=%s', make.list(valac.getvapidirs(cfg.vapidirs)))
|
||||
_p(' PKGS +=%s', make.list(valac.getlinks(cfg.links)))
|
||||
_p(' FLAGS += $(DEFINES) $(VAPIDIRS) $(PKGS)%s', make.list(table.join(valac.getvalaflags(cfg), cfg.buildoptions_vala)))
|
||||
_p(' ALL_LDFLAGS+= $(LDFLAGS)%s', make.list(table.join(cfg.linkoptions)))
|
||||
_p(' LINKOBJS = %s', "$(OBJECTS)")
|
||||
_p(' ALL_CFLAGS += $(CFLAGS) $(ARCH)%s', make.list(table.join(cfg.buildoptions, cfg.buildoptions_c, valac.getvalaccflags(cfg))))
|
||||
_p(' LINKCMD = $(CC) -o $(TARGET) $(LINKOBJS) $(ARCH) $(ALL_LDFLAGS)');
|
||||
|
||||
table.sort(cfg.files)
|
||||
|
||||
-- add objects for compilation, and remove any that are excluded per config.
|
||||
_p(' OBJECTS := \\')
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.issourcefile(file) or path.isgresource(file) then
|
||||
if not is_excluded(prj, cfg, file) then
|
||||
_p('\t$(OBJDIR)/%s.o \\'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
_p(' SOURCES := \\')
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.issourcefile(file) and path.isvalafile(file) then
|
||||
if not is_excluded(prj, cfg, file) then
|
||||
_p('\t%s \\', _MAKE.esc(file))
|
||||
end
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
_p(' GRESOURCES := \\')
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.isgresource(file) then
|
||||
if not is_excluded(prj, cfg, file) then
|
||||
_p('\t%s \\', _MAKE.esc(file))
|
||||
end
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
_p(' define PREBUILDCMDS')
|
||||
if #cfg.prebuildcommands > 0 then
|
||||
_p('\t@echo Running pre-build commands')
|
||||
_p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p(' define PRELINKCMDS')
|
||||
if #cfg.prelinkcommands > 0 then
|
||||
_p('\t@echo Running pre-link commands')
|
||||
_p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p(' define POSTBUILDCMDS')
|
||||
if #cfg.postbuildcommands > 0 then
|
||||
_p('\t@echo Running post-build commands')
|
||||
_p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t"))
|
||||
end
|
||||
_p(' endef')
|
||||
|
||||
_p('endif')
|
||||
_p('')
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Build command for a single file.
|
||||
--
|
||||
|
||||
function vala.fileRules(prj, cc)
|
||||
local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native")
|
||||
|
||||
_p('ifneq (,$(OBJRESP))')
|
||||
_p('$(OBJRESP): $(OBJECTS) | $(TARGETDIR) $(OBJDIRS)')
|
||||
_p('\t$(SILENT) echo $^')
|
||||
_p('\t$(SILENT) echo $^ > $@')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
_p('ifneq (,$(LDRESP))')
|
||||
_p('$(LDRESP): $(LDDEPS) | $(TARGETDIR) $(OBJDIRS)')
|
||||
_p('\t$(SILENT) echo $^')
|
||||
_p('\t$(SILENT) echo $^ > $@')
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
local pattern_targets = ""
|
||||
table.sort(prj.allfiles)
|
||||
for _, file in ipairs(prj.allfiles or {}) do
|
||||
if path.issourcefile(file) or path.isgresource(file) then
|
||||
if path.isvalafile(file) or path.iscfile(file) or path.isgresource(file) then
|
||||
if path.isvalafile(file) or path.isgresource(file) then
|
||||
_p('$(OBJDIR)/%s.o: $(OBJDIR)/%s.c $(GCH) $(MAKEFILE) | $(OBJDIR)/%s'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
, _MAKE.esc(path.getdirectory(path.trimdots(file)))
|
||||
)
|
||||
if not path.isgresource(file) then
|
||||
pattern_targets = pattern_targets
|
||||
.. "$(OBJDIR)/"
|
||||
.. _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
.. ".% \\\n" -- Pattern rule: https://stackoverflow.com/a/3077254
|
||||
end
|
||||
else
|
||||
_p('$(OBJDIR)/%s.o: %s $(GCH) $(MAKEFILE) | $(OBJDIR)/%s'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
, file
|
||||
, _MAKE.esc(path.getdirectory(path.trimdots(file)))
|
||||
)
|
||||
end
|
||||
if prj.msgcompile then
|
||||
_p('\t@echo ' .. prj.msgcompile)
|
||||
else
|
||||
_p('\t@echo $(notdir $<)')
|
||||
end
|
||||
_p('\t$(SILENT) %s $(FORCE_INCLUDE) -o "$@" -c "$<"'
|
||||
, "$(CC) $(ALL_CFLAGS)"
|
||||
, _MAKE.esc(path.getbasename(file))
|
||||
)
|
||||
for _, task in ipairs(prj.postcompiletasks or {}) do
|
||||
_p('\t$(SILENT) %s', task)
|
||||
_p('')
|
||||
end
|
||||
_p('')
|
||||
|
||||
if path.isgresource(file) then
|
||||
_p('$(OBJDIR)/%s.c: %s $(GCH) $(MAKEFILE) | $(OBJDIR)/%s'
|
||||
, _MAKE.esc(path.trimdots(path.removeext(file)))
|
||||
, _MAKE.esc(file)
|
||||
, _MAKE.esc(path.getdirectory(path.trimdots(file)))
|
||||
)
|
||||
if prj.msgcompile then
|
||||
_p('\t@echo ' .. prj.msgcompile)
|
||||
else
|
||||
_p('\t@echo $(notdir $<)')
|
||||
end
|
||||
_p('\t$(SILENT) %s "$<" --target="$@" --sourcedir="%s" --generate'
|
||||
, "$(GLIBRC)"
|
||||
, _MAKE.esc(path.getdirectory(file))
|
||||
)
|
||||
for _, task in ipairs(prj.postcompiletasks or {}) do
|
||||
_p('\t$(SILENT) %s', task)
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if pattern_targets ~= "" then
|
||||
-- Generate .c from corresponding .vala
|
||||
_p('%s: $(SOURCES) $(GRESOURCES) $(GCH) $(MAKEFILE)', pattern_targets)
|
||||
if prj.msgcompile then
|
||||
_p('\t@echo ' .. prj.msgcompile)
|
||||
else
|
||||
_p('\t@echo [GEN] valac')
|
||||
end
|
||||
_p('\t$(SILENT) %s $(SOURCES) --directory $(OBJDIR) --basedir $(BASEDIR) --gresources=$(GRESOURCES) -C > /dev/null'
|
||||
, "$(VALAC) $(FLAGS)"
|
||||
)
|
||||
for _, task in ipairs(prj.postcompiletasks or {}) do
|
||||
_p('\t$(SILENT) %s', task)
|
||||
_p('')
|
||||
end
|
||||
end
|
||||
end
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
--
|
||||
-- GENie - Project generator tool
|
||||
-- https://github.com/bkaradzic/GENie#license
|
||||
--
|
||||
|
||||
premake.ninja = { }
|
||||
|
||||
local p = premake
|
||||
|
||||
newaction
|
||||
{
|
||||
-- Metadata for the command line and help system
|
||||
trigger = "ninja",
|
||||
shortname = "ninja",
|
||||
description = "Generate Ninja build files",
|
||||
module = "ninja",
|
||||
|
||||
-- The capabilities of this action
|
||||
valid_kinds = {"ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle"},
|
||||
valid_languages = {"C", "C++", "Swift"},
|
||||
valid_tools = {
|
||||
cc = { "gcc" },
|
||||
swift = { "swift" },
|
||||
},
|
||||
|
||||
-- Solution and project generation logic
|
||||
onsolution = function(sln)
|
||||
io.eol = "\r\n"
|
||||
io.indent = "\t"
|
||||
io.escaper(p.ninja.esc)
|
||||
p.generate(sln, "Makefile", p.ninja.generate_solution)
|
||||
io.indent = " "
|
||||
p.ninja.generate_ninja_builds(sln)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
io.eol = "\r\n"
|
||||
io.indent = " "
|
||||
io.escaper(p.ninja.esc)
|
||||
p.ninja.generate_project(prj)
|
||||
end,
|
||||
|
||||
oncleansolution = function(sln)
|
||||
for _,name in ipairs(sln.configurations) do
|
||||
premake.clean.file(sln, p.ninja.get_solution_name(sln, name))
|
||||
end
|
||||
end,
|
||||
|
||||
oncleanproject = function(prj)
|
||||
-- TODO
|
||||
end,
|
||||
|
||||
oncleantarget = function(prj)
|
||||
-- TODO
|
||||
end,
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
--
|
||||
-- Name: ninja_base.lua
|
||||
-- Purpose: Define the ninja action.
|
||||
-- Author: Stuart Carnie (stuart.carnie at gmail.com)
|
||||
--
|
||||
|
||||
local ninja = premake.ninja
|
||||
|
||||
function ninja.esc(value)
|
||||
if value then
|
||||
value = string.gsub(value, "%$", "$$") -- TODO maybe there is better way
|
||||
value = string.gsub(value, ":", "$:")
|
||||
value = string.gsub(value, "\n", "$\n")
|
||||
value = string.gsub(value, " ", "$ ")
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
-- in some cases we write file names in rule commands directly
|
||||
-- so we need to propely escape them
|
||||
function ninja.shesc(value)
|
||||
if type(value) == "table" then
|
||||
local result = {}
|
||||
local n = #value
|
||||
for i = 1, n do
|
||||
table.insert(result, ninja.shesc(value[i]))
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
if value:find(" ") then
|
||||
return "\"" .. value .. "\""
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
function ninja.list(value)
|
||||
if #value > 0 then
|
||||
return " " .. table.concat(value, " ")
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
function ninja.arglist(arg, value)
|
||||
if #value > 0 then
|
||||
local args = {}
|
||||
for _, val in ipairs(value) do
|
||||
table.insert(args, string.format("%s %s", arg, val))
|
||||
end
|
||||
return table.concat(args, " ")
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
-- generate all build files for every project configuration
|
||||
function ninja.generate_project(prj)
|
||||
if prj.language == "Swift" then
|
||||
ninja.generate_swift(prj)
|
||||
else
|
||||
ninja.generate_cpp(prj)
|
||||
end
|
||||
end
|
||||
|
||||
local function innerget(self, key)
|
||||
return rawget(getmetatable(self), key) or self.__inner[key]
|
||||
end
|
||||
|
||||
local prj_proxy = { __index = innerget }
|
||||
|
||||
local cfg_proxy = { __index = innerget }
|
||||
|
||||
function new_prj_proxy(prj)
|
||||
prj = prj.project or prj
|
||||
|
||||
local v = { __inner = prj }
|
||||
|
||||
local __configs = {}
|
||||
for key, cfg in pairs(prj.__configs) do
|
||||
if key ~= "" then
|
||||
__configs[key] = ninja.get_proxy("cfg", cfg)
|
||||
else
|
||||
__configs[key] = cfg
|
||||
end
|
||||
end
|
||||
v.__configs = __configs
|
||||
|
||||
return setmetatable(v, prj_proxy)
|
||||
end
|
||||
|
||||
local function rebasekeys(t, keys, old, new)
|
||||
for _,key in ipairs(keys) do
|
||||
t[key] = path.rebase(t[key], old, new)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function rebasearray(t, old, new)
|
||||
local res = { }
|
||||
for _,f in ipairs(t) do
|
||||
table.insert(res, path.rebase(f, old, new))
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function new_cfg_proxy(cfg)
|
||||
local keys = { "directory", "fullpath", "bundlepath" }
|
||||
|
||||
local old = cfg.location
|
||||
local new = path.join(cfg.location, cfg.shortname)
|
||||
local v = {
|
||||
__inner = cfg,
|
||||
location = new,
|
||||
objectsdir = path.rebase(cfg.objectsdir, old, new),
|
||||
buildtarget = rebasekeys(table.deepcopy(cfg.buildtarget), keys, old, new),
|
||||
linktarget = rebasekeys(table.deepcopy(cfg.linktarget), keys, old, new),
|
||||
}
|
||||
|
||||
v.files = rebasearray(cfg.files, old, new)
|
||||
v.includedirs = rebasearray(cfg.includedirs, old, new)
|
||||
v.libdirs = rebasearray(cfg.libdirs, old, new)
|
||||
v.userincludedirs = rebasearray(cfg.userincludedirs, old, new)
|
||||
v.systemincludedirs = rebasearray(cfg.systemincludedirs, old, new)
|
||||
v.swiftmodulemaps = rebasearray(cfg.swiftmodulemaps, old, new)
|
||||
|
||||
return setmetatable(v, cfg_proxy)
|
||||
end
|
||||
|
||||
function cfg_proxy:getprojectfilename(fullpath)
|
||||
local name = self.project.name .. ".ninja"
|
||||
|
||||
if fullpath ~= nil then
|
||||
return path.join(self.location, name)
|
||||
end
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
function cfg_proxy:getoutputfilename()
|
||||
return path.join(self.buildtarget.directory, self.buildtarget.name)
|
||||
end
|
||||
|
||||
local proxy_cache = {
|
||||
prj = { new = new_prj_proxy },
|
||||
cfg = { new = new_cfg_proxy },
|
||||
}
|
||||
|
||||
function get_proxy(cache, obj)
|
||||
if not cache[obj] then
|
||||
cache[obj] = cache.new(obj)
|
||||
end
|
||||
return cache[obj]
|
||||
end
|
||||
|
||||
function ninja.get_proxy(typ, obj)
|
||||
if not proxy_cache[typ] then
|
||||
error("invalid proxy type")
|
||||
end
|
||||
|
||||
return get_proxy(proxy_cache[typ], obj)
|
||||
end
|
||||
|
||||
+409
@@ -0,0 +1,409 @@
|
||||
--
|
||||
-- GENie - Project generator tool
|
||||
-- https://github.com/bkaradzic/GENie#license
|
||||
--
|
||||
|
||||
premake.ninja.cpp = { }
|
||||
local ninja = premake.ninja
|
||||
local cpp = premake.ninja.cpp
|
||||
local p = premake
|
||||
|
||||
local function wrap_ninja_cmd(c)
|
||||
if os.is("windows") then
|
||||
return 'cmd /c "' .. c .. '"'
|
||||
else
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
-- generate project + config build file
|
||||
function ninja.generate_cpp(prj)
|
||||
local pxy = ninja.get_proxy("prj", prj)
|
||||
local tool = premake.gettool(prj)
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native")
|
||||
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in p.eachconfig(pxy, platform) do
|
||||
p.generate(cfg, cfg:getprojectfilename(), function() cpp.generate_config(prj, cfg) end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cpp.generate_config(prj, cfg)
|
||||
local tool = premake.gettool(prj)
|
||||
|
||||
_p('# Ninja build project file autogenerated by GENie')
|
||||
_p('# https://github.com/bkaradzic/GENie')
|
||||
_p("")
|
||||
|
||||
-- needed for implicit outputs, introduced in 1.7
|
||||
_p("ninja_required_version = 1.7")
|
||||
_p("")
|
||||
|
||||
local flags = {
|
||||
defines = ninja.list(tool.getdefines(cfg.defines)),
|
||||
includes = ninja.list(table.join(tool.getincludedirs(cfg.includedirs), tool.getquoteincludedirs(cfg.userincludedirs), tool.getsystemincludedirs(cfg.systemincludedirs))),
|
||||
cppflags = ninja.list(tool.getcppflags(cfg)),
|
||||
asmflags = ninja.list(table.join(tool.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_asm)),
|
||||
cflags = ninja.list(table.join(tool.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_c)),
|
||||
cxxflags = ninja.list(table.join(tool.getcflags(cfg), tool.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_cpp)),
|
||||
objcflags = ninja.list(table.join(tool.getcflags(cfg), tool.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_objc)),
|
||||
}
|
||||
|
||||
_p("")
|
||||
_p("# core rules for " .. cfg.name)
|
||||
_p("rule cc")
|
||||
_p(" command = " .. wrap_ninja_cmd(tool.cc .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in"))
|
||||
_p(" description = cc $out")
|
||||
_p(" depfile = $out.d")
|
||||
_p(" deps = gcc")
|
||||
_p("")
|
||||
_p("rule cxx")
|
||||
_p(" command = " .. wrap_ninja_cmd(tool.cxx .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in"))
|
||||
_p(" description = cxx $out")
|
||||
_p(" depfile = $out.d")
|
||||
_p(" deps = gcc")
|
||||
_p("")
|
||||
|
||||
if cfg.flags.UseObjectResponseFile then
|
||||
_p("rule ar")
|
||||
_p(" command = " .. wrap_ninja_cmd(tool.ar .. " $flags $out @$out.rsp " .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")))
|
||||
_p(" description = ar $out")
|
||||
_p(" rspfile = $out.rsp")
|
||||
_p(" rspfile_content = $in $libs")
|
||||
_p("")
|
||||
else
|
||||
_p("rule ar")
|
||||
_p(" command = " .. wrap_ninja_cmd(tool.ar .. " $flags $out $in $libs" .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")))
|
||||
_p(" description = ar $out")
|
||||
_p("")
|
||||
end
|
||||
|
||||
local link = iif(cfg.language == "C", tool.cc, tool.cxx)
|
||||
_p("rule link")
|
||||
local startgroup = ''
|
||||
local endgroup = ''
|
||||
if (cfg.flags.LinkSupportCircularDependencies) then
|
||||
startgroup = '-Wl,--start-group'
|
||||
endgroup = '-Wl,--end-group'
|
||||
end
|
||||
|
||||
local rspfile_content = "$all_outputfiles $walibs " .. string.format("%s $libs %s", startgroup, endgroup)
|
||||
if cfg.flags.UseLDResponseFile then
|
||||
_p(" command = " .. wrap_ninja_cmd("$pre_link " .. link .. " -o $out @$out.rsp $all_ldflags $post_build"))
|
||||
_p(" description = link $out")
|
||||
_p(" rspfile = $out.rsp")
|
||||
_p(" rspfile_content = %s", rspfile_content)
|
||||
_p("")
|
||||
else
|
||||
_p(" command = " .. wrap_ninja_cmd("$pre_link " .. link .. " -o $out " .. rspfile_content .. " $all_ldflags $post_build"))
|
||||
_p(" description = link $out")
|
||||
_p("")
|
||||
end
|
||||
|
||||
_p("rule exec")
|
||||
_p(" command = " .. wrap_ninja_cmd("$command"))
|
||||
_p(" description = Run $type commands")
|
||||
_p("")
|
||||
|
||||
if #cfg.prebuildcommands > 0 then
|
||||
_p("build __prebuildcommands_" .. premake.esc(prj.name) .. ": exec")
|
||||
_p(1, "command = " .. wrap_ninja_cmd("echo Running pre-build commands && " .. table.implode(cfg.prebuildcommands, "", "", " && ")))
|
||||
_p(1, "type = pre-build")
|
||||
_p("")
|
||||
end
|
||||
|
||||
cfg.pchheader_full = cfg.pchheader
|
||||
for _, incdir in ipairs(cfg.includedirs) do
|
||||
-- convert this back to an absolute path for os.isfile()
|
||||
local abspath = path.getabsolute(path.join(cfg.project.location, cfg.shortname, incdir))
|
||||
|
||||
local testname = path.join(abspath, cfg.pchheader_full)
|
||||
if os.isfile(testname) then
|
||||
cfg.pchheader_full = path.getrelative(cfg.location, testname)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
cpp.custombuildtask(prj, cfg)
|
||||
|
||||
cpp.dependencyRules(prj, cfg)
|
||||
|
||||
cpp.file_rules(prj, cfg, flags)
|
||||
|
||||
local objfiles = {}
|
||||
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.issourcefile(file) then
|
||||
table.insert(objfiles, cpp.objectname(cfg, file))
|
||||
end
|
||||
end
|
||||
_p('')
|
||||
|
||||
cpp.linker(prj, cfg, objfiles, tool, flags)
|
||||
|
||||
_p("")
|
||||
end
|
||||
|
||||
function cpp.custombuildtask(prj, cfg)
|
||||
local cmd_index = 1
|
||||
local seen_commands = {}
|
||||
local command_by_name = {}
|
||||
local command_files = {}
|
||||
|
||||
local prebuildsuffix = #cfg.prebuildcommands > 0 and "||__prebuildcommands_" .. premake.esc(prj.name) or ""
|
||||
|
||||
for _, custombuildtask in ipairs(prj.custombuildtask or {}) do
|
||||
for _, buildtask in ipairs(custombuildtask or {}) do
|
||||
for _, cmd in ipairs(buildtask[4] or {}) do
|
||||
local num = 1
|
||||
|
||||
-- replace dependencies in the command with actual file paths
|
||||
for _, depdata in ipairs(buildtask[3] or {}) do
|
||||
cmd = string.gsub(cmd,"%$%(" .. num .."%)", string.format("%s ", path.getrelative(cfg.location, depdata)))
|
||||
num = num + 1
|
||||
end
|
||||
|
||||
-- replace $(<) and $(@) with $in and $out
|
||||
cmd = string.gsub(cmd, '%$%(<%)', '$in')
|
||||
cmd = string.gsub(cmd, '%$%(@%)', '$out')
|
||||
|
||||
local cmd_name -- shortened command name
|
||||
|
||||
-- generate shortened rule names for the command, may be nonsensical
|
||||
-- in some cases but it will at least be unique.
|
||||
if seen_commands[cmd] == nil then
|
||||
local _, _, name = string.find(cmd, '([.%w]+)%s')
|
||||
name = 'cmd' .. cmd_index .. '_' .. string.gsub(name, '[^%w]', '_')
|
||||
|
||||
seen_commands[cmd] = {
|
||||
name = name,
|
||||
index = cmd_index,
|
||||
}
|
||||
|
||||
cmd_index = cmd_index + 1
|
||||
cmd_name = name
|
||||
else
|
||||
cmd_name = seen_commands[cmd].name
|
||||
end
|
||||
|
||||
local index = seen_commands[cmd].index
|
||||
|
||||
if command_files[index] == nil then
|
||||
command_files[index] = {}
|
||||
end
|
||||
|
||||
local cmd_set = command_files[index]
|
||||
|
||||
table.insert(cmd_set, {
|
||||
buildtask[1],
|
||||
buildtask[2],
|
||||
buildtask[3],
|
||||
seen_commands[cmd].name,
|
||||
})
|
||||
|
||||
command_files[index] = cmd_set
|
||||
command_by_name[cmd_name] = cmd
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
_p("# custom build rules")
|
||||
for command, details in pairs(seen_commands) do
|
||||
_p("rule " .. details.name)
|
||||
_p(1, "command = " .. wrap_ninja_cmd(command))
|
||||
end
|
||||
|
||||
for cmd_index, cmdsets in ipairs(command_files) do
|
||||
for _, cmdset in ipairs(cmdsets) do
|
||||
local file_in = path.getrelative(cfg.location, cmdset[1])
|
||||
local file_out = path.getrelative(cfg.location, cmdset[2])
|
||||
local deps = ''
|
||||
for i, dep in ipairs(cmdset[3]) do
|
||||
deps = deps .. path.getrelative(cfg.location, dep) .. ' '
|
||||
end
|
||||
_p("build " .. file_out .. ': ' .. cmdset[4] .. ' ' .. file_in .. ' | ' .. deps .. prebuildsuffix)
|
||||
_p("")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cpp.dependencyRules(prj, cfg)
|
||||
local extra_deps = {}
|
||||
local order_deps = {}
|
||||
local extra_flags = {}
|
||||
|
||||
for _, dependency in ipairs(prj.dependency or {}) do
|
||||
for _, dep in ipairs(dependency or {}) do
|
||||
-- This is assuming that the depending object is (going to be) an .o file
|
||||
local objfilename = cpp.objectname(cfg, path.getrelative(prj.location, dep[1]))
|
||||
local dependency = path.getrelative(cfg.location, dep[2])
|
||||
|
||||
-- ensure a table exists for the dependent object file
|
||||
if extra_deps[objfilename] == nil then
|
||||
extra_deps[objfilename] = {}
|
||||
end
|
||||
|
||||
table.insert(extra_deps[objfilename], dependency)
|
||||
end
|
||||
end
|
||||
|
||||
local pchfilename = cfg.pchheader_full and cpp.pchname(cfg, cfg.pchheader_full) or ''
|
||||
for _, file in ipairs(cfg.files) do
|
||||
local objfilename = file == cfg.pchheader and cpp.pchname(cfg, file) or cpp.objectname(cfg, file)
|
||||
if path.issourcefile(file) or file == cfg.pchheader then
|
||||
if #cfg.prebuildcommands > 0 then
|
||||
if order_deps[objfilename] == nil then
|
||||
order_deps[objfilename] = {}
|
||||
end
|
||||
table.insert(order_deps[objfilename], '__prebuildcommands_' .. premake.esc(prj.name))
|
||||
end
|
||||
end
|
||||
if path.issourcefile(file) then
|
||||
if cfg.pchheader_full and not cfg.flags.NoPCH then
|
||||
local nopch = table.icontains(prj.nopch, file)
|
||||
if not nopch then
|
||||
local suffix = path.isobjcfile(file) and '_objc' or ''
|
||||
if extra_deps[objfilename] == nil then
|
||||
extra_deps[objfilename] = {}
|
||||
end
|
||||
table.insert(extra_deps[objfilename], pchfilename .. suffix .. ".gch")
|
||||
|
||||
if extra_flags[objfilename] == nil then
|
||||
extra_flags[objfilename] = {}
|
||||
end
|
||||
table.insert(extra_flags[objfilename], '-include ' .. pchfilename .. suffix)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- store prepared deps for file_rules() phase
|
||||
cfg.extra_deps = extra_deps
|
||||
cfg.order_deps = order_deps
|
||||
cfg.extra_flags = extra_flags
|
||||
end
|
||||
|
||||
function cpp.objectname(cfg, file)
|
||||
return path.join(cfg.objectsdir, path.trimdots(path.removeext(file)) .. ".o")
|
||||
end
|
||||
|
||||
function cpp.pchname(cfg, file)
|
||||
return path.join(cfg.objectsdir, path.trimdots(file))
|
||||
end
|
||||
|
||||
function cpp.file_rules(prj,cfg, flags)
|
||||
_p("# build files")
|
||||
|
||||
for _, file in ipairs(cfg.files) do
|
||||
_p("# FILE: " .. file)
|
||||
if cfg.pchheader_full == file then
|
||||
local pchfilename = cpp.pchname(cfg, file)
|
||||
local extra_deps = #cfg.extra_deps and '| ' .. table.concat(cfg.extra_deps[pchfilename] or {}, ' ') or ''
|
||||
local order_deps = #cfg.order_deps and '|| ' .. table.concat(cfg.order_deps[pchfilename] or {}, ' ') or ''
|
||||
local extra_flags = #cfg.extra_flags and ' ' .. table.concat(cfg.extra_flags[pchfilename] or {}, ' ') or ''
|
||||
_p("build " .. pchfilename .. ".gch : cxx " .. file .. extra_deps .. order_deps)
|
||||
_p(1, "flags = " .. flags['cxxflags'] .. extra_flags .. iif(prj.language == "C", "-x c-header", "-x c++-header"))
|
||||
_p(1, "includes = " .. flags.includes)
|
||||
_p(1, "defines = " .. flags.defines)
|
||||
|
||||
_p("build " .. pchfilename .. "_objc.gch : cxx " .. file .. extra_deps .. order_deps)
|
||||
_p(1, "flags = " .. flags['objcflags'] .. extra_flags .. iif(prj.language == "C", "-x objective-c-header", "-x objective-c++-header"))
|
||||
_p(1, "includes = " .. flags.includes)
|
||||
_p(1, "defines = " .. flags.defines)
|
||||
elseif path.issourcefile(file) then
|
||||
local objfilename = cpp.objectname(cfg, file)
|
||||
local extra_deps = #cfg.extra_deps and '| ' .. table.concat(cfg.extra_deps[objfilename] or {}, ' ') or ''
|
||||
local order_deps = #cfg.order_deps and '|| ' .. table.concat(cfg.order_deps[objfilename] or {}, ' ') or ''
|
||||
local extra_flags = #cfg.extra_flags and ' ' .. table.concat(cfg.extra_flags[objfilename] or {}, ' ') or ''
|
||||
|
||||
local cflags = "cflags"
|
||||
if path.isobjcfile(file) then
|
||||
_p("build " .. objfilename .. ": cxx " .. file .. extra_deps .. order_deps)
|
||||
cflags = "objcflags"
|
||||
elseif path.isasmfile(file) then
|
||||
_p("build " .. objfilename .. ": cc " .. file .. extra_deps .. order_deps)
|
||||
cflags = "asmflags"
|
||||
elseif path.iscfile(file) and not cfg.options.ForceCPP then
|
||||
_p("build " .. objfilename .. ": cc " .. file .. extra_deps .. order_deps)
|
||||
else
|
||||
_p("build " .. objfilename .. ": cxx " .. file .. extra_deps .. order_deps)
|
||||
cflags = "cxxflags"
|
||||
end
|
||||
|
||||
_p(1, "flags = " .. flags[cflags] .. extra_flags)
|
||||
_p(1, "includes = " .. flags.includes)
|
||||
_p(1, "defines = " .. flags.defines)
|
||||
elseif path.isresourcefile(file) then
|
||||
-- TODO
|
||||
end
|
||||
end
|
||||
|
||||
_p("")
|
||||
end
|
||||
|
||||
function cpp.linker(prj, cfg, objfiles, tool)
|
||||
local all_ldflags = ninja.list(table.join(tool.getlibdirflags(cfg), tool.getldflags(cfg), cfg.linkoptions))
|
||||
local prebuildsuffix = #cfg.prebuildcommands > 0 and ("||__prebuildcommands_" .. premake.esc(prj.name)) or ""
|
||||
local libs = {}
|
||||
local walibs = {}
|
||||
local lddeps = {}
|
||||
|
||||
if #cfg.wholearchive > 0 then
|
||||
for _, linkcfg in ipairs(premake.getlinks(cfg, "siblings", "object")) do
|
||||
local linkpath = path.rebase(linkcfg.linktarget.fullpath, linkcfg.location, cfg.location)
|
||||
table.insert(lddeps, linkpath)
|
||||
|
||||
if table.icontains(cfg.wholearchive, linkcfg.project.name) then
|
||||
table.insert(walibs, table.concat(tool.wholearchive(linkpath), ' '))
|
||||
else
|
||||
table.insert(libs, linkpath)
|
||||
end
|
||||
end
|
||||
else
|
||||
lddeps = premake.getlinks(cfg, "siblings", "fullpath")
|
||||
libs = lddeps
|
||||
end
|
||||
|
||||
lddeps = ninja.list(lddeps)
|
||||
libs = ninja.list(libs) .. " " .. ninja.list(tool.getlinkflags(cfg))
|
||||
walibs = ninja.list(walibs)
|
||||
|
||||
local function writevars()
|
||||
_p(1, "all_ldflags = " .. all_ldflags)
|
||||
_p(1, "libs = " .. libs)
|
||||
_p(1, "walibs = " .. walibs)
|
||||
_p(1, "all_outputfiles = " .. table.concat(objfiles, " "))
|
||||
if #cfg.prelinkcommands > 0 then
|
||||
_p(1, 'pre_link = echo Running pre-link commands && ' .. table.implode(cfg.prelinkcommands, "", "", " && ") .. " && ")
|
||||
end
|
||||
if #cfg.postbuildcommands > 0 then
|
||||
_p(1, 'post_build = && echo Running post-build commands && ' .. table.implode(cfg.postbuildcommands, "", "", " && "))
|
||||
end
|
||||
end
|
||||
|
||||
if cfg.kind == "StaticLib" then
|
||||
local ar_flags = ninja.list(tool.getarchiveflags(cfg, cfg, false))
|
||||
_p("# link static lib")
|
||||
_p("build " .. cfg:getoutputfilename() .. ": ar " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix)
|
||||
_p(1, "flags = " .. ninja.list(tool.getarchiveflags(cfg, cfg, false)))
|
||||
_p(1, "all_outputfiles = " .. table.concat(objfiles, " "))
|
||||
elseif cfg.kind == "SharedLib" or cfg.kind == "Bundle" then
|
||||
local output = cfg:getoutputfilename()
|
||||
_p("# link shared lib")
|
||||
_p("build " .. output .. ": link " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix)
|
||||
writevars()
|
||||
elseif (cfg.kind == "ConsoleApp") or (cfg.kind == "WindowedApp") then
|
||||
_p("# link executable")
|
||||
_p("build " .. cfg:getoutputfilename() .. ": link " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix)
|
||||
writevars()
|
||||
else
|
||||
p.error("ninja action doesn't support this kind of target " .. cfg.kind)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
--
|
||||
-- GENie - Project generator tool
|
||||
-- https://github.com/bkaradzic/GENie#license
|
||||
--
|
||||
|
||||
local ninja = premake.ninja
|
||||
local p = premake
|
||||
local solution = p.solution
|
||||
|
||||
function ninja.generate_solution(sln)
|
||||
-- create a shortcut to the compiler interface
|
||||
local cc = premake[_OPTIONS.cc]
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(sln, cc.platforms, "Native")
|
||||
|
||||
-- write a header showing the build options
|
||||
_p('# %s solution makefile autogenerated by GENie', premake.action.current().shortname)
|
||||
_p('# Type "make help" for usage help')
|
||||
_p('')
|
||||
_p('NINJA=ninja')
|
||||
|
||||
-- set a default configuration
|
||||
_p('ifndef config')
|
||||
_p(' config=%s', _MAKE.esc(premake.getconfigname(sln.configurations[1], platforms[1], true)))
|
||||
_p('endif')
|
||||
_p('')
|
||||
|
||||
local projects = table.extract(sln.projects, "name")
|
||||
table.sort(projects)
|
||||
|
||||
_p('')
|
||||
_p('.PHONY: all clean help $(PROJECTS)')
|
||||
_p('')
|
||||
_p('all:')
|
||||
if (not sln.messageskip) or (not table.contains(sln.messageskip, "SkipBuildingMessage")) then
|
||||
_p(1, '@echo "==== Building all ($(config)) ===="')
|
||||
end
|
||||
_p(1, '@${NINJA} -C ${config} all')
|
||||
_p('')
|
||||
|
||||
-- write the project build rules
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
local prjx = ninja.get_proxy("prj", prj)
|
||||
_p('%s:', _MAKE.esc(prj.name))
|
||||
if (not sln.messageskip) or (not table.contains(sln.messageskip, "SkipBuildingMessage")) then
|
||||
_p(1, '@echo "==== Building %s ($(config)) ===="', prj.name)
|
||||
end
|
||||
_p(1, '@${NINJA} -C ${config} %s', prj.name)
|
||||
_p('')
|
||||
end
|
||||
|
||||
-- clean rules
|
||||
_p('clean:')
|
||||
_p(1, '@${NINJA} -C ${config} -t clean')
|
||||
_p('')
|
||||
|
||||
-- help rule
|
||||
_p('help:')
|
||||
_p(1,'@echo "Usage: make [config=name] [target]"')
|
||||
_p(1,'@echo ""')
|
||||
_p(1,'@echo "CONFIGURATIONS:"')
|
||||
|
||||
local cfgpairs = { }
|
||||
for _, platform in ipairs(platforms) do
|
||||
for _, cfgname in ipairs(sln.configurations) do
|
||||
_p(1,'@echo " %s"', premake.getconfigname(cfgname, platform, true))
|
||||
end
|
||||
end
|
||||
|
||||
_p(1,'@echo ""')
|
||||
_p(1,'@echo "TARGETS:"')
|
||||
_p(1,'@echo " all (default)"')
|
||||
_p(1,'@echo " clean"')
|
||||
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
_p(1,'@echo " %s"', prj.name)
|
||||
end
|
||||
|
||||
_p(1,'@echo ""')
|
||||
_p(1,'@echo "For more information, see https://github.com/bkaradzic/genie"')
|
||||
end
|
||||
|
||||
-- generate solution that will call ninja for projects
|
||||
local generate
|
||||
|
||||
local function getconfigs(sln, name, plat)
|
||||
local cfgs = {}
|
||||
for prj in solution.eachproject(sln) do
|
||||
prj = ninja.get_proxy("prj", prj)
|
||||
for cfg in p.eachconfig(prj, plat) do
|
||||
if cfg.name == name then
|
||||
table.insert(cfgs, cfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
return cfgs
|
||||
end
|
||||
|
||||
function ninja.generate_ninja_builds(sln)
|
||||
-- create a shortcut to the compiler interface
|
||||
local cc = premake[_OPTIONS.cc]
|
||||
|
||||
sln.getlocation = function(cfg, plat)
|
||||
return path.join(sln.location, premake.getconfigname(cfg, plat, true))
|
||||
end
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(sln, cc.platforms, "Native")
|
||||
|
||||
for _,plat in ipairs(platforms) do
|
||||
for _,name in ipairs(sln.configurations) do
|
||||
p.generate(sln, ninja.get_solution_name(sln, name, plat), function(sln)
|
||||
generate(getconfigs(sln, name, plat))
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ninja.get_solution_name(sln, cfg, plat)
|
||||
return path.join(sln.getlocation(cfg, plat), "build.ninja")
|
||||
end
|
||||
|
||||
function generate(prjcfgs)
|
||||
local cfgs = {}
|
||||
local cfg_start = nil
|
||||
local cfg_first = nil
|
||||
local cfg_first_lib = nil
|
||||
|
||||
_p("# solution build file")
|
||||
_p("# generated with GENie ninja")
|
||||
_p("")
|
||||
|
||||
_p("# build projects")
|
||||
for _,cfg in ipairs(prjcfgs) do
|
||||
local key = cfg.project.name
|
||||
|
||||
-- fill list of output files
|
||||
if not cfgs[key] then cfgs[key] = "" end
|
||||
cfgs[key] = cfg:getoutputfilename() .. " "
|
||||
|
||||
if not cfgs["all"] then cfgs["all"] = "" end
|
||||
cfgs["all"] = cfgs["all"] .. cfg:getoutputfilename() .. " "
|
||||
|
||||
-- set first configuration name
|
||||
if (cfg_start == nil) and (cfg.solution.startproject == key) then
|
||||
cfg_start = key
|
||||
end
|
||||
if (cfg_first == nil) and (cfg.kind == "ConsoleApp" or cfg.kind == "WindowedApp") then
|
||||
cfg_first = key
|
||||
end
|
||||
if (cfg_first_lib == nil) and (cfg.kind == "StaticLib" or cfg.kind == "SharedLib") then
|
||||
cfg_first_lib = key
|
||||
end
|
||||
|
||||
-- include other ninja file
|
||||
_p("subninja " .. cfg:getprojectfilename())
|
||||
end
|
||||
|
||||
_p("")
|
||||
|
||||
_p("# targets")
|
||||
for cfg, outputs in iter.sortByKeys(cfgs) do
|
||||
_p("build " .. cfg .. ": phony " .. outputs)
|
||||
end
|
||||
_p("")
|
||||
|
||||
_p("# default target")
|
||||
_p("default " .. (cfg_start or cfg_first or cfg_first_lib))
|
||||
_p("")
|
||||
end
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
--
|
||||
-- Generates Ninja project file for Swift
|
||||
-- Copyright (c) 2016 Stuart Carnie and the GENie project
|
||||
--
|
||||
|
||||
local ninja = premake.ninja
|
||||
local swift = {}
|
||||
local p = premake
|
||||
|
||||
-- generate project + config build file
|
||||
function ninja.generate_swift(prj)
|
||||
local pxy = ninja.get_proxy("prj", prj)
|
||||
local tool = premake.gettool(prj)
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native")
|
||||
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in p.eachconfig(pxy, platform) do
|
||||
p.generate(cfg, cfg:getprojectfilename(), function() swift.generate_config(prj, cfg) end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function swift.generate_config(prj, cfg)
|
||||
local tool = premake.gettool(prj)
|
||||
|
||||
local flags = {
|
||||
swiftcflags = ninja.list(tool.getswiftcflags(cfg)),
|
||||
swiftlinkflags = ninja.list(tool.getswiftlinkflags(cfg)),
|
||||
}
|
||||
|
||||
_p("# Swift project build file")
|
||||
_p("# generated with GENie ninja")
|
||||
_p("")
|
||||
|
||||
-- needed for implicit outputs, introduced in 1.7
|
||||
_p("ninja_required_version = 1.7")
|
||||
_p("")
|
||||
|
||||
_p("out_dir = %s", cfg.buildtarget.directory)
|
||||
_p("obj_dir = %s", path.join(cfg.objectsdir, prj.name .. ".build"))
|
||||
_p("target = $out_dir/%s", cfg.buildtarget.name)
|
||||
_p("module_name = %s", prj.name)
|
||||
_p("module_maps = %s", ninja.list(tool.getmodulemaps(cfg)))
|
||||
_p("swiftc_flags = %s", flags.swiftcflags)
|
||||
_p("swiftlink_flags = %s", flags.swiftlinkflags)
|
||||
_p("ar_flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false)))
|
||||
--_p("lib_dir_flags = %s", ninja.list(tool.getlibdirflags(cfg)))
|
||||
_p("ld_flags = %s", ninja.list(tool.getldflags(cfg)))
|
||||
|
||||
if cfg.flags.Symbols then
|
||||
_p("symbols = $target.dSYM")
|
||||
symbols_command = string.format("&& %s $target -o $symbols", tool.dsymutil)
|
||||
else
|
||||
_p("symbols = ")
|
||||
symbols_command = ""
|
||||
end
|
||||
|
||||
local sdk = tool.get_sdk_path(cfg)
|
||||
if sdk then
|
||||
_p("toolchain_path = %s", tool.get_toolchain_path(cfg))
|
||||
_p("sdk_path = %s", sdk)
|
||||
_p("platform_path = %s", tool.get_sdk_platform_path(cfg))
|
||||
_p("sdk = -sdk $sdk_path")
|
||||
else
|
||||
_p("sdk_path =")
|
||||
_p("sdk =")
|
||||
end
|
||||
_p("")
|
||||
|
||||
_p("# core rules for %s", cfg.name)
|
||||
_p("rule swiftc")
|
||||
_p(1, "command = %s -frontend -c $in -enable-objc-interop $sdk -I $out_dir $swiftc_flags -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_dir/$module_name.swiftdoc -module-name $module_name -emit-module-path $out_dir/$module_name.swiftmodule -num-threads 8 $obj_files", tool.swift)
|
||||
_p(1, "description = compile $out")
|
||||
_p("")
|
||||
|
||||
_p("rule swiftlink")
|
||||
_p(1, "command = %s $sdk -L $out_dir -o $out $swiftlink_flags $ld_flags $in %s", tool.swiftc, symbols_command)
|
||||
_p(1, "description = create executable")
|
||||
_p("")
|
||||
|
||||
_p("rule ar")
|
||||
_p(1, "command = %s cr $ar_flags $out $in %s", tool.ar, (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))
|
||||
_p(1, "description = ar $out")
|
||||
_p("")
|
||||
|
||||
local objfiles = {}
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.isswiftfile(file) then
|
||||
table.insert(objfiles, swift.objectname(cfg, file))
|
||||
end
|
||||
end
|
||||
|
||||
swift.file_rules(cfg, objfiles)
|
||||
|
||||
_p("")
|
||||
|
||||
swift.linker(prj, cfg, objfiles, tool)
|
||||
end
|
||||
|
||||
function swift.objectname(cfg, file)
|
||||
return path.join("$obj_dir", path.getname(file)..".o")
|
||||
end
|
||||
|
||||
function swift.file_rules(cfg, objfiles)
|
||||
_p("build %s: swiftc %s", ninja.list(objfiles), ninja.list(cfg.files))
|
||||
_p(1, "obj_files = %s", ninja.arglist("-o", objfiles))
|
||||
end
|
||||
|
||||
function swift.linker(prj, cfg, objfiles, tool)
|
||||
local lddeps = ninja.list(premake.getlinks(cfg, "siblings", "fullpath"))
|
||||
|
||||
if cfg.kind == "StaticLib" then
|
||||
_p("build $target: ar %s | %s ", ninja.list(objfiles), lddeps)
|
||||
else
|
||||
local lddeps = ninja.list(premake.getlinks(cfg, "siblings", "fullpath"))
|
||||
_p("build $target: swiftlink %s | %s", ninja.list(objfiles), lddeps)
|
||||
end
|
||||
end
|
||||
Vendored
+180
@@ -0,0 +1,180 @@
|
||||
--
|
||||
-- Generates Ninja project file for Swift
|
||||
-- Copyright (c) 2016 Stuart Carnie and the GENie project
|
||||
--
|
||||
|
||||
local ninja = premake.ninja
|
||||
local swift = { }
|
||||
local p = premake
|
||||
|
||||
-- generate project + config build using incremental approach of generating individual .o files
|
||||
function ninja.generate_swift_incremental(prj)
|
||||
local pxy = ninja.get_proxy("prj", prj)
|
||||
local tool = premake.gettool(prj)
|
||||
|
||||
-- build a list of supported target platforms that also includes a generic build
|
||||
local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native")
|
||||
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in p.eachconfig(pxy, platform) do
|
||||
p.generate(cfg, cfg:getprojectfilename(), function() swift.generate_config(prj, cfg) end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function swift.generate_config(prj, cfg)
|
||||
local tool = premake.gettool(prj)
|
||||
|
||||
local flags = {
|
||||
swiftcflags = ninja.list(table.join(tool.getswiftcflags(cfg), cfg.buildoptions_swiftc)),
|
||||
}
|
||||
|
||||
|
||||
_p("# Swift project build file")
|
||||
_p("# generated with GENie ninja")
|
||||
_p("")
|
||||
|
||||
-- needed for implicit outputs, introduced in 1.7
|
||||
_p("ninja_required_version = 1.7")
|
||||
_p("")
|
||||
|
||||
_p("out_dir = %s", cfg.buildtarget.directory)
|
||||
_p("obj_dir = %s", path.join(cfg.objectsdir, prj.name .. ".build"))
|
||||
_p("module_name = %s", prj.name)
|
||||
_p("module_maps = %s", ninja.list(tool.getmodulemaps(cfg)))
|
||||
_p("swiftc_flags = %s", flags.swiftcflags)
|
||||
_p("swiftlink_flags = %s", flags.swiftlinkflags)
|
||||
_p("ar_flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false)))
|
||||
|
||||
local sdk = tool.get_sdk_path(cfg)
|
||||
if sdk then
|
||||
_p("toolchain_path = %s", tool.get_toolchain_path(cfg))
|
||||
_p("sdk_path = %s", sdk)
|
||||
_p("platform_path = %s", tool.get_sdk_platform_path(cfg))
|
||||
_p("sdk = -sdk $sdk_path")
|
||||
_p("ld_baseflags = -force_load $toolchain_path/usr/lib/arc/libarclite_macosx.a -L $out_dir -F $platform_path/Developer/Library/Frameworks -syslibroot $sdk_path -lobjc -lSystem -L $toolchain_path/usr/lib/swift/macosx -rpath $toolchain_path/usr/lib/swift/macosx -macosx_version_min 10.10.0 -no_objc_category_merging")
|
||||
else
|
||||
_p("sdk_path =")
|
||||
_p("sdk =")
|
||||
_p("ld_baseflags =")
|
||||
end
|
||||
_p("")
|
||||
|
||||
_p("# core rules for %s", cfg.name)
|
||||
_p("rule swiftc")
|
||||
_p(1, "command = %s -frontend -c -primary-file $in $files $target -enable-objc-interop $sdk -I $out_dir -enable-testing -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_doc_name swiftc_flags -module-name $module_name -emit-module-path $out_module_name -emit-dependencies-path $out.d -emit-reference-dependencies-path $obj_dir/$basename.swiftdeps -o $out", tool.swiftc)
|
||||
_p(1, "description = compile $out")
|
||||
_p("")
|
||||
|
||||
_p("rule swiftm")
|
||||
_p(1, "command = %s -frontend -emit-module $in $parse_as_library swiftc_flags $target -enable-objc-interop $sdk -I $out_dir -F $platform_path/Developer/Library/Frameworks -enable-testing -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_dir/$module_name.swiftdoc -module-name $module_name -o $out", tool.swift)
|
||||
_p(1, "description = generate module")
|
||||
_p("")
|
||||
|
||||
_p("rule swiftlink")
|
||||
_p(1, "command = %s $target $sdk $swiftlink_flags -L $out_dir -o $out_dir/$module_name -F $platform_path/Developer/Library/Frameworks $in", tool.swiftc)
|
||||
_p(1, "description = linking $target")
|
||||
_p("")
|
||||
|
||||
_p("rule ar")
|
||||
_p(1, "command = %s cr $ar_flags $out $in $libs %s", tool.ar, (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))
|
||||
_p(1, "description = ar $out")
|
||||
_p("")
|
||||
|
||||
_p("rule link")
|
||||
_p(" command = %s $in $ld_baseflags $all_ldflags $libs -o $out", tool.ld)
|
||||
_p(" description = link $out")
|
||||
_p("")
|
||||
|
||||
swift.file_rules(cfg, flags)
|
||||
|
||||
local objfiles = {}
|
||||
local modfiles = {}
|
||||
local docfiles = {}
|
||||
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.issourcefile(file) then
|
||||
table.insert(objfiles, swift.objectname(cfg, file))
|
||||
table.insert(modfiles, swift.modulename(cfg, file))
|
||||
table.insert(docfiles, swift.docname(cfg, file))
|
||||
end
|
||||
end
|
||||
_p("")
|
||||
|
||||
swift.linker(prj, cfg, {objfiles, modfiles, docfiles}, tool, flags)
|
||||
|
||||
_p("")
|
||||
end
|
||||
|
||||
function swift.objectname(cfg, file)
|
||||
return path.join("$obj_dir", path.getname(file)..".o")
|
||||
end
|
||||
|
||||
function swift.modulename(cfg, file)
|
||||
return path.join("$obj_dir", path.getname(file)..".o.swiftmodule")
|
||||
end
|
||||
|
||||
function swift.docname(cfg, file)
|
||||
return path.join("$obj_dir", path.getname(file)..".o.swiftdoc")
|
||||
end
|
||||
|
||||
function swift.file_rules(cfg, flags)
|
||||
_p("# build files")
|
||||
local sfiles = Set(cfg.files)
|
||||
|
||||
for _, file in ipairs(cfg.files) do
|
||||
if path.issourcefile(file) then
|
||||
if path.isswiftfile(file) then
|
||||
local objn = swift.objectname(cfg, file)
|
||||
local modn = swift.modulename(cfg, file)
|
||||
local docn = swift.docname(cfg, file)
|
||||
|
||||
_p("build %s | %s %s: swiftc %s", objn, modn, docn, file)
|
||||
_p(1, "out_module_name = %s", modn)
|
||||
_p(1, "out_doc_name = %s", docn)
|
||||
_p(1, "files = ".. ninja.list(sfiles - {file}))
|
||||
build_flags = "swiftcflags"
|
||||
end
|
||||
|
||||
_p(1, "flags = " .. flags[build_flags])
|
||||
elseif path.isresourcefile(file) then
|
||||
-- TODO
|
||||
end
|
||||
end
|
||||
|
||||
_p("")
|
||||
end
|
||||
|
||||
function swift.linker(prj, cfg, depfiles, tool)
|
||||
local all_ldflags = ninja.list(table.join(tool.getlibdirflags(cfg), tool.getldflags(cfg), cfg.linkoptions))
|
||||
local lddeps = ninja.list(premake.getlinks(cfg, "siblings", "fullpath"))
|
||||
local libs = lddeps .. " " .. ninja.list(tool.getlinkflags(cfg))
|
||||
|
||||
local function writevars()
|
||||
_p(1, "all_ldflags = " .. all_ldflags)
|
||||
_p(1, "libs = " .. libs)
|
||||
end
|
||||
|
||||
local objfiles, modfiles, docfiles = table.unpack(depfiles)
|
||||
|
||||
_p("build $out_dir/$module_name.swiftmodule | $out_dir/$module_name.swiftdoc: swiftm %s | %s", table.concat(modfiles, " "), table.concat(docfiles, " "))
|
||||
_p("")
|
||||
|
||||
local output = cfg:getoutputfilename()
|
||||
|
||||
if cfg.kind == "StaticLib" then
|
||||
local ar_flags = ninja.list(tool.getarchiveflags(cfg, cfg, false))
|
||||
_p("build %s: ar %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), lddeps)
|
||||
_p(1, "flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false)))
|
||||
elseif cfg.kind == "SharedLib" then
|
||||
_p("build %s : swiftlink %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), libs)
|
||||
writevars()
|
||||
elseif (cfg.kind == "ConsoleApp") or (cfg.kind == "WindowedApp") then
|
||||
--_p("build %s: link %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", cfg:getoutputfilename(), table.concat(objfiles, " "), lddeps)
|
||||
--writevars()
|
||||
_p("build %s: swiftlink %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), lddeps)
|
||||
else
|
||||
p.error("ninja action doesn't support this kind of target " .. cfg.kind)
|
||||
end
|
||||
|
||||
end
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
--
|
||||
-- GENie - Project generator tool
|
||||
-- https://github.com/bkaradzic/GENie#license
|
||||
--
|
||||
|
||||
premake.qbs = { }
|
||||
|
||||
local qbs = premake.qbs
|
||||
|
||||
newaction
|
||||
{
|
||||
-- Metadata for the command line and help system
|
||||
trigger = "qbs",
|
||||
shortname = "qbs",
|
||||
description = "Generate QBS build files",
|
||||
module = "qbs",
|
||||
|
||||
-- The capabilities of this action
|
||||
valid_kinds = {"ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle"},
|
||||
valid_languages = {"C", "C++"},
|
||||
valid_tools = {
|
||||
cc = { "gcc", "msc" },
|
||||
},
|
||||
|
||||
-- Solution and project generation logic
|
||||
onsolution = function(sln)
|
||||
io.eol = "\n"
|
||||
io.indent = "\t"
|
||||
io.escaper(qbs.esc)
|
||||
premake.generate(sln, sln.name .. ".creator.qbs", qbs.generate_solution)
|
||||
io.indent = " "
|
||||
premake.generate(sln, sln.name .. ".creator.qbs.user", qbs.generate_user)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
io.eol = "\n"
|
||||
io.indent = "\t"
|
||||
io.escaper(qbs.esc)
|
||||
premake.generate(prj, prj.name .. ".qbs", qbs.generate_project)
|
||||
end,
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
function premake.qbs.list(indent, name, table)
|
||||
if #table > 0 then
|
||||
_p(indent, '%s: [', name)
|
||||
for _, item in ipairs(table) do
|
||||
_p(indent+1, '"%s",', item:gsub('"', '\\"'))
|
||||
end
|
||||
_p(indent+1, ']')
|
||||
end
|
||||
end
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
--
|
||||
-- GENie - Project generator tool
|
||||
-- https://github.com/bkaradzic/GENie#license
|
||||
--
|
||||
|
||||
local qbs = premake.qbs
|
||||
|
||||
local function is_excluded(prj, cfg, file)
|
||||
if table.icontains(prj.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
if table.icontains(cfg.excludes, file) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function qbs.generate_project(prj)
|
||||
|
||||
local indent = 0
|
||||
|
||||
_p(indent, '/*')
|
||||
_p(indent, ' * QBS project file autogenerated by GENie')
|
||||
_p(indent, ' * https://github.com/bkaradzic/GENie')
|
||||
_p(indent, ' */')
|
||||
_p(indent, '')
|
||||
_p(indent, 'import qbs 1.0')
|
||||
_p(indent, '')
|
||||
|
||||
if prj.kind == "ConsoleApp" then
|
||||
_p(indent, 'CppApplication {')
|
||||
_p(indent + 1, 'consoleApplication: true')
|
||||
elseif prj.kind == "WindowedApp" then
|
||||
_p(indent, 'CppApplication {')
|
||||
_p(indent + 1, 'consoleApplication: false')
|
||||
elseif prj.kind == "StaticLib" then
|
||||
_p(indent, 'StaticLibrary {')
|
||||
elseif prj.kind == "SharedLib" then
|
||||
_p(indent, 'DynamicLibrary {')
|
||||
end
|
||||
|
||||
indent = indent + 1
|
||||
_p(indent, 'name: "' .. prj.name .. '"')
|
||||
|
||||
-- _p(indent, 'cpp.enableReproducibleBuilds: true')
|
||||
|
||||
_p(indent, 'Depends { name: "cpp" }')
|
||||
|
||||
-- List dependencies, if there are any
|
||||
local deps = premake.getdependencies(prj)
|
||||
if #deps > 0 then
|
||||
for _, depprj in ipairs(deps) do
|
||||
_p(indent, 'Depends { name: "%s" }', depprj.name)
|
||||
end
|
||||
end
|
||||
|
||||
local cc = premake.gettool(prj)
|
||||
local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native")
|
||||
|
||||
for _, platform in ipairs(platforms) do
|
||||
for cfg in premake.eachconfig(prj, platform) do
|
||||
|
||||
if cfg.platform ~= "Native" then
|
||||
|
||||
_p('');
|
||||
_p(indent, 'Properties { /* %s */', premake.getconfigname(cfg.name, cfg.platform, true))
|
||||
|
||||
indent = indent + 1
|
||||
|
||||
local arch = ""
|
||||
local linkerFlags = cfg.linkoptions
|
||||
|
||||
if cfg.platform == "x32" then
|
||||
arch = '&& qbs.architecture == "x86"'
|
||||
-- table.insert(linkerFlags, "-m32")
|
||||
elseif cfg.platform == "x64" then
|
||||
arch = '&& qbs.architecture == "x86_64"'
|
||||
-- table.insert(linkerFlags, "-m64")
|
||||
end
|
||||
|
||||
if cfg.name == "Debug" then
|
||||
_p(indent, 'condition: qbs.buildVariant == "debug" %s', arch)
|
||||
else
|
||||
_p(indent, 'condition: qbs.buildVariant == "release" %s', arch)
|
||||
end
|
||||
|
||||
_p(indent, 'targetName: "%s"', cfg.buildtarget.basename)
|
||||
_p(indent, 'destinationDirectory: "%s"', path.getabsolute('projects/qbs/' .. cfg.buildtarget.directory) .. '/')
|
||||
-- _p(indent, 'fileTagsFilter: "application"')
|
||||
-- _p(indent, 'qbs.install: true')
|
||||
-- _p(indent, 'qbs.installDir: "%s"', cfg.buildtarget.directory)
|
||||
-- _p(indent, 'buildDirectory: "%s"', cfg.objectsdir)
|
||||
|
||||
-- qbs.list(
|
||||
-- indent
|
||||
-- , "cpp.cppFlags"
|
||||
-- , cc.getcppflags(cfg)
|
||||
-- )
|
||||
|
||||
if cfg.flags.Cpp11 then
|
||||
_p(indent, 'cpp.cxxLanguageVersion: "c++11"')
|
||||
elseif cfg.flags.Cpp14 then
|
||||
_p(indent, 'cpp.cxxLanguageVersion: "c++14"')
|
||||
elseif cfg.flags.Cpp17 then
|
||||
_p(indent, 'cpp.cxxLanguageVersion: "c++17"')
|
||||
else
|
||||
_p(indent, 'cpp.cxxLanguageVersion: "c++98"')
|
||||
end
|
||||
|
||||
if os.is("windows") then
|
||||
if not cfg.flags.WinMain and (cfg.kind == 'ConsoleApp' or cfg.kind == 'WindowedApp') then
|
||||
if cfg.flags.Unicode then
|
||||
_p(indent, 'cpp.entryPoint: "wmainCRTStartup"')
|
||||
else
|
||||
_p(indent, 'cpp.entryPoint: "mainCRTStartup"')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.commonCompilerFlags"
|
||||
, cfg.buildoptions
|
||||
)
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.cFlags"
|
||||
, cfg.buildoptions_c
|
||||
)
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.cxxFlags"
|
||||
, cfg.buildoptions_cpp
|
||||
)
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.objcFlags"
|
||||
, cfg.buildoptions_objc
|
||||
)
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.objcxxFlags"
|
||||
, cfg.buildoptions_objc
|
||||
)
|
||||
|
||||
if cfg.flags.StaticRuntime then
|
||||
_p(indent, 'cpp.runtimeLibrary: "static"')
|
||||
else
|
||||
_p(indent, 'cpp.runtimeLibrary: "dynamic"')
|
||||
end
|
||||
|
||||
if cfg.flags.PedanticWarnings
|
||||
or cfg.flags.ExtraWarnings
|
||||
then
|
||||
_p(indent, 'cpp.warningLevel: "all"')
|
||||
else
|
||||
_p(indent, 'cpp.warningLevel: "default"')
|
||||
end
|
||||
|
||||
if cfg.flags.FatalWarnings then
|
||||
_p(indent, 'cpp.treatWarningsAsErrors: true')
|
||||
else
|
||||
_p(indent, 'cpp.treatWarningsAsErrors: false')
|
||||
end
|
||||
|
||||
if cfg.flags.NoRTTI then
|
||||
_p(indent, 'cpp.enableRtti: false')
|
||||
else
|
||||
_p(indent, 'cpp.enableRtti: true')
|
||||
end
|
||||
|
||||
if cfg.flags.NoExceptions then
|
||||
_p(indent, 'cpp.enableExceptions: false')
|
||||
else
|
||||
_p(indent, 'cpp.enableExceptions: true')
|
||||
end
|
||||
|
||||
if cfg.flags.Symbols then
|
||||
_p(indent, 'cpp.debugInformation: true')
|
||||
else
|
||||
_p(indent, 'cpp.debugInformation: false')
|
||||
end
|
||||
|
||||
if cfg.flags.Unicode then
|
||||
_p(indent, 'cpp.windowsApiCharacterSet: "unicode"')
|
||||
else
|
||||
_p(indent, 'cpp.windowsApiCharacterSet: ""')
|
||||
end
|
||||
|
||||
if not cfg.pchheader or cfg.flags.NoPCH then
|
||||
_p(indent, 'cpp.usePrecompiledHeader: false')
|
||||
else
|
||||
_p(indent, 'cpp.usePrecompiledHeader: true')
|
||||
_p(indent, 'Group {')
|
||||
_p(indent+1, 'name: "PCH"')
|
||||
_p(indent+1, 'files: ["' .. cfg.pchheader .. '"]')
|
||||
_p(indent+1, 'fileTags: ["cpp_pch_src"]')
|
||||
_p(indent, '}')
|
||||
end
|
||||
|
||||
for _, value in ipairs(cfg.flags) do
|
||||
if (value == "Optimize") then
|
||||
elseif (value == "OptimizeSize") then
|
||||
_p(indent, 'cpp.optimization: "small"')
|
||||
elseif (value == "OptimizeSpeed") then
|
||||
_p(indent, 'cpp.optimization: "fast"')
|
||||
end
|
||||
end
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.defines"
|
||||
, cfg.defines
|
||||
)
|
||||
|
||||
local sortedincdirs = table.join(cfg.userincludedirs, cfg.includedirs, cfg.systemincludedirs)
|
||||
table.sort(sortedincdirs, includesort)
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.includePaths"
|
||||
, sortedincdirs
|
||||
)
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.staticLibraries"
|
||||
, premake.getlinks(cfg, "system", "fullpath")
|
||||
)
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.libraryPaths"
|
||||
, cfg.libdirs
|
||||
)
|
||||
|
||||
qbs.list(
|
||||
indent
|
||||
, "cpp.linkerFlags"
|
||||
, linkerFlags
|
||||
)
|
||||
|
||||
table.sort(prj.files)
|
||||
if #prj.files > 0 then
|
||||
_p(indent, 'files: [')
|
||||
for _, file in ipairs(prj.files) do
|
||||
if path.iscfile(file)
|
||||
or path.iscppfile(file)
|
||||
or path.isobjcfile(file)
|
||||
or path.isresourcefile(file)
|
||||
or path.iscppheader(file) then
|
||||
if not is_excluded(prj, cfg, file) then
|
||||
_p(indent+1, '"%s",', file)
|
||||
end
|
||||
end
|
||||
end
|
||||
_p(indent+1, ']')
|
||||
end
|
||||
|
||||
if #prj.excludes > 0 then
|
||||
_p(indent, 'excludeFiles: [')
|
||||
table.sort(prj.excludes)
|
||||
for _, file in ipairs(prj.excludes) do
|
||||
if path.issourcefile(file) then
|
||||
_p(indent+1, '"%s",', file)
|
||||
end
|
||||
end
|
||||
_p(indent+1, ']')
|
||||
end
|
||||
|
||||
indent = indent - 1
|
||||
_p(indent, '}');
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
indent = indent - 1
|
||||
|
||||
_p(indent, '}')
|
||||
end
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
--
|
||||
-- GENie - Project generator tool
|
||||
-- https://github.com/bkaradzic/GENie#license
|
||||
--
|
||||
|
||||
local qbs = premake.qbs
|
||||
|
||||
function qbs.generate_solution(sln)
|
||||
|
||||
_p('/*')
|
||||
_p(' * QBS project file autogenerated by GENie')
|
||||
_p(' * https://github.com/bkaradzic/GENie')
|
||||
_p(' */')
|
||||
_p('')
|
||||
_p('import qbs')
|
||||
_p('')
|
||||
|
||||
_p(0, 'Project {')
|
||||
|
||||
_p(1, 'references: [')
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
_p(2, '"' .. prj.name .. '.qbs",')
|
||||
end
|
||||
_p(1, ']')
|
||||
|
||||
_p(0, '}')
|
||||
end
|
||||
|
||||
local function is_app(kind)
|
||||
if kind == "ConsoleApp" or kind == "WindowedApp" then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function qbs.generate_user(sln)
|
||||
|
||||
_p(0, '<?xml version="1.0" encoding="UTF-8"?>')
|
||||
_p(0, '<!DOCTYPE QtCreatorProject>')
|
||||
_p(0, '<!-- QBS project file autogenerated by GENie https://github.com/bkaradzic/GENie -->')
|
||||
_p(0, '<qtcreator>')
|
||||
|
||||
local startProject = 0
|
||||
local idx = 0
|
||||
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if is_app(prj.kind) then
|
||||
if sln.startproject == prj.name then
|
||||
startProject = idx
|
||||
end
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
|
||||
_p(1, '<data>')
|
||||
_p(2, '<variable>ProjectExplorer.Project.Target.0</variable>')
|
||||
|
||||
_p(2, '<valuemap type="QVariantMap">')
|
||||
|
||||
_p(3, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>')
|
||||
_p(3, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>')
|
||||
|
||||
local qbsguid = ""
|
||||
local qbsprofile = ""
|
||||
|
||||
local qtcreatordir = ""
|
||||
|
||||
if _OS == "windows" then
|
||||
qtcreatordir = path.join(os.getenv("APPDATA"), "QtProject/qtcreator")
|
||||
else
|
||||
qtcreatordir = path.join(os.getenv("HOME"), ".config/QtProject/qtcreator")
|
||||
end
|
||||
|
||||
local file = io.open(path.join(qtcreatordir, "qbs.conf"))
|
||||
if file == nil then
|
||||
file = io.open(path.join(qtcreatordir, "qbs/1.6.0/qbs.conf"))
|
||||
end
|
||||
|
||||
if file ~= nil then
|
||||
for line in file:lines() do
|
||||
if line == "[org]" then
|
||||
-- BK - Need to figure out how to extract kit associated profile name/guid...
|
||||
-- ~.config/QtProject/qtcreator/qbs.conf
|
||||
--
|
||||
-- [org]
|
||||
-- qt-project\qbs\preferences\qtcreator\kit\%7B9926e565-8fc0-448d-9d5d-4b0293efd443%7D=qtc_Desktop_1bffddf2
|
||||
--
|
||||
local str = 'qt-project\\qbs\\preferences\\qtcreator\\kit\\%'
|
||||
local index = string.len(str)+1
|
||||
for line in file:lines() do
|
||||
if index == string.find(line, '7B', index) then
|
||||
line = string.sub(line, index+2)
|
||||
qbsguid = string.sub(line, 1, 36)
|
||||
qbsprofile = string.sub(line, 41)
|
||||
--print(qbsguid, qbsprofile)
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
-- ~/.config/QtProject/qtcreator/qbs/1.6.0/qbs.conf
|
||||
--
|
||||
-- <key>org.qt-project.qbs.preferences.qtcreator.kit.{d67ae030-7a33-43e0-850a-afe9e47fe5e1}</key>
|
||||
-- <string>qtc_Desktop_ee88281c</string>
|
||||
|
||||
local str = '\t<key>org.qt-project.qbs.preferences.qtcreator.kit.'
|
||||
local index = string.len(str)+1
|
||||
for line in file:lines() do
|
||||
if qbsguid == "" and index == string.find(line, '{', index) then
|
||||
line = string.sub(line, index+1)
|
||||
qbsguid = string.sub(line, 1, 36)
|
||||
elseif qbsguid ~= "" then
|
||||
qbsprofile = string.sub(line, 10, 29)
|
||||
--print(qbsguid, qbsprofile)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
io.close(file)
|
||||
end
|
||||
|
||||
_p(3, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{%s}</value>', qbsguid)
|
||||
|
||||
_p(3, '<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>')
|
||||
_p(3, '<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>')
|
||||
_p(3, '<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">%d</value>', startProject)
|
||||
|
||||
-- BuildConfiguration
|
||||
idx = 0
|
||||
for _, cfgname in ipairs(sln.configurations) do
|
||||
-- cfg.objectsdir
|
||||
_p(3, '<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.%d">', idx)
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">build</value>')
|
||||
_p(4, '<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">')
|
||||
_p(5, '<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">')
|
||||
_p(6, '<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>')
|
||||
_p(6, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName"></value>')
|
||||
_p(6, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Qbs Build</value>')
|
||||
_p(6, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qbs.BuildStep</value>')
|
||||
_p(6, '<value type="bool" key="Qbs.CleanInstallRoot">false</value>')
|
||||
_p(6, '<valuemap type="QVariantMap" key="Qbs.Configuration">')
|
||||
_p(7, '<value type="QString" key="qbs.buildVariant">%s</value>', cfgname:lower())
|
||||
_p(7, '<value type="QString" key="qbs.profile">%s</value>', qbsprofile)
|
||||
_p(6, '</valuemap>')
|
||||
_p(5, '</valuemap>')
|
||||
_p(5, '<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>')
|
||||
_p(4, '</valuemap>')
|
||||
_p(4, '<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">')
|
||||
_p(5, '<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">')
|
||||
_p(6, '<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>')
|
||||
_p(6, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName"></value>')
|
||||
_p(6, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Qbs Clean</value>')
|
||||
_p(6, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qbs.CleanStep</value>')
|
||||
_p(6, '<value type="bool" key="Qbs.CleanAll">true</value>')
|
||||
_p(6, '<value type="bool" key="Qbs.DryKeepGoing">false</value>')
|
||||
_p(6, '<value type="bool" key="Qbs.DryRun">false</value>')
|
||||
_p(5, '</valuemap>')
|
||||
_p(5, '<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>')
|
||||
_p(4, '</valuemap>')
|
||||
_p(4, '<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>')
|
||||
_p(4, '<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>')
|
||||
_p(4, '<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>')
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">%s</value>', cfgname)
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>')
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qbs.QbsBuildConfiguration</value>')
|
||||
_p(3, '</valuemap>')
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
_p(3, '<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">%d</value>', idx)
|
||||
|
||||
-- DeployConfiguration
|
||||
_p(3, '<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">')
|
||||
_p(4, '<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">')
|
||||
_p(5, '<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>')
|
||||
_p(5, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>')
|
||||
_p(4, '</valuemap>')
|
||||
_p(4, '<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>')
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>')
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Qbs Install</value>')
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qbs.Deploy</value>')
|
||||
_p(3, '</valuemap>')
|
||||
_p(3, '<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>')
|
||||
|
||||
-- PluginSettings
|
||||
-- _p(3, '<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>')
|
||||
|
||||
-- RunConfiguration
|
||||
idx = 0
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
|
||||
if is_app(prj.kind) then
|
||||
-- _p(3, '<variable>ProjectExplorer.Project.Target.%d</variable>', idx)
|
||||
|
||||
_p(3, '<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.%d">', idx)
|
||||
|
||||
if idx == startProject then
|
||||
_p(4, '<value type="int" key="PE.EnvironmentAspect.Base">2</value>')
|
||||
else
|
||||
_p(4, '<value type="int" key="PE.EnvironmentAspect.Base">-1</value>')
|
||||
end
|
||||
_p(4, '<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>')
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">%s</value>', prj.name)
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>')
|
||||
_p(4, '<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qbs.RunConfiguration:%s.%s---Qbs.RC.NameSeparator---%s</value>', prj.name, qbsprofile, prj.name)
|
||||
|
||||
_p(4, '<value type="QString" key="Qbs.RunConfiguration.CommandLineArguments"></value>')
|
||||
|
||||
local cfg = premake.getconfig(prj, nil, nil)
|
||||
if cfg.debugdir ~= nil then
|
||||
_p(4, '<value type="QString" key="Qbs.RunConfiguration.WorkingDirectory">%s</value>', cfg.debugdir)
|
||||
else
|
||||
_p(4, '<value type="QString" key="Qbs.RunConfiguration.WorkingDirectory"></value>')
|
||||
end
|
||||
|
||||
_p(3, '</valuemap>')
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
|
||||
_p(3, '<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">%d</value>', idx)
|
||||
|
||||
_p(2, '</valuemap>')
|
||||
_p(1, '</data>')
|
||||
|
||||
_p(1, '<data>')
|
||||
_p(2, '<variable>ProjectExplorer.Project.TargetCount</variable>')
|
||||
_p(2, '<value type="int">1</value>')
|
||||
_p(1, '</data>')
|
||||
|
||||
_p(1, '<data>')
|
||||
_p(2, '<variable>Version</variable>')
|
||||
_p(2, '<value type="int">18</value>')
|
||||
_p(1, '</data>')
|
||||
|
||||
_p(0, '</qtcreator>')
|
||||
|
||||
end
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
--
|
||||
-- _vstudio.lua
|
||||
-- Define the Visual Studio 200x actions.
|
||||
-- Copyright (c) 2008-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.vstudio = { }
|
||||
|
||||
--
|
||||
-- Set default toolset
|
||||
--
|
||||
|
||||
local toolsets = {
|
||||
vs2010 = "v100",
|
||||
vs2012 = "v110",
|
||||
vs2013 = "v120",
|
||||
vs2015 = "v140",
|
||||
vs2017 = "v141",
|
||||
vs2019 = "v142",
|
||||
}
|
||||
premake.vstudio.toolset = toolsets[_ACTION] or "unknown?"
|
||||
premake.vstudio.splashpath = ''
|
||||
premake.vstudio.xpwarning = true
|
||||
|
||||
local vstudio = premake.vstudio
|
||||
|
||||
|
||||
--
|
||||
-- Map Premake platform identifiers to the Visual Studio versions. Adds the Visual
|
||||
-- Studio specific "any" and "mixed" to make solution generation easier.
|
||||
--
|
||||
|
||||
vstudio.platforms = {
|
||||
any = "Any CPU",
|
||||
mixed = "Mixed Platforms",
|
||||
Native = "Win32",
|
||||
x86 = "x86",
|
||||
x32 = "Win32",
|
||||
x64 = "x64",
|
||||
PS3 = "PS3",
|
||||
Xbox360 = "Xbox 360",
|
||||
ARM = "ARM",
|
||||
ARM64 = "ARM64",
|
||||
Orbis = "ORBIS",
|
||||
Durango = "Durango",
|
||||
TegraAndroid = "Tegra-Android",
|
||||
NX32 = "NX32",
|
||||
NX64 = "NX64",
|
||||
Emscripten = "Emscripten",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns the architecture identifier for a project.
|
||||
-- Used by the solutions.
|
||||
--
|
||||
|
||||
function vstudio.arch(prj)
|
||||
if (prj.language == "C#") then
|
||||
return "Any CPU"
|
||||
else
|
||||
return "Win32"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function vstudio.iswinrt()
|
||||
return vstudio.storeapp ~= nil and vstudio.storeapp ~= ''
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Process the solution's list of configurations and platforms, creates a list
|
||||
-- of build configuration/platform pairs in a Visual Studio compatible format.
|
||||
--
|
||||
|
||||
function vstudio.buildconfigs(sln)
|
||||
local cfgs = { }
|
||||
|
||||
local platforms = premake.filterplatforms(sln, vstudio.platforms, "Native")
|
||||
|
||||
-- Figure out what's in this solution
|
||||
local hascpp = premake.hascppproject(sln)
|
||||
local hasdotnet = premake.hasdotnetproject(sln)
|
||||
|
||||
-- "Mixed Platform" solutions are generally those containing both
|
||||
-- C/C++ and .NET projects. Starting in VS2010, all .NET solutions
|
||||
-- also contain the Mixed Platform option.
|
||||
if hasdotnet and (_ACTION > "vs2008" or hascpp) then
|
||||
table.insert(platforms, 1, "mixed")
|
||||
end
|
||||
|
||||
-- "Any CPU" is added to solutions with .NET projects. Starting in
|
||||
-- VS2010, only pure .NET solutions get this option.
|
||||
if hasdotnet and (_ACTION < "vs2010" or not hascpp) then
|
||||
table.insert(platforms, 1, "any")
|
||||
end
|
||||
|
||||
-- In Visual Studio 2010, pure .NET solutions replace the Win32 platform
|
||||
-- with x86. In mixed mode solution, x86 is used in addition to Win32.
|
||||
if _ACTION > "vs2008" then
|
||||
local platforms2010 = { }
|
||||
for _, platform in ipairs(platforms) do
|
||||
if vstudio.platforms[platform] == "Win32" then
|
||||
if hascpp then
|
||||
table.insert(platforms2010, platform)
|
||||
end
|
||||
if hasdotnet then
|
||||
table.insert(platforms2010, "x86")
|
||||
end
|
||||
else
|
||||
table.insert(platforms2010, platform)
|
||||
end
|
||||
end
|
||||
platforms = platforms2010
|
||||
end
|
||||
|
||||
|
||||
for _, buildcfg in ipairs(sln.configurations) do
|
||||
for _, platform in ipairs(platforms) do
|
||||
local entry = { }
|
||||
entry.src_buildcfg = buildcfg
|
||||
entry.src_platform = platform
|
||||
|
||||
-- PS3 is funky and needs special handling; it's more of a build
|
||||
-- configuration than a platform from Visual Studio's point of view.
|
||||
-- This has been fixed in VS2010 as it now truly supports 3rd party
|
||||
-- platforms, so only do this fixup when not in VS2010
|
||||
if platform ~= "PS3" or _ACTION > "vs2008" then
|
||||
entry.buildcfg = buildcfg
|
||||
entry.platform = vstudio.platforms[platform]
|
||||
else
|
||||
entry.buildcfg = platform .. " " .. buildcfg
|
||||
entry.platform = "Win32"
|
||||
end
|
||||
|
||||
-- create a name the way VS likes it
|
||||
entry.name = entry.buildcfg .. "|" .. entry.platform
|
||||
|
||||
-- flag the "fake" platforms added for .NET
|
||||
entry.isreal = (platform ~= "any" and platform ~= "mixed")
|
||||
|
||||
table.insert(cfgs, entry)
|
||||
end
|
||||
end
|
||||
|
||||
return cfgs
|
||||
end
|
||||
|
||||
--
|
||||
-- Process imported projects and set properties that are needed
|
||||
-- for generating the solution.
|
||||
--
|
||||
|
||||
function premake.vstudio.bakeimports(sln)
|
||||
for _,iprj in ipairs(sln.importedprojects) do
|
||||
if string.find(iprj.location, ".csproj") ~= nil then
|
||||
iprj.language = "C#"
|
||||
else
|
||||
iprj.language = "C++"
|
||||
end
|
||||
|
||||
local f, err = io.open(iprj.location, "r")
|
||||
if (not f) then
|
||||
error(err, 1)
|
||||
end
|
||||
|
||||
local projcontents = f:read("*all")
|
||||
f:close()
|
||||
|
||||
local found, _, uuid = string.find(projcontents, "<ProjectGuid>{([%w%-]+)}</ProjectGuid>")
|
||||
if not found then
|
||||
error("Could not find ProjectGuid element in project " .. iprj.location, 1)
|
||||
end
|
||||
|
||||
iprj.uuid = uuid
|
||||
|
||||
if iprj.language == "C++" and string.find(projcontents, "<CLRSupport>true</CLRSupport>") then
|
||||
iprj.flags.Managed = true
|
||||
end
|
||||
|
||||
iprj.relpath = path.getrelative(sln.location, iprj.location)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Look up a imported project by project path
|
||||
--
|
||||
function premake.vstudio.getimportprj(prjpath, sln)
|
||||
for _,iprj in ipairs(sln.importedprojects) do
|
||||
if prjpath == iprj.relpath then
|
||||
return iprj
|
||||
end
|
||||
end
|
||||
|
||||
error("Could not find reference import project " .. prjpath, 1)
|
||||
end
|
||||
|
||||
--
|
||||
-- Clean Visual Studio files
|
||||
--
|
||||
|
||||
function vstudio.cleansolution(sln)
|
||||
premake.clean.file(sln, "%%.sln")
|
||||
premake.clean.file(sln, "%%.suo")
|
||||
premake.clean.file(sln, "%%.ncb")
|
||||
-- MonoDevelop files
|
||||
premake.clean.file(sln, "%%.userprefs")
|
||||
premake.clean.file(sln, "%%.usertasks")
|
||||
end
|
||||
|
||||
function vstudio.cleanproject(prj)
|
||||
local fname = premake.project.getfilename(prj, "%%")
|
||||
|
||||
os.remove(fname .. ".vcproj")
|
||||
os.remove(fname .. ".vcproj.user")
|
||||
|
||||
os.remove(fname .. ".vcxproj")
|
||||
os.remove(fname .. ".vcxproj.user")
|
||||
os.remove(fname .. ".vcxproj.filters")
|
||||
|
||||
os.remove(fname .. ".csproj")
|
||||
os.remove(fname .. ".csproj.user")
|
||||
|
||||
os.remove(fname .. ".pidb")
|
||||
os.remove(fname .. ".sdf")
|
||||
end
|
||||
|
||||
function vstudio.cleantarget(name)
|
||||
os.remove(name .. ".pdb")
|
||||
os.remove(name .. ".idb")
|
||||
os.remove(name .. ".ilk")
|
||||
os.remove(name .. ".vshost.exe")
|
||||
os.remove(name .. ".exe.manifest")
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Assemble the project file name.
|
||||
--
|
||||
|
||||
function vstudio.projectfile(prj)
|
||||
local pattern
|
||||
if prj.language == "C#" then
|
||||
pattern = "%%.csproj"
|
||||
else
|
||||
pattern = iif(_ACTION > "vs2008", "%%.vcxproj", "%%.vcproj")
|
||||
end
|
||||
|
||||
local fname = premake.project.getbasename(prj.name, pattern)
|
||||
fname = path.join(prj.location, fname)
|
||||
return fname
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns the Visual Studio tool ID for a given project type.
|
||||
--
|
||||
|
||||
function vstudio.tool(prj)
|
||||
if (prj.language == "C#") then
|
||||
return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"
|
||||
else
|
||||
return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
|
||||
end
|
||||
end
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
--
|
||||
-- vs2010.lua
|
||||
-- Baseline support for Visual Studio 2010.
|
||||
-- Copyright (c) 2013 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
local vc2010 = premake.vstudio.vc2010
|
||||
local vstudio = premake.vstudio
|
||||
|
||||
---
|
||||
-- Register a command-line action for Visual Studio 2010.
|
||||
---
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "vs2010",
|
||||
shortname = "Visual Studio 2010",
|
||||
description = "Generate Microsoft Visual Studio 2010 project files",
|
||||
os = "windows",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++", "C#"},
|
||||
|
||||
valid_tools = {
|
||||
cc = { "msc" },
|
||||
dotnet = { "msnet" },
|
||||
},
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.sln", vstudio.sln2005.generate)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, "%%.csproj", vstudio.cs2005.generate)
|
||||
premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user)
|
||||
else
|
||||
premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj)
|
||||
premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user)
|
||||
premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters)
|
||||
end
|
||||
end,
|
||||
|
||||
oncleansolution = premake.vstudio.cleansolution,
|
||||
oncleanproject = premake.vstudio.cleanproject,
|
||||
oncleantarget = premake.vstudio.cleantarget,
|
||||
|
||||
vstudio = {
|
||||
productVersion = "8.0.30703",
|
||||
solutionVersion = "11",
|
||||
targetFramework = "4.0",
|
||||
toolsVersion = "4.0",
|
||||
supports64bitEditContinue = false,
|
||||
intDirAbsolute = false,
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
--
|
||||
-- vs2012.lua
|
||||
-- Baseline support for Visual Studio 2012.
|
||||
-- Copyright (c) 2013 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.vstudio.vc2012 = {}
|
||||
local vc2012 = premake.vstudio.vc2012
|
||||
local vstudio = premake.vstudio
|
||||
|
||||
|
||||
---
|
||||
-- Register a command-line action for Visual Studio 2012.
|
||||
---
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "vs2012",
|
||||
shortname = "Visual Studio 2012",
|
||||
description = "Generate Microsoft Visual Studio 2012 project files",
|
||||
os = "windows",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++", "C#"},
|
||||
|
||||
valid_tools = {
|
||||
cc = { "msc" },
|
||||
dotnet = { "msnet" },
|
||||
},
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.sln", vstudio.sln2005.generate)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, "%%.csproj", vstudio.cs2005.generate)
|
||||
premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user)
|
||||
else
|
||||
premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj)
|
||||
premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user)
|
||||
premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters)
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
oncleansolution = premake.vstudio.cleansolution,
|
||||
oncleanproject = premake.vstudio.cleanproject,
|
||||
oncleantarget = premake.vstudio.cleantarget,
|
||||
|
||||
vstudio = {
|
||||
solutionVersion = "12",
|
||||
targetFramework = "4.5",
|
||||
toolsVersion = "4.0",
|
||||
supports64bitEditContinue = false,
|
||||
intDirAbsolute = false,
|
||||
}
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
--
|
||||
-- vs2013.lua
|
||||
-- Baseline support for Visual Studio 2013.
|
||||
-- Copyright (c) 2013 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.vstudio.vc2013 = {}
|
||||
local vc2013 = premake.vstudio.vc2013
|
||||
local vstudio = premake.vstudio
|
||||
|
||||
|
||||
---
|
||||
-- Register a command-line action for Visual Studio 2013.
|
||||
---
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "vs2013",
|
||||
shortname = "Visual Studio 2013",
|
||||
description = "Generate Microsoft Visual Studio 2013 project files",
|
||||
os = "windows",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++", "C#"},
|
||||
|
||||
valid_tools = {
|
||||
cc = { "msc" },
|
||||
dotnet = { "msnet" },
|
||||
},
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.sln", vstudio.sln2005.generate)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, "%%.csproj", vstudio.cs2005.generate)
|
||||
premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user)
|
||||
else
|
||||
premake.vstudio.needAppxManifest = false
|
||||
premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj)
|
||||
premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user)
|
||||
premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters)
|
||||
|
||||
if premake.vstudio.needAppxManifest then
|
||||
premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
oncleansolution = premake.vstudio.cleansolution,
|
||||
oncleanproject = premake.vstudio.cleanproject,
|
||||
oncleantarget = premake.vstudio.cleantarget,
|
||||
|
||||
vstudio = {
|
||||
solutionVersion = "12",
|
||||
targetFramework = "4.5",
|
||||
toolsVersion = "12.0",
|
||||
supports64bitEditContinue = false,
|
||||
intDirAbsolute = false,
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
--
|
||||
-- vs2015.lua
|
||||
-- Baseline support for Visual Studio 2015.
|
||||
--
|
||||
|
||||
premake.vstudio.vc2015 = {}
|
||||
local vc2015 = premake.vstudio.vc2015
|
||||
local vstudio = premake.vstudio
|
||||
|
||||
|
||||
---
|
||||
-- Register a command-line action for Visual Studio 2015.
|
||||
---
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "vs2015",
|
||||
shortname = "Visual Studio 2015",
|
||||
description = "Generate Microsoft Visual Studio 2015 project files",
|
||||
os = "windows",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++", "C#" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "msc" },
|
||||
dotnet = { "msnet" },
|
||||
},
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.sln", vstudio.sln2005.generate)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, "%%.csproj", vstudio.cs2005.generate)
|
||||
premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user)
|
||||
else
|
||||
premake.vstudio.needAppxManifest = false
|
||||
premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj)
|
||||
premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user)
|
||||
premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters)
|
||||
|
||||
if premake.vstudio.needAppxManifest then
|
||||
premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
oncleansolution = premake.vstudio.cleansolution,
|
||||
oncleanproject = premake.vstudio.cleanproject,
|
||||
oncleantarget = premake.vstudio.cleantarget,
|
||||
|
||||
vstudio = {
|
||||
solutionVersion = "12",
|
||||
targetFramework = "4.5",
|
||||
toolsVersion = "14.0",
|
||||
windowsTargetPlatformVersion = "8.1",
|
||||
supports64bitEditContinue = true,
|
||||
intDirAbsolute = false,
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
--
|
||||
-- vs2015.lua
|
||||
-- Baseline support for Visual Studio 2017.
|
||||
--
|
||||
|
||||
premake.vstudio.vc2017 = {}
|
||||
local vc2017 = premake.vstudio.vc2017
|
||||
local vstudio = premake.vstudio
|
||||
|
||||
|
||||
---
|
||||
-- Register a command-line action for Visual Studio 2017.
|
||||
---
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "vs2017",
|
||||
shortname = "Visual Studio 2017",
|
||||
description = "Generate Microsoft Visual Studio 2017 project files",
|
||||
os = "windows",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++", "C#" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "msc" },
|
||||
dotnet = { "msnet" },
|
||||
},
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.sln", vstudio.sln2005.generate)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, "%%.csproj", vstudio.cs2005.generate)
|
||||
premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user)
|
||||
else
|
||||
premake.vstudio.needAppxManifest = false
|
||||
premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj)
|
||||
premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user)
|
||||
premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters)
|
||||
|
||||
if premake.vstudio.needAppxManifest then
|
||||
premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
oncleansolution = premake.vstudio.cleansolution,
|
||||
oncleanproject = premake.vstudio.cleanproject,
|
||||
oncleantarget = premake.vstudio.cleantarget,
|
||||
|
||||
vstudio = {
|
||||
solutionVersion = "12",
|
||||
targetFramework = "4.5.2",
|
||||
toolsVersion = "15.0",
|
||||
windowsTargetPlatformVersion = "8.1",
|
||||
supports64bitEditContinue = true,
|
||||
intDirAbsolute = false,
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
--
|
||||
-- vs2015.lua
|
||||
-- Baseline support for Visual Studio 2019.
|
||||
--
|
||||
|
||||
premake.vstudio.vc2019 = {}
|
||||
local vc2019 = premake.vstudio.vc2019
|
||||
local vstudio = premake.vstudio
|
||||
|
||||
|
||||
---
|
||||
-- Register a command-line action for Visual Studio 2019.
|
||||
---
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "vs2019",
|
||||
shortname = "Visual Studio 2019",
|
||||
description = "Generate Microsoft Visual Studio 2019 project files",
|
||||
os = "windows",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++", "C#" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "msc" },
|
||||
dotnet = { "msnet" },
|
||||
},
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.sln", vstudio.sln2005.generate)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
if premake.isdotnetproject(prj) then
|
||||
premake.generate(prj, "%%.csproj", vstudio.cs2005.generate)
|
||||
premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user)
|
||||
else
|
||||
premake.vstudio.needAppxManifest = false
|
||||
premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj)
|
||||
premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user)
|
||||
premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters)
|
||||
|
||||
if premake.vstudio.needAppxManifest then
|
||||
premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
oncleansolution = premake.vstudio.cleansolution,
|
||||
oncleanproject = premake.vstudio.cleanproject,
|
||||
oncleantarget = premake.vstudio.cleantarget,
|
||||
|
||||
vstudio = {
|
||||
solutionVersion = "12",
|
||||
targetFramework = "4.7.2",
|
||||
toolsVersion = "16.0",
|
||||
windowsTargetPlatformVersion = "10.0",
|
||||
supports64bitEditContinue = true,
|
||||
intDirAbsolute = false,
|
||||
}
|
||||
}
|
||||
Vendored
+263
@@ -0,0 +1,263 @@
|
||||
--
|
||||
-- vs2005_solution.lua
|
||||
-- Generate a Visual Studio 2005-2010 solution.
|
||||
-- Copyright (c) 2009-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.vstudio.sln2005 = { }
|
||||
local vstudio = premake.vstudio
|
||||
local sln2005 = premake.vstudio.sln2005
|
||||
|
||||
|
||||
function sln2005.generate(sln)
|
||||
io.eol = '\r\n'
|
||||
|
||||
-- Precompute Visual Studio configurations
|
||||
sln.vstudio_configs = premake.vstudio.buildconfigs(sln)
|
||||
-- Prepare imported projects
|
||||
premake.vstudio.bakeimports(sln)
|
||||
|
||||
-- Mark the file as Unicode
|
||||
_p('\239\187\191')
|
||||
|
||||
sln2005.reorderProjects(sln)
|
||||
|
||||
sln2005.header(sln)
|
||||
|
||||
for grp in premake.solution.eachgroup(sln) do
|
||||
sln2005.group(grp)
|
||||
end
|
||||
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
sln2005.project(prj)
|
||||
end
|
||||
|
||||
for _,iprj in ipairs(sln.importedprojects) do
|
||||
sln2005.importproject(iprj)
|
||||
end
|
||||
|
||||
_p('Global')
|
||||
sln2005.platforms(sln)
|
||||
sln2005.project_platforms(sln)
|
||||
sln2005.properties(sln)
|
||||
sln2005.project_groups(sln)
|
||||
_p('EndGlobal')
|
||||
end
|
||||
|
||||
--
|
||||
-- If a startup project is specified, move it to the front of the project list.
|
||||
-- This will make Visual Studio treat it like a startup project.
|
||||
--
|
||||
|
||||
function sln2005.reorderProjects(sln)
|
||||
if sln.startproject then
|
||||
for i, prj in ipairs(sln.projects) do
|
||||
if sln.startproject == prj.name then
|
||||
-- Move group tree containing the project to start of group list
|
||||
local cur = prj.group
|
||||
while cur ~= nil do
|
||||
-- Remove group from array
|
||||
for j, group in ipairs(sln.groups) do
|
||||
if group == cur then
|
||||
table.remove(sln.groups, j)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Add back at start
|
||||
table.insert(sln.groups, 1, cur)
|
||||
cur = cur.parent
|
||||
end
|
||||
|
||||
-- Move the project itself to start
|
||||
table.remove(sln.projects, i)
|
||||
table.insert(sln.projects, 1, prj)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Generate the solution header
|
||||
--
|
||||
|
||||
function sln2005.header(sln)
|
||||
local action = premake.action.current()
|
||||
_p('Microsoft Visual Studio Solution File, Format Version %d.00', action.vstudio.solutionVersion)
|
||||
if(_ACTION:sub(3) == "2015" or _ACTION:sub(3) == "2017") then
|
||||
_p('# Visual Studio %s', action.vstudio.toolsVersion:sub(1,2))
|
||||
elseif(_ACTION:sub(3) == "2019") then
|
||||
_p('# Visual Studio Version %s', action.vstudio.toolsVersion:sub(1,2))
|
||||
else
|
||||
_p('# Visual Studio %s', _ACTION:sub(3))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Write out an entry for a project
|
||||
--
|
||||
|
||||
function sln2005.project(prj)
|
||||
-- Build a relative path from the solution file to the project file
|
||||
local projpath = path.translate(path.getrelative(prj.solution.location, vstudio.projectfile(prj)), "\\")
|
||||
|
||||
_p('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(prj), prj.name, projpath, prj.uuid)
|
||||
sln2005.projectdependencies(prj)
|
||||
_p('EndProject')
|
||||
end
|
||||
|
||||
--
|
||||
-- Write out an entry for a solution folder
|
||||
--
|
||||
|
||||
function sln2005.group(grp)
|
||||
_p('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "%s", "%s", "{%s}"', grp.name, grp.name, grp.uuid)
|
||||
_p('EndProject')
|
||||
end
|
||||
|
||||
--
|
||||
-- Write out an entry for an imported project
|
||||
--
|
||||
function sln2005.importproject(iprj)
|
||||
_p('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(iprj), path.getbasename(iprj.location), iprj.relpath, iprj.uuid)
|
||||
_p('EndProject')
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Write out the list of project dependencies for a particular project.
|
||||
--
|
||||
|
||||
function sln2005.projectdependencies(prj)
|
||||
local deps = premake.getdependencies(prj)
|
||||
if #deps > 0 then
|
||||
local function compareuuid(a, b) return a.uuid < b.uuid end
|
||||
table.sort(deps, compareuuid)
|
||||
_p('\tProjectSection(ProjectDependencies) = postProject')
|
||||
for _, dep in ipairs(deps) do
|
||||
_p('\t\t{%s} = {%s}', dep.uuid, dep.uuid)
|
||||
end
|
||||
_p('\tEndProjectSection')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Write out the contents of the SolutionConfigurationPlatforms section, which
|
||||
-- lists all of the configuration/platform pairs that exist in the solution.
|
||||
--
|
||||
|
||||
function sln2005.platforms(sln)
|
||||
_p('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution')
|
||||
for _, cfg in ipairs(sln.vstudio_configs) do
|
||||
_p('\t\t%s = %s', cfg.name, cfg.name)
|
||||
end
|
||||
_p('\tEndGlobalSection')
|
||||
end
|
||||
|
||||
--
|
||||
-- Write the entries for a single project in the ProjectConfigurationPlatforms section, which maps
|
||||
-- the configuration/platform pairs into each project of the solution.
|
||||
--
|
||||
|
||||
function sln2005.project_platform(prj, sln)
|
||||
for _, cfg in ipairs(sln.vstudio_configs) do
|
||||
|
||||
-- C# .NET projects always map to the "Any CPU" platform (for now, at
|
||||
-- least). C++ .NET projects always map to x64. For native C++,
|
||||
-- "Any CPU" and "Mixed Platforms" map to the first
|
||||
-- C++ compatible target platform in the solution list.
|
||||
local mapped
|
||||
local buildfor
|
||||
if premake.isdotnetproject(prj) then
|
||||
buildfor = "x64"
|
||||
mapped = "Any CPU"
|
||||
elseif prj.flags and prj.flags.Managed then
|
||||
mapped = "x64"
|
||||
else
|
||||
if cfg.platform == "Any CPU" or cfg.platform == "Mixed Platforms" then
|
||||
mapped = sln.vstudio_configs[3].platform
|
||||
else
|
||||
mapped = cfg.platform
|
||||
end
|
||||
end
|
||||
|
||||
local build_project = true
|
||||
|
||||
-- c# projects in a solution may not have a reference back to the solution, let
|
||||
-- the default handling decide whether to build it or not
|
||||
if prj.solution ~= nil then
|
||||
build_project = premake.getconfig(prj, cfg.src_buildcfg, cfg.src_platform).build
|
||||
end
|
||||
|
||||
_p('\t\t{%s}.%s.ActiveCfg = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped)
|
||||
if build_project then
|
||||
if mapped == cfg.platform or cfg.platform == "Mixed Platforms" or buildfor == cfg.platform then
|
||||
_p('\t\t{%s}.%s.Build.0 = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped)
|
||||
end
|
||||
|
||||
if premake.vstudio.iswinrt() and prj.kind == "WindowedApp" then
|
||||
_p('\t\t{%s}.%s.Deploy.0 = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Write out the contents of the ProjectConfigurationPlatforms section, which maps
|
||||
-- the configuration/platform pairs into each project of the solution.
|
||||
--
|
||||
|
||||
function sln2005.project_platforms(sln)
|
||||
_p('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution')
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
sln2005.project_platform(prj, sln)
|
||||
end
|
||||
|
||||
for _,iprj in ipairs(sln.importedprojects) do
|
||||
sln2005.project_platform(iprj, sln)
|
||||
end
|
||||
|
||||
_p('\tEndGlobalSection')
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Write out contents of the SolutionProperties section; currently unused.
|
||||
--
|
||||
|
||||
function sln2005.properties(sln)
|
||||
_p('\tGlobalSection(SolutionProperties) = preSolution')
|
||||
_p('\t\tHideSolutionNode = FALSE')
|
||||
_p('\tEndGlobalSection')
|
||||
end
|
||||
|
||||
--
|
||||
-- Write out list of project nestings
|
||||
--
|
||||
function sln2005.project_groups(sln)
|
||||
_p('\tGlobalSection(NestedProjects) = preSolution')
|
||||
|
||||
for grp in premake.solution.eachgroup(sln) do
|
||||
if grp.parent ~= nil then
|
||||
_p('\t\t{%s} = {%s}', grp.uuid, grp.parent.uuid)
|
||||
end
|
||||
end
|
||||
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if prj.group ~= nil then
|
||||
_p('\t\t{%s} = {%s}', prj.uuid, prj.group.uuid)
|
||||
end
|
||||
end
|
||||
|
||||
for _,iprj in ipairs(sln.importedprojects) do
|
||||
if iprj.group ~= nil then
|
||||
_p('\t\t{%s} = {%s}', iprj.uuid, iprj.group.uuid)
|
||||
end
|
||||
end
|
||||
|
||||
_p('\tEndGlobalSection')
|
||||
end
|
||||
Vendored
+1824
File diff suppressed because it is too large
Load Diff
+145
@@ -0,0 +1,145 @@
|
||||
--
|
||||
-- vs2010_vcxproj_filters.lua
|
||||
-- Generate a Visual Studio 2010 C/C++ filters file.
|
||||
-- Copyright (c) 2009-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
local vc2010 = premake.vstudio.vc2010
|
||||
local project = premake.project
|
||||
|
||||
|
||||
--
|
||||
-- The first portion of the filters file assigns unique IDs to each
|
||||
-- directory or virtual group. Would be cool if we could automatically
|
||||
-- map vpaths like "**.h" to an <Extensions>h</Extensions> element.
|
||||
--
|
||||
|
||||
function vc2010.filteridgroup(prj)
|
||||
local filters = { }
|
||||
local filterfound = false
|
||||
|
||||
for file in premake.project.eachfile(prj, true) do
|
||||
-- split the path into its component parts
|
||||
local folders = string.explode(file.vpath, "/", true)
|
||||
local path = ""
|
||||
for i = 1, #folders - 1 do
|
||||
-- element is only written if there *are* filters
|
||||
if not filterfound then
|
||||
filterfound = true
|
||||
_p(1,'<ItemGroup>')
|
||||
end
|
||||
|
||||
path = path .. folders[i]
|
||||
|
||||
-- have I seen this path before?
|
||||
if not filters[path] then
|
||||
filters[path] = true
|
||||
_p(2, '<Filter Include="%s">', path)
|
||||
_p(3, '<UniqueIdentifier>{%s}</UniqueIdentifier>', os.uuid(path))
|
||||
_p(2, '</Filter>')
|
||||
end
|
||||
|
||||
-- prepare for the next subfolder
|
||||
path = path .. "\\"
|
||||
end
|
||||
end
|
||||
|
||||
for _, custombuildtask in ipairs(prj.custombuildtask or {}) do
|
||||
for _, buildtask in ipairs(custombuildtask or {}) do
|
||||
local folders = string.explode(path.trimdots(path.getrelative(prj.location,buildtask[1])), "/", true)
|
||||
local path = ""
|
||||
for i = 1, #folders - 1 do
|
||||
-- element is only written if there *are* filters
|
||||
if not filterfound then
|
||||
filterfound = true
|
||||
_p(1,'<ItemGroup>')
|
||||
end
|
||||
|
||||
path = path .. folders[i]
|
||||
|
||||
-- have I seen this path before?
|
||||
if not filters[path] then
|
||||
filters[path] = true
|
||||
_p(2, '<Filter Include="%s">', path)
|
||||
_p(3, '<UniqueIdentifier>{%s}</UniqueIdentifier>', os.uuid(path))
|
||||
_p(2, '</Filter>')
|
||||
end
|
||||
|
||||
-- prepare for the next subfolder
|
||||
path = path .. "\\"
|
||||
end
|
||||
end
|
||||
end
|
||||
if filterfound then
|
||||
_p(1,'</ItemGroup>')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- The second portion of the filters file assigns filters to each source
|
||||
-- code file, as needed. Section is one of "ClCompile", "ClInclude",
|
||||
-- "ResourceCompile", or "None".
|
||||
--
|
||||
|
||||
function vc2010.filefiltergroup(prj, section, kind)
|
||||
local files = vc2010.getfilegroup(prj, section) or {}
|
||||
|
||||
if kind == nill then
|
||||
kind = section
|
||||
end
|
||||
|
||||
if (section == "CustomBuild") then
|
||||
for _, custombuildtask in ipairs(prj.custombuildtask or {}) do
|
||||
for _, buildtask in ipairs(custombuildtask or {}) do
|
||||
local fcfg = { }
|
||||
fcfg.name = path.getrelative(prj.location,buildtask[1])
|
||||
fcfg.vpath = path.trimdots(fcfg.name)
|
||||
table.insert(files, fcfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
if #files > 0 then
|
||||
_p(1,'<ItemGroup>')
|
||||
for _, file in ipairs(files) do
|
||||
local filter
|
||||
if file.name ~= file.vpath then
|
||||
filter = path.getdirectory(file.vpath)
|
||||
else
|
||||
filter = path.getdirectory(file.name)
|
||||
end
|
||||
|
||||
if filter ~= "." then
|
||||
_p(2,'<%s Include=\"%s\">', kind, path.translate(file.name, "\\"))
|
||||
_p(3,'<Filter>%s</Filter>', path.translate(filter, "\\"))
|
||||
_p(2,'</%s>', kind)
|
||||
else
|
||||
_p(2,'<%s Include=\"%s\" />', kind, path.translate(file.name, "\\"))
|
||||
end
|
||||
end
|
||||
_p(1,'</ItemGroup>')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Output the VC2010 filters file
|
||||
--
|
||||
|
||||
function vc2010.generate_filters(prj)
|
||||
io.indent = " "
|
||||
vc2010.header()
|
||||
vc2010.filteridgroup(prj)
|
||||
vc2010.filefiltergroup(prj, "None")
|
||||
vc2010.filefiltergroup(prj, "ClInclude")
|
||||
vc2010.filefiltergroup(prj, "ClCompile")
|
||||
vc2010.filefiltergroup(prj, "Object")
|
||||
vc2010.filefiltergroup(prj, "ResourceCompile")
|
||||
vc2010.filefiltergroup(prj, "CustomBuild")
|
||||
vc2010.filefiltergroup(prj, "AppxManifest")
|
||||
vc2010.filefiltergroup(prj, "Natvis")
|
||||
vc2010.filefiltergroup(prj, "Image")
|
||||
vc2010.filefiltergroup(prj, "DeploymentContent", "None")
|
||||
vc2010.filefiltergroup(prj, "MASM")
|
||||
_p('</Project>')
|
||||
end
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
--
|
||||
-- _xcode.lua
|
||||
-- Define the Apple XCode action and support functions.
|
||||
-- Copyright (c) 2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.xcode = { }
|
||||
|
||||
--
|
||||
-- Verify only single target kind for Xcode project
|
||||
--
|
||||
-- @param prj
|
||||
-- Project to be analyzed
|
||||
--
|
||||
|
||||
function premake.xcode.checkproject(prj)
|
||||
-- Xcode can't mix target kinds within a project
|
||||
local last
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
if last and last ~= cfg.kind then
|
||||
error("Project '" .. prj.name .. "' uses more than one target kind; not supported by Xcode", 0)
|
||||
end
|
||||
last = cfg.kind
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Set default toolset
|
||||
--
|
||||
|
||||
premake.xcode.toolset = "macosx"
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
--
|
||||
-- xcode10.lua
|
||||
-- Define the Apple XCode 10.0 action and support functions.
|
||||
--
|
||||
|
||||
local premake = premake
|
||||
premake.xcode10 = { }
|
||||
|
||||
local xcode = premake.xcode
|
||||
local xcode8 = premake.xcode8
|
||||
local xcode9 = premake.xcode9
|
||||
local xcode10 = premake.xcode10
|
||||
|
||||
function xcode10.XCBuildConfiguration_Project(tr, prj, cfg)
|
||||
local options = xcode9.XCBuildConfiguration_Project(tr, prj, cfg)
|
||||
|
||||
return table.merge(options, {
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = "YES",
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = "YES",
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = "YES",
|
||||
CLANG_WARN_COMMA = "YES",
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = "YES",
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = "YES",
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = "YES",
|
||||
CLANG_WARN_STRICT_PROTOTYPES = "YES",
|
||||
})
|
||||
end
|
||||
|
||||
function xcode10.XCBuildConfiguration_Target(tr, target, cfg)
|
||||
local options = xcode8.XCBuildConfiguration_Target(tr, target, cfg)
|
||||
|
||||
if not cfg.flags.ObjcARC then
|
||||
options.CLANG_ENABLE_OBJC_WEAK = "YES"
|
||||
end
|
||||
|
||||
return options
|
||||
end
|
||||
|
||||
function xcode10.project(prj)
|
||||
local tr = xcode.buildprjtree(prj)
|
||||
xcode.Header(tr, 48)
|
||||
xcode.PBXBuildFile(tr)
|
||||
xcode.PBXContainerItemProxy(tr)
|
||||
xcode.PBXFileReference(tr,prj)
|
||||
xcode.PBXFrameworksBuildPhase(tr)
|
||||
xcode.PBXGroup(tr)
|
||||
xcode.PBXNativeTarget(tr)
|
||||
xcode.PBXProject(tr, "8.0")
|
||||
xcode.PBXReferenceProxy(tr)
|
||||
xcode.PBXResourcesBuildPhase(tr)
|
||||
xcode.PBXShellScriptBuildPhase(tr)
|
||||
xcode.PBXCopyFilesBuildPhase(tr)
|
||||
xcode.PBXSourcesBuildPhase(tr,prj)
|
||||
xcode.PBXVariantGroup(tr)
|
||||
xcode.PBXTargetDependency(tr)
|
||||
xcode.XCBuildConfiguration(tr, prj, {
|
||||
ontarget = xcode10.XCBuildConfiguration_Target,
|
||||
onproject = xcode10.XCBuildConfiguration_Project,
|
||||
})
|
||||
xcode.XCBuildConfigurationList(tr)
|
||||
xcode.Footer(tr)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- xcode10 action
|
||||
--
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "xcode10",
|
||||
shortname = "Xcode 10",
|
||||
description = "Generate Apple Xcode 10 project files",
|
||||
os = "macosx",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "gcc" },
|
||||
},
|
||||
|
||||
valid_platforms = {
|
||||
Native = "Native",
|
||||
x32 = "Native 32-bit",
|
||||
x64 = "Native 64-bit",
|
||||
Universal = "Universal",
|
||||
},
|
||||
|
||||
default_platform = "Native",
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode10.project)
|
||||
xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes")
|
||||
end,
|
||||
|
||||
oncleanproject = function(prj)
|
||||
premake.clean.directory(prj, "%%.xcodeproj")
|
||||
premake.clean.directory(prj, "%%.xcworkspace")
|
||||
end,
|
||||
|
||||
oncheckproject = xcode.checkproject,
|
||||
|
||||
xcode = {
|
||||
iOSTargetPlatformVersion = nil,
|
||||
macOSTargetPlatformVersion = nil,
|
||||
tvOSTargetPlatformVersion = nil,
|
||||
},
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
--
|
||||
-- xcode11.lua
|
||||
-- Define the Apple XCode 11.0 action and support functions.
|
||||
--
|
||||
|
||||
local premake = premake
|
||||
premake.xcode11 = { }
|
||||
|
||||
local xcode = premake.xcode
|
||||
local xcode10 = premake.xcode10
|
||||
local xcode11 = premake.xcode11
|
||||
|
||||
function xcode11.XCBuildConfiguration_Target(tr, target, cfg)
|
||||
local options = xcode10.XCBuildConfiguration_Target(tr, target, cfg)
|
||||
options.CODE_SIGN_IDENTITY = "-"
|
||||
return options
|
||||
end
|
||||
|
||||
function xcode11.project(prj)
|
||||
local tr = xcode.buildprjtree(prj)
|
||||
xcode.Header(tr, 48)
|
||||
xcode.PBXBuildFile(tr)
|
||||
xcode.PBXContainerItemProxy(tr)
|
||||
xcode.PBXFileReference(tr,prj)
|
||||
xcode.PBXFrameworksBuildPhase(tr)
|
||||
xcode.PBXGroup(tr)
|
||||
xcode.PBXNativeTarget(tr)
|
||||
xcode.PBXProject(tr, "8.0")
|
||||
xcode.PBXReferenceProxy(tr)
|
||||
xcode.PBXResourcesBuildPhase(tr)
|
||||
xcode.PBXShellScriptBuildPhase(tr)
|
||||
xcode.PBXCopyFilesBuildPhase(tr)
|
||||
xcode.PBXSourcesBuildPhase(tr,prj)
|
||||
xcode.PBXVariantGroup(tr)
|
||||
xcode.PBXTargetDependency(tr)
|
||||
xcode.XCBuildConfiguration(tr, prj, {
|
||||
ontarget = xcode11.XCBuildConfiguration_Target,
|
||||
onproject = xcode10.XCBuildConfiguration_Project,
|
||||
})
|
||||
xcode.XCBuildConfigurationList(tr)
|
||||
xcode.Footer(tr)
|
||||
end
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- xcode11 action
|
||||
--
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "xcode11",
|
||||
shortname = "Xcode 11",
|
||||
description = "Generate Apple Xcode 11 project files",
|
||||
os = "macosx",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "gcc" },
|
||||
},
|
||||
|
||||
valid_platforms = { Native = "Native" },
|
||||
default_platform = "Native",
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode11.project)
|
||||
xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes")
|
||||
end,
|
||||
|
||||
oncleanproject = function(prj)
|
||||
premake.clean.directory(prj, "%%.xcodeproj")
|
||||
premake.clean.directory(prj, "%%.xcworkspace")
|
||||
end,
|
||||
|
||||
oncheckproject = xcode.checkproject,
|
||||
|
||||
xcode = {
|
||||
iOSTargetPlatformVersion = nil,
|
||||
macOSTargetPlatformVersion = nil,
|
||||
tvOSTargetPlatformVersion = nil,
|
||||
},
|
||||
}
|
||||
+362
@@ -0,0 +1,362 @@
|
||||
--
|
||||
-- _xcode8.lua
|
||||
-- Define the Apple XCode 8.0 action and support functions.
|
||||
--
|
||||
|
||||
local premake = premake
|
||||
premake.xcode8 = { }
|
||||
|
||||
local xcode = premake.xcode
|
||||
local xcode8 = premake.xcode8
|
||||
|
||||
function xcode8.XCBuildConfiguration_Target(tr, target, cfg)
|
||||
local cfgname = xcode.getconfigname(cfg)
|
||||
local installpaths = {
|
||||
ConsoleApp = "/usr/local/bin",
|
||||
WindowedApp = "$(HOME)/Applications",
|
||||
SharedLib = "/usr/local/lib",
|
||||
StaticLib = "/usr/local/lib",
|
||||
Bundle = "$(LOCAL_LIBRARY_DIR)/Bundles",
|
||||
}
|
||||
|
||||
-- options table to return
|
||||
local options = {
|
||||
ALWAYS_SEARCH_USER_PATHS = "NO",
|
||||
GCC_DYNAMIC_NO_PIC = "NO",
|
||||
GCC_MODEL_TUNING = "G5",
|
||||
INSTALL_PATH = installpaths[cfg.kind],
|
||||
PRODUCT_NAME = cfg.buildtarget.basename,
|
||||
}
|
||||
|
||||
if not cfg.flags.Symbols then
|
||||
options.DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"
|
||||
end
|
||||
|
||||
if cfg.kind ~= "StaticLib" and cfg.buildtarget.prefix ~= "" then
|
||||
options.EXECUTABLE_PREFIX = cfg.buildtarget.prefix
|
||||
end
|
||||
|
||||
if cfg.targetextension then
|
||||
local ext = cfg.targetextension
|
||||
options.EXECUTABLE_EXTENSION = iif(ext:startswith("."), ext:sub(2), ext)
|
||||
end
|
||||
|
||||
if cfg.flags.ObjcARC then
|
||||
options.CLANG_ENABLE_OBJC_ARC = "YES"
|
||||
end
|
||||
|
||||
local outdir = path.getdirectory(cfg.buildtarget.bundlepath)
|
||||
if outdir ~= "." then
|
||||
options.CONFIGURATION_BUILD_DIR = outdir
|
||||
end
|
||||
|
||||
if tr.infoplist then
|
||||
options.INFOPLIST_FILE = tr.infoplist.cfg.name
|
||||
end
|
||||
|
||||
local infoplist_file = nil
|
||||
|
||||
for _, v in ipairs(cfg.files) do
|
||||
-- for any file named *info.plist, use it as the INFOPLIST_FILE
|
||||
if (string.find (string.lower (v), 'info.plist') ~= nil) then
|
||||
infoplist_file = string.format('$(SRCROOT)/%s', v)
|
||||
end
|
||||
end
|
||||
|
||||
if infoplist_file ~= nil then
|
||||
options.INFOPLIST_FILE = infoplist_file
|
||||
end
|
||||
|
||||
local action = premake.action.current()
|
||||
local get_opt = function(opt, def)
|
||||
return (opt and #opt > 0) and opt or def
|
||||
end
|
||||
|
||||
local iosversion = get_opt(cfg.iostargetplatformversion, action.xcode.iOSTargetPlatformVersion)
|
||||
local macosversion = get_opt(cfg.macostargetplatformversion, action.xcode.macOSTargetPlatformVersion)
|
||||
local tvosversion = get_opt(cfg.tvostargetplatformversion, action.xcode.tvOSTargetPlatformVersion)
|
||||
|
||||
if iosversion then
|
||||
options.IPHONEOS_DEPLOYMENT_TARGET = iosversion
|
||||
elseif macosversion then
|
||||
options.MACOSX_DEPLOYMENT_TARGET = macosversion
|
||||
elseif tvosversion then
|
||||
options.TVOS_DEPLOYMENT_TARGET = tvosversion
|
||||
end
|
||||
|
||||
if cfg.kind == "Bundle" and not cfg.options.SkipBundling then
|
||||
options.PRODUCT_BUNDLE_IDENTIFIER = "genie." .. cfg.buildtarget.basename:gsub("%s+", ".") --replace spaces with .
|
||||
local ext = cfg.targetextension
|
||||
if ext then
|
||||
options.WRAPPER_EXTENSION = iif(ext:startswith("."), ext:sub(2), ext)
|
||||
else
|
||||
options.WRAPPER_EXTENSION = "bundle"
|
||||
end
|
||||
end
|
||||
|
||||
return options
|
||||
end
|
||||
|
||||
function xcode8.XCBuildConfiguration_Project(tr, prj, cfg)
|
||||
local cfgname = xcode.getconfigname(cfg)
|
||||
local archs = {
|
||||
Native = nil,
|
||||
x32 = "i386",
|
||||
x64 = "x86_64",
|
||||
Universal32 = "$(ARCHS_STANDARD_32_BIT)",
|
||||
Universal64 = "$(ARCHS_STANDARD_64_BIT)",
|
||||
Universal = "$(ARCHS_STANDARD_32_64_BIT)",
|
||||
}
|
||||
|
||||
-- build list of "other" C/C++ flags
|
||||
local checks = {
|
||||
["-ffast-math"] = cfg.flags.FloatFast,
|
||||
["-ffloat-store"] = cfg.flags.FloatStrict,
|
||||
["-fomit-frame-pointer"] = cfg.flags.NoFramePointer,
|
||||
}
|
||||
|
||||
local cflags = { }
|
||||
for flag, check in pairs(checks) do
|
||||
if check then
|
||||
table.insert(cflags, flag)
|
||||
end
|
||||
end
|
||||
|
||||
-- build list of "other" linked flags. All libraries that aren't frameworks
|
||||
-- are listed here, so I don't have to try and figure out if they are ".a"
|
||||
-- or ".dylib", which Xcode requires to list in the Frameworks section
|
||||
local ldflags = { }
|
||||
for _, lib in ipairs(premake.getlinks(cfg, "system")) do
|
||||
if not xcode.isframework(lib) then
|
||||
table.insert(ldflags, "-l" .. lib)
|
||||
end
|
||||
end
|
||||
|
||||
-- options table to return
|
||||
local options = {
|
||||
ARCHS = archs[cfg.platform],
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = "YES",
|
||||
CLANG_WARN_BOOL_CONVERSION = "YES",
|
||||
CLANG_WARN_CONSTANT_CONVERSION = "YES",
|
||||
CLANG_WARN_EMPTY_BODY = "YES",
|
||||
CLANG_WARN_ENUM_CONVERSION = "YES",
|
||||
CLANG_WARN_INFINITE_RECURSION = "YES",
|
||||
CLANG_WARN_INT_CONVERSION = "YES",
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = "YES",
|
||||
CLANG_WARN_UNREACHABLE_CODE = "YES",
|
||||
CONFIGURATION_TEMP_DIR = "$(OBJROOT)",
|
||||
ENABLE_STRICT_OBJC_MSGSEND = "YES",
|
||||
ENABLE_TESTABILITY = "YES",
|
||||
GCC_C_LANGUAGE_STANDARD = "gnu99",
|
||||
GCC_NO_COMMON_BLOCKS = "YES",
|
||||
GCC_PREPROCESSOR_DEFINITIONS = cfg.defines,
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = "NO",
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = "YES",
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = "YES",
|
||||
GCC_WARN_UNDECLARED_SELECTOR = "YES",
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = "YES",
|
||||
GCC_WARN_UNUSED_FUNCTION = "YES",
|
||||
GCC_WARN_UNUSED_VARIABLE = "YES",
|
||||
HEADER_SEARCH_PATHS = table.join(cfg.includedirs, cfg.systemincludedirs),
|
||||
LIBRARY_SEARCH_PATHS = cfg.libdirs,
|
||||
OBJROOT = cfg.objectsdir,
|
||||
ONLY_ACTIVE_ARCH = "YES",
|
||||
OTHER_CFLAGS = table.join(cflags, cfg.buildoptions, cfg.buildoptions_c),
|
||||
OTHER_CPLUSPLUSFLAGS = table.join(cflags, cfg.buildoptions, cfg.buildoptions_cpp),
|
||||
OTHER_LDFLAGS = table.join(ldflags, cfg.linkoptions),
|
||||
SDKROOT = xcode.toolset,
|
||||
USER_HEADER_SEARCH_PATHS = cfg.userincludedirs,
|
||||
}
|
||||
|
||||
if tr.entitlements then
|
||||
options.CODE_SIGN_ENTITLEMENTS = tr.entitlements.cfg.name
|
||||
end
|
||||
|
||||
local targetdir = path.getdirectory(cfg.buildtarget.bundlepath)
|
||||
if targetdir ~= "." then
|
||||
options.CONFIGURATION_BUILD_DIR = "$(SYMROOT)"
|
||||
options.SYMROOT = targetdir
|
||||
end
|
||||
|
||||
if cfg.flags.Symbols then
|
||||
options.COPY_PHASE_STRIP = "NO"
|
||||
end
|
||||
|
||||
local excluded = xcode.cfg_excluded_files(prj, cfg)
|
||||
if #excluded > 0 then
|
||||
options.EXCLUDED_SOURCE_FILE_NAMES = excluded
|
||||
end
|
||||
|
||||
if cfg.flags.NoExceptions then
|
||||
options.GCC_ENABLE_CPP_EXCEPTIONS = "NO"
|
||||
end
|
||||
|
||||
if cfg.flags.NoRTTI then
|
||||
options.GCC_ENABLE_CPP_RTTI = "NO"
|
||||
end
|
||||
|
||||
if cfg.flags.Symbols and not cfg.flags.NoEditAndContinue then
|
||||
options.GCC_ENABLE_FIX_AND_CONTINUE = "YES"
|
||||
end
|
||||
|
||||
if cfg.flags.NoExceptions then
|
||||
options.GCC_ENABLE_OBJC_EXCEPTIONS = "NO"
|
||||
end
|
||||
|
||||
if cfg.flags.Optimize or cfg.flags.OptimizeSize then
|
||||
options.GCC_OPTIMIZATION_LEVEL = "s"
|
||||
elseif cfg.flags.OptimizeSpeed then
|
||||
options.GCC_OPTIMIZATION_LEVEL = 3
|
||||
else
|
||||
options.GCC_OPTIMIZATION_LEVEL = 0
|
||||
end
|
||||
|
||||
if cfg.pchheader and not cfg.flags.NoPCH then
|
||||
options.GCC_PRECOMPILE_PREFIX_HEADER = "YES"
|
||||
|
||||
-- Visual Studio requires the PCH header to be specified in the same way
|
||||
-- it appears in the #include statements used in the source code; the PCH
|
||||
-- source actual handles the compilation of the header. GCC compiles the
|
||||
-- header file directly, and needs the file's actual file system path in
|
||||
-- order to locate it.
|
||||
|
||||
-- To maximize the compatibility between the two approaches, see if I can
|
||||
-- locate the specified PCH header on one of the include file search paths
|
||||
-- and, if so, adjust the path automatically so the user doesn't have
|
||||
-- add a conditional configuration to the project script.
|
||||
|
||||
local pch = cfg.pchheader
|
||||
for _, incdir in ipairs(cfg.includedirs) do
|
||||
|
||||
-- convert this back to an absolute path for os.isfile()
|
||||
local abspath = path.getabsolute(path.join(cfg.project.location, incdir))
|
||||
|
||||
local testname = path.join(abspath, pch)
|
||||
if os.isfile(testname) then
|
||||
pch = path.getrelative(cfg.location, testname)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
options.GCC_PREFIX_HEADER = pch
|
||||
end
|
||||
|
||||
if cfg.flags.FatalWarnings then
|
||||
options.GCC_TREAT_WARNINGS_AS_ERRORS = "YES"
|
||||
end
|
||||
|
||||
if cfg.kind == "Bundle" then
|
||||
options.MACH_O_TYPE = "mh_bundle"
|
||||
end
|
||||
|
||||
if cfg.flags.StaticRuntime then
|
||||
options.STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = "static"
|
||||
end
|
||||
|
||||
if cfg.flags.PedanticWarnings or cfg.flags.ExtraWarnings then
|
||||
options.WARNING_CFLAGS = "-Wall"
|
||||
end
|
||||
|
||||
if cfg.flags.Cpp11 then
|
||||
options.CLANG_CXX_LANGUAGE_STANDARD = "c++11"
|
||||
elseif cfg.flags.Cpp14 or cfg.flags.CppLatest then
|
||||
options.CLANG_CXX_LANGUAGE_STANDARD = "c++14"
|
||||
elseif cfg.flags.Cpp17 then
|
||||
-- XCode8 does not support C++17, but other actions use this as
|
||||
-- base that *do* support C++17, so check if this is the current
|
||||
-- action before erroring.
|
||||
if premake.action.current() == premake.action.get("xcode8") then
|
||||
error("XCode8 does not support C++17.")
|
||||
end
|
||||
end
|
||||
|
||||
for _, val in ipairs(premake.xcode.parameters) do
|
||||
local eqpos = string.find(val, "=")
|
||||
if eqpos ~= nil then
|
||||
local key = string.trim(string.sub(val, 1, eqpos - 1))
|
||||
local value = string.trim(string.sub(val, eqpos + 1))
|
||||
options[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
return options
|
||||
end
|
||||
|
||||
function xcode8.project(prj)
|
||||
local tr = xcode.buildprjtree(prj)
|
||||
xcode.Header(tr, 48)
|
||||
xcode.PBXBuildFile(tr)
|
||||
xcode.PBXContainerItemProxy(tr)
|
||||
xcode.PBXFileReference(tr,prj)
|
||||
xcode.PBXFrameworksBuildPhase(tr)
|
||||
xcode.PBXGroup(tr)
|
||||
xcode.PBXNativeTarget(tr)
|
||||
xcode.PBXProject(tr, "8.0")
|
||||
xcode.PBXReferenceProxy(tr)
|
||||
xcode.PBXResourcesBuildPhase(tr)
|
||||
xcode.PBXShellScriptBuildPhase(tr)
|
||||
xcode.PBXCopyFilesBuildPhase(tr)
|
||||
xcode.PBXSourcesBuildPhase(tr,prj)
|
||||
xcode.PBXVariantGroup(tr)
|
||||
xcode.PBXTargetDependency(tr)
|
||||
xcode.XCBuildConfiguration(tr, prj, {
|
||||
ontarget = xcode8.XCBuildConfiguration_Target,
|
||||
onproject = xcode8.XCBuildConfiguration_Project,
|
||||
})
|
||||
xcode.XCBuildConfigurationList(tr)
|
||||
xcode.Footer(tr)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- xcode8 action
|
||||
--
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "xcode8",
|
||||
shortname = "Xcode 8",
|
||||
description = "Generate Apple Xcode 8 project files",
|
||||
os = "macosx",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "gcc" },
|
||||
},
|
||||
|
||||
valid_platforms = {
|
||||
Native = "Native",
|
||||
x32 = "Native 32-bit",
|
||||
x64 = "Native 64-bit",
|
||||
Universal = "Universal",
|
||||
},
|
||||
|
||||
default_platform = "Native",
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode8.project)
|
||||
xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes")
|
||||
end,
|
||||
|
||||
oncleanproject = function(prj)
|
||||
premake.clean.directory(prj, "%%.xcodeproj")
|
||||
premake.clean.directory(prj, "%%.xcworkspace")
|
||||
end,
|
||||
|
||||
oncheckproject = xcode.checkproject,
|
||||
|
||||
xcode = {
|
||||
iOSTargetPlatformVersion = nil,
|
||||
macOSTargetPlatformVersion = nil,
|
||||
tvOSTargetPlatformVersion = nil,
|
||||
},
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
--
|
||||
-- xcode9.lua
|
||||
-- Define the Apple XCode 9.0 action and support functions.
|
||||
--
|
||||
|
||||
local premake = premake
|
||||
premake.xcode9 = { }
|
||||
|
||||
local xcode = premake.xcode
|
||||
local xcode8 = premake.xcode8
|
||||
local xcode9 = premake.xcode9
|
||||
|
||||
function xcode9.XCBuildConfiguration_Project(tr, prj, cfg)
|
||||
local options = xcode8.XCBuildConfiguration_Project(tr, prj, cfg)
|
||||
|
||||
if cfg.flags.Cpp17 or cfg.flags.CppLatest then
|
||||
options.CLANG_CXX_LANGUAGE_STANDARD = "c++17"
|
||||
end
|
||||
|
||||
return table.merge(options, {
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = "YES",
|
||||
CLANG_WARN_COMMA = "YES",
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = "YES",
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = "YES",
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = "YES",
|
||||
CLANG_WARN_STRICT_PROTOTYPES = "YES",
|
||||
})
|
||||
end
|
||||
|
||||
function xcode9.project(prj)
|
||||
local tr = xcode.buildprjtree(prj)
|
||||
xcode.Header(tr, 48)
|
||||
xcode.PBXBuildFile(tr)
|
||||
xcode.PBXContainerItemProxy(tr)
|
||||
xcode.PBXFileReference(tr,prj)
|
||||
xcode.PBXFrameworksBuildPhase(tr)
|
||||
xcode.PBXGroup(tr)
|
||||
xcode.PBXNativeTarget(tr)
|
||||
xcode.PBXProject(tr, "8.0")
|
||||
xcode.PBXReferenceProxy(tr)
|
||||
xcode.PBXResourcesBuildPhase(tr)
|
||||
xcode.PBXShellScriptBuildPhase(tr)
|
||||
xcode.PBXCopyFilesBuildPhase(tr)
|
||||
xcode.PBXSourcesBuildPhase(tr,prj)
|
||||
xcode.PBXVariantGroup(tr)
|
||||
xcode.PBXTargetDependency(tr)
|
||||
xcode.XCBuildConfiguration(tr, prj, {
|
||||
ontarget = xcode8.XCBuildConfiguration_Target,
|
||||
onproject = xcode9.XCBuildConfiguration_Project,
|
||||
})
|
||||
xcode.XCBuildConfigurationList(tr)
|
||||
xcode.Footer(tr)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- xcode9 action
|
||||
--
|
||||
|
||||
newaction
|
||||
{
|
||||
trigger = "xcode9",
|
||||
shortname = "Xcode 9",
|
||||
description = "Generate Apple Xcode 9 project files",
|
||||
os = "macosx",
|
||||
|
||||
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" },
|
||||
|
||||
valid_languages = { "C", "C++" },
|
||||
|
||||
valid_tools = {
|
||||
cc = { "gcc" },
|
||||
},
|
||||
|
||||
valid_platforms = {
|
||||
Native = "Native",
|
||||
x32 = "Native 32-bit",
|
||||
x64 = "Native 64-bit",
|
||||
Universal = "Universal",
|
||||
},
|
||||
|
||||
default_platform = "Native",
|
||||
|
||||
onsolution = function(sln)
|
||||
premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings)
|
||||
premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme)
|
||||
end,
|
||||
|
||||
onproject = function(prj)
|
||||
premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode9.project)
|
||||
xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes")
|
||||
end,
|
||||
|
||||
oncleanproject = function(prj)
|
||||
premake.clean.directory(prj, "%%.xcodeproj")
|
||||
premake.clean.directory(prj, "%%.xcworkspace")
|
||||
end,
|
||||
|
||||
oncheckproject = xcode.checkproject,
|
||||
|
||||
xcode = {
|
||||
iOSTargetPlatformVersion = nil,
|
||||
macOSTargetPlatformVersion = nil,
|
||||
tvOSTargetPlatformVersion = nil,
|
||||
},
|
||||
}
|
||||
+1277
File diff suppressed because it is too large
Load Diff
+186
@@ -0,0 +1,186 @@
|
||||
--
|
||||
-- xcode_project.lua
|
||||
-- Generate an Xcode C/C++ project.
|
||||
-- Copyright (c) 2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
local xcode = premake.xcode
|
||||
local tree = premake.tree
|
||||
|
||||
--
|
||||
-- Create a tree corresponding to what is shown in the Xcode project browser
|
||||
-- pane, with nodes for files and folders, resources, frameworks, and products.
|
||||
--
|
||||
-- @param prj
|
||||
-- The project being generated.
|
||||
-- @returns
|
||||
-- A tree, loaded with metadata, which mirrors Xcode's view of the project.
|
||||
--
|
||||
|
||||
function xcode.buildprjtree(prj)
|
||||
local tr = premake.project.buildsourcetree(prj, true)
|
||||
|
||||
-- create a list of build configurations and assign IDs
|
||||
tr.configs = {}
|
||||
for _, cfgname in ipairs(prj.solution.configurations) do
|
||||
for _, platform in ipairs(prj.solution.xcode.platforms) do
|
||||
local cfg = premake.getconfig(prj, cfgname, platform)
|
||||
cfg.xcode = {}
|
||||
cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode, "tgt:"..platform..cfgname)
|
||||
cfg.xcode.projectid = xcode.newid(tr, "prj:"..platform..cfgname)
|
||||
table.insert(tr.configs, cfg)
|
||||
end
|
||||
end
|
||||
|
||||
-- convert localized resources from their filesystem layout (English.lproj/MainMenu.xib)
|
||||
-- to Xcode's display layout (MainMenu.xib/English).
|
||||
tree.traverse(tr, {
|
||||
onbranch = function(node)
|
||||
if path.getextension(node.name) == ".lproj" then
|
||||
local lang = path.getbasename(node.name) -- "English", "French", etc.
|
||||
|
||||
-- create a new language group for each file it contains
|
||||
for _, filenode in ipairs(node.children) do
|
||||
local grpnode = node.parent.children[filenode.name]
|
||||
if not grpnode then
|
||||
grpnode = tree.insert(node.parent, tree.new(filenode.name))
|
||||
grpnode.kind = "vgroup"
|
||||
end
|
||||
|
||||
-- convert the file node to a language node and add to the group
|
||||
filenode.name = path.getbasename(lang)
|
||||
tree.insert(grpnode, filenode)
|
||||
end
|
||||
|
||||
-- remove this directory from the tree
|
||||
tree.remove(node)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- fix .xcassets files, they should be treated as a file, not a folder
|
||||
tree.traverse(tr, {
|
||||
onbranch = function(node)
|
||||
if path.getextension(node.name) == ".xcassets" then
|
||||
node.children = {}
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- the special folder "Frameworks" lists all linked frameworks
|
||||
tr.frameworks = tree.new("Frameworks")
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
for _, link in ipairs(premake.getlinks(cfg, "system", "fullpath")) do
|
||||
local name = path.getname(link)
|
||||
if xcode.isframework(name) and not tr.frameworks.children[name] then
|
||||
node = tree.insert(tr.frameworks, tree.new(name))
|
||||
node.path = link
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- only add it to the tree if there are frameworks to link
|
||||
if #tr.frameworks.children > 0 then
|
||||
tree.insert(tr, tr.frameworks)
|
||||
end
|
||||
|
||||
-- the special folder "Products" holds the target produced by the project; this
|
||||
-- is populated below
|
||||
tr.products = tree.insert(tr, tree.new("Products"))
|
||||
|
||||
-- the special folder "Projects" lists sibling project dependencies
|
||||
tr.projects = tree.new("Projects")
|
||||
for _, dep in ipairs(premake.getdependencies(prj, "sibling", "object")) do
|
||||
-- create a child node for the dependency's xcodeproj
|
||||
local xcpath = xcode.getxcodeprojname(dep)
|
||||
local xcnode = tree.insert(tr.projects, tree.new(path.getname(xcpath)))
|
||||
xcnode.path = xcpath
|
||||
xcnode.project = dep
|
||||
xcnode.productgroupid = xcode.newid(xcnode, "prodgrp")
|
||||
xcnode.productproxyid = xcode.newid(xcnode, "prodprox")
|
||||
xcnode.targetproxyid = xcode.newid(xcnode, "targprox")
|
||||
xcnode.targetdependid = xcode.newid(xcnode, "targdep")
|
||||
|
||||
-- create a grandchild node for the dependency's link target
|
||||
local cfg = premake.getconfig(dep, prj.configurations[1])
|
||||
node = tree.insert(xcnode, tree.new(cfg.linktarget.name))
|
||||
node.path = cfg.linktarget.fullpath
|
||||
node.cfg = cfg
|
||||
end
|
||||
|
||||
if #tr.projects.children > 0 then
|
||||
tree.insert(tr, tr.projects)
|
||||
end
|
||||
|
||||
-- Add intermediate paths so groups have sensible locations
|
||||
|
||||
-- find common prefixes going up the tree
|
||||
tree.traverse(tr, {
|
||||
onbranchexit = function(node)
|
||||
for _, child in ipairs(node.children) do
|
||||
if (child.location) then
|
||||
if (node.location) then
|
||||
while (not string.startswith(child.location, node.location)) do
|
||||
node.location = path.getdirectory(node.location)
|
||||
end
|
||||
else
|
||||
node.location = path.getdirectory(child.location)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
onleaf = function(node)
|
||||
if (node.cfg) then
|
||||
node.location = node.cfg.name
|
||||
end
|
||||
end
|
||||
}, true)
|
||||
|
||||
-- now convert to relative where possible
|
||||
tree.traverse(tr, {
|
||||
onbranchexit = function(node, depth)
|
||||
if (node.location and node.parent and node.parent.location) then
|
||||
node.location = path.getrelative(node.parent.location, node.location)
|
||||
end
|
||||
end,
|
||||
onleaf = function(node, depth)
|
||||
if (node.location and node.parent and node.parent.location) then
|
||||
node.location = path.getrelative(node.parent.location, node.location)
|
||||
end
|
||||
end
|
||||
}, true)
|
||||
|
||||
-- Final setup
|
||||
tree.traverse(tr, {
|
||||
onnode = function(node)
|
||||
-- assign IDs to every node in the tree
|
||||
node.id = xcode.newid(node)
|
||||
|
||||
-- assign build IDs to buildable files
|
||||
if xcode.getbuildcategory(node) then
|
||||
node.buildid = xcode.newid(node, "build")
|
||||
end
|
||||
|
||||
-- remember key files that are needed elsewhere
|
||||
if string.endswith(node.name, "Info.plist") then
|
||||
tr.infoplist = node
|
||||
end
|
||||
if string.endswith(node.name, ".entitlements") then
|
||||
tr.entitlements = node
|
||||
end
|
||||
end
|
||||
}, true)
|
||||
|
||||
-- Plug in the product node into the Products folder in the tree. The node
|
||||
-- was built in xcode.preparesolution() in xcode_common.lua; it contains IDs
|
||||
-- that are necessary for inter-project dependencies
|
||||
node = tree.insert(tr.products, prj.xcode.projectnode)
|
||||
node.kind = "product"
|
||||
node.path = node.cfg.buildtarget.fullpath
|
||||
node.cfgsection = xcode.newid(node, "cfg")
|
||||
node.resstageid = xcode.newid(node, "rez")
|
||||
node.sourcesid = xcode.newid(node, "src")
|
||||
node.fxstageid = xcode.newid(node, "fxs")
|
||||
|
||||
return tr
|
||||
end
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
--
|
||||
-- xcode_scheme.lua
|
||||
--
|
||||
|
||||
local premake = premake
|
||||
local xcode = premake.xcode
|
||||
|
||||
|
||||
--
|
||||
-- Print a BuildableReference element.
|
||||
--
|
||||
|
||||
local function buildableref(indent, prj, cfg)
|
||||
cfg = cfg or premake.eachconfig(prj)()
|
||||
|
||||
_p(indent + 0, '<BuildableReference')
|
||||
_p(indent + 1, 'BuildableIdentifier = "primary"')
|
||||
_p(indent + 1, 'BlueprintIdentifier = "%s"', prj.xcode.projectnode.targetid)
|
||||
_p(indent + 1, 'BuildableName = "%s"', cfg.buildtarget.name)
|
||||
_p(indent + 1, 'BlueprintName = "%s"', prj.name)
|
||||
_p(indent + 1, 'ReferencedContainer = "container:%s.xcodeproj">', prj.name)
|
||||
_p(indent + 0, '</BuildableReference>')
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Print a CommandLineArgs element, if needed by the provided config.
|
||||
--
|
||||
|
||||
local function cmdlineargs(indent, cfg)
|
||||
if #cfg.debugargs > 0 then
|
||||
_p(indent, '<CommandLineArguments>')
|
||||
for _, arg in ipairs(cfg.debugargs) do
|
||||
_p(indent + 1, '<CommandLineArgument')
|
||||
_p(indent + 2, 'argument = "%s"', arg)
|
||||
_p(indent + 2, 'isEnabled = "YES">')
|
||||
_p(indent + 1, '</CommandLineArgument>')
|
||||
end
|
||||
_p(indent, '</CommandLineArguments>')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Print an EnvironmentVariables element, if needed by the provided config.
|
||||
|
||||
local function envvars(indent, cfg)
|
||||
if #cfg.debugenvs > 0 then
|
||||
_p(indent, '<EnvironmentVariables>')
|
||||
for _, arg in ipairs(cfg.debugenvs) do
|
||||
local eq = arg:find("=")
|
||||
local k = arg:sub(1, eq)
|
||||
local v = arg:sub(eq + 1)
|
||||
_p(indent + 1, '<EnvironmentVariable')
|
||||
_p(indent + 2, 'key = "%s"', arg:sub(1, eq))
|
||||
_p(indent + 2, 'value = "%s"', arg:sub(eq))
|
||||
_p(indent + 2, 'isEnabled = "YES">')
|
||||
_p(indent + 1, '</EnvironmentVariable>')
|
||||
end
|
||||
_p(indent, '</EnvironmentVariables>')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Generate the customWorkingDir path from the given dir.
|
||||
--
|
||||
|
||||
local function workingdir(dir)
|
||||
if not path.isabsolute(dir) then
|
||||
dir = "$PROJECT_DIR/" .. dir
|
||||
end
|
||||
return dir
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Determine the best matching configuration.
|
||||
--
|
||||
-- @param fordebug
|
||||
-- True to find a debug configuration.
|
||||
--
|
||||
|
||||
local function bestconfig(prj, fordebug)
|
||||
local bestcfg = nil
|
||||
local bestscore = -1
|
||||
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
local score = 0
|
||||
|
||||
if cfg.platform == "Native" then
|
||||
score = score + 10
|
||||
end
|
||||
|
||||
if fordebug and cfg.name == "Debug" then
|
||||
score = score + 1
|
||||
end
|
||||
|
||||
if not fordebug and cfg.name == "Release" then
|
||||
score = score + 1
|
||||
end
|
||||
|
||||
if score > bestscore then
|
||||
bestcfg = cfg
|
||||
bestscore = score
|
||||
end
|
||||
end
|
||||
|
||||
return bestcfg
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Print out an xcscheme file.
|
||||
--
|
||||
-- @param tobuild
|
||||
-- The list of targets to build. Assumed to be sorted.
|
||||
-- @param primary
|
||||
-- The target to set as test/profile/launch target.
|
||||
--
|
||||
|
||||
function xcode.scheme(tobuild, primary, schemecfg)
|
||||
_p('<?xml version="1.0" encoding="UTF-8"?>')
|
||||
_p('<Scheme')
|
||||
_p(1, 'LastUpgradeVersion = "0940"')
|
||||
_p(1, 'version = "1.3">')
|
||||
_p(1, '<BuildAction')
|
||||
_p(2, 'parallelizeBuildables = "YES"')
|
||||
_p(2, 'buildImplicitDependencies = "YES">')
|
||||
_p(2, '<BuildActionEntries>')
|
||||
|
||||
for _, prj in ipairs(tobuild) do
|
||||
_p(3, '<BuildActionEntry')
|
||||
_p(4, 'buildForTesting = "YES"')
|
||||
_p(4, 'buildForRunning = "YES"')
|
||||
_p(4, 'buildForProfiling = "YES"')
|
||||
_p(4, 'buildForArchiving = "YES"')
|
||||
_p(4, 'buildForAnalyzing = "YES">')
|
||||
buildableref(4, prj)
|
||||
_p(3, '</BuildActionEntry>')
|
||||
end
|
||||
|
||||
local debugcfg = schemecfg or bestconfig(primary, true)
|
||||
local releasecfg = schemecfg or bestconfig(primary, false)
|
||||
local debugname = xcode.getconfigname(debugcfg)
|
||||
local releasename = xcode.getconfigname(releasecfg)
|
||||
|
||||
_p(2, '</BuildActionEntries>')
|
||||
_p(1, '</BuildAction>')
|
||||
_p(1, '<TestAction')
|
||||
_p(2, 'buildConfiguration = "%s"', debugname)
|
||||
_p(2, 'selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"')
|
||||
_p(2, 'selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"')
|
||||
_p(2, 'shouldUseLaunchSchemeArgsEnv = "YES">')
|
||||
_p(2, '<Testables>')
|
||||
_p(2, '</Testables>')
|
||||
_p(2, '<MacroExpansion>')
|
||||
buildableref(3, primary, debugcfg)
|
||||
_p(2, '</MacroExpansion>')
|
||||
_p(2, '<AdditionalOptions>')
|
||||
_p(2, '</AdditionalOptions>')
|
||||
_p(1, '</TestAction>')
|
||||
_p(1, '<LaunchAction')
|
||||
_p(2, 'buildConfiguration = "%s"', debugname)
|
||||
_p(2, 'selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"')
|
||||
_p(2, 'selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"')
|
||||
_p(2, 'launchStyle = "0"')
|
||||
if debugcfg.debugdir then
|
||||
_p(2, 'useCustomWorkingDirectory = "YES"')
|
||||
_p(2, 'customWorkingDirectory = "%s"', workingdir(debugcfg.debugdir))
|
||||
else
|
||||
_p(2, 'useCustomWorkingDirectory = "NO"')
|
||||
end
|
||||
_p(2, 'ignoresPersistentStateOnLaunch = "NO"')
|
||||
_p(2, 'debugDocumentVersioning = "YES"')
|
||||
_p(2, 'debugServiceExtension = "internal"')
|
||||
_p(2, 'allowLocationSimulation = "YES">')
|
||||
if debugcfg.debugcmd then
|
||||
_p(2, '<PathRunnable')
|
||||
_p(3, 'runnableDebuggingMode = "0"')
|
||||
_p(3, 'FilePath = "%s">', debugcfg.debugcmd)
|
||||
_p(2, '</PathRunnable>')
|
||||
else
|
||||
_p(2, '<BuildableProductRunnable')
|
||||
_p(3, 'runnableDebuggingMode = "0">')
|
||||
buildableref(3, primary, debugcfg)
|
||||
_p(2, '</BuildableProductRunnable>')
|
||||
end
|
||||
cmdlineargs(2, debugcfg)
|
||||
envvars(2, debugcfg)
|
||||
_p(2, '<AdditionalOptions>')
|
||||
_p(2, '</AdditionalOptions>')
|
||||
_p(1, '</LaunchAction>')
|
||||
_p(1, '<ProfileAction')
|
||||
_p(2, 'buildConfiguration = "%s"', releasename)
|
||||
_p(2, 'shouldUseLaunchSchemeArgsEnv = "YES"')
|
||||
_p(2, 'savedToolIdentifier = ""')
|
||||
if releasecfg.debugdir then
|
||||
_p(2, 'useCustomWorkingDirectory = "YES"')
|
||||
_p(2, 'customWorkingDirectory = "%s"', workingdir(releasecfg.debugdir))
|
||||
else
|
||||
_p(2, 'useCustomWorkingDirectory = "NO"')
|
||||
end
|
||||
_p(2, 'debugDocumentVersioning = "YES">')
|
||||
_p(2, '<BuildableProductRunnable')
|
||||
_p(3, 'runnableDebuggingMode = "0">')
|
||||
buildableref(3, primary, releasecfg)
|
||||
_p(2, '</BuildableProductRunnable>')
|
||||
cmdlineargs(2, releasecfg)
|
||||
envvars(2, releasecfg)
|
||||
_p(1, '</ProfileAction>')
|
||||
_p(1, '<AnalyzeAction')
|
||||
_p(2, 'buildConfiguration = "%s">', debugname)
|
||||
_p(1, '</AnalyzeAction>')
|
||||
_p(1, '<ArchiveAction')
|
||||
_p(2, 'buildConfiguration = "%s"', releasename)
|
||||
_p(2, 'revealArchiveInOrganizer = "YES">')
|
||||
_p(1, '</ArchiveAction>')
|
||||
_p('</Scheme>')
|
||||
end
|
||||
|
||||
--
|
||||
-- Generate XCode schemes for the given project.
|
||||
--
|
||||
|
||||
function xcode.generate_schemes(prj, base_path)
|
||||
if (prj.kind == "ConsoleApp" or prj.kind == "WindowedApp") or (prj.options and prj.options.XcodeLibrarySchemes) then
|
||||
|
||||
if prj.options and prj.options.XcodeSchemeNoConfigs then
|
||||
premake.generate(prj, path.join(base_path, "%%.xcscheme"),
|
||||
function(prj) xcode.scheme({prj}, prj) end)
|
||||
else
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
premake.generate(prj, path.join(base_path, "%% " .. cfg.name .. ".xcscheme"),
|
||||
function(prj) xcode.scheme({prj}, prj, cfg) end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Vendored
+145
@@ -0,0 +1,145 @@
|
||||
local premake = premake
|
||||
local xcode = premake.xcode
|
||||
|
||||
xcode.allscheme = false
|
||||
|
||||
function xcode.workspace_head()
|
||||
_p('<?xml version="1.0" encoding="UTF-8"?>')
|
||||
_p('<Workspace')
|
||||
_p(1,'version = "1.0">')
|
||||
end
|
||||
|
||||
function xcode.workspace_tail()
|
||||
_p('</Workspace>')
|
||||
end
|
||||
|
||||
function xcode.workspace_file_ref(prj, indent)
|
||||
local projpath = path.getrelative(prj.solution.location, prj.location)
|
||||
if projpath == '.' then projpath = ''
|
||||
else projpath = projpath ..'/'
|
||||
end
|
||||
_p(indent, '<FileRef')
|
||||
_p(indent + 1, 'location = "group:%s">', projpath .. prj.name .. '.xcodeproj')
|
||||
_p(indent, '</FileRef>')
|
||||
end
|
||||
|
||||
function xcode.workspace_group(grp, indent)
|
||||
_p(indent, '<Group')
|
||||
_p(indent + 1, 'location = "container:"')
|
||||
_p(indent + 1, 'name = "%s">', grp.name)
|
||||
|
||||
local function comparenames(a, b)
|
||||
return a.name < b.name
|
||||
end
|
||||
|
||||
local groups = table.join(grp.groups)
|
||||
local projects = table.join(grp.projects)
|
||||
table.sort(groups, comparenames)
|
||||
table.sort(projects, comparenames)
|
||||
|
||||
for _, child in ipairs(groups) do
|
||||
xcode.workspace_group(child, indent + 1)
|
||||
end
|
||||
|
||||
for _, prj in ipairs(projects) do
|
||||
xcode.workspace_file_ref(prj, indent + 1)
|
||||
end
|
||||
|
||||
_p(indent, '</Group>')
|
||||
end
|
||||
|
||||
function xcode.workspace_generate(sln)
|
||||
xcode.preparesolution(sln)
|
||||
xcode.workspace_head()
|
||||
xcode.reorderProjects(sln)
|
||||
|
||||
for grp in premake.solution.eachgroup(sln) do
|
||||
if grp.parent == nil then
|
||||
xcode.workspace_group(grp, 1)
|
||||
end
|
||||
end
|
||||
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if prj.group == nil then
|
||||
xcode.workspace_file_ref(prj, 1)
|
||||
end
|
||||
end
|
||||
|
||||
xcode.workspace_tail()
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Generate the `-ALL` scheme, building all targets.
|
||||
--
|
||||
|
||||
function xcode.workspace_scheme(sln)
|
||||
if not xcode.allscheme then
|
||||
return false
|
||||
end
|
||||
|
||||
local projects = {}
|
||||
local primary = nil
|
||||
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if not primary or (sln.startproject == prj.name) then
|
||||
primary = prj
|
||||
end
|
||||
table.insert(projects, prj)
|
||||
end
|
||||
|
||||
xcode.scheme(projects, primary)
|
||||
end
|
||||
|
||||
--
|
||||
-- Generate the workspace settings file, preventing xcode from auto-generating
|
||||
-- schemes we have manually provided.
|
||||
--
|
||||
|
||||
function xcode.workspace_settings(sln)
|
||||
_p('<?xml version="1.0" encoding="UTF-8"?>')
|
||||
_p('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">')
|
||||
_p('<plist version="1.0">')
|
||||
_p('<dict>')
|
||||
_p(1, '<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>')
|
||||
_p(1, '<false/>')
|
||||
_p('</dict>')
|
||||
_p('</plist>')
|
||||
end
|
||||
|
||||
--
|
||||
-- If a startup project is specified, move it to the front of the project list.
|
||||
-- This will make Visual Studio treat it like a startup project.
|
||||
--
|
||||
|
||||
function xcode.reorderProjects(sln)
|
||||
if sln.startproject then
|
||||
for i, prj in ipairs(sln.projects) do
|
||||
if sln.startproject == prj.name then
|
||||
-- Move group tree containing the project to start of group list
|
||||
local cur = prj.group
|
||||
while cur ~= nil do
|
||||
-- Remove group from array
|
||||
for j, group in ipairs(sln.groups) do
|
||||
if group == cur then
|
||||
table.remove(sln.groups, j)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Add back at start
|
||||
table.insert(sln.groups, 1, cur)
|
||||
cur = cur.parent
|
||||
end
|
||||
-- Move the project itself to start
|
||||
table.remove(sln.projects, i)
|
||||
table.insert(sln.projects, 1, prj)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
--
|
||||
-- action.lua
|
||||
-- Work with the list of registered actions.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.action = { }
|
||||
|
||||
|
||||
--
|
||||
-- The list of registered actions.
|
||||
--
|
||||
|
||||
premake.action.list = { }
|
||||
|
||||
|
||||
--
|
||||
-- Register a new action.
|
||||
--
|
||||
-- @param a
|
||||
-- The new action object.
|
||||
--
|
||||
|
||||
function premake.action.add(a)
|
||||
-- validate the action object, at least a little bit
|
||||
local missing
|
||||
for _, field in ipairs({"description", "trigger"}) do
|
||||
if (not a[field]) then
|
||||
missing = field
|
||||
end
|
||||
end
|
||||
|
||||
if (missing) then
|
||||
error("action needs a " .. missing, 3)
|
||||
end
|
||||
|
||||
-- add it to the master list
|
||||
premake.action.list[a.trigger] = a
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Trigger an action.
|
||||
--
|
||||
-- @param name
|
||||
-- The name of the action to be triggered.
|
||||
-- @returns
|
||||
-- None.
|
||||
--
|
||||
|
||||
function premake.action.call(name)
|
||||
local a = premake.action.list[name]
|
||||
for sln in premake.solution.each() do
|
||||
if a.onsolution then
|
||||
a.onsolution(sln)
|
||||
end
|
||||
if sln.postsolutioncallbacks then
|
||||
for _,cb in ipairs(sln.postsolutioncallbacks) do
|
||||
cb(sln)
|
||||
end
|
||||
end
|
||||
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if a.onproject then
|
||||
a.onproject(prj)
|
||||
end
|
||||
if prj.postprojectcallbacks then
|
||||
for _,cb in ipairs(prj.postprojectcallbacks) do
|
||||
cb(prj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if a.execute then
|
||||
a.execute()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve the current action, as determined by _ACTION.
|
||||
--
|
||||
-- @return
|
||||
-- The current action, or nil if _ACTION is nil or does not match any action.
|
||||
--
|
||||
|
||||
function premake.action.current()
|
||||
return premake.action.get(_ACTION)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve an action by name.
|
||||
--
|
||||
-- @param name
|
||||
-- The name of the action to retrieve.
|
||||
-- @returns
|
||||
-- The requested action, or nil if the action does not exist.
|
||||
--
|
||||
|
||||
function premake.action.get(name)
|
||||
return premake.action.list[name]
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Iterator for the list of actions.
|
||||
--
|
||||
|
||||
function premake.action.each()
|
||||
-- sort the list by trigger
|
||||
local keys = { }
|
||||
for _, action in pairs(premake.action.list) do
|
||||
table.insert(keys, action.trigger)
|
||||
end
|
||||
table.sort(keys)
|
||||
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
return premake.action.list[keys[i]]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Activates a particular action.
|
||||
--
|
||||
-- @param name
|
||||
-- The name of the action to activate.
|
||||
--
|
||||
|
||||
function premake.action.set(name)
|
||||
_ACTION = name
|
||||
-- Some actions imply a particular operating system
|
||||
local action = premake.action.get(name)
|
||||
if action then
|
||||
_OS = action.os or _OS
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Determines if an action supports a particular language or target type.
|
||||
--
|
||||
-- @param action
|
||||
-- The action to test.
|
||||
-- @param feature
|
||||
-- The feature to check, either a programming language or a target type.
|
||||
-- @returns
|
||||
-- True if the feature is supported, false otherwise.
|
||||
--
|
||||
|
||||
function premake.action.supports(action, feature)
|
||||
if not action then
|
||||
return false
|
||||
end
|
||||
if action.valid_languages then
|
||||
if table.contains(action.valid_languages, feature) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if action.valid_kinds then
|
||||
if table.contains(action.valid_kinds, feature) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,865 @@
|
||||
--
|
||||
-- base/bake.lua
|
||||
--
|
||||
-- Takes all the configuration information provided by the project scripts
|
||||
-- and stored in the solution->project->block hierarchy and flattens it all
|
||||
-- down into one object per configuration. These objects are cached with the
|
||||
-- project, and can be retrieved by calling the getconfig() or eachconfig().
|
||||
--
|
||||
-- Copyright (c) 2008-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.bake = { }
|
||||
local bake = premake.bake
|
||||
|
||||
|
||||
-- do not copy these fields into the configurations
|
||||
|
||||
local nocopy =
|
||||
{
|
||||
blocks = true,
|
||||
keywords = true,
|
||||
projects = true,
|
||||
__configs = true,
|
||||
}
|
||||
|
||||
-- do not cascade these fields from projects to configurations
|
||||
|
||||
local nocascade =
|
||||
{
|
||||
makesettings = true,
|
||||
}
|
||||
|
||||
-- leave these paths as absolute, rather than converting to project relative
|
||||
|
||||
local keeprelative =
|
||||
{
|
||||
basedir = true,
|
||||
location = true,
|
||||
}
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns a list of all of the active terms from the current environment.
|
||||
-- See the docs for configuration() for more information about the terms.
|
||||
--
|
||||
|
||||
function premake.getactiveterms(obj)
|
||||
-- While the `obj` argument is not used in this function, it should
|
||||
-- remain accepted so users can override this function if need be, and
|
||||
-- still have access to the context (solution/project).
|
||||
|
||||
local terms = { _action = _ACTION:lower(), os = os.get() }
|
||||
|
||||
-- add option keys or values
|
||||
for key, value in pairs(_OPTIONS) do
|
||||
if value ~= "" then
|
||||
table.insert(terms, value:lower())
|
||||
else
|
||||
table.insert(terms, key:lower())
|
||||
end
|
||||
end
|
||||
|
||||
return terms
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Test a single configuration block keyword against a list of terms.
|
||||
-- The terms are a mix of key/value pairs. The keyword is tested against
|
||||
-- the values; on a match, the corresponding key is returned. This
|
||||
-- enables testing for required values in iskeywordsmatch(), below.
|
||||
--
|
||||
|
||||
function premake.iskeywordmatch(keyword, terms)
|
||||
-- is it negated?
|
||||
if keyword:startswith("not ") then
|
||||
return not premake.iskeywordmatch(keyword:sub(5), terms)
|
||||
end
|
||||
|
||||
for _, pattern in ipairs(keyword:explode(" or ")) do
|
||||
for termkey, term in pairs(terms) do
|
||||
if term:match(pattern) == term then
|
||||
return termkey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Checks a set of configuration block keywords against a list of terms.
|
||||
-- The required flag is used by the file configurations: only blocks
|
||||
-- with a term that explictly matches the filename get applied; more
|
||||
-- general blocks are skipped over (since they were already applied at
|
||||
-- the config level).
|
||||
--
|
||||
|
||||
function premake.iskeywordsmatch(keywords, terms)
|
||||
local hasrequired = false
|
||||
for _, keyword in ipairs(keywords) do
|
||||
local matched = premake.iskeywordmatch(keyword, terms)
|
||||
if not matched then
|
||||
return false
|
||||
end
|
||||
if matched == "required" then
|
||||
hasrequired = true
|
||||
end
|
||||
end
|
||||
|
||||
if terms.required and not hasrequired then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Converts path fields from absolute to location-relative paths.
|
||||
--
|
||||
-- @param location
|
||||
-- The base location, paths will be relative to this directory.
|
||||
-- @param obj
|
||||
-- The object containing the fields to be adjusted.
|
||||
--
|
||||
|
||||
local function adjustpaths(location, obj)
|
||||
function adjustpathlist(list)
|
||||
for i, p in ipairs(list) do
|
||||
list[i] = path.getrelative(location, p)
|
||||
end
|
||||
end
|
||||
|
||||
if obj.allfiles ~= nil then
|
||||
adjustpathlist(obj.allfiles)
|
||||
end
|
||||
|
||||
for name, value in pairs(obj) do
|
||||
local field = premake.fields[name]
|
||||
if field and value and not keeprelative[name] then
|
||||
if field.kind == "path" then
|
||||
obj[name] = path.getrelative(location, value)
|
||||
elseif field.kind == "dirlist" or field.kind == "filelist" then
|
||||
adjustpathlist(value)
|
||||
elseif field.kind == "keypath" then
|
||||
for k,v in pairs(value) do
|
||||
adjustpathlist(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function removevalue(tbl, remove)
|
||||
for index, item in ipairs(tbl) do
|
||||
if item == remove then
|
||||
table.remove(tbl, index)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function removevalues(tbl, removes)
|
||||
for k, v in pairs(tbl) do
|
||||
for _, pattern in ipairs(removes) do
|
||||
if pattern == tbl[k] then
|
||||
if type(k) == "number" then
|
||||
table.remove(tbl, k)
|
||||
else
|
||||
tbl[k] = nil
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Merge all of the fields from one object into another. String values are overwritten,
|
||||
-- while list values are merged. Fields listed in premake.nocopy are skipped.
|
||||
--
|
||||
-- @param dest
|
||||
-- The destination object, to contain the merged settings.
|
||||
-- @param src
|
||||
-- The source object, containing the settings to added to the destination.
|
||||
--
|
||||
|
||||
local function mergefield(kind, dest, src, mergecopiestotail)
|
||||
local tbl = dest or { }
|
||||
if kind == "keyvalue" or kind == "keypath" then
|
||||
for key, value in pairs(src) do
|
||||
tbl[key] = mergefield("list", tbl[key], value, mergecopiestotail)
|
||||
end
|
||||
else
|
||||
for _, item in ipairs(src) do
|
||||
if tbl[item] then
|
||||
if mergecopiestotail then
|
||||
removevalue(tbl, item)
|
||||
table.insert(tbl, item)
|
||||
tbl[item] = item
|
||||
end
|
||||
else
|
||||
table.insert(tbl, item)
|
||||
tbl[item] = item
|
||||
end
|
||||
end
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
local function mergeobject(dest, src)
|
||||
-- if there's nothing to add, quick out
|
||||
if not src then
|
||||
return
|
||||
end
|
||||
|
||||
for fieldname, value in pairs(src) do
|
||||
if not nocopy[fieldname] then
|
||||
-- fields that are included in the API are merged...
|
||||
local field = premake.fields[fieldname]
|
||||
if field then
|
||||
if type(value) == "table" then
|
||||
dest[fieldname] = mergefield(field.kind, dest[fieldname], value, field.mergecopiestotail)
|
||||
if src.removes then
|
||||
removes = src.removes[fieldname]
|
||||
if removes then
|
||||
removevalues(dest[fieldname], removes)
|
||||
end
|
||||
end
|
||||
else
|
||||
dest[fieldname] = value
|
||||
end
|
||||
|
||||
-- ...everything else is just copied as-is
|
||||
else
|
||||
dest[fieldname] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Merges the settings from a solution's or project's list of configuration blocks,
|
||||
-- for all blocks that match the provided set of environment terms.
|
||||
--
|
||||
-- @param dest
|
||||
-- The destination object, to contain the merged settings.
|
||||
-- @param obj
|
||||
-- The solution or project object being collapsed.
|
||||
-- @param basis
|
||||
-- "Root" level settings, from the solution, which act as a starting point for
|
||||
-- all of the collapsed settings built during this call.
|
||||
-- @param terms
|
||||
-- A list of keywords to filter the configuration blocks; only those that
|
||||
-- match will be included in the destination.
|
||||
-- @param cfgname
|
||||
-- The name of the configuration being collapsed. May be nil.
|
||||
-- @param pltname
|
||||
-- The name of the platform being collapsed. May be nil.
|
||||
--
|
||||
|
||||
local function merge(dest, obj, basis, terms, cfgname, pltname)
|
||||
-- the configuration key is the merged configuration and platform names
|
||||
local key = cfgname or ""
|
||||
pltname = pltname or "Native"
|
||||
if pltname ~= "Native" then
|
||||
key = key .. pltname
|
||||
end
|
||||
|
||||
-- add the configuration and platform to the block filter terms
|
||||
terms.config = (cfgname or ""):lower()
|
||||
terms.platform = pltname:lower()
|
||||
|
||||
-- build the configuration base by merging the solution and project level settings
|
||||
local cfg = {}
|
||||
mergeobject(cfg, basis[key])
|
||||
|
||||
adjustpaths(obj.location, cfg)
|
||||
mergeobject(cfg, obj)
|
||||
|
||||
-- add `kind` to the filter terms
|
||||
if (cfg.kind) then
|
||||
terms['kind']=cfg.kind:lower()
|
||||
end
|
||||
|
||||
-- now add in any blocks that match the filter terms
|
||||
for _, blk in ipairs(obj.blocks) do
|
||||
if (premake.iskeywordsmatch(blk.keywords, terms))then
|
||||
mergeobject(cfg, blk)
|
||||
if (cfg.kind and not cfg.terms.kind) then
|
||||
cfg.terms['kind'] = cfg.kind:lower()
|
||||
terms['kind'] = cfg.kind:lower()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- package it all up and add it to the result set
|
||||
cfg.name = cfgname
|
||||
cfg.platform = pltname
|
||||
for k,v in pairs(terms) do
|
||||
cfg.terms[k] =v
|
||||
end
|
||||
dest[key] = cfg
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Collapse a solution or project object down to a canonical set of configuration settings,
|
||||
-- keyed by configuration block/platform pairs, and taking into account the current
|
||||
-- environment settings.
|
||||
--
|
||||
-- @param obj
|
||||
-- The solution or project to be collapsed.
|
||||
-- @param basis
|
||||
-- "Root" level settings, from the solution, which act as a starting point for
|
||||
-- all of the collapsed settings built during this call.
|
||||
-- @returns
|
||||
-- The collapsed list of settings, keyed by configuration block/platform pair.
|
||||
--
|
||||
|
||||
local function collapse(obj, basis)
|
||||
local result = {}
|
||||
basis = basis or {}
|
||||
|
||||
-- find the solution, which contains the configuration and platform lists
|
||||
local sln = obj.solution or obj
|
||||
|
||||
-- build a set of configuration filter terms; only those configuration blocks
|
||||
-- with a matching set of keywords will be included in the merged results
|
||||
local terms = premake.getactiveterms(obj)
|
||||
|
||||
-- build a project-level configuration.
|
||||
merge(result, obj, basis, terms)--this adjusts terms
|
||||
|
||||
-- now build configurations for each build config/platform pair
|
||||
for _, cfgname in ipairs(sln.configurations) do
|
||||
local terms_local = {}
|
||||
for k,v in pairs(terms)do terms_local[k]=v end
|
||||
merge(result, obj, basis, terms_local, cfgname, "Native")--terms cam also be adjusted here
|
||||
for _, pltname in ipairs(sln.platforms or {}) do
|
||||
if pltname ~= "Native" then
|
||||
merge(result, obj, basis,terms_local, cfgname, pltname)--terms also here
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Computes a unique objects directory for every configuration, using the
|
||||
-- following choices:
|
||||
-- [1] -> the objects directory as set in the project of config
|
||||
-- [2] -> [1] + the platform name
|
||||
-- [3] -> [2] + the configuration name
|
||||
-- [4] -> [3] + the project name
|
||||
--
|
||||
|
||||
local function builduniquedirs()
|
||||
local num_variations = 4
|
||||
|
||||
-- Start by listing out each possible object directory for each configuration.
|
||||
-- Keep a count of how many times each path gets used across the session.
|
||||
local cfg_dirs = {}
|
||||
local hit_counts = {}
|
||||
|
||||
for sln in premake.solution.each() do
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
for _, cfg in pairs(prj.__configs) do
|
||||
|
||||
local dirs = { }
|
||||
dirs[1] = path.getabsolute(path.join(cfg.location, cfg.objdir or cfg.project.objdir or "obj"))
|
||||
dirs[2] = path.join(dirs[1], iif(cfg.platform == "Native", "", cfg.platform))
|
||||
dirs[3] = path.join(dirs[2], cfg.name)
|
||||
dirs[4] = path.join(dirs[3], cfg.project.name)
|
||||
cfg_dirs[cfg] = dirs
|
||||
|
||||
-- configurations other than the root should bias toward a more
|
||||
-- description path, including the platform or config name
|
||||
local start = iif(cfg.name, 2, 1)
|
||||
for v = start, num_variations do
|
||||
local d = dirs[v]
|
||||
hit_counts[d] = (hit_counts[d] or 0) + 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now assign an object directory to each configuration, skipping those
|
||||
-- that are in use somewhere else in the session
|
||||
for sln in premake.solution.each() do
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
for _, cfg in pairs(prj.__configs) do
|
||||
|
||||
local dir
|
||||
local start = iif(cfg.name, 2, 1)
|
||||
for v = start, iif(cfg.flags.SingleOutputDir==true,num_variations-1,num_variations) do
|
||||
dir = cfg_dirs[cfg][v]
|
||||
if hit_counts[dir] == 1 then break end
|
||||
end
|
||||
cfg.objectsdir = path.getrelative(cfg.location, dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Pre-computes the build and link targets for a configuration.
|
||||
--
|
||||
|
||||
local function buildtargets()
|
||||
for sln in premake.solution.each() do
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
for _, cfg in pairs(prj.__configs) do
|
||||
-- determine which conventions the target should follow for this config
|
||||
local pathstyle = premake.getpathstyle(cfg)
|
||||
local namestyle = premake.getnamestyle(cfg)
|
||||
|
||||
-- build the targets
|
||||
cfg.buildtarget = premake.gettarget(cfg, "build", pathstyle, namestyle, cfg.system)
|
||||
cfg.linktarget = premake.gettarget(cfg, "link", pathstyle, namestyle, cfg.system)
|
||||
if pathstyle == "windows" then
|
||||
cfg.objectsdir = path.translate(cfg.objectsdir, "\\")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getCfgKind(cfg)
|
||||
if(cfg.kind) then
|
||||
return cfg.kind;
|
||||
end
|
||||
|
||||
if(cfg.project.__configs[""] and cfg.project.__configs[""].kind) then
|
||||
return cfg.project.__configs[""].kind;
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function getprojrec(dstArray, foundList, cfg, cfgname, searchField, bLinkage)
|
||||
if(not cfg) then return end
|
||||
|
||||
local foundUsePrjs = {};
|
||||
for _, useName in ipairs(cfg[searchField]) do
|
||||
local testName = useName:lower();
|
||||
if((not foundList[testName])) then
|
||||
local theProj = nil;
|
||||
local theUseProj = nil;
|
||||
for _, prj in ipairs(cfg.project.solution.projects) do
|
||||
if (prj.name:lower() == testName) then
|
||||
if(prj.usage) then
|
||||
theUseProj = prj;
|
||||
else
|
||||
theProj = prj;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Must connect to a usage project.
|
||||
if(theUseProj) then
|
||||
foundList[testName] = true;
|
||||
local prjEntry = {
|
||||
name = testName,
|
||||
proj = theProj,
|
||||
usageProj = theUseProj,
|
||||
bLinkageOnly = bLinkage,
|
||||
};
|
||||
dstArray[testName] = prjEntry;
|
||||
table.insert(foundUsePrjs, theUseProj);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, usePrj in ipairs(foundUsePrjs) do
|
||||
--Links can only recurse through static libraries.
|
||||
if((searchField ~= "links") or
|
||||
(getCfgKind(usePrj.__configs[cfgname]) == "StaticLib")) then
|
||||
getprojrec(dstArray, foundList, usePrj.__configs[cfgname],
|
||||
cfgname, searchField, bLinkage);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- This function will recursively get all projects that the given configuration has in its "uses"
|
||||
-- field. The return values are a list of tables. Each table in that list contains the following:
|
||||
-- name = The lowercase name of the project.
|
||||
-- proj = The project. Can be nil if it is usage-only.
|
||||
-- usageProj = The usage project. Can't be nil, as using a project that has no
|
||||
-- usage project is not put into the list.
|
||||
-- bLinkageOnly = If this is true, then only the linkage information should be copied.
|
||||
-- The recursion will only look at the "uses" field on *usage* projects.
|
||||
-- This function will also add projects to the list that are mentioned in the "links"
|
||||
-- field of usage projects. These will only copy linker information, but they will recurse.
|
||||
-- through other "links" fields.
|
||||
--
|
||||
local function getprojectsconnections(cfg, cfgname)
|
||||
local dstArray = {};
|
||||
local foundList = {};
|
||||
foundList[cfg.project.name:lower()] = true;
|
||||
|
||||
--First, follow the uses recursively.
|
||||
getprojrec(dstArray, foundList, cfg, cfgname, "uses", false);
|
||||
|
||||
--Next, go through all of the usage projects and recursively get their links.
|
||||
--But only if they're not already there. Get the links as linkage-only.
|
||||
local linkArray = {};
|
||||
for prjName, prjEntry in pairs(dstArray) do
|
||||
getprojrec(linkArray, foundList, prjEntry.usageProj.__configs[cfgname], cfgname,
|
||||
"links", true);
|
||||
end
|
||||
|
||||
--Copy from linkArray into dstArray.
|
||||
for prjName, prjEntry in pairs(linkArray) do
|
||||
dstArray[prjName] = prjEntry;
|
||||
end
|
||||
|
||||
return dstArray;
|
||||
end
|
||||
|
||||
|
||||
local function isnameofproj(cfg, strName)
|
||||
local sln = cfg.project.solution;
|
||||
local strTest = strName:lower();
|
||||
for prjIx, prj in ipairs(sln.projects) do
|
||||
if (prj.name:lower() == strTest) then
|
||||
return true;
|
||||
end
|
||||
end
|
||||
|
||||
return false;
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Copies the field from dstCfg to srcCfg.
|
||||
--
|
||||
local function copydependentfield(srcCfg, dstCfg, strSrcField)
|
||||
local srcField = premake.fields[strSrcField];
|
||||
local strDstField = strSrcField;
|
||||
|
||||
if type(srcCfg[strSrcField]) == "table" then
|
||||
--handle paths.
|
||||
if (srcField.kind == "dirlist" or srcField.kind == "filelist") and
|
||||
(not keeprelative[strSrcField]) then
|
||||
for i,p in ipairs(srcCfg[strSrcField]) do
|
||||
table.insert(dstCfg[strDstField],
|
||||
path.rebase(p, srcCfg.project.location, dstCfg.project.location))
|
||||
end
|
||||
else
|
||||
if(strSrcField == "links") then
|
||||
for i,p in ipairs(srcCfg[strSrcField]) do
|
||||
if(not isnameofproj(dstCfg, p)) then
|
||||
table.insert(dstCfg[strDstField], p)
|
||||
else
|
||||
printf("Failed to copy '%s' from proj '%s'.",
|
||||
p, srcCfg.project.name);
|
||||
end
|
||||
end
|
||||
else
|
||||
for i,p in ipairs(srcCfg[strSrcField]) do
|
||||
table.insert(dstCfg[strDstField], p)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if(srcField.kind == "path" and (not keeprelative[strSrcField])) then
|
||||
dstCfg[strDstField] = path.rebase(srcCfg[strSrcField],
|
||||
prj.location, dstCfg.project.location);
|
||||
else
|
||||
dstCfg[strDstField] = srcCfg[strSrcField];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This function will take the list of project entries and apply their usage project data
|
||||
-- to the given configuration. It will copy compiling information for the projects that are
|
||||
-- not listed as linkage-only. It will copy the linking information for projects only if
|
||||
-- the source project is not a static library. It won't copy linking information
|
||||
-- if the project is in this solution; instead it will add that project to the configuration's
|
||||
-- links field, expecting that Premake will handle the rest.
|
||||
--
|
||||
local function copyusagedata(cfg, cfgname, linkToProjs)
|
||||
local myPrj = cfg.project;
|
||||
local bIsStaticLib = (getCfgKind(cfg) == "StaticLib");
|
||||
|
||||
for prjName, prjEntry in pairs(linkToProjs) do
|
||||
local srcPrj = prjEntry.usageProj;
|
||||
local srcCfg = srcPrj.__configs[cfgname];
|
||||
|
||||
for name, field in pairs(premake.fields) do
|
||||
if(srcCfg[name]) then
|
||||
if(field.usagecopy) then
|
||||
if(not prjEntry.bLinkageOnly) then
|
||||
copydependentfield(srcCfg, cfg, name)
|
||||
end
|
||||
elseif(field.linkagecopy) then
|
||||
--Copy the linkage data if we're building a non-static thing
|
||||
--and this is a pure usage project. If it's not pure-usage, then
|
||||
--we will simply put the project's name in the links field later.
|
||||
if((not bIsStaticLib) and (not prjEntry.proj)) then
|
||||
copydependentfield(srcCfg, cfg, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if((not bIsStaticLib) and prjEntry.proj) then
|
||||
table.insert(cfg.links, prjEntry.proj.name);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Build an inverse dictionary of literal vpaths for fast lookup
|
||||
--
|
||||
|
||||
local function inverseliteralvpaths()
|
||||
for sln in premake.solution.each() do
|
||||
for _,prj in ipairs(sln.projects) do
|
||||
prj.inversevpaths = {}
|
||||
for replacement, patterns in pairs(prj.vpaths or {}) do
|
||||
for _, pattern in ipairs(patterns) do
|
||||
if string.find(pattern, "*") == nil then
|
||||
prj.inversevpaths[pattern] = replacement
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--
|
||||
-- Main function, controls the process of flattening the configurations.
|
||||
--
|
||||
|
||||
function premake.bake.buildconfigs()
|
||||
|
||||
-- convert project path fields to be relative to project location
|
||||
for sln in premake.solution.each() do
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
prj.location = prj.location or sln.location or prj.basedir
|
||||
adjustpaths(prj.location, prj)
|
||||
for _, blk in ipairs(prj.blocks) do
|
||||
adjustpaths(prj.location, blk)
|
||||
end
|
||||
end
|
||||
sln.location = sln.location or sln.basedir
|
||||
end
|
||||
|
||||
-- convert paths for imported projects to be relative to solution location
|
||||
for sln in premake.solution.each() do
|
||||
for _, iprj in ipairs(sln.importedprojects) do
|
||||
iprj.location = path.getabsolute(iprj.location)
|
||||
end
|
||||
end
|
||||
|
||||
inverseliteralvpaths()
|
||||
|
||||
-- collapse configuration blocks, so that there is only one block per build
|
||||
-- configuration/platform pair, filtered to the current operating environment
|
||||
for sln in premake.solution.each() do
|
||||
local basis = collapse(sln)
|
||||
for _, prj in ipairs(sln.projects) do
|
||||
prj.__configs = collapse(prj, basis)
|
||||
for _, cfg in pairs(prj.__configs) do
|
||||
bake.postprocess(prj, cfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- This loop finds the projects that a configuration is connected to
|
||||
-- via its "uses" field. It will then copy any usage project information from that
|
||||
-- usage project to the configuration in question.
|
||||
for sln in premake.solution.each() do
|
||||
for prjIx, prj in ipairs(sln.projects) do
|
||||
if(not prj.usage) then
|
||||
for cfgname, cfg in pairs(prj.__configs) do
|
||||
local usesPrjs = getprojectsconnections(cfg, cfgname);
|
||||
copyusagedata(cfg, cfgname, usesPrjs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- mark all configurations that have been removed via their removes table.
|
||||
for sln in premake.solution.each() do
|
||||
for prjIx, prj in ipairs(sln.projects) do
|
||||
for cfgName, cfg in pairs(prj.__configs) do
|
||||
cfg.build = true
|
||||
|
||||
local removes = nil
|
||||
|
||||
if cfg.removes ~= nil then
|
||||
removes = cfg.removes["platforms"];
|
||||
end
|
||||
|
||||
if removes ~= nil then
|
||||
for _,p in ipairs(removes) do
|
||||
if p == cfg.platform then
|
||||
cfg.build = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove all usage projects.
|
||||
for sln in premake.solution.each() do
|
||||
local removeList = {};
|
||||
for index, prj in ipairs(sln.projects) do
|
||||
if(prj.usage) then
|
||||
table.insert(removeList, 1, index); --Add in reverse order.
|
||||
end
|
||||
end
|
||||
|
||||
for _, index in ipairs(removeList) do
|
||||
table.remove(sln.projects, index);
|
||||
end
|
||||
end
|
||||
|
||||
-- assign unique object directories to each configuration
|
||||
builduniquedirs()
|
||||
|
||||
-- walk it again and build the targets and unique directories
|
||||
buildtargets(cfg)
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Post-process a project configuration, applying path fix-ups and other adjustments
|
||||
-- to the "raw" setting data pulled from the project script.
|
||||
--
|
||||
-- @param prj
|
||||
-- The project object which contains the configuration.
|
||||
-- @param cfg
|
||||
-- The configuration object to be fixed up.
|
||||
--
|
||||
|
||||
function premake.bake.postprocess(prj, cfg)
|
||||
cfg.project = prj
|
||||
cfg.shortname = premake.getconfigname(cfg.name, cfg.platform, true)
|
||||
cfg.longname = premake.getconfigname(cfg.name, cfg.platform)
|
||||
|
||||
-- set the project location, if not already set
|
||||
cfg.location = cfg.location or cfg.basedir
|
||||
|
||||
-- figure out the target system
|
||||
local platform = premake.platforms[cfg.platform]
|
||||
if platform.iscrosscompiler then
|
||||
cfg.system = cfg.platform
|
||||
else
|
||||
cfg.system = os.get()
|
||||
end
|
||||
|
||||
-- adjust the kind as required by the target system
|
||||
if cfg.kind == "Bundle"
|
||||
and _ACTION ~= "gmake"
|
||||
and (_ACTION ~= "ninja" and (not prj.options or not prj.options.SkipBundling))
|
||||
and not _ACTION:match("xcode[0-9]") then
|
||||
cfg.kind = "SharedLib"
|
||||
end
|
||||
|
||||
if cfg.kind == "SharedLib" and platform.nosharedlibs then
|
||||
cfg.kind = "StaticLib"
|
||||
end
|
||||
|
||||
local removefiles = cfg.removefiles
|
||||
if _ACTION == 'gmake' or _ACTION == 'ninja' then
|
||||
removefiles = table.join(removefiles, cfg.excludes)
|
||||
end
|
||||
|
||||
-- build a table of removed files, indexed by file name
|
||||
local removefilesDict = {}
|
||||
for _, fname in ipairs(removefiles) do
|
||||
removefilesDict[fname] = true
|
||||
end
|
||||
|
||||
-- remove excluded files from the file list
|
||||
local files = {}
|
||||
for _, fname in ipairs(cfg.files) do
|
||||
if removefilesDict[fname] == nil then
|
||||
table.insert(files, fname)
|
||||
end
|
||||
end
|
||||
cfg.files = files
|
||||
|
||||
-- remove excluded files from the project's allfiles list, and
|
||||
-- un-duplify it
|
||||
local allfiles = {}
|
||||
local allfilesDict = {}
|
||||
if cfg.allfiles ~= nil then
|
||||
for _, fname in ipairs(cfg.allfiles) do
|
||||
if allfilesDict[fname] == nil then
|
||||
if removefilesDict[fname] == nil then
|
||||
allfilesDict[fname] = true
|
||||
table.insert(allfiles, fname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
cfg.allfiles = allfiles
|
||||
|
||||
-- fixup the data
|
||||
for name, field in pairs(premake.fields) do
|
||||
-- re-key flag fields for faster lookups
|
||||
if field.isflags then
|
||||
local values = cfg[name]
|
||||
for _, flag in ipairs(values) do values[flag] = true end
|
||||
end
|
||||
end
|
||||
|
||||
-- build configuration objects for all files
|
||||
-- TODO: can I build this as a tree instead, and avoid the extra
|
||||
-- step of building it later?
|
||||
local cfgfields = {
|
||||
{"__fileconfigs", cfg.files},
|
||||
{"__allfileconfigs", cfg.allfiles},
|
||||
}
|
||||
|
||||
for _, cfgfield in ipairs(cfgfields) do
|
||||
local fieldname = cfgfield[1]
|
||||
local field = cfgfield[2]
|
||||
|
||||
cfg[fieldname] = { }
|
||||
for _, fname in ipairs(field) do
|
||||
local fcfg = {}
|
||||
|
||||
-- Only do this if the script has called enablefilelevelconfig()
|
||||
if premake._filelevelconfig then
|
||||
cfg.terms.required = fname:lower()
|
||||
for _, blk in ipairs(cfg.project.blocks) do
|
||||
-- BK - `iskeywordsmatch` call is super slow for large projects...
|
||||
if (premake.iskeywordsmatch(blk.keywords, cfg.terms)) then
|
||||
mergeobject(fcfg, blk)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add indexed by name and integer
|
||||
-- TODO: when everything is converted to trees I won't need
|
||||
-- to index by name any longer
|
||||
fcfg.name = fname
|
||||
cfg[fieldname][fname] = fcfg
|
||||
table.insert(cfg[fieldname], fcfg)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,103 @@
|
||||
--
|
||||
-- cmdline.lua
|
||||
-- Functions to define and handle command line actions and options.
|
||||
-- Copyright (c) 2002-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Built-in command line options
|
||||
--
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "cc",
|
||||
value = "VALUE",
|
||||
description = "Choose a C/C++ compiler set",
|
||||
allowed = {
|
||||
{ "gcc", "GNU GCC (gcc/g++)" },
|
||||
{ "ow", "OpenWatcom" },
|
||||
{ "ghs", "Green Hills Software" },
|
||||
}
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "dotnet",
|
||||
value = "VALUE",
|
||||
description = "Choose a .NET compiler set",
|
||||
allowed = {
|
||||
{ "msnet", "Microsoft .NET (csc)" },
|
||||
{ "mono", "Novell Mono (mcs)" },
|
||||
{ "pnet", "Portable.NET (cscc)" },
|
||||
}
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "file",
|
||||
value = "FILE",
|
||||
description = "Read FILE as a Premake script; default is 'premake4.lua'"
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "help",
|
||||
description = "Display this information"
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "os",
|
||||
value = "VALUE",
|
||||
description = "Generate files for a different operating system",
|
||||
allowed = {
|
||||
{ "bsd", "OpenBSD, NetBSD, or FreeBSD" },
|
||||
{ "linux", "Linux" },
|
||||
{ "macosx", "Apple Mac OS X" },
|
||||
{ "solaris", "Solaris" },
|
||||
{ "windows", "Microsoft Windows" },
|
||||
}
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "platform",
|
||||
value = "VALUE",
|
||||
description = "Add target architecture (if supported by action)",
|
||||
allowed = {
|
||||
{ "x32", "32-bit" },
|
||||
{ "x64", "64-bit" },
|
||||
{ "universal", "Mac OS X Universal, 32- and 64-bit" },
|
||||
{ "universal32", "Mac OS X Universal, 32-bit only" },
|
||||
{ "universal64", "Mac OS X Universal, 64-bit only" },
|
||||
{ "ps3", "Playstation 3" },
|
||||
{ "orbis", "Playstation 4" },
|
||||
{ "xbox360", "Xbox 360" },
|
||||
{ "durango", "Xbox One" },
|
||||
{ "ARM", "ARM" },
|
||||
{ "ARM64", "ARM64" },
|
||||
{ "PowerPC", "PowerPC" },
|
||||
{ "nx32", "Nintendo Switch, 32-bit only" },
|
||||
{ "nx64", "Nintendo Switch, 64-bit only" },
|
||||
}
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "scripts",
|
||||
value = "path",
|
||||
description = "Search for additional scripts on the given path"
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "debug-profiler",
|
||||
description = "GENie script generation profiler."
|
||||
}
|
||||
|
||||
newoption
|
||||
{
|
||||
trigger = "version",
|
||||
description = "Display version information"
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
--
|
||||
-- configs.lua
|
||||
--
|
||||
-- Functions for working with configuration objects (which can include
|
||||
-- projects and solutions).
|
||||
--
|
||||
-- Copyright (c) 2008-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.config = { }
|
||||
local config = premake.config
|
||||
|
||||
|
||||
--
|
||||
-- Determine if a configuration represents a "debug" or "release" build.
|
||||
-- This controls the runtime library selected for Visual Studio builds
|
||||
-- (and might also be useful elsewhere).
|
||||
--
|
||||
|
||||
function premake.config.isdebugbuild(cfg)
|
||||
-- If any of the specific runtime flags are set
|
||||
if cfg.flags.DebugRuntime then
|
||||
return true
|
||||
end
|
||||
|
||||
if cfg.flags.ReleaseRuntime then
|
||||
return false
|
||||
end
|
||||
|
||||
-- If any of the optimize flags are set, it's a release a build
|
||||
if cfg.flags.Optimize or cfg.flags.OptimizeSize or cfg.flags.OptimizeSpeed then
|
||||
return false
|
||||
end
|
||||
|
||||
-- If symbols are not defined, it's a release build
|
||||
if not cfg.flags.Symbols then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Return an iterator over each file included in this configuration.
|
||||
--
|
||||
|
||||
function premake.config.eachfile(cfg)
|
||||
local i = 0
|
||||
local t = cfg.files
|
||||
return function ()
|
||||
i = i + 1
|
||||
if (i <= #t) then
|
||||
local fcfg = cfg.__fileconfigs[t[i]]
|
||||
fcfg.vpath = premake.project.getvpath(cfg.project, fcfg.name)
|
||||
return fcfg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Determines if this configuration can be linked incrementally.
|
||||
--
|
||||
|
||||
function premake.config.isincrementallink(cfg)
|
||||
if cfg.kind == "StaticLib" then
|
||||
return false
|
||||
end
|
||||
return not config.islinkeroptimizedbuild(cfg.flags) and not cfg.flags.NoIncrementalLink
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Determine if this configuration uses one of the optimize flags.
|
||||
--
|
||||
|
||||
function premake.config.isoptimizedbuild(flags)
|
||||
return flags.Optimize or flags.OptimizeSize or flags.OptimizeSpeed
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Determine if this configuration uses one of the optimize flags.
|
||||
-- Optimized builds get different treatment, such as full linking
|
||||
-- instead of incremental.
|
||||
--
|
||||
|
||||
function premake.config.islinkeroptimizedbuild(flags)
|
||||
return config.isoptimizedbuild(flags) and not flags.NoOptimizeLink
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Determines if this configuration uses edit and continue.
|
||||
--
|
||||
|
||||
function premake.config.iseditandcontinue(cfg)
|
||||
if cfg.flags.NoEditAndContinue
|
||||
or cfg.flags.Managed
|
||||
or (cfg.kind ~= "StaticLib" and not config.isincrementallink(cfg))
|
||||
or config.islinkeroptimizedbuild(cfg.flags) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
--
|
||||
-- globals.lua
|
||||
-- Global tables and variables, replacements and extensions to Lua's global functions.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
-- A top-level namespace for support functions
|
||||
|
||||
premake = { }
|
||||
|
||||
|
||||
-- The list of supported platforms; also update list in cmdline.lua
|
||||
|
||||
premake.platforms =
|
||||
{
|
||||
Native =
|
||||
{
|
||||
cfgsuffix = "",
|
||||
},
|
||||
x32 =
|
||||
{
|
||||
cfgsuffix = "32",
|
||||
},
|
||||
x64 =
|
||||
{
|
||||
cfgsuffix = "64",
|
||||
},
|
||||
Universal =
|
||||
{
|
||||
cfgsuffix = "univ",
|
||||
},
|
||||
Universal32 =
|
||||
{
|
||||
cfgsuffix = "univ32",
|
||||
},
|
||||
Universal64 =
|
||||
{
|
||||
cfgsuffix = "univ64",
|
||||
},
|
||||
PS3 =
|
||||
{
|
||||
cfgsuffix = "ps3",
|
||||
iscrosscompiler = true,
|
||||
nosharedlibs = true,
|
||||
namestyle = "PS3",
|
||||
},
|
||||
WiiDev =
|
||||
{
|
||||
cfgsuffix = "wii",
|
||||
iscrosscompiler = true,
|
||||
namestyle = "PS3",
|
||||
},
|
||||
Xbox360 =
|
||||
{
|
||||
cfgsuffix = "xbox360",
|
||||
iscrosscompiler = true,
|
||||
namestyle = "windows",
|
||||
},
|
||||
PowerPC =
|
||||
{
|
||||
cfgsuffix = "ppc",
|
||||
iscrosscompiler = true,
|
||||
},
|
||||
ARM =
|
||||
{
|
||||
cfgsuffix = "ARM",
|
||||
iscrosscompiler = true,
|
||||
},
|
||||
ARM64 =
|
||||
{
|
||||
cfgsuffix = "ARM64",
|
||||
iscrosscompiler = true,
|
||||
},
|
||||
Orbis =
|
||||
{
|
||||
cfgsuffix = "orbis",
|
||||
iscrosscompiler = true,
|
||||
namestyle = "Orbis",
|
||||
},
|
||||
Durango =
|
||||
{
|
||||
cfgsuffix = "durango",
|
||||
iscrosscompiler = true,
|
||||
nosharedlibs = true,
|
||||
namestyle = "windows",
|
||||
},
|
||||
TegraAndroid =
|
||||
{
|
||||
cfgsuffix = "tegraandroid",
|
||||
iscrosscompiler = true,
|
||||
namestyle = "TegraAndroid",
|
||||
},
|
||||
NX32 =
|
||||
{
|
||||
cfgsuffix = "nx32",
|
||||
iscrosscompiler = true,
|
||||
namestyle = "NX",
|
||||
},
|
||||
NX64 =
|
||||
{
|
||||
cfgsuffix = "nx64",
|
||||
iscrosscompiler = true,
|
||||
namestyle = "NX",
|
||||
},
|
||||
Emscripten =
|
||||
{
|
||||
cfgsuffix = "emscripten",
|
||||
iscrosscompiler = true,
|
||||
nosharedlibs = true,
|
||||
namestyle = "Emscripten",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--
|
||||
-- A replacement for Lua's built-in dofile() function, this one sets the
|
||||
-- current working directory to the script's location, enabling script-relative
|
||||
-- referencing of other files and resources.
|
||||
--
|
||||
|
||||
local builtin_dofile = dofile
|
||||
function dofile(fname)
|
||||
-- remember the current working directory and file; I'll restore it shortly
|
||||
local oldcwd = os.getcwd()
|
||||
local oldfile = _SCRIPT
|
||||
|
||||
-- if the file doesn't exist, check the search path
|
||||
if (not os.isfile(fname)) then
|
||||
local path = os.pathsearch(fname, _OPTIONS["scripts"], os.getenv("PREMAKE_PATH"))
|
||||
if (path) then
|
||||
fname = path.."/"..fname
|
||||
end
|
||||
end
|
||||
|
||||
-- use the absolute path to the script file, to avoid any file name
|
||||
-- ambiguity if an error should arise
|
||||
_SCRIPT = path.getabsolute(fname)
|
||||
|
||||
-- switch the working directory to the new script location
|
||||
local newcwd = path.getdirectory(_SCRIPT)
|
||||
os.chdir(newcwd)
|
||||
|
||||
-- run the chunk. How can I catch variable return values?
|
||||
local a, b, c, d, e, f = builtin_dofile(_SCRIPT)
|
||||
|
||||
-- restore the previous working directory when done
|
||||
_SCRIPT = oldfile
|
||||
os.chdir(oldcwd)
|
||||
return a, b, c, d, e, f
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- "Immediate If" - returns one of the two values depending on the value of expr.
|
||||
--
|
||||
|
||||
function iif(expr, trueval, falseval)
|
||||
if (expr) then
|
||||
return trueval
|
||||
else
|
||||
return falseval
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- A shortcut for including another build file, often used for projects.
|
||||
--
|
||||
|
||||
function include(fname)
|
||||
local dir, name = premake.findDefaultScript(fname, false)
|
||||
if dir ~= nil then
|
||||
return dofile(dir .. "/" .. name)
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- A shortcut for printing formatted output.
|
||||
--
|
||||
|
||||
function printf(msg, ...)
|
||||
local arg={...}
|
||||
print(string.format(msg, table.unpack(arg)))
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- An extended type API to identify project object types by reading the
|
||||
-- "__type" field from the metatable.
|
||||
--
|
||||
|
||||
function typex(t)
|
||||
local mt = getmetatable(t)
|
||||
if (mt) then
|
||||
if (mt.__type) then
|
||||
return mt.__type
|
||||
end
|
||||
end
|
||||
return type(t)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
--
|
||||
-- help.lua
|
||||
-- User help, displayed on /help option.
|
||||
-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
function premake.showhelp()
|
||||
|
||||
-- display the basic usage
|
||||
printf("")
|
||||
printf("Usage: genie [options] action [arguments]")
|
||||
printf("")
|
||||
|
||||
|
||||
-- display all options
|
||||
printf("OPTIONS")
|
||||
printf("")
|
||||
for option in premake.option.each() do
|
||||
local trigger = option.trigger
|
||||
local description = option.description
|
||||
if (option.value) then trigger = trigger .. "=" .. option.value end
|
||||
if (option.allowed) then description = description .. "; one of:" end
|
||||
|
||||
printf(" --%-15s %s", trigger, description)
|
||||
if (option.allowed) then
|
||||
for _, value in ipairs(option.allowed) do
|
||||
printf(" %-14s %s", value[1], value[2])
|
||||
end
|
||||
end
|
||||
printf("")
|
||||
end
|
||||
|
||||
-- display all actions
|
||||
printf("ACTIONS")
|
||||
printf("")
|
||||
for action in premake.action.each() do
|
||||
printf(" %-17s %s", action.trigger, action.description)
|
||||
end
|
||||
printf("")
|
||||
|
||||
|
||||
-- see more
|
||||
printf("For additional information, see https://github.com/bkaradzic/genie")
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
-- Copyright (c) 2013 Enrique García Cota
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a
|
||||
-- copy of this software and associated documentation files (the
|
||||
-- "Software"), to deal in the Software without restriction, including
|
||||
-- without limitation the rights to use, copy, modify, merge, publish,
|
||||
-- distribute, sublicense, and/or sell copies of the Software, and to
|
||||
-- permit persons to whom the Software is furnished to do so, subject to
|
||||
-- the following conditions:
|
||||
--
|
||||
-- The above copyright notice and this permission notice shall be included
|
||||
-- in all copies or substantial portions of the Software.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
-- Apostrophizes the string if it has quotes, but not aphostrophes
|
||||
-- Otherwise, it returns a regular quoted string
|
||||
local function smartQuote(str)
|
||||
if str:match('"') and not str:match("'") then
|
||||
return "'" .. str .. "'"
|
||||
end
|
||||
return '"' .. str:gsub('"', '\\"') .. '"'
|
||||
end
|
||||
|
||||
local controlCharsTranslation = {
|
||||
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
|
||||
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v"
|
||||
}
|
||||
|
||||
local function escapeChar(c) return controlCharsTranslation[c] end
|
||||
|
||||
local function escape(str)
|
||||
local result = str:gsub("\\", "\\\\"):gsub("(%c)", escapeChar)
|
||||
return result
|
||||
end
|
||||
|
||||
local function isIdentifier(str)
|
||||
return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" )
|
||||
end
|
||||
|
||||
local function isArrayKey(k, length)
|
||||
return type(k) == 'number' and 1 <= k and k <= length
|
||||
end
|
||||
|
||||
local function isDictionaryKey(k, length)
|
||||
return not isArrayKey(k, length)
|
||||
end
|
||||
|
||||
local defaultTypeOrders = {
|
||||
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
|
||||
['function'] = 5, ['userdata'] = 6, ['thread'] = 7
|
||||
}
|
||||
|
||||
local function sortKeys(a, b)
|
||||
local ta, tb = type(a), type(b)
|
||||
|
||||
-- strings and numbers are sorted numerically/alphabetically
|
||||
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
|
||||
|
||||
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
|
||||
-- Two default types are compared according to the defaultTypeOrders table
|
||||
if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
|
||||
elseif dta then return true -- default types before custom ones
|
||||
elseif dtb then return false -- custom types after default ones
|
||||
end
|
||||
|
||||
-- custom types are sorted out alphabetically
|
||||
return ta < tb
|
||||
end
|
||||
|
||||
local function getDictionaryKeys(t)
|
||||
local keys, length = {}, #t
|
||||
for k,_ in pairs(t) do
|
||||
if isDictionaryKey(k, length) then table.insert(keys, k) end
|
||||
end
|
||||
table.sort(keys, sortKeys)
|
||||
return keys
|
||||
end
|
||||
|
||||
local function getToStringResultSafely(t, mt)
|
||||
local __tostring = type(mt) == 'table' and rawget(mt, '__tostring')
|
||||
local str, ok
|
||||
if type(__tostring) == 'function' then
|
||||
ok, str = pcall(__tostring, t)
|
||||
str = ok and str or 'error: ' .. tostring(str)
|
||||
end
|
||||
if type(str) == 'string' and #str > 0 then return str end
|
||||
end
|
||||
|
||||
local maxIdsMetaTable = {
|
||||
__index = function(self, typeName)
|
||||
rawset(self, typeName, 0)
|
||||
return 0
|
||||
end
|
||||
}
|
||||
|
||||
local idsMetaTable = {
|
||||
__index = function (self, typeName)
|
||||
local col = setmetatable({}, {__mode = "kv"})
|
||||
rawset(self, typeName, col)
|
||||
return col
|
||||
end
|
||||
}
|
||||
|
||||
local function countTableAppearances(t, tableAppearances)
|
||||
tableAppearances = tableAppearances or setmetatable({}, {__mode = "k"})
|
||||
|
||||
if type(t) == 'table' then
|
||||
if not tableAppearances[t] then
|
||||
tableAppearances[t] = 1
|
||||
for k,v in pairs(t) do
|
||||
countTableAppearances(k, tableAppearances)
|
||||
countTableAppearances(v, tableAppearances)
|
||||
end
|
||||
countTableAppearances(getmetatable(t), tableAppearances)
|
||||
else
|
||||
tableAppearances[t] = tableAppearances[t] + 1
|
||||
end
|
||||
end
|
||||
|
||||
return tableAppearances
|
||||
end
|
||||
|
||||
local function parse_filter(filter)
|
||||
if type(filter) == 'function' then return filter end
|
||||
-- not a function, so it must be a table or table-like
|
||||
filter = type(filter) == 'table' and filter or {filter}
|
||||
local dictionary = {}
|
||||
for _,v in pairs(filter) do dictionary[v] = true end
|
||||
return function(x) return dictionary[x] end
|
||||
end
|
||||
|
||||
local function makePath(path, key)
|
||||
local newPath, len = {}, #path
|
||||
for i=1, len do newPath[i] = path[i] end
|
||||
newPath[len+1] = key
|
||||
return newPath
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
function inspect(rootObject, options)
|
||||
options = options or {}
|
||||
local depth = options.depth or math.huge
|
||||
local filter = parse_filter(options.filter or {})
|
||||
|
||||
local tableAppearances = countTableAppearances(rootObject)
|
||||
|
||||
local buffer = {}
|
||||
local maxIds = setmetatable({}, maxIdsMetaTable)
|
||||
local ids = setmetatable({}, idsMetaTable)
|
||||
local level = 0
|
||||
local blen = 0 -- buffer length
|
||||
|
||||
local function puts(...)
|
||||
local args = {...}
|
||||
for i=1, #args do
|
||||
blen = blen + 1
|
||||
buffer[blen] = tostring(args[i])
|
||||
end
|
||||
end
|
||||
|
||||
local function down(f)
|
||||
level = level + 1
|
||||
f()
|
||||
level = level - 1
|
||||
end
|
||||
|
||||
local function tabify()
|
||||
puts("\n", string.rep(" ", level))
|
||||
end
|
||||
|
||||
local function commaControl(needsComma)
|
||||
if needsComma then puts(',') end
|
||||
return true
|
||||
end
|
||||
|
||||
local function alreadyVisited(v)
|
||||
return ids[type(v)][v] ~= nil
|
||||
end
|
||||
|
||||
local function getId(v)
|
||||
local tv = type(v)
|
||||
local id = ids[tv][v]
|
||||
if not id then
|
||||
id = maxIds[tv] + 1
|
||||
maxIds[tv] = id
|
||||
ids[tv][v] = id
|
||||
end
|
||||
return id
|
||||
end
|
||||
|
||||
local putValue -- forward declaration that needs to go before putTable & putKey
|
||||
|
||||
local function putKey(k)
|
||||
if isIdentifier(k) then return puts(k) end
|
||||
puts( "[" )
|
||||
putValue(k, {})
|
||||
puts("]")
|
||||
end
|
||||
|
||||
local function putTable(t, path)
|
||||
if alreadyVisited(t) then
|
||||
puts('<table ', getId(t), '>')
|
||||
elseif level >= depth then
|
||||
puts('{...}')
|
||||
else
|
||||
if tableAppearances[t] > 1 then puts('<', getId(t), '>') end
|
||||
|
||||
local dictKeys = getDictionaryKeys(t)
|
||||
local length = #t
|
||||
local mt = getmetatable(t)
|
||||
local to_string_result = getToStringResultSafely(t, mt)
|
||||
|
||||
puts('{')
|
||||
down(function()
|
||||
if to_string_result then
|
||||
puts(' -- ', escape(to_string_result))
|
||||
if length >= 1 then tabify() end -- tabify the array values
|
||||
end
|
||||
|
||||
local needsComma = false
|
||||
for i=1, length do
|
||||
needsComma = commaControl(needsComma)
|
||||
puts(' ')
|
||||
putValue(t[i], makePath(path, i))
|
||||
end
|
||||
|
||||
for _,k in ipairs(dictKeys) do
|
||||
needsComma = commaControl(needsComma)
|
||||
tabify()
|
||||
putKey(k)
|
||||
puts(' = ')
|
||||
putValue(t[k], makePath(path, k))
|
||||
end
|
||||
|
||||
if mt then
|
||||
needsComma = commaControl(needsComma)
|
||||
tabify()
|
||||
puts('<metatable> = ')
|
||||
putValue(mt, makePath(path, '<metatable>'))
|
||||
end
|
||||
end)
|
||||
|
||||
if #dictKeys > 0 or mt then -- dictionary table. Justify closing }
|
||||
tabify()
|
||||
elseif length > 0 then -- array tables have one extra space before closing }
|
||||
puts(' ')
|
||||
end
|
||||
|
||||
puts('}')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- putvalue is forward-declared before putTable & putKey
|
||||
putValue = function(v, path)
|
||||
if filter(v, path) then
|
||||
puts('<filtered>')
|
||||
else
|
||||
local tv = type(v)
|
||||
|
||||
if tv == 'string' then
|
||||
puts(smartQuote(escape(v)))
|
||||
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then
|
||||
puts(tostring(v))
|
||||
elseif tv == 'table' then
|
||||
putTable(v, path)
|
||||
else
|
||||
puts('<',tv,' ',getId(v),'>')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
putValue(rootObject, {})
|
||||
|
||||
return table.concat(buffer)
|
||||
end
|
||||
|
||||
function printtable(name, table)
|
||||
print("table: ", name, inspect(table), "\n")
|
||||
end
|
||||
|
||||
function printstack()
|
||||
print(debug.traceback(), "\n")
|
||||
end
|
||||
@@ -0,0 +1,136 @@
|
||||
--
|
||||
-- io.lua
|
||||
-- Additions to the I/O namespace.
|
||||
-- Copyright (c) 2008-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
io.eol = "\n"
|
||||
io.indent = "\t"
|
||||
io.indentLevel = 0
|
||||
|
||||
-- default escaper function
|
||||
local function _escaper(v) return v end
|
||||
_esc = _escaper
|
||||
|
||||
|
||||
--
|
||||
-- Prepare to capture the output from all subsequent calls to io.printf(),
|
||||
-- used for automated testing of the generators. Returns the previously
|
||||
-- captured text.
|
||||
--
|
||||
|
||||
function io.capture()
|
||||
local prev = io.captured
|
||||
io.captured = ''
|
||||
return prev
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns the captured text and stops capturing, optionally restoring a
|
||||
-- previous capture.
|
||||
--
|
||||
|
||||
function io.endcapture(restore)
|
||||
local captured = io.captured
|
||||
io.captured = restore
|
||||
return captured
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Open an overload of the io.open() function, which will create any missing
|
||||
-- subdirectories in the filename if "mode" is set to writeable.
|
||||
--
|
||||
|
||||
local builtin_open = io.open
|
||||
function io.open(fname, mode)
|
||||
if (mode) then
|
||||
if (mode:find("w")) then
|
||||
local dir = path.getdirectory(fname)
|
||||
ok, err = os.mkdir(dir)
|
||||
if (not ok) then
|
||||
error(err, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
return builtin_open(fname, mode)
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- A shortcut for printing formatted output to an output stream.
|
||||
--
|
||||
|
||||
function io.printf(msg, ...)
|
||||
local arg={...}
|
||||
if not io.eol then
|
||||
io.eol = "\n"
|
||||
end
|
||||
|
||||
if not io.indent then
|
||||
io.indent = "\t"
|
||||
end
|
||||
|
||||
if type(msg) == "number" then
|
||||
s = string.rep(io.indent, msg) .. string.format(table.unpack(arg))
|
||||
else
|
||||
s = string.format(msg, table.unpack(arg))
|
||||
end
|
||||
|
||||
if io.captured then
|
||||
io.captured = io.captured .. s .. io.eol
|
||||
else
|
||||
io.write(s)
|
||||
io.write(io.eol)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Write a formatted string to the exported file, after passing all
|
||||
-- arguments (except for the first, which is the formatting string)
|
||||
-- through io.esc().
|
||||
--
|
||||
|
||||
function io.xprintf(msg, ...)
|
||||
local arg = {...}
|
||||
for i = 1, #arg do
|
||||
arg[i] = io.esc(arg[i])
|
||||
end
|
||||
io.printf(msg, unpack(arg))
|
||||
end
|
||||
|
||||
--
|
||||
-- Handle escaping of strings for various outputs
|
||||
--
|
||||
|
||||
function io.esc(value)
|
||||
if type(value) == "table" then
|
||||
local result = {}
|
||||
local n = #value
|
||||
for i = 1, n do
|
||||
table.insert(result, io.esc(value[i]))
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
return _esc(value or "")
|
||||
end
|
||||
|
||||
--
|
||||
-- Set a new string escaping function
|
||||
--
|
||||
|
||||
function io.escaper(func)
|
||||
_esc = func or _escaper
|
||||
end
|
||||
|
||||
--
|
||||
-- Because I use io.printf() so often in the generators, create a terse shortcut
|
||||
-- for it. This saves me typing, and also reduces the size of the executable.
|
||||
--
|
||||
|
||||
_p = io.printf
|
||||
_x = io.xprintf
|
||||
@@ -0,0 +1,16 @@
|
||||
iter = {}
|
||||
|
||||
-- sortByKeys iterates over the table where the keys are in sort order
|
||||
|
||||
function iter.sortByKeys(arr, f)
|
||||
local a = table.keys(arr)
|
||||
table.sort(a, f)
|
||||
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
if a[i] ~= nil then
|
||||
return a[i], arr[a[i]]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,113 @@
|
||||
--
|
||||
-- option.lua
|
||||
-- Work with the list of registered options.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.option = { }
|
||||
|
||||
|
||||
--
|
||||
-- The list of registered options.
|
||||
--
|
||||
|
||||
premake.option.list = { }
|
||||
|
||||
|
||||
--
|
||||
-- Register a new option.
|
||||
--
|
||||
-- @param opt
|
||||
-- The new option object.
|
||||
--
|
||||
|
||||
function premake.option.add(opt)
|
||||
-- some sanity checking
|
||||
local missing
|
||||
for _, field in ipairs({ "description", "trigger" }) do
|
||||
if (not opt[field]) then
|
||||
missing = field
|
||||
end
|
||||
end
|
||||
|
||||
if (missing) then
|
||||
error("option needs a " .. missing, 3)
|
||||
end
|
||||
|
||||
-- add it to the master list
|
||||
premake.option.list[opt.trigger] = opt
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve an option by name.
|
||||
--
|
||||
-- @param name
|
||||
-- The name of the option to retrieve.
|
||||
-- @returns
|
||||
-- The requested option, or nil if the option does not exist.
|
||||
--
|
||||
|
||||
function premake.option.get(name)
|
||||
return premake.option.list[name]
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Iterator for the list of options.
|
||||
--
|
||||
|
||||
function premake.option.each()
|
||||
-- sort the list by trigger
|
||||
local keys = { }
|
||||
for _, option in pairs(premake.option.list) do
|
||||
table.insert(keys, option.trigger)
|
||||
end
|
||||
table.sort(keys)
|
||||
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
return premake.option.list[keys[i]]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Validate a list of user supplied key/value pairs against the list of registered options.
|
||||
--
|
||||
-- @param values
|
||||
-- The list of user supplied key/value pairs.
|
||||
-- @returns
|
||||
--- True if the list of pairs are valid, false and an error message otherwise.
|
||||
--
|
||||
|
||||
function premake.option.validate(values)
|
||||
for key, value in pairs(values) do
|
||||
-- does this option exist
|
||||
local opt = premake.option.get(key)
|
||||
if (not opt) then
|
||||
return false, "invalid option '" .. key .. "'"
|
||||
end
|
||||
|
||||
-- does it need a value?
|
||||
if (opt.value and value == "") then
|
||||
return false, "no value specified for option '" .. key .. "'"
|
||||
end
|
||||
|
||||
-- is the value allowed?
|
||||
if opt.allowed then
|
||||
local found = false
|
||||
for _, match in ipairs(opt.allowed) do
|
||||
if match[1] == value then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
return false, string.format("invalid value '%s' for option '%s'", value, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -0,0 +1,298 @@
|
||||
--
|
||||
-- os.lua
|
||||
-- Additions to the OS namespace.
|
||||
-- Copyright (c) 2002-2011 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Same as os.execute(), but accepts string formatting arguments.
|
||||
--
|
||||
|
||||
function os.executef(cmd, ...)
|
||||
local arg={...}
|
||||
cmd = string.format(cmd, table.unpack(arg))
|
||||
return os.execute(cmd)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Scan the well-known system locations for a particular library.
|
||||
--
|
||||
|
||||
local function parse_ld_so_conf(conf_file)
|
||||
-- Linux ldconfig file parser to find system library locations
|
||||
local first, last
|
||||
local dirs = { }
|
||||
local file = io.open(conf_file)
|
||||
-- Handle missing ld.so.conf (BSDs) gracefully
|
||||
if file == nil then
|
||||
return dirs
|
||||
end
|
||||
for line in file:lines() do
|
||||
-- ignore comments
|
||||
first = line:find("#", 1, true)
|
||||
if first ~= nil then
|
||||
line = line:sub(1, first - 1)
|
||||
end
|
||||
|
||||
if line ~= "" then
|
||||
-- check for include files
|
||||
first, last = line:find("include%s+")
|
||||
if first ~= nil then
|
||||
-- found include glob
|
||||
local include_glob = line:sub(last + 1)
|
||||
local includes = os.matchfiles(include_glob)
|
||||
for _, v in ipairs(includes) do
|
||||
dirs = table.join(dirs, parse_ld_so_conf(v))
|
||||
end
|
||||
else
|
||||
-- found an actual ld path entry
|
||||
table.insert(dirs, line)
|
||||
end
|
||||
end
|
||||
end
|
||||
return dirs
|
||||
end
|
||||
|
||||
function os.findlib(libname)
|
||||
local path, formats
|
||||
|
||||
-- assemble a search path, depending on the platform
|
||||
if os.is("windows") then
|
||||
formats = { "%s.dll", "%s" }
|
||||
path = os.getenv("PATH")
|
||||
else
|
||||
if os.is("macosx") then
|
||||
formats = { "lib%s.dylib", "%s.dylib" }
|
||||
path = os.getenv("DYLD_LIBRARY_PATH")
|
||||
else
|
||||
formats = { "lib%s.so", "%s.so" }
|
||||
path = os.getenv("LD_LIBRARY_PATH") or ""
|
||||
|
||||
for _, v in ipairs(parse_ld_so_conf("/etc/ld.so.conf")) do
|
||||
path = path .. ":" .. v
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(formats, "%s")
|
||||
path = path or ""
|
||||
if os.is64bit() then
|
||||
path = path .. ":/lib64:/usr/lib64/:usr/local/lib64"
|
||||
end
|
||||
path = path .. ":/lib:/usr/lib:/usr/local/lib"
|
||||
end
|
||||
|
||||
for _, fmt in ipairs(formats) do
|
||||
local name = string.format(fmt, libname)
|
||||
local result = os.pathsearch(name, path)
|
||||
if result then return result end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve the current operating system ID string.
|
||||
--
|
||||
|
||||
function os.get()
|
||||
return _OPTIONS.os or _OS
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Check the current operating system; may be set with the /os command line flag.
|
||||
--
|
||||
|
||||
function os.is(id)
|
||||
return (os.get():lower() == id:lower())
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Determine if the current system is running a 64-bit architecture
|
||||
--
|
||||
|
||||
local _64BitHostTypes = {
|
||||
"x86_64",
|
||||
"ia64",
|
||||
"amd64",
|
||||
"ppc64",
|
||||
"powerpc64",
|
||||
"sparc64",
|
||||
"arm64"
|
||||
}
|
||||
|
||||
function os.is64bit()
|
||||
-- Call the native code implementation. If this returns true then
|
||||
-- we're 64-bit, otherwise do more checking locally
|
||||
if (os._is64bit()) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Identify the system
|
||||
local arch = ""
|
||||
if _OS == "windows" then
|
||||
arch = os.getenv("PROCESSOR_ARCHITECTURE")
|
||||
elseif _OS == "macosx" then
|
||||
arch = os.outputof("echo $HOSTTYPE")
|
||||
else
|
||||
arch = os.outputof("uname -m")
|
||||
end
|
||||
|
||||
if nil ~= arch then
|
||||
-- Check our known 64-bit identifiers
|
||||
arch = arch:lower()
|
||||
for _, hosttype in ipairs(_64BitHostTypes) do
|
||||
if arch:find(hosttype) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- The os.matchdirs() and os.matchfiles() functions
|
||||
--
|
||||
|
||||
local function domatch(result, mask, wantfiles)
|
||||
-- need to remove extraneous path info from the mask to ensure a match
|
||||
-- against the paths returned by the OS. Haven't come up with a good
|
||||
-- way to do it yet, so will handle cases as they come up
|
||||
if mask:startswith("./") then
|
||||
mask = mask:sub(3)
|
||||
end
|
||||
|
||||
-- strip off any leading directory information to find out
|
||||
-- where the search should take place
|
||||
local basedir = mask
|
||||
local starpos = mask:find("%*")
|
||||
if starpos then
|
||||
basedir = basedir:sub(1, starpos - 1)
|
||||
end
|
||||
basedir = path.getdirectory(basedir)
|
||||
if (basedir == ".") then basedir = "" end
|
||||
|
||||
-- recurse into subdirectories?
|
||||
local recurse = mask:find("**", nil, true)
|
||||
|
||||
-- convert mask to a Lua pattern
|
||||
mask = path.wildcards(mask)
|
||||
|
||||
local function matchwalker(basedir)
|
||||
local wildcard = path.join(basedir, "*")
|
||||
|
||||
-- retrieve files from OS and test against mask
|
||||
local m = os.matchstart(wildcard)
|
||||
while (os.matchnext(m)) do
|
||||
local isfile = os.matchisfile(m)
|
||||
if ((wantfiles and isfile) or (not wantfiles and not isfile)) then
|
||||
local fname = path.join(basedir, os.matchname(m))
|
||||
if fname:match(mask) == fname then
|
||||
table.insert(result, fname)
|
||||
end
|
||||
end
|
||||
end
|
||||
os.matchdone(m)
|
||||
|
||||
-- check subdirectories
|
||||
if recurse then
|
||||
m = os.matchstart(wildcard)
|
||||
while (os.matchnext(m)) do
|
||||
if not os.matchisfile(m) then
|
||||
local dirname = os.matchname(m)
|
||||
matchwalker(path.join(basedir, dirname))
|
||||
end
|
||||
end
|
||||
os.matchdone(m)
|
||||
end
|
||||
end
|
||||
|
||||
matchwalker(basedir)
|
||||
end
|
||||
|
||||
function os.matchdirs(...)
|
||||
local arg={...}
|
||||
local result = { }
|
||||
for _, mask in ipairs(arg) do
|
||||
domatch(result, mask, false)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function os.matchfiles(...)
|
||||
local arg={...}
|
||||
local result = { }
|
||||
for _, mask in ipairs(arg) do
|
||||
domatch(result, mask, true)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- An overload of the os.mkdir() function, which will create any missing
|
||||
-- subdirectories along the path.
|
||||
--
|
||||
|
||||
local builtin_mkdir = os.mkdir
|
||||
function os.mkdir(p)
|
||||
local dir = iif(p:startswith("/"), "/", "")
|
||||
for part in p:gmatch("[^/]+") do
|
||||
dir = dir .. part
|
||||
|
||||
if (part ~= "" and not path.isabsolute(part) and not os.isdir(dir)) then
|
||||
local ok, err = builtin_mkdir(dir)
|
||||
if (not ok) then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
dir = dir .. "/"
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Run a shell command and return the output.
|
||||
--
|
||||
|
||||
function os.outputof(cmd)
|
||||
local pipe = io.popen(cmd)
|
||||
local result = pipe:read('*a')
|
||||
pipe:close()
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Remove a directory, along with any contained files or subdirectories.
|
||||
--
|
||||
|
||||
local builtin_rmdir = os.rmdir
|
||||
function os.rmdir(p)
|
||||
-- recursively remove subdirectories
|
||||
local dirs = os.matchdirs(p .. "/*")
|
||||
for _, dname in ipairs(dirs) do
|
||||
os.rmdir(dname)
|
||||
end
|
||||
|
||||
-- remove any files
|
||||
local files = os.matchfiles(p .. "/*")
|
||||
for _, fname in ipairs(files) do
|
||||
os.remove(fname)
|
||||
end
|
||||
|
||||
-- remove this directory
|
||||
builtin_rmdir(p)
|
||||
end
|
||||
@@ -0,0 +1,400 @@
|
||||
--
|
||||
-- path.lua
|
||||
-- Path manipulation functions.
|
||||
-- Copyright (c) 2002-2010 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve the filename portion of a path, without any extension.
|
||||
--
|
||||
|
||||
function path.getbasename(p)
|
||||
local name = path.getname(p)
|
||||
local i = name:findlast(".", true)
|
||||
if (i) then
|
||||
return name:sub(1, i - 1)
|
||||
else
|
||||
return name
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Retrieve the path, without any extension.
|
||||
--
|
||||
|
||||
function path.removeext(name)
|
||||
local i = name:findlast(".", true)
|
||||
if (i) then
|
||||
return name:sub(1, i - 1)
|
||||
else
|
||||
return name
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Retrieve the directory portion of a path, or an empty string if
|
||||
-- the path does not include a directory.
|
||||
--
|
||||
|
||||
function path.getdirectory(p)
|
||||
local i = p:findlast("/", true)
|
||||
if (i) then
|
||||
if i > 1 then i = i - 1 end
|
||||
return p:sub(1, i)
|
||||
else
|
||||
return "."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve the drive letter, if a Windows path.
|
||||
--
|
||||
|
||||
function path.getdrive(p)
|
||||
local ch1 = p:sub(1,1)
|
||||
local ch2 = p:sub(2,2)
|
||||
if ch2 == ":" then
|
||||
return ch1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve the file extension.
|
||||
--
|
||||
|
||||
function path.getextension(p)
|
||||
local i = p:findlast(".", true)
|
||||
if (i) then
|
||||
return p:sub(i)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve the filename portion of a path.
|
||||
--
|
||||
|
||||
function path.getname(p)
|
||||
local i = p:findlast("[/\\]")
|
||||
if (i) then
|
||||
return p:sub(i + 1)
|
||||
else
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns the common base directory of two paths.
|
||||
--
|
||||
|
||||
function path.getcommonbasedir(a, b)
|
||||
a = path.getdirectory(a)..'/'
|
||||
b = path.getdirectory(b)..'/'
|
||||
|
||||
-- find the common leading directories
|
||||
local idx = 0
|
||||
while (true) do
|
||||
local tst = a:find('/', idx + 1, true)
|
||||
if tst then
|
||||
if a:sub(1,tst) == b:sub(1,tst) then
|
||||
idx = tst
|
||||
else
|
||||
break
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
-- idx is the index of the last sep before path string 'a' ran out or didn't match.
|
||||
local result = ''
|
||||
if idx > 1 then
|
||||
result = a:sub(1, idx - 1) -- Remove the trailing slash to be consistent with other functions.
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the filename has a particular extension.
|
||||
--
|
||||
-- @param fname
|
||||
-- The file name to test.
|
||||
-- @param extensions
|
||||
-- The extension(s) to test. Maybe be a string or table.
|
||||
--
|
||||
|
||||
function path.hasextension(fname, extensions)
|
||||
local fext = path.getextension(fname):lower()
|
||||
if type(extensions) == "table" then
|
||||
for _, extension in pairs(extensions) do
|
||||
if fext == extension then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
else
|
||||
return (fext == extensions)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns true if the filename represents a C/C++ source code file. This check
|
||||
-- is used to prevent passing non-code files to the compiler in makefiles. It is
|
||||
-- not foolproof, but it has held up well. I'm open to better suggestions.
|
||||
--
|
||||
|
||||
function path.iscfile(fname)
|
||||
return path.hasextension(fname, { ".c", ".m" })
|
||||
end
|
||||
|
||||
function path.iscppfile(fname)
|
||||
return path.hasextension(fname, { ".cc", ".cpp", ".cxx", ".c++", ".c", ".m", ".mm" })
|
||||
end
|
||||
|
||||
function path.iscxfile(fname)
|
||||
return path.hasextension(fname, ".cx")
|
||||
end
|
||||
|
||||
function path.isobjcfile(fname)
|
||||
return path.hasextension(fname, { ".m", ".mm" })
|
||||
end
|
||||
|
||||
function path.iscppheader(fname)
|
||||
return path.hasextension(fname, { ".h", ".hh", ".hpp", ".hxx" })
|
||||
end
|
||||
|
||||
function path.iscppmodule(fname)
|
||||
return path.hasextension(fname, { ".ixx", ".cppm" })
|
||||
end
|
||||
|
||||
function path.isappxmanifest(fname)
|
||||
return path.hasextension(fname, ".appxmanifest")
|
||||
end
|
||||
|
||||
function path.isandroidbuildfile(fname)
|
||||
return path.getname(fname) == "AndroidManifest.xml"
|
||||
end
|
||||
|
||||
function path.isnatvis(fname)
|
||||
return path.hasextension(fname, ".natvis")
|
||||
end
|
||||
|
||||
function path.isasmfile(fname)
|
||||
return path.hasextension(fname, { ".asm", ".s", ".S" })
|
||||
end
|
||||
|
||||
function path.isvalafile(fname)
|
||||
return path.hasextension(fname, ".vala")
|
||||
end
|
||||
|
||||
function path.isgresource(fname)
|
||||
local ending = ".gresource.xml"
|
||||
return ending == "" or fname:sub(-#ending) == ending
|
||||
end
|
||||
|
||||
function path.isswiftfile(fname)
|
||||
return path.hasextension(fname, ".swift")
|
||||
end
|
||||
|
||||
function path.issourcefile(fname)
|
||||
return path.iscfile(fname)
|
||||
or path.iscppfile(fname)
|
||||
or path.iscxfile(fname)
|
||||
or path.isasmfile(fname)
|
||||
or path.isvalafile(fname)
|
||||
or path.isswiftfile(fname)
|
||||
end
|
||||
|
||||
function path.issourcefilevs(fname)
|
||||
return path.hasextension(fname, { ".cc", ".cpp", ".cxx", ".c++", ".c" })
|
||||
or path.iscxfile(fname)
|
||||
or path.iscppmodule(fname)
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns true if the filename represents a compiled object file. This check
|
||||
-- is used to support object files in the "files" list for archiving.
|
||||
--
|
||||
|
||||
function path.isobjectfile(fname)
|
||||
return path.hasextension(fname, { ".o", ".obj" })
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns true if the filename represents a Windows resource file. This check
|
||||
-- is used to prevent passing non-resources to the compiler in makefiles.
|
||||
--
|
||||
|
||||
function path.isresourcefile(fname)
|
||||
return path.hasextension(fname, ".rc")
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the filename represents a Windows image file.
|
||||
--
|
||||
|
||||
function path.isimagefile(fname)
|
||||
local extensions = { ".png" }
|
||||
local ext = path.getextension(fname):lower()
|
||||
return table.contains(extensions, ext)
|
||||
end
|
||||
|
||||
--
|
||||
-- Join one or more pieces of a path together into a single path.
|
||||
--
|
||||
-- @param ...
|
||||
-- One or more path strings.
|
||||
-- @return
|
||||
-- The joined path.
|
||||
--
|
||||
|
||||
function path.join(...)
|
||||
local arg={...}
|
||||
local numargs = select("#", ...)
|
||||
if numargs == 0 then
|
||||
return "";
|
||||
end
|
||||
|
||||
local allparts = {}
|
||||
for i = numargs, 1, -1 do
|
||||
local part = select(i, ...)
|
||||
if part and #part > 0 and part ~= "." then
|
||||
-- trim off trailing slashes
|
||||
while part:endswith("/") do
|
||||
part = part:sub(1, -2)
|
||||
end
|
||||
|
||||
table.insert(allparts, 1, part)
|
||||
if path.isabsolute(part) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(allparts, "/")
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Takes a path which is relative to one location and makes it relative
|
||||
-- to another location instead.
|
||||
--
|
||||
|
||||
function path.rebase(p, oldbase, newbase)
|
||||
p = path.getabsolute(path.join(oldbase, p))
|
||||
p = path.getrelative(newbase, p)
|
||||
return p
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Convert the separators in a path from one form to another. If `sep`
|
||||
-- is nil, then a platform-specific separator is used.
|
||||
--
|
||||
|
||||
function path.translate(p, sep)
|
||||
if (type(p) == "table") then
|
||||
local result = { }
|
||||
for _, value in ipairs(p) do
|
||||
table.insert(result, path.translate(value))
|
||||
end
|
||||
return result
|
||||
else
|
||||
if (not sep) then
|
||||
if (os.is("windows")) then
|
||||
sep = "\\"
|
||||
else
|
||||
sep = "/"
|
||||
end
|
||||
end
|
||||
local result = p:gsub("[/\\]", sep)
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Converts from a simple wildcard syntax, where * is "match any"
|
||||
-- and ** is "match recursive", to the corresponding Lua pattern.
|
||||
--
|
||||
-- @param pattern
|
||||
-- The wildcard pattern to convert.
|
||||
-- @returns
|
||||
-- The corresponding Lua pattern.
|
||||
--
|
||||
|
||||
function path.wildcards(pattern)
|
||||
-- Escape characters that have special meanings in Lua patterns
|
||||
pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1")
|
||||
|
||||
-- Replace wildcard patterns with special placeholders so I don't
|
||||
-- have competing star replacements to worry about
|
||||
pattern = pattern:gsub("%*%*", "\001")
|
||||
pattern = pattern:gsub("%*", "\002")
|
||||
|
||||
-- Replace the placeholders with their Lua patterns
|
||||
pattern = pattern:gsub("\001", ".*")
|
||||
pattern = pattern:gsub("\002", "[^/]*")
|
||||
|
||||
return pattern
|
||||
end
|
||||
|
||||
--
|
||||
-- remove any dot ("./", "../") patterns from the start of the path
|
||||
--
|
||||
function path.trimdots(p)
|
||||
local changed
|
||||
repeat
|
||||
changed = true
|
||||
if p:startswith("./") then
|
||||
p = p:sub(3)
|
||||
elseif p:startswith("../") then
|
||||
p = p:sub(4)
|
||||
else
|
||||
changed = false
|
||||
end
|
||||
until not changed
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
--
|
||||
-- Takes a path which is relative to one location and makes it relative
|
||||
-- to another location instead.
|
||||
--
|
||||
|
||||
function path.rebase(p, oldbase, newbase)
|
||||
p = path.getabsolute(path.join(oldbase, p))
|
||||
p = path.getrelative(newbase, p)
|
||||
return p
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Replace the file extension.
|
||||
--
|
||||
|
||||
function path.replaceextension(p, newext)
|
||||
local ext = path.getextension(p)
|
||||
|
||||
if not ext then
|
||||
return p
|
||||
end
|
||||
|
||||
if #newext > 0 and not newext:findlast(".", true) then
|
||||
newext = "."..newext
|
||||
end
|
||||
|
||||
return p:match("^(.*)"..ext.."$")..newext
|
||||
end
|
||||
@@ -0,0 +1,120 @@
|
||||
--
|
||||
-- premake.lua
|
||||
-- High-level processing functions.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake._filelevelconfig = false
|
||||
premake._checkgenerate = true
|
||||
|
||||
--
|
||||
-- Open a file for output, and call a function to actually do the writing.
|
||||
-- Used by the actions to generate solution and project files.
|
||||
--
|
||||
-- @param obj
|
||||
-- A solution or project object; will be based to the callback function.
|
||||
-- @param filename
|
||||
-- The output filename; see the docs for premake.project.getfilename()
|
||||
-- for the expected format.
|
||||
-- @param callback
|
||||
-- The function responsible for writing the file, should take a solution
|
||||
-- or project as a parameters.
|
||||
--
|
||||
|
||||
function premake.generate(obj, filename, callback)
|
||||
local prev = io.capture()
|
||||
local abort = (callback(obj) == false)
|
||||
local new = io.endcapture(prev)
|
||||
|
||||
if abort then
|
||||
premake.stats.num_skipped = premake.stats.num_skipped + 1
|
||||
return
|
||||
end
|
||||
|
||||
filename = premake.project.getfilename(obj, filename)
|
||||
|
||||
if (premake._checkgenerate) then
|
||||
local delta = false
|
||||
|
||||
local f, err = io.open(filename, "rb")
|
||||
if (not f) then
|
||||
if string.find(err, "No such file or directory") then
|
||||
delta = true
|
||||
else
|
||||
error(err, 0)
|
||||
end
|
||||
else
|
||||
local existing = f:read("*all")
|
||||
if existing ~= new then
|
||||
delta = true
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
if delta then
|
||||
printf("Generating %q", filename)
|
||||
local f, err = io.open(filename, "wb")
|
||||
if (not f) then
|
||||
error(err, 0)
|
||||
end
|
||||
|
||||
f:write(new)
|
||||
f:close()
|
||||
|
||||
premake.stats.num_generated = premake.stats.num_generated + 1
|
||||
else
|
||||
-- printf("Skipping %s as its contents would not change.", filename)
|
||||
premake.stats.num_skipped = premake.stats.num_skipped + 1
|
||||
end
|
||||
else
|
||||
printf("Generating %q", filename)
|
||||
|
||||
local f, err = io.open(filename, "wb")
|
||||
if (not f) then
|
||||
error(err, 0)
|
||||
end
|
||||
|
||||
f:write(new)
|
||||
f:close()
|
||||
premake.stats.num_generated = premake.stats.num_generated + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Finds a valid premake build file in the specified directory
|
||||
-- Used by both the main genie process, and include commands
|
||||
--
|
||||
-- @param dir
|
||||
-- The path in which to start looking for the script
|
||||
-- @param search_upwards
|
||||
-- When the script was not found in the specified directory, does the
|
||||
-- script need to look upwards in the file system
|
||||
--
|
||||
|
||||
function premake.findDefaultScript(dir, search_upwards)
|
||||
search_upwards = search_upwards or true
|
||||
|
||||
local last = ""
|
||||
while dir ~= last do
|
||||
for _, name in ipairs({ "genie.lua", "solution.lua", "premake4.lua" }) do
|
||||
|
||||
local script0 = dir .. "/" .. name
|
||||
if (os.isfile(script0)) then
|
||||
return dir, name
|
||||
end
|
||||
|
||||
local script1 = dir .. "/scripts/" .. name
|
||||
if (os.isfile(script1)) then
|
||||
return dir .. "/scripts/", name
|
||||
end
|
||||
end
|
||||
|
||||
last = dir
|
||||
dir = path.getabsolute(dir .. "/..")
|
||||
|
||||
if dir == "." or not search_upwards then break end
|
||||
end
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
@@ -0,0 +1,613 @@
|
||||
--
|
||||
-- http://lua-users.org/wiki/PepperfishProfiler
|
||||
--
|
||||
-- == Introduction ==
|
||||
--
|
||||
-- Note that this requires os.clock(), debug.sethook(),
|
||||
-- and debug.getinfo() or your equivalent replacements to
|
||||
-- be available if this is an embedded application.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- profiler = newProfiler()
|
||||
-- profiler:start()
|
||||
--
|
||||
-- < call some functions that take time >
|
||||
--
|
||||
-- profiler:stop()
|
||||
--
|
||||
-- local outfile = io.open( "profile.txt", "w+" )
|
||||
-- profiler:report( outfile )
|
||||
-- outfile:close()
|
||||
--
|
||||
-- == Optionally choosing profiling method ==
|
||||
--
|
||||
-- The rest of this comment can be ignored if you merely want a good profiler.
|
||||
--
|
||||
-- newProfiler(method, sampledelay):
|
||||
--
|
||||
-- If method is omitted or "time", will profile based on real performance.
|
||||
-- optionally, frequency can be provided to control the number of opcodes
|
||||
-- per profiling tick. By default this is 100000, which (on my system) provides
|
||||
-- one tick approximately every 2ms and reduces system performance by about 10%.
|
||||
-- This can be reduced to increase accuracy at the cost of performance, or
|
||||
-- increased for the opposite effect.
|
||||
--
|
||||
-- If method is "call", will profile based on function calls. Frequency is
|
||||
-- ignored.
|
||||
--
|
||||
--
|
||||
-- "time" may bias profiling somewhat towards large areas with "simple opcodes",
|
||||
-- as the profiling function (which introduces a certain amount of unavoidable
|
||||
-- overhead) will be called more often. This can be minimized by using a larger
|
||||
-- sample delay - the default should leave any error largely overshadowed by
|
||||
-- statistical noise. With a delay of 1000 I was able to achieve inaccuray of
|
||||
-- approximately 25%. Increasing the delay to 100000 left inaccuracy below my
|
||||
-- testing error.
|
||||
--
|
||||
-- "call" may bias profiling heavily towards areas with many function calls.
|
||||
-- Testing found a degenerate case giving a figure inaccurate by approximately
|
||||
-- 20,000%. (Yes, a multiple of 200.) This is, however, more directly comparable
|
||||
-- to common profilers (such as gprof) and also gives accurate function call
|
||||
-- counts, which cannot be retrieved from "time".
|
||||
--
|
||||
-- I strongly recommend "time" mode, and it is now the default.
|
||||
--
|
||||
-- == History ==
|
||||
--
|
||||
-- 2008-09-16 - Time-based profiling and conversion to Lua 5.1
|
||||
-- by Ben Wilhelm ( zorba-pepperfish@pavlovian.net ).
|
||||
-- Added the ability to optionally choose profiling methods, along with a new
|
||||
-- profiling method.
|
||||
--
|
||||
-- Converted to Lua 5, a few improvements, and
|
||||
-- additional documentation by Tom Spilman ( tom@sickheadgames.com )
|
||||
--
|
||||
-- Additional corrections and tidying by original author
|
||||
-- Daniel Silverstone ( dsilvers@pepperfish.net )
|
||||
--
|
||||
-- == Status ==
|
||||
--
|
||||
-- Daniel Silverstone is no longer using this code, and judging by how long it's
|
||||
-- been waiting for Lua 5.1 support, I don't think Tom Spilman is either. I'm
|
||||
-- perfectly willing to take on maintenance, so if you have problems or
|
||||
-- questions, go ahead and email me :)
|
||||
-- -- Ben Wilhelm ( zorba-pepperfish@pavlovian.net ) '
|
||||
--
|
||||
-- == Copyright ==
|
||||
--
|
||||
-- Lua profiler - Copyright Pepperfish 2002,2003,2004
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to
|
||||
-- deal in the Software without restriction, including without limitation the
|
||||
-- rights to use, copy, modify, merge, publish, distribute, and/or sell copies
|
||||
-- of the Software, and to permit persons to whom the Software is furnished to
|
||||
-- do so, subject to the following conditions:
|
||||
--
|
||||
-- The above copyright notice and this permission notice shall be included in
|
||||
-- all copies or substantial portions of the Software.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
-- IN THE SOFTWARE.
|
||||
--
|
||||
|
||||
--
|
||||
-- All profiler related stuff is stored in the top level table '_profiler'
|
||||
--
|
||||
_profiler = {}
|
||||
|
||||
|
||||
--
|
||||
-- newProfiler() creates a new profiler object for managing
|
||||
-- the profiler and storing state. Note that only one profiler
|
||||
-- object can be executing at one time.
|
||||
--
|
||||
function newProfiler(variant, sampledelay)
|
||||
if _profiler.running then
|
||||
print("Profiler already running.")
|
||||
return
|
||||
end
|
||||
|
||||
variant = variant or "time"
|
||||
|
||||
if variant ~= "time" and variant ~= "call" then
|
||||
print("Profiler method must be 'time' or 'call'.")
|
||||
return
|
||||
end
|
||||
|
||||
local newprof = {}
|
||||
for k,v in pairs(_profiler) do
|
||||
newprof[k] = v
|
||||
end
|
||||
newprof.variant = variant
|
||||
newprof.sampledelay = sampledelay or 100000
|
||||
return newprof
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This function starts the profiler. It will do nothing
|
||||
-- if this (or any other) profiler is already running.
|
||||
--
|
||||
function _profiler.start(self)
|
||||
if _profiler.running then
|
||||
return
|
||||
end
|
||||
-- Start the profiler. This begins by setting up internal profiler state
|
||||
_profiler.running = self
|
||||
self.rawstats = {}
|
||||
self.callstack = {}
|
||||
if self.variant == "time" then
|
||||
self.lastclock = os.clock()
|
||||
debug.sethook( _profiler_hook_wrapper_by_time, "", self.sampledelay )
|
||||
elseif self.variant == "call" then
|
||||
debug.sethook( _profiler_hook_wrapper_by_call, "cr" )
|
||||
else
|
||||
print("Profiler method must be 'time' or 'call'.")
|
||||
sys.exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This function stops the profiler. It will do nothing
|
||||
-- if a profiler is not running, and nothing if it isn't
|
||||
-- the currently running profiler.
|
||||
--
|
||||
function _profiler.stop(self)
|
||||
if _profiler.running ~= self then
|
||||
return
|
||||
end
|
||||
-- Stop the profiler.
|
||||
debug.sethook( nil )
|
||||
_profiler.running = nil
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Simple wrapper to handle the hook. You should not
|
||||
-- be calling this directly. Duplicated to reduce overhead.
|
||||
--
|
||||
function _profiler_hook_wrapper_by_call(action)
|
||||
if _profiler.running == nil then
|
||||
debug.sethook( nil )
|
||||
end
|
||||
_profiler.running:_internal_profile_by_call(action)
|
||||
end
|
||||
function _profiler_hook_wrapper_by_time(action)
|
||||
if _profiler.running == nil then
|
||||
debug.sethook( nil )
|
||||
end
|
||||
_profiler.running:_internal_profile_by_time(action)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This is the main by-function-call function of the profiler and should not
|
||||
-- be called except by the hook wrapper
|
||||
--
|
||||
function _profiler._internal_profile_by_call(self,action)
|
||||
-- Since we can obtain the 'function' for the item we've had call us, we
|
||||
-- can use that...
|
||||
local caller_info = debug.getinfo( 3 )
|
||||
if caller_info == nil then
|
||||
print "No caller_info"
|
||||
return
|
||||
end
|
||||
|
||||
--SHG_LOG("[_profiler._internal_profile] "..(caller_info.name or "<nil>"))
|
||||
|
||||
-- Retrieve the most recent activation record...
|
||||
local latest_ar = nil
|
||||
if table.getn(self.callstack) > 0 then
|
||||
latest_ar = self.callstack[table.getn(self.callstack)]
|
||||
end
|
||||
|
||||
-- Are we allowed to profile this function?
|
||||
local should_not_profile = 0
|
||||
for k,v in pairs(self.prevented_functions) do
|
||||
if k == caller_info.func then
|
||||
should_not_profile = v
|
||||
end
|
||||
end
|
||||
-- Also check the top activation record...
|
||||
if latest_ar then
|
||||
if latest_ar.should_not_profile == 2 then
|
||||
should_not_profile = 2
|
||||
end
|
||||
end
|
||||
|
||||
-- Now then, are we in 'call' or 'return' ?
|
||||
-- print("Profile:", caller_info.name, "SNP:", should_not_profile,
|
||||
-- "Action:", action )
|
||||
if action == "call" then
|
||||
-- Making a call...
|
||||
local this_ar = {}
|
||||
this_ar.should_not_profile = should_not_profile
|
||||
this_ar.parent_ar = latest_ar
|
||||
this_ar.anon_child = 0
|
||||
this_ar.name_child = 0
|
||||
this_ar.children = {}
|
||||
this_ar.children_time = {}
|
||||
this_ar.clock_start = os.clock()
|
||||
-- Last thing to do on a call is to insert this onto the ar stack...
|
||||
table.insert( self.callstack, this_ar )
|
||||
else
|
||||
local this_ar = latest_ar
|
||||
if this_ar == nil then
|
||||
return -- No point in doing anything if no upper activation record
|
||||
end
|
||||
|
||||
-- Right, calculate the time in this function...
|
||||
this_ar.clock_end = os.clock()
|
||||
this_ar.this_time = this_ar.clock_end - this_ar.clock_start
|
||||
|
||||
-- Now, if we have a parent, update its call info...
|
||||
if this_ar.parent_ar then
|
||||
this_ar.parent_ar.children[caller_info.func] =
|
||||
(this_ar.parent_ar.children[caller_info.func] or 0) + 1
|
||||
this_ar.parent_ar.children_time[caller_info.func] =
|
||||
(this_ar.parent_ar.children_time[caller_info.func] or 0 ) +
|
||||
this_ar.this_time
|
||||
if caller_info.name == nil then
|
||||
this_ar.parent_ar.anon_child =
|
||||
this_ar.parent_ar.anon_child + this_ar.this_time
|
||||
else
|
||||
this_ar.parent_ar.name_child =
|
||||
this_ar.parent_ar.name_child + this_ar.this_time
|
||||
end
|
||||
end
|
||||
-- Now if we're meant to record information about ourselves, do so...
|
||||
if this_ar.should_not_profile == 0 then
|
||||
local inforec = self:_get_func_rec(caller_info.func,1)
|
||||
inforec.count = inforec.count + 1
|
||||
inforec.time = inforec.time + this_ar.this_time
|
||||
inforec.anon_child_time = inforec.anon_child_time + this_ar.anon_child
|
||||
inforec.name_child_time = inforec.name_child_time + this_ar.name_child
|
||||
inforec.func_info = caller_info
|
||||
for k,v in pairs(this_ar.children) do
|
||||
inforec.children[k] = (inforec.children[k] or 0) + v
|
||||
inforec.children_time[k] =
|
||||
(inforec.children_time[k] or 0) + this_ar.children_time[k]
|
||||
end
|
||||
end
|
||||
|
||||
-- Last thing to do on return is to drop the last activation record...
|
||||
table.remove( self.callstack, table.getn( self.callstack ) )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This is the main by-time internal function of the profiler and should not
|
||||
-- be called except by the hook wrapper
|
||||
--
|
||||
function _profiler._internal_profile_by_time(self,action)
|
||||
-- we do this first so we add the minimum amount of extra time to this call
|
||||
local timetaken = os.clock() - self.lastclock
|
||||
|
||||
local depth = 3
|
||||
local at_top = true
|
||||
local last_caller
|
||||
local caller = debug.getinfo(depth)
|
||||
while caller do
|
||||
if not caller.func then caller.func = "(tail call)" end
|
||||
if self.prevented_functions[caller.func] == nil then
|
||||
local info = self:_get_func_rec(caller.func, 1, caller)
|
||||
info.count = info.count + 1
|
||||
info.time = info.time + timetaken
|
||||
if last_caller then
|
||||
-- we're not the head, so update the "children" times also
|
||||
if last_caller.name then
|
||||
info.name_child_time = info.name_child_time + timetaken
|
||||
else
|
||||
info.anon_child_time = info.anon_child_time + timetaken
|
||||
end
|
||||
info.children[last_caller.func] =
|
||||
(info.children[last_caller.func] or 0) + 1
|
||||
info.children_time[last_caller.func] =
|
||||
(info.children_time[last_caller.func] or 0) + timetaken
|
||||
end
|
||||
end
|
||||
depth = depth + 1
|
||||
last_caller = caller
|
||||
caller = debug.getinfo(depth)
|
||||
end
|
||||
|
||||
self.lastclock = os.clock()
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This returns a (possibly empty) function record for
|
||||
-- the specified function. It is for internal profiler use.
|
||||
--
|
||||
function _profiler._get_func_rec(self,func,force,info)
|
||||
-- Find the function ref for 'func' (if force and not present, create one)
|
||||
local ret = self.rawstats[func]
|
||||
if ret == nil and force ~= 1 then
|
||||
return nil
|
||||
end
|
||||
if ret == nil then
|
||||
-- Build a new function statistics table
|
||||
ret = {}
|
||||
ret.func = func
|
||||
ret.count = 0
|
||||
ret.time = 0
|
||||
ret.anon_child_time = 0
|
||||
ret.name_child_time = 0
|
||||
ret.children = {}
|
||||
ret.children_time = {}
|
||||
ret.func_info = info
|
||||
self.rawstats[func] = ret
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This writes a profile report to the output file object. If
|
||||
-- sort_by_total_time is nil or false the output is sorted by
|
||||
-- the function time minus the time in it's children.
|
||||
--
|
||||
function _profiler.report( self, outfile, sort_by_total_time )
|
||||
|
||||
outfile:write
|
||||
[[Lua Profile output created by profiler.lua. Copyright Pepperfish 2002+
|
||||
|
||||
]]
|
||||
|
||||
-- This is pretty awful.
|
||||
local terms = {}
|
||||
if self.variant == "time" then
|
||||
terms.capitalized = "Sample"
|
||||
terms.single = "sample"
|
||||
terms.pastverb = "sampled"
|
||||
elseif self.variant == "call" then
|
||||
terms.capitalized = "Call"
|
||||
terms.single = "call"
|
||||
terms.pastverb = "called"
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
|
||||
local total_time = 0
|
||||
local ordering = {}
|
||||
for func,record in pairs(self.rawstats) do
|
||||
table.insert(ordering, func)
|
||||
end
|
||||
|
||||
if sort_by_total_time then
|
||||
table.sort( ordering,
|
||||
function(a,b) return self.rawstats[a].time > self.rawstats[b].time end
|
||||
)
|
||||
else
|
||||
table.sort( ordering,
|
||||
function(a,b)
|
||||
local arec = self.rawstats[a]
|
||||
local brec = self.rawstats[b]
|
||||
local atime = arec.time - (arec.anon_child_time + arec.name_child_time)
|
||||
local btime = brec.time - (brec.anon_child_time + brec.name_child_time)
|
||||
return atime > btime
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
for i=1,#ordering do
|
||||
local func = ordering[i]
|
||||
local record = self.rawstats[func]
|
||||
local thisfuncname = " " .. self:_pretty_name(func) .. " "
|
||||
if string.len( thisfuncname ) < 42 then
|
||||
thisfuncname = string.rep( "-", math.floor((42 - string.len(thisfuncname))/2) ) .. thisfuncname
|
||||
thisfuncname = thisfuncname .. string.rep( "-", 42 - string.len(thisfuncname) )
|
||||
end
|
||||
|
||||
total_time = total_time + ( record.time - ( record.anon_child_time +
|
||||
record.name_child_time ) )
|
||||
outfile:write( string.rep( "-", 19 ) .. thisfuncname ..
|
||||
string.rep( "-", 19 ) .. "\n" )
|
||||
outfile:write( terms.capitalized.." count: " ..
|
||||
string.format( "%4d", record.count ) .. "\n" )
|
||||
outfile:write( "Time spend total: " ..
|
||||
string.format( "%4.3f", record.time ) .. "s\n" )
|
||||
outfile:write( "Time spent in children: " ..
|
||||
string.format("%4.3f",record.anon_child_time+record.name_child_time) ..
|
||||
"s\n" )
|
||||
local timeinself =
|
||||
record.time - (record.anon_child_time + record.name_child_time)
|
||||
outfile:write( "Time spent in self: " ..
|
||||
string.format("%4.3f", timeinself) .. "s\n" )
|
||||
outfile:write( "Time spent per " .. terms.single .. ": " ..
|
||||
string.format("%4.5f", record.time/record.count) ..
|
||||
"s/" .. terms.single .. "\n" )
|
||||
outfile:write( "Time spent in self per "..terms.single..": " ..
|
||||
string.format( "%4.5f", timeinself/record.count ) .. "s/" ..
|
||||
terms.single.."\n" )
|
||||
|
||||
-- Report on each child in the form
|
||||
-- Child <funcname> called n times and took a.bs
|
||||
local added_blank = 0
|
||||
for k,v in pairs(record.children) do
|
||||
if self.prevented_functions[k] == nil or
|
||||
self.prevented_functions[k] == 0
|
||||
then
|
||||
if added_blank == 0 then
|
||||
outfile:write( "\n" ) -- extra separation line
|
||||
added_blank = 1
|
||||
end
|
||||
outfile:write( "Child " .. self:_pretty_name(k) ..
|
||||
string.rep( " ", 41-string.len(self:_pretty_name(k)) ) .. " " ..
|
||||
terms.pastverb.." " .. string.format("%6d", v) )
|
||||
outfile:write( " times. Took " ..
|
||||
string.format("%4.2f", record.children_time[k] ) .. "s\n" )
|
||||
end
|
||||
end
|
||||
|
||||
outfile:write( "\n" ) -- extra separation line
|
||||
outfile:flush()
|
||||
end
|
||||
outfile:write( "\n\n" )
|
||||
outfile:write( "Total time spent in profiled functions: " ..
|
||||
string.format("%5.3g",total_time) .. "s\n" )
|
||||
outfile:write( [[
|
||||
|
||||
END
|
||||
]] )
|
||||
outfile:flush()
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This writes the profile to the output file object as
|
||||
-- loadable Lua source.
|
||||
--
|
||||
function _profiler.lua_report(self,outfile)
|
||||
-- Purpose: Write out the entire raw state in a cross-referenceable form.
|
||||
local ordering = {}
|
||||
local functonum = {}
|
||||
for func,record in pairs(self.rawstats) do
|
||||
table.insert(ordering, func)
|
||||
functonum[func] = table.getn(ordering)
|
||||
end
|
||||
|
||||
outfile:write(
|
||||
"-- Profile generated by profiler.lua Copyright Pepperfish 2002+\n\n" )
|
||||
outfile:write( "-- Function names\nfuncnames = {}\n" )
|
||||
for i=1,table.getn(ordering) do
|
||||
local thisfunc = ordering[i]
|
||||
outfile:write( "funcnames[" .. i .. "] = " ..
|
||||
string.format("%q", self:_pretty_name(thisfunc)) .. "\n" )
|
||||
end
|
||||
outfile:write( "\n" )
|
||||
outfile:write( "-- Function times\nfunctimes = {}\n" )
|
||||
for i=1,table.getn(ordering) do
|
||||
local thisfunc = ordering[i]
|
||||
local record = self.rawstats[thisfunc]
|
||||
outfile:write( "functimes[" .. i .. "] = { " )
|
||||
outfile:write( "tot=" .. record.time .. ", " )
|
||||
outfile:write( "achild=" .. record.anon_child_time .. ", " )
|
||||
outfile:write( "nchild=" .. record.name_child_time .. ", " )
|
||||
outfile:write( "count=" .. record.count .. " }\n" )
|
||||
end
|
||||
outfile:write( "\n" )
|
||||
outfile:write( "-- Child links\nchildren = {}\n" )
|
||||
for i=1,table.getn(ordering) do
|
||||
local thisfunc = ordering[i]
|
||||
local record = self.rawstats[thisfunc]
|
||||
outfile:write( "children[" .. i .. "] = { " )
|
||||
for k,v in pairs(record.children) do
|
||||
if functonum[k] then -- non-recorded functions will be ignored now
|
||||
outfile:write( functonum[k] .. ", " )
|
||||
end
|
||||
end
|
||||
outfile:write( "}\n" )
|
||||
end
|
||||
outfile:write( "\n" )
|
||||
outfile:write( "-- Child call counts\nchildcounts = {}\n" )
|
||||
for i=1,table.getn(ordering) do
|
||||
local thisfunc = ordering[i]
|
||||
local record = self.rawstats[thisfunc]
|
||||
outfile:write( "children[" .. i .. "] = { " )
|
||||
for k,v in record.children do
|
||||
if functonum[k] then -- non-recorded functions will be ignored now
|
||||
outfile:write( v .. ", " )
|
||||
end
|
||||
end
|
||||
outfile:write( "}\n" )
|
||||
end
|
||||
outfile:write( "\n" )
|
||||
outfile:write( "-- Child call time\nchildtimes = {}\n" )
|
||||
for i=1,table.getn(ordering) do
|
||||
local thisfunc = ordering[i]
|
||||
local record = self.rawstats[thisfunc];
|
||||
outfile:write( "children[" .. i .. "] = { " )
|
||||
for k,v in pairs(record.children) do
|
||||
if functonum[k] then -- non-recorded functions will be ignored now
|
||||
outfile:write( record.children_time[k] .. ", " )
|
||||
end
|
||||
end
|
||||
outfile:write( "}\n" )
|
||||
end
|
||||
outfile:write( "\n\n-- That is all.\n\n" )
|
||||
outfile:flush()
|
||||
end
|
||||
|
||||
-- Internal function to calculate a pretty name for the profile output
|
||||
function _profiler._pretty_name(self,func)
|
||||
|
||||
-- Only the data collected during the actual
|
||||
-- run seems to be correct.... why?
|
||||
local info = self.rawstats[ func ].func_info
|
||||
-- local info = debug.getinfo( func )
|
||||
|
||||
local name = ""
|
||||
if info.what == "Lua" then
|
||||
name = "L:"
|
||||
end
|
||||
if info.what == "C" then
|
||||
name = "C:"
|
||||
end
|
||||
if info.what == "main" then
|
||||
name = " :"
|
||||
end
|
||||
|
||||
if info.name == nil then
|
||||
name = name .. "<"..tostring(func) .. ">"
|
||||
else
|
||||
name = name .. info.name
|
||||
end
|
||||
|
||||
if info.source then
|
||||
name = name
|
||||
else
|
||||
if info.what == "C" then
|
||||
name = name .. "@?"
|
||||
else
|
||||
name = name .. "@<string>"
|
||||
end
|
||||
end
|
||||
name = name .. ":"
|
||||
if info.what == "C" then
|
||||
name = name .. "?"
|
||||
else
|
||||
name = name .. info.linedefined
|
||||
end
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This allows you to specify functions which you do
|
||||
-- not want profiled. Setting level to 1 keeps the
|
||||
-- function from being profiled. Setting level to 2
|
||||
-- keeps both the function and its children from
|
||||
-- being profiled.
|
||||
--
|
||||
-- BUG: 2 will probably act exactly like 1 in "time" mode.
|
||||
-- If anyone cares, let me (zorba) know and it can be fixed.
|
||||
--
|
||||
function _profiler.prevent(self, func, level)
|
||||
self.prevented_functions[func] = (level or 1)
|
||||
end
|
||||
|
||||
|
||||
_profiler.prevented_functions = {
|
||||
[_profiler.start] = 2,
|
||||
[_profiler.stop] = 2,
|
||||
[_profiler._internal_profile_by_time] = 2,
|
||||
[_profiler._internal_profile_by_call] = 2,
|
||||
[_profiler_hook_wrapper_by_time] = 2,
|
||||
[_profiler_hook_wrapper_by_call] = 2,
|
||||
[_profiler.prevent] = 2,
|
||||
[_profiler._get_func_rec] = 2,
|
||||
[_profiler.report] = 2,
|
||||
[_profiler.lua_report] = 2,
|
||||
[_profiler._pretty_name] = 2
|
||||
}
|
||||
@@ -0,0 +1,775 @@
|
||||
--
|
||||
-- project.lua
|
||||
-- Functions for working with the project data.
|
||||
-- Copyright (c) 2002 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.project = { }
|
||||
|
||||
|
||||
--
|
||||
-- Create a tree from a project's list of files, representing the filesystem hierarchy.
|
||||
--
|
||||
-- @param prj
|
||||
-- The project containing the files to map.
|
||||
-- @returns
|
||||
-- A new tree object containing a corresponding filesystem hierarchy. The root node
|
||||
-- contains a reference back to the original project: prj = tr.project.
|
||||
--
|
||||
|
||||
function premake.project.buildsourcetree(prj, allfiles)
|
||||
local tr = premake.tree.new(prj.name)
|
||||
tr.project = prj
|
||||
|
||||
local isvpath
|
||||
|
||||
local function onadd(node)
|
||||
node.isvpath = isvpath
|
||||
end
|
||||
|
||||
for fcfg in premake.project.eachfile(prj, allfiles) do
|
||||
isvpath = (fcfg.name ~= fcfg.vpath)
|
||||
local node = premake.tree.add(tr, fcfg.vpath, onadd)
|
||||
node.cfg = fcfg
|
||||
end
|
||||
|
||||
premake.tree.sort(tr)
|
||||
return tr
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns an iterator for a set of build configuration settings. If a platform is
|
||||
-- specified, settings specific to that platform and build configuration pair are
|
||||
-- returned.
|
||||
--
|
||||
|
||||
function premake.eachconfig(prj, platform)
|
||||
-- I probably have the project root config, rather than the actual project
|
||||
if prj.project then prj = prj.project end
|
||||
|
||||
local cfgs = prj.solution.configurations
|
||||
local i = 0
|
||||
|
||||
return function ()
|
||||
i = i + 1
|
||||
if i <= #cfgs then
|
||||
return premake.getconfig(prj, cfgs[i], platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Iterator for a project's files; returns a file configuration object.
|
||||
--
|
||||
|
||||
function premake.project.eachfile(prj, allfiles)
|
||||
-- project root config contains the file config list
|
||||
if not prj.project then prj = premake.getconfig(prj) end
|
||||
local i = 0
|
||||
local t = iif(allfiles, prj.allfiles, prj.files)
|
||||
local c = iif(allfiles, prj.__allfileconfigs, prj.__fileconfigs)
|
||||
return function ()
|
||||
i = i + 1
|
||||
if (i <= #t) then
|
||||
local fcfg = c[t[i]]
|
||||
fcfg.vpath = premake.project.getvpath(prj, fcfg.name)
|
||||
return fcfg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Apply XML escaping to a value.
|
||||
--
|
||||
|
||||
function premake.esc(value)
|
||||
if (type(value) == "table") then
|
||||
local result = { }
|
||||
for _,v in ipairs(value) do
|
||||
table.insert(result, premake.esc(v))
|
||||
end
|
||||
return result
|
||||
else
|
||||
value = value:gsub('&', "&")
|
||||
value = value:gsub('"', """)
|
||||
value = value:gsub("'", "'")
|
||||
value = value:gsub('<', "<")
|
||||
value = value:gsub('>', ">")
|
||||
value = value:gsub('\r', "
")
|
||||
value = value:gsub('\n', "
")
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Given a map of supported platform identifiers, filters the solution's list
|
||||
-- of platforms to match. A map takes the form of a table like:
|
||||
--
|
||||
-- { x32 = "Win32", x64 = "x64" }
|
||||
--
|
||||
-- Only platforms that are listed in both the solution and the map will be
|
||||
-- included in the results. An optional default platform may also be specified;
|
||||
-- if the result set would otherwise be empty this platform will be used.
|
||||
--
|
||||
|
||||
function premake.filterplatforms(sln, map, default)
|
||||
local result = { }
|
||||
local keys = { }
|
||||
if sln.platforms then
|
||||
for _, p in ipairs(sln.platforms) do
|
||||
if map[p] and not table.contains(keys, map[p]) then
|
||||
table.insert(result, p)
|
||||
table.insert(keys, map[p])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #result == 0 and default then
|
||||
table.insert(result, default)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Locate a project by name; case insensitive.
|
||||
--
|
||||
|
||||
function premake.findproject(name)
|
||||
for sln in premake.solution.each() do
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if (prj.name == name) then
|
||||
return prj
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Locate a file in a project with a given extension; used to locate "special"
|
||||
-- items such as Windows .def files.
|
||||
--
|
||||
|
||||
function premake.findfile(prj, extension)
|
||||
for _, fname in ipairs(prj.files) do
|
||||
if fname:endswith(extension) then return fname end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve a configuration for a given project/configuration pairing.
|
||||
-- @param prj
|
||||
-- The project to query.
|
||||
-- @param cfgname
|
||||
-- The target build configuration; only settings applicable to this configuration
|
||||
-- will be returned. May be nil to retrieve project-wide settings.
|
||||
-- @param pltname
|
||||
-- The target platform; only settings applicable to this platform will be returned.
|
||||
-- May be nil to retrieve platform-independent settings.
|
||||
-- @returns
|
||||
-- A configuration object containing all the settings for the given platform/build
|
||||
-- configuration pair.
|
||||
--
|
||||
|
||||
function premake.getconfig(prj, cfgname, pltname)
|
||||
-- might have the root configuration, rather than the actual project
|
||||
prj = prj.project or prj
|
||||
|
||||
-- if platform is not included in the solution, use general settings instead
|
||||
if pltname == "Native" or not table.contains(prj.solution.platforms or {}, pltname) then
|
||||
pltname = nil
|
||||
end
|
||||
|
||||
local key = (cfgname or "")
|
||||
if pltname then key = key .. pltname end
|
||||
return prj.__configs[key]
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Build a name from a build configuration/platform pair. The short name
|
||||
-- is good for makefiles or anywhere a user will have to type it in. The
|
||||
-- long name is more readable.
|
||||
--
|
||||
|
||||
function premake.getconfigname(cfgname, platform, useshortname)
|
||||
if cfgname then
|
||||
local name = cfgname
|
||||
if platform and platform ~= "Native" then
|
||||
if useshortname then
|
||||
name = name .. premake.platforms[platform].cfgsuffix
|
||||
else
|
||||
name = name .. "|" .. platform
|
||||
end
|
||||
end
|
||||
return iif(useshortname, name:lower(), name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns a list of sibling projects on which the specified project depends.
|
||||
-- This is used to list dependencies within a solution or workspace. Must
|
||||
-- consider all configurations because Visual Studio does not support per-config
|
||||
-- project dependencies.
|
||||
--
|
||||
-- @param prj
|
||||
-- The project to query.
|
||||
-- @returns
|
||||
-- A list of dependent projects, as an array of objects.
|
||||
--
|
||||
|
||||
function premake.getdependencies(prj)
|
||||
-- make sure I've got the project and not root config
|
||||
prj = prj.project or prj
|
||||
|
||||
local results = { }
|
||||
for _, cfg in pairs(prj.__configs) do
|
||||
for _, link in ipairs(cfg.links) do
|
||||
local dep = premake.findproject(link)
|
||||
if dep and not table.contains(results, dep) then
|
||||
table.insert(results, dep)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Uses a pattern to format the basename of a file (i.e. without path).
|
||||
--
|
||||
-- @param prjname
|
||||
-- A project name (string) to use.
|
||||
-- @param pattern
|
||||
-- A naming pattern. The sequence "%%" will be replaced by the
|
||||
-- project name.
|
||||
-- @returns
|
||||
-- A filename (basename only) matching the specified pattern, without
|
||||
-- path components.
|
||||
--
|
||||
|
||||
function premake.project.getbasename(prjname, pattern)
|
||||
return pattern:gsub("%%%%", prjname)
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Uses information from a project (or solution) to format a filename.
|
||||
--
|
||||
-- @param prj
|
||||
-- A project or solution object with the file naming information.
|
||||
-- @param pattern
|
||||
-- A naming pattern. The sequence "%%" will be replaced by the
|
||||
-- project name.
|
||||
-- @returns
|
||||
-- A filename matching the specified pattern, with a relative path
|
||||
-- from the current directory to the project location.
|
||||
--
|
||||
|
||||
function premake.project.getfilename(prj, pattern)
|
||||
local fname = premake.project.getbasename(prj.name, pattern)
|
||||
fname = path.join(prj.location, fname)
|
||||
return path.getrelative(os.getcwd(), fname)
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns a list of link targets. Kind may be one of:
|
||||
-- siblings - linkable sibling projects
|
||||
-- system - system (non-sibling) libraries
|
||||
-- dependencies - all sibling dependencies, including non-linkable
|
||||
-- all - return everything
|
||||
--
|
||||
-- Part may be one of:
|
||||
-- name - the decorated library name with no directory
|
||||
-- basename - the undecorated library name
|
||||
-- directory - just the directory, no name
|
||||
-- fullpath - full path with decorated name
|
||||
-- object - return the project object of the dependency
|
||||
--
|
||||
|
||||
function premake.getlinks(cfg, kind, part)
|
||||
-- if I'm building a list of link directories, include libdirs
|
||||
local result = iif (part == "directory" and kind == "all", cfg.libdirs, {})
|
||||
|
||||
-- am I getting links for a configuration or a project?
|
||||
local cfgname = iif(cfg.name == cfg.project.name, "", cfg.name)
|
||||
|
||||
-- how should files be named?
|
||||
local pathstyle = premake.getpathstyle(cfg)
|
||||
local namestyle = premake.getnamestyle(cfg)
|
||||
|
||||
local function canlink(source, target)
|
||||
if (target.kind ~= "SharedLib" and target.kind ~= "StaticLib") then
|
||||
return false
|
||||
end
|
||||
if premake.iscppproject(source) then
|
||||
return premake.iscppproject(target)
|
||||
elseif premake.isdotnetproject(source) then
|
||||
return premake.isdotnetproject(target)
|
||||
elseif premake.isswiftproject(source) then
|
||||
return premake.isswiftproject(source) or premake.iscppproject(source)
|
||||
end
|
||||
end
|
||||
|
||||
for _, link in ipairs(cfg.links) do
|
||||
local item
|
||||
|
||||
-- is this a sibling project?
|
||||
local prj = premake.findproject(link)
|
||||
if prj and kind ~= "system" then
|
||||
|
||||
local prjcfg = premake.getconfig(prj, cfgname, cfg.platform)
|
||||
if kind == "dependencies" or canlink(cfg, prjcfg) then
|
||||
if (part == "directory") then
|
||||
item = path.rebase(prjcfg.linktarget.directory, prjcfg.location, cfg.location)
|
||||
elseif (part == "basename") then
|
||||
item = prjcfg.linktarget.basename
|
||||
elseif (part == "fullpath") then
|
||||
item = path.rebase(prjcfg.linktarget.fullpath, prjcfg.location, cfg.location)
|
||||
elseif (part == "object") then
|
||||
item = prjcfg
|
||||
end
|
||||
end
|
||||
|
||||
elseif not prj and (kind == "system" or kind == "all") then
|
||||
|
||||
if (part == "directory") then
|
||||
item = path.getdirectory(link)
|
||||
elseif (part == "fullpath") then
|
||||
item = link
|
||||
if namestyle == "windows" then
|
||||
if premake.iscppproject(cfg) then
|
||||
item = item .. ".lib"
|
||||
elseif premake.isdotnetproject(cfg) then
|
||||
item = item .. ".dll"
|
||||
end
|
||||
end
|
||||
elseif part == "name" then
|
||||
item = path.getname(link)
|
||||
elseif part == "basename" then
|
||||
item = path.getbasename(link)
|
||||
else
|
||||
item = link
|
||||
end
|
||||
|
||||
if item:find("/", nil, true) then
|
||||
item = path.getrelative(cfg.project.location, item)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if item then
|
||||
if pathstyle == "windows" and part ~= "object" then
|
||||
item = path.translate(item, "\\")
|
||||
end
|
||||
if not table.contains(result, item) then
|
||||
table.insert(result, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Gets the name style for a configuration, indicating what kind of prefix,
|
||||
-- extensions, etc. should be used in target file names.
|
||||
--
|
||||
-- @param cfg
|
||||
-- The configuration to check.
|
||||
-- @returns
|
||||
-- The target naming style, one of "windows", "posix", or "PS3".
|
||||
--
|
||||
|
||||
function premake.getnamestyle(cfg)
|
||||
return premake.platforms[cfg.platform].namestyle or premake.gettool(cfg).namestyle or "posix"
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Gets the path style for a configuration, indicating what kind of path separator
|
||||
-- should be used in target file names.
|
||||
--
|
||||
-- @param cfg
|
||||
-- The configuration to check.
|
||||
-- @returns
|
||||
-- The target path style, one of "windows" or "posix".
|
||||
--
|
||||
|
||||
function premake.getpathstyle(cfg)
|
||||
if premake.action.current().os == "windows" then
|
||||
return "windows"
|
||||
else
|
||||
return "posix"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Assembles a target for a particular tool/system/configuration.
|
||||
--
|
||||
-- @param cfg
|
||||
-- The configuration to be targeted.
|
||||
-- @param direction
|
||||
-- One of 'build' for the build target, or 'link' for the linking target.
|
||||
-- @param pathstyle
|
||||
-- The path format, one of "windows" or "posix". This comes from the current
|
||||
-- action: Visual Studio uses "windows", GMake uses "posix", etc.
|
||||
-- @param namestyle
|
||||
-- The file naming style, one of "windows" or "posix". This comes from the
|
||||
-- current tool: GCC uses "posix", MSC uses "windows", etc.
|
||||
-- @param system
|
||||
-- The target operating system, which can modify the naming style. For example,
|
||||
-- shared libraries on Mac OS X use a ".dylib" extension.
|
||||
-- @returns
|
||||
-- An object with these fields:
|
||||
-- basename - the target with no directory or file extension
|
||||
-- name - the target name and extension, with no directory
|
||||
-- directory - relative path to the target, with no file name
|
||||
-- prefix - the file name prefix
|
||||
-- suffix - the file name suffix
|
||||
-- fullpath - directory, name, and extension
|
||||
-- bundlepath - the relative path and file name of the bundle
|
||||
--
|
||||
|
||||
function premake.gettarget(cfg, direction, pathstyle, namestyle, system)
|
||||
if system == "bsd" then
|
||||
system = "linux"
|
||||
end
|
||||
|
||||
-- Fix things up based on the current system
|
||||
local kind = cfg.kind
|
||||
if premake.iscppproject(cfg) or premake.isvalaproject(cfg) then
|
||||
-- On Windows, shared libraries link against a static import library
|
||||
if (namestyle == "windows" or system == "windows")
|
||||
and kind == "SharedLib" and direction == "link"
|
||||
and not cfg.flags.NoImportLib
|
||||
then
|
||||
kind = "StaticLib"
|
||||
end
|
||||
|
||||
-- Posix name conventions only apply to static libs on windows (by user request)
|
||||
if namestyle == "posix" and system == "windows" and kind ~= "StaticLib" then
|
||||
namestyle = "windows"
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialize the target components
|
||||
local field = "build"
|
||||
if direction == "link" and cfg.kind == "SharedLib" then
|
||||
field = "implib"
|
||||
end
|
||||
|
||||
local name = cfg[field.."name"] or cfg.targetname or cfg.project.name
|
||||
local dir = cfg[field.."dir"] or cfg.targetdir or path.getrelative(cfg.location, cfg.basedir)
|
||||
local subdir = cfg[field.."subdir"] or cfg.targetsubdir or "."
|
||||
local prefix = ""
|
||||
local suffix = ""
|
||||
local ext = ""
|
||||
local bundlepath, bundlename
|
||||
|
||||
-- targetpath/targetsubdir/bundlepath/prefix..name..suffix..ext
|
||||
|
||||
dir = path.join(dir, subdir)
|
||||
|
||||
|
||||
if namestyle == "windows" then
|
||||
if kind == "ConsoleApp" or kind == "WindowedApp" then
|
||||
ext = ".exe"
|
||||
elseif kind == "SharedLib" then
|
||||
ext = ".dll"
|
||||
elseif kind == "StaticLib" then
|
||||
ext = ".lib"
|
||||
end
|
||||
elseif namestyle == "posix" then
|
||||
if kind == "WindowedApp" and system == "macosx" and not cfg.options.SkipBundling then
|
||||
bundlename = name .. ".app"
|
||||
bundlepath = path.join(dir, bundlename)
|
||||
dir = path.join(bundlepath, "Contents/MacOS")
|
||||
elseif (kind == "ConsoleApp" or kind == "WindowedApp") and system == "os2" then
|
||||
ext = ".exe"
|
||||
elseif kind == "SharedLib" then
|
||||
prefix = "lib"
|
||||
ext = iif(system == "macosx", ".dylib", ".so")
|
||||
elseif kind == "StaticLib" then
|
||||
prefix = "lib"
|
||||
ext = ".a"
|
||||
end
|
||||
elseif namestyle == "PS3" then
|
||||
if kind == "ConsoleApp" or kind == "WindowedApp" then
|
||||
ext = ".elf"
|
||||
elseif kind == "StaticLib" then
|
||||
prefix = "lib"
|
||||
ext = ".a"
|
||||
end
|
||||
elseif namestyle == "Orbis" then
|
||||
if kind == "ConsoleApp" or kind == "WindowedApp" then
|
||||
ext = ".elf"
|
||||
elseif kind == "StaticLib" then
|
||||
prefix = "lib"
|
||||
ext = ".a"
|
||||
elseif kind == "SharedLib" then
|
||||
ext = ".prx"
|
||||
end
|
||||
elseif namestyle == "TegraAndroid" then
|
||||
-- the .so->.apk happens later for Application types
|
||||
if kind == "ConsoleApp" or kind == "WindowedApp" or kind == "SharedLib" then
|
||||
prefix = "lib"
|
||||
ext = ".so"
|
||||
elseif kind == "StaticLib" then
|
||||
prefix = "lib"
|
||||
ext = ".a"
|
||||
end
|
||||
elseif namestyle == "NX" then
|
||||
-- NOTE: it would be cleaner to just output $(TargetExt) for all cases, but
|
||||
-- there is logic elsewhere that assumes a '.' to be present in target name
|
||||
-- such that it can reverse engineer the extension set here.
|
||||
if kind == "ConsoleApp" or kind == "WindowedApp" then
|
||||
ext = ".nspd_root"
|
||||
elseif kind == "StaticLib" then
|
||||
ext = ".a"
|
||||
elseif kind == "SharedLib" then
|
||||
ext = ".nro"
|
||||
end
|
||||
elseif namestyle == "Emscripten" then
|
||||
if kind == "ConsoleApp" or kind == "WindowedApp" then
|
||||
ext = ".html"
|
||||
elseif kind == "StaticLib" then
|
||||
ext = ".bc"
|
||||
elseif kind == "SharedLib" then
|
||||
ext = ".js"
|
||||
end
|
||||
end
|
||||
|
||||
prefix = cfg[field.."prefix"] or cfg.targetprefix or prefix
|
||||
suffix = cfg[field.."suffix"] or cfg.targetsuffix or suffix
|
||||
ext = cfg[field.."extension"] or cfg.targetextension or ext
|
||||
|
||||
-- build the results object
|
||||
local result = { }
|
||||
result.basename = name .. suffix
|
||||
result.name = prefix .. name .. suffix .. ext
|
||||
result.directory = dir
|
||||
result.subdirectory = subdir
|
||||
result.prefix = prefix
|
||||
result.suffix = suffix
|
||||
result.fullpath = path.join(result.directory, result.name)
|
||||
result.bundlepath = bundlepath or result.fullpath
|
||||
|
||||
if pathstyle == "windows" then
|
||||
result.directory = path.translate(result.directory, "\\")
|
||||
result.subdirectory = path.translate(result.subdirectory, "\\")
|
||||
result.fullpath = path.translate(result.fullpath, "\\")
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Return the appropriate tool interface, based on the target language and
|
||||
-- any relevant command-line options.
|
||||
--
|
||||
|
||||
function premake.gettool(prj)
|
||||
if premake.iscppproject(prj) then
|
||||
if _OPTIONS.cc then
|
||||
return premake[_OPTIONS.cc]
|
||||
end
|
||||
local action = premake.action.current()
|
||||
if action.valid_tools then
|
||||
return premake[action.valid_tools.cc[1]]
|
||||
end
|
||||
return premake.gcc
|
||||
elseif premake.isdotnetproject(prj) then
|
||||
return premake.dotnet
|
||||
elseif premake.isswiftproject(prj) then
|
||||
return premake.swift
|
||||
else
|
||||
return premake.valac
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Given a source file path, return a corresponding virtual path based on
|
||||
-- the vpath entries in the project. If no matching vpath entry is found,
|
||||
-- the original path is returned.
|
||||
--
|
||||
|
||||
function premake.project.getvpath(prj, abspath)
|
||||
-- If there is no match, the result is the original filename
|
||||
local vpath = abspath
|
||||
|
||||
-- The file's name must be maintained in the resulting path; use these
|
||||
-- to make sure I don't cut off too much
|
||||
|
||||
local fname = path.getname(abspath)
|
||||
local max = abspath:len() - fname:len()
|
||||
|
||||
-- First check for an exact match from the inverse vpaths
|
||||
if prj.inversevpaths and prj.inversevpaths[abspath] then
|
||||
return path.join(prj.inversevpaths[abspath], fname)
|
||||
end
|
||||
|
||||
-- Look for matching patterns
|
||||
local matches = {}
|
||||
for replacement, patterns in pairs(prj.vpaths or {}) do
|
||||
for _, pattern in ipairs(patterns) do
|
||||
local i = abspath:find(path.wildcards(pattern))
|
||||
if i == 1 then
|
||||
|
||||
-- Trim out the part of the name that matched the pattern; what's
|
||||
-- left is the part that gets appended to the replacement to make
|
||||
-- the virtual path. So a pattern like "src/**.h" matching the
|
||||
-- file src/include/hello.h, I want to trim out the src/ part,
|
||||
-- leaving include/hello.h.
|
||||
|
||||
-- Find out where the wildcard appears in the match. If there is
|
||||
-- no wildcard, the match includes the entire pattern
|
||||
|
||||
i = pattern:find("*", 1, true) or (pattern:len() + 1)
|
||||
|
||||
-- Trim, taking care to keep the actual file name intact.
|
||||
|
||||
local leaf
|
||||
if i < max then
|
||||
leaf = abspath:sub(i)
|
||||
else
|
||||
leaf = fname
|
||||
end
|
||||
|
||||
if leaf:startswith("/") then
|
||||
leaf = leaf:sub(2)
|
||||
end
|
||||
|
||||
-- check for (and remove) stars in the replacement pattern.
|
||||
-- If there are none, then trim all path info from the leaf
|
||||
-- and use just the filename in the replacement (stars should
|
||||
-- really only appear at the end; I'm cheating here)
|
||||
|
||||
local stem = ""
|
||||
if replacement:len() > 0 then
|
||||
stem, stars = replacement:gsub("%*", "")
|
||||
if stars == 0 then
|
||||
leaf = path.getname(leaf)
|
||||
end
|
||||
else
|
||||
leaf = path.getname(leaf)
|
||||
end
|
||||
|
||||
table.insert(matches, path.join(stem, leaf))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #matches > 0 then
|
||||
-- for the sake of determinism, return the first alphabetically
|
||||
table.sort(matches)
|
||||
vpath = matches[1]
|
||||
end
|
||||
|
||||
return path.trimdots(vpath)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the solution contains at least one C/C++ project.
|
||||
--
|
||||
|
||||
function premake.hascppproject(sln)
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if premake.iscppproject(prj) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the solution contains at least one .NET project.
|
||||
--
|
||||
|
||||
function premake.hasdotnetproject(sln)
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
if premake.isdotnetproject(prj) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the project use the C language.
|
||||
--
|
||||
|
||||
function premake.project.iscproject(prj)
|
||||
local language = prj.language or prj.solution.language
|
||||
return language == "C"
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the project uses a C/C++ language.
|
||||
--
|
||||
|
||||
function premake.iscppproject(prj)
|
||||
local language = prj.language or prj.solution.language
|
||||
return (language == "C" or language == "C++")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the project uses a .NET language.
|
||||
--
|
||||
|
||||
function premake.isdotnetproject(prj)
|
||||
local language = prj.language or prj.solution.language
|
||||
return (language == "C#")
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns true if the project uses the Vala language.
|
||||
--
|
||||
|
||||
function premake.isvalaproject(prj)
|
||||
local language = prj.language or prj.solution.language
|
||||
return (language == "Vala")
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns true if the project uses the Swift language.
|
||||
--
|
||||
|
||||
function premake.isswiftproject(prj)
|
||||
local language = prj.language or prj.solution.language
|
||||
return (language == "Swift")
|
||||
end
|
||||
@@ -0,0 +1,77 @@
|
||||
Set_mt = {}
|
||||
|
||||
function Set(t)
|
||||
local set = {}
|
||||
for k, l in ipairs(t) do
|
||||
set[l] = true
|
||||
end
|
||||
setmetatable(set, Set_mt)
|
||||
return set
|
||||
end
|
||||
|
||||
function Set_mt.union(a, b)
|
||||
local res = Set{}
|
||||
for k in pairs(a) do res[k] = true end
|
||||
for k in pairs(b) do res[k] = true end
|
||||
return res
|
||||
end
|
||||
|
||||
function Set_mt.intersection(a, b)
|
||||
local res = Set{}
|
||||
for k in pairs(a) do
|
||||
res[k] = b[k]
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local function get_cache(a)
|
||||
if not rawget(a, "__cache") then
|
||||
rawset(a, "__cache", Set_mt.totable(a))
|
||||
end
|
||||
return rawget(a, "__cache")
|
||||
end
|
||||
|
||||
function Set_mt.len(a)
|
||||
return #get_cache(a)
|
||||
end
|
||||
|
||||
function Set_mt.implode(a, sep)
|
||||
return table.concat(get_cache(a), sep)
|
||||
end
|
||||
|
||||
function Set_mt.totable(a)
|
||||
local res = {}
|
||||
for k in pairs(a) do
|
||||
table.insert(res, k)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function Set_mt.difference(a, b)
|
||||
if getmetatable(b) ~= Set_mt then
|
||||
if type(b) ~= "table" then
|
||||
error(type(b).." is not a Set or table")
|
||||
end
|
||||
b=Set(b)
|
||||
end
|
||||
|
||||
local res = Set{}
|
||||
for k in pairs(a) do
|
||||
res[k] = not b[k] or nil
|
||||
end
|
||||
rawset(res, "__cache", nil)
|
||||
return res
|
||||
end
|
||||
|
||||
function Set_mt.__index(a, i)
|
||||
if type(i) == "number" then
|
||||
return get_cache(a)[i]
|
||||
end
|
||||
return Set_mt[i] or rawget(a, i)
|
||||
end
|
||||
|
||||
Set_mt.__add = Set_mt.union
|
||||
Set_mt.__mul = Set_mt.intersection
|
||||
Set_mt.__sub = Set_mt.difference
|
||||
Set_mt.__len = Set_mt.len
|
||||
Set_mt.__concat = Set_mt.implode
|
||||
@@ -0,0 +1,148 @@
|
||||
--
|
||||
-- solution.lua
|
||||
-- Work with the list of solutions loaded from the script.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.solution = { }
|
||||
|
||||
|
||||
-- The list of defined solutions (which contain projects, etc.)
|
||||
|
||||
premake.solution.list = { }
|
||||
|
||||
|
||||
--
|
||||
-- Create a new solution and add it to the session.
|
||||
--
|
||||
-- @param name
|
||||
-- The new solution's name.
|
||||
--
|
||||
|
||||
function premake.solution.new(name)
|
||||
local sln = { }
|
||||
|
||||
-- add to master list keyed by both name and index
|
||||
table.insert(premake.solution.list, sln)
|
||||
premake.solution.list[name] = sln
|
||||
|
||||
-- attach a type descriptor
|
||||
setmetatable(sln, { __type="solution" })
|
||||
|
||||
sln.name = name
|
||||
sln.basedir = os.getcwd()
|
||||
sln.projects = { }
|
||||
sln.blocks = { }
|
||||
sln.configurations = { }
|
||||
sln.groups = { }
|
||||
sln.importedprojects = { }
|
||||
return sln
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Iterate over the collection of solutions in a session.
|
||||
--
|
||||
-- @returns
|
||||
-- An iterator function.
|
||||
--
|
||||
|
||||
function premake.solution.each()
|
||||
local i = 0
|
||||
return function ()
|
||||
i = i + 1
|
||||
if i <= #premake.solution.list then
|
||||
return premake.solution.list[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Iterate over the projects of a solution.
|
||||
--
|
||||
-- @param sln
|
||||
-- The solution.
|
||||
-- @returns
|
||||
-- An iterator function.
|
||||
--
|
||||
|
||||
function premake.solution.eachproject(sln)
|
||||
local i = 0
|
||||
return function ()
|
||||
i = i + 1
|
||||
if (i <= #sln.projects) then
|
||||
return premake.solution.getproject(sln, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Iterate over the groups of a solution
|
||||
--
|
||||
-- @param sln
|
||||
-- The solution.
|
||||
-- @returns
|
||||
-- An iterator function.
|
||||
|
||||
function premake.solution.eachgroup(sln)
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
if(i <= #sln.groups) then
|
||||
return premake.solution.getgroup(sln, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve a solution by name or index.
|
||||
--
|
||||
-- @param key
|
||||
-- The solution key, either a string name or integer index.
|
||||
-- @returns
|
||||
-- The solution with the provided key.
|
||||
--
|
||||
|
||||
function premake.solution.get(key)
|
||||
return premake.solution.list[key]
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve the project at a particular index.
|
||||
--
|
||||
-- @param sln
|
||||
-- The solution.
|
||||
-- @param idx
|
||||
-- An index into the array of projects.
|
||||
-- @returns
|
||||
-- The project at the given index.
|
||||
--
|
||||
|
||||
function premake.solution.getproject(sln, idx)
|
||||
-- retrieve the root configuration of the project, with all of
|
||||
-- the global (not configuration specific) settings collapsed
|
||||
local prj = sln.projects[idx]
|
||||
local cfg = premake.getconfig(prj)
|
||||
|
||||
-- root configuration doesn't have a name; use the project's
|
||||
cfg.name = prj.name
|
||||
return cfg
|
||||
end
|
||||
|
||||
--
|
||||
-- Retrieve the group at a particular index
|
||||
--
|
||||
-- @param sln
|
||||
-- The solution.
|
||||
-- @param idx
|
||||
-- The index into the array of groups
|
||||
-- @returns
|
||||
-- The group at the given index
|
||||
|
||||
function premake.solution.getgroup(sln, idx)
|
||||
local grp = sln.groups[idx]
|
||||
return grp
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
--
|
||||
-- string.lua
|
||||
-- Additions to Lua's built-in string functions.
|
||||
-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Returns an array of strings, each of which is a substring of s
|
||||
-- formed by splitting on boundaries formed by `pattern`.
|
||||
--
|
||||
|
||||
function string.explode(s, pattern, plain)
|
||||
if (pattern == '') then return false end
|
||||
local pos = 0
|
||||
local arr = { }
|
||||
for st,sp in function() return s:find(pattern, pos, plain) end do
|
||||
table.insert(arr, s:sub(pos, st-1))
|
||||
pos = sp + 1
|
||||
end
|
||||
table.insert(arr, s:sub(pos))
|
||||
return arr
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Find the last instance of a pattern in a string.
|
||||
--
|
||||
|
||||
function string.findlast(s, pattern, plain)
|
||||
local curr = 0
|
||||
local term = nil
|
||||
repeat
|
||||
local next, nextterm = s:find(pattern, curr + 1, plain)
|
||||
if (next) then
|
||||
curr = next
|
||||
term = nextterm
|
||||
end
|
||||
until (not next)
|
||||
if (curr > 0) then
|
||||
return curr, term
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if `haystack` starts with the sequence `needle`.
|
||||
--
|
||||
|
||||
function string.startswith(haystack, needle)
|
||||
return (haystack:find(needle, 1, true) == 1)
|
||||
end
|
||||
|
||||
--
|
||||
-- remove leading and trailing whitespace from string.
|
||||
--
|
||||
|
||||
function string.trim(s)
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
@@ -0,0 +1,260 @@
|
||||
--
|
||||
-- table.lua
|
||||
-- Additions to Lua's built-in table functions.
|
||||
-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the table contains the specified value.
|
||||
--
|
||||
|
||||
function table.contains(t, value)
|
||||
for _, v in pairs(t) do
|
||||
if v == value then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function table.icontains(t, value)
|
||||
for _, v in ipairs(t) do
|
||||
if v == value then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make a complete copy of a table, including any child tables it contains.
|
||||
--
|
||||
|
||||
function table.deepcopy(object)
|
||||
-- keep track of already seen objects to avoid loops
|
||||
local seen = {}
|
||||
|
||||
local function copy(object)
|
||||
if type(object) ~= "table" then
|
||||
return object
|
||||
elseif seen[object] then
|
||||
return seen[object]
|
||||
end
|
||||
|
||||
local clone = {}
|
||||
seen[object] = clone
|
||||
for key, value in pairs(object) do
|
||||
clone[key] = copy(value)
|
||||
end
|
||||
|
||||
setmetatable(clone, getmetatable(object))
|
||||
return clone
|
||||
end
|
||||
|
||||
return copy(object)
|
||||
end
|
||||
|
||||
--
|
||||
-- Enumerates an array of objects and returns a new table containing
|
||||
-- only the value of one particular field.
|
||||
--
|
||||
|
||||
function table.extract(arr, fname)
|
||||
local result = { }
|
||||
for _,v in ipairs(arr) do
|
||||
table.insert(result, v[fname])
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Flattens a hierarchy of tables into a single array containing all
|
||||
-- of the values.
|
||||
--
|
||||
|
||||
function table.flatten(arr)
|
||||
local result = { }
|
||||
|
||||
local function flatten(arr)
|
||||
for _, v in ipairs(arr) do
|
||||
if type(v) == "table" then
|
||||
flatten(v)
|
||||
else
|
||||
table.insert(result, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
flatten(arr)
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Merges an array of items into a string.
|
||||
--
|
||||
|
||||
function table.implode(arr, before, after, between)
|
||||
local result = ""
|
||||
for _,v in ipairs(arr) do
|
||||
if (result ~= "" and between) then
|
||||
result = result .. between
|
||||
end
|
||||
result = result .. before .. v .. after
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Inserts a value of array of values into a table. If the value is
|
||||
-- itself a table, its contents are enumerated and added instead. So
|
||||
-- these inputs give these outputs:
|
||||
--
|
||||
-- "x" -> { "x" }
|
||||
-- { "x", "y" } -> { "x", "y" }
|
||||
-- { "x", { "y" }} -> { "x", "y" }
|
||||
--
|
||||
|
||||
function table.insertflat(tbl, values)
|
||||
if type(values) == "table" then
|
||||
for _, value in ipairs(values) do
|
||||
table.insertflat(tbl, value)
|
||||
end
|
||||
else
|
||||
table.insert(tbl, values)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Returns true if the table is empty, and contains no indexed or keyed values.
|
||||
--
|
||||
|
||||
function table.isempty(t)
|
||||
return next(t) == nil
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Adds the values from one array to the end of another and
|
||||
-- returns the result.
|
||||
--
|
||||
|
||||
function table.join(...)
|
||||
local arg={...}
|
||||
local result = { }
|
||||
for _,t in ipairs(arg) do
|
||||
if type(t) == "table" then
|
||||
for _,v in ipairs(t) do
|
||||
table.insert(result, v)
|
||||
end
|
||||
else
|
||||
table.insert(result, t)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Return a list of all keys used in a table.
|
||||
--
|
||||
|
||||
function table.keys(tbl)
|
||||
local keys = {}
|
||||
for k, _ in pairs(tbl) do
|
||||
table.insert(keys, k)
|
||||
end
|
||||
return keys
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Return an iterator over key/value pairs in a table, sorted by key.
|
||||
--
|
||||
|
||||
function table.sortedpairs(t)
|
||||
local keys = table.keys(t)
|
||||
local i = 0
|
||||
table.sort(keys)
|
||||
return function()
|
||||
i = i + 1
|
||||
if keys[i] == nil then
|
||||
return nil
|
||||
end
|
||||
return keys[i], t[keys[i]]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Adds the key-value associations from one table into another
|
||||
-- and returns the resulting merged table.
|
||||
--
|
||||
|
||||
function table.merge(...)
|
||||
local arg={...}
|
||||
local result = { }
|
||||
for _,t in ipairs(arg) do
|
||||
if type(t) == "table" then
|
||||
for k,v in pairs(t) do
|
||||
result[k] = v
|
||||
end
|
||||
else
|
||||
error("invalid value")
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Translates the values contained in array, using the specified
|
||||
-- translation table, and returns the results in a new array.
|
||||
--
|
||||
|
||||
function table.translate(arr, translation)
|
||||
local result = { }
|
||||
for _, value in ipairs(arr) do
|
||||
local tvalue
|
||||
if type(translation) == "function" then
|
||||
tvalue = translation(value)
|
||||
else
|
||||
tvalue = translation[value]
|
||||
end
|
||||
if (tvalue) then
|
||||
table.insert(result, tvalue)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- reverse table order
|
||||
--
|
||||
|
||||
function table.reverse(arr)
|
||||
for i=1, math.floor(#arr / 2) do
|
||||
arr[i], arr[#arr - i + 1] = arr[#arr - i + 1], arr[i]
|
||||
end
|
||||
return arr
|
||||
end
|
||||
|
||||
--
|
||||
-- reverse table order
|
||||
--
|
||||
|
||||
function table.arglist(arg, value)
|
||||
if #value > 0 then
|
||||
local args = {}
|
||||
for _, val in ipairs(value) do
|
||||
table.insert(args, string.format("%s %s", arg, val))
|
||||
end
|
||||
return table.concat(args, " ")
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,231 @@
|
||||
--
|
||||
-- tree.lua
|
||||
-- Functions for working with the source code tree.
|
||||
-- Copyright (c) 2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.tree = { }
|
||||
local tree = premake.tree
|
||||
|
||||
|
||||
--
|
||||
-- Create a new tree.
|
||||
--
|
||||
-- @param n
|
||||
-- The name of the tree, applied to the root node (optional).
|
||||
--
|
||||
|
||||
function premake.tree.new(n)
|
||||
local t = {
|
||||
name = n,
|
||||
children = { }
|
||||
}
|
||||
return t
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Add a new node to the tree, or returns the current node if it already exists.
|
||||
--
|
||||
-- @param tr
|
||||
-- The tree to contain the new node.
|
||||
-- @param p
|
||||
-- The path of the new node.
|
||||
-- @param onaddfunc
|
||||
-- A function to call when a new node is added to the tree. Receives the
|
||||
-- new node as an argument.
|
||||
-- @returns
|
||||
-- The new tree node.
|
||||
--
|
||||
|
||||
function premake.tree.add(tr, p, onaddfunc)
|
||||
-- Special case "." refers to the current node
|
||||
if p == "." then
|
||||
return tr
|
||||
end
|
||||
|
||||
if p == "/" then
|
||||
return tr
|
||||
end
|
||||
|
||||
-- Look for the immediate parent for this new node, creating it if necessary.
|
||||
-- Recurses to create as much of the tree as necessary.
|
||||
local parentnode = tree.add(tr, path.getdirectory(p), onaddfunc)
|
||||
|
||||
-- Another special case, ".." refers to the parent node and doesn't create anything
|
||||
local childname = path.getname(p)
|
||||
if childname == ".." then
|
||||
return parentnode
|
||||
end
|
||||
|
||||
-- Create the child if necessary. If two children with the same name appear
|
||||
-- at the same level, make sure they have the same path to prevent conflicts
|
||||
-- i.e. ../Common and ../../Common can both appear at the top of the tree
|
||||
-- yet they have different paths (Bug #3016050)
|
||||
local childnode = parentnode.children[childname]
|
||||
if not childnode or childnode.path ~= p then
|
||||
childnode = tree.insert(parentnode, tree.new(childname))
|
||||
childnode.path = p
|
||||
if onaddfunc then
|
||||
onaddfunc(childnode)
|
||||
end
|
||||
end
|
||||
|
||||
return childnode
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Insert one tree into another.
|
||||
--
|
||||
-- @param parent
|
||||
-- The parent tree, to contain the child.
|
||||
-- @param child
|
||||
-- The child tree, to be inserted.
|
||||
--
|
||||
|
||||
function premake.tree.insert(parent, child)
|
||||
table.insert(parent.children, child)
|
||||
if child.name then
|
||||
parent.children[child.name] = child
|
||||
end
|
||||
child.parent = parent
|
||||
return child
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Gets the node's relative path from it's parent. If the parent does not have
|
||||
-- a path set (it is the root or other container node) returns the full node path.
|
||||
--
|
||||
-- @param node
|
||||
-- The node to query.
|
||||
--
|
||||
|
||||
function premake.tree.getlocalpath(node)
|
||||
if node.parent.path then
|
||||
return node.name
|
||||
elseif node.cfg then
|
||||
return node.cfg.name
|
||||
else
|
||||
return node.path
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Remove a node from a tree.
|
||||
--
|
||||
-- @param node
|
||||
-- The node to remove.
|
||||
--
|
||||
|
||||
function premake.tree.remove(node)
|
||||
local children = node.parent.children
|
||||
for i = 1, #children do
|
||||
if children[i] == node then
|
||||
table.remove(children, i)
|
||||
end
|
||||
end
|
||||
node.children = {}
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Sort the nodes of a tree in-place.
|
||||
--
|
||||
-- @param tr
|
||||
-- The tree to sort.
|
||||
--
|
||||
|
||||
function premake.tree.sort(tr)
|
||||
tree.traverse(tr, {
|
||||
onnode = function(node)
|
||||
table.sort(node.children, function(a,b)
|
||||
return a.name < b.name
|
||||
end)
|
||||
end
|
||||
}, true)
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Traverse a tree.
|
||||
--
|
||||
-- @param t
|
||||
-- The tree to traverse.
|
||||
-- @param fn
|
||||
-- A collection of callback functions, which may contain any or all of the
|
||||
-- following entries. Entries are called in this order.
|
||||
--
|
||||
-- onnode - called on each node encountered
|
||||
-- onbranchenter - called on branches, before processing children
|
||||
-- onbranch - called only on branch nodes
|
||||
-- onleaf - called only on leaf nodes
|
||||
-- onbranchexit - called on branches, after processing children
|
||||
--
|
||||
-- Callbacks receive two arguments: the node being processed, and the
|
||||
-- current traversal depth.
|
||||
--
|
||||
-- @param includeroot
|
||||
-- True to include the root node in the traversal, otherwise it will be skipped.
|
||||
-- @param initialdepth
|
||||
-- An optional starting value for the traversal depth; defaults to zero.
|
||||
--
|
||||
|
||||
function premake.tree.traverse(t, fn, includeroot, initialdepth)
|
||||
|
||||
-- forward declare my handlers, which call each other
|
||||
local donode, dochildren
|
||||
|
||||
-- process an individual node
|
||||
donode = function(node, fn, depth)
|
||||
if node.isremoved then
|
||||
return
|
||||
end
|
||||
|
||||
if fn.onnode then
|
||||
fn.onnode(node, depth)
|
||||
end
|
||||
|
||||
if #node.children > 0 then
|
||||
if fn.onbranchenter then
|
||||
fn.onbranchenter(node, depth)
|
||||
end
|
||||
if fn.onbranch then
|
||||
fn.onbranch(node, depth)
|
||||
end
|
||||
dochildren(node, fn, depth + 1)
|
||||
if fn.onbranchexit then
|
||||
fn.onbranchexit(node, depth)
|
||||
end
|
||||
else
|
||||
if fn.onleaf then
|
||||
fn.onleaf(node, depth)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- this goofy iterator allows nodes to be removed during the traversal
|
||||
dochildren = function(parent, fn, depth)
|
||||
local i = 1
|
||||
while i <= #parent.children do
|
||||
local node = parent.children[i]
|
||||
donode(node, fn, depth)
|
||||
if node == parent.children[i] then
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- set a default initial traversal depth, if one wasn't set
|
||||
if not initialdepth then
|
||||
initialdepth = 0
|
||||
end
|
||||
|
||||
if includeroot then
|
||||
donode(t, fn, initialdepth)
|
||||
else
|
||||
dochildren(t, fn, initialdepth)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,91 @@
|
||||
--
|
||||
-- validate.lua
|
||||
-- Tests to validate the run-time environment before starting the action.
|
||||
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Performs a sanity check of all of the solutions and projects
|
||||
-- in the session to be sure they meet some minimum requirements.
|
||||
--
|
||||
|
||||
function premake.checkprojects()
|
||||
local action = premake.action.current()
|
||||
|
||||
for sln in premake.solution.each() do
|
||||
|
||||
-- every solution must have at least one project
|
||||
if (#sln.projects == 0) then
|
||||
return nil, "solution '" .. sln.name .. "' needs at least one project"
|
||||
end
|
||||
|
||||
-- every solution must provide a list of configurations
|
||||
if (#sln.configurations == 0) then
|
||||
return nil, "solution '" .. sln.name .. "' needs configurations"
|
||||
end
|
||||
|
||||
for prj in premake.solution.eachproject(sln) do
|
||||
|
||||
-- every project must have a language
|
||||
if (not prj.language) then
|
||||
return nil, "project '" ..prj.name .. "' needs a language"
|
||||
end
|
||||
|
||||
-- and the action must support it
|
||||
if (action.valid_languages) then
|
||||
if (not table.contains(action.valid_languages, prj.language)) then
|
||||
return nil, "the " .. action.shortname .. " action does not support " .. prj.language .. " projects"
|
||||
end
|
||||
end
|
||||
|
||||
for cfg in premake.eachconfig(prj) do
|
||||
|
||||
-- every config must have a kind
|
||||
if (not cfg.kind) then
|
||||
return nil, "project '" ..prj.name .. "' needs a kind in configuration '" .. cfg.name .. "'"
|
||||
end
|
||||
|
||||
-- and the action must support it
|
||||
if (action.valid_kinds) then
|
||||
if (not table.contains(action.valid_kinds, cfg.kind)) then
|
||||
return nil, "the " .. action.shortname .. " action does not support " .. cfg.kind .. " projects"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- some actions have custom validation logic
|
||||
if action.oncheckproject then
|
||||
action.oncheckproject(prj)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Check the specified tools (/cc, /dotnet, etc.) against the current action
|
||||
-- to make sure they are compatible and supported.
|
||||
--
|
||||
|
||||
function premake.checktools()
|
||||
local action = premake.action.current()
|
||||
if (not action.valid_tools) then
|
||||
return true
|
||||
end
|
||||
|
||||
for tool, values in pairs(action.valid_tools) do
|
||||
if (_OPTIONS[tool]) then
|
||||
if (not table.contains(values, _OPTIONS[tool])) then
|
||||
return nil, "the " .. action.shortname .. " action does not support /" .. tool .. "=" .. _OPTIONS[tool] .. " (yet)"
|
||||
end
|
||||
else
|
||||
_OPTIONS[tool] = values[1]
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
# Makefile for installing Lua
|
||||
# See doc/readme.html for installation and customization instructions.
|
||||
|
||||
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
|
||||
|
||||
# Your platform. See PLATS for possible values.
|
||||
PLAT= none
|
||||
|
||||
# Where to install. The installation starts in the src and doc directories,
|
||||
# so take care if INSTALL_TOP is not an absolute path. See the local target.
|
||||
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
|
||||
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
|
||||
INSTALL_TOP= /usr/local
|
||||
INSTALL_BIN= $(INSTALL_TOP)/bin
|
||||
INSTALL_INC= $(INSTALL_TOP)/include
|
||||
INSTALL_LIB= $(INSTALL_TOP)/lib
|
||||
INSTALL_MAN= $(INSTALL_TOP)/man/man1
|
||||
INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V
|
||||
INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V
|
||||
|
||||
# How to install. If your install program does not support "-p", then
|
||||
# you may have to run ranlib on the installed liblua.a.
|
||||
INSTALL= install -p
|
||||
INSTALL_EXEC= $(INSTALL) -m 0755
|
||||
INSTALL_DATA= $(INSTALL) -m 0644
|
||||
#
|
||||
# If you don't have "install" you can use "cp" instead.
|
||||
# INSTALL= cp -p
|
||||
# INSTALL_EXEC= $(INSTALL)
|
||||
# INSTALL_DATA= $(INSTALL)
|
||||
|
||||
# Other utilities.
|
||||
MKDIR= mkdir -p
|
||||
RM= rm -f
|
||||
|
||||
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
|
||||
|
||||
# Convenience platforms targets.
|
||||
PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris
|
||||
|
||||
# What to install.
|
||||
TO_BIN= lua luac
|
||||
TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp
|
||||
TO_LIB= liblua.a
|
||||
TO_MAN= lua.1 luac.1
|
||||
|
||||
# Lua version and release.
|
||||
V= 5.3
|
||||
R= $V.0
|
||||
|
||||
# Targets start here.
|
||||
all: $(PLAT)
|
||||
|
||||
$(PLATS) clean:
|
||||
cd src && $(MAKE) $@
|
||||
|
||||
test: dummy
|
||||
src/lua -v
|
||||
|
||||
install: dummy
|
||||
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
|
||||
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
|
||||
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
|
||||
cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
|
||||
cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)
|
||||
|
||||
uninstall:
|
||||
cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN)
|
||||
cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC)
|
||||
cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB)
|
||||
cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN)
|
||||
|
||||
local:
|
||||
$(MAKE) install INSTALL_TOP=../install
|
||||
|
||||
none:
|
||||
@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
|
||||
@echo " $(PLATS)"
|
||||
@echo "See doc/readme.html for complete instructions."
|
||||
|
||||
# make may get confused with test/ and install/
|
||||
dummy:
|
||||
|
||||
# echo config parameters
|
||||
echo:
|
||||
@cd src && $(MAKE) -s echo
|
||||
@echo "PLAT= $(PLAT)"
|
||||
@echo "V= $V"
|
||||
@echo "R= $R"
|
||||
@echo "TO_BIN= $(TO_BIN)"
|
||||
@echo "TO_INC= $(TO_INC)"
|
||||
@echo "TO_LIB= $(TO_LIB)"
|
||||
@echo "TO_MAN= $(TO_MAN)"
|
||||
@echo "INSTALL_TOP= $(INSTALL_TOP)"
|
||||
@echo "INSTALL_BIN= $(INSTALL_BIN)"
|
||||
@echo "INSTALL_INC= $(INSTALL_INC)"
|
||||
@echo "INSTALL_LIB= $(INSTALL_LIB)"
|
||||
@echo "INSTALL_MAN= $(INSTALL_MAN)"
|
||||
@echo "INSTALL_LMOD= $(INSTALL_LMOD)"
|
||||
@echo "INSTALL_CMOD= $(INSTALL_CMOD)"
|
||||
@echo "INSTALL_EXEC= $(INSTALL_EXEC)"
|
||||
@echo "INSTALL_DATA= $(INSTALL_DATA)"
|
||||
|
||||
# echo pkg-config data
|
||||
pc:
|
||||
@echo "version=$R"
|
||||
@echo "prefix=$(INSTALL_TOP)"
|
||||
@echo "libdir=$(INSTALL_LIB)"
|
||||
@echo "includedir=$(INSTALL_INC)"
|
||||
|
||||
# list targets that do not create files (but not all makes understand .PHONY)
|
||||
.PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho
|
||||
|
||||
# (end of Makefile)
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
|
||||
This is Lua 5.3.0, released on 06 Jan 2015.
|
||||
|
||||
For installation instructions, license details, and
|
||||
further information about Lua, see doc/readme.html.
|
||||
|
||||
+619
@@ -0,0 +1,619 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Lua 5.3 Reference Manual - contents</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<STYLE TYPE="text/css">
|
||||
ul {
|
||||
list-style-type: none ;
|
||||
list-style-position: outside ;
|
||||
}
|
||||
</STYLE>
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
|
||||
<HR>
|
||||
<H1>
|
||||
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="" BORDER=0></A>
|
||||
Lua 5.3 Reference Manual
|
||||
</H1>
|
||||
|
||||
<P>
|
||||
The reference manual is the official definition of the Lua language.
|
||||
For a complete introduction to Lua programming, see the book
|
||||
<A HREF="http://www.lua.org/pil/">Programming in Lua</A>.
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html">start</A>
|
||||
·
|
||||
<A HREF="#contents">contents</A>
|
||||
·
|
||||
<A HREF="#index">index</A>
|
||||
<HR>
|
||||
<SMALL>
|
||||
Copyright © 2015 Lua.org, PUC-Rio.
|
||||
Freely available under the terms of the
|
||||
<A HREF="http://www.lua.org/license.html">Lua license</A>.
|
||||
</SMALL>
|
||||
|
||||
<H2><A NAME="contents">Contents</A></H2>
|
||||
<UL style="padding: 0">
|
||||
<LI><A HREF="manual.html">1 – Introduction</A>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#2">2 – Basic Concepts</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.1">2.1 – Values and Types</A>
|
||||
<LI><A HREF="manual.html#2.2">2.2 – Environments and the Global Environment</A>
|
||||
<LI><A HREF="manual.html#2.3">2.3 – Error Handling</A>
|
||||
<LI><A HREF="manual.html#2.4">2.4 – Metatables and Metamethods</A>
|
||||
<LI><A HREF="manual.html#2.5">2.5 – Garbage Collection</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.5.1">2.5.1 – Garbage-Collection Metamethods</A>
|
||||
<LI><A HREF="manual.html#2.5.2">2.5.2 – Weak Tables</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#2.6">2.6 – Coroutines</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#3">3 – The Language</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#3.1">3.1 – Lexical Conventions</A>
|
||||
<LI><A HREF="manual.html#3.2">3.2 – Variables</A>
|
||||
<LI><A HREF="manual.html#3.3">3.3 – Statements</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#3.3.1">3.3.1 – Blocks</A>
|
||||
<LI><A HREF="manual.html#3.3.2">3.3.2 – Chunks</A>
|
||||
<LI><A HREF="manual.html#3.3.3">3.3.3 – Assignment</A>
|
||||
<LI><A HREF="manual.html#3.3.4">3.3.4 – Control Structures</A>
|
||||
<LI><A HREF="manual.html#3.3.5">3.3.5 – For Statement</A>
|
||||
<LI><A HREF="manual.html#3.3.6">3.3.6 – Function Calls as Statements</A>
|
||||
<LI><A HREF="manual.html#3.3.7">3.3.7 – Local Declarations</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#3.4">3.4 – Expressions</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#3.4.1">3.4.1 – Arithmetic Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.2">3.4.2 – Bitwise Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.3">3.4.3 – Coercions and Conversions</A>
|
||||
<LI><A HREF="manual.html#3.4.4">3.4.4 – Relational Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.5">3.4.5 – Logical Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.6">3.4.6 – Concatenation</A>
|
||||
<LI><A HREF="manual.html#3.4.7">3.4.7 – The Length Operator</A>
|
||||
<LI><A HREF="manual.html#3.4.8">3.4.8 – Precedence</A>
|
||||
<LI><A HREF="manual.html#3.4.9">3.4.9 – Table Constructors</A>
|
||||
<LI><A HREF="manual.html#3.4.10">3.4.10 – Function Calls</A>
|
||||
<LI><A HREF="manual.html#3.4.11">3.4.11 – Function Definitions</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#3.5">3.5 – Visibility Rules</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#4">4 – The Application Program Interface</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#4.1">4.1 – The Stack</A>
|
||||
<LI><A HREF="manual.html#4.2">4.2 – Stack Size</A>
|
||||
<LI><A HREF="manual.html#4.3">4.3 – Valid and Acceptable Indices</A>
|
||||
<LI><A HREF="manual.html#4.4">4.4 – C Closures</A>
|
||||
<LI><A HREF="manual.html#4.5">4.5 – Registry</A>
|
||||
<LI><A HREF="manual.html#4.6">4.6 – Error Handling in C</A>
|
||||
<LI><A HREF="manual.html#4.7">4.7 – Handling Yields in C</A>
|
||||
<LI><A HREF="manual.html#4.8">4.8 – Functions and Types</A>
|
||||
<LI><A HREF="manual.html#4.9">4.9 – The Debug Interface</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#5">5 – The Auxiliary Library</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#5.1">5.1 – Functions and Types</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#6">6 – Standard Libraries</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#6.1">6.1 – Basic Functions</A>
|
||||
<LI><A HREF="manual.html#6.2">6.2 – Coroutine Manipulation</A>
|
||||
<LI><A HREF="manual.html#6.3">6.3 – Modules</A>
|
||||
<LI><A HREF="manual.html#6.4">6.4 – String Manipulation</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#6.4.1">6.4.1 – Patterns</A>
|
||||
<LI><A HREF="manual.html#6.4.2">6.4.2 – Format Strings for Pack and Unpack</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#6.5">6.5 – UTF-8 Support</A>
|
||||
<LI><A HREF="manual.html#6.6">6.6 – Table Manipulation</A>
|
||||
<LI><A HREF="manual.html#6.7">6.7 – Mathematical Functions</A>
|
||||
<LI><A HREF="manual.html#6.8">6.8 – Input and Output Facilities</A>
|
||||
<LI><A HREF="manual.html#6.9">6.9 – Operating System Facilities</A>
|
||||
<LI><A HREF="manual.html#6.10">6.10 – The Debug Library</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#7">7 – Lua Standalone</A>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#8">8 – Incompatibilities with the Previous Version</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#8.1">8.1 – Changes in the Language</A>
|
||||
<LI><A HREF="manual.html#8.2">8.2 – Changes in the Libraries</A>
|
||||
<LI><A HREF="manual.html#8.3">8.3 – Changes in the API</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#9">9 – The Complete Syntax of Lua</A>
|
||||
</UL>
|
||||
|
||||
<H2><A NAME="index">Index</A></H2>
|
||||
<TABLE WIDTH="100%">
|
||||
<TR VALIGN="top">
|
||||
<TD>
|
||||
<H3><A NAME="functions">Lua functions</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#6.1">basic</A><BR>
|
||||
<A HREF="manual.html#pdf-_G">_G</A><BR>
|
||||
<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR>
|
||||
|
||||
<A HREF="manual.html#pdf-assert">assert</A><BR>
|
||||
<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR>
|
||||
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
|
||||
<A HREF="manual.html#pdf-error">error</A><BR>
|
||||
<A HREF="manual.html#pdf-getmetatable">getmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-ipairs">ipairs</A><BR>
|
||||
<A HREF="manual.html#pdf-load">load</A><BR>
|
||||
<A HREF="manual.html#pdf-loadfile">loadfile</A><BR>
|
||||
<A HREF="manual.html#pdf-next">next</A><BR>
|
||||
<A HREF="manual.html#pdf-pairs">pairs</A><BR>
|
||||
<A HREF="manual.html#pdf-pcall">pcall</A><BR>
|
||||
<A HREF="manual.html#pdf-print">print</A><BR>
|
||||
<A HREF="manual.html#pdf-rawequal">rawequal</A><BR>
|
||||
<A HREF="manual.html#pdf-rawget">rawget</A><BR>
|
||||
<A HREF="manual.html#pdf-rawlen">rawlen</A><BR>
|
||||
<A HREF="manual.html#pdf-rawset">rawset</A><BR>
|
||||
<A HREF="manual.html#pdf-require">require</A><BR>
|
||||
<A HREF="manual.html#pdf-select">select</A><BR>
|
||||
<A HREF="manual.html#pdf-setmetatable">setmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-tonumber">tonumber</A><BR>
|
||||
<A HREF="manual.html#pdf-tostring">tostring</A><BR>
|
||||
<A HREF="manual.html#pdf-type">type</A><BR>
|
||||
<A HREF="manual.html#pdf-xpcall">xpcall</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.2">coroutine</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.isyieldable">coroutine.isyieldable</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.resume">coroutine.resume</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.running">coroutine.running</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.status">coroutine.status</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.wrap">coroutine.wrap</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.yield">coroutine.yield</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.10">debug</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.debug">debug.debug</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.gethook">debug.gethook</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getinfo">debug.getinfo</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getlocal">debug.getlocal</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getmetatable">debug.getmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setupvalue">debug.setupvalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setuservalue">debug.setuservalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.traceback">debug.traceback</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.upvalueid">debug.upvalueid</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.upvaluejoin">debug.upvaluejoin</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.8">io</A><BR>
|
||||
<A HREF="manual.html#pdf-io.close">io.close</A><BR>
|
||||
<A HREF="manual.html#pdf-io.flush">io.flush</A><BR>
|
||||
<A HREF="manual.html#pdf-io.input">io.input</A><BR>
|
||||
<A HREF="manual.html#pdf-io.lines">io.lines</A><BR>
|
||||
<A HREF="manual.html#pdf-io.open">io.open</A><BR>
|
||||
<A HREF="manual.html#pdf-io.output">io.output</A><BR>
|
||||
<A HREF="manual.html#pdf-io.popen">io.popen</A><BR>
|
||||
<A HREF="manual.html#pdf-io.read">io.read</A><BR>
|
||||
<A HREF="manual.html#pdf-io.stderr">io.stderr</A><BR>
|
||||
<A HREF="manual.html#pdf-io.stdin">io.stdin</A><BR>
|
||||
<A HREF="manual.html#pdf-io.stdout">io.stdout</A><BR>
|
||||
<A HREF="manual.html#pdf-io.tmpfile">io.tmpfile</A><BR>
|
||||
<A HREF="manual.html#pdf-io.type">io.type</A><BR>
|
||||
<A HREF="manual.html#pdf-io.write">io.write</A><BR>
|
||||
|
||||
<A HREF="manual.html#pdf-file:close">file:close</A><BR>
|
||||
<A HREF="manual.html#pdf-file:flush">file:flush</A><BR>
|
||||
<A HREF="manual.html#pdf-file:lines">file:lines</A><BR>
|
||||
<A HREF="manual.html#pdf-file:read">file:read</A><BR>
|
||||
<A HREF="manual.html#pdf-file:seek">file:seek</A><BR>
|
||||
<A HREF="manual.html#pdf-file:setvbuf">file:setvbuf</A><BR>
|
||||
<A HREF="manual.html#pdf-file:write">file:write</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3> </H3>
|
||||
<P>
|
||||
<A HREF="manual.html#6.7">math</A><BR>
|
||||
<A HREF="manual.html#pdf-math.abs">math.abs</A><BR>
|
||||
<A HREF="manual.html#pdf-math.acos">math.acos</A><BR>
|
||||
<A HREF="manual.html#pdf-math.asin">math.asin</A><BR>
|
||||
<A HREF="manual.html#pdf-math.atan">math.atan</A><BR>
|
||||
<A HREF="manual.html#pdf-math.ceil">math.ceil</A><BR>
|
||||
<A HREF="manual.html#pdf-math.cos">math.cos</A><BR>
|
||||
<A HREF="manual.html#pdf-math.deg">math.deg</A><BR>
|
||||
<A HREF="manual.html#pdf-math.exp">math.exp</A><BR>
|
||||
<A HREF="manual.html#pdf-math.floor">math.floor</A><BR>
|
||||
<A HREF="manual.html#pdf-math.fmod">math.fmod</A><BR>
|
||||
<A HREF="manual.html#pdf-math.huge">math.huge</A><BR>
|
||||
<A HREF="manual.html#pdf-math.log">math.log</A><BR>
|
||||
<A HREF="manual.html#pdf-math.max">math.max</A><BR>
|
||||
<A HREF="manual.html#pdf-math.maxinteger">math.maxinteger</A><BR>
|
||||
<A HREF="manual.html#pdf-math.min">math.min</A><BR>
|
||||
<A HREF="manual.html#pdf-math.mininteger">math.mininteger</A><BR>
|
||||
<A HREF="manual.html#pdf-math.modf">math.modf</A><BR>
|
||||
<A HREF="manual.html#pdf-math.pi">math.pi</A><BR>
|
||||
<A HREF="manual.html#pdf-math.rad">math.rad</A><BR>
|
||||
<A HREF="manual.html#pdf-math.random">math.random</A><BR>
|
||||
<A HREF="manual.html#pdf-math.randomseed">math.randomseed</A><BR>
|
||||
<A HREF="manual.html#pdf-math.sin">math.sin</A><BR>
|
||||
<A HREF="manual.html#pdf-math.sqrt">math.sqrt</A><BR>
|
||||
<A HREF="manual.html#pdf-math.tan">math.tan</A><BR>
|
||||
<A HREF="manual.html#pdf-math.tointeger">math.tointeger</A><BR>
|
||||
<A HREF="manual.html#pdf-math.type">math.type</A><BR>
|
||||
<A HREF="manual.html#pdf-math.ult">math.ult</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.9">os</A><BR>
|
||||
<A HREF="manual.html#pdf-os.clock">os.clock</A><BR>
|
||||
<A HREF="manual.html#pdf-os.date">os.date</A><BR>
|
||||
<A HREF="manual.html#pdf-os.difftime">os.difftime</A><BR>
|
||||
<A HREF="manual.html#pdf-os.execute">os.execute</A><BR>
|
||||
<A HREF="manual.html#pdf-os.exit">os.exit</A><BR>
|
||||
<A HREF="manual.html#pdf-os.getenv">os.getenv</A><BR>
|
||||
<A HREF="manual.html#pdf-os.remove">os.remove</A><BR>
|
||||
<A HREF="manual.html#pdf-os.rename">os.rename</A><BR>
|
||||
<A HREF="manual.html#pdf-os.setlocale">os.setlocale</A><BR>
|
||||
<A HREF="manual.html#pdf-os.time">os.time</A><BR>
|
||||
<A HREF="manual.html#pdf-os.tmpname">os.tmpname</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.3">package</A><BR>
|
||||
<A HREF="manual.html#pdf-package.config">package.config</A><BR>
|
||||
<A HREF="manual.html#pdf-package.cpath">package.cpath</A><BR>
|
||||
<A HREF="manual.html#pdf-package.loaded">package.loaded</A><BR>
|
||||
<A HREF="manual.html#pdf-package.loadlib">package.loadlib</A><BR>
|
||||
<A HREF="manual.html#pdf-package.path">package.path</A><BR>
|
||||
<A HREF="manual.html#pdf-package.preload">package.preload</A><BR>
|
||||
<A HREF="manual.html#pdf-package.searchers">package.searchers</A><BR>
|
||||
<A HREF="manual.html#pdf-package.searchpath">package.searchpath</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.4">string</A><BR>
|
||||
<A HREF="manual.html#pdf-string.byte">string.byte</A><BR>
|
||||
<A HREF="manual.html#pdf-string.char">string.char</A><BR>
|
||||
<A HREF="manual.html#pdf-string.dump">string.dump</A><BR>
|
||||
<A HREF="manual.html#pdf-string.find">string.find</A><BR>
|
||||
<A HREF="manual.html#pdf-string.format">string.format</A><BR>
|
||||
<A HREF="manual.html#pdf-string.gmatch">string.gmatch</A><BR>
|
||||
<A HREF="manual.html#pdf-string.gsub">string.gsub</A><BR>
|
||||
<A HREF="manual.html#pdf-string.len">string.len</A><BR>
|
||||
<A HREF="manual.html#pdf-string.lower">string.lower</A><BR>
|
||||
<A HREF="manual.html#pdf-string.match">string.match</A><BR>
|
||||
<A HREF="manual.html#pdf-string.pack">string.pack</A><BR>
|
||||
<A HREF="manual.html#pdf-string.packsize">string.packsize</A><BR>
|
||||
<A HREF="manual.html#pdf-string.rep">string.rep</A><BR>
|
||||
<A HREF="manual.html#pdf-string.reverse">string.reverse</A><BR>
|
||||
<A HREF="manual.html#pdf-string.sub">string.sub</A><BR>
|
||||
<A HREF="manual.html#pdf-string.unpack">string.unpack</A><BR>
|
||||
<A HREF="manual.html#pdf-string.upper">string.upper</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.6">table</A><BR>
|
||||
<A HREF="manual.html#pdf-table.concat">table.concat</A><BR>
|
||||
<A HREF="manual.html#pdf-table.insert">table.insert</A><BR>
|
||||
<A HREF="manual.html#pdf-table.move">table.move</A><BR>
|
||||
<A HREF="manual.html#pdf-table.pack">table.pack</A><BR>
|
||||
<A HREF="manual.html#pdf-table.remove">table.remove</A><BR>
|
||||
<A HREF="manual.html#pdf-table.sort">table.sort</A><BR>
|
||||
<A HREF="manual.html#pdf-table.unpack">table.unpack</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.5">utf8</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.char">utf8.char</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.charpattern">utf8.charpattern</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.codepoint">utf8.codepoint</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.codes">utf8.codes</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.len">utf8.len</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.offset">utf8.offset</A><BR>
|
||||
|
||||
<H3><A NAME="env">environment<BR>variables</A></H3>
|
||||
<A HREF="manual.html#pdf-LUA_CPATH">LUA_CPATH</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_CPATH_5_3">LUA_CPATH_5_3</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_INIT">LUA_INIT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_INIT_5_3">LUA_INIT_5_3</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_PATH">LUA_PATH</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_PATH_5_3">LUA_PATH_5_3</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3><A NAME="api">C API</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#lua_Alloc">lua_Alloc</A><BR>
|
||||
<A HREF="manual.html#lua_CFunction">lua_CFunction</A><BR>
|
||||
<A HREF="manual.html#lua_Debug">lua_Debug</A><BR>
|
||||
<A HREF="manual.html#lua_Hook">lua_Hook</A><BR>
|
||||
<A HREF="manual.html#lua_Integer">lua_Integer</A><BR>
|
||||
<A HREF="manual.html#lua_KContext">lua_KContext</A><BR>
|
||||
<A HREF="manual.html#lua_KFunction">lua_KFunction</A><BR>
|
||||
<A HREF="manual.html#lua_Number">lua_Number</A><BR>
|
||||
<A HREF="manual.html#lua_Reader">lua_Reader</A><BR>
|
||||
<A HREF="manual.html#lua_State">lua_State</A><BR>
|
||||
<A HREF="manual.html#lua_Unsigned">lua_Unsigned</A><BR>
|
||||
<A HREF="manual.html#lua_Writer">lua_Writer</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#lua_absindex">lua_absindex</A><BR>
|
||||
<A HREF="manual.html#lua_arith">lua_arith</A><BR>
|
||||
<A HREF="manual.html#lua_atpanic">lua_atpanic</A><BR>
|
||||
<A HREF="manual.html#lua_call">lua_call</A><BR>
|
||||
<A HREF="manual.html#lua_callk">lua_callk</A><BR>
|
||||
<A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
|
||||
<A HREF="manual.html#lua_close">lua_close</A><BR>
|
||||
<A HREF="manual.html#lua_compare">lua_compare</A><BR>
|
||||
<A HREF="manual.html#lua_concat">lua_concat</A><BR>
|
||||
<A HREF="manual.html#lua_copy">lua_copy</A><BR>
|
||||
<A HREF="manual.html#lua_createtable">lua_createtable</A><BR>
|
||||
<A HREF="manual.html#lua_dump">lua_dump</A><BR>
|
||||
<A HREF="manual.html#lua_error">lua_error</A><BR>
|
||||
<A HREF="manual.html#lua_gc">lua_gc</A><BR>
|
||||
<A HREF="manual.html#lua_getallocf">lua_getallocf</A><BR>
|
||||
<A HREF="manual.html#lua_getextraspace">lua_getextraspace</A><BR>
|
||||
<A HREF="manual.html#lua_getfield">lua_getfield</A><BR>
|
||||
<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR>
|
||||
<A HREF="manual.html#lua_gethook">lua_gethook</A><BR>
|
||||
<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR>
|
||||
<A HREF="manual.html#lua_gethookmask">lua_gethookmask</A><BR>
|
||||
<A HREF="manual.html#lua_geti">lua_geti</A><BR>
|
||||
<A HREF="manual.html#lua_getinfo">lua_getinfo</A><BR>
|
||||
<A HREF="manual.html#lua_getlocal">lua_getlocal</A><BR>
|
||||
<A HREF="manual.html#lua_getmetatable">lua_getmetatable</A><BR>
|
||||
<A HREF="manual.html#lua_getstack">lua_getstack</A><BR>
|
||||
<A HREF="manual.html#lua_gettable">lua_gettable</A><BR>
|
||||
<A HREF="manual.html#lua_gettop">lua_gettop</A><BR>
|
||||
<A HREF="manual.html#lua_getupvalue">lua_getupvalue</A><BR>
|
||||
<A HREF="manual.html#lua_getuservalue">lua_getuservalue</A><BR>
|
||||
<A HREF="manual.html#lua_insert">lua_insert</A><BR>
|
||||
<A HREF="manual.html#lua_isboolean">lua_isboolean</A><BR>
|
||||
<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR>
|
||||
<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR>
|
||||
<A HREF="manual.html#lua_isinteger">lua_isinteger</A><BR>
|
||||
<A HREF="manual.html#lua_islightuserdata">lua_islightuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_isnil">lua_isnil</A><BR>
|
||||
<A HREF="manual.html#lua_isnone">lua_isnone</A><BR>
|
||||
<A HREF="manual.html#lua_isnoneornil">lua_isnoneornil</A><BR>
|
||||
<A HREF="manual.html#lua_isnumber">lua_isnumber</A><BR>
|
||||
<A HREF="manual.html#lua_isstring">lua_isstring</A><BR>
|
||||
<A HREF="manual.html#lua_istable">lua_istable</A><BR>
|
||||
<A HREF="manual.html#lua_isthread">lua_isthread</A><BR>
|
||||
<A HREF="manual.html#lua_isuserdata">lua_isuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_isyieldable">lua_isyieldable</A><BR>
|
||||
<A HREF="manual.html#lua_len">lua_len</A><BR>
|
||||
<A HREF="manual.html#lua_load">lua_load</A><BR>
|
||||
<A HREF="manual.html#lua_newstate">lua_newstate</A><BR>
|
||||
<A HREF="manual.html#lua_newtable">lua_newtable</A><BR>
|
||||
<A HREF="manual.html#lua_newthread">lua_newthread</A><BR>
|
||||
<A HREF="manual.html#lua_newuserdata">lua_newuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_next">lua_next</A><BR>
|
||||
<A HREF="manual.html#lua_numbertointeger">lua_numbertointeger</A><BR>
|
||||
<A HREF="manual.html#lua_pcall">lua_pcall</A><BR>
|
||||
<A HREF="manual.html#lua_pcallk">lua_pcallk</A><BR>
|
||||
<A HREF="manual.html#lua_pop">lua_pop</A><BR>
|
||||
<A HREF="manual.html#lua_pushboolean">lua_pushboolean</A><BR>
|
||||
<A HREF="manual.html#lua_pushcclosure">lua_pushcclosure</A><BR>
|
||||
<A HREF="manual.html#lua_pushcfunction">lua_pushcfunction</A><BR>
|
||||
<A HREF="manual.html#lua_pushfstring">lua_pushfstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushglobaltable">lua_pushglobaltable</A><BR>
|
||||
<A HREF="manual.html#lua_pushinteger">lua_pushinteger</A><BR>
|
||||
<A HREF="manual.html#lua_pushlightuserdata">lua_pushlightuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_pushliteral">lua_pushliteral</A><BR>
|
||||
<A HREF="manual.html#lua_pushlstring">lua_pushlstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushnil">lua_pushnil</A><BR>
|
||||
<A HREF="manual.html#lua_pushnumber">lua_pushnumber</A><BR>
|
||||
<A HREF="manual.html#lua_pushstring">lua_pushstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushthread">lua_pushthread</A><BR>
|
||||
<A HREF="manual.html#lua_pushvalue">lua_pushvalue</A><BR>
|
||||
<A HREF="manual.html#lua_pushvfstring">lua_pushvfstring</A><BR>
|
||||
<A HREF="manual.html#lua_rawequal">lua_rawequal</A><BR>
|
||||
<A HREF="manual.html#lua_rawget">lua_rawget</A><BR>
|
||||
<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR>
|
||||
<A HREF="manual.html#lua_rawgetp">lua_rawgetp</A><BR>
|
||||
<A HREF="manual.html#lua_rawlen">lua_rawlen</A><BR>
|
||||
<A HREF="manual.html#lua_rawset">lua_rawset</A><BR>
|
||||
<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR>
|
||||
<A HREF="manual.html#lua_rawsetp">lua_rawsetp</A><BR>
|
||||
<A HREF="manual.html#lua_register">lua_register</A><BR>
|
||||
<A HREF="manual.html#lua_remove">lua_remove</A><BR>
|
||||
<A HREF="manual.html#lua_replace">lua_replace</A><BR>
|
||||
<A HREF="manual.html#lua_resume">lua_resume</A><BR>
|
||||
<A HREF="manual.html#lua_rotate">lua_rotate</A><BR>
|
||||
<A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
|
||||
<A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
|
||||
<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
|
||||
<A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
|
||||
<A HREF="manual.html#lua_seti">lua_seti</A><BR>
|
||||
<A HREF="manual.html#lua_setlocal">lua_setlocal</A><BR>
|
||||
<A HREF="manual.html#lua_setmetatable">lua_setmetatable</A><BR>
|
||||
<A HREF="manual.html#lua_settable">lua_settable</A><BR>
|
||||
<A HREF="manual.html#lua_settop">lua_settop</A><BR>
|
||||
<A HREF="manual.html#lua_setupvalue">lua_setupvalue</A><BR>
|
||||
<A HREF="manual.html#lua_setuservalue">lua_setuservalue</A><BR>
|
||||
<A HREF="manual.html#lua_status">lua_status</A><BR>
|
||||
<A HREF="manual.html#lua_stringtonumber">lua_stringtonumber</A><BR>
|
||||
<A HREF="manual.html#lua_toboolean">lua_toboolean</A><BR>
|
||||
<A HREF="manual.html#lua_tocfunction">lua_tocfunction</A><BR>
|
||||
<A HREF="manual.html#lua_tointeger">lua_tointeger</A><BR>
|
||||
<A HREF="manual.html#lua_tointegerx">lua_tointegerx</A><BR>
|
||||
<A HREF="manual.html#lua_tolstring">lua_tolstring</A><BR>
|
||||
<A HREF="manual.html#lua_tonumber">lua_tonumber</A><BR>
|
||||
<A HREF="manual.html#lua_tonumberx">lua_tonumberx</A><BR>
|
||||
<A HREF="manual.html#lua_topointer">lua_topointer</A><BR>
|
||||
<A HREF="manual.html#lua_tostring">lua_tostring</A><BR>
|
||||
<A HREF="manual.html#lua_tothread">lua_tothread</A><BR>
|
||||
<A HREF="manual.html#lua_touserdata">lua_touserdata</A><BR>
|
||||
<A HREF="manual.html#lua_type">lua_type</A><BR>
|
||||
<A HREF="manual.html#lua_typename">lua_typename</A><BR>
|
||||
<A HREF="manual.html#lua_upvalueid">lua_upvalueid</A><BR>
|
||||
<A HREF="manual.html#lua_upvalueindex">lua_upvalueindex</A><BR>
|
||||
<A HREF="manual.html#lua_upvaluejoin">lua_upvaluejoin</A><BR>
|
||||
<A HREF="manual.html#lua_version">lua_version</A><BR>
|
||||
<A HREF="manual.html#lua_xmove">lua_xmove</A><BR>
|
||||
<A HREF="manual.html#lua_yield">lua_yield</A><BR>
|
||||
<A HREF="manual.html#lua_yieldk">lua_yieldk</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3><A NAME="auxlib">auxiliary library</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#luaL_Buffer">luaL_Buffer</A><BR>
|
||||
<A HREF="manual.html#luaL_Reg">luaL_Reg</A><BR>
|
||||
<A HREF="manual.html#luaL_Stream">luaL_Stream</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#luaL_addchar">luaL_addchar</A><BR>
|
||||
<A HREF="manual.html#luaL_addlstring">luaL_addlstring</A><BR>
|
||||
<A HREF="manual.html#luaL_addsize">luaL_addsize</A><BR>
|
||||
<A HREF="manual.html#luaL_addstring">luaL_addstring</A><BR>
|
||||
<A HREF="manual.html#luaL_addvalue">luaL_addvalue</A><BR>
|
||||
<A HREF="manual.html#luaL_argcheck">luaL_argcheck</A><BR>
|
||||
<A HREF="manual.html#luaL_argerror">luaL_argerror</A><BR>
|
||||
<A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR>
|
||||
<A HREF="manual.html#luaL_buffinitsize">luaL_buffinitsize</A><BR>
|
||||
<A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR>
|
||||
<A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR>
|
||||
<A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR>
|
||||
<A HREF="manual.html#luaL_checklstring">luaL_checklstring</A><BR>
|
||||
<A HREF="manual.html#luaL_checknumber">luaL_checknumber</A><BR>
|
||||
<A HREF="manual.html#luaL_checkoption">luaL_checkoption</A><BR>
|
||||
<A HREF="manual.html#luaL_checkstack">luaL_checkstack</A><BR>
|
||||
<A HREF="manual.html#luaL_checkstring">luaL_checkstring</A><BR>
|
||||
<A HREF="manual.html#luaL_checktype">luaL_checktype</A><BR>
|
||||
<A HREF="manual.html#luaL_checkudata">luaL_checkudata</A><BR>
|
||||
<A HREF="manual.html#luaL_checkversion">luaL_checkversion</A><BR>
|
||||
<A HREF="manual.html#luaL_dofile">luaL_dofile</A><BR>
|
||||
<A HREF="manual.html#luaL_dostring">luaL_dostring</A><BR>
|
||||
<A HREF="manual.html#luaL_error">luaL_error</A><BR>
|
||||
<A HREF="manual.html#luaL_execresult">luaL_execresult</A><BR>
|
||||
<A HREF="manual.html#luaL_fileresult">luaL_fileresult</A><BR>
|
||||
<A HREF="manual.html#luaL_getmetafield">luaL_getmetafield</A><BR>
|
||||
<A HREF="manual.html#luaL_getmetatable">luaL_getmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_getsubtable">luaL_getsubtable</A><BR>
|
||||
<A HREF="manual.html#luaL_gsub">luaL_gsub</A><BR>
|
||||
<A HREF="manual.html#luaL_len">luaL_len</A><BR>
|
||||
<A HREF="manual.html#luaL_loadbuffer">luaL_loadbuffer</A><BR>
|
||||
<A HREF="manual.html#luaL_loadbufferx">luaL_loadbufferx</A><BR>
|
||||
<A HREF="manual.html#luaL_loadfile">luaL_loadfile</A><BR>
|
||||
<A HREF="manual.html#luaL_loadfilex">luaL_loadfilex</A><BR>
|
||||
<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR>
|
||||
<A HREF="manual.html#luaL_newlib">luaL_newlib</A><BR>
|
||||
<A HREF="manual.html#luaL_newlibtable">luaL_newlibtable</A><BR>
|
||||
<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
|
||||
<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
|
||||
<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
|
||||
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
|
||||
<A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR>
|
||||
<A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR>
|
||||
<A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR>
|
||||
<A HREF="manual.html#luaL_prepbuffsize">luaL_prepbuffsize</A><BR>
|
||||
<A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR>
|
||||
<A HREF="manual.html#luaL_pushresultsize">luaL_pushresultsize</A><BR>
|
||||
<A HREF="manual.html#luaL_ref">luaL_ref</A><BR>
|
||||
<A HREF="manual.html#luaL_requiref">luaL_requiref</A><BR>
|
||||
<A HREF="manual.html#luaL_setfuncs">luaL_setfuncs</A><BR>
|
||||
<A HREF="manual.html#luaL_setmetatable">luaL_setmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_testudata">luaL_testudata</A><BR>
|
||||
<A HREF="manual.html#luaL_tolstring">luaL_tolstring</A><BR>
|
||||
<A HREF="manual.html#luaL_traceback">luaL_traceback</A><BR>
|
||||
<A HREF="manual.html#luaL_typename">luaL_typename</A><BR>
|
||||
<A HREF="manual.html#luaL_unref">luaL_unref</A><BR>
|
||||
<A HREF="manual.html#luaL_where">luaL_where</A><BR>
|
||||
|
||||
<H3><A NAME="library">standard library</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#pdf-luaopen_base">luaopen_base</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_coroutine">luaopen_coroutine</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_debug">luaopen_debug</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_io">luaopen_io</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_math">luaopen_math</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_os">luaopen_os</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_package">luaopen_package</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_string">luaopen_string</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_table">luaopen_table</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_utf8">luaopen_utf8</A><BR>
|
||||
|
||||
<H3><A NAME="constants">constants</A></H3>
|
||||
<A HREF="manual.html#pdf-LUA_ERRERR">LUA_ERRERR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRFILE">LUA_ERRFILE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRGCMM">LUA_ERRGCMM</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRMEM">LUA_ERRMEM</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRRUN">LUA_ERRRUN</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRSYNTAX">LUA_ERRSYNTAX</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKCALL">LUA_HOOKCALL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKCOUNT">LUA_HOOKCOUNT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKRET">LUA_MASKRET</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MAXINTEGER">LUA_MAXINTEGER</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MININTEGER">LUA_MININTEGER</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MINSTACK">LUA_MINSTACK</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MULTRET">LUA_MULTRET</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_NOREF">LUA_NOREF</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OK">LUA_OK</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPADD">LUA_OPADD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBAND">LUA_OPBAND</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBNOT">LUA_OPBNOT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBOR">LUA_OPBOR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBXOR">LUA_OPBXOR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPDIV">LUA_OPDIV</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPEQ">LUA_OPEQ</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPIDIV">LUA_OPIDIV</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPLE">LUA_OPLE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPLT">LUA_OPLT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPMOD">LUA_OPMOD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPMUL">LUA_OPMUL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPPOW">LUA_OPPOW</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPSHL">LUA_OPSHL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_RIDX_MAINTHREAD">LUA_RIDX_MAINTHREAD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TBOOLEAN">LUA_TBOOLEAN</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TFUNCTION">LUA_TFUNCTION</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TLIGHTUSERDATA">LUA_TLIGHTUSERDATA</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TNIL">LUA_TNIL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TNONE">LUA_TNONE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TNUMBER">LUA_TNUMBER</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TSTRING">LUA_TSTRING</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TTABLE">LUA_TTABLE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TTHREAD">LUA_TTHREAD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
|
||||
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<HR>
|
||||
<SMALL CLASS="footer">
|
||||
Last update:
|
||||
Tue Dec 9 21:26:07 BRST 2014
|
||||
</SMALL>
|
||||
<!--
|
||||
Last change: updated for Lua 5.3.0 (final)
|
||||
-->
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
+111
@@ -0,0 +1,111 @@
|
||||
.TH LUA 1 "$Date: 2014/12/10 15:55:45 $"
|
||||
.SH NAME
|
||||
lua \- Lua interpreter
|
||||
.SH SYNOPSIS
|
||||
.B lua
|
||||
[
|
||||
.I options
|
||||
]
|
||||
[
|
||||
.I script
|
||||
[
|
||||
.I args
|
||||
]
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B lua
|
||||
is the standalone Lua interpreter.
|
||||
It loads and executes Lua programs,
|
||||
either in textual source form or
|
||||
in precompiled binary form.
|
||||
(Precompiled binaries are output by
|
||||
.BR luac ,
|
||||
the Lua compiler.)
|
||||
.B lua
|
||||
can be used as a batch interpreter and also interactively.
|
||||
.LP
|
||||
The given
|
||||
.I options
|
||||
are handled in order and then
|
||||
the Lua program in file
|
||||
.I script
|
||||
is loaded and executed.
|
||||
The given
|
||||
.I args
|
||||
are available to
|
||||
.I script
|
||||
as strings in a global table named
|
||||
.BR arg .
|
||||
If no options or arguments are given,
|
||||
then
|
||||
.B "\-v \-i"
|
||||
is assumed when the standard input is a terminal;
|
||||
otherwise,
|
||||
.B "\-"
|
||||
is assumed.
|
||||
.LP
|
||||
In interactive mode,
|
||||
.B lua
|
||||
prompts the user,
|
||||
reads lines from the standard input,
|
||||
and executes them as they are read.
|
||||
If the line contains an expression or list of expressions,
|
||||
then the line is evaluated and the results are printed.
|
||||
If a line does not contain a complete statement,
|
||||
then a secondary prompt is displayed and
|
||||
lines are read until a complete statement is formed or
|
||||
a syntax error is found.
|
||||
.LP
|
||||
At the very start,
|
||||
before even handling the command line,
|
||||
.B lua
|
||||
checks the contents of the environment variables
|
||||
.B LUA_INIT_5_3
|
||||
or
|
||||
.BR LUA_INIT ,
|
||||
in that order.
|
||||
If the contents is of the form
|
||||
.RI '@ filename ',
|
||||
then
|
||||
.I filename
|
||||
is executed.
|
||||
Otherwise, the string is assumed to be a Lua statement and is executed.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-e " stat"
|
||||
execute statement
|
||||
.IR stat .
|
||||
.TP
|
||||
.B \-i
|
||||
enter interactive mode after executing
|
||||
.IR script .
|
||||
.TP
|
||||
.BI \-l " name"
|
||||
execute the equivalent of
|
||||
.IB name =require(' name ')
|
||||
before executing
|
||||
.IR script .
|
||||
.TP
|
||||
.B \-v
|
||||
show version information.
|
||||
.TP
|
||||
.B \-E
|
||||
ignore environment variables.
|
||||
.TP
|
||||
.B \-\-
|
||||
stop handling options.
|
||||
.TP
|
||||
.B \-
|
||||
stop handling options and execute the standard input as a file.
|
||||
.SH "SEE ALSO"
|
||||
.BR luac (1)
|
||||
.br
|
||||
The documentation at lua.org,
|
||||
especially section 7 of the reference manual.
|
||||
.SH DIAGNOSTICS
|
||||
Error messages should be self explanatory.
|
||||
.SH AUTHORS
|
||||
R. Ierusalimschy,
|
||||
L. H. de Figueiredo,
|
||||
W. Celes
|
||||
.\" EOF
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
html {
|
||||
background-color: #F8F8F8 ;
|
||||
}
|
||||
|
||||
body {
|
||||
border: solid #a0a0a0 1px ;
|
||||
border-radius: 20px ;
|
||||
padding: 26px ;
|
||||
margin: 16px ;
|
||||
color: #000000 ;
|
||||
background-color: #FFFFFF ;
|
||||
font-family: Helvetica, Arial, sans-serif ;
|
||||
text-align: justify ;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-family: Verdana, Geneva, sans-serif ;
|
||||
font-weight: normal ;
|
||||
font-style: normal ;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-top: 0.4em ;
|
||||
padding-bottom: 0.4em ;
|
||||
padding-left: 0.8em ;
|
||||
padding-right: 0.8em ;
|
||||
background-color: #D0D0FF ;
|
||||
border-radius: 8px ;
|
||||
border: solid #a0a0a0 1px ;
|
||||
}
|
||||
|
||||
h3 {
|
||||
padding-left: 0.5em ;
|
||||
border-left: solid #D0D0FF 1em ;
|
||||
}
|
||||
|
||||
table h3 {
|
||||
padding-left: 0px ;
|
||||
border-left: none ;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #000080 ;
|
||||
background-color: inherit ;
|
||||
text-decoration: none ;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
background-color: inherit ;
|
||||
text-decoration: none ;
|
||||
}
|
||||
|
||||
a:link:hover, a:visited:hover {
|
||||
color: #000080 ;
|
||||
background-color: #D0D0FF ;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
a:link:active, a:visited:active {
|
||||
color: #FF0000 ;
|
||||
}
|
||||
|
||||
h1 a img {
|
||||
vertical-align: text-bottom ;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0 ;
|
||||
height: 1px ;
|
||||
color: #a0a0a0 ;
|
||||
background-color: #a0a0a0 ;
|
||||
display: none ;
|
||||
}
|
||||
|
||||
table hr {
|
||||
display: block ;
|
||||
}
|
||||
|
||||
:target {
|
||||
background-color: #F8F8F8 ;
|
||||
padding: 8px ;
|
||||
border: solid #a0a0a0 2px ;
|
||||
border-radius: 8px ;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: gray ;
|
||||
font-size: x-small ;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
border: solid #a0a0a0 2px ;
|
||||
border-radius: 2em ;
|
||||
background-image: url('images/search.png') ;
|
||||
background-repeat: no-repeat ;
|
||||
background-position: 4px center ;
|
||||
padding-left: 20px ;
|
||||
height: 2em ;
|
||||
}
|
||||
|
||||
pre.session {
|
||||
background-color: #F8F8F8 ;
|
||||
padding: 1em ;
|
||||
border-radius: 8px ;
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
.\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $
|
||||
.TH LUAC 1 "$Date: 2011/11/16 13:53:40 $"
|
||||
.SH NAME
|
||||
luac \- Lua compiler
|
||||
.SH SYNOPSIS
|
||||
.B luac
|
||||
[
|
||||
.I options
|
||||
] [
|
||||
.I filenames
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B luac
|
||||
is the Lua compiler.
|
||||
It translates programs written in the Lua programming language
|
||||
into binary files containing precompiled chunks
|
||||
that can be later loaded and executed.
|
||||
.LP
|
||||
The main advantages of precompiling chunks are:
|
||||
faster loading,
|
||||
protecting source code from accidental user changes,
|
||||
and
|
||||
off-line syntax checking.
|
||||
Precompiling does not imply faster execution
|
||||
because in Lua chunks are always compiled into bytecodes before being executed.
|
||||
.B luac
|
||||
simply allows those bytecodes to be saved in a file for later execution.
|
||||
Precompiled chunks are not necessarily smaller than the corresponding source.
|
||||
The main goal in precompiling is faster loading.
|
||||
.LP
|
||||
In the command line,
|
||||
you can mix
|
||||
text files containing Lua source and
|
||||
binary files containing precompiled chunks.
|
||||
.B luac
|
||||
produces a single output file containing the combined bytecodes
|
||||
for all files given.
|
||||
Executing the combined file is equivalent to executing the given files.
|
||||
By default,
|
||||
the output file is named
|
||||
.BR luac.out ,
|
||||
but you can change this with the
|
||||
.B \-o
|
||||
option.
|
||||
.LP
|
||||
Precompiled chunks are
|
||||
.I not
|
||||
portable across different architectures.
|
||||
Moreover,
|
||||
the internal format of precompiled chunks
|
||||
is likely to change when a new version of Lua is released.
|
||||
Make sure you save the source files of all Lua programs that you precompile.
|
||||
.LP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-l
|
||||
produce a listing of the compiled bytecode for Lua's virtual machine.
|
||||
Listing bytecodes is useful to learn about Lua's virtual machine.
|
||||
If no files are given, then
|
||||
.B luac
|
||||
loads
|
||||
.B luac.out
|
||||
and lists its contents.
|
||||
Use
|
||||
.B \-l \-l
|
||||
for a full listing.
|
||||
.TP
|
||||
.BI \-o " file"
|
||||
output to
|
||||
.IR file ,
|
||||
instead of the default
|
||||
.BR luac.out .
|
||||
(You can use
|
||||
.B "'\-'"
|
||||
for standard output,
|
||||
but not on platforms that open standard output in text mode.)
|
||||
The output file may be one of the given files because
|
||||
all files are loaded before the output file is written.
|
||||
Be careful not to overwrite precious files.
|
||||
.TP
|
||||
.B \-p
|
||||
load files but do not generate any output file.
|
||||
Used mainly for syntax checking and for testing precompiled chunks:
|
||||
corrupted files will probably generate errors when loaded.
|
||||
If no files are given, then
|
||||
.B luac
|
||||
loads
|
||||
.B luac.out
|
||||
and tests its contents.
|
||||
No messages are displayed if the file loads without errors.
|
||||
.TP
|
||||
.B \-s
|
||||
strip debug information before writing the output file.
|
||||
This saves some space in very large chunks,
|
||||
but if errors occur when running a stripped chunk,
|
||||
then the error messages may not contain the full information they usually do.
|
||||
In particular,
|
||||
line numbers and names of local variables are lost.
|
||||
.TP
|
||||
.B \-v
|
||||
show version information.
|
||||
.TP
|
||||
.B \-\-
|
||||
stop handling options.
|
||||
.TP
|
||||
.B \-
|
||||
stop handling options and process standard input.
|
||||
.SH "SEE ALSO"
|
||||
.BR lua (1)
|
||||
.br
|
||||
The documentation at lua.org.
|
||||
.SH DIAGNOSTICS
|
||||
Error messages should be self explanatory.
|
||||
.SH AUTHORS
|
||||
R. Ierusalimschy,
|
||||
L. H. de Figueiredo,
|
||||
W. Celes
|
||||
.\" EOF
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
h3 code {
|
||||
font-family: inherit ;
|
||||
font-size: inherit ;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-size: 12pt ;
|
||||
}
|
||||
|
||||
span.apii {
|
||||
float: right ;
|
||||
font-family: inherit ;
|
||||
font-style: normal ;
|
||||
font-size: small ;
|
||||
color: gray ;
|
||||
}
|
||||
|
||||
p+h1, ul+h1 {
|
||||
font-style: normal ;
|
||||
padding-top: 0.4em ;
|
||||
padding-bottom: 0.4em ;
|
||||
padding-left: 16px ;
|
||||
margin-left: -16px ;
|
||||
background-color: #D0D0FF ;
|
||||
border-radius: 8px ;
|
||||
border: solid #000080 1px ;
|
||||
}
|
||||
+10789
File diff suppressed because it is too large
Load Diff
Src/external_dependencies/openmpt-trunk/include/genie/src/host/lua-5.3.0/doc/osi-certified-72x60.png
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
+371
@@ -0,0 +1,371 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Lua 5.3 readme</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<STYLE TYPE="text/css">
|
||||
blockquote, .display {
|
||||
border: solid #a0a0a0 2px ;
|
||||
padding: 1em ;
|
||||
margin: 0px ;
|
||||
border-radius: 8px ;
|
||||
}
|
||||
|
||||
.display {
|
||||
word-spacing: 0.25em ;
|
||||
}
|
||||
|
||||
dl.display dd {
|
||||
padding-bottom: 0.2em ;
|
||||
}
|
||||
|
||||
tt, kbd, code {
|
||||
font-size: 12pt ;
|
||||
}
|
||||
</STYLE>
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
|
||||
<HR>
|
||||
<H1>
|
||||
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
|
||||
Welcome to Lua 5.3.0
|
||||
</H1>
|
||||
|
||||
<P>
|
||||
<A HREF="#about">about</A>
|
||||
·
|
||||
<A HREF="#install">installation</A>
|
||||
·
|
||||
<A HREF="#changes">changes</A>
|
||||
·
|
||||
<A HREF="#license">license</A>
|
||||
·
|
||||
<A HREF="contents.html">reference manual</A>
|
||||
|
||||
<H2><A NAME="about">About Lua</A></H2>
|
||||
|
||||
<P>
|
||||
Lua is a powerful, fast, lightweight, embeddable scripting language
|
||||
developed by a
|
||||
<A HREF="http://www.lua.org/authors.html">team</A>
|
||||
at
|
||||
<A HREF="http://www.puc-rio.br/">PUC-Rio</A>,
|
||||
the Pontifical Catholic University of Rio de Janeiro in Brazil.
|
||||
Lua is
|
||||
<A HREF="#license">free software</A>
|
||||
used in many products and projects around the world.
|
||||
|
||||
<P>
|
||||
Lua's
|
||||
<A HREF="http://www.lua.org/">official web site</A>
|
||||
provides complete information
|
||||
about Lua,
|
||||
including
|
||||
an
|
||||
<A HREF="http://www.lua.org/about.html">executive summary</A>
|
||||
and
|
||||
updated
|
||||
<A HREF="http://www.lua.org/docs.html">documentation</A>,
|
||||
especially the
|
||||
<A HREF="http://www.lua.org/manual/5.3/">reference manual</A>,
|
||||
which may differ slightly from the
|
||||
<A HREF="contents.html">local copy</A>
|
||||
distributed in this package.
|
||||
|
||||
<H2><A NAME="install">Installing Lua</A></H2>
|
||||
|
||||
<P>
|
||||
Lua is distributed in
|
||||
<A HREF="http://www.lua.org/ftp/">source</A>
|
||||
form.
|
||||
You need to build it before using it.
|
||||
Building Lua should be straightforward
|
||||
because
|
||||
Lua is implemented in pure ANSI C and compiles unmodified in all known
|
||||
platforms that have an ANSI C compiler.
|
||||
Lua also compiles unmodified as C++.
|
||||
The instructions given below for building Lua are for Unix-like platforms.
|
||||
See also
|
||||
<A HREF="#other">instructions for other systems</A>
|
||||
and
|
||||
<A HREF="#customization">customization options</A>.
|
||||
|
||||
<P>
|
||||
If you don't have the time or the inclination to compile Lua yourself,
|
||||
get a binary from
|
||||
<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>.
|
||||
Try also
|
||||
<A HREF="http://luadist.org/">LuaDist</A>,
|
||||
a multi-platform distribution of Lua that includes batteries.
|
||||
|
||||
<H3>Building Lua</H3>
|
||||
|
||||
<P>
|
||||
In most Unix-like platforms, simply do "<KBD>make</KBD>" with a suitable target.
|
||||
Here are the details.
|
||||
|
||||
<OL>
|
||||
<LI>
|
||||
Open a terminal window and move to
|
||||
the top-level directory, which is named <TT>lua-5.3.0</TT>.
|
||||
The <TT>Makefile</TT> there controls both the build process and the installation process.
|
||||
<P>
|
||||
<LI>
|
||||
Do "<KBD>make</KBD>" and see if your platform is listed.
|
||||
The platforms currently supported are:
|
||||
<P>
|
||||
<P CLASS="display">
|
||||
aix bsd c89 freebsd generic linux macosx mingw posix solaris
|
||||
</P>
|
||||
<P>
|
||||
If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
|
||||
is your platform name.
|
||||
<P>
|
||||
If your platform is not listed, try the closest one or posix, generic,
|
||||
c89, in this order.
|
||||
<P>
|
||||
<LI>
|
||||
The compilation takes only a few moments
|
||||
and produces three files in the <TT>src</TT> directory:
|
||||
lua (the interpreter),
|
||||
luac (the compiler),
|
||||
and liblua.a (the library).
|
||||
<P>
|
||||
<LI>
|
||||
To check that Lua has been built correctly, do "<KBD>make test</KBD>"
|
||||
after building Lua. This will run the interpreter and print its version.
|
||||
</OL>
|
||||
<P>
|
||||
If you're running Linux and get compilation errors,
|
||||
make sure you have installed the <TT>readline</TT> development package.
|
||||
If you get link errors after that,
|
||||
then try "<KBD>make linux MYLIBS=-ltermcap</KBD>".
|
||||
|
||||
<H3>Installing Lua</H3>
|
||||
<P>
|
||||
Once you have built Lua, you may want to install it in an official
|
||||
place in your system. In this case, do "<KBD>make install</KBD>". The official
|
||||
place and the way to install files are defined in the <TT>Makefile</TT>. You'll
|
||||
probably need the right permissions to install files.
|
||||
|
||||
<P>
|
||||
To build and install Lua in one step, do "<KBD>make xxx install</KBD>",
|
||||
where xxx is your platform name.
|
||||
|
||||
<P>
|
||||
To install Lua locally, do "<KBD>make local</KBD>".
|
||||
This will create a directory <TT>install</TT> with subdirectories
|
||||
<TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>, <TT>share</TT>,
|
||||
and install Lua as listed below.
|
||||
|
||||
To install Lua locally, but in some other directory, do
|
||||
"<KBD>make install INSTALL_TOP=xxx</KBD>", where xxx is your chosen directory.
|
||||
The installation starts in the <TT>src</TT> and <TT>doc</TT> directories,
|
||||
so take care if <TT>INSTALL_TOP</TT> is not an absolute path.
|
||||
|
||||
<DL CLASS="display">
|
||||
<DT>
|
||||
bin:
|
||||
<DD>
|
||||
lua luac
|
||||
<DT>
|
||||
include:
|
||||
<DD>
|
||||
lauxlib.h lua.h lua.hpp luaconf.h lualib.h
|
||||
<DT>
|
||||
lib:
|
||||
<DD>
|
||||
liblua.a
|
||||
<DT>
|
||||
man/man1:
|
||||
<DD>
|
||||
lua.1 luac.1
|
||||
</DL>
|
||||
|
||||
<P>
|
||||
These are the only directories you need for development.
|
||||
If you only want to run Lua programs,
|
||||
you only need the files in <TT>bin</TT> and <TT>man</TT>.
|
||||
The files in <TT>include</TT> and <TT>lib</TT> are needed for
|
||||
embedding Lua in C or C++ programs.
|
||||
|
||||
<H3><A NAME="customization">Customization</A></H3>
|
||||
<P>
|
||||
Three kinds of things can be customized by editing a file:
|
||||
<UL>
|
||||
<LI> Where and how to install Lua — edit <TT>Makefile</TT>.
|
||||
<LI> How to build Lua — edit <TT>src/Makefile</TT>.
|
||||
<LI> Lua features — edit <TT>src/luaconf.h</TT>.
|
||||
</UL>
|
||||
|
||||
<P>
|
||||
You don't actually need to edit the Makefiles because you may set the
|
||||
relevant variables in the command line when invoking make.
|
||||
Nevertheless, it's probably best to edit and save the Makefiles to
|
||||
record the changes you've made.
|
||||
|
||||
<P>
|
||||
On the other hand, if you need to customize some Lua features, you'll need
|
||||
to edit <TT>src/luaconf.h</TT> before building and installing Lua.
|
||||
The edited file will be the one installed, and
|
||||
it will be used by any Lua clients that you build, to ensure consistency.
|
||||
Further customization is available to experts by editing the Lua sources.
|
||||
|
||||
<H3><A NAME="other">Building Lua on other systems</A></H3>
|
||||
|
||||
<P>
|
||||
If you're not using the usual Unix tools, then the instructions for
|
||||
building Lua depend on the compiler you use. You'll need to create
|
||||
projects (or whatever your compiler uses) for building the library,
|
||||
the interpreter, and the compiler, as follows:
|
||||
|
||||
<DL CLASS="display">
|
||||
<DT>
|
||||
library:
|
||||
<DD>
|
||||
lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c
|
||||
lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c
|
||||
ltm.c lundump.c lvm.c lzio.c
|
||||
lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c
|
||||
lmathlib.c loslib.c lstrlib.c ltablib.c lutf8lib.c loadlib.c linit.c
|
||||
<DT>
|
||||
interpreter:
|
||||
<DD>
|
||||
library, lua.c
|
||||
<DT>
|
||||
compiler:
|
||||
<DD>
|
||||
library, luac.c
|
||||
</DL>
|
||||
|
||||
<P>
|
||||
To use Lua as a library in your own programs you'll need to know how to
|
||||
create and use libraries with your compiler. Moreover, to dynamically load
|
||||
C libraries for Lua you'll need to know how to create dynamic libraries
|
||||
and you'll need to make sure that the Lua API functions are accessible to
|
||||
those dynamic libraries — but <EM>don't</EM> link the Lua library
|
||||
into each dynamic library. For Unix, we recommend that the Lua library
|
||||
be linked statically into the host program and its symbols exported for
|
||||
dynamic linking; <TT>src/Makefile</TT> does this for the Lua interpreter.
|
||||
For Windows, we recommend that the Lua library be a DLL.
|
||||
In all cases, the compiler luac should be linked statically.
|
||||
|
||||
<P>
|
||||
As mentioned above, you may edit <TT>src/luaconf.h</TT> to customize
|
||||
some features before building Lua.
|
||||
|
||||
<H2><A NAME="changes">Changes since Lua 5.2</A></H2>
|
||||
|
||||
<P>
|
||||
Here are the main changes introduced in Lua 5.3.
|
||||
The
|
||||
<A HREF="contents.html">reference manual</A>
|
||||
lists the
|
||||
<A HREF="manual.html#8">incompatibilities</A> that had to be introduced.
|
||||
|
||||
<H3>Main changes</H3>
|
||||
<UL>
|
||||
<LI> integers (64-bit by default)
|
||||
<LI> official support for 32-bit numbers
|
||||
<LI> bitwise operators
|
||||
<LI> basic utf-8 support
|
||||
<LI> functions for packing and unpacking values
|
||||
|
||||
</UL>
|
||||
|
||||
Here are the other changes introduced in Lua 5.3:
|
||||
<H3>Language</H3>
|
||||
<UL>
|
||||
<LI> userdata can have any Lua value as uservalue
|
||||
<LI> integer division
|
||||
<LI> more flexible rules for some metamethods
|
||||
</UL>
|
||||
|
||||
<H3>Libraries</H3>
|
||||
<UL>
|
||||
<LI> <CODE>ipairs</CODE> and the table library respect metamethods
|
||||
<LI> strip option in <CODE>string.dump</CODE>
|
||||
<LI> table library respects metamethods
|
||||
<LI> new function <CODE>table.move</CODE>
|
||||
<LI> new function <CODE>string.pack</CODE>
|
||||
<LI> new function <CODE>string.unpack</CODE>
|
||||
<LI> new function <CODE>string.packsize</CODE>
|
||||
</UL>
|
||||
|
||||
<H3>C API</H3>
|
||||
<UL>
|
||||
<LI> simpler API for continuation functions in C
|
||||
<LI> <CODE>lua_gettable</CODE> and similar functions return type of resulted value
|
||||
<LI> strip option in <CODE>lua_dump</CODE>
|
||||
<LI> new function: <CODE>lua_geti</CODE>
|
||||
<LI> new function: <CODE>lua_seti</CODE>
|
||||
<LI> new function: <CODE>lua_isyieldable</CODE>
|
||||
<LI> new function: <CODE>lua_numbertointeger</CODE>
|
||||
<LI> new function: <CODE>lua_rotate</CODE>
|
||||
<LI> new function: <CODE>lua_stringtonumber</CODE>
|
||||
</UL>
|
||||
|
||||
<H3>Lua standalone interpreter</H3>
|
||||
<UL>
|
||||
<LI> can be used as calculator; no need to prefix with '='
|
||||
<LI> <CODE>arg</CODE> table available to all code
|
||||
</UL>
|
||||
|
||||
<H2><A NAME="license">License</A></H2>
|
||||
<A HREF="http://www.opensource.org/docs/definition.php">
|
||||
<IMG SRC="osi-certified-72x60.png" ALIGN="right" BORDER="0" ALT="[osi certified]" STYLE="padding-left: 30px ;">
|
||||
</A>
|
||||
|
||||
<P>
|
||||
Lua is free software distributed under the terms of the
|
||||
<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A>
|
||||
reproduced below;
|
||||
it may be used for any purpose, including commercial purposes,
|
||||
at absolutely no cost without having to ask us.
|
||||
|
||||
The only requirement is that if you do use Lua,
|
||||
then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.
|
||||
|
||||
For details, see
|
||||
<A HREF="http://www.lua.org/license.html">this</A>.
|
||||
|
||||
<BLOCKQUOTE STYLE="padding-bottom: 0em">
|
||||
Copyright © 1994–2015 Lua.org, PUC-Rio.
|
||||
|
||||
<P>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
<P>
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
<P>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</BLOCKQUOTE>
|
||||
<P>
|
||||
|
||||
<HR>
|
||||
<SMALL CLASS="footer">
|
||||
Last update:
|
||||
Fri Dec 12 09:58:42 BRST 2014
|
||||
</SMALL>
|
||||
<!--
|
||||
Last change: updated for Lua 5.3.0 (final)
|
||||
-->
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
# Makefile for building Lua
|
||||
# See ../doc/readme.html for installation and customization instructions.
|
||||
|
||||
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
|
||||
|
||||
# Your platform. See PLATS for possible values.
|
||||
PLAT= none
|
||||
|
||||
CC= gcc -std=gnu99
|
||||
CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 $(SYSCFLAGS) $(MYCFLAGS)
|
||||
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
|
||||
LIBS= -lm $(SYSLIBS) $(MYLIBS)
|
||||
|
||||
AR= ar rcu
|
||||
RANLIB= ranlib
|
||||
RM= rm -f
|
||||
|
||||
SYSCFLAGS=
|
||||
SYSLDFLAGS=
|
||||
SYSLIBS=
|
||||
|
||||
MYCFLAGS=
|
||||
MYLDFLAGS=
|
||||
MYLIBS=
|
||||
MYOBJS=
|
||||
|
||||
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
|
||||
|
||||
PLATS= aix bsd c89 freebsd generic linux macosx mingw posix solaris
|
||||
|
||||
LUA_A= liblua.a
|
||||
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \
|
||||
lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \
|
||||
ltm.o lundump.o lvm.o lzio.o
|
||||
LIB_O= lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \
|
||||
lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o
|
||||
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
|
||||
|
||||
LUA_T= lua
|
||||
LUA_O= lua.o
|
||||
|
||||
LUAC_T= luac
|
||||
LUAC_O= luac.o
|
||||
|
||||
ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
|
||||
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
|
||||
ALL_A= $(LUA_A)
|
||||
|
||||
# Targets start here.
|
||||
default: $(PLAT)
|
||||
|
||||
all: $(ALL_T)
|
||||
|
||||
o: $(ALL_O)
|
||||
|
||||
a: $(ALL_A)
|
||||
|
||||
$(LUA_A): $(BASE_O)
|
||||
$(AR) $@ $(BASE_O)
|
||||
$(RANLIB) $@
|
||||
|
||||
$(LUA_T): $(LUA_O) $(LUA_A)
|
||||
$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
|
||||
|
||||
$(LUAC_T): $(LUAC_O) $(LUA_A)
|
||||
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) $(ALL_T) $(ALL_O)
|
||||
|
||||
depend:
|
||||
@$(CC) $(CFLAGS) -MM l*.c
|
||||
|
||||
echo:
|
||||
@echo "PLAT= $(PLAT)"
|
||||
@echo "CC= $(CC)"
|
||||
@echo "CFLAGS= $(CFLAGS)"
|
||||
@echo "LDFLAGS= $(SYSLDFLAGS)"
|
||||
@echo "LIBS= $(LIBS)"
|
||||
@echo "AR= $(AR)"
|
||||
@echo "RANLIB= $(RANLIB)"
|
||||
@echo "RM= $(RM)"
|
||||
|
||||
# Convenience targets for popular platforms
|
||||
ALL= all
|
||||
|
||||
none:
|
||||
@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
|
||||
@echo " $(PLATS)"
|
||||
|
||||
aix:
|
||||
$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
|
||||
|
||||
bsd:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
|
||||
|
||||
c89:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
|
||||
@echo ''
|
||||
@echo '*** C89 does not guarantee 64-bit integers for Lua.'
|
||||
@echo ''
|
||||
|
||||
|
||||
freebsd:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline"
|
||||
|
||||
generic: $(ALL)
|
||||
|
||||
linux:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
|
||||
|
||||
macosx:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc
|
||||
|
||||
mingw:
|
||||
$(MAKE) "LUA_A=lua53.dll" "LUA_T=lua.exe" \
|
||||
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
|
||||
"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe
|
||||
$(MAKE) "LUAC_T=luac.exe" luac.exe
|
||||
|
||||
posix:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
|
||||
|
||||
solaris:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
|
||||
|
||||
# list targets that do not create files (but not all makes understand .PHONY)
|
||||
.PHONY: all $(PLATS) default o a clean depend echo none
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
|
||||
ltable.h lundump.h lvm.h
|
||||
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
|
||||
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
||||
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
||||
ldo.h lgc.h lstring.h ltable.h lvm.h
|
||||
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
|
||||
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
|
||||
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
|
||||
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
|
||||
lparser.h lstring.h ltable.h lundump.h lvm.h
|
||||
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
|
||||
ltm.h lzio.h lmem.h lundump.h
|
||||
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \
|
||||
lgc.h lstate.h ltm.h lzio.h lmem.h
|
||||
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
|
||||
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
|
||||
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldo.h \
|
||||
lobject.h lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h \
|
||||
ltable.h
|
||||
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
|
||||
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
|
||||
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
|
||||
lvm.h
|
||||
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
|
||||
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
||||
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
||||
ldo.h lfunc.h lstring.h lgc.h ltable.h
|
||||
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
|
||||
lstring.h ltable.h
|
||||
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
||||
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
|
||||
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
|
||||
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h
|
||||
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h lobject.h llimits.h \
|
||||
lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
|
||||
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
||||
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
|
||||
lundump.h
|
||||
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
|
||||
ltable.h lvm.h
|
||||
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
|
||||
lobject.h ltm.h lzio.h
|
||||
|
||||
# (end of Makefile)
|
||||
+1270
File diff suppressed because it is too large
Load Diff
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
** $Id: lapi.h,v 2.8 2014/07/15 21:26:50 roberto Exp $
|
||||
** Auxiliary functions from Lua API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lapi_h
|
||||
#define lapi_h
|
||||
|
||||
|
||||
#include "llimits.h"
|
||||
#include "lstate.h"
|
||||
|
||||
#define api_incr_top(L) {L->top++; api_check(L->top <= L->ci->top, \
|
||||
"stack overflow");}
|
||||
|
||||
#define adjustresults(L,nres) \
|
||||
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
|
||||
|
||||
#define api_checknelems(L,n) api_check((n) < (L->top - L->ci->func), \
|
||||
"not enough elements in the stack")
|
||||
|
||||
|
||||
#endif
|
||||
+972
@@ -0,0 +1,972 @@
|
||||
/*
|
||||
** $Id: lauxlib.c,v 1.279 2014/12/14 18:32:26 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lauxlib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* This file uses only the official API of Lua.
|
||||
** Any function declared here could be written as an application function.
|
||||
*/
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Traceback
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
#define LEVELS1 12 /* size of the first part of the stack */
|
||||
#define LEVELS2 10 /* size of the second part of the stack */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** search for 'objidx' in table at index -1.
|
||||
** return 1 + string at top if find a good name.
|
||||
*/
|
||||
static int findfield (lua_State *L, int objidx, int level) {
|
||||
if (level == 0 || !lua_istable(L, -1))
|
||||
return 0; /* not found */
|
||||
lua_pushnil(L); /* start 'next' loop */
|
||||
while (lua_next(L, -2)) { /* for each pair in table */
|
||||
if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */
|
||||
if (lua_rawequal(L, objidx, -1)) { /* found object? */
|
||||
lua_pop(L, 1); /* remove value (but keep name) */
|
||||
return 1;
|
||||
}
|
||||
else if (findfield(L, objidx, level - 1)) { /* try recursively */
|
||||
lua_remove(L, -2); /* remove table (but keep name) */
|
||||
lua_pushliteral(L, ".");
|
||||
lua_insert(L, -2); /* place '.' between the two names */
|
||||
lua_concat(L, 3);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1); /* remove value */
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Search for a name for a function in all loaded modules
|
||||
** (registry._LOADED).
|
||||
*/
|
||||
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
||||
int top = lua_gettop(L);
|
||||
lua_getinfo(L, "f", ar); /* push function */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
|
||||
if (findfield(L, top + 1, 2)) {
|
||||
const char *name = lua_tostring(L, -1);
|
||||
if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
|
||||
lua_pushstring(L, name + 3); /* push name without prefix */
|
||||
lua_remove(L, -2); /* remove original name */
|
||||
}
|
||||
lua_copy(L, -1, top + 1); /* move name to proper place */
|
||||
lua_pop(L, 2); /* remove pushed values */
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_settop(L, top); /* remove function and global table */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
||||
if (pushglobalfuncname(L, ar)) { /* try first a global name */
|
||||
lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
|
||||
lua_remove(L, -2); /* remove name */
|
||||
}
|
||||
else if (*ar->namewhat != '\0') /* is there a name from code? */
|
||||
lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */
|
||||
else if (*ar->what == 'm') /* main? */
|
||||
lua_pushliteral(L, "main chunk");
|
||||
else if (*ar->what != 'C') /* for Lua functions, use <file:line> */
|
||||
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
|
||||
else /* nothing left... */
|
||||
lua_pushliteral(L, "?");
|
||||
}
|
||||
|
||||
|
||||
static int countlevels (lua_State *L) {
|
||||
lua_Debug ar;
|
||||
int li = 1, le = 1;
|
||||
/* find an upper bound */
|
||||
while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
|
||||
/* do a binary search */
|
||||
while (li < le) {
|
||||
int m = (li + le)/2;
|
||||
if (lua_getstack(L, m, &ar)) li = m + 1;
|
||||
else le = m;
|
||||
}
|
||||
return le - 1;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
|
||||
const char *msg, int level) {
|
||||
lua_Debug ar;
|
||||
int top = lua_gettop(L);
|
||||
int numlevels = countlevels(L1);
|
||||
int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
|
||||
if (msg) lua_pushfstring(L, "%s\n", msg);
|
||||
lua_pushliteral(L, "stack traceback:");
|
||||
while (lua_getstack(L1, level++, &ar)) {
|
||||
if (level == mark) { /* too many levels? */
|
||||
lua_pushliteral(L, "\n\t..."); /* add a '...' */
|
||||
level = numlevels - LEVELS2; /* and skip to last ones */
|
||||
}
|
||||
else {
|
||||
lua_getinfo(L1, "Slnt", &ar);
|
||||
lua_pushfstring(L, "\n\t%s:", ar.short_src);
|
||||
if (ar.currentline > 0)
|
||||
lua_pushfstring(L, "%d:", ar.currentline);
|
||||
lua_pushliteral(L, " in ");
|
||||
pushfuncname(L, &ar);
|
||||
if (ar.istailcall)
|
||||
lua_pushliteral(L, "\n\t(...tail calls...)");
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
}
|
||||
}
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Error-report functions
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
|
||||
lua_Debug ar;
|
||||
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
|
||||
return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
|
||||
lua_getinfo(L, "n", &ar);
|
||||
if (strcmp(ar.namewhat, "method") == 0) {
|
||||
arg--; /* do not count 'self' */
|
||||
if (arg == 0) /* error is in the self argument itself? */
|
||||
return luaL_error(L, "calling '%s' on bad self (%s)",
|
||||
ar.name, extramsg);
|
||||
}
|
||||
if (ar.name == NULL)
|
||||
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
|
||||
return luaL_error(L, "bad argument #%d to '%s' (%s)",
|
||||
arg, ar.name, extramsg);
|
||||
}
|
||||
|
||||
|
||||
static int typeerror (lua_State *L, int arg, const char *tname) {
|
||||
const char *msg;
|
||||
const char *typearg; /* name for the type of the actual argument */
|
||||
if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
|
||||
typearg = lua_tostring(L, -1); /* use the given type name */
|
||||
else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA)
|
||||
typearg = "light userdata"; /* special name for messages */
|
||||
else
|
||||
typearg = luaL_typename(L, arg); /* standard name */
|
||||
msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg);
|
||||
return luaL_argerror(L, arg, msg);
|
||||
}
|
||||
|
||||
|
||||
static void tag_error (lua_State *L, int arg, int tag) {
|
||||
typeerror(L, arg, lua_typename(L, tag));
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_where (lua_State *L, int level) {
|
||||
lua_Debug ar;
|
||||
if (lua_getstack(L, level, &ar)) { /* check function at level */
|
||||
lua_getinfo(L, "Sl", &ar); /* get info about it */
|
||||
if (ar.currentline > 0) { /* is there info? */
|
||||
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lua_pushliteral(L, ""); /* else, no information available... */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
luaL_where(L, 1);
|
||||
lua_pushvfstring(L, fmt, argp);
|
||||
va_end(argp);
|
||||
lua_concat(L, 2);
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
||||
int en = errno; /* calls to Lua API may change this value */
|
||||
if (stat) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
if (fname)
|
||||
lua_pushfstring(L, "%s: %s", fname, strerror(en));
|
||||
else
|
||||
lua_pushstring(L, strerror(en));
|
||||
lua_pushinteger(L, en);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !defined(l_inspectstat) /* { */
|
||||
|
||||
#if defined(LUA_USE_POSIX)
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
/*
|
||||
** use appropriate macros to interpret 'pclose' return status
|
||||
*/
|
||||
#define l_inspectstat(stat,what) \
|
||||
if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
|
||||
else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
|
||||
|
||||
#else
|
||||
|
||||
#define l_inspectstat(stat,what) /* no op */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
LUALIB_API int luaL_execresult (lua_State *L, int stat) {
|
||||
const char *what = "exit"; /* type of termination */
|
||||
if (stat == -1) /* error? */
|
||||
return luaL_fileresult(L, 0, NULL);
|
||||
else {
|
||||
l_inspectstat(stat, what); /* interpret result */
|
||||
if (*what == 'e' && stat == 0) /* successful termination? */
|
||||
lua_pushboolean(L, 1);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, what);
|
||||
lua_pushinteger(L, stat);
|
||||
return 3; /* return true/nil,what,code */
|
||||
}
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Userdata's metatable manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
|
||||
if (luaL_getmetatable(L, tname)) /* name already in use? */
|
||||
return 0; /* leave previous value on top, but return 0 */
|
||||
lua_pop(L, 1);
|
||||
lua_newtable(L); /* create metatable */
|
||||
lua_pushstring(L, tname);
|
||||
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
|
||||
luaL_getmetatable(L, tname);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {
|
||||
void *p = lua_touserdata(L, ud);
|
||||
if (p != NULL) { /* value is a userdata? */
|
||||
if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
|
||||
luaL_getmetatable(L, tname); /* get correct metatable */
|
||||
if (!lua_rawequal(L, -1, -2)) /* not the same? */
|
||||
p = NULL; /* value is a userdata with wrong metatable */
|
||||
lua_pop(L, 2); /* remove both metatables */
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL; /* value is not a userdata with a metatable */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
|
||||
void *p = luaL_testudata(L, ud, tname);
|
||||
if (p == NULL) typeerror(L, ud, tname);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Argument check functions
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
|
||||
const char *const lst[]) {
|
||||
const char *name = (def) ? luaL_optstring(L, arg, def) :
|
||||
luaL_checkstring(L, arg);
|
||||
int i;
|
||||
for (i=0; lst[i]; i++)
|
||||
if (strcmp(lst[i], name) == 0)
|
||||
return i;
|
||||
return luaL_argerror(L, arg,
|
||||
lua_pushfstring(L, "invalid option '%s'", name));
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
|
||||
/* keep some extra space to run error routines, if needed */
|
||||
const int extra = LUA_MINSTACK;
|
||||
if (!lua_checkstack(L, space + extra)) {
|
||||
if (msg)
|
||||
luaL_error(L, "stack overflow (%s)", msg);
|
||||
else
|
||||
luaL_error(L, "stack overflow");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
|
||||
if (lua_type(L, arg) != t)
|
||||
tag_error(L, arg, t);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checkany (lua_State *L, int arg) {
|
||||
if (lua_type(L, arg) == LUA_TNONE)
|
||||
luaL_argerror(L, arg, "value expected");
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
|
||||
const char *s = lua_tolstring(L, arg, len);
|
||||
if (!s) tag_error(L, arg, LUA_TSTRING);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_optlstring (lua_State *L, int arg,
|
||||
const char *def, size_t *len) {
|
||||
if (lua_isnoneornil(L, arg)) {
|
||||
if (len)
|
||||
*len = (def ? strlen(def) : 0);
|
||||
return def;
|
||||
}
|
||||
else return luaL_checklstring(L, arg, len);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
|
||||
int isnum;
|
||||
lua_Number d = lua_tonumberx(L, arg, &isnum);
|
||||
if (!isnum)
|
||||
tag_error(L, arg, LUA_TNUMBER);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) {
|
||||
return luaL_opt(L, luaL_checknumber, arg, def);
|
||||
}
|
||||
|
||||
|
||||
static void interror (lua_State *L, int arg) {
|
||||
if (lua_isnumber(L, arg))
|
||||
luaL_argerror(L, arg, "number has no integer representation");
|
||||
else
|
||||
tag_error(L, arg, LUA_TNUMBER);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
|
||||
int isnum;
|
||||
lua_Integer d = lua_tointegerx(L, arg, &isnum);
|
||||
if (!isnum) {
|
||||
interror(L, arg);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
|
||||
lua_Integer def) {
|
||||
return luaL_opt(L, luaL_checkinteger, arg, def);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** check whether buffer is using a userdata on the stack as a temporary
|
||||
** buffer
|
||||
*/
|
||||
#define buffonstack(B) ((B)->b != (B)->initb)
|
||||
|
||||
|
||||
/*
|
||||
** returns a pointer to a free area with at least 'sz' bytes
|
||||
*/
|
||||
LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
|
||||
lua_State *L = B->L;
|
||||
if (B->size - B->n < sz) { /* not enough space? */
|
||||
char *newbuff;
|
||||
size_t newsize = B->size * 2; /* double buffer size */
|
||||
if (newsize - B->n < sz) /* not big enough? */
|
||||
newsize = B->n + sz;
|
||||
if (newsize < B->n || newsize - B->n < sz)
|
||||
luaL_error(L, "buffer too large");
|
||||
/* create larger buffer */
|
||||
newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
|
||||
/* move content to new buffer */
|
||||
memcpy(newbuff, B->b, B->n * sizeof(char));
|
||||
if (buffonstack(B))
|
||||
lua_remove(L, -2); /* remove old buffer */
|
||||
B->b = newbuff;
|
||||
B->size = newsize;
|
||||
}
|
||||
return &B->b[B->n];
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
|
||||
char *b = luaL_prepbuffsize(B, l);
|
||||
memcpy(b, s, l * sizeof(char));
|
||||
luaL_addsize(B, l);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
||||
luaL_addlstring(B, s, strlen(s));
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
||||
lua_State *L = B->L;
|
||||
lua_pushlstring(L, B->b, B->n);
|
||||
if (buffonstack(B))
|
||||
lua_remove(L, -2); /* remove old buffer */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
|
||||
luaL_addsize(B, sz);
|
||||
luaL_pushresult(B);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
|
||||
lua_State *L = B->L;
|
||||
size_t l;
|
||||
const char *s = lua_tolstring(L, -1, &l);
|
||||
if (buffonstack(B))
|
||||
lua_insert(L, -2); /* put value below buffer */
|
||||
luaL_addlstring(B, s, l);
|
||||
lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
|
||||
B->L = L;
|
||||
B->b = B->initb;
|
||||
B->n = 0;
|
||||
B->size = LUAL_BUFFERSIZE;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
|
||||
luaL_buffinit(L, B);
|
||||
return luaL_prepbuffsize(B, sz);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Reference system
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
/* index of free-list header */
|
||||
#define freelist 0
|
||||
|
||||
|
||||
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
||||
int ref;
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); /* remove from stack */
|
||||
return LUA_REFNIL; /* 'nil' has a unique fixed reference */
|
||||
}
|
||||
t = lua_absindex(L, t);
|
||||
lua_rawgeti(L, t, freelist); /* get first free element */
|
||||
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
|
||||
lua_pop(L, 1); /* remove it from stack */
|
||||
if (ref != 0) { /* any free element? */
|
||||
lua_rawgeti(L, t, ref); /* remove it from list */
|
||||
lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
|
||||
}
|
||||
else /* no free elements */
|
||||
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
|
||||
lua_rawseti(L, t, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
||||
if (ref >= 0) {
|
||||
t = lua_absindex(L, t);
|
||||
lua_rawgeti(L, t, freelist);
|
||||
lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
|
||||
lua_pushinteger(L, ref);
|
||||
lua_rawseti(L, t, freelist); /* t[freelist] = ref */
|
||||
}
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Load functions
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
typedef struct LoadF {
|
||||
int n; /* number of pre-read characters */
|
||||
FILE *f; /* file being read */
|
||||
char buff[BUFSIZ]; /* area for reading file */
|
||||
} LoadF;
|
||||
|
||||
|
||||
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
||||
LoadF *lf = (LoadF *)ud;
|
||||
(void)L; /* not used */
|
||||
if (lf->n > 0) { /* are there pre-read characters to be read? */
|
||||
*size = lf->n; /* return them (chars already in buffer) */
|
||||
lf->n = 0; /* no more pre-read characters */
|
||||
}
|
||||
else { /* read a block from file */
|
||||
/* 'fread' can return > 0 *and* set the EOF flag. If next call to
|
||||
'getF' called 'fread', it might still wait for user input.
|
||||
The next check avoids this problem. */
|
||||
if (feof(lf->f)) return NULL;
|
||||
*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */
|
||||
}
|
||||
return lf->buff;
|
||||
}
|
||||
|
||||
|
||||
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
||||
const char *serr = strerror(errno);
|
||||
const char *filename = lua_tostring(L, fnameindex) + 1;
|
||||
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
|
||||
lua_remove(L, fnameindex);
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
|
||||
|
||||
static int skipBOM (LoadF *lf) {
|
||||
const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
|
||||
int c;
|
||||
lf->n = 0;
|
||||
do {
|
||||
c = getc(lf->f);
|
||||
if (c == EOF || c != *(const unsigned char *)p++) return c;
|
||||
lf->buff[lf->n++] = c; /* to be read by the parser */
|
||||
} while (*p != '\0');
|
||||
lf->n = 0; /* prefix matched; discard it */
|
||||
return getc(lf->f); /* return next character */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** reads the first character of file 'f' and skips an optional BOM mark
|
||||
** in its beginning plus its first line if it starts with '#'. Returns
|
||||
** true if it skipped the first line. In any case, '*cp' has the
|
||||
** first "valid" character of the file (after the optional BOM and
|
||||
** a first-line comment).
|
||||
*/
|
||||
static int skipcomment (LoadF *lf, int *cp) {
|
||||
int c = *cp = skipBOM(lf);
|
||||
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
||||
do { /* skip first line */
|
||||
c = getc(lf->f);
|
||||
} while (c != EOF && c != '\n') ;
|
||||
*cp = getc(lf->f); /* skip end-of-line, if present */
|
||||
return 1; /* there was a comment */
|
||||
}
|
||||
else return 0; /* no comment */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
||||
const char *mode) {
|
||||
LoadF lf;
|
||||
int status, readstatus;
|
||||
int c;
|
||||
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
|
||||
if (filename == NULL) {
|
||||
lua_pushliteral(L, "=stdin");
|
||||
lf.f = stdin;
|
||||
}
|
||||
else {
|
||||
lua_pushfstring(L, "@%s", filename);
|
||||
lf.f = fopen(filename, "r");
|
||||
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
||||
}
|
||||
if (skipcomment(&lf, &c)) /* read initial portion */
|
||||
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
|
||||
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
|
||||
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
||||
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
||||
skipcomment(&lf, &c); /* re-read initial portion */
|
||||
}
|
||||
if (c != EOF)
|
||||
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
|
||||
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
|
||||
readstatus = ferror(lf.f);
|
||||
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
||||
if (readstatus) {
|
||||
lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
|
||||
return errfile(L, "read", fnameindex);
|
||||
}
|
||||
lua_remove(L, fnameindex);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
typedef struct LoadS {
|
||||
const char *s;
|
||||
size_t size;
|
||||
} LoadS;
|
||||
|
||||
|
||||
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
||||
LoadS *ls = (LoadS *)ud;
|
||||
(void)L; /* not used */
|
||||
if (ls->size == 0) return NULL;
|
||||
*size = ls->size;
|
||||
ls->size = 0;
|
||||
return ls->s;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
|
||||
const char *name, const char *mode) {
|
||||
LoadS ls;
|
||||
ls.s = buff;
|
||||
ls.size = size;
|
||||
return lua_load(L, getS, &ls, name, mode);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
|
||||
return luaL_loadbuffer(L, s, strlen(s), s);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
|
||||
if (!lua_getmetatable(L, obj)) /* no metatable? */
|
||||
return LUA_TNIL;
|
||||
else {
|
||||
int tt;
|
||||
lua_pushstring(L, event);
|
||||
tt = lua_rawget(L, -2);
|
||||
if (tt == LUA_TNIL) /* is metafield nil? */
|
||||
lua_pop(L, 2); /* remove metatable and metafield */
|
||||
else
|
||||
lua_remove(L, -2); /* remove only metatable */
|
||||
return tt; /* return metafield type */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
|
||||
obj = lua_absindex(L, obj);
|
||||
if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */
|
||||
return 0;
|
||||
lua_pushvalue(L, obj);
|
||||
lua_call(L, 1, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
|
||||
lua_Integer l;
|
||||
int isnum;
|
||||
lua_len(L, idx);
|
||||
l = lua_tointegerx(L, -1, &isnum);
|
||||
if (!isnum)
|
||||
luaL_error(L, "object length is not an integer");
|
||||
lua_pop(L, 1); /* remove object */
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
||||
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
|
||||
switch (lua_type(L, idx)) {
|
||||
case LUA_TNUMBER: {
|
||||
if (lua_isinteger(L, idx))
|
||||
lua_pushfstring(L, "%I", lua_tointeger(L, idx));
|
||||
else
|
||||
lua_pushfstring(L, "%f", lua_tonumber(L, idx));
|
||||
break;
|
||||
}
|
||||
case LUA_TSTRING:
|
||||
lua_pushvalue(L, idx);
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
|
||||
break;
|
||||
case LUA_TNIL:
|
||||
lua_pushliteral(L, "nil");
|
||||
break;
|
||||
default:
|
||||
lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
|
||||
lua_topointer(L, idx));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return lua_tolstring(L, -1, len);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Compatibility with 5.1 module functions
|
||||
** =======================================================
|
||||
*/
|
||||
#if defined(LUA_COMPAT_MODULE)
|
||||
|
||||
static const char *luaL_findtable (lua_State *L, int idx,
|
||||
const char *fname, int szhint) {
|
||||
const char *e;
|
||||
if (idx) lua_pushvalue(L, idx);
|
||||
do {
|
||||
e = strchr(fname, '.');
|
||||
if (e == NULL) e = fname + strlen(fname);
|
||||
lua_pushlstring(L, fname, e - fname);
|
||||
if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */
|
||||
lua_pop(L, 1); /* remove this nil */
|
||||
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
|
||||
lua_pushlstring(L, fname, e - fname);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, -4); /* set new table into field */
|
||||
}
|
||||
else if (!lua_istable(L, -1)) { /* field has a non-table value? */
|
||||
lua_pop(L, 2); /* remove table and value */
|
||||
return fname; /* return problematic part of the name */
|
||||
}
|
||||
lua_remove(L, -2); /* remove previous table */
|
||||
fname = e + 1;
|
||||
} while (*e == '.');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Count number of elements in a luaL_Reg list.
|
||||
*/
|
||||
static int libsize (const luaL_Reg *l) {
|
||||
int size = 0;
|
||||
for (; l && l->name; l++) size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find or create a module table with a given name. The function
|
||||
** first looks at the _LOADED table and, if that fails, try a
|
||||
** global variable with that name. In any case, leaves on the stack
|
||||
** the module table.
|
||||
*/
|
||||
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
|
||||
int sizehint) {
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
|
||||
if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
|
||||
lua_pop(L, 1); /* remove previous result */
|
||||
/* try global variable (and create one if it does not exist) */
|
||||
lua_pushglobaltable(L);
|
||||
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
|
||||
luaL_error(L, "name conflict for module '%s'", modname);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
|
||||
}
|
||||
lua_remove(L, -2); /* remove _LOADED table */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l, int nup) {
|
||||
luaL_checkversion(L);
|
||||
if (libname) {
|
||||
luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */
|
||||
lua_insert(L, -(nup + 1)); /* move library table to below upvalues */
|
||||
}
|
||||
if (l)
|
||||
luaL_setfuncs(L, l, nup);
|
||||
else
|
||||
lua_pop(L, nup); /* remove upvalues */
|
||||
}
|
||||
|
||||
#endif
|
||||
/* }====================================================== */
|
||||
|
||||
/*
|
||||
** set functions from list 'l' into table at top - 'nup'; each
|
||||
** function gets the 'nup' elements at the top as upvalues.
|
||||
** Returns with only the table at the stack.
|
||||
*/
|
||||
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
||||
luaL_checkstack(L, nup, "too many upvalues");
|
||||
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
||||
int i;
|
||||
for (i = 0; i < nup; i++) /* copy upvalues to the top */
|
||||
lua_pushvalue(L, -nup);
|
||||
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
|
||||
lua_setfield(L, -(nup + 2), l->name);
|
||||
}
|
||||
lua_pop(L, nup); /* remove upvalues */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** ensure that stack[idx][fname] has a table and push that table
|
||||
** into the stack
|
||||
*/
|
||||
LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
|
||||
if (lua_getfield(L, idx, fname) == LUA_TTABLE)
|
||||
return 1; /* table already there */
|
||||
else {
|
||||
lua_pop(L, 1); /* remove previous result */
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_newtable(L);
|
||||
lua_pushvalue(L, -1); /* copy to be left at top */
|
||||
lua_setfield(L, idx, fname); /* assign new table to field */
|
||||
return 0; /* false, because did not find table there */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Stripped-down 'require': After checking "loaded" table, calls 'openf'
|
||||
** to open a module, registers the result in 'package.loaded' table and,
|
||||
** if 'glb' is true, also registers the result in the global table.
|
||||
** Leaves resulting module on the top.
|
||||
*/
|
||||
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
|
||||
lua_CFunction openf, int glb) {
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
|
||||
lua_getfield(L, -1, modname); /* _LOADED[modname] */
|
||||
if (!lua_toboolean(L, -1)) { /* package not already loaded? */
|
||||
lua_pop(L, 1); /* remove field */
|
||||
lua_pushcfunction(L, openf);
|
||||
lua_pushstring(L, modname); /* argument to open function */
|
||||
lua_call(L, 1, 1); /* call 'openf' to open module */
|
||||
lua_pushvalue(L, -1); /* make copy of module (call result) */
|
||||
lua_setfield(L, -3, modname); /* _LOADED[modname] = module */
|
||||
}
|
||||
lua_remove(L, -2); /* remove _LOADED table */
|
||||
if (glb) {
|
||||
lua_pushvalue(L, -1); /* copy of module */
|
||||
lua_setglobal(L, modname); /* _G[modname] = module */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
|
||||
const char *r) {
|
||||
const char *wild;
|
||||
size_t l = strlen(p);
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
while ((wild = strstr(s, p)) != NULL) {
|
||||
luaL_addlstring(&b, s, wild - s); /* push prefix */
|
||||
luaL_addstring(&b, r); /* push replacement in place of pattern */
|
||||
s = wild + l; /* continue after 'p' */
|
||||
}
|
||||
luaL_addstring(&b, s); /* push last suffix */
|
||||
luaL_pushresult(&b);
|
||||
return lua_tostring(L, -1);
|
||||
}
|
||||
|
||||
|
||||
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||
(void)ud; (void)osize; /* not used */
|
||||
if (nsize == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return realloc(ptr, nsize);
|
||||
}
|
||||
|
||||
|
||||
static int panic (lua_State *L) {
|
||||
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
||||
lua_tostring(L, -1));
|
||||
return 0; /* return to Lua to abort */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_State *luaL_newstate (void) {
|
||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
||||
if (L) lua_atpanic(L, &panic);
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
|
||||
const lua_Number *v = lua_version(L);
|
||||
if (sz != LUAL_NUMSIZES) /* check numeric types */
|
||||
luaL_error(L, "core and library have incompatible numeric types");
|
||||
if (v != lua_version(NULL))
|
||||
luaL_error(L, "multiple Lua VMs detected");
|
||||
else if (*v != ver)
|
||||
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
|
||||
ver, *v);
|
||||
}
|
||||
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lauxlib_h
|
||||
#define lauxlib_h
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
|
||||
/* extra error code for 'luaL_load' */
|
||||
#define LUA_ERRFILE (LUA_ERRERR+1)
|
||||
|
||||
|
||||
typedef struct luaL_Reg {
|
||||
const char *name;
|
||||
lua_CFunction func;
|
||||
} luaL_Reg;
|
||||
|
||||
|
||||
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
|
||||
|
||||
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
|
||||
#define luaL_checkversion(L) \
|
||||
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
|
||||
|
||||
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
|
||||
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
|
||||
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
|
||||
size_t *l);
|
||||
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
|
||||
const char *def, size_t *l);
|
||||
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
|
||||
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
|
||||
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
|
||||
lua_Integer def);
|
||||
|
||||
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
|
||||
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
|
||||
LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
|
||||
|
||||
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
|
||||
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
|
||||
|
||||
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
|
||||
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
|
||||
|
||||
LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
|
||||
const char *const lst[]);
|
||||
|
||||
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
|
||||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
||||
|
||||
/* pre-defined references */
|
||||
#define LUA_NOREF (-2)
|
||||
#define LUA_REFNIL (-1)
|
||||
|
||||
LUALIB_API int (luaL_ref) (lua_State *L, int t);
|
||||
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
|
||||
|
||||
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
|
||||
const char *mode);
|
||||
|
||||
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
|
||||
|
||||
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
|
||||
const char *name, const char *mode);
|
||||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
||||
|
||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
||||
|
||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
|
||||
const char *r);
|
||||
|
||||
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
|
||||
|
||||
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
|
||||
|
||||
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
|
||||
const char *msg, int level);
|
||||
|
||||
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
||||
lua_CFunction openf, int glb);
|
||||
|
||||
/*
|
||||
** ===============================================================
|
||||
** some useful macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
|
||||
#define luaL_newlibtable(L,l) \
|
||||
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
|
||||
|
||||
#define luaL_newlib(L,l) \
|
||||
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
||||
|
||||
#define luaL_argcheck(L, cond,arg,extramsg) \
|
||||
((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
|
||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
||||
|
||||
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
|
||||
|
||||
#define luaL_dofile(L, fn) \
|
||||
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_dostring(L, s) \
|
||||
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
||||
|
||||
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
|
||||
|
||||
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
typedef struct luaL_Buffer {
|
||||
char *b; /* buffer address */
|
||||
size_t size; /* buffer size */
|
||||
size_t n; /* number of characters in buffer */
|
||||
lua_State *L;
|
||||
char initb[LUAL_BUFFERSIZE]; /* initial buffer */
|
||||
} luaL_Buffer;
|
||||
|
||||
|
||||
#define luaL_addchar(B,c) \
|
||||
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
|
||||
((B)->b[(B)->n++] = (c)))
|
||||
|
||||
#define luaL_addsize(B,s) ((B)->n += (s))
|
||||
|
||||
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
|
||||
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
|
||||
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
|
||||
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
|
||||
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
|
||||
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
|
||||
|
||||
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** File handles for IO library
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
|
||||
** initial structure 'luaL_Stream' (it may contain other fields
|
||||
** after that initial structure).
|
||||
*/
|
||||
|
||||
#define LUA_FILEHANDLE "FILE*"
|
||||
|
||||
|
||||
typedef struct luaL_Stream {
|
||||
FILE *f; /* stream (NULL for incompletely created streams) */
|
||||
lua_CFunction closef; /* to close stream (NULL for closed streams) */
|
||||
} luaL_Stream;
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
/* compatibility with old module system */
|
||||
#if defined(LUA_COMPAT_MODULE)
|
||||
|
||||
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
|
||||
int sizehint);
|
||||
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l, int nup);
|
||||
|
||||
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** "Abstraction Layer" for basic report of messages and errors
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/* print a string */
|
||||
#if !defined(lua_writestring)
|
||||
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
|
||||
#endif
|
||||
|
||||
/* print a newline and flush the output */
|
||||
#if !defined(lua_writeline)
|
||||
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
|
||||
#endif
|
||||
|
||||
/* print an error message */
|
||||
#if !defined(lua_writestringerror)
|
||||
#define lua_writestringerror(s,p) \
|
||||
(fprintf(stderr, (s), (p)), fflush(stderr))
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {============================================================
|
||||
** Compatibility with deprecated conversions
|
||||
** =============================================================
|
||||
*/
|
||||
#if defined(LUA_COMPAT_APIINTCASTS)
|
||||
|
||||
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
|
||||
#define luaL_optunsigned(L,a,d) \
|
||||
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
|
||||
|
||||
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#endif
|
||||
/* }============================================================ */
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+520
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
** $Id: lbaselib.c,v 1.309 2014/12/10 12:26:42 roberto Exp $
|
||||
** Basic library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lbaselib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
static int luaB_print (lua_State *L) {
|
||||
int n = lua_gettop(L); /* number of arguments */
|
||||
int i;
|
||||
lua_getglobal(L, "tostring");
|
||||
for (i=1; i<=n; i++) {
|
||||
const char *s;
|
||||
size_t l;
|
||||
lua_pushvalue(L, -1); /* function to be called */
|
||||
lua_pushvalue(L, i); /* value to print */
|
||||
lua_call(L, 1, 1);
|
||||
s = lua_tolstring(L, -1, &l); /* get result */
|
||||
if (s == NULL)
|
||||
return luaL_error(L, "'tostring' must return a string to 'print'");
|
||||
if (i>1) lua_writestring("\t", 1);
|
||||
lua_writestring(s, l);
|
||||
lua_pop(L, 1); /* pop result */
|
||||
}
|
||||
lua_writeline();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define SPACECHARS " \f\n\r\t\v"
|
||||
|
||||
static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
|
||||
lua_Unsigned n = 0;
|
||||
int neg = 0;
|
||||
s += strspn(s, SPACECHARS); /* skip initial spaces */
|
||||
if (*s == '-') { s++; neg = 1; } /* handle signal */
|
||||
else if (*s == '+') s++;
|
||||
if (!isalnum((unsigned char)*s)) /* no digit? */
|
||||
return NULL;
|
||||
do {
|
||||
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
|
||||
: toupper((unsigned char)*s) - 'A' + 10;
|
||||
if (digit >= base) return NULL; /* invalid numeral */
|
||||
n = n * base + digit;
|
||||
s++;
|
||||
} while (isalnum((unsigned char)*s));
|
||||
s += strspn(s, SPACECHARS); /* skip trailing spaces */
|
||||
*pn = (lua_Integer)((neg) ? (0u - n) : n);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_tonumber (lua_State *L) {
|
||||
if (lua_isnoneornil(L, 2)) { /* standard conversion? */
|
||||
luaL_checkany(L, 1);
|
||||
if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */
|
||||
lua_settop(L, 1); /* yes; return it */
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
size_t l;
|
||||
const char *s = lua_tolstring(L, 1, &l);
|
||||
if (s != NULL && lua_stringtonumber(L, s) == l + 1)
|
||||
return 1; /* successful conversion to number */
|
||||
/* else not a number */
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t l;
|
||||
const char *s;
|
||||
lua_Integer n = 0; /* to avoid warnings */
|
||||
lua_Integer base = luaL_checkinteger(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TSTRING); /* before 'luaL_checklstring'! */
|
||||
s = luaL_checklstring(L, 1, &l);
|
||||
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
||||
if (b_str2int(s, (int)base, &n) == s + l) {
|
||||
lua_pushinteger(L, n);
|
||||
return 1;
|
||||
} /* else not a number */
|
||||
} /* else not a number */
|
||||
lua_pushnil(L); /* not a number */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_error (lua_State *L) {
|
||||
int level = (int)luaL_optinteger(L, 2, 1);
|
||||
lua_settop(L, 1);
|
||||
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
|
||||
luaL_where(L, level);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_getmetatable (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
lua_pushnil(L);
|
||||
return 1; /* no metatable */
|
||||
}
|
||||
luaL_getmetafield(L, 1, "__metatable");
|
||||
return 1; /* returns either __metatable field (if present) or metatable */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_setmetatable (lua_State *L) {
|
||||
int t = lua_type(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
|
||||
"nil or table expected");
|
||||
if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)
|
||||
return luaL_error(L, "cannot change a protected metatable");
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawequal (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
luaL_checkany(L, 2);
|
||||
lua_pushboolean(L, lua_rawequal(L, 1, 2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawlen (lua_State *L) {
|
||||
int t = lua_type(L, 1);
|
||||
luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
|
||||
"table or string expected");
|
||||
lua_pushinteger(L, lua_rawlen(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawget (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checkany(L, 2);
|
||||
lua_settop(L, 2);
|
||||
lua_rawget(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaB_rawset (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checkany(L, 2);
|
||||
luaL_checkany(L, 3);
|
||||
lua_settop(L, 3);
|
||||
lua_rawset(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_collectgarbage (lua_State *L) {
|
||||
static const char *const opts[] = {"stop", "restart", "collect",
|
||||
"count", "step", "setpause", "setstepmul",
|
||||
"isrunning", NULL};
|
||||
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
|
||||
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
|
||||
LUA_GCISRUNNING};
|
||||
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
|
||||
int ex = (int)luaL_optinteger(L, 2, 0);
|
||||
int res = lua_gc(L, o, ex);
|
||||
switch (o) {
|
||||
case LUA_GCCOUNT: {
|
||||
int b = lua_gc(L, LUA_GCCOUNTB, 0);
|
||||
lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024));
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCSTEP: case LUA_GCISRUNNING: {
|
||||
lua_pushboolean(L, res);
|
||||
return 1;
|
||||
}
|
||||
default: {
|
||||
lua_pushinteger(L, res);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function has all type names as upvalues, to maximize performance.
|
||||
*/
|
||||
static int luaB_type (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
lua_pushvalue(L, lua_upvalueindex(lua_type(L, 1) + 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int pairsmeta (lua_State *L, const char *method, int iszero,
|
||||
lua_CFunction iter) {
|
||||
if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */
|
||||
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
|
||||
lua_pushcfunction(L, iter); /* will return generator, */
|
||||
lua_pushvalue(L, 1); /* state, */
|
||||
if (iszero) lua_pushinteger(L, 0); /* and initial value */
|
||||
else lua_pushnil(L);
|
||||
}
|
||||
else {
|
||||
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
||||
lua_call(L, 1, 3); /* get 3 values from metamethod */
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_next (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_settop(L, 2); /* create a 2nd argument if there isn't one */
|
||||
if (lua_next(L, 1))
|
||||
return 2;
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_pairs (lua_State *L) {
|
||||
return pairsmeta(L, "__pairs", 0, luaB_next);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traversal function for 'ipairs' for raw tables
|
||||
*/
|
||||
static int ipairsaux_raw (lua_State *L) {
|
||||
lua_Integer i = luaL_checkinteger(L, 2) + 1;
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_pushinteger(L, i);
|
||||
return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traversal function for 'ipairs' for tables with metamethods
|
||||
*/
|
||||
static int ipairsaux (lua_State *L) {
|
||||
lua_Integer i = luaL_checkinteger(L, 2) + 1;
|
||||
lua_pushinteger(L, i);
|
||||
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to
|
||||
** traverse a table, depending on whether the table has metamethods
|
||||
** that can affect the traversal.
|
||||
*/
|
||||
static int luaB_ipairs (lua_State *L) {
|
||||
lua_CFunction iter = (luaL_getmetafield(L, 1, "__index") != LUA_TNIL)
|
||||
? ipairsaux : ipairsaux_raw;
|
||||
#if defined(LUA_COMPAT_IPAIRS)
|
||||
return pairsmeta(L, "__ipairs", 1, iter);
|
||||
#else
|
||||
luaL_checkany(L, 1);
|
||||
lua_pushcfunction(L, iter); /* iteration function */
|
||||
lua_pushvalue(L, 1); /* state */
|
||||
lua_pushinteger(L, 0); /* initial value */
|
||||
return 3;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int load_aux (lua_State *L, int status, int envidx) {
|
||||
if (status == LUA_OK) {
|
||||
if (envidx != 0) { /* 'env' parameter? */
|
||||
lua_pushvalue(L, envidx); /* environment for loaded function */
|
||||
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
|
||||
lua_pop(L, 1); /* remove 'env' if not used by previous call */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else { /* error (message is on top of the stack) */
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2); /* put before error message */
|
||||
return 2; /* return nil plus error message */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_loadfile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
const char *mode = luaL_optstring(L, 2, NULL);
|
||||
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
|
||||
int status = luaL_loadfilex(L, fname, mode);
|
||||
return load_aux(L, status, env);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Read function
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** reserved slot, above all arguments, to hold a copy of the returned
|
||||
** string to avoid it being collected while parsed. 'load' has four
|
||||
** optional arguments (chunk, source name, mode, and environment).
|
||||
*/
|
||||
#define RESERVEDSLOT 5
|
||||
|
||||
|
||||
/*
|
||||
** Reader for generic 'load' function: 'lua_load' uses the
|
||||
** stack for internal stuff, so the reader cannot change the
|
||||
** stack top. Instead, it keeps its resulting string in a
|
||||
** reserved slot inside the stack.
|
||||
*/
|
||||
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
||||
(void)(ud); /* not used */
|
||||
luaL_checkstack(L, 2, "too many nested functions");
|
||||
lua_pushvalue(L, 1); /* get function */
|
||||
lua_call(L, 0, 1); /* call it */
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); /* pop result */
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
else if (!lua_isstring(L, -1))
|
||||
luaL_error(L, "reader function must return a string");
|
||||
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
|
||||
return lua_tolstring(L, RESERVEDSLOT, size);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_load (lua_State *L) {
|
||||
int status;
|
||||
size_t l;
|
||||
const char *s = lua_tolstring(L, 1, &l);
|
||||
const char *mode = luaL_optstring(L, 3, "bt");
|
||||
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
|
||||
if (s != NULL) { /* loading a string? */
|
||||
const char *chunkname = luaL_optstring(L, 2, s);
|
||||
status = luaL_loadbufferx(L, s, l, chunkname, mode);
|
||||
}
|
||||
else { /* loading from a reader function */
|
||||
const char *chunkname = luaL_optstring(L, 2, "=(load)");
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
|
||||
status = lua_load(L, generic_reader, NULL, chunkname, mode);
|
||||
}
|
||||
return load_aux(L, status, env);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
|
||||
(void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */
|
||||
return lua_gettop(L) - 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_dofile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
lua_settop(L, 1);
|
||||
if (luaL_loadfile(L, fname) != LUA_OK)
|
||||
return lua_error(L);
|
||||
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
||||
return dofilecont(L, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_assert (lua_State *L) {
|
||||
if (lua_toboolean(L, 1)) /* condition is true? */
|
||||
return lua_gettop(L); /* return all arguments */
|
||||
else { /* error */
|
||||
luaL_checkany(L, 1); /* there must be a condition */
|
||||
lua_remove(L, 1); /* remove it */
|
||||
lua_pushliteral(L, "assertion failed!"); /* default message */
|
||||
lua_settop(L, 1); /* leave only message (default if no other one) */
|
||||
return luaB_error(L); /* call 'error' */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_select (lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
|
||||
lua_pushinteger(L, n-1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_Integer i = luaL_checkinteger(L, 1);
|
||||
if (i < 0) i = n + i;
|
||||
else if (i > n) i = n;
|
||||
luaL_argcheck(L, 1 <= i, 1, "index out of range");
|
||||
return n - (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Continuation function for 'pcall' and 'xpcall'. Both functions
|
||||
** already pushed a 'true' before doing the call, so in case of success
|
||||
** 'finishpcall' only has to return everything in the stack minus
|
||||
** 'extra' values (where 'extra' is exactly the number of items to be
|
||||
** ignored).
|
||||
*/
|
||||
static int finishpcall (lua_State *L, int status, lua_KContext extra) {
|
||||
if (status != LUA_OK && status != LUA_YIELD) { /* error? */
|
||||
lua_pushboolean(L, 0); /* first result (false) */
|
||||
lua_pushvalue(L, -2); /* error message */
|
||||
return 2; /* return false, msg */
|
||||
}
|
||||
else
|
||||
return lua_gettop(L) - (int)extra; /* return all results */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_pcall (lua_State *L) {
|
||||
int status;
|
||||
luaL_checkany(L, 1);
|
||||
lua_pushboolean(L, 1); /* first result if no errors */
|
||||
lua_insert(L, 1); /* put it in place */
|
||||
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);
|
||||
return finishpcall(L, status, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Do a protected call with error handling. After 'lua_rotate', the
|
||||
** stack will have <f, err, true, f, [args...]>; so, the function passes
|
||||
** 2 to 'finishpcall' to skip the 2 first values when returning results.
|
||||
*/
|
||||
static int luaB_xpcall (lua_State *L) {
|
||||
int status;
|
||||
int n = lua_gettop(L);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */
|
||||
lua_pushboolean(L, 1); /* first result */
|
||||
lua_pushvalue(L, 1); /* function */
|
||||
lua_rotate(L, 3, 2); /* move them below function's arguments */
|
||||
status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);
|
||||
return finishpcall(L, status, 2);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_tostring (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
luaL_tolstring(L, 1, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg base_funcs[] = {
|
||||
{"assert", luaB_assert},
|
||||
{"collectgarbage", luaB_collectgarbage},
|
||||
{"dofile", luaB_dofile},
|
||||
{"error", luaB_error},
|
||||
{"getmetatable", luaB_getmetatable},
|
||||
{"ipairs", luaB_ipairs},
|
||||
{"loadfile", luaB_loadfile},
|
||||
{"load", luaB_load},
|
||||
#if defined(LUA_COMPAT_LOADSTRING)
|
||||
{"loadstring", luaB_load},
|
||||
#endif
|
||||
{"next", luaB_next},
|
||||
{"pairs", luaB_pairs},
|
||||
{"pcall", luaB_pcall},
|
||||
{"print", luaB_print},
|
||||
{"rawequal", luaB_rawequal},
|
||||
{"rawlen", luaB_rawlen},
|
||||
{"rawget", luaB_rawget},
|
||||
{"rawset", luaB_rawset},
|
||||
{"select", luaB_select},
|
||||
{"setmetatable", luaB_setmetatable},
|
||||
{"tonumber", luaB_tonumber},
|
||||
{"tostring", luaB_tostring},
|
||||
{"xpcall", luaB_xpcall},
|
||||
/* placeholders */
|
||||
{"type", NULL},
|
||||
{"_G", NULL},
|
||||
{"_VERSION", NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_base (lua_State *L) {
|
||||
int i;
|
||||
/* open lib into global table */
|
||||
lua_pushglobaltable(L);
|
||||
luaL_setfuncs(L, base_funcs, 0);
|
||||
/* set global _G */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "_G");
|
||||
/* set global _VERSION */
|
||||
lua_pushliteral(L, LUA_VERSION);
|
||||
lua_setfield(L, -2, "_VERSION");
|
||||
/* set function 'type' with proper upvalues */
|
||||
for (i = 0; i < LUA_NUMTAGS; i++) /* push all type names as upvalues */
|
||||
lua_pushstring(L, lua_typename(L, i));
|
||||
lua_pushcclosure(L, luaB_type, LUA_NUMTAGS);
|
||||
lua_setfield(L, -2, "type");
|
||||
return 1;
|
||||
}
|
||||
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
** $Id: lbitlib.c,v 1.28 2014/11/02 19:19:04 roberto Exp $
|
||||
** Standard library for bitwise operations
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lbitlib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
#if defined(LUA_COMPAT_BITLIB) /* { */
|
||||
|
||||
|
||||
/* number of bits to consider in a number */
|
||||
#if !defined(LUA_NBITS)
|
||||
#define LUA_NBITS 32
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must
|
||||
** be made in two parts to avoid problems when LUA_NBITS is equal to the
|
||||
** number of bits in a lua_Unsigned.)
|
||||
*/
|
||||
#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
|
||||
|
||||
|
||||
/* macro to trim extra bits */
|
||||
#define trim(x) ((x) & ALLONES)
|
||||
|
||||
|
||||
/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
|
||||
#define mask(n) (~((ALLONES << 1) << ((n) - 1)))
|
||||
|
||||
|
||||
|
||||
static lua_Unsigned andaux (lua_State *L) {
|
||||
int i, n = lua_gettop(L);
|
||||
lua_Unsigned r = ~(lua_Unsigned)0;
|
||||
for (i = 1; i <= n; i++)
|
||||
r &= luaL_checkunsigned(L, i);
|
||||
return trim(r);
|
||||
}
|
||||
|
||||
|
||||
static int b_and (lua_State *L) {
|
||||
lua_Unsigned r = andaux(L);
|
||||
lua_pushunsigned(L, r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_test (lua_State *L) {
|
||||
lua_Unsigned r = andaux(L);
|
||||
lua_pushboolean(L, r != 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_or (lua_State *L) {
|
||||
int i, n = lua_gettop(L);
|
||||
lua_Unsigned r = 0;
|
||||
for (i = 1; i <= n; i++)
|
||||
r |= luaL_checkunsigned(L, i);
|
||||
lua_pushunsigned(L, trim(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_xor (lua_State *L) {
|
||||
int i, n = lua_gettop(L);
|
||||
lua_Unsigned r = 0;
|
||||
for (i = 1; i <= n; i++)
|
||||
r ^= luaL_checkunsigned(L, i);
|
||||
lua_pushunsigned(L, trim(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_not (lua_State *L) {
|
||||
lua_Unsigned r = ~luaL_checkunsigned(L, 1);
|
||||
lua_pushunsigned(L, trim(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {
|
||||
if (i < 0) { /* shift right? */
|
||||
i = -i;
|
||||
r = trim(r);
|
||||
if (i >= LUA_NBITS) r = 0;
|
||||
else r >>= i;
|
||||
}
|
||||
else { /* shift left */
|
||||
if (i >= LUA_NBITS) r = 0;
|
||||
else r <<= i;
|
||||
r = trim(r);
|
||||
}
|
||||
lua_pushunsigned(L, r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_lshift (lua_State *L) {
|
||||
return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkinteger(L, 2));
|
||||
}
|
||||
|
||||
|
||||
static int b_rshift (lua_State *L) {
|
||||
return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkinteger(L, 2));
|
||||
}
|
||||
|
||||
|
||||
static int b_arshift (lua_State *L) {
|
||||
lua_Unsigned r = luaL_checkunsigned(L, 1);
|
||||
lua_Integer i = luaL_checkinteger(L, 2);
|
||||
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
|
||||
return b_shift(L, r, -i);
|
||||
else { /* arithmetic shift for 'negative' number */
|
||||
if (i >= LUA_NBITS) r = ALLONES;
|
||||
else
|
||||
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
|
||||
lua_pushunsigned(L, r);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int b_rot (lua_State *L, lua_Integer d) {
|
||||
lua_Unsigned r = luaL_checkunsigned(L, 1);
|
||||
int i = d & (LUA_NBITS - 1); /* i = d % NBITS */
|
||||
r = trim(r);
|
||||
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
|
||||
r = (r << i) | (r >> (LUA_NBITS - i));
|
||||
lua_pushunsigned(L, trim(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_lrot (lua_State *L) {
|
||||
return b_rot(L, luaL_checkinteger(L, 2));
|
||||
}
|
||||
|
||||
|
||||
static int b_rrot (lua_State *L) {
|
||||
return b_rot(L, -luaL_checkinteger(L, 2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** get field and width arguments for field-manipulation functions,
|
||||
** checking whether they are valid.
|
||||
** ('luaL_error' called without 'return' to avoid later warnings about
|
||||
** 'width' being used uninitialized.)
|
||||
*/
|
||||
static int fieldargs (lua_State *L, int farg, int *width) {
|
||||
lua_Integer f = luaL_checkinteger(L, farg);
|
||||
lua_Integer w = luaL_optinteger(L, farg + 1, 1);
|
||||
luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
|
||||
luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
|
||||
if (f + w > LUA_NBITS)
|
||||
luaL_error(L, "trying to access non-existent bits");
|
||||
*width = (int)w;
|
||||
return (int)f;
|
||||
}
|
||||
|
||||
|
||||
static int b_extract (lua_State *L) {
|
||||
int w;
|
||||
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
|
||||
int f = fieldargs(L, 2, &w);
|
||||
r = (r >> f) & mask(w);
|
||||
lua_pushunsigned(L, r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int b_replace (lua_State *L) {
|
||||
int w;
|
||||
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
|
||||
lua_Unsigned v = luaL_checkunsigned(L, 2);
|
||||
int f = fieldargs(L, 3, &w);
|
||||
int m = mask(w);
|
||||
v &= m; /* erase bits outside given width */
|
||||
r = (r & ~(m << f)) | (v << f);
|
||||
lua_pushunsigned(L, r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg bitlib[] = {
|
||||
{"arshift", b_arshift},
|
||||
{"band", b_and},
|
||||
{"bnot", b_not},
|
||||
{"bor", b_or},
|
||||
{"bxor", b_xor},
|
||||
{"btest", b_test},
|
||||
{"extract", b_extract},
|
||||
{"lrotate", b_lrot},
|
||||
{"lshift", b_lshift},
|
||||
{"replace", b_replace},
|
||||
{"rrotate", b_rrot},
|
||||
{"rshift", b_rshift},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_bit32 (lua_State *L) {
|
||||
luaL_newlib(L, bitlib);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_bit32 (lua_State *L) {
|
||||
return luaL_error(L, "library 'bit32' has been deprecated");
|
||||
}
|
||||
|
||||
#endif /* } */
|
||||
+954
@@ -0,0 +1,954 @@
|
||||
/*
|
||||
** $Id: lcode.c,v 2.99 2014/12/29 16:49:25 roberto Exp $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lcode_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lcode.h"
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lgc.h"
|
||||
#include "llex.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "lvm.h"
|
||||
|
||||
|
||||
/* Maximum number of registers in a Lua function */
|
||||
#define MAXREGS 250
|
||||
|
||||
|
||||
#define hasjumps(e) ((e)->t != (e)->f)
|
||||
|
||||
|
||||
static int tonumeral(expdesc *e, TValue *v) {
|
||||
if (e->t != NO_JUMP || e->f != NO_JUMP)
|
||||
return 0; /* not a numeral */
|
||||
switch (e->k) {
|
||||
case VKINT:
|
||||
if (v) setivalue(v, e->u.ival);
|
||||
return 1;
|
||||
case VKFLT:
|
||||
if (v) setfltvalue(v, e->u.nval);
|
||||
return 1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_nil (FuncState *fs, int from, int n) {
|
||||
Instruction *previous;
|
||||
int l = from + n - 1; /* last register to set nil */
|
||||
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
|
||||
previous = &fs->f->code[fs->pc-1];
|
||||
if (GET_OPCODE(*previous) == OP_LOADNIL) {
|
||||
int pfrom = GETARG_A(*previous);
|
||||
int pl = pfrom + GETARG_B(*previous);
|
||||
if ((pfrom <= from && from <= pl + 1) ||
|
||||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
|
||||
if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
|
||||
if (pl > l) l = pl; /* l = max(l, pl) */
|
||||
SETARG_A(*previous, from);
|
||||
SETARG_B(*previous, l - from);
|
||||
return;
|
||||
}
|
||||
} /* else go through */
|
||||
}
|
||||
luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
|
||||
}
|
||||
|
||||
|
||||
int luaK_jump (FuncState *fs) {
|
||||
int jpc = fs->jpc; /* save list of jumps to here */
|
||||
int j;
|
||||
fs->jpc = NO_JUMP;
|
||||
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
|
||||
luaK_concat(fs, &j, jpc); /* keep them on hold */
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
void luaK_ret (FuncState *fs, int first, int nret) {
|
||||
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
|
||||
}
|
||||
|
||||
|
||||
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
|
||||
luaK_codeABC(fs, op, A, B, C);
|
||||
return luaK_jump(fs);
|
||||
}
|
||||
|
||||
|
||||
static void fixjump (FuncState *fs, int pc, int dest) {
|
||||
Instruction *jmp = &fs->f->code[pc];
|
||||
int offset = dest-(pc+1);
|
||||
lua_assert(dest != NO_JUMP);
|
||||
if (abs(offset) > MAXARG_sBx)
|
||||
luaX_syntaxerror(fs->ls, "control structure too long");
|
||||
SETARG_sBx(*jmp, offset);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** returns current 'pc' and marks it as a jump target (to avoid wrong
|
||||
** optimizations with consecutive instructions not in the same basic block).
|
||||
*/
|
||||
int luaK_getlabel (FuncState *fs) {
|
||||
fs->lasttarget = fs->pc;
|
||||
return fs->pc;
|
||||
}
|
||||
|
||||
|
||||
static int getjump (FuncState *fs, int pc) {
|
||||
int offset = GETARG_sBx(fs->f->code[pc]);
|
||||
if (offset == NO_JUMP) /* point to itself represents end of list */
|
||||
return NO_JUMP; /* end of list */
|
||||
else
|
||||
return (pc+1)+offset; /* turn offset into absolute position */
|
||||
}
|
||||
|
||||
|
||||
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
|
||||
Instruction *pi = &fs->f->code[pc];
|
||||
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
|
||||
return pi-1;
|
||||
else
|
||||
return pi;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** check whether list has any jump that do not produce a value
|
||||
** (or produce an inverted value)
|
||||
*/
|
||||
static int need_value (FuncState *fs, int list) {
|
||||
for (; list != NO_JUMP; list = getjump(fs, list)) {
|
||||
Instruction i = *getjumpcontrol(fs, list);
|
||||
if (GET_OPCODE(i) != OP_TESTSET) return 1;
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
static int patchtestreg (FuncState *fs, int node, int reg) {
|
||||
Instruction *i = getjumpcontrol(fs, node);
|
||||
if (GET_OPCODE(*i) != OP_TESTSET)
|
||||
return 0; /* cannot patch other instructions */
|
||||
if (reg != NO_REG && reg != GETARG_B(*i))
|
||||
SETARG_A(*i, reg);
|
||||
else /* no register to put value or register already has the value */
|
||||
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void removevalues (FuncState *fs, int list) {
|
||||
for (; list != NO_JUMP; list = getjump(fs, list))
|
||||
patchtestreg(fs, list, NO_REG);
|
||||
}
|
||||
|
||||
|
||||
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
|
||||
int dtarget) {
|
||||
while (list != NO_JUMP) {
|
||||
int next = getjump(fs, list);
|
||||
if (patchtestreg(fs, list, reg))
|
||||
fixjump(fs, list, vtarget);
|
||||
else
|
||||
fixjump(fs, list, dtarget); /* jump to default target */
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dischargejpc (FuncState *fs) {
|
||||
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
|
||||
fs->jpc = NO_JUMP;
|
||||
}
|
||||
|
||||
|
||||
void luaK_patchlist (FuncState *fs, int list, int target) {
|
||||
if (target == fs->pc)
|
||||
luaK_patchtohere(fs, list);
|
||||
else {
|
||||
lua_assert(target < fs->pc);
|
||||
patchlistaux(fs, list, target, NO_REG, target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_patchclose (FuncState *fs, int list, int level) {
|
||||
level++; /* argument is +1 to reserve 0 as non-op */
|
||||
while (list != NO_JUMP) {
|
||||
int next = getjump(fs, list);
|
||||
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
|
||||
(GETARG_A(fs->f->code[list]) == 0 ||
|
||||
GETARG_A(fs->f->code[list]) >= level));
|
||||
SETARG_A(fs->f->code[list], level);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_patchtohere (FuncState *fs, int list) {
|
||||
luaK_getlabel(fs);
|
||||
luaK_concat(fs, &fs->jpc, list);
|
||||
}
|
||||
|
||||
|
||||
void luaK_concat (FuncState *fs, int *l1, int l2) {
|
||||
if (l2 == NO_JUMP) return;
|
||||
else if (*l1 == NO_JUMP)
|
||||
*l1 = l2;
|
||||
else {
|
||||
int list = *l1;
|
||||
int next;
|
||||
while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
|
||||
list = next;
|
||||
fixjump(fs, list, l2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaK_code (FuncState *fs, Instruction i) {
|
||||
Proto *f = fs->f;
|
||||
dischargejpc(fs); /* 'pc' will change */
|
||||
/* put new instruction in code array */
|
||||
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
|
||||
MAX_INT, "opcodes");
|
||||
f->code[fs->pc] = i;
|
||||
/* save corresponding line information */
|
||||
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
|
||||
MAX_INT, "opcodes");
|
||||
f->lineinfo[fs->pc] = fs->ls->lastline;
|
||||
return fs->pc++;
|
||||
}
|
||||
|
||||
|
||||
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
|
||||
lua_assert(getOpMode(o) == iABC);
|
||||
lua_assert(getBMode(o) != OpArgN || b == 0);
|
||||
lua_assert(getCMode(o) != OpArgN || c == 0);
|
||||
lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
|
||||
return luaK_code(fs, CREATE_ABC(o, a, b, c));
|
||||
}
|
||||
|
||||
|
||||
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
|
||||
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
|
||||
lua_assert(getCMode(o) == OpArgN);
|
||||
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
|
||||
return luaK_code(fs, CREATE_ABx(o, a, bc));
|
||||
}
|
||||
|
||||
|
||||
static int codeextraarg (FuncState *fs, int a) {
|
||||
lua_assert(a <= MAXARG_Ax);
|
||||
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
|
||||
}
|
||||
|
||||
|
||||
int luaK_codek (FuncState *fs, int reg, int k) {
|
||||
if (k <= MAXARG_Bx)
|
||||
return luaK_codeABx(fs, OP_LOADK, reg, k);
|
||||
else {
|
||||
int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
|
||||
codeextraarg(fs, k);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_checkstack (FuncState *fs, int n) {
|
||||
int newstack = fs->freereg + n;
|
||||
if (newstack > fs->f->maxstacksize) {
|
||||
if (newstack >= MAXREGS)
|
||||
luaX_syntaxerror(fs->ls, "function or expression too complex");
|
||||
fs->f->maxstacksize = cast_byte(newstack);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_reserveregs (FuncState *fs, int n) {
|
||||
luaK_checkstack(fs, n);
|
||||
fs->freereg += n;
|
||||
}
|
||||
|
||||
|
||||
static void freereg (FuncState *fs, int reg) {
|
||||
if (!ISK(reg) && reg >= fs->nactvar) {
|
||||
fs->freereg--;
|
||||
lua_assert(reg == fs->freereg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void freeexp (FuncState *fs, expdesc *e) {
|
||||
if (e->k == VNONRELOC)
|
||||
freereg(fs, e->u.info);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Use scanner's table to cache position of constants in constant list
|
||||
** and try to reuse constants
|
||||
*/
|
||||
static int addk (FuncState *fs, TValue *key, TValue *v) {
|
||||
lua_State *L = fs->ls->L;
|
||||
Proto *f = fs->f;
|
||||
TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */
|
||||
int k, oldsize;
|
||||
if (ttisinteger(idx)) { /* is there an index there? */
|
||||
k = cast_int(ivalue(idx));
|
||||
/* correct value? (warning: must distinguish floats from integers!) */
|
||||
if (k < fs->nk && ttype(&f->k[k]) == ttype(v) &&
|
||||
luaV_rawequalobj(&f->k[k], v))
|
||||
return k; /* reuse index */
|
||||
}
|
||||
/* constant not found; create a new entry */
|
||||
oldsize = f->sizek;
|
||||
k = fs->nk;
|
||||
/* numerical value does not need GC barrier;
|
||||
table has no metatable, so it does not need to invalidate cache */
|
||||
setivalue(idx, k);
|
||||
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
|
||||
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
|
||||
setobj(L, &f->k[k], v);
|
||||
fs->nk++;
|
||||
luaC_barrier(L, f, v);
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
int luaK_stringK (FuncState *fs, TString *s) {
|
||||
TValue o;
|
||||
setsvalue(fs->ls->L, &o, s);
|
||||
return addk(fs, &o, &o);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Integers use userdata as keys to avoid collision with floats with same
|
||||
** value; conversion to 'void*' used only for hashing, no "precision"
|
||||
** problems
|
||||
*/
|
||||
int luaK_intK (FuncState *fs, lua_Integer n) {
|
||||
TValue k, o;
|
||||
setpvalue(&k, cast(void*, cast(size_t, n)));
|
||||
setivalue(&o, n);
|
||||
return addk(fs, &k, &o);
|
||||
}
|
||||
|
||||
|
||||
static int luaK_numberK (FuncState *fs, lua_Number r) {
|
||||
TValue o;
|
||||
setfltvalue(&o, r);
|
||||
return addk(fs, &o, &o);
|
||||
}
|
||||
|
||||
|
||||
static int boolK (FuncState *fs, int b) {
|
||||
TValue o;
|
||||
setbvalue(&o, b);
|
||||
return addk(fs, &o, &o);
|
||||
}
|
||||
|
||||
|
||||
static int nilK (FuncState *fs) {
|
||||
TValue k, v;
|
||||
setnilvalue(&v);
|
||||
/* cannot use nil as key; instead use table itself to represent nil */
|
||||
sethvalue(fs->ls->L, &k, fs->ls->h);
|
||||
return addk(fs, &k, &v);
|
||||
}
|
||||
|
||||
|
||||
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
|
||||
if (e->k == VCALL) { /* expression is an open function call? */
|
||||
SETARG_C(getcode(fs, e), nresults+1);
|
||||
}
|
||||
else if (e->k == VVARARG) {
|
||||
SETARG_B(getcode(fs, e), nresults+1);
|
||||
SETARG_A(getcode(fs, e), fs->freereg);
|
||||
luaK_reserveregs(fs, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_setoneret (FuncState *fs, expdesc *e) {
|
||||
if (e->k == VCALL) { /* expression is an open function call? */
|
||||
e->k = VNONRELOC;
|
||||
e->u.info = GETARG_A(getcode(fs, e));
|
||||
}
|
||||
else if (e->k == VVARARG) {
|
||||
SETARG_B(getcode(fs, e), 2);
|
||||
e->k = VRELOCABLE; /* can relocate its simple result */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
||||
switch (e->k) {
|
||||
case VLOCAL: {
|
||||
e->k = VNONRELOC;
|
||||
break;
|
||||
}
|
||||
case VUPVAL: {
|
||||
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case VINDEXED: {
|
||||
OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
|
||||
freereg(fs, e->u.ind.idx);
|
||||
if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
|
||||
freereg(fs, e->u.ind.t);
|
||||
op = OP_GETTABLE;
|
||||
}
|
||||
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case VVARARG:
|
||||
case VCALL: {
|
||||
luaK_setoneret(fs, e);
|
||||
break;
|
||||
}
|
||||
default: break; /* there is one value available (somewhere) */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int code_label (FuncState *fs, int A, int b, int jump) {
|
||||
luaK_getlabel(fs); /* those instructions may be jump targets */
|
||||
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
|
||||
}
|
||||
|
||||
|
||||
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VNIL: {
|
||||
luaK_nil(fs, reg, 1);
|
||||
break;
|
||||
}
|
||||
case VFALSE: case VTRUE: {
|
||||
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
|
||||
break;
|
||||
}
|
||||
case VK: {
|
||||
luaK_codek(fs, reg, e->u.info);
|
||||
break;
|
||||
}
|
||||
case VKFLT: {
|
||||
luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
|
||||
break;
|
||||
}
|
||||
case VKINT: {
|
||||
luaK_codek(fs, reg, luaK_intK(fs, e->u.ival));
|
||||
break;
|
||||
}
|
||||
case VRELOCABLE: {
|
||||
Instruction *pc = &getcode(fs, e);
|
||||
SETARG_A(*pc, reg);
|
||||
break;
|
||||
}
|
||||
case VNONRELOC: {
|
||||
if (reg != e->u.info)
|
||||
luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lua_assert(e->k == VVOID || e->k == VJMP);
|
||||
return; /* nothing to do... */
|
||||
}
|
||||
}
|
||||
e->u.info = reg;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
|
||||
static void discharge2anyreg (FuncState *fs, expdesc *e) {
|
||||
if (e->k != VNONRELOC) {
|
||||
luaK_reserveregs(fs, 1);
|
||||
discharge2reg(fs, e, fs->freereg-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
discharge2reg(fs, e, reg);
|
||||
if (e->k == VJMP)
|
||||
luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */
|
||||
if (hasjumps(e)) {
|
||||
int final; /* position after whole expression */
|
||||
int p_f = NO_JUMP; /* position of an eventual LOAD false */
|
||||
int p_t = NO_JUMP; /* position of an eventual LOAD true */
|
||||
if (need_value(fs, e->t) || need_value(fs, e->f)) {
|
||||
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
|
||||
p_f = code_label(fs, reg, 0, 1);
|
||||
p_t = code_label(fs, reg, 1, 0);
|
||||
luaK_patchtohere(fs, fj);
|
||||
}
|
||||
final = luaK_getlabel(fs);
|
||||
patchlistaux(fs, e->f, final, reg, p_f);
|
||||
patchlistaux(fs, e->t, final, reg, p_t);
|
||||
}
|
||||
e->f = e->t = NO_JUMP;
|
||||
e->u.info = reg;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
|
||||
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
|
||||
luaK_dischargevars(fs, e);
|
||||
freeexp(fs, e);
|
||||
luaK_reserveregs(fs, 1);
|
||||
exp2reg(fs, e, fs->freereg - 1);
|
||||
}
|
||||
|
||||
|
||||
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
|
||||
luaK_dischargevars(fs, e);
|
||||
if (e->k == VNONRELOC) {
|
||||
if (!hasjumps(e)) return e->u.info; /* exp is already in a register */
|
||||
if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
|
||||
exp2reg(fs, e, e->u.info); /* put value on it */
|
||||
return e->u.info;
|
||||
}
|
||||
}
|
||||
luaK_exp2nextreg(fs, e); /* default */
|
||||
return e->u.info;
|
||||
}
|
||||
|
||||
|
||||
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
|
||||
if (e->k != VUPVAL || hasjumps(e))
|
||||
luaK_exp2anyreg(fs, e);
|
||||
}
|
||||
|
||||
|
||||
void luaK_exp2val (FuncState *fs, expdesc *e) {
|
||||
if (hasjumps(e))
|
||||
luaK_exp2anyreg(fs, e);
|
||||
else
|
||||
luaK_dischargevars(fs, e);
|
||||
}
|
||||
|
||||
|
||||
int luaK_exp2RK (FuncState *fs, expdesc *e) {
|
||||
luaK_exp2val(fs, e);
|
||||
switch (e->k) {
|
||||
case VTRUE:
|
||||
case VFALSE:
|
||||
case VNIL: {
|
||||
if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */
|
||||
e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
|
||||
e->k = VK;
|
||||
return RKASK(e->u.info);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
case VKINT: {
|
||||
e->u.info = luaK_intK(fs, e->u.ival);
|
||||
e->k = VK;
|
||||
goto vk;
|
||||
}
|
||||
case VKFLT: {
|
||||
e->u.info = luaK_numberK(fs, e->u.nval);
|
||||
e->k = VK;
|
||||
/* go through */
|
||||
}
|
||||
case VK: {
|
||||
vk:
|
||||
if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */
|
||||
return RKASK(e->u.info);
|
||||
else break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
/* not a constant in the right range: put it in a register */
|
||||
return luaK_exp2anyreg(fs, e);
|
||||
}
|
||||
|
||||
|
||||
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
|
||||
switch (var->k) {
|
||||
case VLOCAL: {
|
||||
freeexp(fs, ex);
|
||||
exp2reg(fs, ex, var->u.info);
|
||||
return;
|
||||
}
|
||||
case VUPVAL: {
|
||||
int e = luaK_exp2anyreg(fs, ex);
|
||||
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
|
||||
break;
|
||||
}
|
||||
case VINDEXED: {
|
||||
OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
|
||||
int e = luaK_exp2RK(fs, ex);
|
||||
luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lua_assert(0); /* invalid var kind to store */
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeexp(fs, ex);
|
||||
}
|
||||
|
||||
|
||||
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
|
||||
int ereg;
|
||||
luaK_exp2anyreg(fs, e);
|
||||
ereg = e->u.info; /* register where 'e' was placed */
|
||||
freeexp(fs, e);
|
||||
e->u.info = fs->freereg; /* base register for op_self */
|
||||
e->k = VNONRELOC;
|
||||
luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */
|
||||
luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
|
||||
freeexp(fs, key);
|
||||
}
|
||||
|
||||
|
||||
static void invertjump (FuncState *fs, expdesc *e) {
|
||||
Instruction *pc = getjumpcontrol(fs, e->u.info);
|
||||
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
|
||||
GET_OPCODE(*pc) != OP_TEST);
|
||||
SETARG_A(*pc, !(GETARG_A(*pc)));
|
||||
}
|
||||
|
||||
|
||||
static int jumponcond (FuncState *fs, expdesc *e, int cond) {
|
||||
if (e->k == VRELOCABLE) {
|
||||
Instruction ie = getcode(fs, e);
|
||||
if (GET_OPCODE(ie) == OP_NOT) {
|
||||
fs->pc--; /* remove previous OP_NOT */
|
||||
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
|
||||
}
|
||||
/* else go through */
|
||||
}
|
||||
discharge2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
|
||||
}
|
||||
|
||||
|
||||
void luaK_goiftrue (FuncState *fs, expdesc *e) {
|
||||
int pc; /* pc of last jump */
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VJMP: {
|
||||
invertjump(fs, e);
|
||||
pc = e->u.info;
|
||||
break;
|
||||
}
|
||||
case VK: case VKFLT: case VKINT: case VTRUE: {
|
||||
pc = NO_JUMP; /* always true; do nothing */
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pc = jumponcond(fs, e, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
luaK_concat(fs, &e->f, pc); /* insert last jump in 'f' list */
|
||||
luaK_patchtohere(fs, e->t);
|
||||
e->t = NO_JUMP;
|
||||
}
|
||||
|
||||
|
||||
void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
||||
int pc; /* pc of last jump */
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VJMP: {
|
||||
pc = e->u.info;
|
||||
break;
|
||||
}
|
||||
case VNIL: case VFALSE: {
|
||||
pc = NO_JUMP; /* always false; do nothing */
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pc = jumponcond(fs, e, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
luaK_concat(fs, &e->t, pc); /* insert last jump in 't' list */
|
||||
luaK_patchtohere(fs, e->f);
|
||||
e->f = NO_JUMP;
|
||||
}
|
||||
|
||||
|
||||
static void codenot (FuncState *fs, expdesc *e) {
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VNIL: case VFALSE: {
|
||||
e->k = VTRUE;
|
||||
break;
|
||||
}
|
||||
case VK: case VKFLT: case VKINT: case VTRUE: {
|
||||
e->k = VFALSE;
|
||||
break;
|
||||
}
|
||||
case VJMP: {
|
||||
invertjump(fs, e);
|
||||
break;
|
||||
}
|
||||
case VRELOCABLE:
|
||||
case VNONRELOC: {
|
||||
discharge2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lua_assert(0); /* cannot happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* interchange true and false lists */
|
||||
{ int temp = e->f; e->f = e->t; e->t = temp; }
|
||||
removevalues(fs, e->f);
|
||||
removevalues(fs, e->t);
|
||||
}
|
||||
|
||||
|
||||
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
||||
lua_assert(!hasjumps(t));
|
||||
t->u.ind.t = t->u.info;
|
||||
t->u.ind.idx = luaK_exp2RK(fs, k);
|
||||
t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
|
||||
: check_exp(vkisinreg(t->k), VLOCAL);
|
||||
t->k = VINDEXED;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** return false if folding can raise an error
|
||||
*/
|
||||
static int validop (int op, TValue *v1, TValue *v2) {
|
||||
switch (op) {
|
||||
case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
|
||||
case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */
|
||||
lua_Integer i;
|
||||
return (tointeger(v1, &i) && tointeger(v2, &i));
|
||||
}
|
||||
case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */
|
||||
return (nvalue(v2) != 0);
|
||||
default: return 1; /* everything else is valid */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to "constant-fold" an operation; return 1 iff successful
|
||||
*/
|
||||
static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
|
||||
TValue v1, v2, res;
|
||||
if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
|
||||
return 0; /* non-numeric operands or not safe to fold */
|
||||
luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */
|
||||
if (ttisinteger(&res)) {
|
||||
e1->k = VKINT;
|
||||
e1->u.ival = ivalue(&res);
|
||||
}
|
||||
else { /* folds neither NaN nor 0.0 (to avoid collapsing with -0.0) */
|
||||
lua_Number n = fltvalue(&res);
|
||||
if (luai_numisnan(n) || n == 0)
|
||||
return 0;
|
||||
e1->k = VKFLT;
|
||||
e1->u.nval = n;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Code for binary and unary expressions that "produce values"
|
||||
** (arithmetic operations, bitwise operations, concat, length). First
|
||||
** try to do constant folding (only for numeric [arithmetic and
|
||||
** bitwise] operations, which is what 'lua_arith' accepts).
|
||||
** Expression to produce final result will be encoded in 'e1'.
|
||||
*/
|
||||
static void codeexpval (FuncState *fs, OpCode op,
|
||||
expdesc *e1, expdesc *e2, int line) {
|
||||
lua_assert(op >= OP_ADD);
|
||||
if (op <= OP_BNOT && constfolding(fs, op - OP_ADD + LUA_OPADD, e1, e2))
|
||||
return; /* result has been folded */
|
||||
else {
|
||||
int o1, o2;
|
||||
/* move operands to registers (if needed) */
|
||||
if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */
|
||||
o2 = 0; /* no second expression */
|
||||
o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */
|
||||
}
|
||||
else { /* regular case (binary operators) */
|
||||
o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
|
||||
o1 = luaK_exp2RK(fs, e1);
|
||||
}
|
||||
if (o1 > o2) { /* free registers in proper order */
|
||||
freeexp(fs, e1);
|
||||
freeexp(fs, e2);
|
||||
}
|
||||
else {
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
}
|
||||
e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */
|
||||
e1->k = VRELOCABLE; /* all those operations are relocable */
|
||||
luaK_fixline(fs, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
|
||||
expdesc *e2) {
|
||||
int o1 = luaK_exp2RK(fs, e1);
|
||||
int o2 = luaK_exp2RK(fs, e2);
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
if (cond == 0 && op != OP_EQ) {
|
||||
int temp; /* exchange args to replace by '<' or '<=' */
|
||||
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
|
||||
cond = 1;
|
||||
}
|
||||
e1->u.info = condjump(fs, op, cond, o1, o2);
|
||||
e1->k = VJMP;
|
||||
}
|
||||
|
||||
|
||||
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
|
||||
expdesc e2;
|
||||
e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
|
||||
switch (op) {
|
||||
case OPR_MINUS: case OPR_BNOT: case OPR_LEN: {
|
||||
codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line);
|
||||
break;
|
||||
}
|
||||
case OPR_NOT: codenot(fs, e); break;
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||
switch (op) {
|
||||
case OPR_AND: {
|
||||
luaK_goiftrue(fs, v);
|
||||
break;
|
||||
}
|
||||
case OPR_OR: {
|
||||
luaK_goiffalse(fs, v);
|
||||
break;
|
||||
}
|
||||
case OPR_CONCAT: {
|
||||
luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */
|
||||
break;
|
||||
}
|
||||
case OPR_ADD: case OPR_SUB:
|
||||
case OPR_MUL: case OPR_DIV: case OPR_IDIV:
|
||||
case OPR_MOD: case OPR_POW:
|
||||
case OPR_BAND: case OPR_BOR: case OPR_BXOR:
|
||||
case OPR_SHL: case OPR_SHR: {
|
||||
if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
luaK_exp2RK(fs, v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_posfix (FuncState *fs, BinOpr op,
|
||||
expdesc *e1, expdesc *e2, int line) {
|
||||
switch (op) {
|
||||
case OPR_AND: {
|
||||
lua_assert(e1->t == NO_JUMP); /* list must be closed */
|
||||
luaK_dischargevars(fs, e2);
|
||||
luaK_concat(fs, &e2->f, e1->f);
|
||||
*e1 = *e2;
|
||||
break;
|
||||
}
|
||||
case OPR_OR: {
|
||||
lua_assert(e1->f == NO_JUMP); /* list must be closed */
|
||||
luaK_dischargevars(fs, e2);
|
||||
luaK_concat(fs, &e2->t, e1->t);
|
||||
*e1 = *e2;
|
||||
break;
|
||||
}
|
||||
case OPR_CONCAT: {
|
||||
luaK_exp2val(fs, e2);
|
||||
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
|
||||
lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
|
||||
freeexp(fs, e1);
|
||||
SETARG_B(getcode(fs, e2), e1->u.info);
|
||||
e1->k = VRELOCABLE; e1->u.info = e2->u.info;
|
||||
}
|
||||
else {
|
||||
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
|
||||
codeexpval(fs, OP_CONCAT, e1, e2, line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
|
||||
case OPR_IDIV: case OPR_MOD: case OPR_POW:
|
||||
case OPR_BAND: case OPR_BOR: case OPR_BXOR:
|
||||
case OPR_SHL: case OPR_SHR: {
|
||||
codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line);
|
||||
break;
|
||||
}
|
||||
case OPR_EQ: case OPR_LT: case OPR_LE: {
|
||||
codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
|
||||
break;
|
||||
}
|
||||
case OPR_NE: case OPR_GT: case OPR_GE: {
|
||||
codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_fixline (FuncState *fs, int line) {
|
||||
fs->f->lineinfo[fs->pc - 1] = line;
|
||||
}
|
||||
|
||||
|
||||
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
|
||||
int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
|
||||
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
|
||||
lua_assert(tostore != 0);
|
||||
if (c <= MAXARG_C)
|
||||
luaK_codeABC(fs, OP_SETLIST, base, b, c);
|
||||
else if (c <= MAXARG_Ax) {
|
||||
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
|
||||
codeextraarg(fs, c);
|
||||
}
|
||||
else
|
||||
luaX_syntaxerror(fs->ls, "constructor too long");
|
||||
fs->freereg = base + 1; /* free registers with list values */
|
||||
}
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lcode_h
|
||||
#define lcode_h
|
||||
|
||||
#include "llex.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
|
||||
|
||||
/*
|
||||
** Marks the end of a patch list. It is an invalid value both as an absolute
|
||||
** address, and as a list link (would link an element to itself).
|
||||
*/
|
||||
#define NO_JUMP (-1)
|
||||
|
||||
|
||||
/*
|
||||
** grep "ORDER OPR" if you change these enums (ORDER OP)
|
||||
*/
|
||||
typedef enum BinOpr {
|
||||
OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,
|
||||
OPR_DIV,
|
||||
OPR_IDIV,
|
||||
OPR_BAND, OPR_BOR, OPR_BXOR,
|
||||
OPR_SHL, OPR_SHR,
|
||||
OPR_CONCAT,
|
||||
OPR_EQ, OPR_LT, OPR_LE,
|
||||
OPR_NE, OPR_GT, OPR_GE,
|
||||
OPR_AND, OPR_OR,
|
||||
OPR_NOBINOPR
|
||||
} BinOpr;
|
||||
|
||||
|
||||
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
|
||||
|
||||
|
||||
#define getcode(fs,e) ((fs)->f->code[(e)->u.info])
|
||||
|
||||
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
|
||||
|
||||
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
|
||||
|
||||
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
|
||||
|
||||
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
|
||||
LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
|
||||
LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);
|
||||
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
||||
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
||||
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
|
||||
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
|
||||
LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
|
||||
LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n);
|
||||
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
||||
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_jump (FuncState *fs);
|
||||
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
|
||||
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
|
||||
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
|
||||
LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
|
||||
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
|
||||
LUAI_FUNC int luaK_getlabel (FuncState *fs);
|
||||
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
|
||||
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
|
||||
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
|
||||
expdesc *v2, int line);
|
||||
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
||||
|
||||
|
||||
#endif
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $
|
||||
** Coroutine Library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lcorolib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
static lua_State *getco (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, 1);
|
||||
luaL_argcheck(L, co, 1, "thread expected");
|
||||
return co;
|
||||
}
|
||||
|
||||
|
||||
static int auxresume (lua_State *L, lua_State *co, int narg) {
|
||||
int status;
|
||||
if (!lua_checkstack(co, narg)) {
|
||||
lua_pushliteral(L, "too many arguments to resume");
|
||||
return -1; /* error flag */
|
||||
}
|
||||
if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
|
||||
lua_pushliteral(L, "cannot resume dead coroutine");
|
||||
return -1; /* error flag */
|
||||
}
|
||||
lua_xmove(L, co, narg);
|
||||
status = lua_resume(co, L, narg);
|
||||
if (status == LUA_OK || status == LUA_YIELD) {
|
||||
int nres = lua_gettop(co);
|
||||
if (!lua_checkstack(L, nres + 1)) {
|
||||
lua_pop(co, nres); /* remove results anyway */
|
||||
lua_pushliteral(L, "too many results to resume");
|
||||
return -1; /* error flag */
|
||||
}
|
||||
lua_xmove(co, L, nres); /* move yielded values */
|
||||
return nres;
|
||||
}
|
||||
else {
|
||||
lua_xmove(co, L, 1); /* move error message */
|
||||
return -1; /* error flag */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_coresume (lua_State *L) {
|
||||
lua_State *co = getco(L);
|
||||
int r;
|
||||
r = auxresume(L, co, lua_gettop(L) - 1);
|
||||
if (r < 0) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_insert(L, -2);
|
||||
return 2; /* return false + error message */
|
||||
}
|
||||
else {
|
||||
lua_pushboolean(L, 1);
|
||||
lua_insert(L, -(r + 1));
|
||||
return r + 1; /* return true + 'resume' returns */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_auxwrap (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
|
||||
int r = auxresume(L, co, lua_gettop(L));
|
||||
if (r < 0) {
|
||||
if (lua_isstring(L, -1)) { /* error object is a string? */
|
||||
luaL_where(L, 1); /* add extra info */
|
||||
lua_insert(L, -2);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
return lua_error(L); /* propagate error */
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_cocreate (lua_State *L) {
|
||||
lua_State *NL;
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
NL = lua_newthread(L);
|
||||
lua_pushvalue(L, 1); /* move function to top */
|
||||
lua_xmove(L, NL, 1); /* move function from L to NL */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_cowrap (lua_State *L) {
|
||||
luaB_cocreate(L);
|
||||
lua_pushcclosure(L, luaB_auxwrap, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_yield (lua_State *L) {
|
||||
return lua_yield(L, lua_gettop(L));
|
||||
}
|
||||
|
||||
|
||||
static int luaB_costatus (lua_State *L) {
|
||||
lua_State *co = getco(L);
|
||||
if (L == co) lua_pushliteral(L, "running");
|
||||
else {
|
||||
switch (lua_status(co)) {
|
||||
case LUA_YIELD:
|
||||
lua_pushliteral(L, "suspended");
|
||||
break;
|
||||
case LUA_OK: {
|
||||
lua_Debug ar;
|
||||
if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
|
||||
lua_pushliteral(L, "normal"); /* it is running */
|
||||
else if (lua_gettop(co) == 0)
|
||||
lua_pushliteral(L, "dead");
|
||||
else
|
||||
lua_pushliteral(L, "suspended"); /* initial state */
|
||||
break;
|
||||
}
|
||||
default: /* some error occurred */
|
||||
lua_pushliteral(L, "dead");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_yieldable (lua_State *L) {
|
||||
lua_pushboolean(L, lua_isyieldable(L));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_corunning (lua_State *L) {
|
||||
int ismain = lua_pushthread(L);
|
||||
lua_pushboolean(L, ismain);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg co_funcs[] = {
|
||||
{"create", luaB_cocreate},
|
||||
{"resume", luaB_coresume},
|
||||
{"running", luaB_corunning},
|
||||
{"status", luaB_costatus},
|
||||
{"wrap", luaB_cowrap},
|
||||
{"yield", luaB_yield},
|
||||
{"isyieldable", luaB_yieldable},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_coroutine (lua_State *L) {
|
||||
luaL_newlib(L, co_funcs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $
|
||||
** 'ctype' functions for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lctype_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include "lctype.h"
|
||||
|
||||
#if !LUA_USE_CTYPE /* { */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
|
||||
0x00, /* EOZ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */
|
||||
0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */
|
||||
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05,
|
||||
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */
|
||||
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#endif /* } */
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $
|
||||
** 'ctype' functions for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lctype_h
|
||||
#define lctype_h
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
/*
|
||||
** WARNING: the functions defined here do not necessarily correspond
|
||||
** to the similar functions in the standard C ctype.h. They are
|
||||
** optimized for the specific needs of Lua
|
||||
*/
|
||||
|
||||
#if !defined(LUA_USE_CTYPE)
|
||||
|
||||
#if 'A' == 65 && '0' == 48
|
||||
/* ASCII case: can use its own tables; faster and fixed */
|
||||
#define LUA_USE_CTYPE 0
|
||||
#else
|
||||
/* must use standard C ctype */
|
||||
#define LUA_USE_CTYPE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !LUA_USE_CTYPE /* { */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "llimits.h"
|
||||
|
||||
|
||||
#define ALPHABIT 0
|
||||
#define DIGITBIT 1
|
||||
#define PRINTBIT 2
|
||||
#define SPACEBIT 3
|
||||
#define XDIGITBIT 4
|
||||
|
||||
|
||||
#define MASK(B) (1 << (B))
|
||||
|
||||
|
||||
/*
|
||||
** add 1 to char to allow index -1 (EOZ)
|
||||
*/
|
||||
#define testprop(c,p) (luai_ctype_[(c)+1] & (p))
|
||||
|
||||
/*
|
||||
** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'
|
||||
*/
|
||||
#define lislalpha(c) testprop(c, MASK(ALPHABIT))
|
||||
#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))
|
||||
#define lisdigit(c) testprop(c, MASK(DIGITBIT))
|
||||
#define lisspace(c) testprop(c, MASK(SPACEBIT))
|
||||
#define lisprint(c) testprop(c, MASK(PRINTBIT))
|
||||
#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
|
||||
|
||||
/*
|
||||
** this 'ltolower' only works for alphabetic characters
|
||||
*/
|
||||
#define ltolower(c) ((c) | ('A' ^ 'a'))
|
||||
|
||||
|
||||
/* two more entries for 0 and -1 (EOZ) */
|
||||
LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];
|
||||
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
/*
|
||||
** use standard C ctypes
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define lislalpha(c) (isalpha(c) || (c) == '_')
|
||||
#define lislalnum(c) (isalnum(c) || (c) == '_')
|
||||
#define lisdigit(c) (isdigit(c))
|
||||
#define lisspace(c) (isspace(c))
|
||||
#define lisprint(c) (isprint(c))
|
||||
#define lisxdigit(c) (isxdigit(c))
|
||||
|
||||
#define ltolower(c) (tolower(c))
|
||||
|
||||
#endif /* } */
|
||||
|
||||
#endif
|
||||
|
||||
+437
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
** $Id: ldblib.c,v 1.148 2015/01/02 12:52:22 roberto Exp $
|
||||
** Interface from Lua to its debug API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define ldblib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
/*
|
||||
** The hook table at registry[&HOOKKEY] maps threads to their current
|
||||
** hook function. (We only need the unique address of 'HOOKKEY'.)
|
||||
*/
|
||||
static const int HOOKKEY = 0;
|
||||
|
||||
|
||||
static int db_getregistry (lua_State *L) {
|
||||
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_getmetatable (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
lua_pushnil(L); /* no metatable */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_setmetatable (lua_State *L) {
|
||||
int t = lua_type(L, 2);
|
||||
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
|
||||
"nil or table expected");
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
return 1; /* return 1st argument */
|
||||
}
|
||||
|
||||
|
||||
static int db_getuservalue (lua_State *L) {
|
||||
if (lua_type(L, 1) != LUA_TUSERDATA)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
lua_getuservalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_setuservalue (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TUSERDATA);
|
||||
luaL_checkany(L, 2);
|
||||
lua_settop(L, 2);
|
||||
lua_setuservalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Auxiliary function used by several library functions: check for
|
||||
** an optional thread as function's first argument and set 'arg' with
|
||||
** 1 if this argument is present (so that functions can skip it to
|
||||
** access their other arguments)
|
||||
*/
|
||||
static lua_State *getthread (lua_State *L, int *arg) {
|
||||
if (lua_isthread(L, 1)) {
|
||||
*arg = 1;
|
||||
return lua_tothread(L, 1);
|
||||
}
|
||||
else {
|
||||
*arg = 0;
|
||||
return L; /* function will operate over current thread */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Variations of 'lua_settable', used by 'db_getinfo' to put results
|
||||
** from 'lua_getinfo' into result table. Key is always a string;
|
||||
** value can be a string, an int, or a boolean.
|
||||
*/
|
||||
static void settabss (lua_State *L, const char *k, const char *v) {
|
||||
lua_pushstring(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
}
|
||||
|
||||
static void settabsi (lua_State *L, const char *k, int v) {
|
||||
lua_pushinteger(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
}
|
||||
|
||||
static void settabsb (lua_State *L, const char *k, int v) {
|
||||
lua_pushboolean(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** In function 'db_getinfo', the call to 'lua_getinfo' may push
|
||||
** results on the stack; later it creates the result table to put
|
||||
** these objects. Function 'treatstackoption' puts the result from
|
||||
** 'lua_getinfo' on top of the result table so that it can call
|
||||
** 'lua_setfield'.
|
||||
*/
|
||||
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
|
||||
if (L == L1)
|
||||
lua_rotate(L, -2, 1); /* exchange object and table */
|
||||
else
|
||||
lua_xmove(L1, L, 1); /* move object to the "main" stack */
|
||||
lua_setfield(L, -2, fname); /* put object into table */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Calls 'lua_getinfo' and collects all results in a new table.
|
||||
*/
|
||||
static int db_getinfo (lua_State *L) {
|
||||
lua_Debug ar;
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *options = luaL_optstring(L, arg+2, "flnStu");
|
||||
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
|
||||
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
|
||||
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
|
||||
lua_xmove(L, L1, 1);
|
||||
}
|
||||
else { /* stack level */
|
||||
if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
|
||||
lua_pushnil(L); /* level out of range */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!lua_getinfo(L1, options, &ar))
|
||||
return luaL_argerror(L, arg+2, "invalid option");
|
||||
lua_newtable(L); /* table to collect results */
|
||||
if (strchr(options, 'S')) {
|
||||
settabss(L, "source", ar.source);
|
||||
settabss(L, "short_src", ar.short_src);
|
||||
settabsi(L, "linedefined", ar.linedefined);
|
||||
settabsi(L, "lastlinedefined", ar.lastlinedefined);
|
||||
settabss(L, "what", ar.what);
|
||||
}
|
||||
if (strchr(options, 'l'))
|
||||
settabsi(L, "currentline", ar.currentline);
|
||||
if (strchr(options, 'u')) {
|
||||
settabsi(L, "nups", ar.nups);
|
||||
settabsi(L, "nparams", ar.nparams);
|
||||
settabsb(L, "isvararg", ar.isvararg);
|
||||
}
|
||||
if (strchr(options, 'n')) {
|
||||
settabss(L, "name", ar.name);
|
||||
settabss(L, "namewhat", ar.namewhat);
|
||||
}
|
||||
if (strchr(options, 't'))
|
||||
settabsb(L, "istailcall", ar.istailcall);
|
||||
if (strchr(options, 'L'))
|
||||
treatstackoption(L, L1, "activelines");
|
||||
if (strchr(options, 'f'))
|
||||
treatstackoption(L, L1, "func");
|
||||
return 1; /* return table */
|
||||
}
|
||||
|
||||
|
||||
static int db_getlocal (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
const char *name;
|
||||
int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */
|
||||
if (lua_isfunction(L, arg + 1)) { /* function argument? */
|
||||
lua_pushvalue(L, arg + 1); /* push function */
|
||||
lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
|
||||
return 1; /* return only name (there is no value) */
|
||||
}
|
||||
else { /* stack-level argument */
|
||||
int level = (int)luaL_checkinteger(L, arg + 1);
|
||||
if (!lua_getstack(L1, level, &ar)) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
name = lua_getlocal(L1, &ar, nvar);
|
||||
if (name) {
|
||||
lua_xmove(L1, L, 1); /* move local value */
|
||||
lua_pushstring(L, name); /* push name */
|
||||
lua_rotate(L, -2, 1); /* re-order */
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L); /* no name (nor value) */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int db_setlocal (lua_State *L) {
|
||||
int arg;
|
||||
const char *name;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
int level = (int)luaL_checkinteger(L, arg + 1);
|
||||
int nvar = (int)luaL_checkinteger(L, arg + 2);
|
||||
if (!lua_getstack(L1, level, &ar)) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
luaL_checkany(L, arg+3);
|
||||
lua_settop(L, arg+3);
|
||||
lua_xmove(L, L1, 1);
|
||||
name = lua_setlocal(L1, &ar, nvar);
|
||||
if (name == NULL)
|
||||
lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */
|
||||
lua_pushstring(L, name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** get (if 'get' is true) or set an upvalue from a closure
|
||||
*/
|
||||
static int auxupvalue (lua_State *L, int get) {
|
||||
const char *name;
|
||||
int n = (int)luaL_checkinteger(L, 2); /* upvalue index */
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */
|
||||
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
|
||||
if (name == NULL) return 0;
|
||||
lua_pushstring(L, name);
|
||||
lua_insert(L, -(get+1)); /* no-op if get is false */
|
||||
return get + 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_getupvalue (lua_State *L) {
|
||||
return auxupvalue(L, 1);
|
||||
}
|
||||
|
||||
|
||||
static int db_setupvalue (lua_State *L) {
|
||||
luaL_checkany(L, 3);
|
||||
return auxupvalue(L, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether a given upvalue from a given closure exists and
|
||||
** returns its index
|
||||
*/
|
||||
static int checkupval (lua_State *L, int argf, int argnup) {
|
||||
int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */
|
||||
luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */
|
||||
luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,
|
||||
"invalid upvalue index");
|
||||
return nup;
|
||||
}
|
||||
|
||||
|
||||
static int db_upvalueid (lua_State *L) {
|
||||
int n = checkupval(L, 1, 2);
|
||||
lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_upvaluejoin (lua_State *L) {
|
||||
int n1 = checkupval(L, 1, 2);
|
||||
int n2 = checkupval(L, 3, 4);
|
||||
luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
|
||||
luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
|
||||
lua_upvaluejoin(L, 1, n1, 3, n2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Call hook function registered at hook table for the current
|
||||
** thread (if there is one)
|
||||
*/
|
||||
static void hookf (lua_State *L, lua_Debug *ar) {
|
||||
static const char *const hooknames[] =
|
||||
{"call", "return", "line", "count", "tail call"};
|
||||
lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
|
||||
lua_pushthread(L);
|
||||
if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */
|
||||
lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */
|
||||
if (ar->currentline >= 0)
|
||||
lua_pushinteger(L, ar->currentline); /* push current line */
|
||||
else lua_pushnil(L);
|
||||
lua_assert(lua_getinfo(L, "lS", ar));
|
||||
lua_call(L, 2, 0); /* call hook function */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert a string mask (for 'sethook') into a bit mask
|
||||
*/
|
||||
static int makemask (const char *smask, int count) {
|
||||
int mask = 0;
|
||||
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
|
||||
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
|
||||
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
|
||||
if (count > 0) mask |= LUA_MASKCOUNT;
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert a bit mask (for 'gethook') into a string mask
|
||||
*/
|
||||
static char *unmakemask (int mask, char *smask) {
|
||||
int i = 0;
|
||||
if (mask & LUA_MASKCALL) smask[i++] = 'c';
|
||||
if (mask & LUA_MASKRET) smask[i++] = 'r';
|
||||
if (mask & LUA_MASKLINE) smask[i++] = 'l';
|
||||
smask[i] = '\0';
|
||||
return smask;
|
||||
}
|
||||
|
||||
|
||||
static int db_sethook (lua_State *L) {
|
||||
int arg, mask, count;
|
||||
lua_Hook func;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
if (lua_isnoneornil(L, arg+1)) { /* no hook? */
|
||||
lua_settop(L, arg+1);
|
||||
func = NULL; mask = 0; count = 0; /* turn off hooks */
|
||||
}
|
||||
else {
|
||||
const char *smask = luaL_checkstring(L, arg+2);
|
||||
luaL_checktype(L, arg+1, LUA_TFUNCTION);
|
||||
count = (int)luaL_optinteger(L, arg + 3, 0);
|
||||
func = hookf; mask = makemask(smask, count);
|
||||
}
|
||||
if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) {
|
||||
lua_createtable(L, 0, 2); /* create a hook table */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */
|
||||
lua_pushstring(L, "k");
|
||||
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
|
||||
}
|
||||
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
|
||||
lua_pushvalue(L, arg + 1); /* value (hook function) */
|
||||
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
|
||||
lua_sethook(L1, func, mask, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int db_gethook (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
char buff[5];
|
||||
int mask = lua_gethookmask(L1);
|
||||
lua_Hook hook = lua_gethook(L1);
|
||||
if (hook == NULL) /* no hook? */
|
||||
lua_pushnil(L);
|
||||
else if (hook != hookf) /* external hook? */
|
||||
lua_pushliteral(L, "external hook");
|
||||
else { /* hook table must exist */
|
||||
lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
|
||||
lua_pushthread(L1); lua_xmove(L1, L, 1);
|
||||
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
|
||||
lua_remove(L, -2); /* remove hook table */
|
||||
}
|
||||
lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */
|
||||
lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
static int db_debug (lua_State *L) {
|
||||
for (;;) {
|
||||
char buffer[250];
|
||||
lua_writestringerror("%s", "lua_debug> ");
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
|
||||
strcmp(buffer, "cont\n") == 0)
|
||||
return 0;
|
||||
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
||||
lua_pcall(L, 0, 0, 0))
|
||||
lua_writestringerror("%s\n", lua_tostring(L, -1));
|
||||
lua_settop(L, 0); /* remove eventual returns */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int db_traceback (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *msg = lua_tostring(L, arg + 1);
|
||||
if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
|
||||
lua_pushvalue(L, arg + 1); /* return it untouched */
|
||||
else {
|
||||
int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
|
||||
luaL_traceback(L, L1, msg, level);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg dblib[] = {
|
||||
{"debug", db_debug},
|
||||
{"getuservalue", db_getuservalue},
|
||||
{"gethook", db_gethook},
|
||||
{"getinfo", db_getinfo},
|
||||
{"getlocal", db_getlocal},
|
||||
{"getregistry", db_getregistry},
|
||||
{"getmetatable", db_getmetatable},
|
||||
{"getupvalue", db_getupvalue},
|
||||
{"upvaluejoin", db_upvaluejoin},
|
||||
{"upvalueid", db_upvalueid},
|
||||
{"setuservalue", db_setuservalue},
|
||||
{"sethook", db_sethook},
|
||||
{"setlocal", db_setlocal},
|
||||
{"setmetatable", db_setmetatable},
|
||||
{"setupvalue", db_setupvalue},
|
||||
{"traceback", db_traceback},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_debug (lua_State *L) {
|
||||
luaL_newlib(L, dblib);
|
||||
return 1;
|
||||
}
|
||||
|
||||
+643
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
** $Id: ldebug.c,v 2.110 2015/01/02 12:52:22 roberto Exp $
|
||||
** Debug Interface
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define ldebug_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lapi.h"
|
||||
#include "lcode.h"
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lfunc.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "ltm.h"
|
||||
#include "lvm.h"
|
||||
|
||||
|
||||
|
||||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
|
||||
|
||||
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
|
||||
|
||||
|
||||
static int currentpc (CallInfo *ci) {
|
||||
lua_assert(isLua(ci));
|
||||
return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
|
||||
}
|
||||
|
||||
|
||||
static int currentline (CallInfo *ci) {
|
||||
return getfuncline(ci_func(ci)->p, currentpc(ci));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** this function can be called asynchronous (e.g. during a signal)
|
||||
*/
|
||||
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
|
||||
if (func == NULL || mask == 0) { /* turn off hooks? */
|
||||
mask = 0;
|
||||
func = NULL;
|
||||
}
|
||||
if (isLua(L->ci))
|
||||
L->oldpc = L->ci->u.l.savedpc;
|
||||
L->hook = func;
|
||||
L->basehookcount = count;
|
||||
resethookcount(L);
|
||||
L->hookmask = cast_byte(mask);
|
||||
}
|
||||
|
||||
|
||||
LUA_API lua_Hook lua_gethook (lua_State *L) {
|
||||
return L->hook;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_gethookmask (lua_State *L) {
|
||||
return L->hookmask;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_gethookcount (lua_State *L) {
|
||||
return L->basehookcount;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
|
||||
int status;
|
||||
CallInfo *ci;
|
||||
if (level < 0) return 0; /* invalid (negative) level */
|
||||
lua_lock(L);
|
||||
for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
|
||||
level--;
|
||||
if (level == 0 && ci != &L->base_ci) { /* level found? */
|
||||
status = 1;
|
||||
ar->i_ci = ci;
|
||||
}
|
||||
else status = 0; /* no such level */
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static const char *upvalname (Proto *p, int uv) {
|
||||
TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
|
||||
if (s == NULL) return "?";
|
||||
else return getstr(s);
|
||||
}
|
||||
|
||||
|
||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||
int nparams = clLvalue(ci->func)->p->numparams;
|
||||
if (n >= ci->u.l.base - ci->func - nparams)
|
||||
return NULL; /* no such vararg */
|
||||
else {
|
||||
*pos = ci->func + nparams + n;
|
||||
return "(*vararg)"; /* generic name for any vararg */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *findlocal (lua_State *L, CallInfo *ci, int n,
|
||||
StkId *pos) {
|
||||
const char *name = NULL;
|
||||
StkId base;
|
||||
if (isLua(ci)) {
|
||||
if (n < 0) /* access to vararg values? */
|
||||
return findvararg(ci, -n, pos);
|
||||
else {
|
||||
base = ci->u.l.base;
|
||||
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
||||
}
|
||||
}
|
||||
else
|
||||
base = ci->func + 1;
|
||||
if (name == NULL) { /* no 'standard' name? */
|
||||
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
|
||||
if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */
|
||||
name = "(*temporary)"; /* generic name for any valid slot */
|
||||
else
|
||||
return NULL; /* no name */
|
||||
}
|
||||
*pos = base + (n - 1);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
const char *name;
|
||||
lua_lock(L);
|
||||
if (ar == NULL) { /* information about non-active function? */
|
||||
if (!isLfunction(L->top - 1)) /* not a Lua function? */
|
||||
name = NULL;
|
||||
else /* consider live variables at function start (parameters) */
|
||||
name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
|
||||
}
|
||||
else { /* active function; get information through 'ar' */
|
||||
StkId pos = 0; /* to avoid warnings */
|
||||
name = findlocal(L, ar->i_ci, n, &pos);
|
||||
if (name) {
|
||||
setobj2s(L, L->top, pos);
|
||||
api_incr_top(L);
|
||||
}
|
||||
}
|
||||
lua_unlock(L);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
StkId pos = 0; /* to avoid warnings */
|
||||
const char *name = findlocal(L, ar->i_ci, n, &pos);
|
||||
lua_lock(L);
|
||||
if (name) {
|
||||
setobjs2s(L, pos, L->top - 1);
|
||||
L->top--; /* pop value */
|
||||
}
|
||||
lua_unlock(L);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||
if (noLuaClosure(cl)) {
|
||||
ar->source = "=[C]";
|
||||
ar->linedefined = -1;
|
||||
ar->lastlinedefined = -1;
|
||||
ar->what = "C";
|
||||
}
|
||||
else {
|
||||
Proto *p = cl->l.p;
|
||||
ar->source = p->source ? getstr(p->source) : "=?";
|
||||
ar->linedefined = p->linedefined;
|
||||
ar->lastlinedefined = p->lastlinedefined;
|
||||
ar->what = (ar->linedefined == 0) ? "main" : "Lua";
|
||||
}
|
||||
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
||||
}
|
||||
|
||||
|
||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
if (noLuaClosure(f)) {
|
||||
setnilvalue(L->top);
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
TValue v;
|
||||
int *lineinfo = f->l.p->lineinfo;
|
||||
Table *t = luaH_new(L); /* new table to store active lines */
|
||||
sethvalue(L, L->top, t); /* push it on stack */
|
||||
api_incr_top(L);
|
||||
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
|
||||
for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
|
||||
luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
Closure *f, CallInfo *ci) {
|
||||
int status = 1;
|
||||
for (; *what; what++) {
|
||||
switch (*what) {
|
||||
case 'S': {
|
||||
funcinfo(ar, f);
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
||||
if (noLuaClosure(f)) {
|
||||
ar->isvararg = 1;
|
||||
ar->nparams = 0;
|
||||
}
|
||||
else {
|
||||
ar->isvararg = f->l.p->is_vararg;
|
||||
ar->nparams = f->l.p->numparams;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't': {
|
||||
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
/* calling function is a known Lua function? */
|
||||
if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
|
||||
ar->namewhat = getfuncname(L, ci->previous, &ar->name);
|
||||
else
|
||||
ar->namewhat = NULL;
|
||||
if (ar->namewhat == NULL) {
|
||||
ar->namewhat = ""; /* not found */
|
||||
ar->name = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'L':
|
||||
case 'f': /* handled by lua_getinfo */
|
||||
break;
|
||||
default: status = 0; /* invalid option */
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||
int status;
|
||||
Closure *cl;
|
||||
CallInfo *ci;
|
||||
StkId func;
|
||||
lua_lock(L);
|
||||
if (*what == '>') {
|
||||
ci = NULL;
|
||||
func = L->top - 1;
|
||||
api_check(ttisfunction(func), "function expected");
|
||||
what++; /* skip the '>' */
|
||||
L->top--; /* pop function */
|
||||
}
|
||||
else {
|
||||
ci = ar->i_ci;
|
||||
func = ci->func;
|
||||
lua_assert(ttisfunction(ci->func));
|
||||
}
|
||||
cl = ttisclosure(func) ? clvalue(func) : NULL;
|
||||
status = auxgetinfo(L, what, ar, cl, ci);
|
||||
if (strchr(what, 'f')) {
|
||||
setobjs2s(L, L->top, func);
|
||||
api_incr_top(L);
|
||||
}
|
||||
if (strchr(what, 'L'))
|
||||
collectvalidlines(L, cl);
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Symbolic Execution
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
static const char *getobjname (Proto *p, int lastpc, int reg,
|
||||
const char **name);
|
||||
|
||||
|
||||
/*
|
||||
** find a "name" for the RK value 'c'
|
||||
*/
|
||||
static void kname (Proto *p, int pc, int c, const char **name) {
|
||||
if (ISK(c)) { /* is 'c' a constant? */
|
||||
TValue *kvalue = &p->k[INDEXK(c)];
|
||||
if (ttisstring(kvalue)) { /* literal constant? */
|
||||
*name = svalue(kvalue); /* it is its own name */
|
||||
return;
|
||||
}
|
||||
/* else no reasonable name found */
|
||||
}
|
||||
else { /* 'c' is a register */
|
||||
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
|
||||
if (what && *what == 'c') { /* found a constant name? */
|
||||
return; /* 'name' already filled */
|
||||
}
|
||||
/* else no reasonable name found */
|
||||
}
|
||||
*name = "?"; /* no reasonable name found */
|
||||
}
|
||||
|
||||
|
||||
static int filterpc (int pc, int jmptarget) {
|
||||
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
||||
return -1; /* cannot know who sets that register */
|
||||
else return pc; /* current position sets that register */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** try to find last instruction before 'lastpc' that modified register 'reg'
|
||||
*/
|
||||
static int findsetreg (Proto *p, int lastpc, int reg) {
|
||||
int pc;
|
||||
int setreg = -1; /* keep last instruction that changed 'reg' */
|
||||
int jmptarget = 0; /* any code before this address is conditional */
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
int a = GETARG_A(i);
|
||||
switch (op) {
|
||||
case OP_LOADNIL: {
|
||||
int b = GETARG_B(i);
|
||||
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
case OP_TFORCALL: {
|
||||
if (reg >= a + 2) /* affect all regs above its base */
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL: {
|
||||
if (reg >= a) /* affect all registers above base */
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
case OP_JMP: {
|
||||
int b = GETARG_sBx(i);
|
||||
int dest = pc + 1 + b;
|
||||
/* jump is forward and do not skip 'lastpc'? */
|
||||
if (pc < dest && dest <= lastpc) {
|
||||
if (dest > jmptarget)
|
||||
jmptarget = dest; /* update 'jmptarget' */
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (testAMode(op) && reg == a) /* any instruction that set A */
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return setreg;
|
||||
}
|
||||
|
||||
|
||||
static const char *getobjname (Proto *p, int lastpc, int reg,
|
||||
const char **name) {
|
||||
int pc;
|
||||
*name = luaF_getlocalname(p, reg + 1, lastpc);
|
||||
if (*name) /* is a local? */
|
||||
return "local";
|
||||
/* else try symbolic execution */
|
||||
pc = findsetreg(p, lastpc, reg);
|
||||
if (pc != -1) { /* could find instruction? */
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
switch (op) {
|
||||
case OP_MOVE: {
|
||||
int b = GETARG_B(i); /* move from 'b' to 'a' */
|
||||
if (b < GETARG_A(i))
|
||||
return getobjname(p, pc, b, name); /* get name for 'b' */
|
||||
break;
|
||||
}
|
||||
case OP_GETTABUP:
|
||||
case OP_GETTABLE: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
int t = GETARG_B(i); /* table index */
|
||||
const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
|
||||
? luaF_getlocalname(p, t + 1, pc)
|
||||
: upvalname(p, t);
|
||||
kname(p, pc, k, name);
|
||||
return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
|
||||
}
|
||||
case OP_GETUPVAL: {
|
||||
*name = upvalname(p, GETARG_B(i));
|
||||
return "upvalue";
|
||||
}
|
||||
case OP_LOADK:
|
||||
case OP_LOADKX: {
|
||||
int b = (op == OP_LOADK) ? GETARG_Bx(i)
|
||||
: GETARG_Ax(p->code[pc + 1]);
|
||||
if (ttisstring(&p->k[b])) {
|
||||
*name = svalue(&p->k[b]);
|
||||
return "constant";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_SELF: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
kname(p, pc, k, name);
|
||||
return "method";
|
||||
}
|
||||
default: break; /* go through to return NULL */
|
||||
}
|
||||
}
|
||||
return NULL; /* could not find reasonable name */
|
||||
}
|
||||
|
||||
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
||||
TMS tm = (TMS)0; /* to avoid warnings */
|
||||
Proto *p = ci_func(ci)->p; /* calling function */
|
||||
int pc = currentpc(ci); /* calling instruction index */
|
||||
Instruction i = p->code[pc]; /* calling instruction */
|
||||
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
|
||||
*name = "?";
|
||||
return "hook";
|
||||
}
|
||||
switch (GET_OPCODE(i)) {
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL: /* get function name */
|
||||
return getobjname(p, pc, GETARG_A(i), name);
|
||||
case OP_TFORCALL: { /* for iterator */
|
||||
*name = "for iterator";
|
||||
return "for iterator";
|
||||
}
|
||||
/* all other instructions can call only through metamethods */
|
||||
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
|
||||
tm = TM_INDEX;
|
||||
break;
|
||||
case OP_SETTABUP: case OP_SETTABLE:
|
||||
tm = TM_NEWINDEX;
|
||||
break;
|
||||
case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD:
|
||||
case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND:
|
||||
case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: {
|
||||
int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */
|
||||
tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */
|
||||
break;
|
||||
}
|
||||
case OP_UNM: tm = TM_UNM; break;
|
||||
case OP_BNOT: tm = TM_BNOT; break;
|
||||
case OP_LEN: tm = TM_LEN; break;
|
||||
case OP_CONCAT: tm = TM_CONCAT; break;
|
||||
case OP_EQ: tm = TM_EQ; break;
|
||||
case OP_LT: tm = TM_LT; break;
|
||||
case OP_LE: tm = TM_LE; break;
|
||||
default: lua_assert(0); /* other instructions cannot call a function */
|
||||
}
|
||||
*name = getstr(G(L)->tmname[tm]);
|
||||
return "metamethod";
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** The subtraction of two potentially unrelated pointers is
|
||||
** not ISO C, but it should not crash a program; the subsequent
|
||||
** checks are ISO C and ensure a correct result.
|
||||
*/
|
||||
static int isinstack (CallInfo *ci, const TValue *o) {
|
||||
ptrdiff_t i = o - ci->u.l.base;
|
||||
return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Checks whether value 'o' came from an upvalue. (That can only happen
|
||||
** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on
|
||||
** upvalues.)
|
||||
*/
|
||||
static const char *getupvalname (CallInfo *ci, const TValue *o,
|
||||
const char **name) {
|
||||
LClosure *c = ci_func(ci);
|
||||
int i;
|
||||
for (i = 0; i < c->nupvalues; i++) {
|
||||
if (c->upvals[i]->v == o) {
|
||||
*name = upvalname(c->p, i);
|
||||
return "upvalue";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char *varinfo (lua_State *L, const TValue *o) {
|
||||
const char *name = NULL; /* to avoid warnings */
|
||||
CallInfo *ci = L->ci;
|
||||
const char *kind = NULL;
|
||||
if (isLua(ci)) {
|
||||
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
||||
if (!kind && isinstack(ci, o)) /* no? try a register */
|
||||
kind = getobjname(ci_func(ci)->p, currentpc(ci),
|
||||
cast_int(o - ci->u.l.base), &name);
|
||||
}
|
||||
return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
||||
const char *t = objtypename(o);
|
||||
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
if (ttisstring(p1) || cvt2str(p1)) p1 = p2;
|
||||
luaG_typeerror(L, p1, "concatenate");
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_opinterror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2, const char *msg) {
|
||||
lua_Number temp;
|
||||
if (!tonumber(p1, &temp)) /* first operand is wrong? */
|
||||
p2 = p1; /* now second is wrong */
|
||||
luaG_typeerror(L, p2, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Error when both values are convertible to numbers, but not to integers
|
||||
*/
|
||||
l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
lua_Integer temp;
|
||||
if (!tointeger(p1, &temp))
|
||||
p2 = p1;
|
||||
luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
const char *t1 = objtypename(p1);
|
||||
const char *t2 = objtypename(p2);
|
||||
if (t1 == t2)
|
||||
luaG_runerror(L, "attempt to compare two %s values", t1);
|
||||
else
|
||||
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
|
||||
}
|
||||
|
||||
|
||||
static void addinfo (lua_State *L, const char *msg) {
|
||||
CallInfo *ci = L->ci;
|
||||
if (isLua(ci)) { /* is Lua code? */
|
||||
char buff[LUA_IDSIZE]; /* add file:line information */
|
||||
int line = currentline(ci);
|
||||
TString *src = ci_func(ci)->p->source;
|
||||
if (src)
|
||||
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
|
||||
else { /* no source available; use "?" instead */
|
||||
buff[0] = '?'; buff[1] = '\0';
|
||||
}
|
||||
luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_errormsg (lua_State *L) {
|
||||
if (L->errfunc != 0) { /* is there an error handling function? */
|
||||
StkId errfunc = restorestack(L, L->errfunc);
|
||||
setobjs2s(L, L->top, L->top - 1); /* move argument */
|
||||
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
||||
L->top++; /* assume EXTRA_STACK */
|
||||
luaD_call(L, L->top - 2, 1, 0); /* call it */
|
||||
}
|
||||
luaD_throw(L, LUA_ERRRUN);
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
addinfo(L, luaO_pushvfstring(L, fmt, argp));
|
||||
va_end(argp);
|
||||
luaG_errormsg(L);
|
||||
}
|
||||
|
||||
|
||||
void luaG_traceexec (lua_State *L) {
|
||||
CallInfo *ci = L->ci;
|
||||
lu_byte mask = L->hookmask;
|
||||
int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
|
||||
if (counthook)
|
||||
resethookcount(L); /* reset count */
|
||||
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
|
||||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||
return; /* do not call hook again (VM yielded, so it did not move) */
|
||||
}
|
||||
if (counthook)
|
||||
luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */
|
||||
if (mask & LUA_MASKLINE) {
|
||||
Proto *p = ci_func(ci)->p;
|
||||
int npc = pcRel(ci->u.l.savedpc, p);
|
||||
int newline = getfuncline(p, npc);
|
||||
if (npc == 0 || /* call linehook when enter a new function, */
|
||||
ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */
|
||||
newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */
|
||||
luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */
|
||||
}
|
||||
L->oldpc = ci->u.l.savedpc;
|
||||
if (L->status == LUA_YIELD) { /* did hook yield? */
|
||||
if (counthook)
|
||||
L->hookcount = 1; /* undo decrement to zero */
|
||||
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
|
||||
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
||||
ci->func = L->top - 1; /* protect stack below results */
|
||||
luaD_throw(L, LUA_YIELD);
|
||||
}
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
** $Id: ldebug.h,v 2.12 2014/11/10 14:46:05 roberto Exp $
|
||||
** Auxiliary functions from Debug Interface module
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef ldebug_h
|
||||
#define ldebug_h
|
||||
|
||||
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
|
||||
|
||||
#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1)
|
||||
|
||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||
|
||||
/* Active Lua function (given call info) */
|
||||
#define ci_func(ci) (clLvalue((ci)->func))
|
||||
|
||||
|
||||
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
|
||||
const char *opname);
|
||||
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2,
|
||||
const char *msg);
|
||||
LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
||||
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
|
||||
LUAI_FUNC void luaG_traceexec (lua_State *L);
|
||||
|
||||
|
||||
#endif
|
||||
+717
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
** $Id: ldo.c,v 2.135 2014/11/11 17:13:39 roberto Exp $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define ldo_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lapi.h"
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lfunc.h"
|
||||
#include "lgc.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "ltm.h"
|
||||
#include "lundump.h"
|
||||
#include "lvm.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
|
||||
#define errorstatus(s) ((s) > LUA_YIELD)
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Error-recovery functions
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By
|
||||
** default, Lua handles errors with exceptions when compiling as
|
||||
** C++ code, with _longjmp/_setjmp when asked to use them, and with
|
||||
** longjmp/setjmp otherwise.
|
||||
*/
|
||||
#if !defined(LUAI_THROW) /* { */
|
||||
|
||||
#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */
|
||||
|
||||
/* C++ exceptions */
|
||||
#define LUAI_THROW(L,c) throw(c)
|
||||
#define LUAI_TRY(L,c,a) \
|
||||
try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
|
||||
#define luai_jmpbuf int /* dummy variable */
|
||||
|
||||
#elif defined(LUA_USE_POSIX) /* }{ */
|
||||
|
||||
/* in POSIX, try _longjmp/_setjmp (more efficient) */
|
||||
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
|
||||
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
|
||||
#define luai_jmpbuf jmp_buf
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
/* ISO C handling with long jumps */
|
||||
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
|
||||
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
|
||||
#define luai_jmpbuf jmp_buf
|
||||
|
||||
#endif /* } */
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
|
||||
/* chain list of long jump buffers */
|
||||
struct lua_longjmp {
|
||||
struct lua_longjmp *previous;
|
||||
luai_jmpbuf b;
|
||||
volatile int status; /* error code */
|
||||
};
|
||||
|
||||
|
||||
static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
|
||||
switch (errcode) {
|
||||
case LUA_ERRMEM: { /* memory error? */
|
||||
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
|
||||
break;
|
||||
}
|
||||
case LUA_ERRERR: {
|
||||
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
|
||||
break;
|
||||
}
|
||||
}
|
||||
L->top = oldtop + 1;
|
||||
}
|
||||
|
||||
|
||||
l_noret luaD_throw (lua_State *L, int errcode) {
|
||||
if (L->errorJmp) { /* thread has an error handler? */
|
||||
L->errorJmp->status = errcode; /* set status */
|
||||
LUAI_THROW(L, L->errorJmp); /* jump to it */
|
||||
}
|
||||
else { /* thread has no error handler */
|
||||
global_State *g = G(L);
|
||||
L->status = cast_byte(errcode); /* mark it as dead */
|
||||
if (g->mainthread->errorJmp) { /* main thread has a handler? */
|
||||
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
|
||||
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
|
||||
}
|
||||
else { /* no handler at all; abort */
|
||||
if (g->panic) { /* panic function? */
|
||||
seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
|
||||
if (L->ci->top < L->top)
|
||||
L->ci->top = L->top; /* pushing msg. can break this invariant */
|
||||
lua_unlock(L);
|
||||
g->panic(L); /* call panic function (last chance to jump out) */
|
||||
}
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
||||
unsigned short oldnCcalls = L->nCcalls;
|
||||
struct lua_longjmp lj;
|
||||
lj.status = LUA_OK;
|
||||
lj.previous = L->errorJmp; /* chain new error handler */
|
||||
L->errorJmp = &lj;
|
||||
LUAI_TRY(L, &lj,
|
||||
(*f)(L, ud);
|
||||
);
|
||||
L->errorJmp = lj.previous; /* restore old error handler */
|
||||
L->nCcalls = oldnCcalls;
|
||||
return lj.status;
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
static void correctstack (lua_State *L, TValue *oldstack) {
|
||||
CallInfo *ci;
|
||||
UpVal *up;
|
||||
L->top = (L->top - oldstack) + L->stack;
|
||||
for (up = L->openupval; up != NULL; up = up->u.open.next)
|
||||
up->v = (up->v - oldstack) + L->stack;
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||
ci->top = (ci->top - oldstack) + L->stack;
|
||||
ci->func = (ci->func - oldstack) + L->stack;
|
||||
if (isLua(ci))
|
||||
ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* some space for error handling */
|
||||
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
|
||||
|
||||
|
||||
void luaD_reallocstack (lua_State *L, int newsize) {
|
||||
TValue *oldstack = L->stack;
|
||||
int lim = L->stacksize;
|
||||
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
|
||||
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
|
||||
luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);
|
||||
for (; lim < newsize; lim++)
|
||||
setnilvalue(L->stack + lim); /* erase new segment */
|
||||
L->stacksize = newsize;
|
||||
L->stack_last = L->stack + newsize - EXTRA_STACK;
|
||||
correctstack(L, oldstack);
|
||||
}
|
||||
|
||||
|
||||
void luaD_growstack (lua_State *L, int n) {
|
||||
int size = L->stacksize;
|
||||
if (size > LUAI_MAXSTACK) /* error after extra size? */
|
||||
luaD_throw(L, LUA_ERRERR);
|
||||
else {
|
||||
int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
|
||||
int newsize = 2 * size;
|
||||
if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
|
||||
if (newsize < needed) newsize = needed;
|
||||
if (newsize > LUAI_MAXSTACK) { /* stack overflow? */
|
||||
luaD_reallocstack(L, ERRORSTACKSIZE);
|
||||
luaG_runerror(L, "stack overflow");
|
||||
}
|
||||
else
|
||||
luaD_reallocstack(L, newsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int stackinuse (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
StkId lim = L->top;
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
if (lim < ci->top) lim = ci->top;
|
||||
}
|
||||
return cast_int(lim - L->stack) + 1; /* part of stack in use */
|
||||
}
|
||||
|
||||
|
||||
void luaD_shrinkstack (lua_State *L) {
|
||||
int inuse = stackinuse(L);
|
||||
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
|
||||
if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
|
||||
if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */
|
||||
luaE_freeCI(L); /* free all CIs (list grew because of an error) */
|
||||
else
|
||||
luaE_shrinkCI(L); /* shrink list */
|
||||
if (inuse > LUAI_MAXSTACK || /* still handling stack overflow? */
|
||||
goodsize >= L->stacksize) /* would grow instead of shrink? */
|
||||
condmovestack(L); /* don't change stack (change only for debugging) */
|
||||
else
|
||||
luaD_reallocstack(L, goodsize); /* shrink it */
|
||||
}
|
||||
|
||||
|
||||
void luaD_hook (lua_State *L, int event, int line) {
|
||||
lua_Hook hook = L->hook;
|
||||
if (hook && L->allowhook) {
|
||||
CallInfo *ci = L->ci;
|
||||
ptrdiff_t top = savestack(L, L->top);
|
||||
ptrdiff_t ci_top = savestack(L, ci->top);
|
||||
lua_Debug ar;
|
||||
ar.event = event;
|
||||
ar.currentline = line;
|
||||
ar.i_ci = ci;
|
||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
L->allowhook = 0; /* cannot call hooks inside a hook */
|
||||
ci->callstatus |= CIST_HOOKED;
|
||||
lua_unlock(L);
|
||||
(*hook)(L, &ar);
|
||||
lua_lock(L);
|
||||
lua_assert(!L->allowhook);
|
||||
L->allowhook = 1;
|
||||
ci->top = restorestack(L, ci_top);
|
||||
L->top = restorestack(L, top);
|
||||
ci->callstatus &= ~CIST_HOOKED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void callhook (lua_State *L, CallInfo *ci) {
|
||||
int hook = LUA_HOOKCALL;
|
||||
ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
|
||||
if (isLua(ci->previous) &&
|
||||
GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
|
||||
ci->callstatus |= CIST_TAIL;
|
||||
hook = LUA_HOOKTAILCALL;
|
||||
}
|
||||
luaD_hook(L, hook, -1);
|
||||
ci->u.l.savedpc--; /* correct 'pc' */
|
||||
}
|
||||
|
||||
|
||||
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
||||
int i;
|
||||
int nfixargs = p->numparams;
|
||||
StkId base, fixed;
|
||||
lua_assert(actual >= nfixargs);
|
||||
/* move fixed parameters to final position */
|
||||
luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
|
||||
fixed = L->top - actual; /* first fixed argument */
|
||||
base = L->top; /* final position of first argument */
|
||||
for (i=0; i<nfixargs; i++) {
|
||||
setobjs2s(L, L->top++, fixed + i);
|
||||
setnilvalue(fixed + i);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether __call metafield of 'func' is a function. If so, put
|
||||
** it in stack below original 'func' so that 'luaD_precall' can call
|
||||
** it. Raise an error if __call metafield is not a function.
|
||||
*/
|
||||
static void tryfuncTM (lua_State *L, StkId func) {
|
||||
const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
|
||||
StkId p;
|
||||
if (!ttisfunction(tm))
|
||||
luaG_typeerror(L, func, "call");
|
||||
/* Open a hole inside the stack at 'func' */
|
||||
for (p = L->top; p > func; p--)
|
||||
setobjs2s(L, p, p-1);
|
||||
L->top++; /* slot ensured by caller */
|
||||
setobj2s(L, func, tm); /* tag method is the new function to be called */
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
|
||||
|
||||
|
||||
/*
|
||||
** returns true if function has been executed (C function)
|
||||
*/
|
||||
int luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
lua_CFunction f;
|
||||
CallInfo *ci;
|
||||
int n; /* number of arguments (Lua) or returns (C) */
|
||||
ptrdiff_t funcr = savestack(L, func);
|
||||
switch (ttype(func)) {
|
||||
case LUA_TLCF: /* light C function */
|
||||
f = fvalue(func);
|
||||
goto Cfunc;
|
||||
case LUA_TCCL: { /* C closure */
|
||||
f = clCvalue(func)->f;
|
||||
Cfunc:
|
||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||
ci = next_ci(L); /* now 'enter' new function */
|
||||
ci->nresults = nresults;
|
||||
ci->func = restorestack(L, funcr);
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
ci->callstatus = 0;
|
||||
luaC_checkGC(L); /* stack grow uses memory */
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
luaD_hook(L, LUA_HOOKCALL, -1);
|
||||
lua_unlock(L);
|
||||
n = (*f)(L); /* do the actual call */
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
luaD_poscall(L, L->top - n);
|
||||
return 1;
|
||||
}
|
||||
case LUA_TLCL: { /* Lua function: prepare its call */
|
||||
StkId base;
|
||||
Proto *p = clLvalue(func)->p;
|
||||
n = cast_int(L->top - func) - 1; /* number of real arguments */
|
||||
luaD_checkstack(L, p->maxstacksize);
|
||||
for (; n < p->numparams; n++)
|
||||
setnilvalue(L->top++); /* complete missing arguments */
|
||||
if (!p->is_vararg) {
|
||||
func = restorestack(L, funcr);
|
||||
base = func + 1;
|
||||
}
|
||||
else {
|
||||
base = adjust_varargs(L, p, n);
|
||||
func = restorestack(L, funcr); /* previous call can change stack */
|
||||
}
|
||||
ci = next_ci(L); /* now 'enter' new function */
|
||||
ci->nresults = nresults;
|
||||
ci->func = func;
|
||||
ci->u.l.base = base;
|
||||
ci->top = base + p->maxstacksize;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
ci->u.l.savedpc = p->code; /* starting point */
|
||||
ci->callstatus = CIST_LUA;
|
||||
L->top = ci->top;
|
||||
luaC_checkGC(L); /* stack grow uses memory */
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
callhook(L, ci);
|
||||
return 0;
|
||||
}
|
||||
default: { /* not a function */
|
||||
luaD_checkstack(L, 1); /* ensure space for metamethod */
|
||||
func = restorestack(L, funcr); /* previous call may change stack */
|
||||
tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
return luaD_precall(L, func, nresults); /* now it must be a function */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int luaD_poscall (lua_State *L, StkId firstResult) {
|
||||
StkId res;
|
||||
int wanted, i;
|
||||
CallInfo *ci = L->ci;
|
||||
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
|
||||
if (L->hookmask & LUA_MASKRET) {
|
||||
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
|
||||
luaD_hook(L, LUA_HOOKRET, -1);
|
||||
firstResult = restorestack(L, fr);
|
||||
}
|
||||
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
|
||||
}
|
||||
res = ci->func; /* res == final position of 1st result */
|
||||
wanted = ci->nresults;
|
||||
L->ci = ci = ci->previous; /* back to caller */
|
||||
/* move results to correct place */
|
||||
for (i = wanted; i != 0 && firstResult < L->top; i--)
|
||||
setobjs2s(L, res++, firstResult++);
|
||||
while (i-- > 0)
|
||||
setnilvalue(res++);
|
||||
L->top = res;
|
||||
return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Call a function (C or Lua). The function to be called is at *func.
|
||||
** The arguments are on the stack, right after the function.
|
||||
** When returns, all the results are on the stack, starting at the original
|
||||
** function position.
|
||||
*/
|
||||
void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
|
||||
if (++L->nCcalls >= LUAI_MAXCCALLS) {
|
||||
if (L->nCcalls == LUAI_MAXCCALLS)
|
||||
luaG_runerror(L, "C stack overflow");
|
||||
else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
|
||||
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
|
||||
}
|
||||
if (!allowyield) L->nny++;
|
||||
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
|
||||
luaV_execute(L); /* call it */
|
||||
if (!allowyield) L->nny--;
|
||||
L->nCcalls--;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Completes the execution of an interrupted C function, calling its
|
||||
** continuation function.
|
||||
*/
|
||||
static void finishCcall (lua_State *L, int status) {
|
||||
CallInfo *ci = L->ci;
|
||||
int n;
|
||||
/* must have a continuation and must be able to call it */
|
||||
lua_assert(ci->u.c.k != NULL && L->nny == 0);
|
||||
/* error status can only happen in a protected call */
|
||||
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
|
||||
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
|
||||
ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
|
||||
L->errfunc = ci->u.c.old_errfunc;
|
||||
}
|
||||
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
|
||||
handled */
|
||||
adjustresults(L, ci->nresults);
|
||||
/* call continuation function */
|
||||
lua_unlock(L);
|
||||
n = (*ci->u.c.k)(L, status, ci->u.c.ctx);
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
/* finish 'luaD_precall' */
|
||||
luaD_poscall(L, L->top - n);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Executes "full continuation" (everything in the stack) of a
|
||||
** previously interrupted coroutine until the stack is empty (or another
|
||||
** interruption long-jumps out of the loop). If the coroutine is
|
||||
** recovering from an error, 'ud' points to the error status, which must
|
||||
** be passed to the first continuation function (otherwise the default
|
||||
** status is LUA_YIELD).
|
||||
*/
|
||||
static void unroll (lua_State *L, void *ud) {
|
||||
if (ud != NULL) /* error status? */
|
||||
finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */
|
||||
while (L->ci != &L->base_ci) { /* something in the stack */
|
||||
if (!isLua(L->ci)) /* C function? */
|
||||
finishCcall(L, LUA_YIELD); /* complete its execution */
|
||||
else { /* Lua function */
|
||||
luaV_finishOp(L); /* finish interrupted instruction */
|
||||
luaV_execute(L); /* execute down to higher C 'boundary' */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to find a suspended protected call (a "recover point") for the
|
||||
** given thread.
|
||||
*/
|
||||
static CallInfo *findpcall (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */
|
||||
if (ci->callstatus & CIST_YPCALL)
|
||||
return ci;
|
||||
}
|
||||
return NULL; /* no pending pcall */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Recovers from an error in a coroutine. Finds a recover point (if
|
||||
** there is one) and completes the execution of the interrupted
|
||||
** 'luaD_pcall'. If there is no recover point, returns zero.
|
||||
*/
|
||||
static int recover (lua_State *L, int status) {
|
||||
StkId oldtop;
|
||||
CallInfo *ci = findpcall(L);
|
||||
if (ci == NULL) return 0; /* no recovery point */
|
||||
/* "finish" luaD_pcall */
|
||||
oldtop = restorestack(L, ci->extra);
|
||||
luaF_close(L, oldtop);
|
||||
seterrorobj(L, status, oldtop);
|
||||
L->ci = ci;
|
||||
L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
|
||||
L->nny = 0; /* should be zero to be yieldable */
|
||||
luaD_shrinkstack(L);
|
||||
L->errfunc = ci->u.c.old_errfunc;
|
||||
return 1; /* continue running the coroutine */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** signal an error in the call to 'resume', not in the execution of the
|
||||
** coroutine itself. (Such errors should not be handled by any coroutine
|
||||
** error handler and should not kill the coroutine.)
|
||||
*/
|
||||
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
|
||||
L->top = firstArg; /* remove args from the stack */
|
||||
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
|
||||
api_incr_top(L);
|
||||
luaD_throw(L, -1); /* jump back to 'lua_resume' */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Do the work for 'lua_resume' in protected mode. Most of the work
|
||||
** depends on the status of the coroutine: initial state, suspended
|
||||
** inside a hook, or regularly suspended (optionally with a continuation
|
||||
** function), plus erroneous cases: non-suspended coroutine or dead
|
||||
** coroutine.
|
||||
*/
|
||||
static void resume (lua_State *L, void *ud) {
|
||||
int nCcalls = L->nCcalls;
|
||||
StkId firstArg = cast(StkId, ud);
|
||||
CallInfo *ci = L->ci;
|
||||
if (nCcalls >= LUAI_MAXCCALLS)
|
||||
resume_error(L, "C stack overflow", firstArg);
|
||||
if (L->status == LUA_OK) { /* may be starting a coroutine */
|
||||
if (ci != &L->base_ci) /* not in base level? */
|
||||
resume_error(L, "cannot resume non-suspended coroutine", firstArg);
|
||||
/* coroutine is in base level; start running it */
|
||||
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
|
||||
luaV_execute(L); /* call it */
|
||||
}
|
||||
else if (L->status != LUA_YIELD)
|
||||
resume_error(L, "cannot resume dead coroutine", firstArg);
|
||||
else { /* resuming from previous yield */
|
||||
L->status = LUA_OK; /* mark that it is running (again) */
|
||||
ci->func = restorestack(L, ci->extra);
|
||||
if (isLua(ci)) /* yielded inside a hook? */
|
||||
luaV_execute(L); /* just continue running Lua code */
|
||||
else { /* 'common' yield */
|
||||
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
|
||||
int n;
|
||||
lua_unlock(L);
|
||||
n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
firstArg = L->top - n; /* yield results come from continuation */
|
||||
}
|
||||
luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
|
||||
}
|
||||
unroll(L, NULL); /* run continuation */
|
||||
}
|
||||
lua_assert(nCcalls == L->nCcalls);
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
|
||||
int status;
|
||||
int oldnny = L->nny; /* save "number of non-yieldable" calls */
|
||||
lua_lock(L);
|
||||
luai_userstateresume(L, nargs);
|
||||
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
|
||||
L->nny = 0; /* allow yields */
|
||||
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
|
||||
status = luaD_rawrunprotected(L, resume, L->top - nargs);
|
||||
if (status == -1) /* error calling 'lua_resume'? */
|
||||
status = LUA_ERRRUN;
|
||||
else { /* continue running after recoverable errors */
|
||||
while (errorstatus(status) && recover(L, status)) {
|
||||
/* unroll continuation */
|
||||
status = luaD_rawrunprotected(L, unroll, &status);
|
||||
}
|
||||
if (errorstatus(status)) { /* unrecoverable error? */
|
||||
L->status = cast_byte(status); /* mark thread as 'dead' */
|
||||
seterrorobj(L, status, L->top); /* push error message */
|
||||
L->ci->top = L->top;
|
||||
}
|
||||
else lua_assert(status == L->status); /* normal end or yield */
|
||||
}
|
||||
L->nny = oldnny; /* restore 'nny' */
|
||||
L->nCcalls--;
|
||||
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_isyieldable (lua_State *L) {
|
||||
return (L->nny == 0);
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
|
||||
lua_KFunction k) {
|
||||
CallInfo *ci = L->ci;
|
||||
luai_userstateyield(L, nresults);
|
||||
lua_lock(L);
|
||||
api_checknelems(L, nresults);
|
||||
if (L->nny > 0) {
|
||||
if (L != G(L)->mainthread)
|
||||
luaG_runerror(L, "attempt to yield across a C-call boundary");
|
||||
else
|
||||
luaG_runerror(L, "attempt to yield from outside a coroutine");
|
||||
}
|
||||
L->status = LUA_YIELD;
|
||||
ci->extra = savestack(L, ci->func); /* save current 'func' */
|
||||
if (isLua(ci)) { /* inside a hook? */
|
||||
api_check(k == NULL, "hooks cannot continue after yielding");
|
||||
}
|
||||
else {
|
||||
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
|
||||
ci->u.c.ctx = ctx; /* save context */
|
||||
ci->func = L->top - nresults - 1; /* protect stack below results */
|
||||
luaD_throw(L, LUA_YIELD);
|
||||
}
|
||||
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
|
||||
lua_unlock(L);
|
||||
return 0; /* return to 'luaD_hook' */
|
||||
}
|
||||
|
||||
|
||||
int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||
ptrdiff_t old_top, ptrdiff_t ef) {
|
||||
int status;
|
||||
CallInfo *old_ci = L->ci;
|
||||
lu_byte old_allowhooks = L->allowhook;
|
||||
unsigned short old_nny = L->nny;
|
||||
ptrdiff_t old_errfunc = L->errfunc;
|
||||
L->errfunc = ef;
|
||||
status = luaD_rawrunprotected(L, func, u);
|
||||
if (status != LUA_OK) { /* an error occurred? */
|
||||
StkId oldtop = restorestack(L, old_top);
|
||||
luaF_close(L, oldtop); /* close possible pending closures */
|
||||
seterrorobj(L, status, oldtop);
|
||||
L->ci = old_ci;
|
||||
L->allowhook = old_allowhooks;
|
||||
L->nny = old_nny;
|
||||
luaD_shrinkstack(L);
|
||||
}
|
||||
L->errfunc = old_errfunc;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Execute a protected parser.
|
||||
*/
|
||||
struct SParser { /* data to 'f_parser' */
|
||||
ZIO *z;
|
||||
Mbuffer buff; /* dynamic structure used by the scanner */
|
||||
Dyndata dyd; /* dynamic structures used by the parser */
|
||||
const char *mode;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
|
||||
static void checkmode (lua_State *L, const char *mode, const char *x) {
|
||||
if (mode && strchr(mode, x[0]) == NULL) {
|
||||
luaO_pushfstring(L,
|
||||
"attempt to load a %s chunk (mode is '%s')", x, mode);
|
||||
luaD_throw(L, LUA_ERRSYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void f_parser (lua_State *L, void *ud) {
|
||||
LClosure *cl;
|
||||
struct SParser *p = cast(struct SParser *, ud);
|
||||
int c = zgetc(p->z); /* read first character */
|
||||
if (c == LUA_SIGNATURE[0]) {
|
||||
checkmode(L, p->mode, "binary");
|
||||
cl = luaU_undump(L, p->z, &p->buff, p->name);
|
||||
}
|
||||
else {
|
||||
checkmode(L, p->mode, "text");
|
||||
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
|
||||
}
|
||||
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
||||
luaF_initupvals(L, cl);
|
||||
}
|
||||
|
||||
|
||||
int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
||||
const char *mode) {
|
||||
struct SParser p;
|
||||
int status;
|
||||
L->nny++; /* cannot yield during parsing */
|
||||
p.z = z; p.name = name; p.mode = mode;
|
||||
p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
|
||||
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
|
||||
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
|
||||
luaZ_initbuffer(L, &p.buff);
|
||||
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
|
||||
luaZ_freebuffer(L, &p.buff);
|
||||
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
|
||||
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
|
||||
luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
|
||||
L->nny--;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
** $Id: ldo.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef ldo_h
|
||||
#define ldo_h
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
|
||||
luaD_growstack(L, n); else condmovestack(L);
|
||||
|
||||
|
||||
#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
|
||||
|
||||
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
|
||||
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
|
||||
|
||||
|
||||
/* type of protected functions, to be ran by 'runprotected' */
|
||||
typedef void (*Pfunc) (lua_State *L, void *ud);
|
||||
|
||||
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
||||
const char *mode);
|
||||
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
|
||||
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
|
||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
|
||||
int allowyield);
|
||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||
LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
|
||||
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
|
||||
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
|
||||
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
||||
|
||||
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
|
||||
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||
|
||||
#endif
|
||||
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
** $Id: ldump.c,v 2.34 2014/11/02 19:19:04 roberto Exp $
|
||||
** save precompiled Lua chunks
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define ldump_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lundump.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
lua_State *L;
|
||||
lua_Writer writer;
|
||||
void *data;
|
||||
int strip;
|
||||
int status;
|
||||
} DumpState;
|
||||
|
||||
|
||||
/*
|
||||
** All high-level dumps go through DumpVector; you can change it to
|
||||
** change the endianness of the result
|
||||
*/
|
||||
#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D)
|
||||
|
||||
#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D)
|
||||
|
||||
|
||||
static void DumpBlock (const void *b, size_t size, DumpState *D) {
|
||||
if (D->status == 0) {
|
||||
lua_unlock(D->L);
|
||||
D->status = (*D->writer)(D->L, b, size, D->data);
|
||||
lua_lock(D->L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define DumpVar(x,D) DumpVector(&x,1,D)
|
||||
|
||||
|
||||
static void DumpByte (int y, DumpState *D) {
|
||||
lu_byte x = (lu_byte)y;
|
||||
DumpVar(x, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpInt (int x, DumpState *D) {
|
||||
DumpVar(x, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpNumber (lua_Number x, DumpState *D) {
|
||||
DumpVar(x, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpInteger (lua_Integer x, DumpState *D) {
|
||||
DumpVar(x, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpString (const TString *s, DumpState *D) {
|
||||
if (s == NULL)
|
||||
DumpByte(0, D);
|
||||
else {
|
||||
size_t size = s->len + 1; /* include trailing '\0' */
|
||||
if (size < 0xFF)
|
||||
DumpByte(cast_int(size), D);
|
||||
else {
|
||||
DumpByte(0xFF, D);
|
||||
DumpVar(size, D);
|
||||
}
|
||||
DumpVector(getstr(s), size - 1, D); /* no need to save '\0' */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void DumpCode (const Proto *f, DumpState *D) {
|
||||
DumpInt(f->sizecode, D);
|
||||
DumpVector(f->code, f->sizecode, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
|
||||
|
||||
static void DumpConstants (const Proto *f, DumpState *D) {
|
||||
int i;
|
||||
int n = f->sizek;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++) {
|
||||
const TValue *o = &f->k[i];
|
||||
DumpByte(ttype(o), D);
|
||||
switch (ttype(o)) {
|
||||
case LUA_TNIL:
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
DumpByte(bvalue(o), D);
|
||||
break;
|
||||
case LUA_TNUMFLT:
|
||||
DumpNumber(fltvalue(o), D);
|
||||
break;
|
||||
case LUA_TNUMINT:
|
||||
DumpInteger(ivalue(o), D);
|
||||
break;
|
||||
case LUA_TSHRSTR:
|
||||
case LUA_TLNGSTR:
|
||||
DumpString(tsvalue(o), D);
|
||||
break;
|
||||
default:
|
||||
lua_assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void DumpProtos (const Proto *f, DumpState *D) {
|
||||
int i;
|
||||
int n = f->sizep;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++)
|
||||
DumpFunction(f->p[i], f->source, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpUpvalues (const Proto *f, DumpState *D) {
|
||||
int i, n = f->sizeupvalues;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++) {
|
||||
DumpByte(f->upvalues[i].instack, D);
|
||||
DumpByte(f->upvalues[i].idx, D);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void DumpDebug (const Proto *f, DumpState *D) {
|
||||
int i, n;
|
||||
n = (D->strip) ? 0 : f->sizelineinfo;
|
||||
DumpInt(n, D);
|
||||
DumpVector(f->lineinfo, n, D);
|
||||
n = (D->strip) ? 0 : f->sizelocvars;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++) {
|
||||
DumpString(f->locvars[i].varname, D);
|
||||
DumpInt(f->locvars[i].startpc, D);
|
||||
DumpInt(f->locvars[i].endpc, D);
|
||||
}
|
||||
n = (D->strip) ? 0 : f->sizeupvalues;
|
||||
DumpInt(n, D);
|
||||
for (i = 0; i < n; i++)
|
||||
DumpString(f->upvalues[i].name, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
|
||||
if (D->strip || f->source == psource)
|
||||
DumpString(NULL, D); /* no debug info or same source as its parent */
|
||||
else
|
||||
DumpString(f->source, D);
|
||||
DumpInt(f->linedefined, D);
|
||||
DumpInt(f->lastlinedefined, D);
|
||||
DumpByte(f->numparams, D);
|
||||
DumpByte(f->is_vararg, D);
|
||||
DumpByte(f->maxstacksize, D);
|
||||
DumpCode(f, D);
|
||||
DumpConstants(f, D);
|
||||
DumpUpvalues(f, D);
|
||||
DumpProtos(f, D);
|
||||
DumpDebug(f, D);
|
||||
}
|
||||
|
||||
|
||||
static void DumpHeader (DumpState *D) {
|
||||
DumpLiteral(LUA_SIGNATURE, D);
|
||||
DumpByte(LUAC_VERSION, D);
|
||||
DumpByte(LUAC_FORMAT, D);
|
||||
DumpLiteral(LUAC_DATA, D);
|
||||
DumpByte(sizeof(int), D);
|
||||
DumpByte(sizeof(size_t), D);
|
||||
DumpByte(sizeof(Instruction), D);
|
||||
DumpByte(sizeof(lua_Integer), D);
|
||||
DumpByte(sizeof(lua_Number), D);
|
||||
DumpInteger(LUAC_INT, D);
|
||||
DumpNumber(LUAC_NUM, D);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** dump Lua function as precompiled chunk
|
||||
*/
|
||||
int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
|
||||
int strip) {
|
||||
DumpState D;
|
||||
D.L = L;
|
||||
D.writer = w;
|
||||
D.data = data;
|
||||
D.strip = strip;
|
||||
D.status = 0;
|
||||
DumpHeader(&D);
|
||||
DumpByte(f->sizeupvalues, &D);
|
||||
DumpFunction(f, NULL, &D);
|
||||
return D.status;
|
||||
}
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lfunc_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lfunc.h"
|
||||
#include "lgc.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
|
||||
CClosure *luaF_newCclosure (lua_State *L, int n) {
|
||||
GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n));
|
||||
CClosure *c = gco2ccl(o);
|
||||
c->nupvalues = cast_byte(n);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
LClosure *luaF_newLclosure (lua_State *L, int n) {
|
||||
GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n));
|
||||
LClosure *c = gco2lcl(o);
|
||||
c->p = NULL;
|
||||
c->nupvalues = cast_byte(n);
|
||||
while (n--) c->upvals[n] = NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
** fill a closure with new closed upvalues
|
||||
*/
|
||||
void luaF_initupvals (lua_State *L, LClosure *cl) {
|
||||
int i;
|
||||
for (i = 0; i < cl->nupvalues; i++) {
|
||||
UpVal *uv = luaM_new(L, UpVal);
|
||||
uv->refcount = 1;
|
||||
uv->v = &uv->u.value; /* make it closed */
|
||||
setnilvalue(uv->v);
|
||||
cl->upvals[i] = uv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UpVal *luaF_findupval (lua_State *L, StkId level) {
|
||||
UpVal **pp = &L->openupval;
|
||||
UpVal *p;
|
||||
UpVal *uv;
|
||||
lua_assert(isintwups(L) || L->openupval == NULL);
|
||||
while (*pp != NULL && (p = *pp)->v >= level) {
|
||||
lua_assert(upisopen(p));
|
||||
if (p->v == level) /* found a corresponding upvalue? */
|
||||
return p; /* return it */
|
||||
pp = &p->u.open.next;
|
||||
}
|
||||
/* not found: create a new upvalue */
|
||||
uv = luaM_new(L, UpVal);
|
||||
uv->refcount = 0;
|
||||
uv->u.open.next = *pp; /* link it to list of open upvalues */
|
||||
uv->u.open.touched = 1;
|
||||
*pp = uv;
|
||||
uv->v = level; /* current value lives in the stack */
|
||||
if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
|
||||
L->twups = G(L)->twups; /* link it to the list */
|
||||
G(L)->twups = L;
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
||||
void luaF_close (lua_State *L, StkId level) {
|
||||
UpVal *uv;
|
||||
while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
|
||||
lua_assert(upisopen(uv));
|
||||
L->openupval = uv->u.open.next; /* remove from 'open' list */
|
||||
if (uv->refcount == 0) /* no references? */
|
||||
luaM_free(L, uv); /* free upvalue */
|
||||
else {
|
||||
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
|
||||
uv->v = &uv->u.value; /* now current value lives here */
|
||||
luaC_upvalbarrier(L, uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Proto *luaF_newproto (lua_State *L) {
|
||||
GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));
|
||||
Proto *f = gco2p(o);
|
||||
f->k = NULL;
|
||||
f->sizek = 0;
|
||||
f->p = NULL;
|
||||
f->sizep = 0;
|
||||
f->code = NULL;
|
||||
f->cache = NULL;
|
||||
f->sizecode = 0;
|
||||
f->lineinfo = NULL;
|
||||
f->sizelineinfo = 0;
|
||||
f->upvalues = NULL;
|
||||
f->sizeupvalues = 0;
|
||||
f->numparams = 0;
|
||||
f->is_vararg = 0;
|
||||
f->maxstacksize = 0;
|
||||
f->locvars = NULL;
|
||||
f->sizelocvars = 0;
|
||||
f->linedefined = 0;
|
||||
f->lastlinedefined = 0;
|
||||
f->source = NULL;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
void luaF_freeproto (lua_State *L, Proto *f) {
|
||||
luaM_freearray(L, f->code, f->sizecode);
|
||||
luaM_freearray(L, f->p, f->sizep);
|
||||
luaM_freearray(L, f->k, f->sizek);
|
||||
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
|
||||
luaM_freearray(L, f->locvars, f->sizelocvars);
|
||||
luaM_freearray(L, f->upvalues, f->sizeupvalues);
|
||||
luaM_free(L, f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Look for n-th local variable at line 'line' in function 'func'.
|
||||
** Returns NULL if not found.
|
||||
*/
|
||||
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
|
||||
int i;
|
||||
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
|
||||
if (pc < f->locvars[i].endpc) { /* is variable active? */
|
||||
local_number--;
|
||||
if (local_number == 0)
|
||||
return getstr(f->locvars[i].varname);
|
||||
}
|
||||
}
|
||||
return NULL; /* not found */
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
** $Id: lfunc.h,v 2.14 2014/06/19 18:27:20 roberto Exp $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lfunc_h
|
||||
#define lfunc_h
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
|
||||
|
||||
#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
|
||||
cast(int, sizeof(TValue)*((n)-1)))
|
||||
|
||||
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
|
||||
cast(int, sizeof(TValue *)*((n)-1)))
|
||||
|
||||
|
||||
/* test whether thread is in 'twups' list */
|
||||
#define isintwups(L) (L->twups != L)
|
||||
|
||||
|
||||
/*
|
||||
** Upvalues for Lua closures
|
||||
*/
|
||||
struct UpVal {
|
||||
TValue *v; /* points to stack or to its own value */
|
||||
lu_mem refcount; /* reference counter */
|
||||
union {
|
||||
struct { /* (when open) */
|
||||
UpVal *next; /* linked list */
|
||||
int touched; /* mark to avoid cycles with dead threads */
|
||||
} open;
|
||||
TValue value; /* the value (when closed) */
|
||||
} u;
|
||||
};
|
||||
|
||||
#define upisopen(up) ((up)->v != &(up)->u.value)
|
||||
|
||||
|
||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||
LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
|
||||
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
|
||||
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
|
||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||
int pc);
|
||||
|
||||
|
||||
#endif
|
||||
+1159
File diff suppressed because it is too large
Load Diff
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
** $Id: lgc.h,v 2.86 2014/10/25 11:50:46 roberto Exp $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lgc_h
|
||||
#define lgc_h
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
|
||||
/*
|
||||
** Collectable objects may have one of three colors: white, which
|
||||
** means the object is not marked; gray, which means the
|
||||
** object is marked, but its references may be not marked; and
|
||||
** black, which means that the object and all its references are marked.
|
||||
** The main invariant of the garbage collector, while marking objects,
|
||||
** is that a black object can never point to a white one. Moreover,
|
||||
** any gray object must be in a "gray list" (gray, grayagain, weak,
|
||||
** allweak, ephemeron) so that it can be visited again before finishing
|
||||
** the collection cycle. These lists have no meaning when the invariant
|
||||
** is not being enforced (e.g., sweep phase).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* how much to allocate before next GC step */
|
||||
#if !defined(GCSTEPSIZE)
|
||||
/* ~100 small strings */
|
||||
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Possible states of the Garbage Collector
|
||||
*/
|
||||
#define GCSpropagate 0
|
||||
#define GCSatomic 1
|
||||
#define GCSswpallgc 2
|
||||
#define GCSswpfinobj 3
|
||||
#define GCSswptobefnz 4
|
||||
#define GCSswpend 5
|
||||
#define GCScallfin 6
|
||||
#define GCSpause 7
|
||||
|
||||
|
||||
#define issweepphase(g) \
|
||||
(GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend)
|
||||
|
||||
|
||||
/*
|
||||
** macro to tell when main invariant (white objects cannot point to black
|
||||
** ones) must be kept. During a collection, the sweep
|
||||
** phase may break the invariant, as objects turned white may point to
|
||||
** still-black objects. The invariant is restored when sweep ends and
|
||||
** all objects are white again.
|
||||
*/
|
||||
|
||||
#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
|
||||
|
||||
|
||||
/*
|
||||
** some useful bit tricks
|
||||
*/
|
||||
#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
|
||||
#define setbits(x,m) ((x) |= (m))
|
||||
#define testbits(x,m) ((x) & (m))
|
||||
#define bitmask(b) (1<<(b))
|
||||
#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
|
||||
#define l_setbit(x,b) setbits(x, bitmask(b))
|
||||
#define resetbit(x,b) resetbits(x, bitmask(b))
|
||||
#define testbit(x,b) testbits(x, bitmask(b))
|
||||
|
||||
|
||||
/* Layout for bit use in 'marked' field: */
|
||||
#define WHITE0BIT 0 /* object is white (type 0) */
|
||||
#define WHITE1BIT 1 /* object is white (type 1) */
|
||||
#define BLACKBIT 2 /* object is black */
|
||||
#define FINALIZEDBIT 3 /* object has been marked for finalization */
|
||||
/* bit 7 is currently used by tests (luaL_checkmemory) */
|
||||
|
||||
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
|
||||
|
||||
|
||||
#define iswhite(x) testbits((x)->marked, WHITEBITS)
|
||||
#define isblack(x) testbit((x)->marked, BLACKBIT)
|
||||
#define isgray(x) /* neither white nor black */ \
|
||||
(!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT)))
|
||||
|
||||
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
|
||||
|
||||
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
|
||||
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
|
||||
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
|
||||
|
||||
#define changewhite(x) ((x)->marked ^= WHITEBITS)
|
||||
#define gray2black(x) l_setbit((x)->marked, BLACKBIT)
|
||||
|
||||
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
|
||||
|
||||
|
||||
#define luaC_condGC(L,c) \
|
||||
{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
|
||||
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
|
||||
|
||||
|
||||
#define luaC_barrier(L,p,v) { \
|
||||
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
|
||||
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
|
||||
|
||||
#define luaC_barrierback(L,p,v) { \
|
||||
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
|
||||
luaC_barrierback_(L,p); }
|
||||
|
||||
#define luaC_objbarrier(L,p,o) { \
|
||||
if (isblack(p) && iswhite(o)) \
|
||||
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
|
||||
|
||||
#define luaC_upvalbarrier(L,uv) \
|
||||
{ if (iscollectable((uv)->v) && !upisopen(uv)) \
|
||||
luaC_upvalbarrier_(L,uv); }
|
||||
|
||||
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
||||
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
||||
LUAI_FUNC void luaC_step (lua_State *L);
|
||||
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
|
||||
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
|
||||
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
|
||||
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
||||
LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
|
||||
LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv);
|
||||
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
||||
LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv);
|
||||
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user