diff options
| author | ruki <[email protected]> | 2017-06-27 20:50:52 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2017-06-27 20:50:52 +0800 |
| commit | 02089d7955813aee5d34671f2a92639d8b8bd7d3 (patch) | |
| tree | d8fcfb023190972826d7679d960d9d999941bc4e | |
| parent | d88cab7a400904e6a44f795479cbc3f2bdcc6297 (diff) | |
improve option.check using has_cxsnippets
| -rw-r--r-- | xmake/core/project/option.lua | 404 | ||||
| -rw-r--r-- | xmake/core/tool/tool.lua | 4 | ||||
| -rw-r--r-- | xmake/modules/lib/detect/has_cxsnippets.lua | 56 |
3 files changed, 80 insertions, 384 deletions
diff --git a/xmake/core/project/option.lua b/xmake/core/project/option.lua index 403945f97..2b0746281 100644 --- a/xmake/core/project/option.lua +++ b/xmake/core/project/option.lua @@ -26,18 +26,19 @@ local option = option or {} -- load modules -local io = require("base/io") -local os = require("base/os") -local path = require("base/path") -local table = require("base/table") -local utils = require("base/utils") -local option_ = require("base/option") -local config = require("project/config") -local cache = require("project/cache") -local linker = require("tool/linker") -local compiler = require("tool/compiler") -local sandbox = require("sandbox/sandbox") -local language = require("language/language") +local io = require("base/io") +local os = require("base/os") +local path = require("base/path") +local table = require("base/table") +local utils = require("base/utils") +local option_ = require("base/option") +local config = require("project/config") +local cache = require("project/cache") +local linker = require("tool/linker") +local compiler = require("tool/compiler") +local sandbox = require("sandbox/sandbox") +local language = require("language/language") +local import = require("sandbox/modules/import") -- get cache function option._cache() @@ -54,370 +55,65 @@ function option._cache() return option._CACHE end --- check link -function option:_check_link(sourcefile, objectfile, targetfile) +-- check option for c/c++ +function option:_check_cx(kind) - -- check - assert(sourcefile and objectfile and targetfile) - - -- update source kinds - self._SOURCEKINDS = language.sourcekind_of(sourcefile) - - -- load the linker instance - local instance = linker.load("binary", self._SOURCEKINDS) - if not instance then - return false - end - - -- attempt to link it - return instance:link(objectfile, targetfile, {target = self}) -end - --- check include -function option:_check_include(include, srcpath, objpath) - - -- check - assert(srcpath and objpath) - - -- open the checking source file - local srcfile = io.open(srcpath, "w") - if not srcfile then - return false - end - - -- make include - if include then - srcfile:print("#include <%s>\n", include) - end - - -- make the main function header - srcfile:print("int main(int argc, char** argv)") - srcfile:print("{") - srcfile:print(" return 0;") - srcfile:print("}") - - -- exit this file - srcfile:close() - - -- load the compiler instance - local instance = compiler.load(language.sourcekind_of(srcpath)) - if not instance then - return false - end - - -- attempt to compile it - return instance:compile(srcpath, objpath, {target = self}) -end - --- check function -function option:_check_function(checkcode, srcpath, objpath) - - -- check - assert(checkcode) - - -- open the checking source file - local srcfile = io.open(srcpath, "w") - if not srcfile then - return false - end - - -- get source kind - local sourcekind = language.sourcekind_of(srcpath) - - -- load the compiler instance - local instance = compiler.load(sourcekind) - if not instance then - return false - end - - -- make includes - local includes = nil - if sourcekind == "cc" then includes = self:get("cincludes") - elseif sourcekind == "cxx" then includes = self:get("cxxincludes") - end - if includes then - for _, include in ipairs(table.wrap(includes)) do - srcfile:print("#include <%s>", include) - end - srcfile:print("") - end - - -- make the main function header - srcfile:print("int main(int argc, char** argv)") - srcfile:print("{") - - -- make check code - srcfile:print(" %s;", checkcode) + -- get snippets + local snippets = self:get(kind .. "snippet") - -- make the main function tailer - srcfile:print(" return 0;") - srcfile:print("}") + -- get types + local types = self:get(kind .. "types") - -- exit this file - srcfile:close() + -- get funcs + local funcs = self:get(kind .. "funcs") - -- attempt to compile it - return instance:compile(srcpath, objpath, {target = self}) -end - --- check type -function option:_check_type(typename, srcpath, objpath) - - -- check - assert(typename) - - -- open the checking source file - local srcfile = io.open(srcpath, "w") - if not srcfile then - return false - end - - -- get source kind - local sourcekind = language.sourcekind_of(srcpath) - - -- load the compiler instance - local instance = compiler.load(sourcekind) - if not instance then - return false - end - - -- make includes - local includes = nil - if sourcekind == "cc" then includes = self:get("cincludes") - elseif sourcekind == "cxx" then includes = self:get("cxxincludes") - end - if includes then - for _, include in ipairs(table.wrap(includes)) do - srcfile:print("#include <%s>", include) - end - srcfile:print("") - end - - -- make the main function header - srcfile:print("int main(int argc, char** argv)") - srcfile:print("{") - - -- make interfaces - srcfile:print(" typedef %s __type_xxx;", typename) - - -- make the main function tailer - srcfile:print(" return 0;") - srcfile:print("}") - - -- exit this file - srcfile:close() - - -- attempt to compile it - return instance:compile(srcpath, objpath, {target = self}) -end - --- check snippet -function option:_check_snippet(snippet, srcpath, objpath) - - -- check - assert(snippet) - - -- get source kind - local sourcekind = language.sourcekind_of(srcpath) - - -- load the compiler instance - local instance = compiler.load(sourcekind) - if not instance then - return false - end - - -- write snippet to source file - if not io.writefile(srcpath, snippet) then - return false - end - - -- attempt to compile it - return instance:compile(srcpath, objpath, {target = self}) -end + -- get links + local links = self:get(kind .. "links") --- check option for checking links -function option:_check_links(cfile, objectfile, targetfile) + -- get includes + local includes = self:get(kind .. "includes") - -- get links - local links = self:get("links") - if not links then + -- need not check it + if not snippets and not types and not funcs and not links and not includes 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 + -- init source kind + local sourcekind = kind + if kind == "c" then + sourcekind = "cc" end - - -- only for compile a object file - local ok, errors = self:_check_include(nil, cfile, objectfile) - -- check link - if ok then ok, errors = self:_check_link(cfile, objectfile, targetfile) end + -- import has_cxsnippets() + self._has_cxsnippets = self._has_cxsnippets or import("lib.detect.has_cxsnippets") - -- trace - utils.cprint("checking for the links %s ... %s", links_str, utils.ifelse(ok, "${green}ok", "${red}no")) - if not ok and option_.get("verbose") then - utils.cprint("${red}" .. (errors or "")) + -- get the tool name from the program + local ok, results_or_errors = sandbox.load(self._has_cxsnippets, snippets, {name = self:name(), target = self, sourcekind = sourcekind, types = types, funcs = funcs, includes = includes}) + if not ok then + return false, results_or_errors end - -- cache the result - option._CHECKED_LINKS[links_str] = ok - -- ok? - return ok -end - --- check option for checking includes -function option:_check_includes(kind, file, objectfile) - - -- done - for _, include in ipairs(table.wrap(self:get(kind .. "includes"))) do - - -- this include has been checked? - option._CHECKED_INCLUDES = option._CHECKED_INCLUDES or {} - if option._CHECKED_INCLUDES[include] then return true end - - -- check include - local ok, errors = self:_check_include(include, file, objectfile) - - -- trace - utils.cprint("checking for the %s include %s ... %s", kind, include, utils.ifelse(ok, "${green}ok", "${red}no")) - if not ok and option_.get("verbose") then - utils.cprint("${red}" .. (errors or "")) - end - - -- cache the result - option._CHECKED_INCLUDES[include] = ok - - -- failed - if not ok then return false end - end - - -- ok - return true -end - --- check option for checking functions -function option:_check_functions(kind, file, objectfile, targetfile) - - -- done - for _, checkinfo in ipairs(table.wrap(self:get(kind .. "funcs"))) do - - -- parse the check code - local checkname, checkcode = option.checkinfo(checkinfo) - assert(checkname and checkcode) - - -- check function - local ok, errors = self:_check_function(checkcode, file, objectfile) - - -- check link - if ok and self:get("links") then ok, errors = self:_check_link(file, objectfile, targetfile) end - - -- trace - utils.cprint("checking for the %s function %s ... %s", kind, checkname, utils.ifelse(ok, "${green}ok", "${red}no")) - if not ok and option_.get("verbose") then - utils.cprint("${red}" .. (errors or "")) - end - - -- failed - if not ok then return false end - end - - -- ok - return true -end - --- check option for checking types -function option:_check_types(kind, file, objectfile, targetfile) - - -- done - for _, t in ipairs(table.wrap(self:get(kind .. "types"))) do - - -- check type - local ok, errors = self:_check_type(t, file, objectfile) - - -- trace - utils.cprint("checking for the %s type %s ... %s", kind, t, utils.ifelse(ok, "${green}ok", "${red}no")) - if not ok and option_.get("verbose") then - utils.cprint("${red}" .. (errors or "")) - end - - -- failed - if not ok then return false end - end - - -- ok - return true -end - --- check option for checking snippets -function option:_check_snippets(kind, file, objectfile, targetfile) - - -- done - for name, snippet in pairs(table.wrap(self:get(kind .. "snippet"))) do - - -- check snippet - local ok, errors = self:_check_snippet(snippet, file, objectfile) - - -- trace - utils.cprint("checking for the %s snippet %s ... %s", kind, name, utils.ifelse(ok, "${green}ok", "${red}no")) - if not ok and option_.get("verbose") then - utils.cprint("${red}" .. (errors or "")) - end - - -- failed - if not ok then return false end - end - - -- ok - return true + return results_or_errors end -- check option -function option:_check_condition() - - -- the files - local cfile = os.tmpfile() .. ".c" - local cxxfile = os.tmpfile() .. ".cpp" - local objectfile = os.tmpfile() .. ".obj" - local targetfile = os.tmpfile() .. ".bin" - - -- check links - if not self:_check_links(cfile, objectfile, targetfile) then return false end - - -- check types - if not self:_check_types("c", cfile, objectfile, targetfile) then return false end - if not self:_check_types("cxx", cxxfile, objectfile, targetfile) then return false end +function option:_check() - -- check csnippets - if not self:_check_snippets("c", cfile, objectfile, targetfile) then return false end - if not self:_check_snippets("cxx", cxxfile, objectfile, targetfile) then return false end + -- check it + local ok = self:_check_cx("c") and self:_check_cx("cxx") - -- check includes and functions - if self:get("cincludes") or self:get("cxxincludes") then - - -- check includes - if not self:_check_includes("c", cfile, objectfile) then return false end - if not self:_check_includes("cxx", cxxfile, objectfile) then return false end - - -- check functions - if not self:_check_functions("c", cfile, objectfile, targetfile) then return false end - if not self:_check_functions("cxx", cxxfile, objectfile, targetfile) then return false end + -- get name + local name = self:name() + if name:startswith("__") then + name = name:sub(3) end - -- remove files - os.rm(cfile) - os.rm(cxxfile) - os.rm(objectfile) - os.rm(targetfile) + -- trace + utils.cprint("checking for the %s ... %s", name, utils.ifelse(ok, "${green}ok", "${red}no")) - -- ok - return true + -- ok? + return ok end -- attempt to check option @@ -450,7 +146,7 @@ function option:check(force) self:save() -- check option as boolean switch automatically if the default value not exists - elseif default == nil and self:_check_condition() then + elseif default == nil and self:_check() then -- enable this option config.set(name, true) diff --git a/xmake/core/tool/tool.lua b/xmake/core/tool/tool.lua index 3be75f4d4..67c95cc24 100644 --- a/xmake/core/tool/tool.lua +++ b/xmake/core/tool/tool.lua @@ -116,10 +116,10 @@ function tool.load(kind) end -- import find_toolname() - local find_toolname = import("lib.detect.find_toolname") + tool._find_toolname = tool._find_toolname or import("lib.detect.find_toolname") -- get the tool name from the program - local ok, name_or_errors = sandbox.load(find_toolname, program) + local ok, name_or_errors = sandbox.load(tool._find_toolname, program) if not ok then return nil, name_or_errors end diff --git a/xmake/modules/lib/detect/has_cxsnippets.lua b/xmake/modules/lib/detect/has_cxsnippets.lua index 3d3d1ee42..c00021bb9 100644 --- a/xmake/modules/lib/detect/has_cxsnippets.lua +++ b/xmake/modules/lib/detect/has_cxsnippets.lua @@ -101,8 +101,8 @@ function _sourcecode(snippets, opt) -- enter main function sourcecode = sourcecode .. "int main(int argc, char** argv)\n{\n" - -- add functions - for _, funcinfo in ipairs(opt.functions) do + -- add funcs + for _, funcinfo in ipairs(opt.funcs) do sourcecode = format("%s\n %s;", sourcecode, _funccode(funcinfo)) end @@ -119,9 +119,9 @@ end -- @param opt the argument options -- .e.g -- { name = "", verbose = false, target = [target|option], sourcekind = "[cc|cxx]" --- , types = {"wchar_t", "char*"}, includes = "stdio.h", functions = {"sigsetjmp", "sigsetjmp((void*)0, 0)"}} +-- , types = {"wchar_t", "char*"}, includes = "stdio.h", funcs = {"sigsetjmp", "sigsetjmp((void*)0, 0)"}} -- --- functions: +-- funcs: -- sigsetjmp -- sigsetjmp((void*)0, 0) -- sigsetjmp{sigsetjmp((void*)0, 0);} @@ -134,17 +134,21 @@ end -- local ok = has_csnippets({"void test(){}", "#define TEST 1"}, {types = "wchar_t", includes = "stdio.h"}) -- @endcode -- -function main(csnippets, opt) +function main(snippets, opt) -- init options opt = opt or {} + -- init snippets + snippets = snippets or {} + -- init cache and key local key = opt.name local results = _g._RESULTS or {} -- get result from the cache first if key ~= nil then + key = key .. (opt.sourcekind or "") local ok = results[key] if ok ~= nil then return ok @@ -163,10 +167,10 @@ function main(csnippets, opt) -- get includes local includes = table.wrap(opt.includes) - -- get functions - local functions = {} - for _, funcinfo in ipairs(opt.functions) do - table.insert(functions, _funcname(funcinfo)) + -- get funcs + local funcs = {} + for _, funcinfo in ipairs(opt.funcs) do + table.insert(funcs, _funcname(funcinfo)) end -- make source code @@ -209,25 +213,21 @@ function main(csnippets, opt) -- trace if opt.verbose or option.get("verbose") then - if opt.name then - cprint("checking for the %s ... %s", opt.name, ifelse(ok, "${green}ok", "${red}no")) - else - local kind = ifelse(sourcekind == "cc", "c", "c++") - if #includes > 0 then - cprint("checking for the %s includes %s ... %s", kind, table.concat(includes, ", "), ifelse(ok, "${green}ok", "${red}no")) - end - if #types > 0 then - cprint("checking for the %s types %s ... %s", kind, table.concat(types, ", "), ifelse(ok, "${green}ok", "${red}no")) - end - if #functions > 0 then - cprint("checking for the %s functions %s ... %s", kind, table.concat(functions, ", "), ifelse(ok, "${green}ok", "${red}no")) - end - if #links > 0 then - cprint("checking for the %s links %s ... %s", kind, table.concat(links, ", "), ifelse(ok, "${green}ok", "${red}no")) - end - for _, snippet in ipairs(opt.snippets) do - cprint("checking for the %s snippet %s ... %s", kind, snippet:sub(1, 16), ifelse(ok, "${green}ok", "${red}no")) - end + local kind = ifelse(sourcekind == "cc", "c", "c++") + if #includes > 0 then + cprint("checking for the %s includes %s ... %s", kind, table.concat(includes, ", "), ifelse(ok, "${green}ok", "${red}no")) + end + if #types > 0 then + cprint("checking for the %s types %s ... %s", kind, table.concat(types, ", "), ifelse(ok, "${green}ok", "${red}no")) + end + if #funcs > 0 then + cprint("checking for the %s funcs %s ... %s", kind, table.concat(funcs, ", "), ifelse(ok, "${green}ok", "${red}no")) + end + if #links > 0 then + cprint("checking for the %s links %s ... %s", kind, table.concat(links, ", "), ifelse(ok, "${green}ok", "${red}no")) + end + for _, snippet in ipairs(snippets) do + cprint("checking for the %s snippet %s ... %s", kind, snippet:sub(1, 16), ifelse(ok, "${green}ok", "${red}no")) end end |
