diff options
| author | ruki <[email protected]> | 2016-01-14 09:19:14 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2016-01-14 09:19:14 +0800 |
| commit | cdcf953259aee5e7e1a06855ddbedbaabf585bc9 (patch) | |
| tree | 47b8e5de10522cca3b67354fa527b3525193e880 /xmake/core | |
| parent | 8c50566e7ab2139b9f6c2976b9ce875b7ad11b7a (diff) | |
rename script directory to core
Diffstat (limited to 'xmake/core')
87 files changed, 16735 insertions, 0 deletions
diff --git a/xmake/core/_xmake_main.lua b/xmake/core/_xmake_main.lua new file mode 100644 index 000000000..49fbb0105 --- /dev/null +++ b/xmake/core/_xmake_main.lua @@ -0,0 +1,50 @@ +--!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 _xmake_main.lua +-- + +-- init namespace: xmake +xmake = xmake or {} +xmake._ARGV = _ARGV +xmake._HOST = _HOST +xmake._ARCH = _ARCH +xmake._NULDEV = _NULDEV +xmake._VERSION = _VERSION +xmake._PROGRAM_DIR = _PROGRAM_DIR +xmake._PROJECT_DIR = _PROJECT_DIR +xmake._CORE_DIR = _PROGRAM_DIR .. "/core" +xmake._PACKAGES_DIR = _PROGRAM_DIR .. "/packages" +xmake._TEMPLATES_DIR = _PROGRAM_DIR .. "/templates" +xmake._PROJECT_FILE = "xmake.lua" +xmake._OPTIONS = {} +xmake._CONFIGS = {} + +-- init package path +package.path = xmake._CORE_DIR .. "/?.lua;" .. package.path + +-- load modules +local main = require("base/main") + +-- the main function +function _xmake_main() + + -- done main + return main.done() +end diff --git a/xmake/core/action/_build.lua b/xmake/core/action/_build.lua new file mode 100644 index 000000000..bf660eab5 --- /dev/null +++ b/xmake/core/action/_build.lua @@ -0,0 +1,120 @@ +--!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 _build.lua +-- + +-- define module: _build +local _build = _build or {} + +-- load modules +local rule = require("base/rule") +local utils = require("base/utils") +local clean = require("base/clean") +local config = require("base/config") +local project = require("base/project") +local makefile = require("base/makefile") + +-- need access to the given file? +function _build.need(name) + + -- check + assert(name) + + -- the accessors + local accessors = { config = true, global = true, project = true, platform = true } + + -- need it? + return accessors[name] +end + +-- done +function _build.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- the target name + local target_name = options.target + + -- check target + if not project.checktarget(target_name) then + return false + end + + -- rebuild it? + if options.rebuild or config.get("__rebuild") then + clean.remove(target_name, "build") + -- update it? + elseif options.update then + clean.remove(target_name, "targets") + end + + -- clear rebuild mark and save configure to file + if config.get("__rebuild") then + + -- clear it + config.set("__rebuild", nil) + + -- save the configure + if not config.save() then + -- error + utils.error("update configure failed!") + end + end + + -- check makefile + if not os.isfile(rule.makefile()) then + + -- make the configure file for the given target + if not project.makeconf(options.target) then + -- error + utils.error("make configure failed!") + return false + end + + -- make makefile + if not makefile.make() then + -- error + utils.error("make makefile failed!") + return false + end + end + + -- build target for makefile + if not makefile.build(target_name) then + -- error + print("") + if options.verbose then + io.cat(rule.logfile()) + else + io.tail(rule.logfile(), 32) + end + utils.error("build target: %s failed!\n", target_name) + return false + end + + -- ok + print("build ok!") + return true +end + +-- return module: _build +return _build diff --git a/xmake/core/action/_clean.lua b/xmake/core/action/_clean.lua new file mode 100644 index 000000000..677ff2470 --- /dev/null +++ b/xmake/core/action/_clean.lua @@ -0,0 +1,106 @@ +--!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 _clean.lua +-- + +-- define module: _clean +local _clean = _clean or {} + +-- load modules +local clean = require("base/clean") +local config = require("base/config") +local project = require("base/project") +local utils = require("base/utils") +local platform = require("platform/platform") + +-- need access to the given file? +function _clean.need(name) + + -- check + assert(name) + + -- the accessors + local accessors = { global = true, config = true, project = true, platform = true } + + -- need it? + return accessors[name] +end + +-- done +function _clean.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- check target + if not project.checktarget(options.target) then + return false + end + + -- clean the current target + if not clean.remove(options.target, utils.ifelse(options.all, "all", "build")) then + return false + end + + -- trace + print("clean ok!") + + -- ok + return true +end + +-- the menu +function _clean.menu() + + return { + -- xmake c + shortname = 'c' + + -- usage + , usage = "xmake clean|c [options] [target]" + + -- description + , description = "Remove all binary and temporary files." + + -- options + , options = + { + {'f', "file", "kv", "xmake.lua", "Read a given xmake.lua file." } + , {'P', "project", "kv", nil, "Change to the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + , {} + , {'a', "all", "k", nil, "Clean all auto-generated files by xmake." } + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", "all", "Clean for the given target." } + } + } +end + +-- return module: _clean +return _clean diff --git a/xmake/core/action/_config.lua b/xmake/core/action/_config.lua new file mode 100644 index 000000000..a883b0499 --- /dev/null +++ b/xmake/core/action/_config.lua @@ -0,0 +1,215 @@ +--!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 _config.lua +-- + +-- define module: _config +local _config = _config or {} + +-- load modules +local utils = require("base/utils") +local config = require("base/config") +local project = require("base/project") +local makefile = require("base/makefile") +local platform = require("platform/platform") + +-- need access to the given file? +function _config.need(name) + + -- check + assert(name) + + -- the accessors + local accessors = { config = true, global = true, project = true, platform = true } + + -- need it? + return accessors[name] +end + +-- done +function _config.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- check target + if not project.checktarget(options.target) then + return false + end + + -- trace + print("configure ...") + + -- save the configure + if not config.save() then + -- error + utils.error("save configure failed!") + return false + end + + -- make the configure file for the given target + if not project.makeconf(options.target) then + -- error + utils.error("make configure failed!") + return false + end + + -- make makefile + if not makefile.make() then + -- error + utils.error("make makefile failed!") + return false + end + + -- dump configure + config.dump() + + -- trace + print("configure ok!") + + -- ok + return true +end + +-- the menu +function _config.menu() + + return { + -- xmake f + shortname = 'f' + + -- usage + , usage = "xmake config|f [options] [target]" + + -- description + , description = "Configure the project." + + -- options + , options = + { + {'c', "clean", "k", nil, "Clean the cached configure and configure all again." } + + , {} + , {'p', "plat", "kv", xmake._HOST, "Compile for the given platform." + , function () + local descriptions = {} + local plats = platform.plats() + if plats then + for i, plat in ipairs(plats) do + descriptions[i] = " - " .. plat + end + end + return descriptions + end } + , {'a', "arch", "kv", "auto", "Compile for the given architecture." + , function () + local descriptions = {} + local plats = platform.plats() + if plats then + for i, plat in ipairs(plats) do + descriptions[i] = " - " .. plat .. ":" + local archs = platform.archs(plat) + if archs then + for _, arch in ipairs(archs) do + descriptions[i] = descriptions[i] .. " " .. arch + end + end + end + end + return descriptions + end } + , {'m', "mode", "kv", "release", "Compile for the given mode." + , " - debug" + , " - release" + , " - profile" } + , {'k', "kind", "kv", "static", "Compile for the given target kind." + , " - static" + , " - shared" + , " - binary" } + , {nil, "host", "kv", xmake._HOST, "The current host environment." } + + -- the options for project + , function () return project.menu() end + + , {} + , {nil, "make", "kv", "auto", "Set the make path." } + , {nil, "ccache", "kv", "auto", "Enable or disable the c/c++ compiler cache." } + + , {} + , {nil, "cross", "kv", nil, "The cross toolchains prefix" + , ".e.g" + , " - i386-mingw32-" + , " - arm-linux-androideabi-" } + , {nil, "toolchains", "kv", nil, "The cross toolchains directory" } + + , {} + , {nil, "cc", "kv", nil, "The C Compiler" } + , {nil, "cxx", "kv", nil, "The C++ Compiler" } + , {nil, "cflags", "kv", nil, "The C Compiler Flags" } + , {nil, "cxflags", "kv", nil, "The C/C++ compiler Flags" } + , {nil, "cxxflags", "kv", nil, "The C++ Compiler Flags" } + + , {} + , {nil, "as", "kv", nil, "The Assembler" } + , {nil, "asflags", "kv", nil, "The Assembler Flags" } + + , {} + , {nil, "sc", "kv", nil, "The Swift Compiler" } + , {nil, "scflags", "kv", nil, "The Swift Compiler Flags" } + + , {} + , {nil, "ld", "kv", nil, "The Linker" } + , {nil, "ldflags", "kv", nil, "The Binary Linker Flags" } + + , {} + , {nil, "ar", "kv", nil, "The Static Library Linker" } + , {nil, "arflags", "kv", nil, "The Static Library Linker Flags" } + + , {} + , {nil, "sh", "kv", nil, "The Shared Library Linker" } + , {nil, "shflags", "kv", nil, "The Shared Library Linker Flags" } + + -- the options for all platforms + , function () return platform.menu("config") end + + , {} + , {'f', "file", "kv", "xmake.lua", "Read a given xmake.lua file." } + , {'P', "project", "kv", nil, "Change to the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + , {'o', "buildir", "kv", "build", "Set the build directory." } + + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", "all", "Configure for the given target." } + } + } +end + +-- return module: _config +return _config diff --git a/xmake/core/action/_create.lua b/xmake/core/action/_create.lua new file mode 100644 index 000000000..840631f65 --- /dev/null +++ b/xmake/core/action/_create.lua @@ -0,0 +1,173 @@ +--!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 _create.lua +-- + +-- define module: _create +local _create = _create or {} + +-- load modules +local utils = require("base/utils") +local template = require("base/template") + +-- need access to the given file? +function _create.need(name) + + -- no accessors + return false +end + +-- done +function _create.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- the target name + local targetname = options.target or options.name or path.basename(xmake._PROJECT_DIR) or "demo" + + -- trace + utils.printf("create %s ...", targetname) + + -- the language + local language = options.language + if not language then + utils.error("no language!") + return false + end + + -- the template id + local templateid = tonumber(options.template) + if type(templateid) ~= "number" then + utils.error("invalid template id: %s!", options.template) + return false + end + + -- load all templates for the given language + local templates = template.loadall(language) + + -- load the template module + local module = nil + if templates then module = templates[templateid] end + if not module then + utils.error("invalid template id: %s!", options.template) + return false + end + + -- enter the template directory + if not module._DIRECTORY or not os.cd(module._DIRECTORY) then + -- error + utils.error("not found template id: %s!", options.template) + return false + end + + -- check the template project + if not os.isdir("project") then + -- errors + utils.error("the template project not exists!") + return false + end + + -- ensure the project directory + if not os.isdir(xmake._PROJECT_DIR) then + os.mkdir(xmake._PROJECT_DIR) + end + + -- copy the project files + local ok, errors = os.cp("project/*", xmake._PROJECT_DIR) + if not ok then + -- errors + utils.error(errors) + return false + end + + -- done the template files + if not module.done(targetname, xmake._PROJECT_DIR, xmake._PACKAGES_DIR) then + utils.error("update the template failed!") + return false + end + + -- trace + utils.printf("create %s ok!", targetname) + + -- ok + return true +end + +-- the menu +function _create.menu() + + return { + -- usage + usage = "xmake create [options] [target]" + + -- description + , description = "Create a new project." + + -- options + , options = + { + {'n', "name", "kv", nil, "The project name." } + , {'f', "file", "kv", "xmake.lua", "Create a given xmake.lua file." } + , {'P', "project", "kv", nil, "Create from the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + , {'l', "language", "kv", "c", "The project language" + , function () + local descriptions = {} + local languages = template.languages() + for _, language in ipairs(languages) do + table.insert(descriptions, " - " .. language) + end + return descriptions + end } + , {'t', "template", "kv", "1", "Select the project template id of the given language." + , function () + local descriptions = {} + local languages = template.languages() + for _, language in ipairs(languages) do + table.insert(descriptions, string.format(" - language: %s", language)) + local templates = template.loadall(language) + if templates then + for i, template in ipairs(templates) do + table.insert(descriptions, string.format(" %d. %s", i, utils.ifelse(template.description, template.description, "The Unknown Project"))) + end + end + end + return descriptions + end } + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", nil, "Create the given target." + , "Uses the project name as target if not exists." } + } + } +end + +-- return module: _create +return _create diff --git a/xmake/core/action/_debug.lua b/xmake/core/action/_debug.lua new file mode 100644 index 000000000..c84d78073 --- /dev/null +++ b/xmake/core/action/_debug.lua @@ -0,0 +1,89 @@ +--!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 _debug.lua +-- + +-- define module: _debug +local _debug = _debug or {} + +-- load modules +local utils = require("base/utils") +local config = require("base/config") +local platform = require("platform/platform") + +-- need access to the given file? +function _debug.need(name) + + -- check + assert(name) + + -- the accessors + local accessors = { config = true, global = true, project = true, platform = true } + + -- need it? + return accessors[name] +end + +-- done +function _debug.done() + + -- TODO + print("not implement!") + + -- ok + return true +end + +-- the menu +function _debug.menu() + + return { + -- xmake d + shortname = 'd' + + -- usage + , usage = "xmake debug|d [options] [target]" + + -- description + , description = "Debug target." + + -- options + , options = + { + {'f', "file", "kv", "xmake.lua", "Create a given xmake.lua file." } + , {'P', "project", "kv", nil, "Create from the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", nil, "Debug a given target" } + } + } +end + +-- return module: _debug +return _debug diff --git a/xmake/core/action/_global.lua b/xmake/core/action/_global.lua new file mode 100644 index 000000000..a8fffa0bc --- /dev/null +++ b/xmake/core/action/_global.lua @@ -0,0 +1,104 @@ +--!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 _global.lua +-- + +-- define module: _global +local _global = _global or {} + +-- load modules +local utils = require("base/utils") +local global = require("base/global") +local platform = require("platform/platform") + +-- need access to the given file? +function _global.need(name) + + -- check + assert(name) + + -- the accessors + local accessors = { global = true } + + -- need it? + return accessors[name] +end + +-- done +function _global.done() + + -- probe the global platform configure + if not platform.probe(true) then + return false + end + + -- clear up the global configure + global.clearup() + + -- save the global configure + if not global.save() then + -- error + utils.error("save configure failed!") + return false + end + + -- dump global + global.dump() + + -- ok + print("configure ok!") + return true +end + +-- the menu +function _global.menu() + + return { + -- xmake g + shortname = 'g' + + -- usage + , usage = "xmake global|g [options] [target]" + + -- description + , description = "Configure the global options for xmake." + + -- options + , options = + { + {'c', "clean", "k", nil, "Clean the cached configure and configure all again." } + , {nil, "make", "kv", "auto", "Set the make path." } + , {nil, "ccache", "kv", "auto", "Enable or disable the c/c++ compiler cache." + , " --ccache=[y|n]" } + + , {} + -- the options for all platforms + , function () return platform.menu("global") end + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + } + } +end + +-- return module: _global +return _global diff --git a/xmake/core/action/_install.lua b/xmake/core/action/_install.lua new file mode 100644 index 000000000..28ef3650d --- /dev/null +++ b/xmake/core/action/_install.lua @@ -0,0 +1,224 @@ +--!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 _install.lua +-- + +-- define module: _install +local _install = _install or {} + +-- load modules +local utils = require("base/utils") +local config = require("base/config") +local global = require("base/global") +local install = require("base/install") +local package = require("base/package") +local project = require("base/project") +local platform = require("platform/platform") + +-- need access to the given file? +function _install.need(name) + + -- no accessors + return false +end + +-- make configure for the given target +function _install._makeconf(configs, target_name, target) + + -- check + assert(configs and target_name and target) + + -- init configs for targets + configs[target_name] = configs[target_name] or {} + local configs_target = configs[target_name] + + -- save the install script + local installscript = target.installscript + if type(installscript) == "string" and os.isfile(installscript) then + local script, errors = loadfile(installscript) + if script then + installscript = script() + if type(installscript) == "table" and installscript.main then + installscript = installscript.main + end + else + utils.error(errors) + return false + end + end + if target.installscript and type(installscript) ~= "function" then + utils.error("invalid install script!") + return false + end + configs_target.installscript = installscript + + -- ok + return true +end + +-- package target +function _install._package(target_name) + + -- get the target name + if not target_name or target_name == "all" then + target_name = "" + end + + -- package it + if os.execute(string.format("xmake p -P %s -f %s %s", xmake._PROJECT_DIR, xmake._PROJECT_FILE, target_name)) ~= 0 then + return false + end + + -- ok + return true +end + +-- done +function _install.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- trace + print("install: ...") + + -- load the global configure first + global.load() + + -- enter the project directory + if not os.cd(xmake._PROJECT_DIR) then + -- errors + utils.error("not found project: %s!", xmake._PROJECT_DIR) + return false + end + + -- package the given target first + if not _install._package(options.target) then + -- errors + utils.error("package: failed!") + return false + end + + -- load the package configure + local configs, errors = package.load() + if not configs then + -- errors + utils.error(errors) + return false + end + + -- reload configure + local errors = config.reload() + if errors then + -- error + utils.error(errors) + return false + end + + -- make the platform configure + if not platform.make() then + utils.error("make platform configure: %s failed!", config.get("plat")) + return false + end + + -- reload project + local errors = project.reload() + if errors then + -- error + utils.error(errors) + return false + end + + -- update the outputdir + for _, target in pairs(configs) do + target.outputdir = options.installdir + end + + -- the targets + local targets = project.targets() + assert(targets) + + -- make configure for the given target + if target_name and target_name ~= "all" then + if not _install._makeconf(configs, target_name, targets[target_name]) then + utils.error("make target configure: %s failed!", target_name) + return false + end + else + for target_name, target in pairs(targets) do + if not _install._makeconf(configs, target_name, target) then + utils.error("make target configure: %s failed!", target_name) + return false + end + end + end + + -- done install + if not install.done(configs) then + -- errors + utils.error("install: failed!") + return false + end + + -- trace + print("install: ok!") + + -- ok + return true +end + +-- the menu +function _install.menu() + + return { + -- xmake i + shortname = 'i' + + -- usage + , usage = "xmake install|i [options] [target]" + + -- description + , description = "Package and install the project binary files." + + -- options + , options = + { + {'f', "file", "kv", "xmake.lua", "Read a given xmake.lua file." } + , {'P', "project", "kv", nil, "Change to the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + , {'o', "installdir", "kv", nil, "Set the install directory." } + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", "all", "Install the given target." } + } + } +end + +-- return module: _install +return _install diff --git a/xmake/core/action/_lua.lua b/xmake/core/action/_lua.lua new file mode 100644 index 000000000..e342d82e7 --- /dev/null +++ b/xmake/core/action/_lua.lua @@ -0,0 +1,168 @@ +--!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 _lua.lua +-- + +-- define module: _lua +local _lua = _lua or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local config = require("base/config") +local string = require("base/string") +local tools = require("tools/tools") +local platform = require("platform/platform") + +-- need access to the given file? +function _lua.need(name) + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- do not load config if be not given -f or -P options + if options.file == nil and options.project == nil then + return false + end + + -- patch target for loading config ok + options.target = "all" + + -- the accessors + local accessors = { config = true, global = true, platform = true } + + -- need it? + return accessors[name] +end + +-- done +function _lua.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- no script? + if not options.script then + return false + end + + -- the arguments + local arguments = options.arguments or {} + if type(arguments) ~= "table" then + arguments = {} + end + + -- is string script? + if options.string then + + -- trace + utils.verbose("script: %s", options.script) + + -- load and run string + local script = loadstring(options.script) + if script then + return script(arguments) + end + else + -- attempt to load script from the given file if exists + local file = options.script + if not path.is_absolute(file) then + file = path.absolute(file) + end + + -- attempt to load script from the tools directory + if not os.isfile(file) then + file = tools.find(options.script, xmake._CORE_DIR .. "/tools") + end + + -- load and run the script file + if os.isfile(file) then + + -- load script + local script = loadfile(file) + if script then + + -- load module + local module = script() + if module then + + -- init module + if module.init then + module:init(options.script) + end + + -- done module + return module:main(arguments) + end + end + end + end + + -- failed + utils.error("cannot run this script: %s", options.script) + return false +end + +-- the menu +function _lua.menu() + + return { + -- xmake l + shortname = 'l' + + -- usage + , usage = "xmake lua|l [options] [script] [arguments]" + + -- description + , description = "Run the lua script." + + -- options + , options = + { + {'f', "file", "kv", nil, "Read a given xmake.lua file." } + , {'P', "project", "kv", nil, "Change to the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + + , {} + , {'s', "string", "k", nil, "Run the lua string script." } + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "script", "v", nil, "Run the given lua script." + , " - The script name from the xmake tool directory" + , " - The script file" + , " - The script string" } + , {nil, "arguments", "vs", nil, "The script arguments" } + } + } +end + +-- return module: _lua +return _lua diff --git a/xmake/core/action/_man.lua b/xmake/core/action/_man.lua new file mode 100644 index 000000000..feb70dd92 --- /dev/null +++ b/xmake/core/action/_man.lua @@ -0,0 +1,89 @@ +--!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 _man.lua +-- + +-- define module: _man +local _man = _man or {} + +-- load modules +local utils = require("base/utils") +local config = require("base/config") +local platform = require("platform/platform") + +-- need access to the given file? +function _man.need(name) + + -- check + assert(name) + + -- the accessors + local accessors = { config = true, global = true, project = true } + + -- need it? + return accessors[name] +end + +-- done +function _man.done() + + -- TODO + print("not implement!") + + -- ok + return true +end + +-- the menu +function _man.menu() + + return { + -- xmake m + shortname = 'm' + + -- usage + , usage = "xmake man|m [options] [target]" + + -- description + , description = "Create a project man." + + -- options + , options = + { + {'f', "file", "kv", "xmake.lua", "Create a given xmake.lua file." } + , {'P', "project", "kv", nil, "Create from the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", "all", "Create man for the given target" } + } + } +end + +-- return module: _man +return _man diff --git a/xmake/core/action/_package.lua b/xmake/core/action/_package.lua new file mode 100644 index 000000000..e39604a33 --- /dev/null +++ b/xmake/core/action/_package.lua @@ -0,0 +1,365 @@ +--!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 _package.lua +-- + +-- define module: _package +local _package = _package or {} + +-- load modules +local rule = require("base/rule") +local path = require("base/path") +local utils = require("base/utils") +local config = require("base/config") +local global = require("base/global") +local string = require("base/string") +local project = require("base/project") +local package = require("base/package") +local platform = require("platform/platform") + +-- need access to the given file? +function _package.need(name) + + -- no accessors + return false +end + +-- configure target for the given architecture +function _package._config(arch, target_name) + + -- need not configure it + if not arch then return true end + + -- done the command + return os.execute(string.format("xmake f -P %s -f %s -a %s %s", xmake._PROJECT_DIR, xmake._PROJECT_FILE, arch, target_name)) == 0; +end + +-- build target for the given architecture +function _package._build(arch, target_name) + + -- get the target name + if not target_name or target_name == "all" then + target_name = "" + end + + -- configure it first + if not _package._config(arch, target_name) then return false end + + -- build it + if os.execute(string.format("xmake -P %s %s", xmake._PROJECT_DIR, target_name)) ~= 0 then + -- errors + utils.error("build failed!") + return false + end + + -- ok + return true +end + +-- backup the target files +function _package._backup(rootdir, filepath) + + -- the relative file path + if filepath and path.is_absolute(filepath) then + filepath = path.relative(filepath, xmake._PROJECT_DIR) + end + + -- not exists? return it directly + if not filepath or not os.isfile(filepath) then return end + + -- the backup file + local backupfile = string.format("%s/%s", rootdir, filepath) + + -- backup it + local ok, errors = os.cp(filepath, backupfile) + if not ok then + -- errors + utils.error(errors) + return + end + + -- ok + return filepath +end + +-- make configure for the given target +function _package._makeconf(target_name, target) + + -- check + assert(target_name and target) + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- the configs + local configs = _package._CONFIGS + assert(configs) + + -- the architecture + local arch = config.get("arch") + if not arch then return false end + + -- init configs for targets + configs[target_name] = configs[target_name] or {} + local configs_target = configs[target_name] + + -- init configs for architectures + configs_target.archs = configs_target.archs or {} + + -- init configs for architecture + configs_target.archs[arch] = configs_target.archs[arch] or {} + local configs_arch = configs_target.archs[arch] + + -- save name + configs_target.name = target_name + + -- save kind + configs_target.kind = target.kind + + -- save the output directory + configs_target.outputdir = options.outputdir or config.get("buildir") + + -- save the header files + configs_target.headers = target.headers + + -- save the target directory + configs_arch.targetdir = rule.backupdir(target_name, arch) + + -- save the config file + configs_arch.config_h = _package._backup(configs_arch.targetdir, rule.config_h(target)) + + -- save the target file + configs_arch.targetfile = _package._backup(configs_arch.targetdir, rule.targetfile(target_name, target)) + + -- save the package script + local packagescript = target.packagescript + if type(packagescript) == "string" and os.isfile(packagescript) then + local script, errors = loadfile(packagescript) + if script then + packagescript = script() + if type(packagescript) == "table" and packagescript.main then + packagescript = packagescript.main + end + else + utils.error(errors) + return false + end + end + if target.packagescript and type(packagescript) ~= "function" then + utils.error("invalid package script!") + return false + end + configs_target.packagescript = packagescript + + -- ok + return true +end + +-- load configure for the given target +function _package._loadconf(target_name) + + -- reload configure + local errors = config.reload() + if errors then + -- error + utils.error(errors) + return false + end + + -- make the platform configure + if not platform.make() then + utils.error("make platform configure: %s failed!", config.get("plat")) + return false + end + + -- reload project + local errors = project.reload() + if errors then + -- error + utils.error(errors) + return false + end + + -- the targets + local targets = project.targets() + assert(targets) + + -- make configure for the given target + if target_name and target_name ~= "all" then + if not _package._makeconf(target_name, targets[target_name]) then + utils.error("make target configure: %s failed!", target_name) + return false + end + else + for target_name, target in pairs(targets) do + if not _package._makeconf(target_name, target) then + utils.error("make target configure: %s failed!", target_name) + return false + end + end + end + + -- ok + return true +end + +-- build target for all architectures +function _package._build_all(archs, target_name) + + -- exists the given architectures? + if archs then + + -- split all architectures + archs = archs:split(",") + if not archs then return false end + + -- build for all architectures + for _, arch in ipairs(archs) do + + -- trim it + arch = arch:trim() + + -- build it + if not _package._build(arch, target_name) then return false end + + -- load configure + if not _package._loadconf(target_name) then return false end + + end + + -- build for single architecture + else + + -- build it + if not _package._build(nil, target_name) then return false end + + -- load configure + if not _package._loadconf(target_name) then return false end + + end + + -- ok + return true +end + +-- done +function _package.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- trace + print("package: ...") + + -- init configs + _package._CONFIGS = _package._CONFIGS or {} + local configs = _package._CONFIGS + + -- load the global configure first + global.load() + + -- enter the project directory + if not os.cd(xmake._PROJECT_DIR) then + -- errors + utils.error("not found project: %s!", xmake._PROJECT_DIR) + return false + end + + -- build the given target first for all architectures + if not _package._build_all(options.archs, options.target) then + -- errors + utils.error("build package failed!") + return false + end + + -- done package + if not package.done(configs) then + -- errors + utils.error("package: failed!") + return false + end + + -- trace + print("package: ok!") + + -- ok + return true +end + +-- the menu +function _package.menu() + + return { + -- xmake p + shortname = 'p' + + -- usage + , usage = "xmake package|p [options] [target]" + + -- description + , description = "Package target." + + -- options + , options = + { + {'a', "archs", "kv", nil, "Package multiple given architectures." + , " .e.g --archs=\"armv7, arm64\" or -a i386" + , "" + , function () + local descriptions = {} + local plats = platform.plats() + if plats then + for i, plat in ipairs(plats) do + descriptions[i] = " - " .. plat .. ":" + local archs = platform.archs(plat) + if archs then + for _, arch in ipairs(archs) do + descriptions[i] = descriptions[i] .. " " .. arch + end + end + end + end + return descriptions + end } + + , {} + , {'f', "file", "kv", "xmake.lua", "Create a given xmake.lua file." } + , {'P', "project", "kv", nil, "Create from the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + , {'o', "outputdir", "kv", nil, "Set the output directory." } + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", "all", "Package a given target" } + } + } +end + +-- return module: _package +return _package diff --git a/xmake/core/action/_run.lua b/xmake/core/action/_run.lua new file mode 100644 index 000000000..64649fcb8 --- /dev/null +++ b/xmake/core/action/_run.lua @@ -0,0 +1,179 @@ +--!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 _run.lua +-- + +-- define module: _run +local _run = _run or {} + +-- load modules +local rule = require("base/rule") +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") + +-- need access to the given file? +function _run.need(name) + + -- check + assert(name) + + -- the accessors + local accessors = { config = true, global = true, project = true, platform = true } + + -- need it? + return accessors[name] +end + +-- done +function _run.done() + + -- the options + local options = xmake._OPTIONS + assert(options and xmake._PROJECT_DIR) + + -- the target name + local name = options.target + if not name then + -- error + utils.error("no runable target!") + return false + end + + -- the arguments + local arguments = options.arguments or {} + if type(arguments) ~= "table" then + arguments = {} + end + + -- the targets + local targets = project.targets() + if not targets or not targets[name] then + -- error + utils.error("not found target: %s!", name) + return false + end + + -- the target + local target = targets[name] + + -- the target file + local targetfile = rule.targetfile(name, target) + if targetfile and not path.is_absolute(targetfile) then + targetfile = path.absolute(targetfile, xmake._PROJECT_DIR) + end + + -- load the run script + local runscript = target.runscript + if type(runscript) == "string" and os.isfile(runscript) then + local script, errors = loadfile(runscript) + if script then + runscript = script() + if type(runscript) == "table" and runscript.main then + runscript = runscript.main + end + else + utils.error(errors) + return false + end + end + + -- run script + if runscript ~= nil then + if type(runscript) == "function" then + + -- make passed target + local target_passed = {} + target_passed.name = name + target_passed.arguments = arguments + target_passed.targetfile = targetfile + + -- run it + local ok = runscript(target_passed) + if ok ~= 0 then return utils.ifelse(ok == 1, true, false) end + else + utils.error("invalid run script!") + return false + end + end + + -- not executale? + if not target.kind or type(target.kind) ~= "string" or target.kind ~= "binary" then + -- error + utils.error("the target %s is not executale!", name) + return false + end + + -- check the target file + if not targetfile and not os.isfile(targetfile) then + -- error + utils.error("not found target file: %s!", targetfile) + return false + end + + -- done + local ok = os.execute(string.format("%s %s", targetfile, table.concat(arguments, " "))) + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- the menu +function _run.menu() + + return { + -- xmake r + shortname = 'r' + + -- usage + , usage = "xmake run|r [options] [target] [arguments]" + + -- description + , description = "Run the project target." + + -- options + , options = + { + {'d', "debug", "k", nil, "Run and debug the given target." } + , {nil, "debugger", "kv", "auto", "Set the debugger path." } + + , {} + , {'f', "file", "kv", "xmake.lua", "Read a given xmake.lua file." } + , {'P', "project", "kv", nil, "Change to the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", nil, "Run the given target." } + , {nil, "arguments", "vs", nil, "The target arguments" } + } + } +end + +-- return module: _run +return _run diff --git a/xmake/core/action/_uninstall.lua b/xmake/core/action/_uninstall.lua new file mode 100644 index 000000000..8f82907d6 --- /dev/null +++ b/xmake/core/action/_uninstall.lua @@ -0,0 +1,160 @@ +--!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 _uninstall.lua +-- + +-- define module: _uninstall +local _uninstall = _uninstall or {} + +-- load modules +local utils = require("base/utils") +local config = require("base/config") +local global = require("base/global") +local install = require("base/install") +local uninstall = require("base/uninstall") +local package = require("base/package") +local project = require("base/project") +local platform = require("platform/platform") + +-- need access to the given file? +function _uninstall.need(name) + + -- no accessors + return false +end + +-- package target +function _uninstall._package(target_name) + + -- get the target name + if not target_name or target_name == "all" then + target_name = "" + end + + -- package it + if os.execute(string.format("xmake p -P %s -f %s %s", xmake._PROJECT_DIR, xmake._PROJECT_FILE, target_name)) ~= 0 then + return false + end + + -- ok + return true +end + + +-- done +function _uninstall.done() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- trace + print("uninstall: ...") + + -- load the global configure first + global.load() + + -- enter the project directory + if not os.cd(xmake._PROJECT_DIR) then + -- errors + utils.error("not found project: %s!", xmake._PROJECT_DIR) + return false + end + + -- load the install configure + local configs, errors = install.load() + if not configs then + -- errors + utils.error(errors) + return false + end + + -- reload configure + local errors = config.reload() + if errors then + -- error + utils.error(errors) + return false + end + + -- make the platform configure + if not platform.make() then + utils.error("make platform configure: %s failed!", config.get("plat")) + return false + end + + -- reload project + local errors = project.reload() + if errors then + -- error + utils.error(errors) + return false + end + + -- done uninstall + if not uninstall.done(configs) then + -- errors + utils.error("uninstall: failed!") + return false + end + + -- trace + print("uninstall: ok!") + + -- ok + return true +end + +-- the menu +function _uninstall.menu() + + return { + -- xmake u + shortname = 'u' + + -- usage + , usage = "xmake uninstall|u [options] [target]" + + -- description + , description = "Uninstall the project binary files." + + -- options + , options = + { + {'f', "file", "kv", "xmake.lua", "Read a given xmake.lua file." } + , {'P', "project", "kv", nil, "Change to the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + + , {} + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", "all", "Install the given target." } + } + } +end + +-- return module: _uninstall +return _uninstall diff --git a/xmake/core/action/action.lua b/xmake/core/action/action.lua new file mode 100644 index 000000000..96e51b5d8 --- /dev/null +++ b/xmake/core/action/action.lua @@ -0,0 +1,190 @@ +--!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 action.lua +-- + +-- define module: action +local action = action or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local global = require("base/global") +local config = require("base/config") +local project = require("base/project") +local platform = require("platform/platform") + +-- load the given action +function action._load(name) + + -- load the given action + return require("action/_" .. name) +end + +-- load the project file +function action._load_project() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- enter the project directory + if not os.cd(xmake._PROJECT_DIR) then + -- error + return string.format("not found project: %s!", xmake._PROJECT_DIR) + end + + -- check the project file + if not os.isfile(xmake._PROJECT_FILE) then + return string.format("not found the project file: %s", xmake._PROJECT_FILE) + end + + -- init the build directory + if options.buildir and path.is_absolute(options.buildir) then + options.buildir = path.relative(options.buildir, xmake._PROJECT_DIR) + end + + -- xmake config or marked as "reconfig"? + if options._ACTION == "config" or config._RECONFIG then + + -- probe the current project + project.probe() + + -- clear up the configure + config.clearup() + + end + + -- load the project + return project.load() +end + +-- done the given action +function action.done(name) + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- load the given action + local _action = action._load(name) + if not _action then return false end + + -- load the global configure first + if _action.need("global") then global.load() end + + -- load the project configure + if _action.need("config") then + local errors = config.load() + if errors then + -- error + utils.error(errors) + return false + end + end + + -- probe the platform + if _action.need("platform") and (options._ACTION == "config" or config._RECONFIG) then + if not platform.probe(false) then + return false + end + 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 platform configure + if _action.need("platform") and not platform.make() then + utils.error("make platform configure: %s failed!", config.get("plat")) + return false + end + + -- load the project file + if _action.need("project") then + local errors = action._load_project() + if errors then + -- error + utils.error(errors) + return false + end + end + + -- reconfig it first if marked as "reconfig" + if _action.need("config") and config._RECONFIG then + + -- config it + local _action_config = action._load("config") + if not _action_config or not _action_config.done() then + -- error + utils.error("reconfig failed for the changed host!") + return false + end + end + + -- done the given action + return _action.done() +end + +-- list the all actions +function action.list() + + -- find all action scripts + local list = {} + local files = os.match(xmake._CORE_DIR .. "/action/_*.lua") + if files then + for _, file in ipairs(files) do + local name = path.basename(file) + if name and name ~= "_build" then + table.insert(list, name:sub(2)) + end + end + end + + -- ok? + return list +end + +-- get the all action menus +function action.menu() + + -- get all actions + local menus = {} + local actions = action.list() + for _, name in ipairs(actions) do + + -- load action + local a = action._load(name) + if a and a.menu then + local m = a.menu() + if m then + menus[name] = m + end + end + end + + -- ok? + return menus +end + +-- return module: action +return action diff --git a/xmake/core/base/clean.lua b/xmake/core/base/clean.lua new file mode 100644 index 000000000..9fbb3258a --- /dev/null +++ b/xmake/core/base/clean.lua @@ -0,0 +1,192 @@ +--!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 clean.lua +-- + +-- define module: clean +local clean = clean or {} + +-- load modules +local os = require("base/os") +local rule = require("base/rule") +local utils = require("base/utils") +local config = require("base/config") +local project = require("base/project") + +-- remove the given files or directories +function clean._remove(filedirs) + + -- empty? + if not filedirs then return true end + + -- wrap it first + filedirs = utils.wrap(filedirs) + for _, filedir in ipairs(filedirs) do + + -- exists? remove it + if os.exists(filedir) then + -- remove it + local ok, errors = os.rm(filedir) + if not ok then + -- error + utils.error(errors) + return false + end + end + end + + -- ok + return true +end + +-- remove the given target name +function clean._remove_target(target_name, target, mode, buildir) + + -- check + assert(target_name and target) + + -- remove the target file + if not clean._remove(rule.targetfile(target_name, target, buildir)) then + return false + end + + -- not only remove target file? + if mode ~= "targets" then + + -- remove the object files + if not clean._remove(rule.objectfiles(target_name, target, rule.sourcefiles(target), buildir)) then + return false + end + + -- remove the header files + local _, dstheaders = rule.headerfiles(target) + if not clean._remove(dstheaders) then + return false + end + + -- remove the config.h file + if mode == "all" and target.config_h then + + -- translate file path + local config_h = nil + if not path.is_absolute(target.config_h) then + config_h = path.absolute(target.config_h, xmake._PROJECT_DIR) + else + config_h = path.translate(target.config_h) + end + if not clean._remove(config_h) then + return false + end + end + end + + -- ok + return true +end + +-- remove the given target and all dependent targets +function clean._remove_target_and_deps(target_name, mode, buildir) + + -- the targets + local targets = project.targets() + assert(targets) + + -- the target + local target = targets[target_name] + assert(target) + + -- remove the target + if not clean._remove_target(target_name, target, mode, buildir) 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 clean._remove_target_and_deps(dep, mode, buildir) then return false end + end + end + + -- ok + return true +end + +-- remove the target and object files for the given target +-- +-- mode: +-- all +-- build +-- targets +-- +function clean.remove(target_name, mode) + + -- the build directory + local buildir = config.get("buildir") + assert(buildir and mode) + + -- the target name + if target_name and target_name ~= "all" then + -- remove target + if not clean._remove_target_and_deps(target_name, mode, buildir) then return false end + else + + -- the targets + local targets = project.targets() + assert(targets) + + -- remove targets + for target_name, target in pairs(targets) do + if not clean._remove_target(target_name, target, mode, buildir) then return false end + end + end + + -- remove all + if mode == "all" then + + -- remove makefile + if not clean._remove(rule.makefile()) then + return false + end + + -- remove the configure directory + if not clean._remove(config.directory()) then + return false + end + + -- remove the log file + if not clean._remove(rule.logfile()) then + return false + end + + -- remove build directory if be empty + local buildir = config.get("buildir") + if os.isdir(buildir) then + os.rm(buildir, true) + end + + end + + -- ok + return true +end + +-- return module: clean +return clean diff --git a/xmake/core/base/compiler.lua b/xmake/core/base/compiler.lua new file mode 100644 index 000000000..a64f8bae0 --- /dev/null +++ b/xmake/core/base/compiler.lua @@ -0,0 +1,574 @@ +--!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 compiler.lua +-- + +-- define module: compiler +local compiler = compiler or {} + +-- load modules +local io = require("base/io") +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") +local config = require("base/config") +local tools = require("tools/tools") +local platform = require("platform/platform") + +-- map gcc flag to the given compiler flag +function compiler._mapflag(module, flag) + + -- check + assert(module.mapflags and flag) + + -- attempt to map it directly + local flag_mapped = module.mapflags[flag] + if flag_mapped and type(flag_mapped) == "string" then + return flag_mapped + end + + -- find and replace it using pattern + for k, v in pairs(module.mapflags) do + local flag_mapped, count = flag:gsub("^" .. k .. "$", function (w) + if type(v) == "function" then + return v(module, w) + else + return v + end + end) + if flag_mapped and count ~= 0 then + return utils.ifelse(#flag_mapped ~= 0, flag_mapped, nil) + end + end + + -- return it directly + return flag +end + +-- map gcc flags to the given compiler flags +function compiler._mapflags(module, flags) + + -- check + assert(module) + + -- wrap flags first + flags = utils.wrap(flags) + + -- need not map flags? return it directly + if not module.mapflags then + return flags + end + + -- map flags + local flags_mapped = {} + for _, flag in pairs(flags) do + -- map it + local flag_mapped = compiler._mapflag(module, flag) + if flag_mapped then + table.insert(flags_mapped, flag_mapped) + end + end + + -- ok? + return flags_mapped +end + +-- get the compiler flags from names +function compiler._getflags(module, names, flags) + + -- check + assert(flags) + + -- the mapped flags + local flags_mapped = {} + + -- wrap it first + names = utils.wrap(names) + for _, name in ipairs(names) do + table.join2(flags_mapped, compiler._mapflags(module, flags[name])) + end + + -- get it + return flags_mapped +end + +-- add flags from the compiler +function compiler._addflags_from_compiler(module, flags, flagnames, kind) + + -- check + assert(module and flags and flagnames) + + -- done + for _, flagname in ipairs(flagnames) do + + -- add compiler.xxflags + table.join2(flags, module, module[flagname]) + + -- add compiler.kind.xxflags + if kind ~= nil and module[kind] ~= nil then + table.join2(flags, module, module[kind][flagname]) + end + end +end + +-- add flags from the configure +function compiler._addflags_from_config(module, flags, flagnames) + + -- check + assert(module and flags and flagnames) + + -- done + for _, flagname in ipairs(flagnames) do + table.join2(flags, config.get(flagname)) + end +end + +-- add flags from the platform +function compiler._addflags_from_platform(module, flags, flagnames) + + -- check + assert(module and flags and flagnames) + + -- add flags + for _, flagname in ipairs(flagnames) do + table.join2(flags, compiler._mapflags(module, platform.get(flagname))) + end + + -- add the includedirs flags + if module.flag_includedir then + for _, includedir in ipairs(utils.wrap(platform.get("includedirs"))) do + table.join2(flags, module:flag_includedir(includedir)) + end + end + + -- add the defines flags + if module.flag_define then + for _, define in ipairs(utils.wrap(platform.get("defines"))) do + table.join2(flags, module:flag_define(define)) + end + end + + -- append the undefines flags + if module.flag_undefine then + for _, undefine in ipairs(utils.wrap(platform.get("undefines"))) do + table.join2(flags, module:flag_undefine(undefine)) + end + end +end + + +-- add flags from the target +function compiler._addflags_from_target(module, flags, flagnames, target) + + -- check + assert(module and flags and flagnames and target) + + -- add the target flags from the current project + for _, flagname in ipairs(flagnames) do + table.join2(flags, compiler._mapflags(module, target[flagname])) + end + + -- add the symbols flags from the current project + table.join2(flags, compiler._getflags(module, target.symbols, { debug = "-g" + , hidden = "-fvisibility=hidden" + })) + + -- add the warning flags from the current project + table.join2(flags, compiler._getflags(module, target.warnings, { none = "-w" + , less = "-W1" + , more = "-W3" + , all = "-Wall" + , error = "-Werror" + })) + + -- add the optimize flags from the current project + table.join2(flags, compiler._getflags(module, target.optimize, { none = "-O0" + , fast = "-O1" + , faster = "-O2" + , fastest = "-O3" + , smallest = "-Os" + , aggressive = "-Ofast" + })) + + -- add the vector extensions flags from the current project + table.join2(flags, compiler._getflags(module, target.vectorexts, { mmx = "-mmmx" + , sse = "-msse" + , sse2 = "-msse2" + , sse3 = "-msse3" + , ssse3 = "-mssse3" + , avx = "-mavx" + , avx2 = "-mavx2" + , neon = "-mfpu=neon" + })) + + -- add the language flags from the current project + local languages = {} + for _, flagname in ipairs(flagnames) do + if flagname == "cflags" or flagname == "mflags" then + table.join2(languages, { ansi = "-ansi" + , c89 = "-std=c89" + , gnu89 = "-std=gnu89" + , c99 = "-std=c99" + , gnu99 = "-std=gnu99" + , c11 = "-std=c11" + , gnu11 = "-std=gnu11" + }) + elseif flagname == "cxxflags" or flagname == "mxxflags" then + table.join2(languages, { cxx98 = "-std=c++98" + , gnuxx98 = "-std=gnu++98" + , cxx11 = "-std=c++11" + , gnuxx11 = "-std=gnu++11" + , cxx14 = "-std=c++14" + , gnuxx14 = "-std=gnu++14" + }) + end + end + table.join2(flags, compiler._getflags(module, target.languages, languages)) + + -- add the includedirs flags from the current project + if module.flag_includedir then + for _, includedir in ipairs(utils.wrap(target.includedirs)) do + table.join2(flags, module:flag_includedir(includedir)) + end + end + + -- add the defines flags from the current project + if module.flag_define then + for _, define in ipairs(utils.wrap(target.defines)) do + table.join2(flags, module:flag_define(define)) + end + end + + -- append the undefines flags from the current project + if module.flag_undefine then + for _, undefine in ipairs(utils.wrap(target.undefines)) do + table.join2(flags, module:flag_undefine(undefine)) + end + 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 + + -- add the flags from the option + compiler._addflags_from_target(module, flags, flagnames, opt) + + -- append the defines flags + if opt.defines_if_ok and module.flag_define then + local defines = utils.wrap(opt.defines_if_ok) + for _, define in ipairs(defines) do + table.join2(flags, module:flag_define(define)) + end + end + + -- append the undefines flags + if opt.undefines_if_ok and module.flag_undefine then + local undefines = utils.wrap(opt.undefines_if_ok) + for _, undefine in ipairs(undefines) do + table.join2(flags, module:flag_undefine(undefine)) + end + end + end + end + end +end + +-- add flags from the option +function compiler._addflags_from_option(module, flags, flagnames, opt) + + -- check + assert(module and flags and flagnames and opt) + + -- add the flags from the option + compiler._addflags_from_target(module, flags, flagnames, opt) + +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" } + elseif name == "sc" then flagnames = { "scflags" } + else + -- error + utils.error("unknown compiler: %s", name) + return + end + + -- ok + return flagnames +end + +-- get the compiler kind from the source file type +function compiler._kind(srcfile) + + -- get the source file type + local filetype = path.extension(srcfile) + if not filetype then + return nil + end + + -- get the lower file type + filetype = filetype:lower() + + -- get the compiler kind + local kind = nil + if filetype == ".c" then kind = "cc" + elseif filetype == ".cpp" or filetype == ".cc" then kind = "cxx" + elseif filetype == ".m" then kind = "mm" + elseif filetype == ".mm" then kind = "mxx" + elseif filetype == ".s" or filetype == ".asm" then kind = "as" + elseif filetype == ".swift" then kind = "sc" + end + + -- ok + return kind +end + +-- make the compile command for option +function compiler._make_for_option(module, opt, srcfile, objfile, logfile) + + -- check + assert(module and opt) + + -- the flag names + local flagnames = compiler._flagnames(module._KIND) + assert(flagnames) + + -- init flags + local flags = {} + + -- add flags from the configure + compiler._addflags_from_config(module, flags, flagnames) + + -- add flags from the option + compiler._addflags_from_option(module, flags, flagnames, opt) + + -- add flags from the platform + compiler._addflags_from_platform(module, flags, flagnames) + + -- add flags from the compiler + compiler._addflags_from_compiler(module, flags, flagnames) + + -- remove repeat + flags = utils.unique(flags) + + -- execute the compile command + return module:command_compile(srcfile, objfile, table.concat(flags, " "):trim(), logfile) +end + +-- get the compiler from the given source file +function compiler.get(srcfile) + + -- get the compiler kind + local kind = compiler._kind(srcfile) + if not kind then + return nil, string.format("unknown source file: %s", srcfile) + end + + -- get compiler from the source file type + local module = tools.get(kind) + if module then + + -- invalid compiler + if not module.command_compile then + return nil, string.format("invalid compiler for %s", kind) + end + + -- save kind + module._KIND = kind + else + return nil, string.format("unknown compiler for %s", kind) + end + + -- ok? + return module +end + +-- make the compile command +function compiler.make(module, target, srcfile, objfile, logfile) + + -- check + assert(module and target) + + -- the flag names + local flagnames = compiler._flagnames(module._KIND) + assert(flagnames) + + -- init flags + local flags = {} + + -- add flags from the configure + compiler._addflags_from_config(module, flags, flagnames) + + -- add flags from the target + compiler._addflags_from_target(module, flags, flagnames, target) + + -- add flags from the platform + compiler._addflags_from_platform(module, flags, flagnames) + + -- add flags from the compiler + compiler._addflags_from_compiler(module, flags, flagnames, target.kind) + + -- remove repeat + flags = utils.unique(flags) + + -- make the compile command + return module:command_compile(srcfile, objfile, table.concat(flags, " "):trim(), logfile) +end + +-- check include for the project option +function compiler.check_include(opt, include, srcpath, objpath) + + -- check + assert(opt and srcpath and objpath) + + -- open the checking source file + local srcfile = io.openmk(srcpath) + if not srcfile then return end + + -- make include + if include then + srcfile:write(string.format("#include <%s>\n\n", include)) + end + + -- 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 module = compiler.get(srcpath) + if not module then return end + + -- execute the compile command + return module:main(compiler._make_for_option(module, opt, srcpath, objpath, utils.ifelse(xmake._OPTIONS.verbose, nil, xmake._NULDEV))) +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.openmk(srcpath) + if not srcfile then return end + + -- get the compiler + local module = compiler.get(srcpath) + if not module then return end + + -- make includes + local includes = nil + if module._KIND == "cc" then includes = opt.cincludes + elseif module._KIND == "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() + + -- execute the compile command + return module:main(compiler._make_for_option(module, opt, srcpath, objpath, utils.ifelse(xmake._OPTIONS.verbose, nil, xmake._NULDEV))) +end + +-- check typedef for the project option +function compiler.check_typedef(opt, typedef, srcpath, objpath) + + -- check + assert(opt and typedef) + + -- open the checking source file + local srcfile = io.openmk(srcpath) + if not srcfile then return end + + -- get the compiler + local module = compiler.get(srcpath) + if not module then return end + + -- make includes + local includes = nil + if module._KIND == "cc" then includes = opt.cincludes + elseif module._KIND == "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(" typedef %s __type_xxx;\n\n", typedef)) + + -- make the main function tailer + srcfile:write(" return 0;\n") + srcfile:write("}\n") + + -- exit this file + srcfile:close() + + -- execute the compile command + return module:main(compiler._make_for_option(module, opt, srcpath, objpath, utils.ifelse(xmake._OPTIONS.verbose, nil, xmake._NULDEV))) +end + +-- return module: compiler +return compiler diff --git a/xmake/core/base/config.lua b/xmake/core/base/config.lua new file mode 100644 index 000000000..3cea6a652 --- /dev/null +++ b/xmake/core/base/config.lua @@ -0,0 +1,395 @@ +--!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 config.lua +-- + +-- define module: config +local config = config or {} + +-- load modules +local io = require("base/io") +local os = require("base/os") +local utils = require("base/utils") +local option = require("base/option") +local global = require("base/global") + +-- make configure for the current target +function config._make(configs) + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- init current target configure + local current = {} + + -- get configs from the default configure + if configs._DEFAULTS then + for k, v in pairs(configs._DEFAULTS) do + if type(v) ~= "string" or v ~= "auto" then current[k] = v end + end + end + + -- get configs from the global configure + if global._CURRENT then + for k, v in pairs(global._CURRENT) do + current[k] = v + end + end + + -- get configs from all targets + for k, v in pairs(configs) do + if type(k) == "string" and not k:find("^_%u+") then + current[k] = v + end + end + + -- get configs from the current target + if configs._TARGETS and current.target ~= "all" then + + -- get the target config + local target_config = configs._TARGETS[current.target] + if target_config then + + -- merge it + for k, v in pairs(target_config) do + current[k] = v + end + end + end + + -- ok? + return current +end + +-- get the configure file +function config._file() + + -- get it + return config.directory() .. "/xmake.conf" +end + +-- need configure? +function config._need(name) + return name and name ~= "target" and name ~= "file" and name ~= "project" and name ~= "verbose" and name ~= "clean" +end + +-- get the current target scope +function config._target() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- check + local configs = config._CONFIGS + assert(configs) + + -- the target name + local name = options.target or options._DEFAULTS.target + assert(name and type(name) == "string") + + -- for all targets? + if name == "all" then + return configs + elseif configs._TARGETS then + -- get it + return configs._TARGETS[name] + end +end + +-- get the given configure from the current +function config.get(name) + + -- the configure has been not loaded + if not config._CURRENT then return end + + -- get it + return config._CURRENT[name] +end + +-- set the given configure to the current +function config.set(name, value) + + -- check + assert(config._CURRENT and name) + + -- get the current target + local target = config._target() + assert(target) + + -- set it to the current target configure for saving to file + target[name] = value + + -- set it to the current configure + config._CURRENT[name] = value +end + +-- the given configure need probe automatically +function config.auto(name) + + -- the configs + local configs = config._CONFIGS + assert(configs) + + -- need probe it automatically? + if configs._DEFAULTS then + local value = configs._DEFAULTS[name] + if value then + if type(value) == "string" and value == "auto" then + return true + end + end + end + + -- need not probe it if have been setted manually + if config._CURRENT and nil ~= config._CURRENT[name] then + return false + end + + -- attempt to probe it if not exists + return true +end + +-- get the configure directory +function config.directory() + + -- the directory + local dir = xmake._PROJECT_DIR .. "/.xmake" + + -- create it directly first if not exists + if not os.isdir(dir) then + assert(os.mkdir(dir)) + end + + -- get it + return dir +end + +-- save xmake.conf +function config.save() + + -- the configs + local configs = config._CONFIGS + assert(configs) + + -- save to the configure file + return io.save(config._file(), configs) +end + +function config.load() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- check + assert(option._MENU) + assert(option._MENU.config) + + -- the target name + local name = options.target or options._DEFAULTS.target + if not name then + return "no given target name!" + end + + -- does not clean the cached configure? + if not options.clean then + + -- load and execute the xmake.xconf + local filepath = config._file() + if os.isfile(filepath) then + + -- load the configure file + local configs, errors = io.load(filepath) + + -- exists local configures? + if configs then + + -- save configs + config._CONFIGS = configs + + -- make the current target configs + local current = config._make(configs) + + -- clear configs and mark as "rebuild" and "reconfig" if the host has been changed + if (current and current.host ~= xmake._HOST) then + + -- clear configs and mark as "rebuild" + config._CONFIGS = { __rebuild = true } + + -- mark as "reconfig" if the current action is not "config" + if options._ACTION ~= "config" then + config._RECONFIG = true + end + end + + -- clear configs and mark as "rebuild" if the plat has been changed + if current and current.plat and options.plat and current.plat ~= options.plat then + + -- clear configs and mark as "rebuild" + config._CONFIGS = { __rebuild = true } + end + + -- mark as "rebuild" if the arch has been changed + if current and current.arch and options.arch and current.arch ~= options.arch then + + -- mark as "rebuild" + config._CONFIGS.__rebuild = true + end + + -- mark as "rebuild" if the mode has been changed + if current and current.mode and options.mode and current.mode ~= options.mode then + + -- mark as "rebuild" + config._CONFIGS.__rebuild = true + end + elseif errors then + -- error + utils.error(errors) + end + end + end + + -- init configs if not exists + if not config._CONFIGS then + -- clear configs and mark as "rebuild" + config._CONFIGS = { __rebuild = true } + + -- mark as "reconfig" if the current action is not "config" + if options._ACTION ~= "config" then + config._RECONFIG = true + end + end + + -- the configs + local configs = config._CONFIGS + + -- mark as "rebuild" if clean the cached configure + if options.clean then + configs.__rebuild = true + end + + -- init the defaults + local defaults = nil + if not configs._DEFAULTS then + if config._RECONFIG then defaults = option.defaults("config") + elseif options._ACTION == "config" then defaults = options._DEFAULTS + end + if defaults then + for k, v in pairs(defaults) do + + -- check + assert(type(k) == "string") + + -- skip some options + if config._need(k) then + + -- save the default option + configs._DEFAULTS = configs._DEFAULTS or {} + configs._DEFAULTS[k] = v + end + end + end + end + defaults = configs._DEFAULTS + + -- init targets + configs._TARGETS = configs._TARGETS or {} + if name ~= "all" then + configs._TARGETS[name] = configs._TARGETS[name] or {} + end + + -- get the current target scope + local target = config._target() + assert(target and type(target) == "table") + + -- merge xmake._OPTIONS to target + if options._ACTION == "config" then + for k, v in pairs(options) do + + -- check + assert(type(k) == "string") + + -- skip some options + if not k:startswith("_") and config._need(k) then + + -- save the option to the target + target[k] = v + + -- remove it from the defaults, because we have setted it manually + if defaults then defaults[k] = nil end + end + end + end + + -- make the current config + config._CURRENT = config._make(config._CONFIGS) +end + +-- clear up and remove all auto values +function config.clearup() + + -- clear up the current configure + local current = config._CURRENT + if current then + for k, v in pairs(current) do + if type(v) == "string" and v == "auto" then + current[k] = nil + end + end + end + + -- clear up the current target configure + local target = config._target() + if target then + for k, v in pairs(target) do + if type(v) == "string" and v == "auto" then + target[k] = nil + end + end + end + +end + +-- reload configure +function config.reload() + + -- clear the old configure + config._CURRENT = nil + config._CONFIGS = nil + + -- load it + return config.load() +end + +-- dump the current configure +function config.dump() + + -- check + assert(config._CURRENT) + + -- dump + utils.dump(config._CURRENT, "__%w*", "configure") + +end + +-- return module: config +return config diff --git a/xmake/core/base/global.lua b/xmake/core/base/global.lua new file mode 100644 index 000000000..0017590c6 --- /dev/null +++ b/xmake/core/base/global.lua @@ -0,0 +1,246 @@ +--!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 global.lua +-- + +-- define module: global +local global = global or {} + +-- load modules +local io = require("base/io") +local os = require("base/os") +local utils = require("base/utils") +local option = require("base/option") + +-- make configure +function global._make() + + -- the configs + local configs = global._CONFIGS + assert(configs) + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- init current global configure + global._CURRENT = global._CURRENT or {} + local current = global._CURRENT + + -- make current global configure + for k, v in pairs(configs) do + if type(k) == "string" and not k:find("^_%u+") then + current[k] = v + end + end +end + +-- get the configure file +function global._file() + + -- get it + return global.directory() .. "/xmake.conf" +end + +-- need configure? +function global._need(name) + return name and name ~= "verbose" and name ~= "clean" +end + +-- get the given configure from the current +function global.get(name) + + -- check + assert(global._CURRENT) + + -- the value + local value = global._CURRENT[name] + if value and value == "auto" then + value = nil + end + + -- get it + return value +end + +-- set the given configure to the current +function global.set(name, value) + + -- check + assert(global._CURRENT and global._CONFIGS) + assert(name and value and type(value) ~= "table") + + -- set it to the current configure + global._CURRENT[name] = value + + -- set it to the configure for saving to file + global._CONFIGS[name] = value + +end + +-- get the global configure directory +function global.directory() + + -- the directory + local dir = path.translate("~/.xmake") + + -- create it directly first if not exists + if not os.isdir(dir) then + assert(os.mkdir(dir)) + end + + -- get it + return dir +end + +-- save xmake.conf +function global.save() + + -- the configs + local configs = global._CONFIGS + assert(configs) + + -- save to the configure file + return io.save(global._file(), configs) +end + +-- load xmake.conf +function global.load() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- check + assert(option._MENU) + assert(option._MENU.global) + + -- get all configure names + local i = 1 + local configures = {} + for _, o in ipairs(option._MENU.global.options) do + local name = o[2] + if global._need(name) then + configures[i] = name + i = i + 1 + end + end + + -- does not clean the cached configure? + if not options.clean then + + -- load and execute the xmake.conf + local filepath = global._file() + if os.isfile(filepath) then + + -- load the configure file + local configs, errors = io.load(filepath) + + -- exists local configures? + if configs then + -- save configs + global._CONFIGS = configs + elseif errors then + -- error + utils.error(errors) + end + end + end + + -- init configs + global._CONFIGS = global._CONFIGS or {} + local configs = global._CONFIGS + + -- xmake global? + if options._ACTION == "global" then + + -- merge xmake._OPTIONS to the global configure + for k, v in pairs(options) do + + -- check + assert(type(k) == "string") + + -- need configure it? + if not k:startswith("_") and global._need(k) then + configs[k] = v + end + end + + -- merge the default global configure options to the global configure + local defaults = options._DEFAULTS + if defaults then + for k, v in pairs(defaults) do + + -- check + assert(type(k) == "string") + + -- need configure it? + if global._need(k) then + + -- save the default option + if nil == configs[k] then + configs[k] = v + end + end + end + end + end + + -- make the current global + global._make() +end + +-- clear up and remove all auto values +function global.clearup() + + -- clear up the current configure + local current = global._CURRENT + if current then + for k, v in pairs(current) do + if v and type(v) and v == "auto" then + current[k] = nil + end + end + end + + -- clear up the configure + local configs = global._CONFIGS + if configs then + for k, v in pairs(configs) do + if v and type(v) and v == "auto" then + configs[k] = nil + end + end + end +end + +-- dump the current configure +function global.dump() + + -- check + assert(global._CURRENT) + + -- dump + utils.dump(global._CURRENT, "__%w*", "configure") + +end + +-- return module: global +return global diff --git a/xmake/core/base/install.lua b/xmake/core/base/install.lua new file mode 100644 index 000000000..9fc41a14a --- /dev/null +++ b/xmake/core/base/install.lua @@ -0,0 +1,143 @@ +--!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 install.lua +-- + +-- define module: install +local install = install 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 config = require("base/config") +local platform = require("platform/platform") + +-- install target from the project script +function install._done_from_project(target) + + -- check + assert(target) + + -- install it using the project script first + local installscript = target.installscript + if type(installscript) == "function" then + + -- remove it + target.installscript = nil + + -- install it + return installscript(target) + end + + -- continue + return 0 +end + +-- install target from the platform script +function install._done_from_platform(target) + + -- check + assert(target) + + -- the platform install script file + local installscript = nil + local scriptfile = platform.directory() .. "/install.lua" + if os.isfile(scriptfile) then + + -- load the install script + local script, errors = loadfile(scriptfile) + if script then + installscript = script() + if type(installscript) == "table" and installscript.main then + installscript = installscript.main + end + else + utils.error(errors) + end + end + + -- install it + if type(installscript) == "function" then + return installscript(target) + end + + -- continue + return 0 +end + +-- install target from the given target configure +function install._done(target) + + -- check + assert(target) + + -- install it from the project script + local ok = install._done_from_project(target) + if ok ~= 0 then return utils.ifelse(ok == 1, true, false) end + + -- install it from the platform script + local ok = install._done_from_platform(target) + if ok ~= 0 then return utils.ifelse(ok == 1, true, false) end + + -- ok + return true +end + +-- get the configure file +function install._file() + + -- get it + return config.directory() .. "/install.conf" +end + +-- done install from the configure +function install.done(configs) + + -- check + assert(configs) + + -- install targets + for _, target in pairs(configs) do + + -- install it + if not install._done(target) then + -- errors + utils.error("install %s failed!", target.name) + return false + end + + end + + -- save to the configure file + return io.save(install._file(), configs) +end + +-- load the install configure +function install.load() + + -- load it + return io.load(install._file()) +end + +-- return module: install +return install diff --git a/xmake/core/base/io.lua b/xmake/core/base/io.lua new file mode 100644 index 000000000..66b23911a --- /dev/null +++ b/xmake/core/base/io.lua @@ -0,0 +1,324 @@ +--!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 io.lua +-- + +-- define module: io +local io = io or {} + +-- load modules +local path = require("base/path") +local utils = require("base/utils") + +-- save object with the level +function io._save_with_level(file, object, level) + + -- save string + if type(object) == "string" then + file:write(string.format("%q", object)) + -- save boolean + elseif type(object) == "boolean" then + file:write(tostring(object)) + -- save number + elseif type(object) == "number" then + file:write(object) + -- save table + elseif type(object) == "table" then + + -- save head + file:write("\n") + for l = 1, level do + file:write(" ") + end + file:write("{\n") + + -- save body + local i = 0 + for k, v in pairs(object) do + + -- save spaces and separator + for l = 1, level do + file:write(" ") + end + + file:write(utils.ifelse(i == 0, " ", ", ")) + + -- save key + if type(k) == "string" then + file:write(string.format("[%q]", k), " = ") + end + + -- save value + if not io._save_with_level(file, v, level + 1) then + return false + end + + -- save newline + file:write("\n") + i = i + 1 + end + + -- save tail + for l = 1, level do + file:write(" ") + end + file:write("}\n") + else + -- error + utils.error("invalid object type: %s", type(object)) + return false + end + + -- ok + return true +end + +-- save object to given file +function io._save(file, object) + + -- save it + return io._save_with_level(file, object, 0) +end + +-- create directory and open a writable file +function io.openmk(filepath) + + -- check + assert(filepath) + + -- get the file directory + local dir = path.directory(filepath) + + -- ensure the file directory + if not os.isdir(dir) then os.mkdir(dir) end + + -- open it + return io.open(filepath, "w") +end + +-- read all data from file +function io.readall(filepath) + + -- open file + local file = io.open(filepath, "r") + if not file then + -- error + return nil, string.format("open %s failed!", filepath) + end + + -- read all + local data = file:read("*all") + + -- exit file + file:close() + + -- ok? + return data +end + +-- write all data to file +function io.writall(filepath, data) + + -- open file + local file = io.open(filepath, "w") + if not file then + -- error + return false, string.format("open %s failed!", filepath) + end + + -- write all + file:write(data) + + -- exit file + file:close() + + -- ok? + return true +end + +-- save object the the given filepath +function io.save(filepath, object) + + -- open the file + local file = io.openmk(filepath) + if not file then + -- error + return false, string.format("open %s failed!", filepath) + end + + -- save object to file + if not io._save(file, object) then + -- error + file:close() + return false, string.format("save %s failed!", filepath) + end + + -- close file + file:close() + + -- ok + return true +end + +-- load object from the given file +function io.load(filepath) + + -- open the file + local file = io.open(filepath, "r") + if not file then + -- error + return nil, string.format("open %s failed!", filepath) + end + + -- load data + local result = nil + local errors = nil + local data = file:read("*all") + if data and type(data) == "string" then + + -- load script + local script, errs = loadstring("return " .. data) + if script then + + -- load object + local ok, object = pcall(script) + if ok and object then + result = object + elseif object then + -- error + errors = object + else + -- error + errors = string.format("load %s failed!", filepath) + end + -- errors + else errors = errs end + end + + -- close file + file:close() + + -- ok? + return result, errors +end + +-- gsub the given file and return replaced data +function io.gsub(filepath, pattern, replace) + + -- read all data from file + local data, errors = io.readall(filepath) + if not data then return nil, 0, errors end + + -- replace it + local count = 0 + if type(data) == "string" then + data, count = data:gsub(pattern, replace) + else + return nil, 0, string.format("data is not string!") + end + + -- replace ok? + if count ~= 0 then + -- write all data to file + local ok, errors = io.writall(filepath, data) + if not ok then return nil, 0, errors end + end + + -- ok + return data, count +end + +-- cat the given file +function io.cat(filepath, linecount) + + -- open file + local file = io.open(filepath, "r") + if file then + + -- show file + local count = 1 + for line in file:lines() do + + -- show line + print(line) + + -- end? + if linecount and count >= linecount then + break + end + + -- update the line count + count = count + 1 + end + + -- exit file + file:close() + end +end + +-- tail the given file +function io.tail(filepath, linecount) + + -- open file + local file = io.open(filepath, "r") + if file then + + -- read lines + local lines = {} + for line in file:lines() do + table.insert(lines, line) + end + + -- tail lines + local tails = {} + if #lines ~= 0 then + local count = 1 + for index = #lines, 1, -1 do + + -- show line + table.insert(tails, lines[index]) + + -- end? + if linecount and count >= linecount then + break + end + + -- update the line count + count = count + 1 + end + end + + -- show tails + if #tails ~= 0 then + for index = #tails, 1, -1 do + + -- show tail + print(tails[index]) + + end + end + + -- exit file + file:close() + end +end + +-- return module: io +return io diff --git a/xmake/core/base/linker.lua b/xmake/core/base/linker.lua new file mode 100644 index 000000000..9a0388757 --- /dev/null +++ b/xmake/core/base/linker.lua @@ -0,0 +1,386 @@ +--!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 linker.lua +-- + +-- define module: linker +local linker = linker or {} + +-- load modules +local utils = require("base/utils") +local table = require("base/table") +local string = require("base/string") +local config = require("base/config") +local compiler = require("base/compiler") +local tools = require("tools/tools") +local platform = require("platform/platform") + +-- map gcc flag to the given linker flag +function linker._mapflag(module, flag) + + -- check + assert(module.mapflags and flag) + + -- attempt to map it directly + local flag_mapped = module.mapflags[flag] + if flag_mapped and type(flag_mapped) == "string" then + return flag_mapped + end + + -- find and replace it using pattern + for k, v in pairs(module.mapflags) do + local flag_mapped, count = flag:gsub("^" .. k .. "$", function (w) + if type(v) == "function" then + return v(module, w) + else + return v + end + end) + if flag_mapped and count ~= 0 then + return utils.ifelse(#flag_mapped ~= 0, flag_mapped, nil) + end + end + + -- return it directly + return flag +end + +-- map gcc flags to the given linker flags +function linker._mapflags(module, flags) + + -- check + assert(module) + + -- wrap flags first + flags = utils.wrap(flags) + + -- need not map flags? return it directly + if not module.mapflags then + return flags + end + + -- map flags + local flags_mapped = {} + for _, flag in pairs(flags) do + -- map it + local flag_mapped = linker._mapflag(module, flag) + if flag_mapped then + table.insert(flags_mapped, flag_mapped) + end + end + + -- ok? + return flags_mapped +end + +-- get the linker flags from names +function linker._getflags(module, names, flags) + + -- check + assert(flags) + + -- the mapped flags + local flags_mapped = {} + + -- wrap it first + names = utils.wrap(names) + for _, name in ipairs(names) do + table.join2(flags_mapped, linker._mapflags(module, flags[name])) + end + + -- get it + return flags_mapped +end + + +-- add flags from the links +function linker._addflags_from_links(module, flags, links) + + -- check + assert(module and flags and links) + + -- done + if module.flag_link then + for _, link in ipairs(utils.wrap(links)) do + table.join2(flags, module:flag_link(link)) + end + end +end + +-- add flags from the linker +function linker._addflags_from_linker(module, flags, flagname) + + -- check + assert(module and flags and flagname) + + -- done + table.join2(flags, module[flagname]) +end + +-- add flags from the compiler +function linker._addflags_from_compiler(module, flags, flagname, srcfiles) + + -- check + assert(module and flags and flagname) + + -- add the flags for compiler + local flags_for_compiler = {} + if srcfiles then + for _, srcfile in ipairs(utils.wrap(srcfiles)) do + + -- get the compiler + local c, errors = compiler.get(srcfile) + if not c then + -- error + utils.error(errors) + return + end + + -- add flags + table.join2(flags_for_compiler, c[flagname]) + end + end + + -- done + table.join2(flags, utils.unique(flags_for_compiler)) +end + +-- add flags from the configure +function linker._addflags_from_config(module, flags, flagname) + + -- check + assert(module and flags and flagname) + + -- done + table.join2(flags, config.get(flagname)) +end + +-- add flags from the platform +function linker._addflags_from_platform(module, flags, flagname) + + -- check + assert(module and flags and flagname) + + -- add flags + table.join2(flags, linker._mapflags(module, platform.get(flagname))) + + -- add the linkdirs flags + if module.flag_linkdir then + for _, linkdir in ipairs(utils.wrap(platform.get("linkdirs"))) do + table.join2(flags, module:flag_linkdir(linkdir)) + end + end + + -- add the links flags + if module.flag_link then + for _, link in ipairs(utils.wrap(platform.get("links"))) do + table.join2(flags, module:flag_link(link)) + end + end +end + +-- add flags from the target +function linker._addflags_from_target(module, flags, flagname, target) + + -- check + assert(module and flags and flagname and target) + + -- add the target flags from the current project + table.join2(flags, linker._mapflags(module, target[flagname])) + + -- add the linkdirs flags from the current project + if module.flag_linkdir then + for _, linkdir in ipairs(utils.wrap(target.linkdirs)) do + table.join2(flags, module:flag_linkdir(linkdir)) + end + end + + -- add the links flags from the current project + if module.flag_link then + for _, link in ipairs(utils.wrap(target.links)) do + table.join2(flags, module:flag_link(link)) + end + 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 + + -- add the flags from the option + table.join2(flags, linker._mapflags(module, opt[flagname])) + + -- add the linkdirs flags from the option + if module.flag_linkdir then + for _, linkdir in ipairs(utils.wrap(opt.linkdirs)) do + table.join2(flags, module:flag_linkdir(linkdir)) + end + end + + -- add the links flags from the option + if module.flag_link then + for _, link in ipairs(utils.wrap(opt.links)) do + table.join2(flags, module:flag_link(link)) + end + end + end + end + end + + -- add the flags from the configure + table.join2(flags, linker._mapflags(module, config.get(flagname))) + + -- add the strip flags from the current project + table.join2(flags, linker._getflags(module, target.strip, { debug = "-S" + , all = "-s" + })) +end + +-- add flags from the option +function linker._addflags_from_option(module, flags, flagname, opt) + + -- check + assert(module and flags and flagname and opt) + + -- append the option flags + table.join2(flags, linker._mapflags(module, opt[flagname])) + + -- append the linkdirs flags + if opt.linkdirs and module.flag_linkdir then + for _, linkdir in ipairs(utils.wrap(opt.linkdirs)) do + table.join2(flags, module:flag_linkdir(linkdir)) + end + end +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, srcfiles, objfiles, targetfile, logfile) + + -- check + assert(module and target) + + -- the target kind + local kind = target.kind or "" + + -- the flag name + local flagname = nil + if kind == "binary" then flagname = "ldflags" + elseif kind == "static" then flagname = "arflags" + elseif kind == "shared" then flagname = "shflags" + else + -- error + utils.error("unknown type for linker: %s", kind) + return + end + + -- init flags + local flags = {} + + -- add flags from the configure + linker._addflags_from_config(module, flags, flagname) + + -- add flags from the target + linker._addflags_from_target(module, flags, flagname, target) + + -- add flags from the platform + linker._addflags_from_platform(module, flags, flagname) + + -- add flags from the compiler + linker._addflags_from_compiler(module, flags, flagname, srcfiles) + + -- add flags from the linker + linker._addflags_from_linker(module, flags, flagname) + + -- remove repeat + flags = utils.unique(flags) + + -- make the link command + return module:command_link(table.concat(objfiles, " "), targetfile, table.concat(flags, " "):trim(), logfile) +end + +-- check link for the project option +function linker.check_links(opt, links, sourcefile, objectfile, targetfile) + + -- check + assert(opt and links and objectfile and targetfile) + + -- get the linker + local module = linker.get("binary") + assert(module and module.flag_link) + + -- init flags + local flags = {} + + -- add flags from the configure + linker._addflags_from_config(module, flags, "ldflags") + + -- add flags from the option + linker._addflags_from_option(module, flags, "ldflags", opt) + + -- add flags from the platform + linker._addflags_from_platform(module, flags, "ldflags") + + -- add flags from the links + linker._addflags_from_links(module, flags, links) + + -- add flags from the compiler + linker._addflags_from_compiler(module, flags, "ldflags", sourcefile) + + -- add flags from the linker + linker._addflags_from_linker(module, flags, "ldflags") + + -- remove repeat + flags = utils.unique(flags) + + -- execute the link command + return module:main(module:command_link(objectfile, targetfile, table.concat(flags, " "):trim(), utils.ifelse(xmake._OPTIONS.verbose, nil, xmake._NULDEV))) +end + +-- return module: linker +return linker diff --git a/xmake/core/base/main.lua b/xmake/core/base/main.lua new file mode 100644 index 000000000..470815701 --- /dev/null +++ b/xmake/core/base/main.lua @@ -0,0 +1,179 @@ +--!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 main.lua +-- + +-- define module: main +local main = main or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local option = require("base/option") +local action = require("action/action") + +-- init the option menu +local menu = +{ + -- title + title = xmake._VERSION .. ", The Automatic Cross-platform Build Tool" + + -- copyright +, copyright = "Copyright (C) 2015-2016 Ruki Wang, tboox.org\nCopyright (C) 2005-2014 Mike Pall, luajit.org" + + -- build project: xmake +, main = + { + -- usage + usage = "xmake [action] [options] [target]" + + -- description + , description = "Build the project if no given action." + + -- actions + , actions = action.list + + -- options + , options = + { + {'b', "build", "k", nil, "Build project. This is default building mode and optional." } + , {'u', "update", "k", nil, "Only relink and update the binary files." } + , {'r', "rebuild", "k", nil, "Rebuild the project." } + + , {} + , {'f', "file", "kv", "xmake.lua", "Read a given xmake.lua file." } + , {'P', "project", "kv", nil, "Change to the given project directory." + , "Search priority:" + , " 1. The Given Command Argument" + , " 2. The Envirnoment Variable: XMAKE_PROJECT_DIR" + , " 3. The Current Directory" } + + + , {} + , {'j', "jobs", "kv", nil, "Specifies the number of jobs to build simultaneously" } + , {'v', "verbose", "k", nil, "Print lots of verbose information." } + , {nil, "version", "k", nil, "Print the version number and exit." } + , {'h', "help", "k", nil, "Print this help message and exit." } + + , {} + , {nil, "target", "v", "all", "Build the given target." } + } + } + + -- the actions: xmake [action] +, action.menu + +} + +-- done help +function main._done_help() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- done help + if options.help then + + -- print menu + option.print_menu(options._ACTION) + + -- ok + return true + + -- done version + elseif options.version then + + -- print title + if option._MENU.title then + print(option._MENU.title) + end + + -- print copyright + if option._MENU.copyright then + print(option._MENU.copyright) + end + + -- ok + return true + end +end + +-- done option +function main._done_option() + + -- the options + local options = xmake._OPTIONS + assert(options) + + -- done help? + if main._done_help() then + return true + end + + -- done action + return action.done(options._ACTION or "build") +end + +-- the init function for main +function main._init() + + -- init the project directory + local projectdir = option.find(xmake._ARGV, "project", "P") or xmake._PROJECT_DIR + if projectdir and not path.is_absolute(projectdir) then + projectdir = path.absolute(projectdir) + elseif projectdir then + projectdir = path.translate(projectdir) + end + xmake._PROJECT_DIR = projectdir + assert(projectdir) + + -- init the xmake.lua file path + local projectfile = option.find(xmake._ARGV, "file", "f") or xmake._PROJECT_FILE + if projectfile and not path.is_absolute(projectfile) then + projectfile = path.absolute(projectfile, projectdir) + end + xmake._PROJECT_FILE = projectfile + assert(projectfile) +end + +-- the main function +function main.done() + + -- init + main._init() + + -- init option + if not option.init(xmake._ARGV, menu) then + return -1 + end + + -- done option + if not main._done_option() then + return -1 + end + + -- ok + return 0 +end + +-- return module: main +return main diff --git a/xmake/core/base/makefile.lua b/xmake/core/base/makefile.lua new file mode 100644 index 000000000..826310d1a --- /dev/null +++ b/xmake/core/base/makefile.lua @@ -0,0 +1,417 @@ +--!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 makefile.lua +-- + +-- define module: makefile +local makefile = makefile or {} + +-- load modules +local io = require("base/io") +local os = require("base/os") +local rule = require("base/rule") +local path = require("base/path") +local utils = require("base/utils") +local config = require("base/config") +local project = require("base/project") +local linker = require("base/linker") +local compiler = require("base/compiler") +local tools = require("tools/tools") +local platform = require("platform/platform") + +-- make object for the *.[o|obj] source file +function makefile._make_object_for_object(file, target, srcfile, objfile) + + -- get the source file type + local filetype = path.extension(srcfile) + if not filetype then return false end + + -- get the lower file type + filetype = filetype:lower() + + -- not object file? + if filetype ~= ".o" and filetype ~= ".obj" then return false end + + -- get mode + local mode = config.get("mode") + if mode then + mode = "." .. mode + else + mode = "" + end + + -- make command + local cmd = string.format("xmake l cp %s %s", srcfile, objfile) + + -- make head + file:write(string.format("%s:", objfile)) + + -- make dependence + file:write(string.format(" %s\n", srcfile)) + + -- make body + file:write(string.format("\t@echo inserting%s %s\n", mode, srcfile)) + file:write(string.format("\t@xmake l $(VERBOSE) verbose \"%s\"\n", cmd:encode())) + file:write(string.format("\t@%s\n", cmd)) + + -- make tail + file:write("\n") + + -- ok + return true +end + +-- make object for the *.[a|lib] source file +function makefile._make_object_for_static(file, target, srcfile, objfile) + + -- get the source file type + local filetype = path.extension(srcfile) + if not filetype then return false end + + -- get the lower file type + filetype = filetype:lower() + + -- not static file? + if filetype ~= ".a" and filetype ~= ".lib" then return false end + + -- get mode + local mode = config.get("mode") + if mode then + mode = "." .. mode + else + mode = "" + end + + -- make command + local cmd = string.format("xmake l -P %s -f %s dispatcher ex extract %s %s > %s 2>&1", xmake._PROJECT_DIR, xmake._PROJECT_FILE, srcfile:encode(), objfile:encode(), makefile._LOGFILE) + + -- make head + file:write(string.format("%s:", objfile)) + + -- make dependence + file:write(string.format(" %s\n", srcfile)) + + -- make body + file:write(string.format("\t@echo inserting%s %s\n", mode, srcfile)) + file:write(string.format("\t@xmake l $(VERBOSE) verbose \"%s\"\n", cmd:encode())) + file:write(string.format("\t@xmake l rmdir %s\n", path.directory(objfile))) + file:write(string.format("\t@%s\n", cmd)) + + -- make tail + file:write("\n") + + -- ok + return true +end + +-- make the object to the makefile +function makefile._make_object(file, target, srcfile, objfile) + + -- check + assert(file and target and srcfile and objfile) + + -- make object for the *.o/obj source file + if makefile._make_object_for_object(file, target, srcfile, objfile) then + return true + elseif makefile._make_object_for_static(file, target, srcfile, objfile) then + return true + end + + -- get the compiler + local c, errors = compiler.get(srcfile) + if not c then + -- error + utils.error(errors) + return false + end + + -- get mode + local mode = config.get("mode") + if mode then + mode = "." .. mode + else + mode = "" + end + + -- get ccache + local ccache = platform.tool("ccache") + + -- make command + local cmd = compiler.make(c, target, srcfile, objfile, makefile._LOGFILE) + if ccache then + cmd = ccache:append(cmd, " ") + end + + -- make head + file:write(string.format("%s:", objfile)) + + -- make dependence + file:write(string.format(" %s\n", srcfile)) + + -- make body + file:write(string.format("\t@echo %scompiling%s %s\n", utils.ifelse(ccache, "ccache ", ""), mode, srcfile)) + file:write(string.format("\t@xmake l $(VERBOSE) verbose \"%s\"\n", cmd:encode())) + file:write(string.format("\t@xmake l mkdir %s\n", path.directory(objfile))) + file:write(string.format("\t@%s\n", cmd)) + + -- make tail + file:write("\n") + + -- ok + return true +end + +-- make all objects of the given target to the makefile +function makefile._make_objects(file, target, srcfiles, objfiles) + + -- check + assert(file and target and srcfiles and objfiles) + + -- make all objects + local i = 1 + for _, objfile in ipairs(objfiles) do + + -- make object + if not makefile._make_object(file, target, srcfiles[i], objfile) then + return false + end + + -- next + i = i + 1 + end + + -- ok + return true +end + +-- make the given target to the makefile +function makefile._make_target(file, name, target) + + -- check + assert(file and name and target and target.kind) + + -- get source and object files + local srcfiles = rule.sourcefiles(target) + local objfiles = rule.objectfiles(name, target, srcfiles) + assert(srcfiles and objfiles) + + -- get source and destinate header files + local srcheaders, dstheaders = rule.headerfiles(target) + + -- get target file + local targetfile = rule.targetfile(name, target) + assert(targetfile) + + -- get the targets + local targets = project.targets() + assert(targets) + + -- get the linker from the given kind + local l = linker.get(target.kind) + if not l then + utils.error("cannot get linker with kind: %s", target.kind) + return false + end + + -- make head + file:write(string.format("%s: %s\n", name, targetfile)) + file:write(string.format("%s:", targetfile)) + + -- make dependence for the dependent targets + if target.deps then + + -- get all dependent target + local deps = utils.wrap(target.deps) + for _, dep in ipairs(deps) do + + -- the dependent target + local deptarget = targets[dep] + if not deptarget then + utils.error("the dependent target: %s is invalid!", dep) + return false + end + + -- get the dependent target file + local depfile = rule.targetfile(dep, deptarget) + assert(depfile) + + -- add dependence + file:write(" " .. depfile) + end + end + + -- make dependence for objects + for _, objfile in ipairs(objfiles) do + file:write(" " .. objfile) + end + + -- make dependence end + file:write("\n") + + -- get mode + local mode = config.get("mode") + if mode then + mode = "." .. mode + else + mode = "" + end + + -- make the command + local cmd = linker.make(l, target, srcfiles, objfiles, targetfile, makefile._LOGFILE) + + -- the verbose + local verbose = cmd:encode() + -- too long? + if verbose and #verbose > 256 then + verbose = linker.make(l, target, srcfiles, {rule.filename("*", "object")}, targetfile) + verbose = verbose:encode() + end + + -- make body + file:write(string.format("\t@echo linking%s %s\n", mode, path.filename(targetfile))) + file:write(string.format("\t@xmake l $(VERBOSE) verbose \"%s\"\n", verbose)) + file:write(string.format("\t@xmake l mkdir %s\n", path.directory(targetfile))) + file:write(string.format("\t@%s\n", cmd)) + if srcheaders and dstheaders then + local i = 1 + for _, srcheader in ipairs(srcheaders) do + local dstheader = dstheaders[i] + if dstheader then + file:write(string.format("\t@xmake l cp %s %s\n", srcheader, dstheader)) + end + i = i + 1 + end + end + + -- make tail + file:write("\n") + + -- make objects for this target + return makefile._make_objects(file, target, srcfiles, objfiles) +end + +-- make all targets to the makefile +function makefile._make_targets(file) + + -- check + assert(file) + + -- get all project targets + local targets = project.targets() + if not targets then + -- error + utils.error("not found target in this project!") + return false + end + + -- make all first + local all = "" + for name, _ in pairs(targets) do + -- append the target name to all + all = all .. " " .. name + end + file:write(string.format("all: %s\n\n", all)) + file:write(string.format(".PHONY: all %s\n\n", all)) + + -- make it for all targets + for name, target in pairs(targets) do + -- make target + if not makefile._make_target(file, name, target) then + -- error + utils.error("failed to make target %s to makefile!", name) + return false + end + + -- append the target name to all + all = all .. " " .. name + end + + -- ok + return true +end + +-- make makefile in the build directory +function makefile.make() + + -- get the build directory + local buildir = config.get("buildir") + assert(buildir) + + -- init the log file + local logfile = rule.logfile() + if logfile and os.isfile(logfile) then + os.rmfile(logfile) + end + + -- save the log file + makefile._LOGFILE = logfile + assert(logfile) + + -- open the makefile + local path = rule.makefile() + local file = io.openmk(path) + if not file then + -- error + utils.error("open %s failed!", path) + return false + end + + -- make all targets to the makefile + if not makefile._make_targets(file) then + + -- error + utils.error("save %s failed!", path) + + -- close the makefile + file:close() + + -- remove the makefile + os.rm(path) + + -- failed + return false + end + + -- close the makefile + file:close() + + -- ok + return true +end + +-- build target +function makefile.build(target) + + -- check + assert(target and type(target) == "string") + + -- load make + local make = tools.get("make") + if not make then + utils.error("not found the make command!") + return false + end + + -- done make + return make:main(rule.makefile(), target) +end + +-- return module: makefile +return makefile diff --git a/xmake/core/base/option.lua b/xmake/core/base/option.lua new file mode 100644 index 000000000..1c8c35573 --- /dev/null +++ b/xmake/core/base/option.lua @@ -0,0 +1,650 @@ +--!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 option.lua +-- + +-- define module: option +local option = option or {} + +-- load modules +local utils = require("base/utils") +local table = require("base/table") + +-- save the option menu +function option._save_menu(menu) + + -- translate the action menus if exists function + local submenus_all = {} + for k, submenu in pairs(menu) do + if type(submenu) == "function" then + local _submenus = submenu() + if _submenus then + for k, m in pairs(_submenus) do + submenus_all[k] = m + end + end + else + submenus_all[k] = submenu + end + end + table.copy2(menu, submenus_all) + + -- translate the actions of the main menu if exists function + if menu.main and type(menu.main.actions) == "function" then + menu.main.actions = menu.main.actions() + end + + -- translate it if exists function in the option menu + for _, submenu in pairs(menu) do + + -- exits options? + if submenu.options then + + -- translate options + local options_all = {} + for _, option in ipairs(submenu.options) do + + -- this option is function? translate it + if type(option) == "function" then + local _options = option() + if _options then + for _, o in ipairs(_options) do + table.insert(options_all, o) + end + end + else + table.insert(options_all, option) + end + end + + -- update the options + submenu.options = options_all + end + end + + -- save menu + option._MENU = menu + +end + +-- init the option +function option.init(argv, menu) + + -- check + assert(argv and menu) + + -- the main menu + local main = menu.main + assert(main) + + -- init _OPTIONS + xmake._OPTIONS = {} + xmake._OPTIONS._DEFAULTS = {} + + -- save menu + option._save_menu(menu) + + -- parse _ARGV to _OPTIONS + local _iter, _s, _k = ipairs(argv) + while true do + + -- the idx and arg + local idx, arg = _iter(_s, _k) + + -- end? + _k = idx + if idx == nil then break end + + -- parse key and value + local key, value + local i = arg:find("=", 1, true) + + -- key=value? + if i then + key = arg:sub(1, i - 1) + value = arg:sub(i + 1) + -- only key? + else + key = arg + value = true + end + + -- --key? + local prefix = 0 + if key:startswith("--") then + key = key:sub(3) + prefix = 2 + -- -k? + elseif key:startswith("-") then + key = key:sub(2) + prefix = 1 + end + + -- check key + if prefix and #key == 0 then + + -- invalid option + print("invalid option: " .. arg) + + -- print menu + option.print_menu(xmake._OPTIONS._ACTION) + + -- failed + return false + end + + -- --key=value or -k value or -k? + if prefix ~= 0 then + + -- find this option + local opt = nil + for _, o in ipairs(menu[xmake._OPTIONS._ACTION or "main"].options) do + + -- check + assert(o) + + -- --key? + if prefix == 2 and key == o[2] then + opt = o + break + -- k? + elseif prefix == 1 and key == o[1] then + opt = o + break + end + end + + -- not found? + if not opt then + + -- invalid option + print("invalid option: " .. arg) + + -- print menu + option.print_menu(xmake._OPTIONS._ACTION) + + -- failed + return false + end + + -- -k value? continue to get the value + if prefix == 1 and opt[3] == "kv" then + + -- get the next idx and arg + idx, arg = _iter(_s, _k) + + -- exists value? + _k = idx + if idx == nil or arg:startswith("-") then + + -- invalid option + print("invalid option: " .. utils.ifelse(idx, arg, key)) + + -- print menu + option.print_menu(xmake._OPTIONS._ACTION) + + -- failed + return false + end + + -- get value + value = arg + end + + -- check mode + if (opt[3] == "k" and type(value) ~= "boolean") or (opt[3] == "kv" and type(value) ~= "string") then + + -- invalid option + print("invalid option: " .. arg) + + -- print menu + option.print_menu(xmake._OPTIONS._ACTION) + + -- failed + return false + end + + -- value is "true" or "false", translate it + if type(value) == "string" then + if value == "true" then value = true + elseif value == "false" then value = false + end + end + + -- save option + xmake._OPTIONS[utils.ifelse(prefix == 1 and opt[2], opt[2], key)] = value + + -- action? + elseif idx == 1 then + + -- find this action + for _, action in ipairs(main.actions) do + + -- check + assert(menu[action]) + + -- ok? + if action == key or menu[action].shortname == key then + -- save this action + xmake._OPTIONS._ACTION = action + break + end + end + + -- not found? + if not xmake._OPTIONS._ACTION or not menu[xmake._OPTIONS._ACTION] then + + -- invalid action + print("invalid action: " .. key) + + -- print the main menu + option.print_main() + + -- failed + return false + + end + + -- value? + else + + -- find a value option with name + local opt = nil + for _, o in ipairs(menu[xmake._OPTIONS._ACTION or "main"].options) do + + -- the mode + local mode = o[3] + + -- the name + local name = o[2] + + -- check + assert(o and ((mode ~= "v" and mode ~= "vs") or name)) + + -- is value and with name? + if mode == "v" and name and not xmake._OPTIONS[name] then + opt = o + break + -- is values and with name? + elseif mode == "vs" and name then + opt = o + break + end + end + + -- ok? save this value with name opt[2] + if opt then + + -- the mode + local mode = opt[3] + + -- the name + local name = opt[2] + + -- save value + if mode == "v" then + xmake._OPTIONS[name] = key + elseif mode == "vs" then + -- the option + local o = xmake._OPTIONS[name] + if not o then + xmake._OPTIONS[name] = {} + o = xmake._OPTIONS[name] + end + + -- append value + table.insert(o, key) + end + else + -- invalid option + print("invalid option: " .. arg) + + -- print menu + option.print_menu(xmake._OPTIONS._ACTION) + + -- failed + return false + end + + end + end + + -- init the default value + for _, o in ipairs(menu[xmake._OPTIONS._ACTION or "main"].options) do + + -- key=value? + if o[3] == "kv" then + + -- the key + local key = o[2] or o[1] + assert(key) + + -- save the default value + xmake._OPTIONS._DEFAULTS[key] = o[4] + -- value with name? + elseif o[3] == "v" and o[2] then + -- save the default value + xmake._OPTIONS._DEFAULTS[o[2]] = o[4] + end + end + + -- ok + return true +end + +-- find the value of a given name from the arguments +-- only for kv mode and need not check it using menu +-- +function option.find(argv, name, shortname) + + -- check + assert(argv and (name or shortname)) + + -- find it + local nextvalue = false + for _, arg in ipairs(argv) do + + -- get this value + if nextvalue then return arg end + + -- --name=value? + if name and arg:startswith("--" .. name) then + + -- get value + local i = arg:find("=", 1, true) + if i then return arg:sub(i + 1) end + + -- -shortname value? + elseif shortname and arg:startswith("-" .. shortname) then + + -- get value + nextvalue = true + end + + end +end + +-- get all default options from the given action +function option.defaults(action) + + -- make defaults + local defaults = {} + + -- init the default value + for _, o in ipairs(option._MENU[action or "main"].options) do + + -- key=value? + if o[3] == "kv" then + + -- the key + local key = o[2] or o[1] + assert(key) + + -- save the default value + defaults[key] = o[4] + -- value with name? + elseif o[3] == "v" and o[2] then + -- save the default value + defaults[o[2]] = o[4] + end + end + + -- ok? + return defaults +end + +-- print the menu +function option.print_menu(action) + + -- no action? print main menu + if not action then + option.print_main() + return + end + + -- the menu + local menu = option._MENU + assert(menu) + + -- the action + action = menu[action] + assert(action) + + -- print title + if menu.title then + print(menu.title) + end + + -- print copyright + if menu.copyright then + print(menu.copyright) + end + + -- print usage + if action.usage then + print("") + print("Usage: " .. action.usage) + end + + -- print description + if action.description then + print("") + print(action.description) + end + + -- print options + if action.options then + option.print_options(action.options) + end +end + +-- print the main menu +function option.print_main() + + -- the menu + local menu = option._MENU + assert(menu) + + -- the main menu + local main = menu.main + assert(main) + + -- print title + if menu.title then + print(menu.title) + end + + -- print copyright + if menu.copyright then + print(menu.copyright) + end + + -- print usage + if main.usage then + print("") + print("Usage: " .. main.usage) + end + + -- print description + if main.description then + print("") + print(main.description) + end + + -- print actions + if main.actions then + + -- print header + print("") + print("Actions: ") + + -- the padding spaces + local padding = 42 + + -- print actions + for _, action in ipairs(main.actions) do + + -- the action menu + local action_menu = menu[action] + + -- init the action info + local action_info = " " + if action_menu and action_menu.shortname then + action_info = action_info .. action_menu.shortname .. ", " + else + action_info = action_info .. " " + end + + -- append the action + action_info = action_info .. action + + if action_menu then + -- append spaces + for i = (#action_info), padding do + action_info = action_info .. " " + end + + -- append the action description + if action_menu.description then + action_info = action_info .. action_menu.description + end + end + + -- print action info + print(action_info) + end + end + + -- print options + if main.options then + option.print_options(main.options) + end +end + +-- print the options menu +function option.print_options(options) + + -- check + assert(options) + + -- print header + print("") + print("Options: ") + + -- the padding spaces + local padding = 42 + + -- print options + for _, option in ipairs(options) do + + -- init the option info + local option_info = "" + + -- append the shortname + local shortname = option[1]; + local name = option[2]; + local mode = option[3]; + if shortname then + option_info = option_info .. " -" .. shortname + if mode == "kv" then + option_info = option_info .. " " .. utils.ifelse(name, name:upper(), "XXX") + end + end + + -- append the name + if name then + if mode == "v" then + option_info = option_info .. " " .. name + else + option_info = option_info .. utils.ifelse(shortname, ", --", " --") .. name + end + if mode == "kv" then + option_info = option_info .. "=" .. name:upper() + end + elseif mode == "v" then + option_info = option_info .. " ..." + end + + -- append spaces + for i = (#option_info), padding do + option_info = option_info .. " " + end + + -- append the option description + local description = option[5] + if description then + option_info = option_info .. description + end + + -- append the default value + local default = option[4] + if default then + option_info = option_info .. " (default: " .. tostring(default) .. ")" + end + + -- print option info + print(option_info) + + -- print more description if exists + for i = 6, 64 do + + -- the description, @note some option may be nil + local description = option[i] + if not description then break end + + -- is function? get results + if type(description) == "function" then + description = description() + end + + -- the description is string? + if type(description) == "string" then + + -- make spaces + local spaces = "" + for i = 0, padding do + spaces = spaces .. " " + end + + -- print this description + print(spaces .. description) + + -- the description is table? + elseif type(description) == "table" then + + -- print all descriptions + for _, v in pairs(description) do + + -- make spaces + local spaces = "" + for i = 0, padding do + spaces = spaces .. " " + end + + -- print this description + print(spaces .. v) + end + end + end + end +end + +-- return module: option +return option diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua new file mode 100644 index 000000000..b08ac3820 --- /dev/null +++ b/xmake/core/base/os.lua @@ -0,0 +1,237 @@ +--!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 os.lua +-- + +-- define module: os +local os = os or {} + +-- load modules +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") + +-- match files or directories +-- +-- @param pattern the search pattern +-- uses "*" to match any part of a file or directory name, +-- uses "**" to recurse into subdirectories. +-- +-- @param findir true: find directory, false: find file +-- @return the result array and count +-- +-- @code +-- local dirs, count = os.match("./src/*", true) +-- local files, count = os.match("./src/**.c") +-- local file = os.match("./src/test.c") +-- @endcode +-- +function os.match(pattern, findir) + + -- get the excludes + local excludes = pattern:match("|.*$") + if excludes then excludes = excludes:split("|") end + + -- translate excludes + if excludes then + local _excludes = {} + for _, exclude in ipairs(excludes) do + exclude = path.translate(exclude) + exclude = exclude:gsub("([%+%.%-%^%$%(%)%%])", "%%%1") + exclude = exclude:gsub("%*%*", "\001") + exclude = exclude:gsub("%*", "\002") + exclude = exclude:gsub("\001", ".*") + exclude = exclude:gsub("\002", "[^/]*") + table.insert(_excludes, exclude) + end + excludes = _excludes + end + + -- translate path and remove some repeat separators + pattern = path.translate(pattern:gsub("|.*$", "")) + + -- get the root directory + local rootdir = pattern + local starpos = pattern:find("%*") + if starpos then + rootdir = rootdir:sub(1, starpos - 1) + end + rootdir = path.directory(rootdir) + + -- is recurse? + local recurse = pattern:find("**", nil, true) + + -- convert pattern to a lua pattern + pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1") + pattern = pattern:gsub("%*%*", "\001") + pattern = pattern:gsub("%*", "\002") + pattern = pattern:gsub("\001", ".*") + pattern = pattern:gsub("\002", "[^/]*") + + -- patch "./" for matching ok if root directory is '.' + if rootdir == '.' then + pattern = "./" .. pattern + end + + -- find it + return os.find(rootdir, pattern, recurse, findir, excludes) +end + +-- copy file or directory +function os.cp(src, dst) + + -- check + assert(src and dst) + + -- is file? + if os.isfile(src) then + + -- the destination is directory? append the filename + if os.isdir(dst) then + dst = string.format("%s/%s", dst, path.filename(src)) + end + + -- copy file + if not os.cpfile(src, dst) then + return false, string.format("cannot copy file %s to %s %s", src, dst, os.strerror()) + end + -- is directory? + elseif os.isdir(src) then + -- copy directory + if not os.cpdir(src, dst) then + return false, string.format("cannot copy directory %s to %s %s", src, dst, os.strerror()) + end + -- cp dir/*? + elseif src:find("%*") then + + -- get the root directory + local starpos = src:find("%*") + + -- match all files + local files = os.match((src:gsub("%*+", "**"))) + if files then + for _, file in ipairs(files) do + local dstfile = string.format("%s/%s", dst, file:sub(starpos)) + if not os.cpfile(file, dstfile) then + return false, string.format("cannot copy file %s to %s %s", file, dstfile, os.strerror()) + end + end + end + + -- not exists? + else + return false, string.format("cannot copy file %s, not found this file %s", src, os.strerror()) + end + + -- ok + return true +end + +-- move file or directory +function os.mv(src, dst) + + -- check + assert(src and dst) + + -- exists file or directory? + if os.exists(src) then + -- move file or directory + if not os.rename(src, dst) then + return false, string.format("cannot move %s to %s %s", src, dst, os.strerror()) + end + -- not exists? + else + return false, string.format("cannot move %s to %s, not found this file %s", src, dst, os.strerror()) + end + + -- ok + return true +end + +-- remove file or directory +function os.rm(file_or_dir, emptydir) + + -- check + assert(file_or_dir) + + -- is file? + if os.isfile(file_or_dir) then + -- remove file + if not os.rmfile(file_or_dir) then + return false, string.format("cannot remove file %s %s", file_or_dir, os.strerror()) + end + -- is directory? + elseif os.isdir(file_or_dir) then + -- remove directory + if not os.rmdir(file_or_dir, emptydir) then + return false, string.format("cannot remove directory %s %s", file_or_dir, os.strerror()) + end + -- not exists? + else + return false, string.format("cannot remove file %s, not found this file %s", file_or_dir, os.strerror()) + end + + -- ok + return true +end + +-- change to directory +function os.cd(dir) + + -- check + assert(dir) + + -- change to the previous directory? + if dir == "-" then + -- exists the previous directory? + if os._PREDIR then + dir = os._PREDIR + os._PREDIR = nil + else + -- error + return false, string.format("not found the previous directory %s", os.strerror()) + end + end + + -- is directory? + if os.isdir(dir) then + + -- get the current directory + local current = os.curdir() + + -- change to directory + if not os.chdir(dir) then + return false, string.format("cannot change directory %s %s", dir, os.strerror()) + end + + -- save the previous directory + os._PREDIR = current + + -- not exists? + else + return false, string.format("cannot change directory %s, not found this directory %s", dir, os.strerror()) + end + + -- ok + return true +end + +-- return module: os +return os diff --git a/xmake/core/base/package.lua b/xmake/core/base/package.lua new file mode 100644 index 000000000..ffb1a0d38 --- /dev/null +++ b/xmake/core/base/package.lua @@ -0,0 +1,314 @@ +--!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 package.lua +-- + +-- define module: package +local package = package 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 config = require("base/config") +local platform = require("platform/platform") + +-- package target for the library file +function package._done_library(target) + + -- check + assert(target and target.name and target.archs) + + -- the output directory + local outputdir = target.outputdir + assert(outputdir) + + -- the plat and mode + local plat = config.get("plat") + local mode = config.get("mode") + assert(plat and mode) + + -- package it + for arch, info in pairs(target.archs) do + + -- check + assert(info.targetdir and info.targetfile) + + -- copy the library file to the output directory + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.targetfile), string.format("%s/%s.pkg/lib/%s/%s/%s/%s", outputdir, target.name, mode, plat, arch, path.filename(info.targetfile))) + if not ok then + utils.error(errors) + return -1 + end + + -- copy the config.h to the output directory + if info.config_h then + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.config_h), string.format("%s/%s.pkg/inc/%s/%s", outputdir, target.name, plat, path.filename(info.config_h))) + if not ok then + utils.error(errors) + return -1 + end + end + end + + -- copy headers + if target.headers then + local srcheaders, dstheaders = rule.headerfiles(target, string.format("%s/%s.pkg/inc", outputdir, target.name)) + if srcheaders and dstheaders then + local i = 1 + for _, srcheader in ipairs(srcheaders) do + local dstheader = dstheaders[i] + if dstheader then + local ok, errors = os.cp(srcheader, dstheader) + if not ok then + utils.error(errors) + return -1 + end + end + i = i + 1 + end + end + end + + -- make xmake.lua + local file = io.open(string.format("%s/%s.pkg/xmake.lua", outputdir, target.name), "w") + if file then + + -- the xmake.lua template content + local template = [[ +-- add [targetname] package +add_option("[targetname]") + + -- show menu + set_option_showmenu(true) + + -- set category + set_option_category("package") + + -- set description + set_option_description("The [targetname] package") + + -- set language: c99, c++11 + set_option_languages("c99", "cxx11") + + -- add defines to config.h if checking ok + add_option_defines_h_if_ok("$(prefix)_PACKAGE_HAVE_[TARGETNAME]") + + -- add links for checking + add_option_links("[targetname]") + + -- add link directories + add_option_linkdirs("lib/$(mode)/$(plat)/$(arch)") + + -- add c includes for checking + add_option_cincludes("[targetname]/[targetname].h") + + -- add include directories + add_option_includedirs("inc/$(plat)", "inc") +]] + + -- save file + file:write((template:gsub("%[targetname%]", target.name):gsub("%[TARGETNAME%]", target.name:upper()))) + + -- exit file + file:close() + end + + -- ok + return 1 +end + +-- package target for the binary file +function package._done_binary(target) + + -- check + assert(target and target.archs) + + -- the output directory + local outputdir = target.outputdir + assert(outputdir) + + -- the count of architectures + local count = 0 + for _, _ in pairs(target.archs) do count = count + 1 end + + -- package it + local ok = nil + local errors = nil + for arch, info in pairs(target.archs) do + + -- check + assert(info.targetdir and info.targetfile) + + -- copy the binary file to the output directory + if count == 1 then + ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.targetfile), string.format("%s/%s", outputdir, path.filename(info.targetfile))) + else + ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.targetfile), string.format("%s/%s", outputdir, rule.filename(path.basename(info.targetfile) .. "_" .. arch, "binary"))) + end + + -- ok? + if not ok then + utils.error(errors) + return -1 + end + end + + -- ok + return 1 +end + +-- package target from the default script +function package._done_from_default(target) + + -- check + assert(target.kind) + + -- the package scripts + local packagescripts = + { + static = package._done_library + , shared = package._done_library + , binary = package._done_binary + } + + -- package it + local packagescript = packagescripts[target.kind] + if packagescript then return packagescript(target) end + + -- continue + return 0 +end + +-- package target from the project script +function package._done_from_project(target) + + -- check + assert(target) + + -- package it using the project script first + local packagescript = target.packagescript + if type(packagescript) == "function" then + + -- remove it + target.packagescript = nil + + -- package it + return packagescript(target) + end + + -- continue + return 0 +end + +-- package target from the platform script +function package._done_from_platform(target) + + -- check + assert(target) + + -- the platform package script file + local packagescript = nil + local scriptfile = platform.directory() .. "/package.lua" + if os.isfile(scriptfile) then + + -- load the package script + local script, errors = loadfile(scriptfile) + if script then + packagescript = script() + if type(packagescript) == "table" and packagescript.main then + packagescript = packagescript.main + end + else + utils.error(errors) + end + end + + -- package it + if type(packagescript) == "function" then + return packagescript(target) + end + + -- continue + return 0 +end + +-- get the configure file +function package._file() + + -- get it + return config.directory() .. "/package.conf" +end + +-- package target from the given target configure +function package._done(target) + + -- check + assert(target) + + -- package it from the project script + local ok = package._done_from_project(target) + if ok ~= 0 then return utils.ifelse(ok == 1, true, false) end + + -- package it from the platform script + local ok = package._done_from_platform(target) + if ok ~= 0 then return utils.ifelse(ok == 1, true, false) end + + -- package it from the default script + local ok = package._done_from_default(target) + if ok ~= 0 then return utils.ifelse(ok == 1, true, false) end + + -- ok + return true +end + +-- done package from the configure +function package.done(configs) + + -- check + assert(configs) + + -- package targets + for _, target in pairs(configs) do + + -- package it + if not package._done(target) then + -- errors + utils.error("package %s failed!", target.name) + return false + end + + end + + -- save to the configure file + return io.save(package._file(), configs) +end + +-- load the package configure +function package.load() + + -- load it + return io.load(package._file()) +end + +-- return module: package +return package diff --git a/xmake/core/base/path.lua b/xmake/core/base/path.lua new file mode 100644 index 000000000..eb35283b2 --- /dev/null +++ b/xmake/core/base/path.lua @@ -0,0 +1,72 @@ +--!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 path.lua +-- + +-- define module: path +local path = path or {} + +-- load modules +local string = require("base/string") + +-- get the directory of the path +function path.directory(p) + local i = p:find_last("[/\\]") + if i then + if i > 1 then i = i - 1 end + return p:sub(1, i) + else + return "." + end +end + +-- get the filename of the path +function path.filename(p) + local i = p:find_last("[/\\]") + if i then + return p:sub(i + 1) + else + return p + end +end + +-- get the basename of the path +function path.basename(p) + local name = path.filename(p) + local i = name:find_last(".", true) + if i then + return name:sub(1, i - 1) + else + return name + end +end + +-- get the file extension of the path: .xxx +function path.extension(p) + local i = p:find_last(".", true) + if i then + return p:sub(i) + else + return "" + end +end + +-- return module: path +return path diff --git a/xmake/core/base/project.lua b/xmake/core/base/project.lua new file mode 100644 index 000000000..51b46afe3 --- /dev/null +++ b/xmake/core/base/project.lua @@ -0,0 +1,1469 @@ +--!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_kinds(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.kinds = function (...) return project._api_kinds(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.kinds = function (...) return project._api_kinds(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 diff --git a/xmake/core/base/rule.lua b/xmake/core/base/rule.lua new file mode 100644 index 000000000..b3dc1825c --- /dev/null +++ b/xmake/core/base/rule.lua @@ -0,0 +1,300 @@ +--!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 rule.lua +-- + +-- define module: rule +local rule = rule 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("base/config") +local platform = require("platform/platform") + +-- get the building log file path +function rule.logfile() + + -- the logdir + local logdir = config.get("buildir") or os.tmpdir() + assert(logdir) + + -- get it + return path.translate(logdir .. "/.build.log") +end + +-- get the filename from the given name and kind +function rule.filename(name, kind) + + -- check + assert(name and kind) + + -- get format + local format = platform.format(kind) or {"", ""} + + -- make it + return format[1] .. name .. format[2] +end + +-- get the makefile path +function rule.makefile() + + -- get the build directory + local buildir = config.get("buildir") + assert(buildir) + + -- get it + return path.translate(buildir .. "/makefile") +end + +-- get configure file for the given target +function rule.config_h(target) + + -- get the target configure file + local config_h = target.config_h + if config_h then + -- 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 + end + + -- ok? + return config_h +end + +-- get the temporary backup directory for package +function rule.backupdir(target_name, arch) + + -- the temporary directory + local tmpdir = os.tmpdir() + assert(tmpdir) + + -- the project name + local project_name = path.basename(xmake._PROJECT_DIR) + assert(project_name) + + -- make it + return string.format("%s/.xmake/%s/pkgfiles/%s/%s", tmpdir, project_name, target_name, arch) +end + +-- get target file for the given target +function rule.targetfile(target_name, target, buildir) + + -- check + assert(target_name and target and target.kind) + + -- the target directory + local targetdir = target.targetdir or buildir or config.get("buildir") + assert(targetdir and type(targetdir) == "string") + + -- the target file name + local filename = rule.filename(target_name, target.kind) + assert(filename) + + -- make the target file path + return targetdir .. "/" .. filename +end + +-- get object files for the given source files +function rule.objectdir(target_name, target, buildir) + + -- check + assert(target_name and target) + + -- the object directory + local objectdir = target.objectdir + if not objectdir then + + -- the build directory + if not buildir then + buildir = config.get("buildir") + end + assert(buildir) + + -- make the default object directory + objectdir = buildir .. "/.objs" + end + + -- ok? + return objectdir +end + +-- get object files for the given source files +function rule.objectfiles(target_name, target, sourcefiles, buildir) + + -- check + assert(target_name and target and sourcefiles) + + -- the object directory + local objectdir = rule.objectdir(target_name, target, buildir) + assert(objectdir and type(objectdir) == "string") + + -- make object files + local i = 1 + local objectfiles = {} + for _, sourcefile in ipairs(sourcefiles) do + + -- translate: [lib]xxx*.[a|lib] => xxx/*.[o|obj] object file + sourcefile = sourcefile:gsub(rule.filename("(%w+)", "static"):gsub("%.", "%%.") .. "$", "%1/*") + + -- make object file + local objectfile = string.format("%s/%s/%s/%s", objectdir, target_name, path.directory(sourcefile), rule.filename(path.basename(sourcefile), "object")) + + -- translate path + -- + -- .e.g + -- + -- src/xxx.c + -- project/xmake.lua + -- build/.objs + -- + -- objectfile: project/build/.objs/xxxx/../../xxx.c will be out of range for objectdir + -- + -- we need replace '..' to '__' in this case + -- + objectfile = (path.translate(objectfile):gsub("%.%.", "__")) + + -- save it + objectfiles[i] = objectfile + i = i + 1 + + end + + -- ok? + return objectfiles +end + +-- get the source files from the given target +function rule.sourcefiles(target) + + -- check + assert(target) + + -- no files? + if not target.files then + return {} + end + + -- wrap files first + local targetfiles = utils.wrap(target.files) + + -- match files + local i = 1 + local sourcefiles = {} + for _, targetfile in ipairs(targetfiles) do + + -- normalize *.[o|obj] filename + targetfile = targetfile:gsub("([%w%*]+)%.obj|", rule.filename("%1|", "object")) + targetfile = targetfile:gsub("([%w%*]+)%.obj$", rule.filename("%1", "object")) + targetfile = targetfile:gsub("([%w%*]+)%.o|", rule.filename("%1|", "object")) + targetfile = targetfile:gsub("([%w%*]+)%.o$", rule.filename("%1", "object")) + + -- normalize [lib]*.[a|lib] filename + targetfile = targetfile:gsub("([%w%*]+)%.lib|", rule.filename("%1|", "static")) + targetfile = targetfile:gsub("([%w%*]+)%.lib$", rule.filename("%1", "static")) + targetfile = targetfile:gsub("lib([%w%*]+)%.a|", rule.filename("%1|", "static")) + targetfile = targetfile:gsub("lib([%w%*]+)%.a$", rule.filename("%1", "static")) + + -- match source files + local files = os.match(targetfile) + if #files == 0 then + utils.warning("cannot match add_files(\"%s\")", targetfile) + end + + -- process source files + for _, file in ipairs(files) do + + -- convert to the relative path + if path.is_absolute(file) then + file = path.relative(file, xmake._PROJECT_DIR) + end + + -- save it + sourcefiles[i] = file + i = i + 1 + + end + end + + -- remove repeat files + sourcefiles = utils.unique(sourcefiles) + + -- ok? + return sourcefiles +end + +-- get the header files from the given target +function rule.headerfiles(target, headerdir) + + -- check + assert(target) + + -- no headers? + local headers = target.headers + if not headers then return end + + -- get the headerdir + if not headerdir then headerdir = target.headerdir or config.get("buildir") end + assert(headerdir) + + -- get the source pathes and destinate pathes + local srcheaders = {} + local dstheaders = {} + for _, header in ipairs(utils.wrap(headers)) do + + -- get the root directory + local rootdir = header:gsub("%(.*%)", ""):gsub("|.*$", "") + + -- remove '(' and ')' + local srcpathes = header:gsub("[%(%)]", "") + if srcpathes then + + -- get the source pathes + srcpathes = os.match(srcpathes) + if srcpathes then + + -- add the source headers + table.join2(srcheaders, srcpathes) + + -- add the destinate headers + for _, srcpath in ipairs(srcpathes) do + + -- the header + local dstheader = path.absolute(path.relative(srcpath, rootdir), headerdir) + assert(dstheader) + + -- add it + table.insert(dstheaders, dstheader) + end + end + end + end + + -- ok? + return srcheaders, dstheaders +end + +-- return module: rule +return rule diff --git a/xmake/core/base/string.lua b/xmake/core/base/string.lua new file mode 100644 index 000000000..b4be08cfa --- /dev/null +++ b/xmake/core/base/string.lua @@ -0,0 +1,115 @@ +--!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 string.lua +-- + +-- define module: string +local string = string or {} + +-- find the last substring with the given pattern +function string.find_last(self, pattern, plain) + + -- find the last substring + local curr = 0 + repeat + local next = self:find(pattern, curr + 1, plain) + if next then + curr = next + end + until (not next) + + -- found? + if curr > 0 then + return curr + end +end + +-- split string with the given pattern +function string.split(self, pattern) + + -- split it + local list = {} + self:gsub("[^" .. pattern .."]+", function(v) table.insert(list, v) end ) + return list +end + +-- trim the spaces +function string.trim(self) + return (self:gsub("^%s*(.-)%s*$", "%1")) +end + +-- trim the left spaces +function string.ltrim(self) + return (self:gsub("^%s*", "")) +end + +-- trim the right spaces +function string.rtrim(self) + local n = #self + while n > 0 and s:find("^%s", n) do n = n - 1 end + return self:sub(1, n) +end + +-- append a substring with a given separator +function string.append(self, substr, separator) + + -- check + assert(self) + + -- not substr? return self + if not substr then + return self + end + + -- append it + local s = self + if #s == 0 then + s = substr + else + s = string.format("%s%s%s", s, separator or "", substr) + end + + -- ok + return s +end + +-- encode: ' ', '=', '\"', '<' +function string.encode(self) + + -- null? + if self == nil then return end + + -- done + return (self:gsub("[%s=\"<]", function (w) return string.format("%%%x", w:byte()) end)) +end + +-- decode: ' ', '=', '\"' +function string.decode(self) + + -- null? + if self == nil then return end + + -- done + return (self:gsub("%%(%x%x)", function (w) return string.char(tonumber(w, 16)) end)) +end + + +-- return module: string +return string diff --git a/xmake/core/base/table.lua b/xmake/core/base/table.lua new file mode 100644 index 000000000..52b726412 --- /dev/null +++ b/xmake/core/base/table.lua @@ -0,0 +1,99 @@ +--!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 table.lua +-- + +-- define module: table +local table = table or {} + +-- join all objects and tables +function table.join(...) + + -- done + local args = {...} + local result = {} + for _, t in ipairs(args) do + if type(t) == "table" then + for k, v in pairs(t) do + if type(k) == "number" then table.insert(result, v) + else result[k] = v end + end + else + table.insert(result, t) + end + end + + -- ok? + return result +end + +-- join all objects and tables to self +function table.join2(self, ...) + + -- check + assert(self and type(self) == "table") + + -- done + local args = {...} + for _, t in ipairs(args) do + if type(t) == "table" then + for k, v in pairs(t) do + if type(k) == "number" then table.insert(self, v) + else self[k] = v end + end + else + table.insert(self, t) + end + end + + -- ok? + return self +end + +-- clear the table +function table.clear(self) + + -- check + assert(self and type(self) == "table") + + -- clear it + for k in next, self do + rawset(self, k, nil) + end +end + +-- copy the table to self +function table.copy2(self, copied) + + -- check + assert(self and copied) + + -- clear self first + table.clear(self) + + -- copy it + for k, v in pairs(copied) do + self[k] = v + end + +end + +-- return module: table +return table diff --git a/xmake/core/base/template.lua b/xmake/core/base/template.lua new file mode 100644 index 000000000..c02b135c3 --- /dev/null +++ b/xmake/core/base/template.lua @@ -0,0 +1,77 @@ +--!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 template.lua +-- + +-- define module: template +local template = template or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") + +-- get the language list +function template.languages() + + -- make list + local list = {} + + -- get the language list + local languages = os.match(xmake._TEMPLATES_DIR .. "/*", true) + if languages then + for _, v in ipairs(languages) do + table.insert(list, path.basename(v)) + end + end + + -- ok? + return list +end + +-- load all templates from the given language +function template.loadall(language) + + -- check + assert(language) + + -- load all templates + local modules = {} + local templates = os.match(string.format("%s/%s/**/_template.lua", xmake._TEMPLATES_DIR, language)) + if templates then + for _, t in ipairs(templates) do + local script = assert(loadfile(t)) + if script then + local module = script() + if module then + module._DIRECTORY = path.directory(t) + table.insert(modules, module) + end + end + end + end + + -- ok? + return modules +end + + +-- return module: template +return template diff --git a/xmake/core/base/uninstall.lua b/xmake/core/base/uninstall.lua new file mode 100644 index 000000000..304b73c92 --- /dev/null +++ b/xmake/core/base/uninstall.lua @@ -0,0 +1,104 @@ +--!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 uninstall.lua +-- + +-- define module: uninstall +local uninstall = uninstall 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 config = require("base/config") +local platform = require("platform/platform") + +-- uninstall target from the platform script +function uninstall._done_from_platform(target) + + -- check + assert(target) + + -- the platform uninstall script file + local uninstallscript = nil + local scriptfile = platform.directory() .. "/uninstall.lua" + if os.isfile(scriptfile) then + + -- load the uninstall script + local script, errors = loadfile(scriptfile) + if script then + uninstallscript = script() + if type(uninstallscript) == "table" and uninstallscript.main then + uninstallscript = uninstallscript.main + end + else + utils.error(errors) + end + end + + -- uninstall it + if type(uninstallscript) == "function" then + return uninstallscript(target) + end + + -- continue + return 0 +end + +-- uninstall target from the given target configure +function uninstall._done(target) + + -- check + assert(target) + + -- uninstall it from the platform script + local ok = uninstall._done_from_platform(target) + if ok ~= 0 then return utils.ifelse(ok == 1, true, false) end + + -- ok + return true +end + +-- done uninstall from the configure +function uninstall.done(configs) + + -- check + assert(configs) + + -- uninstall targets + for _, target in pairs(configs) do + + -- uninstall it + if not uninstall._done(target) then + -- errors + utils.error("uninstall %s failed!", target.name) + return false + end + + end + + -- ok + return true +end + +-- return module: uninstall +return uninstall diff --git a/xmake/core/base/utils.lua b/xmake/core/base/utils.lua new file mode 100644 index 000000000..fd1f053d6 --- /dev/null +++ b/xmake/core/base/utils.lua @@ -0,0 +1,258 @@ +--!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 utils.lua +-- + +-- define module: utils +local utils = utils or {} + +-- the printf function +function utils.printf(msg, ...) + + -- check + assert(msg) + + -- trace + print(string.format(msg, ...)) +end + +-- the verbose function +function utils.verbose(msg, ...) + + if xmake._OPTIONS.verbose then + + -- check + assert(msg) + + -- trace + print(string.format(msg, ...)) + end +end + +-- the error function +function utils.error(msg, ...) + + -- check + assert(msg) + + -- trace + print("error: " .. string.format(msg, ...)) +end + +-- the warning function +function utils.warning(msg, ...) + + -- check + assert(msg) + + -- trace + print("warning: " .. string.format(msg, ...)) +end + +-- ifelse, a? b : c +function utils.ifelse(a, b, c) + if a then return b else return c end +end + +-- dump object with the level +function utils._dump_with_level(object, exclude, level) + + -- dump string + if type(object) == "string" then + io.write(string.format("%q", object)) + -- dump boolean + elseif type(object) == "boolean" then + io.write(tostring(object)) + -- dump number + elseif type(object) == "number" then + io.write(object) + -- dump function + elseif type(object) == "function" then + io.write("<function>") + -- dump table + elseif type(object) == "table" then + + -- dump head + io.write("\n") + for l = 1, level do + io.write(" ") + end + io.write("{\n") + + -- dump body + local i = 0 + for k, v in pairs(object) do + + -- exclude some keys + if not exclude or type(k) ~= "string" or not k:find(exclude) then + + -- dump spaces and separator + for l = 1, level do + io.write(" ") + end + + io.write(utils.ifelse(i == 0, " ", ", ")) + + -- dump key + if type(k) == "string" then + io.write(k, " = ") + end + + -- dump value + if not utils._dump_with_level(v, exclude, level + 1) then + return false + end + + -- dump newline + io.write("\n") + i = i + 1 + end + end + + -- dump tail + for l = 1, level do + io.write(" ") + end + io.write("}\n") + else + -- error + utils.error("invalid object type: %s", type(object)) + return false + end + + -- ok + return true +end + +-- dump object +function utils.dump(object, exclude, prefix) + + -- dump prefix + if prefix then + io.write(prefix) + end + + -- dump it + utils._dump_with_level(object, exclude, 0) + + -- return it + return object +end + +-- unwrap object if be only one +function utils.unwrap(object) + + -- check + assert(object) + + -- unwrap it + if type(object) == "table" and table.getn(object) == 1 then + for _, v in pairs(object) do + return v + end + end + + -- ok + return object +end + +-- wrap object to table +function utils.wrap(object) + + -- no object? + if not object then + return {} + end + + -- wrap it if not table + if type(object) ~= "table" then + return {object} + end + + -- ok + return object +end + +-- remove repeat from the given array +function utils.unique(array) + + -- check + assert(array) + + -- remove repeat + if type(array) == "table" then + + -- not only one? + if table.getn(array) ~= 1 then + + -- done + local exists = {} + local unique = {} + for _, v in ipairs(array) do + if type(v) == "string" then + if not exists[v] then + exists[v] = true + table.insert(unique, v) + end + else + if not exists["\"" .. v .. "\""] then + exists["\"" .. v .. "\""] = true + table.insert(unique, v) + end + end + end + + -- update it + array = unique + end + end + + -- ok + return array +end + +-- call functions +function utils.call(funcs, pred, ...) + + -- check + assert(funcs) + + -- call all + for _, func in ipairs(utils.wrap(funcs)) do + + -- check + assert(type(func) == "function") + + -- call it + local result = func(...) + + -- exists predicate? + if pred and type(pred) == "function" then + if not pred(name, result) then return false end + -- failed? + elseif not result then return false end + end + + -- ok + return true +end + +-- return module: utils +return utils diff --git a/xmake/core/module/os.lua b/xmake/core/module/os.lua new file mode 100644 index 000000000..3689086f2 --- /dev/null +++ b/xmake/core/module/os.lua @@ -0,0 +1,46 @@ +--!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 os.lua +-- + +-- load modules +local io = require("base/io") +local os = require("base/os") + +-- define module: _os +local _os = _os or {} + +-- cat the given file +function _os.cat(filepath, linecount) + + -- cat it + return io.cat(filepath, linecount) +end + +-- only copy the interfaces of os +for k, v in pairs(os) do + if type(v) == "function" then + _os[k] = v + end +end + +-- return module: _os +return _os + diff --git a/xmake/core/module/path.lua b/xmake/core/module/path.lua new file mode 100644 index 000000000..9de905667 --- /dev/null +++ b/xmake/core/module/path.lua @@ -0,0 +1,25 @@ +--!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 path.lua +-- + +-- return module: path +return require("base/path") + diff --git a/xmake/core/module/project.lua b/xmake/core/module/project.lua new file mode 100644 index 000000000..f3f726c6f --- /dev/null +++ b/xmake/core/module/project.lua @@ -0,0 +1,73 @@ +--!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 rule = require("base/rule") +local config = require("base/config") + +-- get the build directory +function project.buildir() + + -- get it + return config.get("buildir") +end + +-- get the project directory +function project.projectdir() + + -- get it + return xmake._PROJECT_DIR +end + +-- get the log file +function project.logfile() + + -- get it + return rule.logfile() +end + +-- get the current platform +function project.plat() + + -- get it + return config.get("plat") +end + +-- get the current architecture +function project.arch() + + -- get it + return config.get("arch") +end + +-- get the current mode +function project.mode() + + -- get it + return config.get("mode") +end + +-- return module: project +return project diff --git a/xmake/core/module/string.lua b/xmake/core/module/string.lua new file mode 100644 index 000000000..60d3408cf --- /dev/null +++ b/xmake/core/module/string.lua @@ -0,0 +1,24 @@ +--!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 string.lua +-- + +-- return module: string +return require("base/string") diff --git a/xmake/core/module/utils.lua b/xmake/core/module/utils.lua new file mode 100644 index 000000000..ab4d2c96f --- /dev/null +++ b/xmake/core/module/utils.lua @@ -0,0 +1,24 @@ +--!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 utils.lua +-- + +-- return module: utils +return require("base/utils") diff --git a/xmake/core/platform/android/android.lua b/xmake/core/platform/android/android.lua new file mode 100644 index 000000000..15e3c33a2 --- /dev/null +++ b/xmake/core/platform/android/android.lua @@ -0,0 +1,120 @@ +--!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 android.lua +-- + +-- define module: android +local android = android or {} + +-- load modules +local config = require("base/config") + +-- init host +android._HOST = xmake._HOST + +-- init os +android._OS = "android" + +-- init architectures +android._ARCHS = {"armv5te", "armv6", "armv7-a", "armv8-a", "arm64-v8a"} + +-- make configure +function android.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".so"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.as = config.get("as") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + + -- init flags + local arch = config.get("arch") + if arch:startswith("arm64") then + configs.cxflags = {} + configs.asflags = {} + configs.ldflags = {"-llog"} + configs.shflags = {"-llog"} + else + configs.cxflags = { "-march=" .. arch, "-mthumb"} + configs.asflags = { "-march=" .. arch, "-mthumb"} + configs.ldflags = { "-march=" .. arch, "-llog", "-mthumb"} + configs.shflags = { "-march=" .. arch, "-llog", "-mthumb"} + end + + -- add flags for the sdk directory of ndk + local ndk = config.get("ndk") + local ndk_sdkver = config.get("ndk_sdkver") + if ndk and ndk_sdkver then + local ndk_sdkdir = path.translate(string.format("%s/platforms/android-%d", ndk, ndk_sdkver)) + if arch:startswith("arm64") then + table.insert(configs.cxflags, string.format("--sysroot=%s/arch-arm64", ndk_sdkdir)) + table.insert(configs.asflags, string.format("--sysroot=%s/arch-arm64", ndk_sdkdir)) + table.insert(configs.ldflags, string.format("--sysroot=%s/arch-arm64", ndk_sdkdir)) + table.insert(configs.shflags, string.format("--sysroot=%s/arch-arm64", ndk_sdkdir)) + else + table.insert(configs.cxflags, string.format("--sysroot=%s/arch-arm", ndk_sdkdir)) + table.insert(configs.asflags, string.format("--sysroot=%s/arch-arm", ndk_sdkdir)) + table.insert(configs.ldflags, string.format("--sysroot=%s/arch-arm", ndk_sdkdir)) + table.insert(configs.shflags, string.format("--sysroot=%s/arch-arm", ndk_sdkdir)) + end + end + +end + +-- get the option menu for action: xmake config or global +function android.menu(action) + + -- init config option menu + android._MENU_CONFIG = android._MENU_CONFIG or + { {} + , {nil, "ndk", "kv", nil, "The NDK Directory" } + , {nil, "ndk_sdkver", "kv", "auto", "The SDK Version for NDK" } + , } + + -- init global option menu + android._MENU_GLOBAL = android._MENU_GLOBAL or + { {} + , {nil, "ndk", "kv", nil, "The NDK Directory" } + , {nil, "ndk_sdkver", "kv", "auto", "The SDK Version for NDK" } + , } + + -- get the option menu + if action == "config" then + return android._MENU_CONFIG + elseif action == "global" then + return android._MENU_GLOBAL + end +end + +-- return module: android +return android diff --git a/xmake/core/platform/android/prober.lua b/xmake/core/platform/android/prober.lua new file mode 100644 index 000000000..a6446e0e1 --- /dev/null +++ b/xmake/core/platform/android/prober.lua @@ -0,0 +1,269 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", "armv7-a") + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the sdk version for ndk +function prober._probe_ndk_sdkver(configs) + + -- ok? + local ndk_sdkver = configs.get("ndk_sdkver") + if ndk_sdkver then return true end + + -- get the ndk + local ndk = configs.get("ndk") + if ndk then + + -- match all sdk directories + local sdkdirs = os.match(ndk .. "/platforms/android-*", true) + if sdkdirs then + + -- get the max version + local version_maxn = 0 + for _, sdkdir in ipairs(sdkdirs) do + local filename = path.filename(sdkdir) + local version, count = filename:gsub("android%-", "") + if count > 0 then + version = tonumber(version) + if version > version_maxn then version_maxn = version end + end + end + + -- save the version + if version_maxn > 0 then ndk_sdkver = version_maxn end + end + end + + -- probe ok? update it + if type(ndk_sdkver) == "number" and ndk_sdkver > 0 then + + -- save it + configs.set("ndk_sdkver", ndk_sdkver) + + -- trace + utils.printf("checking for the SDK version of NDK ... %s", string.format("android-%d", ndk_sdkver)) + else + + -- trace + utils.printf("checking for the SDK version of NDK ... no") + end + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolpath(configs, kind, cross, name, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- attempt to get it from the given cross toolchains + local toolpath = nil + local toolchains = configs.get("toolchains") + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to get it from the ndk + if not toolpath then + local ndk = configs.get("ndk") + if ndk then + + -- match all toolchains + local arch = configs.get("arch") + if arch and arch:startswith("arm64") then + toolchains = os.match(string.format("%s/toolchains/aarch64-linux-android-**/prebuilt/*/bin/%s%s", ndk, cross, name)) + else + toolchains = os.match(string.format("%s/toolchains/arm-linux-androideabi-**/prebuilt/*/bin/%s%s", ndk, cross, name)) + end + + -- probe the tool path + if toolchains then + for _, filepath in ipairs(toolchains) do + toolpath = tools.probe(cross .. name, path.directory(filepath)) + if toolpath then break end + end + end + end + end + + -- probe ok? update it + if toolpath then configs.set(kind, toolpath) end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- failed? + if not toolpath and not configs.get("ndk") then + utils.error("checking for the NDK directory ... no") + utils.error(" - xmake config --ndk=xxx") + utils.error("or - xmake global --ndk=xxx") + return false + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- init prefix + local prefix = "arm-linux-androideabi-" + local arch = configs.get("arch") + if arch and arch:startswith("arm64") then + prefix = "aarch64-linux-android-" + end + + -- done + if not prober._probe_toolpath(configs, "cc", prefix, "gcc", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", prefix, "g++", "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", prefix, "gcc", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", prefix, "g++", "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", prefix, "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", prefix, "g++", "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", prefix, "swiftc", "the swift compiler") then return false end + + -- ok + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_make + , prober._probe_ccache + , prober._probe_ndk_sdkver + , prober._probe_toolchains} + , nil + , config) + +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_make + , prober._probe_ccache + , prober._probe_ndk_sdkver} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/iphoneos/iphoneos.lua b/xmake/core/platform/iphoneos/iphoneos.lua new file mode 100644 index 000000000..f9147945c --- /dev/null +++ b/xmake/core/platform/iphoneos/iphoneos.lua @@ -0,0 +1,141 @@ +--!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 iphoneos.lua +-- + +-- define module: iphoneos +local iphoneos = iphoneos or {} + +-- load modules +local config = require("base/config") + +-- init host +iphoneos._HOST = "macosx" + +-- init os +iphoneos._OS = "ios" + +-- init architectures +iphoneos._ARCHS = {"armv7", "armv7s", "arm64"} + +-- make configure +function iphoneos.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".dylib"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.mm = config.get("mm") + configs.tools.mxx = config.get("mxx") + configs.tools.as = config.get("as") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + configs.tools.lipo = config.get("lipo") + + -- init target minimal version + local target_minver = config.get("target_minver") + assert(target_minver) + + -- init flags for architecture + local archflags = nil + local arch = config.get("arch") + if arch then archflags = "-arch " .. arch end + configs.cxflags = { archflags, "-miphoneos-version-min=" .. target_minver } + configs.mxflags = { archflags, "-miphoneos-version-min=" .. target_minver } + configs.asflags = { archflags, "-miphoneos-version-min=" .. target_minver } + configs.ldflags = { archflags, "-ObjC", "-lstdc++", "-fobjc-link-runtime", "-miphoneos-version-min=" .. target_minver } + configs.shflags = { archflags, "-ObjC", "-lstdc++", "-fobjc-link-runtime", "-miphoneos-version-min=" .. target_minver } + if arch then + configs.scflags = { string.format("-target %s-apple-ios%s", arch, target_minver) } + end + + -- init flags for the xcode sdk directory + local xcode_dir = config.get("xcode_dir") + local xcode_sdkver = config.get("xcode_sdkver") + if xcode_dir and xcode_sdkver then + + -- init flags + local xcode_sdkdir = xcode_dir .. "/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" .. xcode_sdkver .. ".sdk" + table.insert(configs.cxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.asflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.mxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.ldflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.shflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.scflags, "-sdk " .. xcode_sdkdir) + + -- save swift link directory + config.set("__swift_linkdirs", xcode_dir .. "/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos") + end + +end + +-- get the option menu for action: xmake config or global +function iphoneos.menu(action) + + -- init config option menu + iphoneos._MENU_CONFIG = iphoneos._MENU_CONFIG or + { {} + , {nil, "mm", "kv", nil, "The Objc Compiler" } + , {nil, "mxx", "kv", nil, "The Objc++ Compiler" } + , {nil, "mflags", "kv", nil, "The Objc Compiler Flags" } + , {nil, "mxflags", "kv", nil, "The Objc/c++ Compiler Flags" } + , {nil, "mxxflags", "kv", nil, "The Objc++ Compiler Flags" } + , {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {nil, "xcode_sdkver", "kv", "auto", "The SDK Version for Xcode" } + , {nil, "target_minver", "kv", "auto", "The Target Minimal Version" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- init global option menu + iphoneos._MENU_GLOBAL = iphoneos._MENU_GLOBAL or + { {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- get the option menu + if action == "config" then + return iphoneos._MENU_CONFIG + elseif action == "global" then + return iphoneos._MENU_GLOBAL + end +end + + +-- return module: iphoneos +return iphoneos diff --git a/xmake/core/platform/iphoneos/package.lua b/xmake/core/platform/iphoneos/package.lua new file mode 100644 index 000000000..1e46ddadc --- /dev/null +++ b/xmake/core/platform/iphoneos/package.lua @@ -0,0 +1,76 @@ +--!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 package.lua +-- + +-- define module: package +local package = package or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local rule = require("base/rule") +local utils = require("base/utils") +local string = require("base/string") +local platform = require("platform/platform") + +-- package target +function package.main(target) + + -- check + assert(target and target.name) + + -- the count of architectures + local count = 0 + for _, _ in pairs(target.archs) do count = count + 1 end + if count < 2 then return 0 end + + -- get the lipo tool + local lipo = platform.tool("lipo") + if not lipo then return 0 end + + -- make universal info + local universal = {} + universal.targetdir = rule.backupdir(target.name, "universal") + universal.targetfile = rule.targetfile(target.name, target) + if not universal.targetdir or not universal.targetfile then return 0 end + + -- make the universal directory + os.mkdir(path.directory(string.format("%s/%s", universal.targetdir, universal.targetfile))) + + -- make the lipo command + local cmd = lipo .. " -create" + for arch, info in pairs(target.archs) do + cmd = string.format("%s -arch %s %s/%s", cmd, arch, info.targetdir, info.targetfile) + end + cmd = string.format("%s -output %s/%s", cmd, universal.targetdir, universal.targetfile) + + -- make the universal target + if 0 ~= os.execute(cmd) then return 0 end + + -- ok + target.archs.universal = universal + + -- continue + return 0 +end + +-- return module: package +return package diff --git a/xmake/core/platform/iphoneos/prober.lua b/xmake/core/platform/iphoneos/prober.lua new file mode 100644 index 000000000..0de95c783 --- /dev/null +++ b/xmake/core/platform/iphoneos/prober.lua @@ -0,0 +1,310 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", "armv7") + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the xcode application directory +function prober._probe_xcode(configs) + + -- get the xcode directory + local xcode_dir = configs.get("xcode_dir") + + -- ok? + if xcode_dir then return true end + + -- clear it first + xcode_dir = nil + + -- attempt to get the default directory + if not xcode_dir then + if os.isdir("/Applications/Xcode.app") then + xcode_dir = "/Applications/Xcode.app" + end + end + + -- attempt to match the other directories + if not xcode_dir then + local dirs = os.match("/Applications/Xcode*.app", true) + if dirs and table.getn(dirs) ~= 0 then + xcode_dir = dirs[1] + end + end + + -- probe ok? update it + if xcode_dir then + -- save it + configs.set("xcode_dir", xcode_dir) + + -- trace + utils.printf("checking for the Xcode application directory ... %s", xcode_dir) + else + -- failed + utils.error("checking for the Xcode application directory ... no") + utils.error(" - xmake config --xcode_dir=xxx") + utils.error("or - xmake global --xcode_dir=xxx") + return false + end + + -- ok + return true +end + +-- probe the xcode sdk version +function prober._probe_xcode_sdkver(configs) + + -- get the xcode sdk version + local xcode_sdkver = configs.get("xcode_sdkver") + + -- ok? + if xcode_sdkver then return true end + + -- clear it first + xcode_sdkver = nil + + -- attempt to match the directory + if not xcode_sdkver then + local dirs = os.match(configs.get("xcode_dir") .. "/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS*.sdk", true) + if dirs then + for _, dir in ipairs(dirs) do + xcode_sdkver = string.match(dir, "%d+%.%d+") + if xcode_sdkver then break end + end + end + end + + -- probe ok? update it + if xcode_sdkver then + + -- save it + configs.set("xcode_sdkver", xcode_sdkver) + + -- trace + utils.printf("checking for the Xcode SDK version for %s ... %s", configs.get("plat"), xcode_sdkver) + else + -- failed + utils.error("checking for the Xcode SDK version for %s ... no", configs.get("plat")) + utils.error(" - xmake config --xcode_sdkver=xxx") + utils.error("or - xmake global --xcode_sdkver=xxx") + return false + end + + -- ok + return true +end + +-- probe the target minimal version +function prober._probe_target_minver(configs) + + -- get the target minimal version + local target_minver = configs.get("target_minver") + + -- ok? + if target_minver then return true end + + -- init the default target minimal version + configs.set("target_minver", "7.0") + + -- trace + utils.printf("checking for the target minimal version ... %s", configs.get("target_minver")) + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, cross, names, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- done + local toolpath = nil + local toolchains = configs.get("toolchains") + for _, name in ipairs(utils.wrap(names)) do + + -- attempt to get it from the given cross toolchains + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to run it directly + if not toolpath then + toolpath = tools.probe(cross .. name) + end + + -- probe ok? + if toolpath then + + -- update config + configs.set(kind, toolpath) + + -- end + break + end + + end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- done + if not prober._probe_toolpath(configs, "cc", "xcrun -sdk iphoneos ", "clang", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", "xcrun -sdk iphoneos ", {"clang++", "clang"}, "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "mm", "xcrun -sdk iphoneos ", "clang", "the objc compiler") then return false end + if not prober._probe_toolpath(configs, "mxx", "xcrun -sdk iphoneos ", {"clang++", "clang"}, "the objc++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", xmake._CORE_DIR .. "/tools/gas-preprocessor.pl xcrun -sdk iphoneos ", "clang", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", "xcrun -sdk iphoneos ", {"clang++", "clang"}, "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", "xcrun -sdk iphoneos ", "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", "xcrun -sdk iphoneos ", {"clang++", "clang"}, "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", "xcrun -sdk iphoneos ", "swiftc", "the swift compiler") then return false end + if not prober._probe_toolpath(configs, "lipo", "xcrun -sdk iphoneos ", "lipo", "the universal files creater") then return false end + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_xcode + , prober._probe_xcode_sdkver + , prober._probe_target_minver + , prober._probe_make + , prober._probe_ccache + , prober._probe_toolchains} + , nil + , config) + +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_xcode + , prober._probe_make + , prober._probe_ccache} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/iphonesimulator/iphonesimulator.lua b/xmake/core/platform/iphonesimulator/iphonesimulator.lua new file mode 100644 index 000000000..4ceeb3eca --- /dev/null +++ b/xmake/core/platform/iphonesimulator/iphonesimulator.lua @@ -0,0 +1,138 @@ +--!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 iphonesimulator.lua +-- + +-- define module: iphonesimulator +local iphonesimulator = iphonesimulator or {} + +-- load modules +local config = require("base/config") + +-- init host +iphonesimulator._HOST = "macosx" + +-- init os +iphonesimulator._OS = "ios" + +-- init architectures +iphonesimulator._ARCHS = {"i386", "x86_64"} + +-- make configure +function iphonesimulator.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".dylib"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.mm = config.get("mm") + configs.tools.mxx = config.get("mxx") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + + -- init target minimal version + local target_minver = config.get("target_minver") + assert(target_minver) + + -- init flags for architecture + local archflags = nil + local arch = config.get("arch") + if arch then archflags = "-arch " .. arch end + configs.cxflags = { archflags, "-mios-simulator-version-min=" .. target_minver } + configs.mxflags = { archflags, "-mios-simulator-version-min=" .. target_minver } + configs.asflags = { archflags, "-mios-simulator-version-min=" .. target_minver } + configs.ldflags = { archflags, "-Xlinker -objc_abi_version", "-Xlinker 2 -stdlib=libc++", "-Xlinker -no_implicit_dylibs", "-fobjc-link-runtime", "-mios-simulator-version-min=" .. target_minver } + configs.shflags = { archflags, "-Xlinker -objc_abi_version", "-Xlinker 2 -stdlib=libc++", "-Xlinker -no_implicit_dylibs", "-fobjc-link-runtime", "-mios-simulator-version-min=" .. target_minver } + if arch then + configs.scflags = { string.format("-target %s-apple-ios%s", arch, target_minver) } + end + + -- init flags for the xcode sdk directory + local xcode_dir = config.get("xcode_dir") + local xcode_sdkver = config.get("xcode_sdkver") + if xcode_dir and xcode_sdkver then + + -- init flags + local xcode_sdkdir = xcode_dir .. "/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" .. xcode_sdkver .. ".sdk" + table.insert(configs.cxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.asflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.mxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.ldflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.shflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.scflags, "-sdk " .. xcode_sdkdir) + + -- save swift link directory + config.set("__swift_linkdirs", xcode_dir .. "/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator") + end +end + +-- get the option menu for action: xmake config or global +function iphonesimulator.menu(action) + + -- init config option menu + iphonesimulator._MENU_CONFIG = iphonesimulator._MENU_CONFIG or + { {} + , {nil, "mm", "kv", nil, "The Objc Compiler" } + , {nil, "mxx", "kv", nil, "The Objc++ Compiler" } + , {nil, "mflags", "kv", nil, "The Objc Compiler Flags" } + , {nil, "mxflags", "kv", nil, "The Objc/c++ Compiler Flags" } + , {nil, "mxxflags", "kv", nil, "The Objc++ Compiler Flags" } + , {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {nil, "xcode_sdkver", "kv", "auto", "The SDK Version for Xcode" } + , {nil, "target_minver", "kv", "auto", "The Target Minimal Version" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- init global option menu + iphonesimulator._MENU_GLOBAL = iphonesimulator._MENU_GLOBAL or + { {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- get the option menu + if action == "config" then + return iphonesimulator._MENU_CONFIG + elseif action == "global" then + return iphonesimulator._MENU_GLOBAL + end +end + + +-- return module: iphonesimulator +return iphonesimulator diff --git a/xmake/core/platform/iphonesimulator/prober.lua b/xmake/core/platform/iphonesimulator/prober.lua new file mode 100644 index 000000000..a4c69c72a --- /dev/null +++ b/xmake/core/platform/iphonesimulator/prober.lua @@ -0,0 +1,308 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", "x86_64") + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the xcode application directory +function prober._probe_xcode(configs) + + -- get the xcode directory + local xcode_dir = configs.get("xcode_dir") + + -- ok? + if xcode_dir then return true end + + -- clear it first + xcode_dir = nil + + -- attempt to get the default directory + if not xcode_dir then + if os.isdir("/Applications/Xcode.app") then + xcode_dir = "/Applications/Xcode.app" + end + end + + -- attempt to match the other directories + if not xcode_dir then + local dirs = os.match("/Applications/Xcode*.app", true) + if dirs and table.getn(dirs) ~= 0 then + xcode_dir = dirs[1] + end + end + + -- probe ok? update it + if xcode_dir then + -- save it + configs.set("xcode_dir", xcode_dir) + + -- trace + utils.printf("checking for the Xcode application directory ... %s", xcode_dir) + else + -- failed + utils.error("checking for the Xcode application directory ... no") + utils.error(" - xmake config --xcode_dir=xxx") + utils.error("or - xmake global --xcode_dir=xxx") + return false + end + + -- ok + return true +end + +-- probe the xcode sdk version +function prober._probe_xcode_sdkver(configs) + + -- get the xcode sdk version + local xcode_sdkver = configs.get("xcode_sdkver") + + -- ok? + if xcode_sdkver then return true end + + -- clear it first + xcode_sdkver = nil + + -- attempt to match the directory + if not xcode_sdkver then + local dirs = os.match(configs.get("xcode_dir") .. "/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator*.sdk", true) + if dirs then + for _, dir in ipairs(dirs) do + xcode_sdkver = string.match(dir, "%d+%.%d+") + if xcode_sdkver then break end + end + end + end + + -- probe ok? update it + if xcode_sdkver then + + -- save it + configs.set("xcode_sdkver", xcode_sdkver) + + -- trace + utils.printf("checking for the Xcode SDK version for %s ... %s", configs.get("plat"), xcode_sdkver) + else + -- failed + utils.error("checking for the Xcode SDK version for %s ... no", configs.get("plat")) + utils.error(" - xmake config --xcode_sdkver=xxx") + utils.error("or - xmake global --xcode_sdkver=xxx") + return false + end + + -- ok + return true +end + +-- probe the target minimal version +function prober._probe_target_minver(configs) + + -- get the target minimal version + local target_minver = configs.get("target_minver") + + -- ok? + if target_minver then return true end + + -- init the default target minimal version + configs.set("target_minver", "7.0") + + -- trace + utils.printf("checking for the target minimal version ... %s", configs.get("target_minver")) + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, cross, names, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- done + local toolpath = nil + local toolchains = configs.get("toolchains") + for _, name in ipairs(utils.wrap(names)) do + + -- attempt to get it from the given cross toolchains + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to run it directly + if not toolpath then + toolpath = tools.probe(cross .. name) + end + + -- probe ok? + if toolpath then + + -- update config + configs.set(kind, toolpath) + + -- end + break + end + + end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- done + if not prober._probe_toolpath(configs, "cc", "xcrun -sdk iphonesimulator ", "clang", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", "xcrun -sdk iphonesimulator ", {"clang++", "clang"}, "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "mm", "xcrun -sdk iphonesimulator ", "clang", "the objc compiler") then return false end + if not prober._probe_toolpath(configs, "mxx", "xcrun -sdk iphonesimulator ", {"clang++", "clang"}, "the objc++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", "xcrun -sdk iphonesimulator ", "clang", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", "xcrun -sdk iphonesimulator ", {"clang++", "clang"}, "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", "xcrun -sdk iphonesimulator ", "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", "xcrun -sdk iphonesimulator ", {"clang++", "clang"}, "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", "xcrun -sdk iphonesimulator ", "swiftc", "the swift compiler") then return false end + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_xcode + , prober._probe_xcode_sdkver + , prober._probe_target_minver + , prober._probe_make + , prober._probe_ccache + , prober._probe_toolchains} + , nil + , config) +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_xcode + , prober._probe_make + , prober._probe_ccache} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/linux/install.lua b/xmake/core/platform/linux/install.lua new file mode 100644 index 000000000..870cf5040 --- /dev/null +++ b/xmake/core/platform/linux/install.lua @@ -0,0 +1,182 @@ +--!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 install.lua +-- + +-- define module: install +local install = install or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local rule = require("base/rule") +local utils = require("base/utils") +local string = require("base/string") +local platform = require("platform/platform") + +-- install target for the library file +function install._done_library(target) + + -- check + assert(target and target.name and target.archs) + + -- the output directory + local outputdir = target.outputdir or "/usr/local" + assert(outputdir) + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- make the library directory + local librarydir = outputdir .. "/lib" + if not os.isdir(librarydir) then + if not os.mkdir(librarydir) then + utils.error("create directory %s failed", librarydir) + return -1 + end + end + + -- copy the library file to the library directory + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.targetfile), string.format("%s/%s", librarydir, path.filename(info.targetfile))) + if not ok then + utils.error(errors) + return -1 + end + + -- make the include directory + local includedir = outputdir .. "/include" + if not os.isdir(includedir) then + if not os.mkdir(includedir) then + utils.error("create directory %s failed", includedir) + return -1 + end + end + + -- copy the config.h to the output directory + if info.config_h then + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.config_h), string.format("%s/%s/%s", includedir, target.name, path.filename(info.config_h))) + if not ok then + utils.error(errors) + return -1 + end + + -- update the config.h + info.config_h = string.format("%s/%s/%s", includedir, target.name, path.filename(info.config_h)) + end + + -- copy headers + if target.headers then + local srcheaders, dstheaders = rule.headerfiles(target, includedir) + if srcheaders and dstheaders then + local i = 1 + for _, srcheader in ipairs(srcheaders) do + local dstheader = dstheaders[i] + if dstheader then + local ok, errors = os.cp(srcheader, dstheader) + if not ok then + utils.error(errors) + return -1 + end + end + i = i + 1 + end + end + + -- update the headers + target.headers = dstheaders + end + + -- update the target directory and file + info.targetdir = librarydir + info.targetfile = path.filename(info.targetfile) + + -- ok + return 1 +end + +-- install target for the binary file +function install._done_binary(target) + + -- check + assert(target and target.archs) + + -- the output directory + local outputdir = target.outputdir or "/usr/local" + assert(outputdir) + + -- make the binary directory + local binarydir = outputdir .. "/bin" + if not os.isdir(binarydir) then + if not os.mkdir(binarydir) then + utils.error("create directory %s failed", binarydir) + return -1 + end + end + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- copy the binary file to the binary directory + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.targetfile), binarydir) + if not ok then + utils.error(errors) + return -1 + end + + -- update the target directory and file + info.targetdir = binarydir + info.targetfile = path.filename(info.targetfile) + + -- ok + return 1 +end + +-- install target +function install.main(target) + + -- check + assert(target and target.kind) + + -- the install scripts + local installscripts = + { + static = install._done_library + , shared = install._done_library + , binary = install._done_binary + } + + -- install it + local installscript = installscripts[target.kind] + if installscript then return installscript(target) end + + -- continue + return 0 +end + +-- return module: install +return install diff --git a/xmake/core/platform/linux/linux.lua b/xmake/core/platform/linux/linux.lua new file mode 100644 index 000000000..406dc5c58 --- /dev/null +++ b/xmake/core/platform/linux/linux.lua @@ -0,0 +1,103 @@ +--!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 linux.lua +-- + +-- define module: linux +local linux = linux or {} + +-- load modules +local config = require("base/config") + +-- init host +linux._HOST = "linux" + +-- init os +linux._OS = "linux" + +-- init architectures +linux._ARCHS = {"i386", "x86_64"} + +-- make configure +function linux.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".so"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.mm = config.get("mm") + configs.tools.mxx = config.get("mxx") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + + -- cross toolchains? + if config.get("cross") then return end + + -- init flags for architecture + local archflags = nil + local arch = config.get("arch") + if arch then + if arch == "x86_64" then archflags = "-m64" + elseif arch == "i386" then archflags = "-m32" + else archflags = "-arch " .. arch + end + end + configs.cxflags = { archflags } + configs.mxflags = { archflags } + configs.asflags = { archflags } + configs.ldflags = { archflags } + configs.shflags = { archflags } + + -- init linkdirs and includedirs + configs.linkdirs = {"/usr/lib", "/usr/local/lib"} + configs.includedirs = {"/usr/include", "/usr/local/include"} + +end + +-- get the option menu for action: xmake config or global +function linux.menu(action) + + -- init config option menu + linux._MENU_CONFIG = linux._MENU_CONFIG or {} + + -- init global option menu + linux._MENU_GLOBAL = linux._MENU_GLOBAL or {} + + -- get the option menu + if action == "config" then + return linux._MENU_CONFIG + elseif action == "global" then + return linux._MENU_GLOBAL + end +end + +-- return module: linux +return linux diff --git a/xmake/core/platform/linux/prober.lua b/xmake/core/platform/linux/prober.lua new file mode 100644 index 000000000..4e50b13cf --- /dev/null +++ b/xmake/core/platform/linux/prober.lua @@ -0,0 +1,198 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + if configs.get("cross") then + configs.set("arch", "none") + else + configs.set("arch", xmake._ARCH) + end + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, cross, names, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- done + local toolpath = nil + local toolchains = configs.get("toolchains") + for _, name in ipairs(utils.wrap(names)) do + + -- attempt to get it from the given cross toolchains + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to run it directly + if not toolpath then + toolpath = tools.probe(cross .. name) + end + + -- probe ok? + if toolpath then + + -- update config + configs.set(kind, toolpath) + + -- end + break + end + + end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- done + if not prober._probe_toolpath(configs, "cc", "", "gcc", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", "", {"g++", "gcc"}, "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", "", "gcc", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", "", {"g++", "gcc"}, "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", "", "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", "", {"g++", "gcc"}, "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", "", "swiftc", "the swift compiler") then return false end + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_make + , prober._probe_ccache + , prober._probe_toolchains} + , nil + , config) +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_make + , prober._probe_ccache} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/linux/uninstall.lua b/xmake/core/platform/linux/uninstall.lua new file mode 100644 index 000000000..468692620 --- /dev/null +++ b/xmake/core/platform/linux/uninstall.lua @@ -0,0 +1,134 @@ +--!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 uninstall.lua +-- + +-- define module: uninstall +local uninstall = uninstall or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local rule = require("base/rule") +local utils = require("base/utils") +local string = require("base/string") +local platform = require("platform/platform") + +-- uninstall target for the library file +function uninstall._done_library(target) + + -- check + assert(target and target.name and target.archs) + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- remove the target file + local targetfile = info.targetdir .. "/" .. info.targetfile + if os.isfile(targetfile) then + local ok, errors = os.rm(targetfile) + if not ok then + utils.error(errors) + return -1 + end + end + + -- remove config.h + if info.config_h and os.isfile(info.config_h) then + local ok, errors = os.rm(info.config_h) + if not ok then + utils.error(errors) + return -1 + end + end + + -- remove headers + if target.headers then + for _, header in ipairs(target.headers) do + if os.isfile(header) then + local ok, errors = os.rm(header) + if not ok then + utils.error(errors) + return -1 + end + end + end + end + + -- ok + return 1 +end + +-- uninstall target for the binary file +function uninstall._done_binary(target) + + -- check + assert(target and target.archs) + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- the target file + local targetfile = info.targetdir .. "/" .. info.targetfile + if not os.isfile(targetfile) then return 1 end + + -- remove the target file + local ok, errors = os.rm(targetfile) + if not ok then + utils.error(errors) + return -1 + end + + -- ok + return 1 +end + +-- uninstall target +function uninstall.main(target) + + -- check + assert(target and target.kind) + + -- the uninstall scripts + local uninstallscripts = + { + static = uninstall._done_library + , shared = uninstall._done_library + , binary = uninstall._done_binary + } + + -- uninstall it + local uninstallscript = uninstallscripts[target.kind] + if uninstallscript then return uninstallscript(target) end + + -- continue + return 0 +end + +-- return module: uninstall +return uninstall diff --git a/xmake/core/platform/macosx/install.lua b/xmake/core/platform/macosx/install.lua new file mode 100644 index 000000000..870cf5040 --- /dev/null +++ b/xmake/core/platform/macosx/install.lua @@ -0,0 +1,182 @@ +--!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 install.lua +-- + +-- define module: install +local install = install or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local rule = require("base/rule") +local utils = require("base/utils") +local string = require("base/string") +local platform = require("platform/platform") + +-- install target for the library file +function install._done_library(target) + + -- check + assert(target and target.name and target.archs) + + -- the output directory + local outputdir = target.outputdir or "/usr/local" + assert(outputdir) + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- make the library directory + local librarydir = outputdir .. "/lib" + if not os.isdir(librarydir) then + if not os.mkdir(librarydir) then + utils.error("create directory %s failed", librarydir) + return -1 + end + end + + -- copy the library file to the library directory + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.targetfile), string.format("%s/%s", librarydir, path.filename(info.targetfile))) + if not ok then + utils.error(errors) + return -1 + end + + -- make the include directory + local includedir = outputdir .. "/include" + if not os.isdir(includedir) then + if not os.mkdir(includedir) then + utils.error("create directory %s failed", includedir) + return -1 + end + end + + -- copy the config.h to the output directory + if info.config_h then + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.config_h), string.format("%s/%s/%s", includedir, target.name, path.filename(info.config_h))) + if not ok then + utils.error(errors) + return -1 + end + + -- update the config.h + info.config_h = string.format("%s/%s/%s", includedir, target.name, path.filename(info.config_h)) + end + + -- copy headers + if target.headers then + local srcheaders, dstheaders = rule.headerfiles(target, includedir) + if srcheaders and dstheaders then + local i = 1 + for _, srcheader in ipairs(srcheaders) do + local dstheader = dstheaders[i] + if dstheader then + local ok, errors = os.cp(srcheader, dstheader) + if not ok then + utils.error(errors) + return -1 + end + end + i = i + 1 + end + end + + -- update the headers + target.headers = dstheaders + end + + -- update the target directory and file + info.targetdir = librarydir + info.targetfile = path.filename(info.targetfile) + + -- ok + return 1 +end + +-- install target for the binary file +function install._done_binary(target) + + -- check + assert(target and target.archs) + + -- the output directory + local outputdir = target.outputdir or "/usr/local" + assert(outputdir) + + -- make the binary directory + local binarydir = outputdir .. "/bin" + if not os.isdir(binarydir) then + if not os.mkdir(binarydir) then + utils.error("create directory %s failed", binarydir) + return -1 + end + end + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- copy the binary file to the binary directory + local ok, errors = os.cp(string.format("%s/%s", info.targetdir, info.targetfile), binarydir) + if not ok then + utils.error(errors) + return -1 + end + + -- update the target directory and file + info.targetdir = binarydir + info.targetfile = path.filename(info.targetfile) + + -- ok + return 1 +end + +-- install target +function install.main(target) + + -- check + assert(target and target.kind) + + -- the install scripts + local installscripts = + { + static = install._done_library + , shared = install._done_library + , binary = install._done_binary + } + + -- install it + local installscript = installscripts[target.kind] + if installscript then return installscript(target) end + + -- continue + return 0 +end + +-- return module: install +return install diff --git a/xmake/core/platform/macosx/macosx.lua b/xmake/core/platform/macosx/macosx.lua new file mode 100644 index 000000000..088a01c18 --- /dev/null +++ b/xmake/core/platform/macosx/macosx.lua @@ -0,0 +1,140 @@ +--!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 macosx.lua +-- + +-- define module: macosx +local macosx = macosx or {} + +-- load modules +local config = require("base/config") + +-- init host +macosx._HOST = "macosx" + +-- init os +macosx._OS = "macosx" + +-- init architectures +macosx._ARCHS = {"i386", "x86_64"} + +-- make configure +function macosx.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".dylib"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.mm = config.get("mm") + configs.tools.mxx = config.get("mxx") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + + -- init target minimal version + local target_minver = config.get("target_minver") + assert(target_minver) + + -- init flags for architecture + local archflags = nil + local arch = config.get("arch") + if arch then archflags = "-arch " .. arch end + configs.cxflags = { archflags, "-fpascal-strings", "-fmessage-length=0" } + configs.mxflags = { archflags, "-fpascal-strings", "-fmessage-length=0" } + configs.asflags = { archflags } + configs.ldflags = { archflags, "-mmacosx-version-min=" .. target_minver, "-stdlib=libc++", "-lz" } + configs.shflags = { archflags, "-mmacosx-version-min=" .. target_minver, "-stdlib=libc++", "-lz" } + if arch then + configs.scflags = { string.format("-target %s-apple-macosx%s", arch, target_minver) } + end + + -- init flags for the xcode sdk directory + local xcode_dir = config.get("xcode_dir") + local xcode_sdkver = config.get("xcode_sdkver") + if xcode_dir and xcode_sdkver then + + -- init flags + local xcode_sdkdir = xcode_dir .. "/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX" .. xcode_sdkver .. ".sdk" + table.insert(configs.cxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.asflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.mxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.ldflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.shflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.scflags, "-sdk " .. xcode_sdkdir) + + -- save swift link directory + config.set("__swift_linkdirs", xcode_dir .. "/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx") + end + + -- init linkdirs + configs.linkdirs = {"/usr/lib", "/usr/local/lib"} + + -- init includedirs + -- + -- @note + -- cannot use configs.includedirs because the swift/objc compiler will compile code failed + table.insert(configs.cxflags, "-I/usr/include") + table.insert(configs.cxflags, "-I/usr/local/include") + +end + +-- get the option menu for action: xmake config or global +function macosx.menu(action) + + -- init config option menu + macosx._MENU_CONFIG = macosx._MENU_CONFIG or + { {} + , {nil, "mm", "kv", nil, "The Objc Compiler" } + , {nil, "mxx", "kv", nil, "The Objc++ Compiler" } + , {nil, "mflags", "kv", nil, "The Objc Compiler Flags" } + , {nil, "mxflags", "kv", nil, "The Objc/c++ Compiler Flags" } + , {nil, "mxxflags", "kv", nil, "The Objc++ Compiler Flags" } + , {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {nil, "xcode_sdkver", "kv", "auto", "The SDK Version for Xcode" } + , {nil, "target_minver", "kv", "auto", "The Target Minimal Version" } + , } + + -- init global option menu + macosx._MENU_GLOBAL = macosx._MENU_GLOBAL or + { {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , } + + -- get the option menu + if action == "config" then + return macosx._MENU_CONFIG + elseif action == "global" then + return macosx._MENU_GLOBAL + end +end + +-- return module: macosx +return macosx diff --git a/xmake/core/platform/macosx/prober.lua b/xmake/core/platform/macosx/prober.lua new file mode 100644 index 000000000..e2571fdd9 --- /dev/null +++ b/xmake/core/platform/macosx/prober.lua @@ -0,0 +1,307 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", xmake._ARCH) + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the xcode application directory +function prober._probe_xcode(configs) + + -- get the xcode directory + local xcode_dir = configs.get("xcode_dir") + + -- ok? + if xcode_dir then return true end + + -- clear it first + xcode_dir = nil + + -- attempt to get the default directory + if not xcode_dir then + if os.isdir("/Applications/Xcode.app") then + xcode_dir = "/Applications/Xcode.app" + end + end + + -- attempt to match the other directories + if not xcode_dir then + local dirs = os.match("/Applications/Xcode*.app", true) + if dirs and table.getn(dirs) ~= 0 then + xcode_dir = dirs[1] + end + end + + -- probe ok? update it + if xcode_dir then + -- save it + configs.set("xcode_dir", xcode_dir) + + -- trace + utils.printf("checking for the Xcode application directory ... %s", xcode_dir) + else + -- failed + utils.error("checking for the Xcode application directory ... no") + utils.error(" - xmake config --xcode_dir=xxx") + utils.error("or - xmake global --xcode_dir=xxx") + return false + end + + -- ok + return true +end + +-- probe the xcode sdk version +function prober._probe_xcode_sdkver(configs) + + -- get the xcode sdk version + local xcode_sdkver = configs.get("xcode_sdkver") + + -- ok? + if xcode_sdkver then return true end + + -- clear it first + xcode_sdkver = nil + + -- attempt to match the directory + if not xcode_sdkver then + local dirs = os.match(configs.get("xcode_dir") .. "/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk", true) + if dirs then + for _, dir in ipairs(dirs) do + xcode_sdkver = string.match(dir, "%d+%.%d+") + if xcode_sdkver then break end + end + end + end + + -- probe ok? update it + if xcode_sdkver then + + -- save it + configs.set("xcode_sdkver", xcode_sdkver) + + -- trace + utils.printf("checking for the Xcode SDK version for %s ... %s", configs.get("plat"), xcode_sdkver) + else + -- failed + utils.error("checking for the Xcode SDK version for %s ... no", configs.get("plat")) + utils.error(" - xmake config --xcode_sdkver=xxx") + utils.error("or - xmake global --xcode_sdkver=xxx") + return false + end + + -- ok + return true +end + +-- probe the target minimal version +function prober._probe_target_minver(configs) + + -- get the target minimal version + local target_minver = configs.get("target_minver") + + -- ok? + if target_minver then return true end + + -- init the default target minimal version + configs.set("target_minver", "10.9") + + -- trace + utils.printf("checking for the target minimal version ... %s", configs.get("target_minver")) + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, cross, names, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- done + local toolpath = nil + local toolchains = configs.get("toolchains") + for _, name in ipairs(utils.wrap(names)) do + + -- attempt to get it from the given cross toolchains + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to run it directly + if not toolpath then + toolpath = tools.probe(cross .. name) + end + + -- probe ok? + if toolpath then + + -- update config + configs.set(kind, toolpath) + + -- end + break + end + + end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- done + if not prober._probe_toolpath(configs, "cc", "xcrun -sdk macosx ", "clang", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", "xcrun -sdk macosx ", {"clang++", "clang"}, "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "mm", "xcrun -sdk macosx ", "clang", "the objc compiler") then return false end + if not prober._probe_toolpath(configs, "mxx", "xcrun -sdk macosx ", {"clang++", "clang"}, "the objc++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", "xcrun -sdk macosx ", "clang", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", "xcrun -sdk macosx ", {"clang++", "clang"}, "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", "xcrun -sdk macosx ", "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", "xcrun -sdk macosx ", {"clang++", "clang"}, "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", "xcrun -sdk macosx ", "swiftc", "the swift compiler") then return false end + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_xcode + , prober._probe_xcode_sdkver + , prober._probe_target_minver + , prober._probe_make + , prober._probe_ccache + , prober._probe_toolchains} + , nil + , config) +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_xcode + , prober._probe_ccache} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/macosx/uninstall.lua b/xmake/core/platform/macosx/uninstall.lua new file mode 100644 index 000000000..468692620 --- /dev/null +++ b/xmake/core/platform/macosx/uninstall.lua @@ -0,0 +1,134 @@ +--!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 uninstall.lua +-- + +-- define module: uninstall +local uninstall = uninstall or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local rule = require("base/rule") +local utils = require("base/utils") +local string = require("base/string") +local platform = require("platform/platform") + +-- uninstall target for the library file +function uninstall._done_library(target) + + -- check + assert(target and target.name and target.archs) + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- remove the target file + local targetfile = info.targetdir .. "/" .. info.targetfile + if os.isfile(targetfile) then + local ok, errors = os.rm(targetfile) + if not ok then + utils.error(errors) + return -1 + end + end + + -- remove config.h + if info.config_h and os.isfile(info.config_h) then + local ok, errors = os.rm(info.config_h) + if not ok then + utils.error(errors) + return -1 + end + end + + -- remove headers + if target.headers then + for _, header in ipairs(target.headers) do + if os.isfile(header) then + local ok, errors = os.rm(header) + if not ok then + utils.error(errors) + return -1 + end + end + end + end + + -- ok + return 1 +end + +-- uninstall target for the binary file +function uninstall._done_binary(target) + + -- check + assert(target and target.archs) + + -- get target info + local info = target.archs[xmake._ARCH] or target.archs["x86_64"] or target.archs["i386"] + if not info then return -1 end + + -- check + assert(info.targetdir and info.targetfile) + + -- the target file + local targetfile = info.targetdir .. "/" .. info.targetfile + if not os.isfile(targetfile) then return 1 end + + -- remove the target file + local ok, errors = os.rm(targetfile) + if not ok then + utils.error(errors) + return -1 + end + + -- ok + return 1 +end + +-- uninstall target +function uninstall.main(target) + + -- check + assert(target and target.kind) + + -- the uninstall scripts + local uninstallscripts = + { + static = uninstall._done_library + , shared = uninstall._done_library + , binary = uninstall._done_binary + } + + -- uninstall it + local uninstallscript = uninstallscripts[target.kind] + if uninstallscript then return uninstallscript(target) end + + -- continue + return 0 +end + +-- return module: uninstall +return uninstall diff --git a/xmake/core/platform/mingw/mingw.lua b/xmake/core/platform/mingw/mingw.lua new file mode 100644 index 000000000..7264489b2 --- /dev/null +++ b/xmake/core/platform/mingw/mingw.lua @@ -0,0 +1,93 @@ +--!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 mingw.lua +-- + +-- define module: mingw +local mingw = mingw or {} + +-- load modules +local config = require("base/config") + +-- init host +mingw._HOST = xmake._HOST + +-- init os +mingw._OS = "windows" + +-- init architectures +mingw._ARCHS = {"i386", "x86_64"} + +-- make configure +function mingw.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".so"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + + -- init flags for architecture + local archflags = nil + local arch = config.get("arch") + if arch then + if arch == "x86_64" then archflags = "-m64" + elseif arch == "i386" then archflags = "-m32" + else archflags = "-arch " .. arch + end + end + configs.cxflags = { archflags } + configs.asflags = { archflags } + configs.ldflags = { archflags } + configs.shflags = { archflags } + +end + +-- get the option menu for action: xmake config or global +function mingw.menu(action) + + -- init config option menu + mingw._MENU_CONFIG = mingw._MENU_CONFIG or {} + + -- init global option menu + mingw._MENU_GLOBAL = mingw._MENU_GLOBAL or {} + + -- get the option menu + if action == "config" then + return mingw._MENU_CONFIG + elseif action == "global" then + return mingw._MENU_GLOBAL + end +end + +-- return module: mingw +return mingw diff --git a/xmake/core/platform/mingw/prober.lua b/xmake/core/platform/mingw/prober.lua new file mode 100644 index 000000000..575e3a7ba --- /dev/null +++ b/xmake/core/platform/mingw/prober.lua @@ -0,0 +1,207 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", "i386") + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, cross, names, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- done + local toolpath = nil + local toolchains = configs.get("toolchains") + for _, name in ipairs(utils.wrap(names)) do + + -- attempt to get it from the given cross toolchains + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to run it directly + if not toolpath then + toolpath = tools.probe(cross .. name) + end + + -- probe ok? + if toolpath then + + -- update config + configs.set(kind, toolpath) + + -- end + break + end + + end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- init the default cross from the current host and architecture + local cross = "" + local arch = configs.get("arch") + if arch then + if xmake._HOST == "macosx" and arch == "i386" then + cross = "i386-mingw32-" + elseif arch == "i386" then + cross = "i686-w64-mingw32-" + elseif arch == "x86_64" then + cross = "x86_64-w64-mingw32-" + end + end + + -- done + if not prober._probe_toolpath(configs, "cc", cross, "gcc", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", cross, {"g++", "gcc"}, "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", cross, "gcc", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", cross, {"g++", "gcc"}, "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", cross, "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", cross, {"g++", "gcc"}, "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", cross, "swiftc", "the swift compiler") then return false end + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_make + , prober._probe_ccache + , prober._probe_toolchains} + , nil + , config) +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_make + , prober._probe_ccache} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/platform.lua b/xmake/core/platform/platform.lua new file mode 100644 index 000000000..2fc411cbf --- /dev/null +++ b/xmake/core/platform/platform.lua @@ -0,0 +1,385 @@ +--!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 platform.lua +-- + +-- define module: platform +local platform = platform or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local config = require("base/config") +local global = require("base/global") + +-- load prober the given platform directory +function platform._load_prober(root) + + -- the platform file path + local filepath = string.format("%s/prober.lua", root) + if os.isfile(filepath) then + + -- load script + local script = loadfile(filepath) + if script then + + -- load prober + local prober = script() + if prober then + + -- ok + return prober + end + end + end +end + +-- load the given platform from the given root directory +function platform._load_from(root, plat) + + -- the platform file path + local filepath = string.format("%s/platform/%s/%s.lua", root, plat, plat) + if os.isfile(filepath) then + + -- load script + local script = loadfile(filepath) + if script then + + -- load module + local module = script() + if module then + + -- save directory + module._DIRECTORY = path.directory(filepath) + assert(module._DIRECTORY) + + -- attempt to load prober + module._PROBER = platform._load_prober(module._DIRECTORY) + + -- ok + return module + end + end + end +end + +-- load the given platform +function platform._load(plat) + + -- the module + platform._MODULES = platform._MODULES or {} + local module = platform._MODULES[plat] + + -- return it directory if ok + if module then return module end + + -- attempt to load it from the project configure directory + if not module then module = platform._load_from(config.directory(), plat) end + + -- attempt to load it from the global configure directory + if not module then module = platform._load_from(global.directory(), plat) end + + -- attempt to load it from the script directory + if not module then module = platform._load_from(xmake._CORE_DIR, plat) end + + -- cache it if ok + if module then + platform._MODULES[plat] = module + end + + -- ok? + return module +end + +-- get the configure of the given platform +function platform._configs(plat) + + -- the configure + platform._CONFIGS = platform._CONFIGS or {} + local configs = platform._CONFIGS[plat] + + -- return it directly if exists + if configs then + return configs + end + + -- load platform + local module = platform._load(plat) + if module then + + -- init configure + platform._CONFIGS[plat]= {} + configs = platform._CONFIGS[plat] + + -- make configure + module.make(configs) + end + + -- ok? + return configs +end + +-- get the current platform module +function platform.module() + + -- load it + return platform._load(config.get("plat")) +end + +-- get the current platform module directory +function platform.directory() + + -- load it + local module = platform.module() + if module then + return module._DIRECTORY + end +end + +-- make the current platform configure +function platform.make() + + -- get the platform + local plat = config.get("plat") + assert(plat) + + -- make and get the current platform configure + return platform._configs(plat) +end + +-- get the platform os +function platform.os() + + -- get module + local module = platform.module() + if not module then return end + + -- ok? + return module._OS +end + +-- get the given configure +function platform.get(name) + + -- check + assert(platform._CONFIGS) + + -- get the current platform configure + local configs = platform._configs(config.get("plat")) + if configs then + -- get it + return configs[name] + end +end + +-- get the given tool +function platform.tool(name) + + -- check + assert(name) + + -- get tools + local tools = platform.get("tools") + if tools then + return tools[name] + end + +end + +-- get the given format +function platform.format(kind) + + -- check + assert(kind) + + -- get formats + local formats = platform.get("formats") + if formats then + return formats[kind] + end + +end + +-- dump the platform configure +function platform.dump() + + -- check + assert(platform._CONFIGS) + + -- dump + if xmake._OPTIONS.verbose then + utils.dump(platform._configs(config.get("plat"))) + end + +end + +-- list all platforms +function platform.plats() + + -- return it directly if exists + if platform._PLATS then + return platform._PLATS + end + + -- make list + local list = {} + + -- get the platform list from the project configure directory + local plats = os.match(config.directory() .. "/platform/*", true) + if plats then + for _, v in ipairs(plats) do + table.insert(list, path.basename(v)) + end + end + + -- get the platform list from the global configure directory + plats = os.match(global.directory() .. "/platform/*", true) + if plats then + for _, v in ipairs(plats) do + table.insert(list, path.basename(v)) + end + end + + -- get the platform list from the script directory + plats = os.match(xmake._CORE_DIR .. "/platform/*", true) + if plats then + for _, v in ipairs(plats) do + table.insert(list, path.basename(v)) + end + end + + -- save it + platform._PLATS = list + + -- ok + return list +end + +-- list all architectures +function platform.archs(plat) + + -- check + assert(plat) + + -- load all platform configs + local archs = {} + local module = platform._load(plat) + if module and module._ARCHS then + for _, arch in ipairs(module._ARCHS) do + table.insert(archs, arch) + end + end + + -- ok + return archs +end + +-- get the option menu for action: xmake config or global +function platform.menu(action) + + -- check + assert(action) + + -- get all platforms + local plats = platform.plats() + assert(plats) + + -- load and merge all platform menus + local menus = {} + local exist = {} + for _, plat in ipairs(plats) do + + -- load platform + local module = platform._load(plat) + if module and module.menu then + + -- get the platform menu + local menu = module.menu(action) + if menu then + + -- exists options? + local exists = false + for _, option in ipairs(menu) do + local name = option[2] + if name and not exist[name] then + exists = true + break + end + end + + -- merge it and remove repeat if exists options + if exists then + -- get the platform menu option + for _, option in ipairs(menu) do + + -- merge it and remove repeat + local name = option[2] + if name then + if not exist[name] then + table.insert(menus, option) + exist[name] = true + end + else + table.insert(menus, option) + end + end + end + end + end + end + + -- get all platform menus + return menus +end + +-- probe the platform configure +function platform.probe(is_global) + + -- probe global + if is_global then + + -- get all platforms + local plats = platform.plats() + assert(plats) + + -- probe all platforms with the current host + for _, plat in ipairs(plats) do + local module = platform._load(plat) + if module and module._PROBER and module._PROBER.global and module._HOST and module._HOST == xmake._HOST then + if not module._PROBER.global() then return false end + end + end + + -- probe config + else + -- probe it + local module = platform.module() + if module and module._PROBER and module._PROBER.config then + if not module._PROBER.config() then return false end + end + end + + -- ok + return true +end + +-- return module: platform +return platform diff --git a/xmake/core/platform/watchos/package.lua b/xmake/core/platform/watchos/package.lua new file mode 100644 index 000000000..1e46ddadc --- /dev/null +++ b/xmake/core/platform/watchos/package.lua @@ -0,0 +1,76 @@ +--!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 package.lua +-- + +-- define module: package +local package = package or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local rule = require("base/rule") +local utils = require("base/utils") +local string = require("base/string") +local platform = require("platform/platform") + +-- package target +function package.main(target) + + -- check + assert(target and target.name) + + -- the count of architectures + local count = 0 + for _, _ in pairs(target.archs) do count = count + 1 end + if count < 2 then return 0 end + + -- get the lipo tool + local lipo = platform.tool("lipo") + if not lipo then return 0 end + + -- make universal info + local universal = {} + universal.targetdir = rule.backupdir(target.name, "universal") + universal.targetfile = rule.targetfile(target.name, target) + if not universal.targetdir or not universal.targetfile then return 0 end + + -- make the universal directory + os.mkdir(path.directory(string.format("%s/%s", universal.targetdir, universal.targetfile))) + + -- make the lipo command + local cmd = lipo .. " -create" + for arch, info in pairs(target.archs) do + cmd = string.format("%s -arch %s %s/%s", cmd, arch, info.targetdir, info.targetfile) + end + cmd = string.format("%s -output %s/%s", cmd, universal.targetdir, universal.targetfile) + + -- make the universal target + if 0 ~= os.execute(cmd) then return 0 end + + -- ok + target.archs.universal = universal + + -- continue + return 0 +end + +-- return module: package +return package diff --git a/xmake/core/platform/watchos/prober.lua b/xmake/core/platform/watchos/prober.lua new file mode 100644 index 000000000..1a818dfdf --- /dev/null +++ b/xmake/core/platform/watchos/prober.lua @@ -0,0 +1,310 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", "armv7") + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the xcode application directory +function prober._probe_xcode(configs) + + -- get the xcode directory + local xcode_dir = configs.get("xcode_dir") + + -- ok? + if xcode_dir then return true end + + -- clear it first + xcode_dir = nil + + -- attempt to get the default directory + if not xcode_dir then + if os.isdir("/Applications/Xcode.app") then + xcode_dir = "/Applications/Xcode.app" + end + end + + -- attempt to match the other directories + if not xcode_dir then + local dirs = os.match("/Applications/Xcode*.app", true) + if dirs and table.getn(dirs) ~= 0 then + xcode_dir = dirs[1] + end + end + + -- probe ok? update it + if xcode_dir then + -- save it + configs.set("xcode_dir", xcode_dir) + + -- trace + utils.printf("checking for the Xcode application directory ... %s", xcode_dir) + else + -- failed + utils.error("checking for the Xcode application directory ... no") + utils.error(" - xmake config --xcode_dir=xxx") + utils.error("or - xmake global --xcode_dir=xxx") + return false + end + + -- ok + return true +end + +-- probe the xcode sdk version +function prober._probe_xcode_sdkver(configs) + + -- get the xcode sdk version + local xcode_sdkver = configs.get("xcode_sdkver") + + -- ok? + if xcode_sdkver then return true end + + -- clear it first + xcode_sdkver = nil + + -- attempt to match the directory + if not xcode_sdkver then + local dirs = os.match(configs.get("xcode_dir") .. "/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS*.sdk", true) + if dirs then + for _, dir in ipairs(dirs) do + xcode_sdkver = string.match(dir, "%d+%.%d+") + if xcode_sdkver then break end + end + end + end + + -- probe ok? update it + if xcode_sdkver then + + -- save it + configs.set("xcode_sdkver", xcode_sdkver) + + -- trace + utils.printf("checking for the Xcode SDK version for %s ... %s", configs.get("plat"), xcode_sdkver) + else + -- failed + utils.error("checking for the Xcode SDK version for %s ... no", configs.get("plat")) + utils.error(" - xmake config --xcode_sdkver=xxx") + utils.error("or - xmake global --xcode_sdkver=xxx") + return false + end + + -- ok + return true +end + +-- probe the target minimal version +function prober._probe_target_minver(configs) + + -- get the target minimal version + local target_minver = configs.get("target_minver") + + -- ok? + if target_minver then return true end + + -- init the default target minimal version + configs.set("target_minver", "7.0") + + -- trace + utils.printf("checking for the target minimal version ... %s", configs.get("target_minver")) + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, cross, names, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- done + local toolpath = nil + local toolchains = configs.get("toolchains") + for _, name in ipairs(utils.wrap(names)) do + + -- attempt to get it from the given cross toolchains + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to run it directly + if not toolpath then + toolpath = tools.probe(cross .. name) + end + + -- probe ok? + if toolpath then + + -- update config + configs.set(kind, toolpath) + + -- end + break + end + + end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- done + if not prober._probe_toolpath(configs, "cc", "xcrun -sdk watchos ", "clang", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", "xcrun -sdk watchos ", {"clang++", "clang"}, "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "mm", "xcrun -sdk watchos ", "clang", "the objc compiler") then return false end + if not prober._probe_toolpath(configs, "mxx", "xcrun -sdk watchos ", {"clang++", "clang"}, "the objc++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", xmake._CORE_DIR .. "/tools/gas-preprocessor.pl xcrun -sdk watchos ", "clang", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", "xcrun -sdk watchos ", {"clang++", "clang"}, "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", "xcrun -sdk watchos ", "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", "xcrun -sdk watchos ", {"clang++", "clang"}, "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", "xcrun -sdk watchos ", "swiftc", "the swift compiler") then return false end + if not prober._probe_toolpath(configs, "lipo", "xcrun -sdk watchos ", "lipo", "the universal files creater") then return false end + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_xcode + , prober._probe_xcode_sdkver + , prober._probe_target_minver + , prober._probe_make + , prober._probe_ccache + , prober._probe_toolchains} + , nil + , config) + +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_xcode + , prober._probe_make + , prober._probe_ccache} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/watchos/watchos.lua b/xmake/core/platform/watchos/watchos.lua new file mode 100644 index 000000000..9551084f8 --- /dev/null +++ b/xmake/core/platform/watchos/watchos.lua @@ -0,0 +1,141 @@ +--!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 watchos.lua +-- + +-- define module: watchos +local watchos = watchos or {} + +-- load modules +local config = require("base/config") + +-- init host +watchos._HOST = "macosx" + +-- init os +watchos._OS = "ios" + +-- init architectures +watchos._ARCHS = {"armv7", "armv7s", "arm64"} + +-- make configure +function watchos.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".dylib"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.mm = config.get("mm") + configs.tools.mxx = config.get("mxx") + configs.tools.as = config.get("as") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + configs.tools.lipo = config.get("lipo") + + -- init target minimal version + local target_minver = config.get("target_minver") + assert(target_minver) + + -- init flags for architecture + local archflags = nil + local arch = config.get("arch") + if arch then archflags = "-arch " .. arch end + configs.cxflags = { archflags, "-mwatchos-version-min=" .. target_minver } + configs.mxflags = { archflags, "-mwatchos-version-min=" .. target_minver } + configs.asflags = { archflags, "-mwatchos-version-min=" .. target_minver } + configs.ldflags = { archflags, "-ObjC", "-lstdc++", "-fobjc-link-runtime", "-mwatchos-version-min=" .. target_minver } + configs.shflags = { archflags, "-ObjC", "-lstdc++", "-fobjc-link-runtime", "-mwatchos-version-min=" .. target_minver } + if arch then + configs.scflags = { string.format("-target %s-apple-ios%s", arch, target_minver) } + end + + -- init flags for the xcode sdk directory + local xcode_dir = config.get("xcode_dir") + local xcode_sdkver = config.get("xcode_sdkver") + if xcode_dir and xcode_sdkver then + + -- init flags + local xcode_sdkdir = xcode_dir .. "/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS" .. xcode_sdkver .. ".sdk" + table.insert(configs.cxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.asflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.mxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.ldflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.shflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.scflags, "-sdk " .. xcode_sdkdir) + + -- save swift link directory + config.set("__swift_linkdirs", xcode_dir .. "/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/watchos") + end + +end + +-- get the option menu for action: xmake config or global +function watchos.menu(action) + + -- init config option menu + watchos._MENU_CONFIG = watchos._MENU_CONFIG or + { {} + , {nil, "mm", "kv", nil, "The Objc Compiler" } + , {nil, "mxx", "kv", nil, "The Objc++ Compiler" } + , {nil, "mflags", "kv", nil, "The Objc Compiler Flags" } + , {nil, "mxflags", "kv", nil, "The Objc/c++ Compiler Flags" } + , {nil, "mxxflags", "kv", nil, "The Objc++ Compiler Flags" } + , {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {nil, "xcode_sdkver", "kv", "auto", "The SDK Version for Xcode" } + , {nil, "target_minver", "kv", "auto", "The Target Minimal Version" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- init global option menu + watchos._MENU_GLOBAL = watchos._MENU_GLOBAL or + { {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- get the option menu + if action == "config" then + return watchos._MENU_CONFIG + elseif action == "global" then + return watchos._MENU_GLOBAL + end +end + + +-- return module: watchos +return watchos diff --git a/xmake/core/platform/watchsimulator/prober.lua b/xmake/core/platform/watchsimulator/prober.lua new file mode 100644 index 000000000..d33059c36 --- /dev/null +++ b/xmake/core/platform/watchsimulator/prober.lua @@ -0,0 +1,308 @@ +--!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 prober.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") +local config = require("base/config") +local global = require("base/global") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", "x86_64") + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the xcode application directory +function prober._probe_xcode(configs) + + -- get the xcode directory + local xcode_dir = configs.get("xcode_dir") + + -- ok? + if xcode_dir then return true end + + -- clear it first + xcode_dir = nil + + -- attempt to get the default directory + if not xcode_dir then + if os.isdir("/Applications/Xcode.app") then + xcode_dir = "/Applications/Xcode.app" + end + end + + -- attempt to match the other directories + if not xcode_dir then + local dirs = os.match("/Applications/Xcode*.app", true) + if dirs and table.getn(dirs) ~= 0 then + xcode_dir = dirs[1] + end + end + + -- probe ok? update it + if xcode_dir then + -- save it + configs.set("xcode_dir", xcode_dir) + + -- trace + utils.printf("checking for the Xcode application directory ... %s", xcode_dir) + else + -- failed + utils.error("checking for the Xcode application directory ... no") + utils.error(" - xmake config --xcode_dir=xxx") + utils.error("or - xmake global --xcode_dir=xxx") + return false + end + + -- ok + return true +end + +-- probe the xcode sdk version +function prober._probe_xcode_sdkver(configs) + + -- get the xcode sdk version + local xcode_sdkver = configs.get("xcode_sdkver") + + -- ok? + if xcode_sdkver then return true end + + -- clear it first + xcode_sdkver = nil + + -- attempt to match the directory + if not xcode_sdkver then + local dirs = os.match(configs.get("xcode_dir") .. "/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator*.sdk", true) + if dirs then + for _, dir in ipairs(dirs) do + xcode_sdkver = string.match(dir, "%d+%.%d+") + if xcode_sdkver then break end + end + end + end + + -- probe ok? update it + if xcode_sdkver then + + -- save it + configs.set("xcode_sdkver", xcode_sdkver) + + -- trace + utils.printf("checking for the Xcode SDK version for %s ... %s", configs.get("plat"), xcode_sdkver) + else + -- failed + utils.error("checking for the Xcode SDK version for %s ... no", configs.get("plat")) + utils.error(" - xmake config --xcode_sdkver=xxx") + utils.error("or - xmake global --xcode_sdkver=xxx") + return false + end + + -- ok + return true +end + +-- probe the target minimal version +function prober._probe_target_minver(configs) + + -- get the target minimal version + local target_minver = configs.get("target_minver") + + -- ok? + if target_minver then return true end + + -- init the default target minimal version + configs.set("target_minver", "7.0") + + -- trace + utils.printf("checking for the target minimal version ... %s", configs.get("target_minver")) + + -- ok + return true +end + +-- probe the make +function prober._probe_make(configs) + + -- ok? + local make = configs.get("make") + if make then return true end + + -- probe the make path + make = tools.probe("make", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if make then configs.set("make", make) end + + -- trace + utils.printf("checking for the make ... %s", utils.ifelse(make, make, "no")) + + -- ok + return true +end + +-- probe the ccache +function prober._probe_ccache(configs) + + -- ok? + local ccache_enable = configs.get("ccache") + if ccache_enable and configs.get("__ccache") then return true end + + -- disable? + if type(ccache_enable) == "boolean" and not ccache_enable then + configs.set("__ccache", nil) + return true + end + + -- probe the ccache path + local ccache_path = tools.probe("ccache", {"/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin"}) + + -- probe ok? update it + if ccache_path then + configs.set("ccache", true) + configs.set("__ccache", ccache_path) + else + configs.set("ccache", false) + end + + -- trace + utils.printf("checking for the ccache ... %s", utils.ifelse(ccache_path, ccache_path, "no")) + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, cross, names, description) + + -- check + assert(kind) + + -- get the cross + cross = configs.get("cross") or cross + + -- done + local toolpath = nil + local toolchains = configs.get("toolchains") + for _, name in ipairs(utils.wrap(names)) do + + -- attempt to get it from the given cross toolchains + if toolchains then + toolpath = tools.probe(cross .. (configs.get(kind) or name), toolchains) + end + + -- attempt to get it directly from the configure + if not toolpath then + toolpath = configs.get(kind) + end + + -- attempt to run it directly + if not toolpath then + toolpath = tools.probe(cross .. name) + end + + -- probe ok? + if toolpath then + + -- update config + configs.set(kind, toolpath) + + -- end + break + end + + end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- done + if not prober._probe_toolpath(configs, "cc", "xcrun -sdk watchsimulator ", "clang", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", "xcrun -sdk watchsimulator ", {"clang++", "clang"}, "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "mm", "xcrun -sdk watchsimulator ", "clang", "the objc compiler") then return false end + if not prober._probe_toolpath(configs, "mxx", "xcrun -sdk watchsimulator ", {"clang++", "clang"}, "the objc++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", "xcrun -sdk watchsimulator ", "clang", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", "xcrun -sdk watchsimulator ", {"clang++", "clang"}, "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", "xcrun -sdk watchsimulator ", "ar", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", "xcrun -sdk watchsimulator ", {"clang++", "clang"}, "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "sc", "xcrun -sdk watchsimulator ", "swiftc", "the swift compiler") then return false end + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_xcode + , prober._probe_xcode_sdkver + , prober._probe_target_minver + , prober._probe_make + , prober._probe_ccache + , prober._probe_toolchains} + , nil + , config) +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_xcode + , prober._probe_make + , prober._probe_ccache} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/watchsimulator/watchsimulator.lua b/xmake/core/platform/watchsimulator/watchsimulator.lua new file mode 100644 index 000000000..a13bfde1e --- /dev/null +++ b/xmake/core/platform/watchsimulator/watchsimulator.lua @@ -0,0 +1,138 @@ +--!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 watchsimulator.lua +-- + +-- define module: watchsimulator +local watchsimulator = watchsimulator or {} + +-- load modules +local config = require("base/config") + +-- init host +watchsimulator._HOST = "macosx" + +-- init os +watchsimulator._OS = "ios" + +-- init architectures +watchsimulator._ARCHS = {"i386", "x86_64"} + +-- make configure +function watchsimulator.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"lib", ".a"} + configs.formats.object = {"", ".o"} + configs.formats.shared = {"lib", ".dylib"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.ccache = config.get("__ccache") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.mm = config.get("mm") + configs.tools.mxx = config.get("mxx") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.ex = config.get("ar") + configs.tools.sc = config.get("sc") + + -- init target minimal version + local target_minver = config.get("target_minver") + assert(target_minver) + + -- init flags for architecture + local archflags = nil + local arch = config.get("arch") + if arch then archflags = "-arch " .. arch end + configs.cxflags = { archflags, "-mios-simulator-version-min=" .. target_minver } + configs.mxflags = { archflags, "-mios-simulator-version-min=" .. target_minver } + configs.asflags = { archflags, "-mios-simulator-version-min=" .. target_minver } + configs.ldflags = { archflags, "-Xlinker -objc_abi_version", "-Xlinker 2 -stdlib=libc++", "-Xlinker -no_implicit_dylibs", "-fobjc-link-runtime", "-mios-simulator-version-min=" .. target_minver } + configs.shflags = { archflags, "-Xlinker -objc_abi_version", "-Xlinker 2 -stdlib=libc++", "-Xlinker -no_implicit_dylibs", "-fobjc-link-runtime", "-mios-simulator-version-min=" .. target_minver } + if arch then + configs.scflags = { string.format("-target %s-apple-ios%s", arch, target_minver) } + end + + -- init flags for the xcode sdk directory + local xcode_dir = config.get("xcode_dir") + local xcode_sdkver = config.get("xcode_sdkver") + if xcode_dir and xcode_sdkver then + + -- init flags + local xcode_sdkdir = xcode_dir .. "/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator" .. xcode_sdkver .. ".sdk" + table.insert(configs.cxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.asflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.mxflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.ldflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.shflags, "-isysroot " .. xcode_sdkdir) + table.insert(configs.scflags, "-sdk " .. xcode_sdkdir) + + -- save swift link directory + config.set("__swift_linkdirs", xcode_dir .. "/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/watchsimulator") + end +end + +-- get the option menu for action: xmake config or global +function watchsimulator.menu(action) + + -- init config option menu + watchsimulator._MENU_CONFIG = watchsimulator._MENU_CONFIG or + { {} + , {nil, "mm", "kv", nil, "The Objc Compiler" } + , {nil, "mxx", "kv", nil, "The Objc++ Compiler" } + , {nil, "mflags", "kv", nil, "The Objc Compiler Flags" } + , {nil, "mxflags", "kv", nil, "The Objc/c++ Compiler Flags" } + , {nil, "mxxflags", "kv", nil, "The Objc++ Compiler Flags" } + , {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {nil, "xcode_sdkver", "kv", "auto", "The SDK Version for Xcode" } + , {nil, "target_minver", "kv", "auto", "The Target Minimal Version" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- init global option menu + watchsimulator._MENU_GLOBAL = watchsimulator._MENU_GLOBAL or + { {} + , {nil, "xcode_dir", "kv", "auto", "The Xcode Application Directory" } + , {} + , {nil, "mobileprovision","kv", "auto", "The Provisioning Profile File" } + , {nil, "codesign", "kv", "auto", "The Code Signing Indentity" } + , {nil, "entitlements", "kv", "auto", "The Code Signing Entitlements" } + , } + + -- get the option menu + if action == "config" then + return watchsimulator._MENU_CONFIG + elseif action == "global" then + return watchsimulator._MENU_GLOBAL + end +end + + +-- return module: watchsimulator +return watchsimulator diff --git a/xmake/core/platform/windows/prober.lua b/xmake/core/platform/windows/prober.lua new file mode 100644 index 000000000..40d214efd --- /dev/null +++ b/xmake/core/platform/windows/prober.lua @@ -0,0 +1,300 @@ +--!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 prober.lua +-- + +-- load modules +local io = require("base/io") +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local config = require("base/config") +local global = require("base/global") +local tools = require("tools/tools") +local platform = require("platform/platform") + +-- define module: prober +local prober = prober or {} + +-- probe the architecture +function prober._probe_arch(configs) + + -- get the architecture + local arch = configs.get("arch") + + -- ok? + if arch then return true end + + -- init the default architecture + configs.set("arch", "x86") + + -- trace + utils.printf("checking for the architecture ... %s", configs.get("arch")) + + -- ok + return true +end + +-- probe the vs version +function prober._probe_vs_version(configs) + + -- get the vs version + local vs = configs.get("vs") + + -- ok? + if vs then return true end + + -- clear it first + vs = nil + + -- make the map table + local map = + { + VS140COMNTOOLS = "2015" + , VS120COMNTOOLS = "2013" + , VS110COMNTOOLS = "2012" + , VS100COMNTOOLS = "2010" + , VS90COMNTOOLS = "2008" + , VS80COMNTOOLS = "2005" + , VS71COMNTOOLS = "2003" + , VS70COMNTOOLS = "7.0" + , VS60COMNTOOLS = "6.0" + , VS50COMNTOOLS = "5.0" + , VS42COMNTOOLS = "4.2" + } + + -- attempt to get it from the envirnoment variable + if not vs then + for k, v in pairs(map) do + if os.getenv(k) then + vs = v + break + end + end + end + + -- probe ok? update it + if vs then + -- save it + configs.set("vs", vs) + + -- trace + utils.printf("checking for the Microsoft Visual Studio version ... %s", vs) + else + -- failed + utils.error("checking for the Microsoft Visual Studio version ... no") + utils.error(" - xmake config --vs=xxx") + utils.error("or - xmake global --vs=xxx") + return false + end + + -- ok + return true +end + +-- probe the vs path +function prober._probe_vs_path(configs) + + -- ok? + if configs.get("__vsenv_path") then return true end + + -- get the vs version + local vs = configs.get("vs") + assert(vs) + + -- make the map table + local map = + { + ["2015"] = "VS140COMNTOOLS" + , ["2013"] = "VS120COMNTOOLS" + , ["2012"] = "VS110COMNTOOLS" + , ["2010"] = "VS100COMNTOOLS" + , ["2008"] = "VS90COMNTOOLS" + , ["2005"] = "VS80COMNTOOLS" + , ["2003"] = "VS71COMNTOOLS" + , ["7.0"] = "VS70COMNTOOLS" + , ["6.0"] = "VS60COMNTOOLS" + , ["5.0"] = "VS50COMNTOOLS" + , ["4.2"] = "VS42COMNTOOLS" + } + + -- attempt to get the vs directory from the envirnoment variable + local vsdir = map[vs] + if vsdir then + vsdir = os.getenv(vsdir) + end + if vsdir then + vsdir = vsdir .. "\\..\\.." + end + if not os.isdir(vsdir) then + -- error + utils.error("not found %s", vsdir) + return false + end + + -- the vcvarsall.bat path + local vcvarsall = vsdir .. "\\VC\\vcvarsall.bat" + if not os.isfile(vcvarsall) then + -- error + utils.error("not found %s", vcvarsall) + return false + end + + -- get the temporary directory + local tmpdir = os.tmpdir() + assert(tmpdir) + + -- make the call(vcvarsall.bat) file + local callpath = tmpdir .. "\\call_vcvarsall.bat" + local callfile = io.openmk(callpath) + assert(callfile) + + -- make call scripts + callfile:write("@echo off\n") + callfile:write(string.format("call \"%s\" %s > nul\n", vcvarsall, configs.get("arch"))) + callfile:write("echo return \n") + callfile:write("echo { \n") + callfile:write("echo path = \"%path%\"\n") + callfile:write("echo , lib = \"%lib%\"\n") + callfile:write("echo , libpath = \"%libpath%\"\n") + callfile:write("echo , include = \"%include%\"\n") + callfile:write("echo , devenvdir = \"%devenvdir%\"\n") + callfile:write("echo , vsinstalldir = \"%vsinstalldir%\"\n") + callfile:write("echo , vcinstalldir = \"%vcinstalldir%\"\n") + callfile:write("echo } \n") + + -- close the file + callfile:close() + + -- execute the call(vsvars32.bat) file and get all envirnoment variables + local cmd = io.popen(callpath) + local results = cmd:read("*all") + cmd:close() + + -- translate '\' => '\\' + results = results:gsub("\\", "\\\\") + + -- get all envirnoment variables + local variables = assert(loadstring(results))() + if not variables or not variables.path then + return false + end + + -- save the variables + for k, v in pairs(variables) do + configs.set("__vsenv_" .. k, v) + end + + -- ok + return true +end + +-- probe the tool path +function prober._probe_toolpath(configs, kind, name, description) + + -- check + assert(kind) + + -- attempt to get it directly from the configure + local toolpath = configs.get(kind) + if toolpath then return true end + + -- make cmd + local cmd = string.format("%s > %s 2>&1", name, xmake._NULDEV) + if kind == "ld" then + cmd = string.format("%s nul > %s 2>&1", name, xmake._NULDEV) + end + + -- attempt to run it directly first + if not toolpath and os.execute(cmd) ~= 1 then + toolpath = name + end + + -- probe ok? update it + if toolpath then configs.set(kind, toolpath) end + + -- trace + if toolpath then + utils.printf("checking for %s (%s) ... %s", description, kind, path.filename(toolpath)) + else + utils.printf("checking for %s (%s) ... no", description, kind) + end + + -- failed? + if not toolpath and (kind == "cc" or kind == "ld" or kind == "make") then + return false + end + + -- ok + return true +end + +-- probe the toolchains +function prober._probe_toolchains(configs) + + -- the windows module + local windows = platform.module() + assert(windows) + + -- enter envirnoment + windows.enter() + + -- done + if not prober._probe_toolpath(configs, "cc", "cl.exe", "the c compiler") then return false end + if not prober._probe_toolpath(configs, "cxx", "cl.exe", "the c++ compiler") then return false end + if not prober._probe_toolpath(configs, "as", "ml.exe", "the assember") then return false end + if not prober._probe_toolpath(configs, "ld", "link.exe", "the linker") then return false end + if not prober._probe_toolpath(configs, "ar", "link.exe -lib", "the static library linker") then return false end + if not prober._probe_toolpath(configs, "sh", "link.exe -dll", "the shared library linker") then return false end + if not prober._probe_toolpath(configs, "ex", "lib.exe", "the library extractor") then return false end + if not prober._probe_toolpath(configs, "make", "nmake.exe", "the make") then return false end + + -- leave envirnoment + windows.leave() + + -- ok + return true +end + +-- probe the project configure +function prober.config() + + -- call all probe functions + return utils.call( { prober._probe_arch + , prober._probe_vs_version + , prober._probe_vs_path + , prober._probe_toolchains} + , nil + , config) +end + +-- probe the global configure +function prober.global() + + -- call all probe functions + return utils.call( { prober._probe_vs_version + , prober._probe_vs_path} + , nil + , global) +end + +-- return module: prober +return prober diff --git a/xmake/core/platform/windows/tools/cl.lua b/xmake/core/platform/windows/tools/cl.lua new file mode 100644 index 000000000..299960bb8 --- /dev/null +++ b/xmake/core/platform/windows/tools/cl.lua @@ -0,0 +1,139 @@ +--!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 cl.lua +-- + +-- define module: cl +local cl = cl or {} + +-- load modules +local utils = require("base/utils") +local string = require("base/string") +local config = require("base/config") +local platform = require("platform/platform") + +-- init the compiler +function cl.init(self, name) + + -- save name + self.name = name or "cl.exe" + + -- init cxflags + self.cxflags = { "-nologo", "-Gd", "-MP4", "-D_MBCS", "-D_CRT_SECURE_NO_WARNINGS"} + + -- init flags map + self.mapflags = + { + -- optimize + ["-O0"] = "-Od" + , ["-O3"] = "-Ot" + , ["-Ofast"] = "-Ox" + , ["-fomit-frame-pointer"] = "-Oy" + + -- symbols + , ["-g"] = "-Z7" + , ["-fvisibility=.*"] = "" + + -- warnings + , ["-Wall"] = "-W3" -- = "-Wall" will enable too more warnings + , ["-W1"] = "-W1" + , ["-W2"] = "-W2" + , ["-W3"] = "-W3" + , ["-Werror"] = "-WX" + , ["%-Wno%-error=.*"] = "" + , ["%-fno%-.*"] = "" + + -- vectorexts + , ["-mmmx"] = "-arch:MMX" + , ["-msse"] = "-arch:SSE" + , ["-msse2"] = "-arch:SSE2" + , ["-msse3"] = "-arch:SSE3" + , ["-mssse3"] = "-arch:SSSE3" + , ["-mavx"] = "-arch:AVX" + , ["-mavx2"] = "-arch:AVX2" + , ["-mfpu=.*"] = "" + + -- language + , ["-ansi"] = "" + , ["-std=c99"] = "-TP" -- compile as c++ files because msvc only support c89 + , ["-std=gnu99"] = "-TP" -- compile as c++ files because msvc only support c89 + , ["-std=.*"] = "" + + -- others + , ["-ftrapv"] = "" + , ["-fsanitize=address"] = "" + } + +end + +-- make the compiler command +function cl.command_compile(self, srcfile, objfile, flags, logfile) + + -- redirect + local redirect = "" + if logfile then redirect = string.format(" > %s 2>&1", logfile) end + + -- make it + return string.format("%s -c %s -Fo%s %s%s", self.name, flags, objfile, srcfile, redirect) +end + +-- make the define flag +function cl.flag_define(self, define) + + -- make it + return "-D" .. define:gsub("\"", "\\\"") +end + +-- make the undefine flag +function cl.flag_undefine(self, undefine) + + -- make it + return "-U" .. undefine +end + +-- make the includedir flag +function cl.flag_includedir(self, includedir) + + -- make it + return "-I" .. includedir +end + +-- the main function +function cl.main(self, cmd) + + -- the windows module + local windows = platform.module() + assert(windows) + + -- enter envirnoment + windows.enter() + + -- execute it + local ok = os.execute(cmd) + + -- leave envirnoment + windows.leave() + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: cl +return cl diff --git a/xmake/core/platform/windows/tools/lib.lua b/xmake/core/platform/windows/tools/lib.lua new file mode 100644 index 000000000..1d94152cc --- /dev/null +++ b/xmake/core/platform/windows/tools/lib.lua @@ -0,0 +1,138 @@ +--!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 lib.lua +-- + +-- define module: lib +local lib = lib or {} + +-- load modules +local io = require("base/io") +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local config = require("base/config") +local platform = require("platform/platform") + +-- init the compiler +function lib.init(self, name) + + -- save name + self.name = name or "lib.exe" + +end + +-- extract the static library to object files +function lib.extract(self, ...) + + -- check + local args = ... + assert(#args == 2 and self.name) + + -- get library and object file path + local libfile = args[1] + local objfile = args[2] + assert(libfile and objfile) + + -- get object directory + local objdir = path.directory(objfile) + if not os.isdir(objdir) then os.mkdir(objdir) end + if not os.isdir(objdir) then + utils.error("%s not found!", objdir) + return false + end + + -- the windows module + local windows = platform.module() + assert(windows) + + -- enter envirnoment + windows.enter() + + -- list object files + local file = io.popen(string.format("%s -nologo -list %s", self.name, libfile)) + if not file then + utils.error("extract %s to %s failed!", libfile, objdir) + windows.leave() + return false + end + + -- extrace all object files + for line in file:lines() do + + -- is object file? + if line:find("%.obj") then + + -- init command + local out = path.translate(string.format("%s\\%s", objdir, path.filename(line))) + + -- repeat? rename it + if os.isfile(out) then + for i = 0, 10 do + out = path.translate(string.format("%s\\%d_%s", objdir, i, path.filename(line))) + if not os.isfile(out) then break end + end + end + + -- init command + local cmd = string.format("%s -nologo -extract:%s -out:%s %s", self.name, line, out, libfile) + + -- extract it + if 0 ~= os.execute(cmd) then + utils.error("extract %s to %s failed!", libfile, objdir) + windows.leave() + return false + end + end + end + + -- exit file + file:close() + + -- leave envirnoment + windows.leave() + + -- ok + return true +end + +-- the main function +function lib.main(self, cmd) + + -- the windows module + local windows = platform.module() + assert(windows) + + -- enter envirnoment + windows.enter() + + -- execute it + local ok = os.execute(cmd) + + -- leave envirnoment + windows.leave() + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: lib +return lib diff --git a/xmake/core/platform/windows/tools/link.lua b/xmake/core/platform/windows/tools/link.lua new file mode 100644 index 000000000..66476fa41 --- /dev/null +++ b/xmake/core/platform/windows/tools/link.lua @@ -0,0 +1,128 @@ +--!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 link.lua +-- + +-- define module: link +local link = link or {} + +-- load modules +local utils = require("base/utils") +local string = require("base/string") +local config = require("base/config") +local platform = require("platform/platform") + +-- init the compiler +function link.init(self, name) + + -- save name + self.name = name or "link.exe" + + -- the architecture + local arch = config.get("arch") + assert(arch) + + -- init flags for architecture + local flags_arch = "" + if arch == "x86" then flags_arch = "-machine:x86" + elseif arch == "x64" or arch == "amd64" or arch == "x86_amd64" then flags_arch = "-machine:x64" + end + + -- init ldflags + self.ldflags = { "-nologo" + , "-dynamicbase" + , "-nxcompat" + , flags_arch} + + -- init arflags + self.arflags = {"-nologo", flags_arch} + + -- init shflags + self.shflags = {"-nologo", flags_arch} + + -- init flags map + self.mapflags = + { + -- strip + ["-s"] = "" + , ["-S"] = "" + + -- others + , ["-ftrapv"] = "" + , ["-fsanitize=address"] = "" + } + +end + +-- make the linker command +function link.command_link(self, objfiles, targetfile, flags, logfile) + + -- redirect + local redirect = "" + if logfile then redirect = string.format(" > %s 2>&1", logfile) end + + -- make it + local cmd = string.format("%s %s -out:%s %s%s", self.name, flags, targetfile, objfiles, redirect) + + -- too long? + if #cmd > 256 then + cmd = string.format("%s%s @<<\n%s -out:%s %s\n<<", self.name, redirect, flags, targetfile, objfiles) + end + + -- ok? + return cmd +end + +-- make the link flag +function link.flag_link(self, link) + + -- make it + return link .. ".lib" +end + +-- make the linkdir flag +function link.flag_linkdir(self, linkdir) + + -- make it + return "-libpath:" .. linkdir +end + +-- the main function +function link.main(self, cmd) + + -- the windows module + local windows = platform.module() + assert(windows) + + -- enter envirnoment + windows.enter() + + -- execute it + local ok = os.execute(cmd) + + -- leave envirnoment + windows.leave() + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: link +return link diff --git a/xmake/core/platform/windows/tools/ml.lua b/xmake/core/platform/windows/tools/ml.lua new file mode 100644 index 000000000..5a6034320 --- /dev/null +++ b/xmake/core/platform/windows/tools/ml.lua @@ -0,0 +1,132 @@ +--!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 ml.lua +-- + +-- define module: ml +local ml = ml or {} + +-- load modules +local utils = require("base/utils") +local string = require("base/string") +local config = require("base/config") +local platform = require("platform/platform") + +-- init the compiler +function ml.init(self, name) + + -- save name + self.name = name or "ml.exe" + + -- init asflags + self.asflags = { "-nologo", "-Gd", "-MP4", "-D_MBCS", "-D_CRT_SECURE_NO_WARNINGS"} + + -- init flags map + self.mapflags = + { + -- optimize + ["-O0"] = "-Od" + , ["-O3"] = "-Ot" + , ["-Ofast"] = "-Ox" + , ["-fomit-frame-pointer"] = "-Oy" + + -- symbols + , ["-g"] = "-Z7" + , ["-fvisibility=.*"] = "" + + -- warnings + , ["-Wall"] = "-W3" -- = "-Wall" will enable too more warnings + , ["-W1"] = "-W1" + , ["-W2"] = "-W2" + , ["-W3"] = "-W3" + , ["-Werror"] = "-WX" + , ["%-Wno%-error=.*"] = "" + + -- vectorexts + , ["-mmmx"] = "-arch:MMX" + , ["-msse"] = "-arch:SSE" + , ["-msse2"] = "-arch:SSE2" + , ["-msse3"] = "-arch:SSE3" + , ["-mssse3"] = "-arch:SSSE3" + , ["-mavx"] = "-arch:AVX" + , ["-mavx2"] = "-arch:AVX2" + , ["-mfpu=.*"] = "" + + -- others + , ["-ftrapv"] = "" + , ["-fsanitize=address"] = "" + } + +end + +-- make the compiler command +function ml.command_compile(self, srcfile, objfile, flags, logfile) + + -- redirect + local redirect = "" + if logfile then redirect = string.format(" > %s 2>&1", logfile) end + + -- make it + return string.format("%s -c %s -Fo%s %s%s", self.name, flags, objfile, srcfile, redirect) +end + +-- make the define flag +function ml.flag_define(self, define) + + -- make it + return "-D" .. define:gsub("\"", "\\\"") +end + +-- make the undefine flag +function ml.flag_undefine(self, undefine) + + -- make it + return "-U" .. undefine +end + +-- make the includedir flag +function ml.flag_includedir(self, includedir) + + -- make it + return "-I" .. includedir +end + +-- the main function +function ml.main(self, cmd) + + -- the windows module + local windows = platform.module() + assert(windows) + + -- enter envirnoment + windows.enter() + + -- execute it + local ok = os.execute(cmd) + + -- leave envirnoment + windows.leave() + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: ml +return ml diff --git a/xmake/core/platform/windows/tools/nmake.lua b/xmake/core/platform/windows/tools/nmake.lua new file mode 100644 index 000000000..3dddc7cf2 --- /dev/null +++ b/xmake/core/platform/windows/tools/nmake.lua @@ -0,0 +1,74 @@ +--!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 nmake.lua +-- + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local config = require("base/config") +local platform = require("platform/platform") + +-- define module: nmake +local nmake = nmake or {} + +-- the init function +function nmake.init(self, name) + + -- save name + self.name = name or "nmake.exe" + + -- is verbose? + self._VERBOSE = utils.ifelse(xmake._OPTIONS.verbose, "-v", "") + +end + +-- the main function +function nmake.main(self, mkfile, target) + + -- the windows module + local windows = platform.module() + assert(windows) + + -- enter envirnoment + windows.enter() + + -- make command + local cmd = nil + if mkfile and os.isfile(mkfile) then + cmd = string.format("%s /nologo /f %s %s VERBOSE=%s", self.name, mkfile, target or "", self._VERBOSE) + else + cmd = string.format("%s /nologo %s VERBOSE=%s", self.name, target or "", self._VERBOSE) + end + + -- done + local ok = os.execute(cmd) + + -- leave envirnoment + windows.leave() + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: nmake +return nmake diff --git a/xmake/core/platform/windows/windows.lua b/xmake/core/platform/windows/windows.lua new file mode 100644 index 000000000..794358dc1 --- /dev/null +++ b/xmake/core/platform/windows/windows.lua @@ -0,0 +1,144 @@ +--!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 windows.lua +-- + +-- define module: windows +local windows = windows or {} + +-- load modules +local os = require("base/os") +local config = require("base/config") + +-- init host +windows._HOST = "windows" + +-- init os +windows._OS = "windows" + +-- init architectures +windows._ARCHS = {"x86", "x64", "amd64", "x86_amd64"} + +-- enter the given environment +function windows._enter(name) + + -- check + assert(name) + + -- get the pathes for the vs environment + local old = nil + local new = config.get("__vsenv_" .. name) + if new then + + -- get the current pathes + old = os.getenv(name) or "" + + -- append the current pathes + new = new .. ";" .. old + + -- update the pathes for the environment + os.setenv(name, new) + end + + -- return the previous environment + return old; +end + +-- leave the given environment +function windows._leave(name, old) + + -- check + assert(name) + + -- restore the previous environment + if old then + os.setenv(name, old) + end +end + +-- enter environment +function windows.enter() + + -- enter the vs environment + windows._pathes = windows._enter("path") + windows._libs = windows._enter("lib") + windows._includes = windows._enter("include") + windows._libpathes = windows._enter("libpath") + +end + +-- leave environment +function windows.leave() + + -- leave the vs environment + windows._leave("path", windows._pathes) + windows._leave("lib", windows._libs) + windows._leave("include", windows._includes) + windows._leave("libpath", windows._libpathes) + +end +-- make configure +function windows.make(configs) + + -- init the file formats + configs.formats = {} + configs.formats.static = {"", ".lib"} + configs.formats.object = {"", ".obj"} + configs.formats.shared = {"", ".dll"} + configs.formats.binary = {"", ".exe"} + + -- init the toolchains + configs.tools = {} + configs.tools.make = config.get("make") + configs.tools.cc = config.get("cc") + configs.tools.cxx = config.get("cxx") + configs.tools.ld = config.get("ld") + configs.tools.ar = config.get("ar") + configs.tools.sh = config.get("sh") + configs.tools.as = config.get("as") + configs.tools.ex = config.get("ex") +end + +-- get the option menu for action: xmake config or global +function windows.menu(action) + + -- init config option menu + windows._MENU_CONFIG = windows._MENU_CONFIG or + { {} + , {nil, "vs", "kv", "auto", "The Microsoft Visual Studio" } + , } + + -- init global option menu + windows._MENU_GLOBAL = windows._MENU_GLOBAL or + { {} + , {nil, "vs", "kv", "auto", "The Microsoft Visual Studio" } + , } + + -- get the option menu + if action == "config" then + return windows._MENU_CONFIG + elseif action == "global" then + return windows._MENU_GLOBAL + end +end + + +-- return module: windows +return windows diff --git a/xmake/core/tools/ar.lua b/xmake/core/tools/ar.lua new file mode 100644 index 000000000..75e63f83d --- /dev/null +++ b/xmake/core/tools/ar.lua @@ -0,0 +1,114 @@ +--!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 ar.lua +-- + +-- define module: ar +local ar = ar or {} + +-- load modules +local utils = require("base/utils") +local string = require("base/string") +local config = require("base/config") + +-- init the linker +function ar.init(self, name) + + -- save name + self.name = name or "ar" + + -- init arflags + self.arflags = { "-crs" } + +end + +-- make the link command +function ar.command_link(self, objfiles, targetfile, flags, logfile) + + -- redirect + local redirect = "" + if logfile then redirect = string.format(" > %s 2>&1", logfile) end + + -- make it + return string.format("%s %s %s %s%s", self.name, flags, targetfile, objfiles, redirect) +end + +-- extract the static library to object files +function ar.extract(self, ...) + + -- check + local args = ... + assert(#args == 2 and self.name) + + -- get library and object file path + local libfile = args[1] + local objfile = args[2] + assert(libfile and objfile) + + -- get object directory + local objdir = path.directory(objfile) + if not os.isdir(objdir) then os.mkdir(objdir) end + if not os.isdir(objdir) then + utils.error("%s not found!", objdir) + return false + end + + -- absolute the library path + libfile = path.absolute(libfile) + assert(libfile) + + -- enter the object directory + ok, errors = os.cd(objdir) + if not ok then + utils.error(errors) + return false + end + + -- extract it + local ok = self:main(string.format("%s -x %s", self.name, libfile)) + if not ok then + utils.error("extract %s to %s failed!", libfile, objdir) + return false + end + + -- leave the object directory + ok, errors = os.cd("-") + if not ok then + utils.error(errors) + return false + end + + -- ok + return true +end + + +-- the main function +function ar.main(self, cmd) + + -- execute it + local ok = os.execute(cmd) + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: ar +return ar diff --git a/xmake/core/tools/cat.lua b/xmake/core/tools/cat.lua new file mode 100644 index 000000000..32fea4e24 --- /dev/null +++ b/xmake/core/tools/cat.lua @@ -0,0 +1,43 @@ +--!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 cat.lua +-- + +-- define module: cat +local cat = cat or {} + +-- load modules +local io = require("base/io") +local os = require("base/os") + +-- the main function +function cat.main(self, ...) + + -- cat all + for _, v in ipairs(...) do + if os.isfile(v) then io.cat(v) end + end + + -- ok + return true +end + +-- return module: cat +return cat diff --git a/xmake/core/tools/clang++.lua b/xmake/core/tools/clang++.lua new file mode 100644 index 000000000..37352dec4 --- /dev/null +++ b/xmake/core/tools/clang++.lua @@ -0,0 +1,38 @@ +--!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 clang.lua +-- + +-- load modules +local gcc = require("tools/gcc") + +-- define module: clang++ +local clangxx = clangxx or {} + +-- only copy the interfaces of gcc to clang++ +for k, v in pairs(gcc) do + if type(v) == "function" then + clangxx[k] = v + end +end + +-- return module: clang++ +return clangxx + diff --git a/xmake/core/tools/clang.lua b/xmake/core/tools/clang.lua new file mode 100644 index 000000000..280ae73a6 --- /dev/null +++ b/xmake/core/tools/clang.lua @@ -0,0 +1,38 @@ +--!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 clang.lua +-- + +-- load modules +local gcc = require("tools/gcc") + +-- define module: clang +local clang = clang or {} + +-- only copy the interfaces of gcc to clang +for k, v in pairs(gcc) do + if type(v) == "function" then + clang[k] = v + end +end + +-- return module: clang +return clang + diff --git a/xmake/core/tools/cp.lua b/xmake/core/tools/cp.lua new file mode 100644 index 000000000..1b3ba9843 --- /dev/null +++ b/xmake/core/tools/cp.lua @@ -0,0 +1,44 @@ +--!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 cp.lua +-- + +-- define module: cp +local cp = cp or {} + +-- load modules +local os = require("base/os") + +-- the main function +function cp.main(self, ...) + + -- cp it + local pathes = ... + if pathes and table.getn(pathes) == 2 then + return os.cp(pathes[1], pathes[2]) + end + + -- failed + return false + +end + +-- return module: cp +return cp diff --git a/xmake/core/tools/dispatcher.lua b/xmake/core/tools/dispatcher.lua new file mode 100644 index 000000000..d019937ec --- /dev/null +++ b/xmake/core/tools/dispatcher.lua @@ -0,0 +1,80 @@ +--!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 dispatcher.lua +-- + +-- define module: dispatcher +local dispatcher = dispatcher or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local tools = require("tools/tools") + +-- the main function +-- +-- dispatcher toolname toolpath action arguments ... +function dispatcher.main(self, ...) + + -- check + local args = ... + assert(#args >= 2) + + -- get tool kind and action name + local tool_kind = args[1] + local action_name = args[2] + assert(tool_kind and action_name) + + -- get the tool + local tool = tools.get(tool_kind) + if tool then + + -- load action + local action = tool[action_name] + if action then + + -- init arguments for action + local action_args = {} + for i = 3, #args do + table.insert(action_args, args[i]:decode()) + end + + -- done action + if not action(tool, action_args) then + utils.error("run action %s failed!", action_name) + assert(false) + end + else + utils.error("load action %s failed!", action_name) + assert(false) + end + + else + assert(false) + end + + -- ok + return true +end + +-- return module: dispatcher +return dispatcher diff --git a/xmake/core/tools/echo.lua b/xmake/core/tools/echo.lua new file mode 100644 index 000000000..dbfa67426 --- /dev/null +++ b/xmake/core/tools/echo.lua @@ -0,0 +1,44 @@ +--!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 echo.lua +-- + +-- define module: echo +local echo = echo or {} + +-- load modules +local io = require("base/io") +local string = require("base/string") + +-- the main function +function echo.main(self, ...) + + -- echo all + for _, v in ipairs(...) do + io.write(string.format("%s ", v:decode())) + end + io.write("\n") + + -- ok + return true +end + +-- return module: echo +return echo diff --git a/xmake/core/tools/g++.lua b/xmake/core/tools/g++.lua new file mode 100644 index 000000000..64970b039 --- /dev/null +++ b/xmake/core/tools/g++.lua @@ -0,0 +1,38 @@ +--!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 g++.lua +-- + +-- load modules +local gcc = require("tools/gcc") + +-- define module: gxx +local gxx = gxx or {} + +-- only copy the interfaces of gcc to g++ +for k, v in pairs(gcc) do + if type(v) == "function" then + gxx[k] = v + end +end + +-- return module: g++ +return gxx + diff --git a/xmake/core/tools/gas-preprocessor.pl b/xmake/core/tools/gas-preprocessor.pl new file mode 100755 index 000000000..98dfe4ad9 --- /dev/null +++ b/xmake/core/tools/gas-preprocessor.pl @@ -0,0 +1,1025 @@ +#!/usr/bin/env perl +# by David Conrad +# This code is licensed under GPLv2 or later; go to gnu.org to read it +# (not that it much matters for an asm preprocessor) +# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc" +use strict; + +# Apple's gas is ancient and doesn't support modern preprocessing features like +# .rept and has ugly macro syntax, among other things. Thus, this script +# implements the subset of the gas preprocessor used by x264 and ffmpeg +# that isn't supported by Apple's gas. + +my %canonical_arch = ("aarch64" => "aarch64", "arm64" => "aarch64", + "arm" => "arm", + "powerpc" => "powerpc", "ppc" => "powerpc"); + +my %comments = ("aarch64" => '//', + "arm" => '@', + "powerpc" => '#'); + +my @gcc_cmd; +my @preprocess_c_cmd; + +my $comm; +my $arch; +my $as_type = "apple-gas"; + +my $fix_unreq = $^O eq "darwin"; +my $force_thumb = 0; + +my $arm_cond_codes = "eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo"; + +my $usage_str = " +$0\n +Gas-preprocessor.pl converts assembler files using modern GNU as syntax for +Apple's ancient gas version or clang's incompatible integrated assembler. The +conversion is regularly tested for Libav, x264 and vlc. Other projects might +use different features which are not correctly handled. + +Options for this program needs to be separated with ' -- ' from the assembler +command. Following options are currently supported: + + -help - this usage text + -arch - target architecture + -as-type - one value out of {{,apple-}{gas,clang},armasm} + -fix-unreq + -no-fix-unreq + -force-thumb - assemble as thumb regardless of the input source + (note, this is incomplete and only works for sources + it explicitly was tested with) +"; + +sub usage() { + print $usage_str; +} + +while (@ARGV) { + my $opt = shift; + + if ($opt =~ /^-(no-)?fix-unreq$/) { + $fix_unreq = $1 ne "no-"; + } elsif ($opt eq "-force-thumb") { + $force_thumb = 1; + } elsif ($opt eq "-arch") { + $arch = shift; + die "unknown arch: '$arch'\n" if not exists $comments{$arch}; + } elsif ($opt eq "-as-type") { + $as_type = shift; + die "unknown as type: '$as_type'\n" if $as_type !~ /^((apple-)?(gas|clang)|armasm)$/; + } elsif ($opt eq "-help") { + usage(); + exit 0; + } elsif ($opt eq "--" ) { + @gcc_cmd = @ARGV; + } elsif ($opt =~ /^-/) { + die "option '$opt' is not known. See '$0 -help' for usage information\n"; + } else { + push @gcc_cmd, $opt, @ARGV; + } + last if (@gcc_cmd); +} + +if (grep /\.c$/, @gcc_cmd) { + # C file (inline asm?) - compile + @preprocess_c_cmd = (@gcc_cmd, "-S"); +} elsif (grep /\.[sS]$/, @gcc_cmd) { + # asm file, just do C preprocessor + @preprocess_c_cmd = (@gcc_cmd, "-E"); +} elsif (grep /-(v|-version|dumpversion)/, @gcc_cmd) { + # pass -v/--version along, used during probing. Matching '-v' might have + # uninteded results but it doesn't matter much if gas-preprocessor or + # the compiler fails. + exec(@gcc_cmd); +} else { + die "Unrecognized input filetype"; +} +if ($as_type eq "armasm") { + + $preprocess_c_cmd[0] = "cpp"; + + @preprocess_c_cmd = grep ! /^-nologo$/, @preprocess_c_cmd; + # Remove -ignore XX parameter pairs from preprocess_c_cmd + my $index = 1; + while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-ignore" and $index + 1 < $#preprocess_c_cmd) { + splice(@preprocess_c_cmd, $index, 2); + next; + } + $index++; + } + if (grep /^-MM$/, @preprocess_c_cmd) { + system(@preprocess_c_cmd) == 0 or die "Error running preprocessor"; + exit 0; + } +} + +# if compiling, avoid creating an output file named '-.o' +if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { + foreach my $i (@gcc_cmd) { + if ($i =~ /\.[csS]$/) { + my $outputfile = $i; + $outputfile =~ s/\.[csS]$/.o/; + push(@gcc_cmd, "-o"); + push(@gcc_cmd, $outputfile); + last; + } + } +} +# replace only the '-o' argument with '-', avoids rewriting the make dependency +# target specified with -MT to '-' +my $index = 1; +while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-o") { + $index++; + $preprocess_c_cmd[$index] = "-"; + } + $index++; +} + +my $tempfile; +if ($as_type ne "armasm") { + @gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; +} else { + @preprocess_c_cmd = grep ! /^-c$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-m/, @preprocess_c_cmd; + + @preprocess_c_cmd = grep ! /^-G/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-W/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-Z/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-fp/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-EHsc$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-O/, @preprocess_c_cmd; + + @gcc_cmd = grep ! /^-G/, @gcc_cmd; + @gcc_cmd = grep ! /^-W/, @gcc_cmd; + @gcc_cmd = grep ! /^-Z/, @gcc_cmd; + @gcc_cmd = grep ! /^-fp/, @gcc_cmd; + @gcc_cmd = grep ! /^-EHsc$/, @gcc_cmd; + @gcc_cmd = grep ! /^-O/, @gcc_cmd; + + my @outfiles = grep /\.(o|obj)$/, @gcc_cmd; + $tempfile = $outfiles[0].".asm"; + + # Remove most parameters from gcc_cmd, which actually is the armasm command, + # which doesn't support any of the common compiler/preprocessor options. + @gcc_cmd = grep ! /^-D/, @gcc_cmd; + @gcc_cmd = grep ! /^-U/, @gcc_cmd; + @gcc_cmd = grep ! /^-m/, @gcc_cmd; + @gcc_cmd = grep ! /^-M/, @gcc_cmd; + @gcc_cmd = grep ! /^-c$/, @gcc_cmd; + @gcc_cmd = grep ! /^-I/, @gcc_cmd; + @gcc_cmd = map { /\.S$/ ? $tempfile : $_ } @gcc_cmd; +} + +# detect architecture from gcc binary name +if (!$arch) { + if ($gcc_cmd[0] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } else { + # look for -arch flag + foreach my $i (1 .. $#gcc_cmd-1) { + if ($gcc_cmd[$i] eq "-arch" and + $gcc_cmd[$i+1] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } + } + } +} + +# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name +$arch = qx/arch/ if (!$arch); + +die "Unknown target architecture '$arch'" if not exists $canonical_arch{$arch}; + +$arch = $canonical_arch{$arch}; +$comm = $comments{$arch}; +my $inputcomm = $comm; +$comm = ";" if $as_type =~ /armasm/; + +my %ppc_spr = (ctr => 9, + vrsave => 256); + +open(INPUT, "-|", @preprocess_c_cmd) || die "Error running preprocessor"; + +if ($ENV{GASPP_DEBUG}) { + open(ASMFILE, ">&STDOUT"); +} else { + if ($as_type ne "armasm") { + open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; + } else { + open(ASMFILE, ">", $tempfile); + } +} + +my $current_macro = ''; +my $macro_level = 0; +my $rept_level = 0; +my %macro_lines; +my %macro_args; +my %macro_args_default; +my $macro_count = 0; +my $altmacro = 0; +my $in_irp = 0; + +my $num_repts; +my @rept_lines; + +my @irp_args; +my $irp_param; + +my @ifstack; + +my %symbols; + +my @sections; + +my %literal_labels; # for ldr <reg>, =<expr> +my $literal_num = 0; +my $literal_expr = ".word"; +$literal_expr = ".quad" if $arch eq "aarch64"; + +my $thumb = 0; + +my %thumb_labels; +my %call_targets; +my %mov32_targets; + +my %neon_alias_reg; +my %neon_alias_type; + +my $temp_label_next = 0; +my %last_temp_labels; +my %next_temp_labels; + +my %labels_seen; + +my %aarch64_req_alias; + +if ($force_thumb) { + parse_line(".thumb\n"); +} + +# pass 1: parse .macro +# note that the handling of arguments is probably overly permissive vs. gas +# but it should be the same for valid cases +while (<INPUT>) { + # remove all comments (to avoid interfering with evaluating directives) + s/(?<!\\)$inputcomm.*//x; + # Strip out windows linefeeds + s/\r$//; + # Strip out line number comments - armasm can handle them in a separate + # syntax, but since the line numbers are off they are only misleading. + s/^#\s+(\d+).*// if $as_type =~ /armasm/; + + parse_line($_); +} + +sub eval_expr { + my $expr = $_[0]; + while ($expr =~ /([A-Za-z._][A-Za-z0-9._]*)/g) { + my $sym = $1; + $expr =~ s/$sym/($symbols{$sym})/ if defined $symbols{$sym}; + } + eval $expr; +} + +sub handle_if { + my $line = $_[0]; + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if ($line =~ /\.if(n?)([a-z]*)\s+(.*)/) { + my $result = $1 eq "n"; + my $type = $2; + my $expr = $3; + + if ($type eq "b") { + $expr =~ s/\s//g; + $result ^= $expr eq ""; + } elsif ($type eq "c") { + if ($expr =~ /(.*)\s*,\s*(.*)/) { + $result ^= $1 eq $2; + } else { + die "argument to .ifc not recognized"; + } + } elsif ($type eq "") { + $result ^= eval_expr($expr) != 0; + } elsif ($type eq "eq") { + $result = eval_expr($expr) == 0; + } elsif ($type eq "lt") { + $result = eval_expr($expr) < 0; + } else { + chomp($line); + die "unhandled .if varient. \"$line\""; + } + push (@ifstack, $result); + return 1; + } else { + return 0; + } +} + +sub parse_if_line { + my $line = $_[0]; + + # evaluate .if blocks + if (scalar(@ifstack)) { + # Don't evaluate any new if statements if we're within + # a repetition or macro - they will be evaluated once + # the repetition is unrolled or the macro is expanded. + if (scalar(@rept_lines) == 0 and $macro_level == 0) { + if ($line =~ /\.endif/) { + pop(@ifstack); + return 1; + } elsif ($line =~ /\.elseif\s+(.*)/) { + if ($ifstack[-1] == 0) { + $ifstack[-1] = !!eval_expr($1); + } elsif ($ifstack[-1] > 0) { + $ifstack[-1] = -$ifstack[-1]; + } + return 1; + } elsif ($line =~ /\.else/) { + $ifstack[-1] = !$ifstack[-1]; + return 1; + } elsif (handle_if($line)) { + return 1; + } + } + + # discard lines in false .if blocks + foreach my $i (0 .. $#ifstack) { + if ($ifstack[$i] <= 0) { + return 1; + } + } + } + return 0; +} + +sub parse_line { + my $line = $_[0]; + + return if (parse_if_line($line)); + + if (scalar(@rept_lines) == 0) { + if (/\.macro/) { + $macro_level++; + if ($macro_level > 1 && !$current_macro) { + die "nested macros but we don't have master macro"; + } + } elsif (/\.endm/) { + $macro_level--; + if ($macro_level < 0) { + die "unmatched .endm"; + } elsif ($macro_level == 0) { + $current_macro = ''; + return; + } + } + } + + if ($macro_level == 0) { + if ($line =~ /\.(rept|irp)/) { + $rept_level++; + } elsif ($line =~ /.endr/) { + $rept_level--; + } + } + + if ($macro_level > 1) { + push(@{$macro_lines{$current_macro}}, $line); + } elsif (scalar(@rept_lines) and $rept_level >= 1) { + push(@rept_lines, $line); + } elsif ($macro_level == 0) { + expand_macros($line); + } else { + if ($line =~ /\.macro\s+([\d\w\.]+)\s*(.*)/) { + $current_macro = $1; + + # commas in the argument list are optional, so only use whitespace as the separator + my $arglist = $2; + $arglist =~ s/,/ /g; + + my @args = split(/\s+/, $arglist); + foreach my $i (0 .. $#args) { + my @argpair = split(/=/, $args[$i]); + $macro_args{$current_macro}[$i] = $argpair[0]; + $argpair[0] =~ s/:vararg$//; + $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1]; + } + # ensure %macro_lines has the macro name added as a key + $macro_lines{$current_macro} = []; + + } elsif ($current_macro) { + push(@{$macro_lines{$current_macro}}, $line); + } else { + die "macro level without a macro name"; + } + } +} + +sub handle_set { + my $line = $_[0]; + if ($line =~ /\.set\s+(.*),\s*(.*)/) { + $symbols{$1} = eval_expr($2); + return 1; + } + return 0; +} + +sub expand_macros { + my $line = $_[0]; + + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if (handle_if($line)) { + return; + } + + if (/\.purgem\s+([\d\w\.]+)/) { + delete $macro_lines{$1}; + delete $macro_args{$1}; + delete $macro_args_default{$1}; + return; + } + + if ($line =~ /\.altmacro/) { + $altmacro = 1; + return; + } + + if ($line =~ /\.noaltmacro/) { + $altmacro = 0; + return; + } + + $line =~ s/\%([^,]*)/eval_expr($1)/eg if $altmacro; + + # Strip out the .set lines from the armasm output + return if (handle_set($line) and $as_type eq "armasm"); + + if ($line =~ /\.rept\s+(.*)/) { + $num_repts = $1; + @rept_lines = ("\n"); + + # handle the possibility of repeating another directive on the same line + # .endr on the same line is not valid, I don't know if a non-directive is + if ($num_repts =~ s/(\.\w+.*)//) { + push(@rept_lines, "$1\n"); + } + $num_repts = eval_expr($num_repts); + } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + # only use whitespace as the separator + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(/\s+/, $irp_arglist); + } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(//, $irp_arglist); + } elsif ($line =~ /\.endr/) { + my @prev_rept_lines = @rept_lines; + my $prev_in_irp = $in_irp; + my @prev_irp_args = @irp_args; + my $prev_irp_param = $irp_param; + my $prev_num_repts = $num_repts; + @rept_lines = (); + $in_irp = 0; + @irp_args = ''; + + if ($prev_in_irp != 0) { + foreach my $i (@prev_irp_args) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + $line =~ s/\\$prev_irp_param/$i/g; + $line =~ s/\\\(\)//g; # remove \() + parse_line($line); + } + } + } else { + for (1 .. $prev_num_repts) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + parse_line($line); + } + } + } + } elsif ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) { + handle_serialized_line($1); + my $macro = $2; + + # commas are optional here too, but are syntactically important because + # parameters can be blank + my @arglist = split(/,/, $3); + my @args; + my @args_seperator; + + my $comma_sep_required = 0; + foreach (@arglist) { + # allow arithmetic/shift operators in macro arguments + $_ =~ s/\s*(\+|-|\*|\/|<<|>>|<|>)\s*/$1/g; + + my @whitespace_split = split(/\s+/, $_); + if (!@whitespace_split) { + push(@args, ''); + push(@args_seperator, ''); + } else { + foreach (@whitespace_split) { + #print ("arglist = \"$_\"\n"); + if (length($_)) { + push(@args, $_); + my $sep = $comma_sep_required ? "," : " "; + push(@args_seperator, $sep); + #print ("sep = \"$sep\", arg = \"$_\"\n"); + $comma_sep_required = 0; + } + } + } + + $comma_sep_required = 1; + } + + my %replacements; + if ($macro_args_default{$macro}){ + %replacements = %{$macro_args_default{$macro}}; + } + + # construct hashtable of text to replace + foreach my $i (0 .. $#args) { + my $argname = $macro_args{$macro}[$i]; + my @macro_args = @{ $macro_args{$macro} }; + if ($args[$i] =~ m/=/) { + # arg=val references the argument name + # XXX: I'm not sure what the expected behaviour if a lot of + # these are mixed with unnamed args + my @named_arg = split(/=/, $args[$i]); + $replacements{$named_arg[0]} = $named_arg[1]; + } elsif ($i > $#{$macro_args{$macro}}) { + # more args given than the macro has named args + # XXX: is vararg allowed on arguments before the last? + $argname = $macro_args{$macro}[-1]; + if ($argname =~ s/:vararg$//) { + #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; + #$replacements{$argname} .= ", $args[$i]"; + $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; + } else { + die "Too many arguments to macro $macro"; + } + } else { + $argname =~ s/:vararg$//; + $replacements{$argname} = $args[$i]; + } + } + + my $count = $macro_count++; + + # apply replacements as regex + foreach (@{$macro_lines{$macro}}) { + my $macro_line = $_; + # do replacements by longest first, this avoids wrong replacement + # when argument names are subsets of each other + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\\$_/$replacements{$_}/g; + } + if ($altmacro) { + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\b$_\b/$replacements{$_}/g; + } + } + $macro_line =~ s/\\\@/$count/g; + $macro_line =~ s/\\\(\)//g; # remove \() + parse_line($macro_line); + } + } else { + handle_serialized_line($line); + } +} + +sub is_arm_register { + my $name = $_[0]; + if ($name eq "lr" or + $name eq "ip" or + $name =~ /^[rav]\d+$/) { + return 1; + } + return 0; +} + +sub handle_local_label { + my $line = $_[0]; + my $num = $_[1]; + my $dir = $_[2]; + my $target = "$num$dir"; + if ($dir eq "b") { + $line =~ s/$target/$last_temp_labels{$num}/g; + } else { + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + push(@{$next_temp_labels{$num}}, $name); + $line =~ s/$target/$name/g; + } + return $line; +} + +sub handle_serialized_line { + my $line = $_[0]; + + # handle .previous (only with regard to .section not .subsection) + if ($line =~ /\.(section|text|const_data)/) { + push(@sections, $line); + } elsif ($line =~ /\.previous/) { + if (!$sections[-2]) { + die ".previous without a previous section"; + } + $line = $sections[-2]; + push(@sections, $line); + } + + $thumb = 1 if $line =~ /\.code\s+16|\.thumb/; + $thumb = 0 if $line =~ /\.code\s+32|\.arm/; + + # handle ldr <reg>, =<expr> + if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/ and $as_type ne "armasm") { + my $label = $literal_labels{$3}; + if (!$label) { + $label = "Literal_$literal_num"; + $literal_num++; + $literal_labels{$3} = $label; + } + $line = "$1 ldr$2, $label\n"; + } elsif ($line =~ /\.ltorg/ and $as_type ne "armasm") { + $line .= ".align 2\n"; + foreach my $literal (keys %literal_labels) { + $line .= "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + %literal_labels = (); + } + + # handle GNU as pc-relative relocations for adrp/add + if ($line =~ /(.*)\s*adrp([\w\s\d]+)\s*,\s*#?:pg_hi21:([^\s]+)/) { + $line = "$1 adrp$2, ${3}\@PAGE\n"; + } elsif ($line =~ /(.*)\s*add([\w\s\d]+)\s*,([\w\s\d]+)\s*,\s*#?:lo12:([^\s]+)/) { + $line = "$1 add$2, $3, ${4}\@PAGEOFF\n"; + } + + # thumb add with large immediate needs explicit add.w + if ($thumb and $line =~ /add\s+.*#([^@]+)/) { + $line =~ s/add/add.w/ if eval_expr($1) > 255; + } + + # mach-o local symbol names start with L (no dot) + $line =~ s/(?<!\w)\.(L\w+)/$1/g; + + # recycle the '.func' directive for '.thumb_func' + if ($thumb and $as_type =~ /^apple-/) { + $line =~ s/\.func/.thumb_func/x; + } + + if ($thumb and $line =~ /^\s*(\w+)\s*:/) { + $thumb_labels{$1}++; + } + + if ($as_type =~ /^apple-/ and + $line =~ /^\s*((\w+\s*:\s*)?bl?x?(..)?(?:\.w)?|\.global)\s+(\w+)/) { + my $cond = $3; + my $label = $4; + # Don't interpret e.g. bic as b<cc> with ic as conditional code + if ($cond =~ /|$arm_cond_codes/) { + if (exists $thumb_labels{$label}) { + print ASMFILE ".thumb_func $label\n"; + } else { + $call_targets{$label}++; + } + } + } + + # @l -> lo16() @ha -> ha16() + $line =~ s/,\s+([^,]+)\@l\b/, lo16($1)/g; + $line =~ s/,\s+([^,]+)\@ha\b/, ha16($1)/g; + + # move to/from SPR + if ($line =~ /(\s+)(m[ft])([a-z]+)\s+(\w+)/ and exists $ppc_spr{$3}) { + if ($2 eq 'mt') { + $line = "$1${2}spr $ppc_spr{$3}, $4\n"; + } else { + $line = "$1${2}spr $4, $ppc_spr{$3}\n"; + } + } + + if ($line =~ /\.unreq\s+(.*)/) { + if (defined $neon_alias_reg{$1}) { + delete $neon_alias_reg{$1}; + delete $neon_alias_type{$1}; + return; + } elsif (defined $aarch64_req_alias{$1}) { + delete $aarch64_req_alias{$1}; + return; + } + } + # old gas versions store upper and lower case names on .req, + # but they remove only one on .unreq + if ($fix_unreq) { + if ($line =~ /\.unreq\s+(.*)/) { + $line = ".unreq " . lc($1) . "\n"; + $line .= ".unreq " . uc($1) . "\n"; + } + } + + if ($line =~ /(\w+)\s+\.(dn|qn)\s+(\w+)(?:\.(\w+))?(\[\d+\])?/) { + $neon_alias_reg{$1} = "$3$5"; + $neon_alias_type{$1} = $4; + return; + } + if (scalar keys %neon_alias_reg > 0 && $line =~ /^\s+v\w+/) { + # This line seems to possibly have a neon instruction + foreach (keys %neon_alias_reg) { + my $alias = $_; + # Require the register alias to match as an invididual word, not as a substring + # of a larger word-token. + if ($line =~ /\b$alias\b/) { + $line =~ s/\b$alias\b/$neon_alias_reg{$alias}/g; + # Add the type suffix. If multiple aliases match on the same line, + # only do this replacement the first time (a vfoo.bar string won't match v\w+). + $line =~ s/^(\s+)(v\w+)(\s+)/$1$2.$neon_alias_type{$alias}$3/; + } + } + } + + if ($arch eq "aarch64" or $as_type eq "armasm") { + # clang's integrated aarch64 assembler in Xcode 5 does not support .req/.unreq + if ($line =~ /\b(\w+)\s+\.req\s+(\w+)\b/) { + $aarch64_req_alias{$1} = $2; + return; + } + foreach (keys %aarch64_req_alias) { + my $alias = $_; + # recursively resolve aliases + my $resolved = $aarch64_req_alias{$alias}; + while (defined $aarch64_req_alias{$resolved}) { + $resolved = $aarch64_req_alias{$resolved}; + } + $line =~ s/\b$alias\b/$resolved/g; + } + } + if ($arch eq "aarch64") { + # fix missing aarch64 instructions in Xcode 5.1 (beta3) + # mov with vector arguments is not supported, use alias orr instead + if ($line =~ /^\s*mov\s+(v\d[\.{}\[\]\w]+),\s*(v\d[\.{}\[\]\w]+)\b\s*$/) { + $line = " orr $1, $2, $2\n"; + } + # movi 16, 32 bit shifted variant, shift is optional + if ($line =~ /^\s*movi\s+(v[0-3]?\d\.(?:2|4|8)[hsHS])\s*,\s*(#\w+)\b\s*$/) { + $line = " movi $1, $2, lsl #0\n"; + } + # Xcode 5 misses the alias uxtl. Replace it with the more general ushll. + # Clang 3.4 misses the alias sxtl too. Replace it with the more general sshll. + if ($line =~ /^\s*(s|u)xtl(2)?\s+(v[0-3]?\d\.[248][hsdHSD])\s*,\s*(v[0-3]?\d\.(?:2|4|8|16)[bhsBHS])\b\s*$/) { + $line = " $1shll$2 $3, $4, #0\n"; + } + # clang 3.4 does not automatically use shifted immediates in add/sub + if ($as_type eq "clang" and + $line =~ /^(\s*(?:add|sub)s?) ([^#l]+)#([\d\+\-\*\/ <>]+)\s*$/) { + my $imm = eval $3; + if ($imm > 4095 and not ($imm & 4095)) { + $line = "$1 $2#" . ($imm >> 12) . ", lsl #12\n"; + } + } + if ($ENV{GASPP_FIX_XCODE5}) { + if ($line =~ /^\s*bsl\b/) { + $line =~ s/\b(bsl)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.$3\b/$1/g; + } + if ($line =~ /^\s*saddl2?\b/) { + $line =~ s/\b(saddl2?)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.\w+\b/$1/g; + } + if ($line =~ /^\s*dup\b.*\]$/) { + $line =~ s/\bdup(\s+v[0-3]?\d)\.(\w+)\b/dup.$2$1/g; + $line =~ s/\b(v[0-3]?\d)\.[bhsdBHSD](\[\d\])$/$1$2/g; + } + } + } + + if ($as_type eq "armasm") { + # Also replace variables set by .set + foreach (keys %symbols) { + my $sym = $_; + $line =~ s/\b$sym\b/$symbols{$sym}/g; + } + + # Handle function declarations and keep track of the declared labels + if ($line =~ s/^\s*\.func\s+(\w+)/$1 PROC/) { + $labels_seen{$1} = 1; + } + + if ($line =~ s/^(\d+)://) { + # Convert local labels into unique labels. armasm (at least in + # RVCT) has something similar, but still different enough. + # By converting to unique labels we avoid any possible + # incompatibilities. + + my $num = $1; + foreach (@{$next_temp_labels{$num}}) { + $line = "$_\n" . $line; + } + @next_temp_labels{$num} = (); + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + # The matching regexp above removes the label from the start of + # the line (which might contain an instruction as well), readd + # it on a separate line above it. + $line = "$name:\n" . $line; + $last_temp_labels{$num} = $name; + } + + if ($line =~ s/^(\w+):/$1/) { + # Skip labels that have already been declared with a PROC, + # labels must not be declared multiple times. + return if (defined $labels_seen{$1}); + $labels_seen{$1} = 1; + } elsif ($line !~ /(\w+) PROC/) { + # If not a label, make sure the line starts with whitespace, + # otherwise ms armasm interprets it incorrectly. + $line =~ s/^[\.\w]/\t$&/; + } + + + # Check branch instructions + if ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(bl?x?(..)?(\.w)?)\s+(\w+)/) { + my $instr = $2; + my $cond = $3; + my $width = $4; + my $target = $5; + # Don't interpret e.g. bic as b<cc> with ic as conditional code + if ($cond !~ /|$arm_cond_codes/) { + # Not actually a branch + } elsif ($target =~ /(\d+)([bf])/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + $line =~ s/\b$instr\b/$&.w/ if $width eq ""; + } elsif (!is_arm_register($target)) { + $call_targets{$target}++; + } + } elsif ($line =~ /^\s*.h?word.*\b\d+[bf]\b/) { + while ($line =~ /\b(\d+)([bf])\b/g) { + $line = handle_local_label($line, $1, $2); + } + } + + # ALIGN in armasm syntax is the actual number of bytes + if ($line =~ /\.align\s+(\d+)/) { + my $align = 1 << $1; + $line =~ s/\.align\s(\d+)/ALIGN $align/; + } + # Convert gas style [r0, :128] into armasm [r0@128] alignment specification + $line =~ s/\[([^\[]+),\s*:(\d+)\]/[$1\@$2]/g; + + # armasm treats logical values {TRUE} and {FALSE} separately from + # numeric values - logical operators and values can't be intermixed + # with numerical values. Evaluate !<number> and (a <> b) into numbers, + # let the assembler evaluate the rest of the expressions. This current + # only works for cases when ! and <> are used with actual constant numbers, + # we don't evaluate subexpressions here. + + # Evaluate !<number> + while ($line =~ /!\s*(\d+)/g) { + my $val = ($1 != 0) ? 0 : 1; + $line =~ s/!(\d+)/$val/; + } + # Evaluate (a > b) + while ($line =~ /\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/) { + my $val; + if ($2 eq "<") { + $val = ($1 < $3) ? 1 : 0; + } else { + $val = ($1 > $3) ? 1 : 0; + } + $line =~ s/\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/$val/; + } + + # Change a movw... #:lower16: into a mov32 pseudoinstruction + $line =~ s/^(\s*)movw(\s+\w+\s*,\s*)\#:lower16:(.*)$/$1mov32$2$3/; + # and remove the following, matching movt completely + $line =~ s/^\s*movt\s+\w+\s*,\s*\#:upper16:.*$//; + + if ($line =~ /^\s*mov32\s+\w+,\s*([a-zA-Z]\w*)/) { + $mov32_targets{$1}++; + } + + # Misc bugs/deficiencies: + # armasm seems unable to parse e.g. "vmov s0, s1" without a type + # qualifier, thus add .f32. + $line =~ s/^(\s+(?:vmov|vadd))(\s+s)/$1.f32$2/; + # armasm is unable to parse &0x - add spacing + $line =~ s/&0x/& 0x/g; + } + + if ($force_thumb) { + # Convert register post indexing to a separate add instruction. + # This converts e.g. "ldr r0, [r1], r2" into "ldr r0, [r1]", + # "add r1, r1, r2". + $line =~ s/(ldr|str)\s+(\w+),\s*\[(\w+)\],\s*(\w+)/$1 $2, [$3]\n\tadd $3, $3, $4/g; + + # Convert "mov pc, lr" into "bx lr", since the former only works + # for switching from arm to thumb (and only in armv7), but not + # from thumb to arm. + s/mov\s*pc\s*,\s*lr/bx lr/g; + + # Convert stmdb/ldmia with only one register into a plain str/ldr with post-increment/decrement + $line =~ s/stmdb\s+sp!\s*,\s*\{([^,-]+)\}/str $1, [sp, #-4]!/g; + $line =~ s/ldmia\s+sp!\s*,\s*\{([^,-]+)\}/ldr $1, [sp], #4/g; + + $line =~ s/\.arm/.thumb/x; + } + + # comment out unsupported directives + $line =~ s/\.type/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.func/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/ENDP/x if $as_type =~ /armasm/; + $line =~ s/\.ltorg/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.ltorg/LTORG/x if $as_type eq "armasm"; + $line =~ s/\.size/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.fpu/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.arch/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; + $line =~ s/\.object_arch/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/.section\s+.note.GNU-stack.*/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.hidden/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; + + $line =~ s/\.syntax/$comm$&/x if $as_type =~ /armasm/; + + $line =~ s/\.hword/.short/x; + + if ($as_type =~ /^apple-/) { + # the syntax for these is a little different + $line =~ s/\.global/.globl/x; + # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const + $line =~ s/(.*)\.rodata/.const_data/x; + $line =~ s/\.int/.long/x; + $line =~ s/\.float/.single/x; + } + if ($as_type eq "armasm") { + $line =~ s/\.global/EXPORT/x; + $line =~ s/\.int/dcd/x; + $line =~ s/\.long/dcd/x; + $line =~ s/\.float/dcfs/x; + $line =~ s/\.word/dcd/x; + $line =~ s/\.short/dcw/x; + $line =~ s/\.byte/dcb/x; + $line =~ s/\.thumb/THUMB/x; + $line =~ s/\.arm/ARM/x; + # The alignment in AREA is the power of two, just as .align in gas + $line =~ s/\.text/AREA |.text|, CODE, READONLY, ALIGN=2, CODEALIGN/; + $line =~ s/(\s*)(.*)\.rodata/$1AREA |.rodata|, DATA, READONLY, ALIGN=5/; + + $line =~ s/fmxr/vmsr/; + $line =~ s/fmrx/vmrs/; + $line =~ s/fadds/vadd/; + } + + # catch unknown section names that aren't mach-o style (with a comma) + if ($as_type =~ /apple-/ and $line =~ /.section ([^,]*)$/) { + die ".section $1 unsupported; figure out the mach-o section name and add it"; + } + + print ASMFILE $line; +} + +if ($as_type ne "armasm") { + print ASMFILE ".text\n"; + print ASMFILE ".align 2\n"; + foreach my $literal (keys %literal_labels) { + print ASMFILE "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + + map print(ASMFILE ".thumb_func $_\n"), + grep exists $thumb_labels{$_}, keys %call_targets; +} else { + map print(ASMFILE "\tIMPORT $_\n"), + grep ! exists $labels_seen{$_}, (keys %call_targets, keys %mov32_targets); + + print ASMFILE "\tEND\n"; +} + +close(INPUT) or exit 1; +close(ASMFILE) or exit 1; +if ($as_type eq "armasm" and ! defined $ENV{GASPP_DEBUG}) { + system(@gcc_cmd) == 0 or die "Error running assembler"; +} + +END { + unlink($tempfile) if defined $tempfile; +} +#exit 1 diff --git a/xmake/core/tools/gcc.lua b/xmake/core/tools/gcc.lua new file mode 100644 index 000000000..ab5e94ccb --- /dev/null +++ b/xmake/core/tools/gcc.lua @@ -0,0 +1,192 @@ +--!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 gcc.lua +-- + +-- load modules +local utils = require("base/utils") +local table = require("base/table") +local string = require("base/string") +local config = require("base/config") +local platform = require("platform/platform") + +-- define module: gcc +local gcc = gcc or {} + +-- check the given flag +function gcc._check(self, flag) + + -- this flag has been checked? + self._CHECK = self._CHECK or {} + if self._CHECK[flag] then + return self._CHECK[flag] + end + + -- check it + local result = flag + if 0 ~= os.execute(string.format("%s %s -S -o %s -xc %s > %s 2>&1", self.name, flag, xmake._NULDEV, xmake._NULDEV, xmake._NULDEV)) then + result = "" + end + + -- trace + utils.verbose("checking for the compiler flags %s ... %s", flag, utils.ifelse(#result ~= 0, "ok", "no")) + + -- save it + self._CHECK[flag] = result + + -- ok? + return result +end + +-- the init function +function gcc.init(self, name) + + -- save name + self.name = name or "gcc" + + -- init mxflags + self.mxflags = { "-fmessage-length=0" + , "-pipe" + , "-fpascal-strings" + , "\"-DIBOutlet=__attribute__((iboutlet))\"" + , "\"-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))\"" + , "\"-DIBAction=void)__attribute__((ibaction)\""} + + -- init shflags + if name:find("clang") then + self.shflags = { "-dynamiclib", "-fPIC" } + else + self.shflags = { "-shared", "-fPIC" } + end + + -- init cxflags for the kind: shared + self.shared = {} + self.shared.cxflags = {"-fPIC"} + + -- suppress warning for the clang + local isclang = false + if name:find("clang") then + isclang = true + self.cxflags = self.cxflags or {} + self.mxflags = self.mxflags or {} + self.asflags = self.asflags or {} + table.join2(self.cxflags, "-Qunused-arguments") + table.join2(self.mxflags, "-Qunused-arguments") + table.join2(self.asflags, "-Qunused-arguments") + end + + -- init flags map + self.mapflags = + { + -- vectorexts + ["-mmmx"] = self._check + , ["-msse$"] = self._check + , ["-msse2"] = self._check + , ["-msse3"] = self._check + , ["-mssse3"] = self._check + , ["-mavx$"] = self._check + , ["-mavx2"] = self._check + , ["-mfpu=.*"] = self._check + + -- warnings + , ["-W1"] = "-Wall" + , ["-W2"] = "-Wall" + , ["-W3"] = "-Wall" + + -- strip + , ["-s"] = utils.ifelse(isclang, "-Wl,-S", "-s") + , ["-S"] = utils.ifelse(isclang, "-Wl,-S", "-S") + + -- others + , ["-ftrapv"] = self._check + , ["-fsanitize=address"] = self._check + } + +end + +-- make the compile command +function gcc.command_compile(self, srcfile, objfile, flags, logfile) + + -- redirect + local redirect = "" + if logfile then redirect = string.format(" > %s 2>&1", logfile) end + + -- make it + return string.format("%s -c %s -o %s %s%s", self.name, flags, objfile, srcfile, redirect) +end + +-- make the link command +function gcc.command_link(self, objfiles, targetfile, flags, logfile) + + -- redirect + local redirect = "" + if logfile then redirect = string.format(" > %s 2>&1", logfile) end + + -- make it + return string.format("%s -o %s %s %s%s", self.name, targetfile, objfiles, flags, redirect) +end + +-- make the define flag +function gcc.flag_define(self, define) + + -- make it + return "-D" .. define:gsub("\"", "\\\"") +end + +-- make the undefine flag +function gcc.flag_undefine(self, undefine) + + -- make it + return "-U" .. undefine +end + +-- make the includedir flag +function gcc.flag_includedir(self, includedir) + + -- make it + return "-I" .. includedir +end + +-- make the link flag +function gcc.flag_link(self, link) + + -- make it + return "-l" .. link +end + +-- make the linkdir flag +function gcc.flag_linkdir(self, linkdir) + + -- make it + return "-L" .. linkdir +end + +-- the main function +function gcc.main(self, cmd) + + -- execute it + local ok = os.execute(cmd) + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: gcc +return gcc diff --git a/xmake/core/tools/make.lua b/xmake/core/tools/make.lua new file mode 100644 index 000000000..5d2d1f42b --- /dev/null +++ b/xmake/core/tools/make.lua @@ -0,0 +1,82 @@ +--!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 make.lua +-- + +-- load modules +local os = require("base/os") +local utils = require("base/utils") + +-- define module: make +local make = make or {} + +-- the init function +function make.init(self, name) + + -- save name + self.name = name or "make" + + -- is verbose? + self._VERBOSE = utils.ifelse(xmake._OPTIONS.verbose, "-v", "") + +end + +-- the main function +function make.main(self, mkfile, target) + + -- enable jobs? + local jobs = "" + if xmake._OPTIONS.jobs ~= nil then + if tonumber(xmake._OPTIONS.jobs) ~= 0 then + jobs = "-j" .. xmake._OPTIONS.jobs + else + jobs = "-j" + end + end + + -- make command + local cmd = nil + if mkfile and os.isfile(mkfile) then + cmd = string.format("%s -r %s -f %s %s VERBOSE=%s", self.name, jobs, mkfile, target or "", self._VERBOSE) + else + cmd = string.format("%s -r %s %s VERBOSE=%s", self.name, jobs, target or "", self._VERBOSE) + end + + -- done + local ok = os.execute(cmd) + if ok ~= 0 then + + -- attempt to execute it again for getting the error logs without jobs + if mkfile and os.isfile(mkfile) then + cmd = string.format("%s -r -f %s %s VERBOSE=%s", self.name, mkfile, target or "", self._VERBOSE) + else + cmd = string.format("%s -r %s VERBOSE=%s", self.name, target or "", self._VERBOSE) + end + + -- done + return os.execute(cmd) == 0 + end + + -- ok + return true +end + +-- return module: make +return make diff --git a/xmake/core/tools/mkdir.lua b/xmake/core/tools/mkdir.lua new file mode 100644 index 000000000..9fadb875d --- /dev/null +++ b/xmake/core/tools/mkdir.lua @@ -0,0 +1,46 @@ +--!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 mkdir.lua +-- + +-- define module: mkdir +local mkdir = mkdir or {} + +-- load modules +local os = require("base/os") + +-- the main function +function mkdir.main(self, ...) + + -- mkdir all + for _, dir in ipairs(...) do + if not os.exists(dir) then + if not os.mkdir(dir) then + return false + end + end + end + + -- ok + return true +end + +-- return module: mkdir +return mkdir diff --git a/xmake/core/tools/mv.lua b/xmake/core/tools/mv.lua new file mode 100644 index 000000000..7af2db9ed --- /dev/null +++ b/xmake/core/tools/mv.lua @@ -0,0 +1,43 @@ +--!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 mv.lua +-- + +-- define module: mv +local mv = mv or {} + +-- load modules +local os = require("base/os") + +-- the main function +function mv.main(self, ...) + + -- mv it + local pathes = ... + if pathes and table.getn(pathes) == 2 then + return os.mv(pathes[1], pathes[2]) + end + + -- failed + return false +end + +-- return module: mv +return mv diff --git a/xmake/core/tools/rm.lua b/xmake/core/tools/rm.lua new file mode 100644 index 000000000..47f57e68b --- /dev/null +++ b/xmake/core/tools/rm.lua @@ -0,0 +1,46 @@ +--!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 rm.lua +-- + +-- define module: rm +local rm = rm or {} + +-- load modules +local os = require("base/os") + +-- the main function +function rm.main(self, ...) + + -- rm all + for _, file_or_dir in ipairs(...) do + if os.exists(file_or_dir) then + if not os.rm(file_or_dir) then + return false + end + end + end + + -- ok + return true +end + +-- return module: rm +return rm diff --git a/xmake/core/tools/rmdir.lua b/xmake/core/tools/rmdir.lua new file mode 100644 index 000000000..cea1e28fa --- /dev/null +++ b/xmake/core/tools/rmdir.lua @@ -0,0 +1,46 @@ +--!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 rmdir.lua +-- + +-- define module: rmdir +local rmdir = rmdir or {} + +-- load modules +local os = require("base/os") + +-- the main function +function rmdir.main(self, ...) + + -- rmdir all + for _, dir in ipairs(...) do + if os.isdir(dir) then + if not os.rmdir(dir) then + return false + end + end + end + + -- ok + return true +end + +-- return module: rmdir +return rmdir diff --git a/xmake/core/tools/swiftc.lua b/xmake/core/tools/swiftc.lua new file mode 100644 index 000000000..39142705f --- /dev/null +++ b/xmake/core/tools/swiftc.lua @@ -0,0 +1,117 @@ +--!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 swiftc.lua +-- + +-- load modules +local utils = require("base/utils") +local table = require("base/table") +local string = require("base/string") +local config = require("base/config") +local platform = require("platform/platform") + +-- define module: swiftc +local swiftc = swiftc or {} + +-- the init function +function swiftc.init(self, name) + + -- save name + self.name = name or "swiftc" + + -- init flags map + self.mapflags = + { + -- symbols + ["-fvisibility=hidden"] = "" + + -- warnings + , ["-w"] = "" + , ["-W.*"] = "" + + -- optimize + , ["-O0"] = "-Onone" + , ["-Ofast"] = "-Ounchecked" + , ["-O.*"] = "-O" + + -- vectorexts + , ["-m.*"] = "" + + -- strip + , ["-s"] = "" + , ["-S"] = "" + + -- others + , ["-ftrapv"] = "" + , ["-fsanitize=address"] = "" + } + + -- init ldflags + local swift_linkdirs = config.get("__swift_linkdirs") + if swift_linkdirs then + self.ldflags = { "-L" .. swift_linkdirs } + end + +end + +-- make the compile command +function swiftc.command_compile(self, srcfile, objfile, flags, logfile) + + -- redirect + local redirect = "" + if logfile then redirect = string.format(" > %s 2>&1", logfile) end + + -- make it + return string.format("%s -c %s -o %s %s%s", self.name, flags, objfile, srcfile, redirect) +end + +-- make the includedir flag +function swiftc.flag_includedir(self, includedir) + + -- make it + return "-Xcc -I" .. includedir +end + +-- make the define flag +function swiftc.flag_define(self, define) + + -- make it + return "-Xcc -D" .. define:gsub("\"", "\\\"") +end + +-- make the undefine flag +function swiftc.flag_undefine(self, undefine) + + -- make it + return "-Xcc -U" .. undefine +end + +-- the main function +function swiftc.main(self, cmd) + + -- execute it + local ok = os.execute(cmd) + + -- ok? + return utils.ifelse(ok == 0, true, false) +end + +-- return module: swiftc +return swiftc diff --git a/xmake/core/tools/tools.lua b/xmake/core/tools/tools.lua new file mode 100644 index 000000000..a61322d3c --- /dev/null +++ b/xmake/core/tools/tools.lua @@ -0,0 +1,222 @@ +--!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 tools.lua +-- + +-- define module: tools +local tools = tools or {} + +-- load modules +local os = require("base/os") +local path = require("base/path") +local utils = require("base/utils") +local string = require("base/string") +local platform = require("platform/platform") + +-- match the tool name +function tools._match(name, toolname) + + -- match full? ok + if name == toolname then return 100 end + + -- match the name for windows? ok + if name:find("^" .. toolname .. "%.exe") then return 90 end + if name:find(toolname .. "%.exe") then return 85 end + + -- match the last word? ok + if name:find(toolname .. "$") then return 80 end + + -- match the partial word? ok + if name:find("%-" .. toolname) then return 60 end + + -- contains it? ok + if name:find(toolname, 1, true) then return 30 end + + -- not matched + return 0 +end + +-- find tool from the given root directory and name +function tools._find_from(root, name) + + -- attempt to get it directly first + local filepath = string.format("%s/%s.lua", root, name) + if os.isfile(filepath) then + return filepath + end + + -- make the lower name + name = name:lower() + + -- get all tool files + local file_ok = nil + local score_maxn = 0 + local files = os.match(string.format("%s/*.lua", root)) + for _, file in ipairs(files) do + + -- the tool name + local toolname = path.basename(file) + + -- found it? + if toolname and toolname ~= "tools" then + + -- match score + local score = tools._match(name, toolname:lower()) + + -- ok? + if score >= 100 then return file end + + -- select the file with the max score + if score > score_maxn then + file_ok = file + score_maxn = score + end + end + end + + -- ok? + return file_ok +end + +-- probe it's absolute path if exists from the given tool name and root directory +function tools._probe(root, name) + + -- check + assert(root and name) + + -- make the tool path + local toolpath = string.format("%s/%s", root, name) + toolpath = path.translate(toolpath) + + -- the tool exists? ok + if toolpath and os.isfile(toolpath) then + return toolpath + end +end + +-- find tool from the given name and directory (optional) +function tools.find(name, root) + + -- check + assert(name) + + -- init filename + local filepath = nil + + -- only find it from this directory if the given directory exists + if root then return tools._find_from(root, name) end + + -- attempt to find it from the current platform directory first + if not filepath then filepath = tools._find_from(platform.directory() .. "/tools", name) end + + -- attempt to find it from the script directory + if not filepath then filepath = tools._find_from(xmake._CORE_DIR .. "/tools", name) end + + -- ok? + return filepath +end + +-- load tool from the given name and directory (optional) +function tools.load(name, root) + + -- check + assert(name) + + -- get it directly from cache dirst + tools._TOOLS = tools._TOOLS or {} + if tools._TOOLS[name] then + return tools._TOOLS[name] + end + + -- find the tool file path + local toolpath = tools.find(name, root) + + -- not exists? + if not toolpath or not os.isfile(toolpath) then + return + end + + -- load script + local script, errors = loadfile(toolpath) + if script then + + -- load tool + local tool = script() + + -- init tool + if tool and tool.init then + tool:init(name) + end + + -- save tool to the cache + tools._TOOLS[name] = tool + + -- ok? + return tool + else + utils.error(errors) + utils.error("load %s failed!", toolpath) + assert(false) + end +end + +-- get the given tool script from the given kind +function tools.get(kind) + + -- get the tool name + local toolname = platform.tool(kind) + if not toolname then + utils.error("cannot get tool name for %s", kind) + return + end + + -- load it + return tools.load(toolname) +end + +-- probe it's absolute path if exists from the given tool name +function tools.probe(name, dirs) + + -- check + assert(name) + + -- attempt to run it directly first + if os.execute(string.format("%s > %s 2>&1", name, xmake._NULDEV)) ~= 0x7f00 then + return name + end + + -- attempt to get it from the given directories + if dirs then + for _, dir in ipairs(utils.wrap(dirs)) do + + -- probe it + local toolpath = tools._probe(dir, name) + + -- ok? + if toolpath and os.execute(string.format("%s > %s 2>&1", toolpath, xmake._NULDEV)) ~= 0x7f00 then + return toolpath + end + end + end +end + + +-- return module: tools +return tools diff --git a/xmake/core/tools/verbose.lua b/xmake/core/tools/verbose.lua new file mode 100644 index 000000000..b1168f29d --- /dev/null +++ b/xmake/core/tools/verbose.lua @@ -0,0 +1,47 @@ +--!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 verbose.lua +-- + + +-- define module: verbose +local verbose = verbose or {} + +-- load modules +local io = require("base/io") +local string = require("base/string") + +-- the main function +function verbose.main(self, ...) + + -- verbose all + if xmake._OPTIONS.verbose then + for _, v in ipairs(...) do + io.write(string.format("%s ", v:decode())) + end + io.write("\n") + end + + -- ok + return true +end + +-- return module: verbose +return verbose |
