Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions
@@ -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
@@ -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
}
@@ -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
@@ -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
@@ -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,
}
@@ -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
@@ -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
@@ -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,
}
@@ -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
@@ -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 = {}
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
}
}
@@ -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,
}
}
@@ -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,
}
}
@@ -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,
}
}
@@ -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,
}
}
@@ -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,
}
}
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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
@@ -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"
@@ -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,
},
}
@@ -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,
},
}
@@ -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,
},
}
@@ -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,
},
}
File diff suppressed because it is too large Load Diff
@@ -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
@@ -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
@@ -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('&', "&amp;")
value = value:gsub('"', "&quot;")
value = value:gsub("'", "&apos;")
value = value:gsub('<', "&lt;")
value = value:gsub('>', "&gt;")
value = value:gsub('\r', "&#x0D;")
value = value:gsub('\n', "&#x0A;")
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
@@ -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)
@@ -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.
@@ -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>
&middot;
<A HREF="#contents">contents</A>
&middot;
<A HREF="#index">index</A>
<HR>
<SMALL>
Copyright &copy; 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 &ndash; Introduction</A>
<P>
<LI><A HREF="manual.html#2">2 &ndash; Basic Concepts</A>
<UL>
<LI><A HREF="manual.html#2.1">2.1 &ndash; Values and Types</A>
<LI><A HREF="manual.html#2.2">2.2 &ndash; Environments and the Global Environment</A>
<LI><A HREF="manual.html#2.3">2.3 &ndash; Error Handling</A>
<LI><A HREF="manual.html#2.4">2.4 &ndash; Metatables and Metamethods</A>
<LI><A HREF="manual.html#2.5">2.5 &ndash; Garbage Collection</A>
<UL>
<LI><A HREF="manual.html#2.5.1">2.5.1 &ndash; Garbage-Collection Metamethods</A>
<LI><A HREF="manual.html#2.5.2">2.5.2 &ndash; Weak Tables</A>
</UL>
<LI><A HREF="manual.html#2.6">2.6 &ndash; Coroutines</A>
</UL>
<P>
<LI><A HREF="manual.html#3">3 &ndash; The Language</A>
<UL>
<LI><A HREF="manual.html#3.1">3.1 &ndash; Lexical Conventions</A>
<LI><A HREF="manual.html#3.2">3.2 &ndash; Variables</A>
<LI><A HREF="manual.html#3.3">3.3 &ndash; Statements</A>
<UL>
<LI><A HREF="manual.html#3.3.1">3.3.1 &ndash; Blocks</A>
<LI><A HREF="manual.html#3.3.2">3.3.2 &ndash; Chunks</A>
<LI><A HREF="manual.html#3.3.3">3.3.3 &ndash; Assignment</A>
<LI><A HREF="manual.html#3.3.4">3.3.4 &ndash; Control Structures</A>
<LI><A HREF="manual.html#3.3.5">3.3.5 &ndash; For Statement</A>
<LI><A HREF="manual.html#3.3.6">3.3.6 &ndash; Function Calls as Statements</A>
<LI><A HREF="manual.html#3.3.7">3.3.7 &ndash; Local Declarations</A>
</UL>
<LI><A HREF="manual.html#3.4">3.4 &ndash; Expressions</A>
<UL>
<LI><A HREF="manual.html#3.4.1">3.4.1 &ndash; Arithmetic Operators</A>
<LI><A HREF="manual.html#3.4.2">3.4.2 &ndash; Bitwise Operators</A>
<LI><A HREF="manual.html#3.4.3">3.4.3 &ndash; Coercions and Conversions</A>
<LI><A HREF="manual.html#3.4.4">3.4.4 &ndash; Relational Operators</A>
<LI><A HREF="manual.html#3.4.5">3.4.5 &ndash; Logical Operators</A>
<LI><A HREF="manual.html#3.4.6">3.4.6 &ndash; Concatenation</A>
<LI><A HREF="manual.html#3.4.7">3.4.7 &ndash; The Length Operator</A>
<LI><A HREF="manual.html#3.4.8">3.4.8 &ndash; Precedence</A>
<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
<LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
</UL>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
</UL>
<P>
<LI><A HREF="manual.html#4">4 &ndash; The Application Program Interface</A>
<UL>
<LI><A HREF="manual.html#4.1">4.1 &ndash; The Stack</A>
<LI><A HREF="manual.html#4.2">4.2 &ndash; Stack Size</A>
<LI><A HREF="manual.html#4.3">4.3 &ndash; Valid and Acceptable Indices</A>
<LI><A HREF="manual.html#4.4">4.4 &ndash; C Closures</A>
<LI><A HREF="manual.html#4.5">4.5 &ndash; Registry</A>
<LI><A HREF="manual.html#4.6">4.6 &ndash; Error Handling in C</A>
<LI><A HREF="manual.html#4.7">4.7 &ndash; Handling Yields in C</A>
<LI><A HREF="manual.html#4.8">4.8 &ndash; Functions and Types</A>
<LI><A HREF="manual.html#4.9">4.9 &ndash; The Debug Interface</A>
</UL>
<P>
<LI><A HREF="manual.html#5">5 &ndash; The Auxiliary Library</A>
<UL>
<LI><A HREF="manual.html#5.1">5.1 &ndash; Functions and Types</A>
</UL>
<P>
<LI><A HREF="manual.html#6">6 &ndash; Standard Libraries</A>
<UL>
<LI><A HREF="manual.html#6.1">6.1 &ndash; Basic Functions</A>
<LI><A HREF="manual.html#6.2">6.2 &ndash; Coroutine Manipulation</A>
<LI><A HREF="manual.html#6.3">6.3 &ndash; Modules</A>
<LI><A HREF="manual.html#6.4">6.4 &ndash; String Manipulation</A>
<UL>
<LI><A HREF="manual.html#6.4.1">6.4.1 &ndash; Patterns</A>
<LI><A HREF="manual.html#6.4.2">6.4.2 &ndash; Format Strings for Pack and Unpack</A>
</UL>
<LI><A HREF="manual.html#6.5">6.5 &ndash; UTF-8 Support</A>
<LI><A HREF="manual.html#6.6">6.6 &ndash; Table Manipulation</A>
<LI><A HREF="manual.html#6.7">6.7 &ndash; Mathematical Functions</A>
<LI><A HREF="manual.html#6.8">6.8 &ndash; Input and Output Facilities</A>
<LI><A HREF="manual.html#6.9">6.9 &ndash; Operating System Facilities</A>
<LI><A HREF="manual.html#6.10">6.10 &ndash; The Debug Library</A>
</UL>
<P>
<LI><A HREF="manual.html#7">7 &ndash; Lua Standalone</A>
<P>
<LI><A HREF="manual.html#8">8 &ndash; Incompatibilities with the Previous Version</A>
<UL>
<LI><A HREF="manual.html#8.1">8.1 &ndash; Changes in the Language</A>
<LI><A HREF="manual.html#8.2">8.2 &ndash; Changes in the Libraries</A>
<LI><A HREF="manual.html#8.3">8.3 &ndash; Changes in the API</A>
</UL>
<P>
<LI><A HREF="manual.html#9">9 &ndash; 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>&nbsp;</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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

@@ -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
@@ -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 ;
}
@@ -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
@@ -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 ;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

@@ -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>
&middot;
<A HREF="#install">installation</A>
&middot;
<A HREF="#changes">changes</A>
&middot;
<A HREF="#license">license</A>
&middot;
<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 &mdash; edit <TT>Makefile</TT>.
<LI> How to build Lua &mdash; edit <TT>src/Makefile</TT>.
<LI> Lua features &mdash; 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 &mdash; 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 &copy; 1994&ndash;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>
@@ -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)
File diff suppressed because it is too large Load Diff
@@ -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
@@ -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);
}
@@ -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
@@ -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;
}
@@ -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 /* } */
@@ -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 */
}
@@ -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
@@ -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;
}
@@ -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 /* } */
@@ -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
@@ -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;
}
@@ -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);
}
}
@@ -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
@@ -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;
}
@@ -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
@@ -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;
}
@@ -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 */
}
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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