Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/premake-4.x-stable.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/project.lua')
-rw-r--r--src/base/project.lua540
1 files changed, 540 insertions, 0 deletions
diff --git a/src/base/project.lua b/src/base/project.lua
new file mode 100644
index 0000000..cf11ee1
--- /dev/null
+++ b/src/base/project.lua
@@ -0,0 +1,540 @@
+--
+-- projects.lua
+-- Implementations of the solution() and project() functions.
+-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
+--
+
+
+ premake.project = { }
+
+
+--
+-- Performs a sanity check all all of the solutions and projects
+-- in the session to be sure they meet some minimum requirements.
+--
+
+ function premake.project.checkall()
+ local action = premake.actions[_ACTION]
+
+ for _,sln in ipairs(_SOLUTIONS) 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 list configurations
+ if (not sln.configurations or #sln.configurations == 0) then
+ return nil, "solution '" .. sln.name .. "' needs configurations"
+ end
+
+ for _,prj in ipairs(sln.projects) do
+ local cfg = premake.project.getconfig(prj)
+
+ -- every project must have a language
+ if (not cfg.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, cfg.language)) then
+ return nil, "the " .. action.shortname .. " action does not support " .. cfg.language .. " projects"
+ end
+ end
+
+ for _,cfgname in ipairs(sln.configurations) do
+ cfg = premake.project.getconfig(prj, cfgname)
+
+ -- every config must have a kind
+ if (not cfg.kind) then
+ return nil, "project '" ..prj.name .. "' needs a kind in configuration '" .. cfgname .. "'"
+ 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
+
+ end
+ end
+
+ return true
+ end
+
+
+
+--
+-- Checks an active set of "terms" against a keyword set. Keywords may use
+-- Lua's pattern matching syntax. Comparisions are case-insensitve. Returns
+-- true if every keyword matches at least one term, false otherwise. This
+-- feature is used to filter the list of configuration blocks to a
+-- particular build or platform.
+--
+
+ function premake.project.checkterms(terms, keywords)
+ local function test(kw)
+ for _,term in pairs(terms) do
+ if (term:match(kw)) then return true end
+ end
+ end
+
+ for _,kw in ipairs(keywords) do
+ -- make keyword pattern case insensitive
+ kw = kw:gsub("(%%*)(%a)",
+ function (p,a)
+ if (p:len() % 2 == 1) then
+ return p..a
+ else
+ return p.."["..a:upper()..a:lower().."]"
+ end
+ end)
+
+ -- match it to a term
+ if (not test(kw)) then
+ return false
+ end
+ end
+
+ return true
+ end
+
+
+
+--
+-- Returns an iterator for a project's configurations.
+--
+
+ function premake.project.configs(prj)
+ local i = 0
+ local t = prj.solution.configurations
+ return function ()
+ i = i + 1
+ if (i <= #t) then
+ prj.filter.config = t[i]
+ return premake.project.getconfig(prj, t[i])
+ else
+ prj.filter.config = nil
+ end
+ end
+ end
+
+
+
+--
+-- Locate a project by name; case insensitive.
+--
+
+ function premake.project.find(name)
+ name = name:lower()
+ for _, sln in ipairs(_SOLUTIONS) do
+ for _, prj in ipairs(sln.projects) do
+ if (prj.name:lower() == name) then
+ return prj
+ end
+ end
+ end
+ end
+
+
+
+--
+-- Build a configuration object holding all of the settings that
+-- match the specified filters.
+--
+
+ function premake.project.getconfig(prj, cfgname)
+ -- see if this configuration has already been built and cached
+ local cachekey = cfgname or ""
+
+ local meta = getmetatable(prj)
+ local cfg = meta.__cfgcache[cachekey]
+ if (cfg) then
+ return cfg
+ end
+
+ -- prepare the list of active terms
+ local terms = premake.getactiveterms()
+ terms.config = cfgname
+
+ local function copyfields(cfg, this)
+ for field,value in pairs(this) do
+ if (not table.contains(premake.project.nocopy, field)) then
+ if (type(value) == "table") then
+ if (not cfg[field]) then cfg[field] = { } end
+ table.append(cfg[field], value)
+ else
+ cfg[field] = value
+ end
+ end
+ end
+ end
+
+ -- fields are copied first from the solution, then the solution's configs,
+ -- then from the project, then the project's configs. Each can overwrite
+ -- or add to the values set previously. The objdir field gets special
+ -- treatment, in order to provide a project-level default and still enable
+ -- solution-level overrides
+
+ local cfg = { }
+
+ copyfields(cfg, prj.solution)
+ for _,blk in ipairs(prj.solution.blocks) do
+ if (premake.project.checkterms(terms, blk.keywords)) then
+ copyfields(cfg, blk)
+ end
+ end
+
+ copyfields(cfg, prj)
+ if (not cfg.objdir) then cfg.objdir = path.join(prj.basedir, "obj") end
+ for _,blk in ipairs(prj.blocks) do
+ if (premake.project.checkterms(terms, blk.keywords)) then
+ copyfields(cfg, blk)
+ end
+ end
+
+ -- remove excluded files
+ local files = { }
+ for _, fname in ipairs(cfg.files) do
+ local excluded = false
+ for _, exclude in ipairs(cfg.excludes) do
+ excluded = (fname == exclude)
+ if (excluded) then break end
+ end
+
+ if (not excluded) then
+ table.insert(files, fname)
+ end
+ end
+ cfg.files = files
+
+ -- fix up paths, making them relative to project location where needed
+ for _,key in ipairs(premake.project.locationrelative) do
+ if (type(cfg[key]) == "table") then
+ for i,p in ipairs(cfg[key]) do
+ cfg[key][i] = path.getrelative(prj.location, p)
+ end
+ else
+ if (cfg[key]) then
+ cfg[key] = path.getrelative(prj.location, cfg[key])
+ end
+ end
+ end
+
+ cfg.name = cfgname
+ cfg.project = prj
+
+ -- precompute common calculated values
+ cfg.target = premake.project.gettargetfile(cfg, "target", cfg.kind)
+
+ meta.__cfgcache[cachekey] = cfg
+ return cfg
+ end
+
+
+
+--
+-- Returns the list of targets, matching the current configuration,
+-- for any dependent sibling projects.
+--
+
+ function premake.project.getdependencies(cfg)
+ local siblings = { }
+ for _, link in ipairs(cfg.links) do
+ -- is ths a sibling project?
+ local prj = premake.project.find(link)
+ if (prj) then
+ table.insert(siblings, link)
+ end
+ end
+ return siblings
+ end
+
+
+
+--
+-- Converts the values in a configuration "links" field into a list
+-- library files to be linked. Converts project names to the correct
+-- target for the current configuration.
+--
+
+ function premake.project.getlibraries(cfg, list)
+ local libs = { }
+
+ for _, link in ipairs(list) do
+ -- is ths a sibling project?
+ local prj = premake.project.find(link)
+ if (prj) then
+ local target
+
+ -- figure out the target name
+ local prjcfg = premake.project.getconfig(prj, cfg.name)
+ if (prjcfg.kind == "SharedLib" and os.is("windows")) then
+ target = premake.project.gettargetfile(prjcfg, "implib", prjcfg.kind)
+ else
+ target = prjcfg.target
+ end
+
+ -- target is currently relative to its project location, make
+ -- it relative to my location instead
+ target = path.getabsolute(path.join(prjcfg.location, target))
+ target = path.getrelative(cfg.location, target)
+
+ table.insert(libs, target)
+ else
+ table.insert(libs, link)
+ end
+ end
+
+ return libs
+ end
+
+
+
+--
+-- Return an object directory that is unique across the entire session.
+--
+
+ function premake.project.getobjdir(cfg)
+ if (premake.project.isuniquevalue("objdir", cfg.objdir)) then
+ return cfg.objdir
+ end
+
+ local fn = function (cfg) return path.join(cfg.objdir, cfg.name) end
+ local objdir = fn(cfg)
+ if (premake.project.isuniquevalue("objdir", objdir, fn)) then
+ return objdir
+ end
+
+ return path.join(cfg.objdir, cfg.project.name .. "/" .. cfg.name)
+ end
+
+
+
+--
+-- Retrieve the current object of the a particular type from the session.
+-- The type may be "solution", "container" (the last activated solution or
+-- project), or "config" (the last activated configuration). Returns the
+-- requested container, or nil and an error message.
+--
+
+ function premake.project.getobject(t)
+ local container
+
+ if (t == "container" or t == "solution") then
+ container = premake.CurrentContainer
+ else
+ container = premake.CurrentConfiguration
+ end
+
+ if (t == "solution" and type(container) ~= "solution") then
+ container = nil
+ end
+
+ local msg
+ if (not container) then
+ if (t == "container") then
+ msg = "no active solution or project"
+ elseif (t == "solution") then
+ msg = "no active solution"
+ else
+ msg = "no active solution, project, or configuration"
+ end
+ end
+
+ return container, msg
+ end
+
+
+
+--
+-- Builds a platform specific target (executable, library) file name of a
+-- specific type, using the information from a project configuration.
+--
+
+ function premake.project.gettargetfile(cfg, field, kind, os)
+ if (not os) then os = _OPTIONS.os or _OS end
+
+ local name = cfg[field.."name"] or cfg.targetname or cfg.project.name
+ local dir = cfg[field.."dir"] or cfg.targetdir or cfg.basedir
+
+ local prefix = ""
+ local extension = ""
+
+ if (os == "windows") then
+ if (kind == "ConsoleExe" or kind == "WindowedExe") then
+ extension = ".exe"
+ elseif (kind == "SharedLib") then
+ extension = ".dll"
+ elseif (kind == "StaticLib") then
+ extension = ".lib"
+ end
+ elseif (os == "macosx" and kind == "WindowedExe") then
+ name = name .. ".app/Contents/MacOS/" .. name
+ else
+ if (kind == "SharedLib") then
+ prefix = "lib"
+ extension = ".so"
+ elseif (kind == "StaticLib") then
+ prefix = "lib"
+ extension = ".a"
+ end
+ end
+
+ prefix = cfg[field.."prefix"] or prefix
+ extension = cfg[field.."extension"] or extension
+
+ return path.join(dir, prefix .. name .. extension)
+ end
+
+
+--
+-- Determines if a field value is unique across all configurations of
+-- all projects in the session. Used to create unique output targets.
+--
+
+ function premake.project.isuniquevalue(fieldname, value, fn)
+ local count = 0
+ for _, sln in ipairs(_SOLUTIONS) do
+ for _, prj in ipairs(sln.projects) do
+ for _, cfgname in ipairs(sln.configurations) do
+ local cfg = premake.project.getconfig(prj, cfgname)
+
+ local tst
+ if (fn) then
+ tst = fn(cfg)
+ else
+ tst = cfg[fieldname]
+ end
+
+ if (tst == value) then
+ count = count + 1
+ if (count > 1) then return false end
+ end
+ end
+ end
+ end
+ return true
+ end
+
+
+
+--
+-- Returns an iterator for a solution's projects.
+--
+
+ function premake.project.projects(sln)
+ local i = 0
+ return function ()
+ i = i + 1
+ if (i <= #sln.projects) then
+ local prj = sln.projects[i]
+
+ -- merge solution and project values
+ local merged = premake.project.getconfig(prj)
+ setmetatable(merged, getmetatable(prj))
+ merged.name = prj.name
+ merged.blocks = prj.blocks
+ return merged
+ end
+ end
+ end
+
+
+
+--
+-- Adds values to an array field of a solution/project/configuration. `ctype`
+-- specifies the container type (see premake.getobject) for the field.
+--
+
+ function premake.project.setarray(ctype, fieldname, value, allowed)
+ local container, err = premake.project.getobject(ctype)
+ if (not container) then
+ error(err, 3)
+ end
+
+ if (not container[fieldname]) then
+ container[fieldname] = { }
+ end
+
+ local function doinsert(value)
+ if (type(value) == "table") then
+ for _,v in ipairs(value) do
+ doinsert(v)
+ end
+ else
+ local v = premake.checkvalue(value, allowed)
+ if (not v) then error("invalid value '" .. value .. "'", 3) end
+ table.insert(container[fieldname], v)
+ end
+ end
+
+ if (value) then
+ doinsert(value)
+ end
+
+ return container[fieldname]
+ end
+
+
+
+--
+-- Adds values to an array-of-directories field of a solution/project/configuration.
+-- `ctype` specifies the container type (see premake.getobject) for the field. All
+-- values are converted to absolute paths before being stored.
+--
+
+ local function domatchedarray(ctype, fieldname, value, matchfunc)
+ local result = { }
+
+ function makeabsolute(arr)
+ for i,value in ipairs(arr) do
+ if (type(value) == "table") then
+ makeabsolute(value)
+ else
+ if value:find("*") then
+ makeabsolute(matchfunc(value))
+ else
+ table.insert(result, path.getabsolute(value))
+ end
+ end
+ end
+ end
+
+ makeabsolute(value)
+ return premake.project.setarray(ctype, fieldname, result)
+ end
+
+ function premake.project.setdirarray(ctype, fieldname, value)
+ return domatchedarray(ctype, fieldname, value, os.matchdirs)
+ end
+
+ function premake.project.setfilearray(ctype, fieldname, value)
+ return domatchedarray(ctype, fieldname, value, os.matchfiles)
+ end
+
+
+--
+-- Set a new value for a string field of a solution/project/configuration. `ctype`
+-- specifies the container type (see premake.project.getobject) for the field.
+--
+
+ function premake.project.setstring(ctype, fieldname, value, allowed)
+ -- find the container for this value
+ local container, err = premake.project.getobject(ctype)
+ if (not container) then
+ error(err, 3)
+ end
+
+ -- if a value was provided, set it
+ if (value) then
+ local v = premake.checkvalue(value, allowed)
+ if (not v) then error("invalid value '" .. value .. "'", 3) end
+ container[fieldname] = v
+ end
+
+ return container[fieldname]
+ end
+ \ No newline at end of file