diff options
| author | ruki <[email protected]> | 2015-06-11 11:59:45 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2015-06-11 11:59:45 +0800 |
| commit | 2680c6575a238d0a199f2a31fcf47cd6d0687b62 (patch) | |
| tree | 87bfdd3873bd2d560f3ce1192ba034974535b024 | |
| parent | b5815f7c047221ea4a85333f7a8b6be5a2a4c737 (diff) | |
check includes, links and interfaces
| -rw-r--r-- | tests/console/xmake.lua | 14 | ||||
| -rw-r--r-- | xmake/scripts/base/compiler.lua | 215 | ||||
| -rw-r--r-- | xmake/scripts/base/linker.lua | 73 | ||||
| -rw-r--r-- | xmake/scripts/base/main.lua | 54 | ||||
| -rw-r--r-- | xmake/scripts/base/makefile.lua | 2 | ||||
| -rw-r--r-- | xmake/scripts/base/project.lua | 143 | ||||
| -rw-r--r-- | xmake/scripts/base/rule.lua | 1 |
7 files changed, 414 insertions, 88 deletions
diff --git a/tests/console/xmake.lua b/tests/console/xmake.lua index 981ab0cd4..d352e5785 100644 --- a/tests/console/xmake.lua +++ b/tests/console/xmake.lua @@ -29,31 +29,31 @@ end add_option("option1") set_option_default(true) - add_option_defines("OPTION1_ENABLE") + add_option_defines_if_ok("OPTION1_ENABLE") set_option_description("The option for definition and need not check.") add_option("option2") set_option_default(false) - add_option_defines("OPTION2_ENABLE") - add_option_includes("stdio.h", "hello1.h") + add_option_defines_if_ok("OPTION2_ENABLE") + add_option_cincludes("stdio.h", "hello1.h") add_option_includedirs("src/hello1") set_option_description("The option for finding includes.") add_option("option3") set_option_default(false) - add_option_defines("OPTION3_ENABLE") + add_option_defines_if_ok("OPTION3_ENABLE") add_option_links("hello1") add_option_linkdirs("$(buildir)") set_option_description("The option for finding links.") add_option("option4") set_option_default(false) - add_option_defines("OPTION4_ENABLE") - add_option_includes("stdio.h", "hello1.h") + add_option_defines_if_ok("OPTION4_ENABLE") + add_option_cincludes("stdio.h", "hello1.h") add_option_includedirs("src/hello1") add_option_links("hello1") add_option_linkdirs("$(buildir)") - add_option_interfaces("hello1") + add_option_cfuncs("hello1") set_option_description("The option for finding interfaces.") add_target("hello1") diff --git a/xmake/scripts/base/compiler.lua b/xmake/scripts/base/compiler.lua index 685d8dc66..8120bd037 100644 --- a/xmake/scripts/base/compiler.lua +++ b/xmake/scripts/base/compiler.lua @@ -25,6 +25,7 @@ local compiler = compiler or {} -- load modules local path = require("base/path") +local rule = require("base/rule") local utils = require("base/utils") local table = require("base/table") local string = require("base/string") @@ -102,6 +103,28 @@ function compiler._getflags(module, names, flags) return flags_mapped end +-- get the flag names from the given compiler name +function compiler._flagnames(name) + + -- check + assert(name) + + -- the flag names + local flagnames = nil + if name == "cc" then flagnames = { "cxflags", "cflags" } + elseif name == "cxx" then flagnames = { "cxflags", "cxxflags" } + elseif name == "mm" then flagnames = { "mxflags", "mflags" } + elseif name == "mxx" then flagnames = { "mxflags", "mxxflags" } + elseif name == "as" then flagnames = { "asflags" } + -- error + utils.error("unknown compiler: %s", name) + return + end + + -- ok + return flagnames +end + -- get the compiler name from the source file type function compiler._name(srcfile) @@ -159,31 +182,19 @@ function compiler.make(module, target, srcfile, objfile) -- check assert(module and target) - -- the compiler name - local name = module._NAME - assert(name) - -- the flag names - local flag_names = nil - if name == "cc" then flag_names = { "cxflags", "cflags" } - elseif name == "cxx" then flag_names = { "cxflags", "cxxflags" } - elseif name == "mm" then flag_names = { "mxflags", "mflags" } - elseif name == "mxx" then flag_names = { "mxflags", "mxxflags" } - elseif name == "as" then flag_names = { "asflags" } - -- error - utils.error("unknown compiler: %s", name) - return - end + local flagnames = compiler._flagnames(module._NAME) + assert(flagnames) -- append the common flags from the current compiler local flags = {} - for _, flag_name in ipairs(flag_names) do - table.join2(flags, module[flag_name]) + for _, flagname in ipairs(flagnames) do + table.join2(flags, module[flagname]) end -- append the target flags from the current project - for _, flag_name in ipairs(flag_names) do - table.join2(flags, compiler._mapflags(module, target[flag_name])) + for _, flagname in ipairs(flagnames) do + table.join2(flags, compiler._mapflags(module, target[flagname])) end -- append the symbols flags from the current project @@ -257,13 +268,177 @@ function compiler.make(module, target, srcfile, objfile) end -- append the flags from the configure - for _, flag_name in ipairs(flag_names) do - table.join2(flags, compiler._mapflags(module, config.get(flag_name))) + for _, flagname in ipairs(flagnames) do + table.join2(flags, compiler._mapflags(module, config.get(flagname))) end -- make the compile command return module.command_compile(srcfile, objfile, table.concat(flags, " "):trim()) end +-- check include for the project option +function compiler.check_include(opt, include, srcpath, objpath) + + -- check + assert(opt and include and srcpath and objpath) + + -- open the checking source file + local srcfile = io.open(srcpath, "w") + if not srcfile then return end + + -- make include + srcfile:write(string.format("#include <%s>\n\n", include)) + + -- make the main function header + srcfile:write("int main(int argc, char** argv)\n") + srcfile:write("{\n") + srcfile:write(" return 0;\n") + srcfile:write("}\n") + + -- exit this file + srcfile:close() + + -- get the compiler + local c = compiler.get(srcpath) + if not c then return end + + -- the flag names + local flagnames = compiler._flagnames(c._NAME) + assert(flagnames) + + -- append the common flags + local flags = {} + for _, flagname in ipairs(flagnames) do + table.join2(flags, c[flagname]) + end + + -- append the option flags + for _, flagname in ipairs(flagnames) do + table.join2(flags, compiler._mapflags(c, opt[flagname])) + end + + -- append the defines flags + if opt.defines and c.flag_define then + local defines = utils.wrap(opt.defines) + for _, define in ipairs(defines) do + table.join2(flags, c.flag_define(define)) + end + end + + -- append the undefines flags + if opt.undefines and c.flag_undefine then + local undefines = utils.wrap(opt.undefines) + for _, undefine in ipairs(undefines) do + table.join2(flags, c.flag_undefine(undefine)) + end + end + + -- append the includedirs flags + if opt.includedirs and c.flag_includedir then + for _, includedir in ipairs(utils.wrap(opt.includedirs)) do + table.join2(flags, c.flag_includedir(includedir)) + end + end + + -- make the compile command + local cmd = string.format("%s > %s 2>&1", c.command_compile(srcpath, objpath, table.concat(flags, " "):trim()), xmake._NULDEV) + if not cmd then return end + + -- check it + if 0 ~= os.execute(cmd) then return end + + -- ok + return true +end + +-- check function for the project option +function compiler.check_function(opt, interface, srcpath, objpath) + + -- check + assert(opt and interface) + + -- open the checking source file + local srcfile = io.open(srcpath, "w") + if not srcfile then return end + + -- get the compiler + local c = compiler.get(srcpath) + if not c then return end + + -- make includes + local includes = nil + if c._NAME == "cc" then includes = opt.cincludes + elseif c._NAME == "cxx" then includes = opt.cxxincludes + end + if includes then + for _, include in ipairs(utils.wrap(includes)) do + srcfile:write(string.format("#include <%s>\n", include)) + end + srcfile:write("\n") + end + + -- make the main function header + srcfile:write("int main(int argc, char** argv)\n") + srcfile:write("{\n") + + -- make interfaces + srcfile:write(string.format(" volatile void* p%s = (void*)&%s;\n\n", interface, interface)) + + -- make the main function tailer + srcfile:write(" return 0;\n") + srcfile:write("}\n") + + -- exit this file + srcfile:close() + + -- the flag names + local flagnames = compiler._flagnames(c._NAME) + assert(flagnames) + + -- append the common flags + local flags = {} + for _, flagname in ipairs(flagnames) do + table.join2(flags, c[flagname]) + end + + -- append the option flags + for _, flagname in ipairs(flagnames) do + table.join2(flags, compiler._mapflags(c, opt[flagname])) + end + + -- append the defines flags + if opt.defines and c.flag_define then + local defines = utils.wrap(opt.defines) + for _, define in ipairs(defines) do + table.join2(flags, c.flag_define(define)) + end + end + + -- append the undefines flags + if opt.undefines and c.flag_undefine then + local undefines = utils.wrap(opt.undefines) + for _, undefine in ipairs(undefines) do + table.join2(flags, c.flag_undefine(undefine)) + end + end + + -- append the includedirs flags + if opt.includedirs and c.flag_includedir then + for _, includedir in ipairs(utils.wrap(opt.includedirs)) do + table.join2(flags, c.flag_includedir(includedir)) + end + end + + -- make the compile command + local cmd = string.format("%s > %s 2>&1", c.command_compile(srcpath, objpath, table.concat(flags, " "):trim()), xmake._NULDEV) + if not cmd then return end + + -- check it + if 0 ~= os.execute(cmd) then return end + + -- ok + return true +end + -- return module: compiler return compiler diff --git a/xmake/scripts/base/linker.lua b/xmake/scripts/base/linker.lua index cefb24050..517f376fc 100644 --- a/xmake/scripts/base/linker.lua +++ b/xmake/scripts/base/linker.lua @@ -101,6 +101,31 @@ function linker._getflags(module, names, flags) return flags_mapped end +-- get the linker from the given kind +function linker.get(kind) + + -- check + assert(kind) + + -- get the linker name from the kind + local name = nil + if kind == "binary" then name = "ld" + elseif kind == "static" then name = "ar" + elseif kind == "shared" then name = "sh" + else return end + + -- get it + local module = tools.get(name) + + -- invalid linker? + if module and not module.command_link then + return + end + + -- ok? + return module +end + -- make the link command function linker.make(module, target, objfiles, targetfile) @@ -156,30 +181,42 @@ function linker.make(module, target, objfiles, targetfile) return module.command_link(table.concat(objfiles, " "), targetfile, table.concat(flags, " "):trim()) end --- get the linker from the given kind -function linker.get(kind) +-- check link for the project option +function linker.check_link(opt, link, objectfile, targetfile) -- check - assert(kind) + assert(opt and link and objectfile and targetfile) - -- get the linker name from the kind - local name = nil - if kind == "binary" then name = "ld" - elseif kind == "static" then name = "ar" - elseif kind == "shared" then name = "sh" - else return end - - -- get it - local module = tools.get(name) + -- get the linker + local l = linker.get("binary") + assert(l and l.flag_link) - -- invalid linker? - if module and not module.command_link then - return + -- append the common flags + local flags = {} + table.join2(flags, l.ldflags) + + -- append the option flags + table.join2(flags, linker._mapflags(l, opt.ldflags)) + + -- append the linkdirs flags + if opt.linkdirs and l.flag_linkdir then + for _, linkdir in ipairs(utils.wrap(opt.linkdirs)) do + table.join2(flags, l.flag_linkdir(linkdir)) + end end - -- ok? - return module -end + -- append the links flags + table.join2(flags, l.flag_link(link)) + -- make the compile command + local cmd = string.format("%s > %s 2>&1", l.command_link(objectfile, targetfile, table.concat(flags, " "):trim()), xmake._NULDEV) + if not cmd then return end + + -- check it + if 0 ~= os.execute(cmd) then return end + + -- ok + return true +end -- return module: linker return linker diff --git a/xmake/scripts/base/main.lua b/xmake/scripts/base/main.lua index 2f038c8cd..888c4d41a 100644 --- a/xmake/scripts/base/main.lua +++ b/xmake/scripts/base/main.lua @@ -87,7 +87,7 @@ local menu = } -- prepare global -function main._prepare_global() +function main._init_global() -- the options local options = xmake._OPTIONS @@ -110,8 +110,8 @@ function main._prepare_global() return true end --- prepare project -function main._prepare_project() +-- init project +function main._init_project() -- the options local options = xmake._OPTIONS @@ -132,6 +132,21 @@ function main._prepare_project() -- probe the current platform platform.probe(false) + end + + -- merge the default options + for k, v in pairs(options._DEFAULTS) do + if nil == options[k] then options[k] = v end + end + + -- make the current platform configure + if not platform.make() then + return string.format("make platform configure: %s failed!", config.get("plat")) + end + + -- xmake config or marked as "reconfig"? + if options._ACTION == "config" or config._RECONFIG then + -- probe the current project project.probe() @@ -140,11 +155,6 @@ function main._prepare_project() end - -- merge the default options - for k, v in pairs(options._DEFAULTS) do - if nil == options[k] then options[k] = v end - end - -- load the project return project.load() end @@ -200,35 +210,21 @@ function main._done_option() return action.done("lua") end - -- prepare global - main._prepare_global() + -- init global + main._init_global() -- done global? if options._ACTION == "global" then return action.done("global") end - -- prepare project - local errors = main._prepare_project() + -- init project + local errors = main._init_project() if errors then -- error utils.error(errors) return false end - - -- make the current platform configure - if not platform.make() then - -- error - utils.error("make platform configure: %s failed!", config.get("plat")) - return false - end - - -- enter the project directory - if not os.cd(xmake._PROJECT_DIR) then - -- error - utils.error("not found project: %s!", xmake._PROJECT_DIR) - return false - end -- reconfig it first if marked as "reconfig" if config._RECONFIG and not action.done("config") then @@ -262,6 +258,12 @@ function main._init() xmake._PROJECT_FILE = projectfile assert(projectfile) + -- enter the project directory + if not os.cd(xmake._PROJECT_DIR) then + -- error + utils.error("not found project: %s!", xmake._PROJECT_DIR) + return false + end end -- the main function diff --git a/xmake/scripts/base/makefile.lua b/xmake/scripts/base/makefile.lua index 9287c1bae..0453df95d 100644 --- a/xmake/scripts/base/makefile.lua +++ b/xmake/scripts/base/makefile.lua @@ -43,7 +43,7 @@ function makefile._make_object(file, target, srcfile, objfile) assert(file and target and srcfile and objfile) -- get the compiler - local c = compiler.get(srcfile); + local c = compiler.get(srcfile) if not c then -- error utils.error("unknown source file: %s", srcfile) diff --git a/xmake/scripts/base/project.lua b/xmake/scripts/base/project.lua index bad0e215f..d78bb7d5f 100644 --- a/xmake/scripts/base/project.lua +++ b/xmake/scripts/base/project.lua @@ -24,10 +24,15 @@ 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") -- the current mode is belong to the given modes? function project._api_modes(env, ...) @@ -213,12 +218,14 @@ function project._filter(values) -- filter all local newvals = {} for _, v in ipairs(utils.wrap(values)) do - v = v:gsub("%$%((.*)%)", function (w) - local r = config.get(w) - if r and type(r) == "string" then return r - elseif w == "projectdir" then return xmake._PROJECT_DIR - end - end) + if type(v) == "string" then + v = v:gsub("%$%((.*)%)", function (w) + local r = config.get(w) + if r and type(r) == "string" then return r + elseif w == "projectdir" then return xmake._PROJECT_DIR + end + end) + end table.insert(newvals, v) end @@ -381,9 +388,97 @@ function project._make_targets(configs) end -- make option -function project._make_option(name, opt) +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 includes and functions + if opt.cincludes or opt.cxxincludes then + + -- check cincludes + for _, cinclude in ipairs(utils.wrap(opt.cincludes)) do + + -- check cinclude + local ok = compiler.check_include(opt, cinclude, cfile, objectfile) + + -- trace + utils.verbose("checking for the c include %s ... %s", cinclude, utils.ifelse(ok, "ok", "no")) + + -- failed + if not ok then return end + end + + -- check cxxincludes + for _, cinclude in ipairs(utils.wrap(opt.cxxincludes)) do + + -- check cxxinclude + local ok = compiler.check_include(opt, cxxinclude, cxxfile, objectfile) + + -- trace + utils.verbose("checking for the c++ include %s ... %s", cxxinclude, utils.ifelse(ok, "ok", "no")) + + -- failed + if not ok then return end + end + + -- check cfuncs + for _, cfunc in ipairs(utils.wrap(opt.cfuncs)) do + + -- check function + local ok = compiler.check_function(opt, cfunc, cfile, objectfile) + + -- trace + utils.verbose("checking for the c function %s ... %s", cfunc, utils.ifelse(ok, "ok", "no")) + + -- failed + if not ok then return end + end + + -- check cxxfuncs + for _, cxxfunc in ipairs(utils.wrap(opt.cxxfuncs)) do + + -- check function + local ok = compiler.check_function(opt, cxxfunc, cxxfile, objectfile) + + -- trace + utils.verbose("checking for the c++ function %s ... %s", cxxfunc, utils.ifelse(ok, "ok", "no")) + -- failed + if not ok then return end + end + end + + -- check links + if opt.links then + for _, link in ipairs(utils.wrap(opt.links)) do + + -- check link + local ok = linker.check_link(opt, link, objectfile, targetfile) + + -- trace + utils.verbose("checking for the link %s ... %s", link, utils.ifelse(ok, "ok", "no")) + + -- failed + if not ok then return end + end + end + -- ok + return opt end -- make options from the project file @@ -392,6 +487,16 @@ 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 @@ -399,7 +504,7 @@ function project._make_options(configs) if nil == config.get(k) then -- make option - local o = project._make_option(k, v) + local o = project._make_option(k, v, cfile, cxxfile, objectfile, targetfile) if o then -- enable this option @@ -419,9 +524,16 @@ function project._make_options(configs) end -- trace - utils.verbose("checking for %s ... %s", k, utils.ifelse(o, "ok", "no")) + utils.verbose("checking for the option %s ... %s", k, utils.ifelse(o, "ok", "no")) 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 @@ -462,18 +574,19 @@ function project._load_options(file) interfaces = { "links" , "linkdirs" , "includedirs" - , "includes" - , "interfaces" + , "cincludes" + , "cxxincludes" + , "cfuncs" + , "cxxfuncs" , "cflags" , "cxflags" , "cxxflags" - , "mflags" - , "mxflags" - , "mxxflags" , "ldflags" , "shflags" , "defines" - , "undefines"} + , "undefines" + , "defines_if_ok" + , "undefines_if_ok"} for _, interface in ipairs(interfaces) do newenv["add_option_" .. interface] = function (...) return project._api_add_values(newenv._OPTION, interface, ...) end diff --git a/xmake/scripts/base/rule.lua b/xmake/scripts/base/rule.lua index 6ce441be8..321ceb8c6 100644 --- a/xmake/scripts/base/rule.lua +++ b/xmake/scripts/base/rule.lua @@ -28,7 +28,6 @@ local os = require("base/os") local path = require("base/path") local utils = require("base/utils") local config = require("base/config") -local project = require("base/project") local platform = require("platform/platform") -- get the building log file path |
