summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2020-03-21 21:55:49 +0800
committerruki <[email protected]>2020-03-21 21:55:49 +0800
commit1429067bf099b4880c000421e8b53d3c3341f66d (patch)
tree2fc0124e074ab9278cbf0256ab7820ccaebc8afd
parent114545bb164cba3de59e4083fa4170f8f851f3d7 (diff)
add clang-cl
-rw-r--r--xmake/modules/core/tools/cl.lua30
-rw-r--r--xmake/modules/core/tools/clang_cl.lua141
-rw-r--r--xmake/modules/core/tools/gcc.lua30
-rw-r--r--xmake/modules/detect/tools/clang_cl/has_flags.lua106
-rw-r--r--xmake/modules/detect/tools/find_clang_cl.lua52
5 files changed, 309 insertions, 50 deletions
diff --git a/xmake/modules/core/tools/cl.lua b/xmake/modules/core/tools/cl.lua
index fb2d69a53..4080bb056 100644
--- a/xmake/modules/core/tools/cl.lua
+++ b/xmake/modules/core/tools/cl.lua
@@ -292,7 +292,7 @@ function add_sourceflags(self, sourcefile, fileconfig, target, targetkind)
end
-- make the compile arguments list for the precompiled header
-function _compargv1_pch(self, pcheaderfile, pcoutputfile, flags)
+function _compargv_pch(self, pcheaderfile, pcoutputfile, flags)
-- remove "-Yuxxx.h" and "-Fpxxx.pch"
local pchflags = {}
@@ -314,12 +314,12 @@ function _compargv1_pch(self, pcheaderfile, pcoutputfile, flags)
end
-- make the compile arguments list
-function _compargv1(self, sourcefile, objectfile, flags)
+function compargv(self, sourcefile, objectfile, flags)
-- precompiled header?
local extension = path.extension(sourcefile)
if (extension:startswith(".h") or extension == ".inl") then
- return _compargv1_pch(self, sourcefile, objectfile, flags)
+ return _compargv_pch(self, sourcefile, objectfile, flags)
end
-- make the compile arguments list
@@ -327,7 +327,7 @@ function _compargv1(self, sourcefile, objectfile, flags)
end
-- compile the source file
-function _compile1(self, sourcefile, objectfile, dependinfo, flags)
+function compile(self, sourcefile, objectfile, dependinfo, flags)
-- ensure the object directory
-- @note this path here has been normalized, we can quickly find it by the unique path separator prompt
@@ -348,7 +348,7 @@ function _compile1(self, sourcefile, objectfile, dependinfo, flags)
end
-- use vstool to compile and enable vs_unicode_output @see https://github.com/xmake-io/xmake/issues/528
- return vstool.iorunv(_compargv1(self, sourcefile, objectfile, compflags))
+ return vstool.iorunv(compargv(self, sourcefile, objectfile, compflags))
end,
catch
{
@@ -411,23 +411,3 @@ function _compile1(self, sourcefile, objectfile, dependinfo, flags)
end
end
--- make the compile arguments list
-function compargv(self, sourcefiles, objectfile, flags)
-
- -- only support single source file now
- assert(type(sourcefiles) ~= "table", "'object:sources' not support!")
-
- -- for only single source file
- return _compargv1(self, sourcefiles, objectfile, flags)
-end
-
--- compile the source file
-function compile(self, sourcefiles, objectfile, dependinfo, flags)
-
- -- only support single source file now
- assert(type(sourcefiles) ~= "table", "'object:sources' not support!")
-
- -- for only single source file
- _compile1(self, sourcefiles, objectfile, dependinfo, flags)
-end
-
diff --git a/xmake/modules/core/tools/clang_cl.lua b/xmake/modules/core/tools/clang_cl.lua
new file mode 100644
index 000000000..b5825be11
--- /dev/null
+++ b/xmake/modules/core/tools/clang_cl.lua
@@ -0,0 +1,141 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-2020, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file clang_cl.lua
+--
+
+-- inherit cl
+inherit("cl")
+import("core.base.option")
+import("core.base.colors")
+
+-- init it
+function init(self)
+ _super.init(self)
+end
+
+-- has color diagnostics?
+function _has_color_diagnostics(self)
+ local colors_diagnostics = _g._HAS_COLOR_DIAGNOSTICS
+ if colors_diagnostics == nil then
+ if io.isatty() and (colors.color8() or colors.color256()) then
+ local theme = colors.theme()
+ if theme and theme:name() ~= "plain" then
+ -- for clang
+ if self:has_flags("-fcolor-diagnostics", "cxflags") then
+ colors_diagnostics = "-fcolor-diagnostics"
+ -- for gcc
+ elseif self:has_flags("-fdiagnostics-color=always", "cxflags") then
+ colors_diagnostics = "-fdiagnostics-color=always"
+ end
+ end
+ end
+ colors_diagnostics = colors_diagnostics or false
+ _g._HAS_COLOR_DIAGNOSTICS = colors_diagnostics
+ end
+ return colors_diagnostics
+end
+
+-- compile the source file
+function compile(self, sourcefile, objectfile, dependinfo, flags)
+
+ -- ensure the object directory
+ -- @note this path here has been normalized, we can quickly find it by the unique path separator prompt
+ os.mkdir(path.directory(objectfile, path.sep()))
+
+ -- compile it
+ local depfile = dependinfo and os.tmpfile() or nil
+ try
+ {
+ function ()
+
+ -- support `-MMD -MF depfile.d`? some old gcc does not support it at same time
+ if depfile and _g._HAS_MMD_MF == nil then
+ _g._HAS_MMD_MF = self:has_flags({"-MMD", "-MF", os.nuldev()}, "cxflags", { flagskey = "-MMD -MF" }) or false
+ end
+
+ -- generate includes file
+ local compflags = flags
+ if depfile and _g._HAS_MMD_MF then
+ compflags = table.join(compflags, "-MMD", "-MF", depfile)
+ end
+
+ -- has color diagnostics? enable it
+ local colors_diagnostics = _has_color_diagnostics(self)
+ if colors_diagnostics then
+ compflags = table.join(compflags, colors_diagnostics)
+ end
+
+ -- do compile
+ return os.iorunv(compargv(self, sourcefile, objectfile, compflags))
+ end,
+ catch
+ {
+ function (errors)
+
+ -- try removing the old object file for forcing to rebuild this source file
+ os.tryrm(objectfile)
+
+ -- parse and strip errors
+ local lines = errors and tostring(errors):split('\n', {plain = true}) or {}
+ if not option.get("verbose") then
+
+ -- find the start line of error
+ local start = 0
+ for index, line in ipairs(lines) do
+ if line:find("error:", 1, true) or line:find("错误:", 1, true) then
+ start = index
+ break
+ end
+ end
+
+ -- get 16 lines of errors
+ if start > 0 then
+ lines = table.slice(lines, start, start + ifelse(#lines - start > 16, 16, #lines - start))
+ end
+ end
+
+ -- raise compiling errors
+ raise(#lines > 0 and table.concat(lines, "\n") or "")
+ end
+ },
+ finally
+ {
+ function (ok, outdata, errdata)
+ -- show warnings?
+ if ok and errdata and #errdata > 0 and (option.get("diagnosis") or option.get("warning")) then
+ local lines = errdata:split('\n', {plain = true})
+ if #lines > 0 then
+ local warnings = table.concat(table.slice(lines, 1, ifelse(#lines > 8, 8, #lines)), "\n")
+ cprint("${color.warning}%s", warnings)
+ end
+ end
+
+ -- generate the dependent includes
+ if depfile and os.isfile(depfile) then
+ if dependinfo then
+ dependinfo.depfiles_gcc = io.readfile(depfile, {continuation = "\\"})
+ end
+
+ -- remove the temporary dependent file
+ os.tryrm(depfile)
+ end
+ end
+ }
+ }
+end
+
diff --git a/xmake/modules/core/tools/gcc.lua b/xmake/modules/core/tools/gcc.lua
index 071a8140a..7b17a3a10 100644
--- a/xmake/modules/core/tools/gcc.lua
+++ b/xmake/modules/core/tools/gcc.lua
@@ -378,7 +378,7 @@ function _has_color_diagnostics(self)
end
-- make the compile arguments list for the precompiled header
-function _compargv1_pch(self, pcheaderfile, pcoutputfile, flags)
+function _compargv_pch(self, pcheaderfile, pcoutputfile, flags)
-- remove "-include xxx.h" and "-include-pch xxx.pch"
local pchflags = {}
@@ -405,18 +405,18 @@ function _compargv1_pch(self, pcheaderfile, pcoutputfile, flags)
end
-- make the compile arguments list
-function _compargv1(self, sourcefile, objectfile, flags)
+function compargv(self, sourcefile, objectfile, flags)
-- precompiled header?
local extension = path.extension(sourcefile)
if (extension:startswith(".h") or extension == ".inl") then
- return _compargv1_pch(self, sourcefile, objectfile, flags)
+ return _compargv_pch(self, sourcefile, objectfile, flags)
end
return ccache.cmdargv(self:program(), table.join("-c", flags, "-o", objectfile, sourcefile))
end
-- compile the source file
-function _compile1(self, sourcefile, objectfile, dependinfo, flags)
+function compile(self, sourcefile, objectfile, dependinfo, flags)
-- ensure the object directory
-- @note this path here has been normalized, we can quickly find it by the unique path separator prompt
@@ -446,7 +446,7 @@ function _compile1(self, sourcefile, objectfile, dependinfo, flags)
end
-- do compile
- return os.iorunv(_compargv1(self, sourcefile, objectfile, compflags))
+ return os.iorunv(compargv(self, sourcefile, objectfile, compflags))
end,
catch
{
@@ -504,23 +504,3 @@ function _compile1(self, sourcefile, objectfile, dependinfo, flags)
}
end
--- make the compile arguments list
-function compargv(self, sourcefiles, objectfile, flags)
-
- -- only support single source file now
- assert(type(sourcefiles) ~= "table", "'object:sources' not support!")
-
- -- for only single source file
- return _compargv1(self, sourcefiles, objectfile, flags)
-end
-
--- compile the source file
-function compile(self, sourcefiles, objectfile, dependinfo, flags)
-
- -- only support single source file now
- assert(type(sourcefiles) ~= "table", "'object:sources' not support!")
-
- -- for only single source file
- _compile1(self, sourcefiles, objectfile, dependinfo, flags)
-end
-
diff --git a/xmake/modules/detect/tools/clang_cl/has_flags.lua b/xmake/modules/detect/tools/clang_cl/has_flags.lua
new file mode 100644
index 000000000..a11bf9057
--- /dev/null
+++ b/xmake/modules/detect/tools/clang_cl/has_flags.lua
@@ -0,0 +1,106 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-2020, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file has_flags.lua
+--
+
+-- imports
+import("lib.detect.cache")
+import("core.language.language")
+
+-- attempt to check it from the argument list
+function _check_from_arglist(flags, opt)
+
+ -- only one flag?
+ if #flags > 1 then
+ return
+ end
+
+ -- make cache key
+ local key = "detect.tools.clang_cl.has_flags"
+
+ -- make allflags key
+ local flagskey = opt.program .. "_" .. (opt.programver or "")
+
+ -- load cache
+ local cacheinfo = cache.load(key)
+
+ -- get all allflags from argument list
+ local allflags = cacheinfo[flagskey]
+ if not allflags then
+
+ -- get argument list
+ allflags = {}
+ local arglist = os.iorunv(opt.program, {"-?"})
+ if arglist then
+ for arg in arglist:gmatch("(/[%-%a%d]+)%s+") do
+ allflags[arg:gsub("/", "-")] = true
+ end
+ end
+
+ -- save cache
+ cacheinfo[flagskey] = allflags
+ cache.save(key, cacheinfo)
+ end
+
+ -- ok?
+ return allflags[flags[1]:gsub("/", "-")]
+end
+
+-- try running
+function _try_running(...)
+
+ local argv = {...}
+ local errors = nil
+ return try { function () os.runv(unpack(argv)); return true end, catch { function (errs) errors = (errs or ""):trim() end }}, errors
+end
+
+-- try running to check flags
+function _check_try_running(flags, opt)
+
+ -- get extension
+ -- @note we need detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
+ local extension = opt.program:endswith("++") and ".cpp" or (table.wrap(language.sourcekinds()[opt.toolkind or "cc"])[1] or ".c")
+
+ -- make an stub source file
+ local sourcefile = path.join(os.tmpdir(), "detect", "clang_cl_has_flags" .. extension)
+ if not os.isfile(sourcefile) then
+ io.writefile(sourcefile, "int main(int argc, char** argv)\n{return 0;}")
+ end
+
+ -- check flags for compiler
+ -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage
+ return _try_running(opt.program, table.join(flags, "-c", "-o", os.tmpfile(), sourcefile))
+end
+
+-- has_flags(flags)?
+--
+-- @param opt the argument options, e.g. {toolname = "", program = "", programver = "", toolkind = "[cc|cxx|ld|ar|sh|gc|rc|dc|mm|mxx]"}
+--
+-- @return true or false
+--
+function main(flags, opt)
+
+ -- attempt to check it from the argument list
+ if _check_from_arglist(flags, opt) then
+ return true
+ end
+
+ -- try running to check it
+ return _check_try_running(flags, opt)
+end
+
diff --git a/xmake/modules/detect/tools/find_clang_cl.lua b/xmake/modules/detect/tools/find_clang_cl.lua
new file mode 100644
index 000000000..6a04da71b
--- /dev/null
+++ b/xmake/modules/detect/tools/find_clang_cl.lua
@@ -0,0 +1,52 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-2020, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file find_clang_cl.lua
+--
+
+-- imports
+import("lib.detect.find_program")
+import("lib.detect.find_programver")
+
+-- find clang_cl
+--
+-- @param opt the argument options, e.g. {version = true}
+--
+-- @return program, version
+--
+-- @code
+--
+-- local clang_cl = find_clang_cl()
+--
+-- @endcode
+--
+function main(opt)
+
+ -- init options
+ opt = opt or {}
+
+ -- find program
+ local program = find_program(opt.program or "clang-cl.exe", opt)
+
+ -- find program version
+ local version = nil
+ if program and opt and opt.version then
+ version = find_programver(program, opt)
+ end
+ return program, version
+end
+