diff options
| author | ruki <[email protected]> | 2016-03-21 20:57:23 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2016-03-21 20:57:37 +0800 |
| commit | b898400a3a5f18d332ce7ef159769d8f17fd28e5 (patch) | |
| tree | 275f124aa7c17c6090d25fefb226b0678f6d231d /xmake/core/project | |
| parent | f0623bf26279430deb6799b7816fb61996120166 (diff) | |
add project option
Diffstat (limited to 'xmake/core/project')
| -rw-r--r-- | xmake/core/project/option.lua | 302 | ||||
| -rw-r--r-- | xmake/core/project/project.lua | 378 | ||||
| -rw-r--r-- | xmake/core/project/target.lua | 35 |
3 files changed, 428 insertions, 287 deletions
diff --git a/xmake/core/project/option.lua b/xmake/core/project/option.lua new file mode 100644 index 000000000..2c4fd1876 --- /dev/null +++ b/xmake/core/project/option.lua @@ -0,0 +1,302 @@ +--!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) 2015 - 2016, ruki All rights reserved. +-- +-- @author ruki +-- @file option.lua +-- + +-- define module +local option = option or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local table = require("base/table") +local utils = require("base/utils") +local config = require("project/config") +local linker = require("platform/linker") +local compiler = require("platform/compiler") + +-- check option for checking links +function option._check_links(self, cfile, objectfile, targetfile) + + -- get links + local links = self:get("links") + if not links then + return true + end + + -- the links string + local links_str = table.concat(table.wrap(links), ", ") + + -- this links has been checked? + option._CHECKED_LINKS = option._CHECKED_LINKS or {} + if option._CHECKED_LINKS[links_str] then + return true + end + + -- only for compile a object file + local ok = compiler.check_include(self, nil, cfile, objectfile) + + -- check link + if ok then ok = linker.check_links(self, cfile, objectfile, targetfile) end + + -- trace + utils.printf("checking for the links %s ... %s", links_str, utils.ifelse(ok, "ok", "no")) + + -- cache the result + option._CHECKED_LINKS[links_str] = ok + + -- ok? + return ok +end + +-- check option for checking cincludes +function option._check_cincludes(self, cfile, objectfile) + + -- done + for _, cinclude in ipairs(table.wrap(self:get("cincludes"))) do + + -- this cinclude has been checked? + option._CHECKED_CINCLUDES = option._CHECKED_CINCLUDES or {} + if option._CHECKED_CINCLUDES[cinclude] then return true end + + -- check cinclude + local ok = compiler.check_include(self, cinclude, cfile, objectfile) + + -- trace + utils.printf("checking for the c include %s ... %s", cinclude, utils.ifelse(ok, "ok", "no")) + + -- cache the result + option._CHECKED_CINCLUDES[cinclude] = ok + + -- failed + if not ok then return false end + end + + -- ok + return true +end + +-- check option for checking cxxincludes +function option._check_cxxincludes(self, cxxfile, objectfile) + + -- done + for _, cxxinclude in ipairs(table.wrap(self:get("cxxincludes"))) do + + -- this cxxinclude has been checked? + option._CHECKED_CXXINCLUDES = option._CHECKED_CXXINCLUDES or {} + if option._CHECKED_CXXINCLUDES[cinclude] then return true end + + -- check cinclude + local ok = compiler.check_include(self, cxxinclude, cxxfile, objectfile) + + -- trace + utils.printf("checking for the c++ include %s ... %s", cxxinclude, utils.ifelse(ok, "ok", "no")) + + -- cache the result + option._CHECKED_CXXINCLUDES[cxxinclude] = ok + + -- failed + if not ok then return false end + end + + -- ok + return true +end + +-- check option for checking cfunctions +function option._check_cfuncs(self, cfile, objectfile, targetfile) + + -- done + for _, cfunc in ipairs(table.wrap(self:get("cfuncs"))) do + + -- check function + local ok = compiler.check_function(self, cfunc, cfile, objectfile) + + -- check link + if ok and self:get("links") then ok = linker.check_links(self, 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 + +-- check option for checking cxxfunctions +function option._check_cxxfuncs(self, cxxfile, objectfile, targetfile) + + -- done + for _, cxxfunc in ipairs(table.wrap(self:get("cxxfuncs"))) do + + -- check function + local ok = compiler.check_function(self, cxxfunc, cxxfile, objectfile) + + -- check link + if ok and self:get("links") then ok = linker.check_links(self, 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 + +-- check option for checking ctypes +function option._check_ctypes(self, cfile, objectfile, targetfile) + + -- done + for _, ctype in ipairs(table.wrap(self:get("ctypes"))) do + + -- check type + local ok = compiler.check_typedef(self, 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 + +-- check option for checking cxxtypes +function option._check_cxxtypes(self, cxxfile, objectfile, targetfile) + + -- done + for _, cxxtype in ipairs(table.wrap(self:get("cxxtypes"))) do + + -- check type + local ok = compiler.check_typedef(self, 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 + +-- check option +function option.check(self, cfile, cxxfile, objectfile, targetfile) + + -- check links + if not self:_check_links(cfile, objectfile, targetfile) then return false end + + -- check ctypes + if not self:_check_ctypes(cfile, objectfile, targetfile) then return false end + + -- check cxxtypes + if not self:_check_cxxtypes(cxxfile, objectfile, targetfile) then return false end + + -- check includes and functions + if self:get("cincludes") or self:get("cxxincludes") then + + -- check cincludes + if not self:_check_cincludes(cfile, objectfile) then return false end + + -- check cxxincludes + if not self:_check_cxxincludes(cxxfile, objectfile) then return false end + + -- check cfuncs + if not self:_check_cfuncs(cfile, objectfile, targetfile) then return false end + + -- check cxxfuncs + if not self:_check_cxxfuncs(cxxfile, objectfile, targetfile) then return false end + + end + + -- ok + return true +end + +-- get the option info +function option.get(self, infoname) + + -- check + assert(self and self._INFO and infoname) + + -- get it + return self._INFO[infoname] +end + +-- save the option info to the project configure +function option.save(self, is_clear) + + -- check + assert(self) + + -- save it + config.set("__option_" .. self:name(), self._INFO) +end + +-- clear the option info for the project configure +function option.clear(self) + + -- check + assert(self) + + -- clear it + config.set("__option_" .. self:name(), nil) +end + +-- load the option info from the project configure +function option.load(name) + + -- check + assert(name) + + -- get info + local info = config.get("__option_" .. name) + if info == nil then + return + end + + -- init option instance + local instance = {} + instance._INFO = info + instance._NAME = name + + -- ok + return instance +end + +-- get the option name +function option.name(self) + + -- get it + return self._NAME +end + + +-- return module +return option diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua index 8e941fb2e..491eb4a44 100644 --- a/xmake/core/project/project.lua +++ b/xmake/core/project/project.lua @@ -29,11 +29,11 @@ local io = require("base/io") local path = require("base/path") local utils = require("base/utils") local table = require("base/table") -local option = require("base/option") local filter = require("base/filter") local interpreter = require("base/interpreter") local target = require("project/target") local config = require("project/config") +local option = require("project/option") local deprecated_project = require("project/deprecated/project") local linker = require("platform/linker") local compiler = require("platform/compiler") @@ -150,7 +150,7 @@ function project._api_add_cfunc(interp, module, alias, links, includes, cfunc) -- save the current scope local scope = interp:scope_save() - -- make option + -- check option interp:api_call("option", name) interp:api_call("set_option_category", "cfuncs") interp:api_call("add_option_cfuncs", cfunc) @@ -196,7 +196,7 @@ function project._api_add_cfuncs(interp, module, links, includes, ...) -- save the current scope local scope = interp:scope_save() - -- make option + -- check option interp:api_call("option", name) interp:api_call("set_option_category", "cfuncs") interp:api_call("add_option_cfuncs", cfunc) @@ -237,7 +237,7 @@ function project._api_add_cxxfunc(interp, module, alias, links, includes, cxxfun -- save the current scope local scope = interp:scope_save() - -- make option + -- check option interp:api_call("option", name) interp:api_call("set_option_category", "cxxfuncs") interp:api_call("add_option_cxxfuncs", cxxfunc) @@ -283,7 +283,7 @@ function project._api_add_cxxfuncs(interp, module, links, includes, ...) -- save the current scope local scope = interp:scope_save() - -- make option + -- check option interp:api_call("option", name) interp:api_call("set_option_category", "cxxfuncs") interp:api_call("add_option_cxxfuncs", cxxfunc) @@ -476,251 +476,60 @@ function project._interpreter() return interp 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(table.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(table.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(table.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(table.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(table.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(table.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(table.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")) +-- probe the project +function project.probe() - -- failed - if not ok then return false end + -- enter the project directory + local ok, errors = os.cd(xmake._PROJECT_DIR) + if not ok then + return false, errors end - -- ok - return true -end - --- make option -function project._make_option(name, opt, cfile, cxxfile, objectfile, targetfile) - - -- 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 - + -- load the options from the the project file + local options, errors = project.options(true) + if not options then + return false, errors end - - -- ok - return opt -end - --- make options from the project file -function project._make_options(options) - - -- check - assert(options) - + -- the source file path - local cfile = os.tmpdir() .. "/__checking.c" - local cxxfile = os.tmpdir() .. "/__checking.cpp" + local cfile = path.join(os.tmpdir(), "__checking.c") + local cxxfile = path.join(os.tmpdir(), "__checking.cpp") -- the object file path - local objectfile = os.tmpdir() .. "/" .. target.filename("__checking", "object") + local objectfile = path.join(os.tmpdir(), target.filename("__checking", "object")) -- the target file path - local targetfile = os.tmpdir() .. "/" .. target.filename("__checking", "binary") + local targetfile = path.join(os.tmpdir(), target.filename("__checking", "binary")) -- make all options - for k, v in pairs(options) do + for name, opt in pairs(options) do -- this option need be probed automatically? if config.get(name) == nil then - -- make option - local o = project._make_option(k, v, cfile, cxxfile, objectfile, targetfile) - if o then + -- check option + if opt:check(cfile, cxxfile, objectfile, targetfile) then -- enable this option - config.set(k, true) + config.set(name, true) -- save this option to configure - config.set("__" .. k, o) + opt:save() else -- disable this option - config.set(k, false) + config.set(name, false) -- clear this option to configure - config.set("__" .. k, nil) + opt:clear() end - elseif nil == config.get("__" .. k) then + elseif nil == option.load(name) then -- save this option to configure - config.set("__" .. k, v) + opt:save() end end @@ -730,54 +539,6 @@ function project._make_options(options) os.rm(objectfile) os.rm(targetfile) -end - --- get the given target -function project.target(targetname) - - -- check - assert(targetname and targetname ~= "all") - - -- the targets - local targets = project.targets() - assert(targets) - - -- get it - return targets[targetname] -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() - - -- get interpreter - local interp = project._interpreter() - assert(interp) - - -- enter the project directory - local ok, errors = os.cd(xmake._PROJECT_DIR) - if not ok then - return false, errors - end - - -- load the options from the the project file - local options, errors = interp:load(xmake._PROJECT_FILE, "option", true, true) - if not options then - return false, errors - end - - -- make the options from the the project file - project._make_options(options) - -- leave the project directory ok, errors = os.cd("-") if not ok then @@ -836,29 +597,72 @@ function project.load() return true end --- dump the current configure -function project.dump() - - -- dump - if option.get("verbose") then - table.dump(project.targets()) - end - +-- get the given target +function project.target(targetname) + + -- check + assert(targetname and targetname ~= "all") + + -- the targets + local targets = project.targets() + assert(targets) + + -- get it + return targets[targetname] end --- get the project menu -function project.menu() +-- get the current configure for targets +function project.targets() + + -- check + assert(project._TARGETS) + + -- return it + return project._TARGETS +end + +-- get options +function project.options(enable_filter) -- get interpreter local interp = project._interpreter() assert(interp) + -- load the options from the the project file + local results, errors = interp:load(xmake._PROJECT_FILE, "option", true, enable_filter) + if not results then + return nil, errors + end + + -- check options + local options = {} + for optionname, optioninfo in pairs(results) do + + -- init a option instance + local instance = table.inherit(option) + assert(instance) + + -- save name and info + instance._NAME = optionname + instance._INFO = optioninfo + + -- save it + options[optionname] = instance + end + + -- ok? + return options + +end + +-- get the project menu +function project.menu() + -- attempt to load options from the project file local options = nil local errors = nil - local projectfile = xmake._PROJECT_FILE - if projectfile and os.isfile(projectfile) then - options, errors = interp:load(projectfile, "option", true, false) + if os.isfile(xmake._PROJECT_FILE) then + options, errors = project.options(false) end -- failed? @@ -873,7 +677,7 @@ function project.menu() -- make the category local category = "default" - if opt.category then category = table.unwrap(opt.category) end + if opt:get("category") then category = table.unwrap(opt:get("category")) end options_by_category[category] = options_by_category[category] or {} -- append option to the current category @@ -889,12 +693,12 @@ function project.menu() for name, opt in pairs(opts) do -- show menu? - if opt.showmenu then + if opt:get("showmenu") then -- the default value local default = "auto" - if opt.enable ~= nil then - default = opt.enable + if opt:get("enable") ~= nil then + default = opt:get("enable") end -- is first? @@ -908,8 +712,8 @@ function project.menu() end -- append it - if opt.description then - table.insert(menu, {nil, name, "kv", default, opt.description}) + if opt:get("description") then + table.insert(menu, {nil, name, "kv", default, opt:get("description")}) else table.insert(menu, {nil, name, "kv", default, nil}) end diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index 6b1da3215..a7fd954d3 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -27,7 +27,9 @@ local target = target or {} local os = require("base/os") local path = require("base/path") local table = require("base/table") +local option = require("project/option") local config = require("project/config") +local linker = require("platform/linker") local platform = require("platform/platform") -- get the filename from the given name and kind @@ -60,6 +62,39 @@ function target.name(self) return self._NAME end +-- get the linker with the target kind +function target.linker(self) + + -- init the linker from the given kind + local result = linker.init(self:get("kind")) + if not result then + os.raise("cannot get linker with kind: %s", self:get("kind")) + end + + -- ok? + return result + +end + +-- get the options +function target.options(self) + + -- the options + local options = {} + for _, name in ipairs(table.wrap(self:get("options"))) do + + -- get option if be enabled + local opt = nil + if config.get(name) then opt = poption.load(name) end + if nil ~= opt then + options[name] = opt + end + end + + -- ok? + return options +end + -- get the object file directory function target.objectdir(self) |
