diff options
| author | ruki <[email protected]> | 2020-03-21 21:55:49 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2020-03-21 21:55:49 +0800 |
| commit | 1429067bf099b4880c000421e8b53d3c3341f66d (patch) | |
| tree | 2fc0124e074ab9278cbf0256ab7820ccaebc8afd | |
| parent | 114545bb164cba3de59e4083fa4170f8f851f3d7 (diff) | |
add clang-cl
| -rw-r--r-- | xmake/modules/core/tools/cl.lua | 30 | ||||
| -rw-r--r-- | xmake/modules/core/tools/clang_cl.lua | 141 | ||||
| -rw-r--r-- | xmake/modules/core/tools/gcc.lua | 30 | ||||
| -rw-r--r-- | xmake/modules/detect/tools/clang_cl/has_flags.lua | 106 | ||||
| -rw-r--r-- | xmake/modules/detect/tools/find_clang_cl.lua | 52 |
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 + |
