summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2016-04-13 10:13:37 +0800
committerruki <[email protected]>2016-04-13 10:13:37 +0800
commit097a0d5eb612d898fb8de01d6db7760aed947b4b (patch)
tree9c2ad3ffe67da1663953f9b7097721e96156cb18
parent833bfb207b3f924eaa81feb496cf74e6223d0041 (diff)
throw os.run errors
-rwxr-xr-xxmake/actions/config/makefile.lua2
-rw-r--r--xmake/core/base/os.lua27
-rw-r--r--xmake/core/project/option.lua168
-rw-r--r--xmake/core/project/project.lua1
-rw-r--r--xmake/core/project/target.lua26
-rw-r--r--xmake/core/sandbox/modules/os.lua14
-rw-r--r--xmake/core/tool/compiler.lua421
-rw-r--r--xmake/core/tool/tool.lua172
-rwxr-xr-xxmake/tools/compiler/clang.lua132
-rwxr-xr-xxmake/tools/compiler/gcc.lua8
10 files changed, 920 insertions, 51 deletions
diff --git a/xmake/actions/config/makefile.lua b/xmake/actions/config/makefile.lua
index e0b66bd8b..b65b8a7b0 100755
--- a/xmake/actions/config/makefile.lua
+++ b/xmake/actions/config/makefile.lua
@@ -93,7 +93,7 @@ function _make_object(makefile, target, srcfile, objfile)
-- make command
local ccache = tool.shellname("ccache")
local compiler = target:compiler(srcfile)
- local cmd = compiler:makecmd(target, srcfile, objfile, _logfile())
+ local cmd = compiler:command(target, srcfile, objfile, _logfile())
if ccache then
cmd = ccache:append(cmd, " ")
end
diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua
index 1cdcd0e08..dfec6dc1d 100644
--- a/xmake/core/base/os.lua
+++ b/xmake/core/base/os.lua
@@ -24,6 +24,7 @@
local os = os or {}
-- load modules
+local io = require("base/io")
local path = require("base/path")
local utils = require("base/utils")
local string = require("base/string")
@@ -230,6 +231,32 @@ function os.cd(dir)
return true
end
+-- run shell
+function os.run(cmd, ...)
+
+ -- make temporary log file
+ local log = os.tmpname()
+
+ -- run command
+ if 0 ~= os.execute(cmd .. string.format(" > %s 2>&1", log)) then
+
+ -- make errors
+ local errors = string.format("%s\nrun: %s failed!", io.readall(log), cmd)
+
+ -- remove the temporary log file
+ os.rm(log)
+
+ -- failed
+ return false, errors
+ end
+
+ -- remove the temporary log file
+ os.rm(log)
+
+ -- ok
+ return true
+end
+
-- raise an exception and abort the current script
--
-- the parent function will capture it if we uses pcall or xpcall
diff --git a/xmake/core/project/option.lua b/xmake/core/project/option.lua
index 9be17f801..4cea021c4 100644
--- a/xmake/core/project/option.lua
+++ b/xmake/core/project/option.lua
@@ -24,13 +24,165 @@
local option = option or {}
-- load modules
+local io = require("base/io")
local os = require("base/os")
local path = require("base/path")
local table = require("base/table")
local utils = require("base/utils")
+local option_ = require("base/option")
local cache = require("project/cache")("local.option")
local linker = require("platform/linker")
-local compiler = require("platform/compiler")
+local compiler = require("tool/compiler")
+
+-- check include
+function option:_check_include(include, srcpath, objpath)
+
+ -- check
+ assert(srcpath and objpath)
+
+ -- open the checking source file
+ local srcfile = io.open(srcpath, "w")
+ if not srcfile then
+ return false
+ end
+
+ -- make include
+ if include then
+ srcfile:print("#include <%s>\n", include)
+ end
+
+ -- make the main function header
+ srcfile:print("int main(int argc, char** argv)")
+ srcfile:print("{")
+ srcfile:print(" return 0;")
+ srcfile:print("}")
+
+ -- exit this file
+ srcfile:close()
+
+ -- load the compiler instance
+ local instance = compiler.load(srcpath)
+ if not instance then
+ return false
+ end
+
+ -- attempt to run this command
+ local ok, errors = instance:run(instance:command(self, srcpath, objpath))
+ if not ok and option_.get("verbose") then
+ print(errors)
+ end
+
+ -- ok?
+ return ok
+end
+
+-- check function
+function option:_check_function(interface, srcpath, objpath)
+
+ -- check
+ assert(interface)
+
+ -- open the checking source file
+ local srcfile = io.open(srcpath, "w")
+ if not srcfile then
+ return false
+ end
+
+ -- load the compiler instance
+ local instance = compiler.load(srcpath)
+ if not instance then
+ return false
+ end
+
+ -- make includes
+ local includes = nil
+ if instance:kind() == "cc" then includes = self:get("cincludes")
+ elseif instance:kind() == "cxx" then includes = self:get("cxxincludes")
+ end
+ if includes then
+ for _, include in ipairs(table.wrap(includes)) do
+ srcfile:print("#include <%s>", include)
+ end
+ srcfile:print("")
+ end
+
+ -- make the main function header
+ srcfile:print("int main(int argc, char** argv)")
+ srcfile:print("{")
+
+ -- make interfaces
+ srcfile:print(" volatile void* p%s = (void*)&%s;\n", interface, interface)
+
+ -- make the main function tailer
+ srcfile:print(" return 0;")
+ srcfile:print("}")
+
+ -- exit this file
+ srcfile:close()
+
+ -- execute the compile command
+ local ok, errors = instance:run(instance:command(self, srcpath, objpath))
+ if not ok and option_.get("verbose") then
+ print(errors)
+ end
+
+ -- ok?
+ return ok
+end
+
+-- check typedef
+function option:_check_typedef(typedef, srcpath, objpath)
+
+ -- check
+ assert(typedef)
+
+ -- open the checking source file
+ local srcfile = io.open(srcpath, "w")
+ if not srcfile then
+ return false
+ end
+
+ -- load the compiler instance
+ local instance = compiler.load(srcpath)
+ if not instance then
+ return false
+ end
+
+ -- make includes
+ local includes = nil
+ if instance:kind() == "cc" then includes = self:get("cincludes")
+ elseif instance:kind() == "cxx" then includes = self:get("cxxincludes")
+ end
+ if includes then
+ for _, include in ipairs(table.wrap(includes)) do
+ srcfile:print("#include <%s>", include)
+ end
+ srcfile:print("")
+ end
+
+ -- make the main function header
+ srcfile:print("int main(int argc, char** argv)")
+ srcfile:print("{")
+
+ -- make interfaces
+ srcfile:print(" typedef %s __type_xxx;\n", typedef)
+
+ -- make the main function tailer
+ srcfile:print(" return 0;")
+ srcfile:print("}")
+
+ -- exit this file
+ srcfile:close()
+
+ -- execute the compile command
+ local ok, errors = instance:run(instance:command(self, srcpath, objpath))
+ if not ok and option_.get("verbose") then
+ print(errors)
+ end
+
+ -- ok?
+ return ok
+end
-- check option for checking links
function option:_check_links(cfile, objectfile, targetfile)
@@ -51,7 +203,7 @@ function option:_check_links(cfile, objectfile, targetfile)
end
-- only for compile a object file
- local ok = compiler.check_include(self, nil, cfile, objectfile)
+ local ok = self:_check_include(nil, cfile, objectfile)
-- check link
if ok then ok = linker.check_links(self, cfile, objectfile, targetfile) end
@@ -77,7 +229,7 @@ function option:_check_cincludes(cfile, objectfile)
if option._CHECKED_CINCLUDES[cinclude] then return true end
-- check cinclude
- local ok = compiler.check_include(self, cinclude, cfile, objectfile)
+ local ok = self:_check_include(cinclude, cfile, objectfile)
-- trace
utils.printf("checking for the c include %s ... %s", cinclude, utils.ifelse(ok, "ok", "no"))
@@ -104,7 +256,7 @@ function option:_check_cxxincludes(cxxfile, objectfile)
if option._CHECKED_CXXINCLUDES[cinclude] then return true end
-- check cinclude
- local ok = compiler.check_include(self, cxxinclude, cxxfile, objectfile)
+ local ok = self:_check_include(cxxinclude, cxxfile, objectfile)
-- trace
utils.printf("checking for the c++ include %s ... %s", cxxinclude, utils.ifelse(ok, "ok", "no"))
@@ -127,7 +279,7 @@ function option:_check_cfuncs(cfile, objectfile, targetfile)
for _, cfunc in ipairs(table.wrap(self:get("cfuncs"))) do
-- check function
- local ok = compiler.check_function(self, cfunc, cfile, objectfile)
+ local ok = self:_check_function(cfunc, cfile, objectfile)
-- check link
if ok and self:get("links") then ok = linker.check_links(self, cfile, objectfile, targetfile) end
@@ -150,7 +302,7 @@ function option:_check_cxxfuncs(cxxfile, objectfile, targetfile)
for _, cxxfunc in ipairs(table.wrap(self:get("cxxfuncs"))) do
-- check function
- local ok = compiler.check_function(self, cxxfunc, cxxfile, objectfile)
+ local ok = self:_check_function(cxxfunc, cxxfile, objectfile)
-- check link
if ok and self:get("links") then ok = linker.check_links(self, cxxfile, objectfile, targetfile) end
@@ -173,7 +325,7 @@ function option:_check_ctypes(cfile, objectfile, targetfile)
for _, ctype in ipairs(table.wrap(self:get("ctypes"))) do
-- check type
- local ok = compiler.check_typedef(self, ctype, cfile, objectfile)
+ local ok = self:_check_typedef(ctype, cfile, objectfile)
-- trace
utils.printf("checking for the c type %s ... %s", ctype, utils.ifelse(ok, "ok", "no"))
@@ -193,7 +345,7 @@ function option:_check_cxxtypes(cxxfile, objectfile, targetfile)
for _, cxxtype in ipairs(table.wrap(self:get("cxxtypes"))) do
-- check type
- local ok = compiler.check_typedef(self, cxxtype, cxxfile, objectfile)
+ local ok = self:_check_typedef(cxxtype, cxxfile, objectfile)
-- trace
utils.printf("checking for the c++ type %s ... %s", cxxtype, utils.ifelse(ok, "ok", "no"))
diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua
index 52e9c4b8e..c52b52a05 100644
--- a/xmake/core/project/project.lua
+++ b/xmake/core/project/project.lua
@@ -36,7 +36,6 @@ local config = require("project/config")
local option = require("project/option")
local deprecated_project = require("project/deprecated/project")
local linker = require("platform/linker")
-local compiler = require("platform/compiler")
local platform = require("platform/platform")
-- the current os is belong to the given os?
diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua
index 834e9f456..42a4df4bf 100644
--- a/xmake/core/project/target.lua
+++ b/xmake/core/project/target.lua
@@ -30,7 +30,7 @@ local table = require("base/table")
local option = require("project/option")
local config = require("project/config")
local linker = require("platform/linker")
-local compiler = require("platform/compiler")
+local compiler = require("tool/compiler")
local platform = require("platform/platform")
-- get the filename from the given name and kind
@@ -47,7 +47,7 @@ function target.filename(name, kind)
end
-- get the target info
-function target.get(self, infoname)
+function target:get(infoname)
-- check
assert(self and self._INFO and infoname)
@@ -57,14 +57,14 @@ function target.get(self, infoname)
end
-- get the target name
-function target.name(self)
+function target:name()
-- get it
return self._NAME
end
-- get the linker
-function target.linker(self)
+function target:linker()
-- check
assert(self)
@@ -81,13 +81,13 @@ function target.linker(self)
end
-- get the compiler with the given source file
-function target.compiler(self, srcfile)
+function target:compiler(srcfile)
-- check
assert(self and srcfile)
- -- init the linker from the given kind
- local result, errors = compiler.init(srcfile)
+ -- load the compiler
+ local result, errors = compiler.load(srcfile)
if not result then
os.raise(errors)
end
@@ -98,7 +98,7 @@ function target.compiler(self, srcfile)
end
-- get the options
-function target.options(self)
+function target:options()
-- the options
local options = {}
@@ -117,7 +117,7 @@ function target.options(self)
end
-- get the object file directory
-function target.objectdir(self)
+function target:objectdir()
-- check
assert(self)
@@ -135,7 +135,7 @@ function target.objectdir(self)
end
-- get the target file
-function target.targetfile(self)
+function target:targetfile()
-- check
assert(self)
@@ -153,7 +153,7 @@ function target.targetfile(self)
end
-- get the source files
-function target.sourcefiles(self)
+function target:sourcefiles()
-- check
assert(self)
@@ -212,7 +212,7 @@ function target.sourcefiles(self)
end
-- get the object files
-function target.objectfiles(self)
+function target:objectfiles()
-- check
assert(self)
@@ -261,7 +261,7 @@ function target.objectfiles(self)
end
-- get the header files
-function target.headerfiles(self)
+function target:headerfiles()
-- check
assert(self)
diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua
index a05e26939..44bef94e1 100644
--- a/xmake/core/sandbox/modules/os.lua
+++ b/xmake/core/sandbox/modules/os.lua
@@ -165,17 +165,11 @@ function sandbox_os.run(cmd, ...)
-- make command
cmd = vformat(cmd, ...)
- -- make temporary log file
- local log = os.tmpname()
-
- -- run command
- if 0 ~= os.execute(cmd .. string.format(" > %s 2>&1", log)) then
- io.cat(log)
- os.raise("run: %s failed!", cmd)
+ -- run it
+ local ok, errors = os.run(cmd)
+ if not ok then
+ os.raise(errors)
end
-
- -- remove the temporary log file
- os.rm(log)
end
-- match files or directories
diff --git a/xmake/core/tool/compiler.lua b/xmake/core/tool/compiler.lua
new file mode 100644
index 000000000..9ffe21253
--- /dev/null
+++ b/xmake/core/tool/compiler.lua
@@ -0,0 +1,421 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file compiler.lua
+--
+
+-- define module
+local compiler = compiler or {}
+
+-- load modules
+local io = require("base/io")
+local path = require("base/path")
+local utils = require("base/utils")
+local table = require("base/table")
+local string = require("base/string")
+local config = require("project/config")
+local tool = require("tool/tool")
+local platform = require("platform/platform")
+
+-- get the current tool
+function compiler:_tool()
+
+ -- get it
+ return self._TOOL
+end
+
+-- get the current flag names
+function compiler:_flagnames()
+
+ -- get it
+ return self._FLAGNAMES
+end
+
+-- get the compiler kind of the source file
+function compiler._kind_of_file(srcfile)
+
+ -- get the source file type
+ local filetype = path.extension(srcfile)
+ if not filetype then
+ return nil
+ end
+
+ -- the kinds
+ local kinds =
+ {
+ [".c"] = "cc"
+ , [".cc"] = "cxx"
+ , [".cpp"] = "cxx"
+ , [".m"] = "mm"
+ , [".mm"] = "mxx"
+ , [".s"] = "as"
+ , [".asm"] = "as"
+ , [".swift"] = "sc"
+ }
+
+ -- get kind
+ return kinds[filetype:lower()]
+end
+
+-- get the flags
+function compiler:_flags(target)
+
+ -- get the target key
+ local key = tostring(target)
+
+ -- get it directly from cache dirst
+ self._FLAGS = self._FLAGS or {}
+ if self._FLAGS[key] then
+ return self._FLAGS[key]
+ end
+
+ -- add flags from the configure
+ local flags = {}
+ self:_addflags_from_config(flags)
+
+ -- add flags from the target
+ self:_addflags_from_target(flags, target)
+
+ -- add flags from the platform
+ self:_addflags_from_platform(flags)
+
+ -- add flags from the compiler
+ self:_addflags_from_compiler(flags, target:get("kind"))
+
+ -- remove repeat
+ flags = table.unique(flags)
+
+ -- merge flags
+ flags = table.concat(flags, " "):trim()
+
+ -- save flags
+ self._FLAGS[key] = flags
+
+ -- get it
+ return flags
+end
+
+-- map gcc flag to the given compiler flag
+function compiler:_mapflag(flag, mapflags)
+
+ -- attempt to map it directly
+ local flag_mapped = mapflags[flag]
+ if flag_mapped then
+ return flag_mapped
+ end
+
+ -- find and replace it using pattern
+ for k, v in pairs(mapflags) do
+ local flag_mapped, count = flag:gsub("^" .. k .. "$", function (w) return v 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(flags)
+
+ -- wrap flags first
+ flags = table.wrap(flags)
+
+ -- the compiler tool
+ local ctool = self:_tool()
+
+ -- done
+ local results = {}
+ local mapflags = ctool:get("mapflags")
+ if mapflags then
+
+ -- map flags
+ for _, flag in pairs(flags) do
+ local flag_mapped = self:_mapflag(flag, mapflags)
+ if flag_mapped then
+ table.insert(results, flag_mapped)
+ end
+ end
+
+ else
+
+ -- check flags
+ for _, flag in pairs(flags) do
+ if ctool:check(flag) then
+ table.insert(results, flag)
+ end
+ end
+
+ end
+
+ -- ok?
+ return results
+end
+
+-- get the named flags
+function compiler:_named_flags(names, flags)
+
+ -- map it
+ local flags_mapped = {}
+ for _, name in ipairs(table.wrap(names)) do
+ table.join2(flags_mapped, self:_mapflags(flags[name]))
+ end
+
+ -- get it
+ return flags_mapped
+end
+
+-- add flags from the configure
+function compiler:_addflags_from_config(flags)
+
+ -- done
+ for _, flagname in ipairs(self:_flagnames()) do
+ table.join2(flags, config.get(flagname))
+ end
+end
+
+-- add flags from the target
+function compiler:_addflags_from_target(flags, target)
+
+ -- the compiler tool
+ local ctool = self:_tool()
+
+ -- add the target flags
+ for _, flagname in ipairs(self:_flagnames()) do
+ table.join2(flags, self:_mapflags(target:get(flagname)))
+ end
+
+ -- add the symbols flags
+ table.join2(flags, self:_named_flags(target:get("symbols"), { debug = "-g"
+ , hidden = "-fvisibility=hidden"
+ }))
+
+ -- add the warning flags
+ table.join2(flags, self:_named_flags(target:get("warnings"), { none = "-w"
+ , less = "-W1"
+ , more = "-W3"
+ , all = "-Wall"
+ , error = "-Werror"
+ }))
+
+ -- add the optimize flags
+ table.join2(flags, self:_named_flags(target:get("optimize"), { none = "-O0"
+ , fast = "-O1"
+ , faster = "-O2"
+ , fastest = "-O3"
+ , smallest = "-Os"
+ , aggressive = "-Ofast"
+ }))
+
+ -- add the vector extensions flags
+ table.join2(flags, self:_named_flags(target:get("vectorexts"), { mmx = "-mmmx"
+ , sse = "-msse"
+ , sse2 = "-msse2"
+ , sse3 = "-msse3"
+ , ssse3 = "-mssse3"
+ , avx = "-mavx"
+ , avx2 = "-mavx2"
+ , neon = "-mfpu=neon"
+ }))
+
+ -- add the language flags
+ local languages = {}
+ for _, flagname in ipairs(self:_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, self:_named_flags(target:get("languages"), languages))
+
+ -- add the includedirs flags
+ for _, includedir in ipairs(table.wrap(target:get("includedirs"))) do
+ table.join2(flags, ctool:includedir(includedir))
+ end
+
+ -- add the defines flags
+ for _, define in ipairs(table.wrap(target:get("defines"))) do
+ table.join2(flags, ctool:define(define))
+ end
+
+ -- append the undefines flags
+ for _, undefine in ipairs(table.wrap(target:get("undefines"))) do
+ table.join2(flags, ctool:undefine(undefine))
+ end
+
+ -- for target options?
+ if target.options then
+
+ -- add the flags for the target options
+ for name, opt in pairs(target:options()) do
+
+ -- add the flags from the option
+ self:_addflags_from_target(flags, opt)
+
+ -- append the defines flags
+ for _, define in ipairs(table.wrap(opt:get("defines_if_ok"))) do
+ table.join2(flags, ctool:define(define))
+ end
+
+ -- append the undefines flags
+ for _, undefine in ipairs(table.wrap(opt:get("undefines_if_ok"))) do
+ table.join2(flags, ctool:undefine(undefine))
+ end
+ end
+ end
+end
+
+-- add flags from the platform
+function compiler:_addflags_from_platform(flags)
+
+ -- the compiler tool
+ local ctool = self:_tool()
+
+ -- add flags
+ for _, flagname in ipairs(self:_flagnames()) do
+ table.join2(flags, self:_mapflags(platform.get(flagname)))
+ end
+
+ -- add the includedirs flags
+ for _, includedir in ipairs(table.wrap(platform.get("includedirs"))) do
+ table.join2(flags, ctool:includedir(includedir))
+ end
+
+ -- add the defines flags
+ for _, define in ipairs(table.wrap(platform.get("defines"))) do
+ table.join2(flags, ctool:define(define))
+ end
+
+ -- append the undefines flags
+ for _, undefine in ipairs(table.wrap(platform.get("undefines"))) do
+ table.join2(flags, ctool:undefine(undefine))
+ end
+end
+
+-- add flags from the compiler
+function compiler:_addflags_from_compiler(flags, kind)
+
+ -- the compiler tool
+ local ctool = self:_tool()
+
+ -- done
+ for _, flagname in ipairs(self:_flagnames()) do
+
+ -- add compiler.xxflags
+ table.join2(flags, ctool:get(flagname))
+
+ -- add compiler.kind.xxflags
+ if kind ~= nil and ctool:get(kind) ~= nil then
+ table.join2(flags, ctool:get(kind)[flagname])
+ end
+ end
+end
+
+-- get the current kind
+function compiler:kind()
+
+ -- get it
+ return self._KIND
+end
+
+-- load the compiler from the given source file
+function compiler.load(srcfile)
+
+ -- get the compiler kind
+ local kind = compiler._kind_of_file(srcfile)
+ if not kind then
+ return nil, string.format("unknown source file: %s", srcfile)
+ end
+
+ -- get it directly from cache dirst
+ compiler._INSTANCES = compiler._INSTANCES or {}
+ if compiler._INSTANCES[kind] then
+ return compiler._INSTANCES[kind]
+ end
+
+ -- new instance
+ local instance = table.inherit(compiler)
+
+ -- load the compiler tool from the source file type
+ local result, errors = tool.load(kind)
+ if not result then
+ return nil, errors
+ end
+
+ -- save tool
+ instance._TOOL = result
+
+ -- save kind
+ instance._KIND = kind
+
+ -- save flagnames
+ local flagnames =
+ {
+ cc = { "cxflags", "cflags" }
+ , cxx = { "cxflags", "cxxflags" }
+ , mm = { "mxflags", "mflags" }
+ , mxx = { "mxflags", "mxxflags" }
+ , as = { "asflags" }
+ , sc = { "scflags" }
+ }
+ instance._FLAGNAMES = flagnames[kind]
+
+ -- check
+ if not instance._FLAGNAMES then
+ return nil, string.format("unknown compiler for kind: %s", kind)
+ end
+
+ -- save this instance
+ compiler._INSTANCES[kind] = instance
+
+ -- ok
+ return instance
+end
+
+-- run the command
+function compiler:run(cmd)
+
+ -- get it
+ return self:_tool():run(cmd)
+end
+
+-- get the command
+function compiler:command(target, srcfile, objfile, logfile)
+
+ -- get it
+ return self:_tool():command(srcfile, objfile, self:_flags(target), logfile)
+end
+
+-- return module
+return compiler
diff --git a/xmake/core/tool/tool.lua b/xmake/core/tool/tool.lua
index 4a4a1db26..fcfc28b1e 100644
--- a/xmake/core/tool/tool.lua
+++ b/xmake/core/tool/tool.lua
@@ -20,19 +20,146 @@
-- @file tool.lua
--
--- define module: tool
-local tool = tool or {}
+-- define module
+local tool = tool or {}
+local _module = _module or {}
-- load modules
local os = require("base/os")
local path = require("base/path")
local utils = require("base/utils")
+local table = require("base/table")
local string = require("base/string")
local filter = require("base/filter")
local config = require("project/config")
local global = require("project/global")
+local sandbox = require("sandbox/sandbox")
local platform = require("platform/platform")
+-- get the property
+function _module:get(name)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- check
+ if not interface.get then
+ return
+ end
+
+ -- get it
+ return interface.get(name)
+end
+
+-- make the define flag
+function _module:define(macro)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- check
+ if not interface.define then
+ return
+ end
+
+ -- make it
+ return interface.define(macro)
+end
+
+-- make the undefine flag
+function _module:undefine(macro)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- check
+ if not interface.undefine then
+ return
+ end
+
+ -- make it
+ return interface.undefine(macro)
+end
+
+-- make the includedir flag
+function _module:includedir(dir)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- check
+ if not interface.includedir then
+ return
+ end
+
+ -- make it
+ return interface.includedir(dir)
+end
+
+-- make the command
+function _module:command(srcfile, objfile, flags, logfile)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface and interface.command)
+
+ -- make it
+ return interface.command(srcfile, objfile, flags, logfile)
+end
+
+-- check the given flags
+function _module:check(flags)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- no check?
+ if not interface.check then
+ return true
+ end
+
+ -- have been checked? return it directly
+ interface.checked = interface.checked or {}
+ if interface.checked[flags] ~= nil then
+ return interface.checked[flags]
+ end
+
+ -- check it
+ local ok, results = sandbox.load(interface.check, flags)
+ if not ok then
+ os.raise(results)
+ end
+
+ -- save the checked result
+ interface.checked[flags] = results
+
+ -- ok?
+ return ok
+end
+
+-- run the command
+function _module:run(cmd, ...)
+
+ -- the private
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- no run interface?
+ if not interface.run then
+
+ -- run it
+ return os.run(cmd, ...)
+ end
+
+ -- run it
+ return sandbox.load(interface.run, cmd, ...)
+end
+
-- the directories of tools
function tool._directories(name)
@@ -146,25 +273,30 @@ function tool._filter()
end
--- load the given tool from the given name(.e.g cc, ar, ld, sh, ..)
-function tool.load(name)
+-- load the given tool from the given kind
+--
+-- the kinds:
+--
+-- .e.g cc, cxx, mm, mxx, as, ar, ld, sh, ..
+--
+function tool.load(kind)
-- get the shell name
- local shellname = platform.tool(name)
+ local shellname = platform.tool(kind)
if not shellname then
- return nil, string.format("cannot get tool for %s", name)
+ return nil, string.format("cannot get tool for %s", kind)
end
-- get it directly from cache dirst
tool._TOOLS = tool._TOOLS or {}
- if tool._TOOLS[name] then
- return tool._TOOLS[name]
+ if tool._TOOLS[kind] then
+ return tool._TOOLS[kind]
end
-- find the tool script path
local toolpath = nil
local toolname = path.basename(shellname)
- for _, dir in ipairs(tool._directories(name)) do
+ for _, dir in ipairs(tool._directories(kind)) do
-- find this directory
toolpath = tool._find(dir, toolname)
@@ -196,15 +328,19 @@ function tool.load(name)
end
-- init the tool module
- if module and module.init then
+ if module.init then
module.init(shellname)
end
+
+ -- wrap this module
+ local result = table.inherit(_module)
+ result._INTERFACE = module
-- save tool to the cache
- tool._TOOLS[name] = module
+ tool._TOOLS[kind] = result
-- ok?
- return module
+ return result
end
-- failed
@@ -212,26 +348,26 @@ function tool.load(name)
end
-- check the tool and return the absolute path if exists
-function tool.check(name, dirs)
+function tool.check(shellname, dirs)
-- check
- assert(name)
+ assert(shellname)
-- attempt to run it directly first
- if os.execute(string.format("%s > %s 2>&1", name, xmake._NULDEV)) ~= 0x7f00 then
- return name
+ if os.execute(string.format("%s > %s 2>&1", shellname, xmake._NULDEV)) ~= 0x7f00 then
+ return shellname
end
-- attempt to get it from the given directories
for _, dir in ipairs(table.wrap(dirs)) do
-- check it
- local toolpath = path.translate(string.format("%s/%s", dir, name))
+ local toolpath = path.translate(string.format("%s/%s", dir, shellname))
if os.isfile(toolpath) and os.execute(string.format("%s > %s 2>&1", toolpath, xmake._NULDEV)) ~= 0x7f00 then
return toolpath
end
end
end
--- return module: tool
+-- return module
return tool
diff --git a/xmake/tools/compiler/clang.lua b/xmake/tools/compiler/clang.lua
new file mode 100755
index 000000000..90dd4150b
--- /dev/null
+++ b/xmake/tools/compiler/clang.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) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file clang.lua
+--
+
+-- init it
+function init(shellname)
+
+ -- save the shell name
+ _g.shellname = shellname or "clang"
+
+ -- init mxflags
+ _g.mxflags = { "-fmessage-length=0"
+ , "-pipe"
+ , "-fpascal-strings"
+ , "\"-DIBOutlet=__attribute__((iboutlet))\""
+ , "\"-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))\""
+ , "\"-DIBAction=void)__attribute__((ibaction)\""}
+
+ -- init shflags
+ _g.shflags = { "-dynamiclib", "-fPIC" }
+
+ -- suppress warning
+ _g.cxflags = {"-Qunused-arguments"}
+ _g.mxflags = {"-Qunused-arguments"}
+ _g.asflags = {"-Qunused-arguments"}
+
+ -- init cxflags for the kind: shared
+ _g.shared = {}
+ _g.shared.cxflags = {"-fPIC"}
+
+ -- init flags map
+ _g.mapflags =
+ {
+ -- warnings
+ ["-W1"] = "-Wall"
+ , ["-W2"] = "-Wall"
+ , ["-W3"] = "-Wall"
+
+ -- strip
+ , ["-s"] = "-Wl,-S"
+ , ["-S"] = "-Wl,-S"
+
+ }
+end
+
+-- get the property
+function get(name)
+
+ -- get it
+ return _g[name]
+end
+
+-- make the define flag
+function define(macro)
+
+ -- make it
+ return "-D" .. macro:gsub("\"", "\\\"")
+end
+
+-- make the undefine flag
+function undefine(macro)
+
+ -- make it
+ return "-U" .. macro
+end
+
+-- make the includedir flag
+function includedir(dir)
+
+ -- make it
+ return "-I" .. dir
+end
+
+-- make the command
+function command(srcfile, objfile, flags, logfile)
+
+ -- redirect
+ local redirect = ""
+ if logfile then redirect = format(" > %s 2>&1", logfile) end
+
+ -- make it
+ return format("%s -c %s -o %s %s%s", _g.shellname, flags, objfile, srcfile, redirect)
+end
+
+-- check the given flags
+function check(flags)
+
+ -- done
+ local ok = false
+ try
+ {
+ function ()
+
+ -- check it
+ os.run("%s %s -S -o $(nuldev) -xc $(nuldev) > $(nuldev) 2>&1", _g.shellname, flags)
+
+ -- ok
+ ok = true
+
+ end
+ }
+
+ -- ok?
+ return ok
+end
+
+-- run the command
+function run(cmd, ...)
+
+ -- run it
+ os.run(cmd, ...)
+
+end
+
diff --git a/xmake/tools/compiler/gcc.lua b/xmake/tools/compiler/gcc.lua
index 44f77cf43..72fb8aede 100755
--- a/xmake/tools/compiler/gcc.lua
+++ b/xmake/tools/compiler/gcc.lua
@@ -117,3 +117,11 @@ function check(flags)
return ok
end
+-- run the command
+function run(cmd, ...)
+
+ -- check it
+ os.run(cmd, ...)
+
+end
+