summaryrefslogtreecommitdiff
path: root/xmake/scripts/base/project.lua
diff options
context:
space:
mode:
authorruki <[email protected]>2016-01-14 09:19:14 +0800
committerruki <[email protected]>2016-01-14 09:19:14 +0800
commitcdcf953259aee5e7e1a06855ddbedbaabf585bc9 (patch)
tree47b8e5de10522cca3b67354fa527b3525193e880 /xmake/scripts/base/project.lua
parent8c50566e7ab2139b9f6c2976b9ce875b7ad11b7a (diff)
rename script directory to core
Diffstat (limited to 'xmake/scripts/base/project.lua')
-rw-r--r--xmake/scripts/base/project.lua1469
1 files changed, 0 insertions, 1469 deletions
diff --git a/xmake/scripts/base/project.lua b/xmake/scripts/base/project.lua
deleted file mode 100644
index abc7897d4..000000000
--- a/xmake/scripts/base/project.lua
+++ /dev/null
@@ -1,1469 +0,0 @@
---!The Automatic Cross-platform Build Tool
---
--- XMake is free software; you can redistribute it and/or modify
--- it under the terms of the GNU Lesser General Public License as published by
--- the Free Software Foundation; either version 2.1 of the License, or
--- (at your option) any later version.
---
--- XMake is distributed in the hope that it will be useful,
--- but WITHOUT ANY WARRANTY; without even the implied warranty of
--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--- GNU Lesser General Public License for more details.
---
--- You should have received a copy of the GNU Lesser General Public License
--- along with XMake;
--- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
---
--- Copyright (C) 2009 - 2015, ruki All rights reserved.
---
--- @author ruki
--- @file project.lua
---
-
--- define module: project
-local project = project or {}
-
--- load modules
-local os = require("base/os")
-local io = require("base/io")
-local rule = require("base/rule")
-local path = require("base/path")
-local utils = require("base/utils")
-local table = require("base/table")
-local config = require("base/config")
-local linker = require("base/linker")
-local compiler = require("base/compiler")
-local platform = require("platform/platform")
-
--- import module
-function project._api_import(env, module)
-
- -- import
- return require("module/" .. module)
-end
-
--- the current os is belong to the given os?
-function project._api_os(env, ...)
-
- -- get the current os
- local os = platform.os()
- if not os then return false end
-
- -- exists this os?
- for _, o in ipairs(table.join(...)) do
- if o and type(o) == "string" and o == os then
- return true
- end
- end
-end
-
--- the current mode is belong to the given modes?
-function project._api_modes(env, ...)
-
- -- get the current mode
- local mode = config.get("mode")
- if not mode then return false end
-
- -- exists this mode?
- for _, m in ipairs(table.join(...)) do
- if m and type(m) == "string" and m == mode then
- return true
- end
- end
-end
-
--- the current platform is belong to the given platforms?
-function project._api_plats(env, ...)
-
- -- get the current platform
- local plat = config.get("plat")
- if not plat then return false end
-
- -- exists this platform? and escape '-'
- for _, p in ipairs(table.join(...)) do
- if p and type(p) == "string" and plat:find(p:gsub("%-", "%%-")) then
- return true
- end
- end
-end
-
--- the current platform is belong to the given architectures?
-function project._api_archs(env, ...)
-
- -- get the current architecture
- local arch = config.get("arch")
- if not arch then return false end
-
- -- exists this architecture? and escape '-'
- for _, a in ipairs(table.join(...)) do
- if a and type(a) == "string" and arch:find(a:gsub("%-", "%%-")) then
- return true
- end
- end
-end
-
--- the current kind is belong to the given kinds?
-function project._api_kind(env, ...)
-
- -- get the current kind
- local kind = config.get("kind")
- if not kind then return false end
-
- -- exists this kind?
- for _, k in ipairs(table.join(...)) do
- if k and type(k) == "string" and k == kind then
- return true
- end
- end
-end
-
--- enable options?
-function project._api_options(env, ...)
-
- -- some options are enabled?
- for _, o in ipairs(table.join(...)) do
- if o and type(o) == "string" and config.get(o) then
- return true
- end
- end
-end
-
--- get all pathes and translate it
-function project._api_get_pathes(...)
-
- -- check
- assert(project._CURDIR)
-
- -- get all pathes
- local pathes = table.join(...)
-
- -- translate the relative path
- local results = {}
- for _, p in ipairs(pathes) do
- if not p:find("^%s-%$%(.-%)") and not path.is_absolute(p) then
- table.insert(results, path.relative(path.absolute(p, project._CURDIR), project._PROJECT_DIR))
- else
- table.insert(results, p)
- end
- end
-
- -- ok?
- return results
-end
-
--- add c function
-function project._api_add_cfunc(env, module, alias, links, includes, cfunc)
-
- -- check
- assert(env and cfunc)
-
- -- make the option name
- local name = nil
- if module ~= nil then
- name = string.format("__%s_%s", module, cfunc)
- else
- name = string.format("__%s", cfunc)
- end
-
- -- make the option define
- local define = nil
- if module ~= nil then
- define = string.format("$(prefix)_%s_HAVE_%s", module:upper(), utils.ifelse(alias, alias, cfunc:upper()))
- else
- define = string.format("$(prefix)_HAVE_%s", utils.ifelse(alias, alias, cfunc:upper()))
- end
-
- -- make option
- env.add_option(name)
- env.set_option_category("cfuncs")
- env.add_option_cfuncs(cfunc)
- if links then env.add_option_links(links) end
- if includes then env.add_option_cincludes(includes) end
- env.add_option_defines_h_if_ok(define)
-
- -- add this option
- env.add_options(name)
-end
-
--- add c functions
-function project._api_add_cfuncs(env, module, links, includes, ...)
-
- -- check
- assert(env)
-
- -- done
- for _, cfunc in ipairs({...}) do
-
- -- check
- assert(cfunc)
-
- -- make the option name
- local name = nil
- if module ~= nil then
- name = string.format("__%s_%s", module, cfunc)
- else
- name = string.format("__%s", cfunc)
- end
-
- -- make the option define
- local define = nil
- if module ~= nil then
- define = string.format("$(prefix)_%s_HAVE_%s", module:upper(), cfunc:upper())
- else
- define = string.format("$(prefix)_HAVE_%s", cfunc:upper())
- end
-
- -- make option
- env.add_option(name)
- env.set_option_category("cfuncs")
- env.add_option_cfuncs(cfunc)
- if links then env.add_option_links(links) end
- if includes then env.add_option_cincludes(includes) end
- env.add_option_defines_h_if_ok(define)
-
- -- add this option
- env.add_options(name)
- end
-end
-
--- add c++ function
-function project._api_add_cxxfunc(env, module, alias, links, includes, cxxfunc)
-
- -- check
- assert(env and cxxfunc)
-
- -- make the option name
- local name = nil
- if module ~= nil then
- name = string.format("__%s_%s", module, cxxfunc)
- else
- name = string.format("__%s", cxxfunc)
- end
-
- -- make the option define
- local define = nil
- if module ~= nil then
- define = string.format("$(prefix)_%s_HAVE_%s", module:upper(), utils.ifelse(alias, alias, cxxfunc:upper()))
- else
- define = string.format("$(prefix)_HAVE_%s", utils.ifelse(alias, alias, cxxfunc:upper()))
- end
-
- -- make option
- env.add_option(name)
- env.set_option_category("cxxfuncs")
- env.add_option_cxxfuncs(cxxfunc)
- if links then env.add_option_links(links) end
- if includes then env.add_option_cxxincludes(includes) end
- env.add_option_defines_h_if_ok(define)
-
- -- add this option
- env.add_options(name)
-end
-
--- add c++ functions
-function project._api_add_cxxfuncs(env, module, links, includes, ...)
-
- -- check
- assert(env and module)
-
- -- done
- for _, cxxfunc in ipairs({...}) do
-
- -- check
- assert(cxxfunc)
-
- -- make the option name
- local name = nil
- if module ~= nil then
- name = string.format("__%s_%s", module, cxxfunc)
- else
- name = string.format("__%s", cxxfunc)
- end
-
- -- make the option define
- local define = nil
- if module ~= nil then
- define = string.format("$(prefix)_%s_HAVE_%s", module:upper(), cxxfunc:upper())
- else
- define = string.format("$(prefix)_HAVE_%s", cxxfunc:upper())
- end
-
- -- make option
- env.add_option(name)
- env.set_option_category("cxxfuncs")
- env.add_option_cxxfuncs(cxxfunc)
- if links then env.add_option_links(links) end
- if includes then env.add_option_cxxincludes(includes) end
- env.add_option_defines_h_if_ok(define)
-
- -- add this option
- env.add_options(name)
- end
-end
-
--- add target
-function project._api_add_target(env, name)
-
- -- check
- assert(env and name)
-
- -- the targets
- local targets = env._CONFIGS._TARGETS
- assert(targets)
-
- -- init the target scope
- targets[name] = targets[name] or {}
-
- -- switch to this target scope
- env._TARGET = targets[name]
-end
-
--- add option
-function project._api_add_option(env, name)
-
- -- check
- assert(env and name)
-
- -- the options
- local options = env._CONFIGS._OPTIONS
- assert(options)
-
- -- init the option scope
- options[name] = options[name] or {}
-
- -- switch to this option scope
- env._OPTION = options[name]
-end
-
--- load all subprojects from the given directories
-function project._api_add_subdirs(env, ...)
-
- -- check
- assert(env)
-
- -- init mtime for files
- project._MTIMES = project._MTIMES or {}
-
- -- save the current project file directory
- local curdir = project._CURDIR
-
- -- get all subdirs
- local subdirs = project._api_get_pathes(...)
-
- -- match all subdirs
- local subdirs_matched = {}
- for _, subdir in ipairs(subdirs) do
- local dirs = os.match(subdir, true)
- if dirs then table.join2(subdirs_matched, dirs) end
- end
-
- -- done
- for _, subdir in ipairs(subdirs_matched) do
- if subdir and type(subdir) == "string" then
-
- -- the project file
- local file = subdir .. "/xmake.lua"
- if not path.is_absolute(file) then
- file = path.absolute(file, xmake._PROJECT_DIR)
- end
-
- -- update the current project file directory
- project._CURDIR = path.directory(file)
-
- -- load the project script
- local script = loadfile(file)
- if script then
-
- -- bind environment
- setfenv(script, env)
-
- -- done the project script
- local ok, errors = pcall(script)
- if not ok then
- utils.error(errors)
- assert(false)
- end
-
- -- get mtime of the file
- project._MTIMES[path.relative(file, xmake._PROJECT_DIR)] = os.mtime(file)
- end
- end
- end
-
- -- restore the current project file directory
- project._CURDIR = curdir
-
-end
-
--- load all subprojects from the given files
-function project._api_add_subfiles(env, ...)
-
- -- check
- assert(env)
-
- -- init mtime for files
- project._MTIMES = project._MTIMES or {}
-
- -- save the current project file directory
- local curdir = project._CURDIR
-
- -- get all subfiles
- local subfiles = project._api_get_pathes(...)
-
- -- match all subfiles
- local subfiles_matched = {}
- for _, subfile in ipairs(subfiles) do
- local files = os.match(subfile)
- if files then table.join2(subfiles_matched, files) end
- end
-
- -- done
- for _, file in ipairs(subfiles_matched) do
- if file and type(file) == "string" then
-
- -- the project file
- if not path.is_absolute(file) then
- file = path.absolute(file, xmake._PROJECT_DIR)
- end
-
- -- update the current project file directory
- project._CURDIR = path.directory(file)
-
- -- load the project script
- local script = loadfile(file)
- if script then
-
- -- bind environment
- setfenv(script, env)
-
- -- done the project script
- local ok, errors = pcall(script)
- if not ok then
- utils.error(errors)
- assert(false)
- end
-
- -- get mtime of the file
- project._MTIMES[path.relative(file, xmake._PROJECT_DIR)] = os.mtime(file)
- end
- end
- end
-
- -- restore the current project file directory
- project._CURDIR = curdir
-end
-
--- load all packages from the given directories
-function project._api_add_pkgdirs(env, ...)
-
- -- get all directories
- local pkgdirs = {}
- local dirs = table.join(...)
- for _, dir in ipairs(dirs) do
- table.insert(pkgdirs, dir .. "/*.pkg")
- end
-
- -- add all packages
- project._api_add_subdirs(env, pkgdirs)
-end
-
--- set configure values
-function project._api_set_values(scope, name, ...)
-
- -- check
- assert(scope and name)
-
- -- update values
- scope[name] = {}
- table.join2(scope[name], ...)
-end
-
--- add configure values
-function project._api_add_values(scope, name, ...)
-
- -- check
- assert(scope and name)
-
- -- append values
- scope[name] = scope[name] or {}
- table.join2(scope[name], ...)
-end
-
--- set configure pathes
-function project._api_set_pathes(scope, name, ...)
-
- -- check
- assert(scope and name)
-
- -- update pathes
- scope[name] = {}
- table.join2(scope[name], project._api_get_pathes(...))
-end
-
--- add configure pathes
-function project._api_add_pathes(scope, name, ...)
-
- -- check
- assert(scope and name)
-
- -- append pathes
- scope[name] = scope[name] or {}
- table.join2(scope[name], project._api_get_pathes(...))
-end
-
--- filter the configure value
-function project._filter(values)
-
- -- check
- assert(values)
-
- -- filter all
- local newvals = {}
- for _, v in ipairs(utils.wrap(values)) do
- if type(v) == "string" then
- v = v:gsub("%$%((.-)%)", function (w)
-
- -- is upper?
- local isupper = false
- local c = string.char(w:byte())
- if c >= 'A' and c <= 'Z' then isupper = true end
-
- -- attempt to get it directly from the configure
- local r = config.get(w)
- if not r or type(r) ~= "string" then
-
- -- attempt to get it from the configure and the lower key
- w = w:lower()
- r = config.get(w)
- if not r or type(r) ~= "string" then
-
- -- get the other keys
- if w == "projectdir" then r = xmake._PROJECT_DIR
- elseif w == "os" then r = platform.os()
- end
- end
- end
-
- -- upper?
- if r and type(r) == "string" and isupper then
- r = r:upper()
- end
-
- -- ok?
- return r
- end)
- end
- table.insert(newvals, v)
- end
-
- -- ok?
- return newvals
-end
-
--- make configure for the given target_name
-function project._makeconf_for_target(target_name, target)
-
- -- check
- assert(target_name and target)
-
- -- get the target configure file
- local config_h = target.config_h
- if not config_h then
- return true
- end
-
- -- translate file path
- if not path.is_absolute(config_h) then
- config_h = path.absolute(config_h, xmake._PROJECT_DIR)
- else
- config_h = path.translate(config_h)
- end
-
- -- the prefix
- local prefix = target.config_h_prefix or (target_name:upper() .. "_CONFIG")
-
- -- open the file
- local file = project._CONFILES[config_h] or io.openmk(config_h)
- assert(file)
-
- -- make the head
- if project._CONFILES[config_h] then file:write("\n") end
- file:write(string.format("#ifndef %s_H\n", prefix))
- file:write(string.format("#define %s_H\n", prefix))
- file:write("\n")
-
- -- make version
- if target.version then
- file:write("// version\n")
- file:write(string.format("#define %s_VERSION \"%s\"\n", prefix, target.version))
- local i = 1
- local m = {"MAJOR", "MINOR", "ALTER"}
- for v in target.version:gmatch("%d+") do
- file:write(string.format("#define %s_VERSION_%s %s\n", prefix, m[i], v))
- i = i + 1
- if i > 3 then break end
- end
- file:write(string.format("#define %s_VERSION_BUILD %s\n", prefix, os.date("%Y%m%d%H%M", os.time())))
- file:write("\n")
- end
-
- -- make the defines
- local defines = {}
- if target.defines_h then table.join2(defines, target.defines_h) end
-
- -- make the undefines
- local undefines = {}
- if target.undefines_h then table.join2(undefines, target.undefines_h) end
-
- -- the options
- if target.options then
- for _, name in ipairs(utils.wrap(target.options)) do
-
- -- get option if be enabled
- local opt = nil
- if config.get(name) then opt = config.get("__" .. name) end
- if nil ~= opt then
-
- -- get the option defines
- if opt.defines_h_if_ok then table.join2(defines, opt.defines_h_if_ok) end
-
- -- get the option undefines
- if opt.undefines_h_if_ok then table.join2(undefines, opt.undefines_h_if_ok) end
-
- end
- end
- end
-
- -- make the defines
- if #defines ~= 0 then
- file:write("// defines\n")
- for _, define in ipairs(defines) do
- file:write(string.format("#define %s 1\n", define:gsub("=", " "):gsub("%$%((.-)%)", function (w) if w == "prefix" then return prefix end end)))
- end
- file:write("\n")
- end
-
- -- make the undefines
- if #undefines ~= 0 then
- file:write("// undefines\n")
- for _, undefine in ipairs(undefines) do
- file:write(string.format("#undef %s\n", undefine:gsub("%$%((.-)%)", function (w) if w == "prefix" then return prefix end end)))
- end
- file:write("\n")
- end
-
- -- make the tail
- file:write("#endif\n")
-
- -- cache the file
- project._CONFILES[config_h] = file
-
- -- ok
- return true
-end
-
--- make the configure file for the given target and dependents
-function project._makeconf_for_target_and_deps(target_name)
-
- -- the targets
- local targets = project.targets()
- assert(targets)
-
- -- the target
- local target = targets[target_name]
- assert(target)
-
- -- make configure for the target
- if not project._makeconf_for_target(target_name, target) then
- return false
- end
-
- -- exists the dependent targets?
- if target.deps then
- local deps = utils.wrap(target.deps)
- for _, dep in ipairs(deps) do
- if not project._makeconf_for_target_and_deps(dep) then return false end
- end
- end
-
- -- ok
- return true
-end
-
--- make targets from the project file
-function project._make_targets(configs)
-
- -- check
- assert(configs and configs._TARGETS)
-
- -- init
- project._TARGETS = project._TARGETS or {}
- local targets = project._TARGETS
-
- -- make all targets
- for k, v in pairs(configs._TARGETS) do
- targets[k] = v
- end
-
- -- merge the root configures to all targets
- for _, target in pairs(targets) do
-
- -- merge the setted configures
- for k, v in pairs(configs._SET) do
- if nil == target[k] then
- target[k] = v
- end
- end
-
- -- merge the added configures
- for k, v in pairs(configs._ADD) do
- if nil == target[k] then
- target[k] = v
- else
- target[k] = table.join(v, target[k])
- end
- end
-
- -- remove repeat values and unwrap it
- for k, v in pairs(target) do
-
- -- remove repeat first
- v = utils.unique(v)
-
- -- filter values
- v = project._filter(v)
-
- -- unwrap it if be only one
- v = utils.unwrap(v)
-
- -- update it
- target[k] = v
- end
- end
-
- -- init mtime for the project file
- project._MTIMES = project._MTIMES or {}
- project._MTIMES[path.relative(xmake._PROJECT_FILE, xmake._PROJECT_DIR)] = os.mtime(xmake._PROJECT_FILE)
-
- -- get the mtimes for configure
- local mtimes_config = config.get("__mtimes")
- if mtimes_config then
-
- -- check for all project files and we need reconfig and rebuild it if them have been modified
- for file, mtime in pairs(project._MTIMES) do
-
- -- modified? reconfig and rebuild it
- local mtime_old = mtimes_config[file]
- if not mtime_old or mtime > mtime_old then
- config._RECONFIG = true
- config.set("__rebuild", true)
- break
- end
- end
- end
-
- -- update mtimes
- config.set("__mtimes", project._MTIMES)
-
- -- reconfig it? we need reprobe it
- if config._RECONFIG then
- project.probe()
- config.clearup()
- end
-end
-
--- make option for checking links
-function project._make_option_for_checking_links(opt, links, cfile, objectfile, targetfile)
-
- -- the links string
- local links_str = table.concat(utils.wrap(links), ", ")
-
- -- this links has been checked?
- project._CHECKED_LINKS = project._CHECKED_LINKS or {}
- if project._CHECKED_LINKS[links_str] then return true end
-
- -- only for compile a object file
- local ok = compiler.check_include(opt, nil, cfile, objectfile)
-
- -- check link
- if ok then ok = linker.check_links(opt, links, cfile, objectfile, targetfile) end
-
- -- trace
- utils.printf("checking for the links %s ... %s", links_str, utils.ifelse(ok, "ok", "no"))
-
- -- cache the result
- project._CHECKED_LINKS[links_str] = ok
-
- -- ok?
- return ok
-end
-
--- make option for checking cincludes
-function project._make_option_for_checking_cincludes(opt, cincludes, cfile, objectfile)
-
- -- done
- for _, cinclude in ipairs(utils.wrap(cincludes)) do
-
- -- this cinclude has been checked?
- project._CHECKED_CINCLUDES = project._CHECKED_CINCLUDES or {}
- if project._CHECKED_CINCLUDES[cinclude] then return true end
-
- -- check cinclude
- local ok = compiler.check_include(opt, cinclude, cfile, objectfile)
-
- -- trace
- utils.printf("checking for the c include %s ... %s", cinclude, utils.ifelse(ok, "ok", "no"))
-
- -- cache the result
- project._CHECKED_CINCLUDES[cinclude] = ok
-
- -- failed
- if not ok then return false end
- end
-
- -- ok
- return true
-end
-
--- make option for checking cxxincludes
-function project._make_option_for_checking_cxxincludes(opt, cxxincludes, cxxfile, objectfile)
-
- -- done
- for _, cxxinclude in ipairs(utils.wrap(cxxincludes)) do
-
- -- this cxxinclude has been checked?
- project._CHECKED_CXXINCLUDES = project._CHECKED_CXXINCLUDES or {}
- if project._CHECKED_CXXINCLUDES[cinclude] then return true end
-
- -- check cinclude
- local ok = compiler.check_include(opt, cxxinclude, cxxfile, objectfile)
-
- -- trace
- utils.printf("checking for the c++ include %s ... %s", cxxinclude, utils.ifelse(ok, "ok", "no"))
-
- -- cache the result
- project._CHECKED_CXXINCLUDES[cxxinclude] = ok
-
- -- failed
- if not ok then return false end
- end
-
- -- ok
- return true
-end
-
--- make option for checking cfunctions
-function project._make_option_for_checking_cfuncs(opt, cfuncs, cfile, objectfile, targetfile)
-
- -- done
- for _, cfunc in ipairs(utils.wrap(cfuncs)) do
-
- -- check function
- local ok = compiler.check_function(opt, cfunc, cfile, objectfile)
-
- -- check link
- if ok and opt.links then ok = linker.check_links(opt, opt.links, cfile, objectfile, targetfile) end
-
- -- trace
- utils.printf("checking for the c function %s ... %s", cfunc, utils.ifelse(ok, "ok", "no"))
-
- -- failed
- if not ok then return false end
- end
-
- -- ok
- return true
-end
-
--- make option for checking cxxfunctions
-function project._make_option_for_checking_cxxfuncs(opt, cxxfuncs, cxxfile, objectfile, targetfile)
-
- -- done
- for _, cxxfunc in ipairs(utils.wrap(cxxfuncs)) do
-
- -- check function
- local ok = compiler.check_function(opt, cxxfunc, cxxfile, objectfile)
-
- -- check link
- if ok and opt.links then ok = linker.check_links(opt, opt.links, cxxfile, objectfile, targetfile) end
-
- -- trace
- utils.printf("checking for the c++ function %s ... %s", cxxfunc, utils.ifelse(ok, "ok", "no"))
-
- -- failed
- if not ok then return false end
- end
-
- -- ok
- return true
-end
-
--- make option for checking ctypes
-function project._make_option_for_checking_ctypes(opt, ctypes, cfile, objectfile, targetfile)
-
- -- done
- for _, ctype in ipairs(utils.wrap(ctypes)) do
-
- -- check type
- local ok = compiler.check_typedef(opt, ctype, cfile, objectfile)
-
- -- trace
- utils.printf("checking for the c type %s ... %s", ctype, utils.ifelse(ok, "ok", "no"))
-
- -- failed
- if not ok then return false end
- end
-
- -- ok
- return true
-end
-
--- make option for checking cxxtypes
-function project._make_option_for_checking_cxxtypes(opt, cxxtypes, cxxfile, objectfile, targetfile)
-
- -- done
- for _, cxxtype in ipairs(utils.wrap(cxxtypes)) do
-
- -- check type
- local ok = compiler.check_typedef(opt, cxxtype, cxxfile, objectfile)
-
- -- trace
- utils.printf("checking for the c++ type %s ... %s", cxxtype, utils.ifelse(ok, "ok", "no"))
-
- -- failed
- if not ok then return false end
- end
-
- -- ok
- return true
-end
-
--- make option
-function project._make_option(name, opt, cfile, cxxfile, objectfile, targetfile)
-
- -- remove repeat values and unwrap it
- for k, v in pairs(opt) do
-
- -- remove repeat first
- v = utils.unique(v)
-
- -- filter values
- v = project._filter(v)
-
- -- unwrap it if be only one
- v = utils.unwrap(v)
-
- -- update it
- opt[k] = v
- end
-
- -- check links
- if opt.links and not project._make_option_for_checking_links(opt, opt.links, cfile, objectfile, targetfile) then return end
-
- -- check ctypes
- if opt.ctypes and not project._make_option_for_checking_ctypes(opt, opt.ctypes, cfile, objectfile, targetfile) then return end
-
- -- check cxxtypes
- if opt.cxxtypes and not project._make_option_for_checking_cxxtypes(opt, opt.cxxtypes, cxxfile, objectfile, targetfile) then return end
-
- -- check includes and functions
- if opt.cincludes or opt.cxxincludes then
-
- -- check cincludes
- if opt.cincludes and not project._make_option_for_checking_cincludes(opt, opt.cincludes, cfile, objectfile) then return end
-
- -- check cxxincludes
- if opt.cxxincludes and not project._make_option_for_checking_cxxincludes(opt, opt.cxxincludes, cxxfile, objectfile) then return end
-
- -- check cfuncs
- if opt.cfuncs and not project._make_option_for_checking_cfuncs(opt, opt.cfuncs, cfile, objectfile, targetfile) then return end
-
- -- check cxxfuncs
- if opt.cxxfuncs and not project._make_option_for_checking_cxxfuncs(opt, opt.cxxfuncs, cxxfile, objectfile, targetfile) then return end
-
- end
-
- -- ok
- return opt
-end
-
--- make options from the project file
-function project._make_options(configs)
-
- -- check
- assert(configs and configs._OPTIONS)
-
- -- the source file path
- local cfile = os.tmpdir() .. "/__checking.c"
- local cxxfile = os.tmpdir() .. "/__checking.cpp"
-
- -- the object file path
- local objectfile = os.tmpdir() .. "/" .. rule.filename("__checking", "object")
-
- -- the target file path
- local targetfile = os.tmpdir() .. "/" .. rule.filename("__checking", "binary")
-
- -- make all options
- for k, v in pairs(configs._OPTIONS) do
-
- -- this option need be probed automatically?
- if config.auto(k) then
-
- -- make option
- local o = project._make_option(k, v, cfile, cxxfile, objectfile, targetfile)
- if o then
-
- -- enable this option
- config.set(k, true)
-
- -- save this option to configure
- config.set("__" .. k, o)
-
- else
-
- -- disable this option
- config.set(k, false)
-
- -- clear this option to configure
- config.set("__" .. k, nil)
-
- end
-
- elseif nil == config.get("__" .. k) then
-
- -- save this option to configure
- config.set("__" .. k, v)
- end
- end
-
- -- remove files
- os.rm(cfile)
- os.rm(cxxfile)
- os.rm(objectfile)
- os.rm(targetfile)
-
-end
-
--- only load options from the the project file
-function project._load_options(file)
-
- -- check
- assert(file)
-
- -- load the project script
- local script = loadfile(file)
- if not script then
- return string.format("load %s failed!", file)
- end
-
- -- set the current project file directory
- project._CURDIR = path.directory(file)
-
- -- bind the new environment
- local newenv = {_CONFIGS = {_OPTIONS = {}}}
- setmetatable(newenv, {__index = function(tbl, key)
- local val = rawget(tbl, key)
- if nil == val then val = rawget(_G, key) end
- if nil == val then return function(...) end end
- return val
- end})
- setfenv(script, newenv)
-
- -- register import
- newenv.import = function (module) return project._api_import(newenv, module) end
-
- -- register interfaces for the condition
- newenv.os = function (...) return project._api_os(newenv, ...) end
- newenv.kind = function (...) return project._api_kind(newenv, ...) end
- newenv.modes = function (...) return project._api_modes(newenv, ...) end
- newenv.plats = function (...) return project._api_plats(newenv, ...) end
- newenv.archs = function (...) return project._api_archs(newenv, ...) end
-
- -- register interfaces for the option
- newenv.set_option = function (...) return project._api_add_option(newenv, ...) end
- newenv.add_option = function (...) return project._api_add_option(newenv, ...) end
-
- -- register interfaces for the subproject files
- newenv.add_subdirs = function (...) return project._api_add_subdirs(newenv, ...) end
- newenv.add_subfiles = function (...) return project._api_add_subfiles(newenv, ...) end
-
- -- register interfaces for the functions
- newenv.add_cfunc = function (...) return project._api_add_cfunc(newenv, ...) end
- newenv.add_cfuncs = function (...) return project._api_add_cfuncs(newenv, ...) end
- newenv.add_cxxfunc = function (...) return project._api_add_cxxfunc(newenv, ...) end
- newenv.add_cxxfuncs = function (...) return project._api_add_cxxfuncs(newenv, ...) end
-
- -- register interfaces for the package files
- newenv.add_pkgdirs = function (...) return project._api_add_pkgdirs(newenv, ...) end
- newenv.add_pkgs = function (...) return project._api_add_subdirs(newenv, ...) end
-
- -- register interfaces for setting option values
- local interfaces = { "enable"
- , "showmenu"
- , "category"
- , "warnings"
- , "optimize"
- , "languages"
- , "description"}
-
- for _, interface in ipairs(interfaces) do
- newenv["set_option_" .. interface] = function (...) return project._api_set_values(newenv._OPTION, interface, ...) end
- end
-
- -- register interfaces for adding option values
- interfaces = { "links"
- , "cincludes"
- , "cxxincludes"
- , "cfuncs"
- , "cxxfuncs"
- , "ctypes"
- , "cxxtypes"
- , "cflags"
- , "cxflags"
- , "cxxflags"
- , "ldflags"
- , "vectorexts"
- , "defines"
- , "defines_if_ok"
- , "defines_h_if_ok"
- , "undefines"
- , "undefines_if_ok"
- , "undefines_h_if_ok"}
-
- for _, interface in ipairs(interfaces) do
- newenv["add_option_" .. interface] = function (...) return project._api_add_values(newenv._OPTION, interface, ...) end
- end
-
- -- register interfaces for adding option pathes
- interfaces = { "linkdirs"
- , "includedirs"}
-
- for _, interface in ipairs(interfaces) do
- newenv["add_option_" .. interface] = function (...) return project._api_add_pathes(newenv._OPTION, interface, ...) end
- end
-
- -- done the project script
- local ok, errors = pcall(script)
- if not ok then
- return nil, errors
- end
-
- -- get the project configure
- return newenv._CONFIGS
-end
-
--- only load targets from the project file
-function project._load_targets(file)
-
- -- check
- assert(file)
-
- -- load the project script
- local script = loadfile(file)
- if not script then
- return string.format("load %s failed!", file)
- end
-
- -- set the current project file directory
- project._CURDIR = path.directory(file)
-
- -- bind the new environment
- local newenv = {_CONFIGS = {_SET = {}, _ADD = {}, _TARGETS = {}}}
- setmetatable(newenv, {__index = function(tbl, key)
- local val = rawget(tbl, key)
- if nil == val then val = rawget(_G, key) end
- if nil == val and type(key) == "string" and (key:startswith("add_option") or key:startswith("set_option")) then
- return function(...) end
- end
- return val
- end})
- setfenv(script, newenv)
-
- -- register import
- newenv.import = function (module) return project._api_import(newenv, module) end
-
- -- register interfaces for the condition
- newenv.os = function (...) return project._api_os(newenv, ...) end
- newenv.kind = function (...) return project._api_kind(newenv, ...) end
- newenv.modes = function (...) return project._api_modes(newenv, ...) end
- newenv.plats = function (...) return project._api_plats(newenv, ...) end
- newenv.archs = function (...) return project._api_archs(newenv, ...) end
- newenv.options = function (...) return project._api_options(newenv, ...) end
-
- -- register interfaces for the target
- newenv.set_target = function (...) return project._api_add_target(newenv, ...) end
- newenv.add_target = function (...) return project._api_add_target(newenv, ...) end
-
- -- register interfaces for the subproject files
- newenv.add_subdirs = function (...) return project._api_add_subdirs(newenv, ...) end
- newenv.add_subfiles = function (...) return project._api_add_subfiles(newenv, ...) end
-
- -- register interfaces for the functions
- newenv.add_cfunc = function (...) return project._api_add_cfunc(newenv, ...) end
- newenv.add_cfuncs = function (...) return project._api_add_cfuncs(newenv, ...) end
- newenv.add_cxxfunc = function (...) return project._api_add_cxxfunc(newenv, ...) end
- newenv.add_cxxfuncs = function (...) return project._api_add_cxxfuncs(newenv, ...) end
-
- -- register interfaces for the package files
- newenv.add_pkgdirs = function (...) return project._api_add_pkgdirs(newenv, ...) end
- newenv.add_pkgs = function (...) return project._api_add_subdirs(newenv, ...) end
-
- -- register interfaces for setting values
- local interfaces = { "kind"
- , "config_h_prefix"
- , "version"
- , "strip"
- , "options"
- , "symbols"
- , "warnings"
- , "optimize"
- , "languages"
- , "runscript"
- , "installscript"
- , "packagescript"}
-
- for _, interface in ipairs(interfaces) do
- newenv["set_" .. interface] = function (...) return project._api_set_values(newenv._TARGET or newenv._CONFIGS._SET, interface, ...) end
- end
-
- -- register interfaces for setting pathes
- local interfaces = { "headerdir"
- , "targetdir"
- , "objectdir"
- , "config_h"}
-
- for _, interface in ipairs(interfaces) do
- newenv["set_" .. interface] = function (...) return project._api_set_pathes(newenv._TARGET or newenv._CONFIGS._SET, interface, ...) end
- end
-
- -- register interfaces for adding values
- interfaces = { "deps"
- , "links"
- , "cflags"
- , "cxflags"
- , "cxxflags"
- , "mflags"
- , "mxflags"
- , "mxxflags"
- , "ldflags"
- , "shflags"
- , "options"
- , "defines"
- , "undefines"
- , "defines_h"
- , "undefines_h"
- , "languages"
- , "vectorexts"}
- for _, interface in ipairs(interfaces) do
- newenv["add_" .. interface] = function (...) return project._api_add_values(newenv._TARGET or newenv._CONFIGS._ADD, interface, ...) end
- end
-
- -- register interfaces for adding pathes
- interfaces = { "files"
- , "headers"
- , "linkdirs"
- , "includedirs"}
- for _, interface in ipairs(interfaces) do
- newenv["add_" .. interface] = function (...) return project._api_add_pathes(newenv._TARGET or newenv._CONFIGS._ADD, interface, ...) end
- end
-
- -- done the project script
- local ok, errors = pcall(script)
- if not ok then
- return nil, errors
- end
-
- -- get the project configure
- return newenv._CONFIGS
-end
-
--- get the current configure for targets
-function project.targets()
-
- -- check
- assert(project._TARGETS)
-
- -- return it
- return project._TARGETS
-end
-
--- probe the project
-function project.probe()
-
- -- load the options from the the project file
- local configs, errors = project._load_options(xmake._PROJECT_FILE)
- if not configs then
- return errors
- end
-
- -- make the options from the the project file
- project._make_options(configs)
-end
-
--- load the project
-function project.load()
-
- -- load the targets from the the project file
- local configs, errors = project._load_targets(xmake._PROJECT_FILE)
- if not configs then
- return errors
- end
-
- -- make the targets from the the project file
- project._make_targets(configs)
-end
-
--- reload the project
-function project.reload()
-
- -- clear it first
- project._MTIMES = nil
- project._TARGETS = nil
- project._CONFILES = nil
- project._CURDIR = nil
-
- -- load it
- return project.load()
-end
-
--- dump the current configure
-function project.dump()
-
- -- check
- assert(project._TARGETS)
-
- -- dump
- if xmake._OPTIONS.verbose then
- utils.dump(project._TARGETS)
- end
-
-end
-
--- make the configure file for the given target
-function project.makeconf(target_name)
-
- -- init files
- project._CONFILES = project._CONFILES or {}
-
- -- the target name
- if target_name and target_name ~= "all" then
- -- make configure for the target and dependents
- if not project._makeconf_for_target_and_deps(target_name) then return false end
- else
-
- -- the targets
- local targets = project.targets()
- assert(targets)
-
- -- make configure for the targets
- for target_name, target in pairs(targets) do
- if not project._makeconf_for_target(target_name, target) then return false end
- end
- end
-
- -- exit files
- for _, file in pairs(project._CONFILES) do
- file:close()
- end
- project._CONFILES = nil
-
- -- ok
- return true
-end
-
--- check target
-function project.checktarget(target_name)
-
- -- the targets
- local targets = project.targets()
-
- -- invalid target?
- if target_name and target_name ~= "all" and targets and not targets[target_name] then
- utils.error("invalid target: %s!", target_name)
- return false
- elseif not target_name then
- utils.error("no target!")
- return false
- end
-
- -- ok
- return true
-end
-
--- get the project menu
-function project.menu()
-
- -- attempt to load project configure
- local configs = nil
- local errors = nil
- local projectfile = xmake._PROJECT_FILE
- if projectfile and os.isfile(projectfile) then
- configs, errors = project._load_options(projectfile)
- end
-
- -- failed?
- if not configs then
- if errors then utils.error(errors) end
- return {}
- end
-
- -- the options
- local options = configs._OPTIONS
- if not options then return {} end
-
- -- arrange options by category
- local options_by_category = {}
- for name, opt in pairs(options) do
-
- -- make the category
- local category = "default"
- if opt.category then category = utils.unwrap(opt.category) end
- options_by_category[category] = options_by_category[category] or {}
-
- -- append option to the current category
- options_by_category[category][name] = opt
- end
-
- -- make menu by category
- local menu = {}
- for k, opts in pairs(options_by_category) do
-
- -- insert options
- local first = true
- for name, opt in pairs(opts) do
-
- -- show menu?
- if opt.showmenu then
-
- -- the default value
- local default = "auto"
- if opt.enable ~= nil then
- default = utils.unwrap(opt.enable)
- end
-
- -- is first?
- if first then
-
- -- insert a separator
- table.insert(menu, {})
-
- -- not first
- first = false
- end
-
- -- append it
- if opt.description then
- table.insert(menu, {nil, name, "kv", default, utils.unwrap(opt.description)})
- else
- table.insert(menu, {nil, name, "kv", default, nil})
- end
- end
- end
- end
-
- -- ok?
- return menu
-end
-
--- return module: project
-return project